diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..52370e4a509b0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4 + +* text=auto +*.cpp rust +*.h rust +*.rs rust +src/rt/msvc/* -whitespace +src/rt/vg/* -whitespace +src/rt/linenoise/* -whitespace diff --git a/COPYRIGHT b/COPYRIGHT index 2315c6fe3cba2..ffbfadaa3391b 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -367,4 +367,3 @@ their own copyright notices and license terms: has chosen for the collective work, enumerated at the top of this file. The only difference is the retention of copyright itself, held by the contributor. - diff --git a/Makefile.in b/Makefile.in index dd2e6a95861bd..8ab704ebe1719 100644 --- a/Makefile.in +++ b/Makefile.in @@ -101,7 +101,7 @@ endif ifdef CFG_ENABLE_DEBUG $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG)) - CFG_RUSTC_FLAGS += + CFG_RUSTC_FLAGS += --cfg debug CFG_GCCISH_CFLAGS += -DRUST_DEBUG else CFG_GCCISH_CFLAGS += -DRUST_NDEBUG @@ -110,6 +110,9 @@ endif ifdef SAVE_TEMPS CFG_RUSTC_FLAGS += --save-temps endif +ifdef ASM_COMMENTS + CFG_RUSTC_FLAGS += -z asm-comments +endif ifdef TIME_PASSES CFG_RUSTC_FLAGS += -Z time-passes endif @@ -238,7 +241,7 @@ $(foreach target,$(CFG_TARGET_TRIPLES),\ CORELIB_CRATE := $(S)src/libcore/core.rc CORELIB_INPUTS := $(wildcard $(addprefix $(S)src/libcore/, \ - core.rc *.rs */*.rs */*/*rs)) + core.rc *.rs */*.rs */*/*rs */*/*/*rs)) ###################################################################### # Standard library variables diff --git a/RELEASES.txt b/RELEASES.txt index 13e4e0c2039cc..fb2bbb45e7c83 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -250,7 +250,7 @@ Version 0.3 (July 2012) * Slices and fixed-size, interior-allocated vectors * #!-comments for lang versioning, shell execution * Destructors and iface implementation for classes; - type-parameterized classes and class methods + type-parameterized classes and class methods * 'const' type kind for types that can be used to implement shared-memory concurrency patterns @@ -261,7 +261,7 @@ Version 0.3 (July 2012) 'crust', 'native' (now 'extern'), 'cont' (now 'again') * Constructs: do-while loops ('do' repurposed), fn binding, - resources (replaced by destructors) + resources (replaced by destructors) * Compiler reorganization * Syntax-layer of compiler split into separate crate @@ -276,7 +276,7 @@ Version 0.3 (July 2012) * Extensive work on libuv interface * Much vector code moved to libraries * Syntax extensions: #line, #col, #file, #mod, #stringify, - #include, #include_str, #include_bin + #include, #include_str, #include_bin * Tool improvements * Cargo automatically resolves dependencies diff --git a/configure b/configure index 884ececa24b1e..0c4afa0566de3 100755 --- a/configure +++ b/configure @@ -439,6 +439,10 @@ then probe CFG_ZCAT zcat fi +step_msg "looking for target specific programs" + +probe CFG_ADB adb + if [ ! -z "$CFG_PANDOC" ] then PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc ' | diff --git a/doc/README b/doc/README index 505b5383dcd80..c3bb28a9e85e9 100644 --- a/doc/README +++ b/doc/README @@ -1,6 +1,6 @@ The markdown docs are only generated by make when node is installed (use -`make doc`). If you don't have node installed you can generate them yourself. -Unfortunately there's no real standard for markdown and all the tools work +`make doc`). If you don't have node installed you can generate them yourself. +Unfortunately there's no real standard for markdown and all the tools work differently. pandoc is one that seems to work well. To generate an html version of a doc do something like: @@ -10,4 +10,4 @@ The syntax for pandoc flavored markdown can be found at: http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown A nice quick reference (for non-pandoc markdown) is at: -http://kramdown.rubyforge.org/quickref.html \ No newline at end of file +http://kramdown.rubyforge.org/quickref.html diff --git a/doc/rust.md b/doc/rust.md index 136c7ee9da3f2..102d1d08a45f7 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -618,7 +618,7 @@ each of which may have some number of [attributes](#attributes) attached to it. ~~~~~~~~ {.ebnf .gram} item : mod_item | fn_item | type_item | struct_item | enum_item - | static_item | trait_item | impl_item | foreign_mod_item ; + | static_item | trait_item | impl_item | extern_block ; ~~~~~~~~ An _item_ is a component of a crate; some module items can be defined in crate @@ -752,10 +752,11 @@ link_attr : ident '=' literal ; ~~~~~~~~ An _`extern mod` declaration_ specifies a dependency on an external crate. -The external crate is then bound into the declaring scope as the `ident` provided in the `extern_mod_decl`. +The external crate is then bound into the declaring scope +as the `ident` provided in the `extern_mod_decl`. -The external crate is resolved to a specific `soname` at compile time, and a -runtime linkage requirement to that `soname` is passed to the linker for +The external crate is resolved to a specific `soname` at compile time, +and a runtime linkage requirement to that `soname` is passed to the linker for loading at runtime. The `soname` is resolved at compile time by scanning the compiler's library path and matching the `link_attrs` provided in the `use_decl` against any `#link` attributes that were declared on the external @@ -992,10 +993,10 @@ Thus the return type on `f` only needs to reflect the `if` branch of the conditi #### Extern functions Extern functions are part of Rust's foreign function interface, -providing the opposite functionality to [foreign modules](#foreign-modules). -Whereas foreign modules allow Rust code to call foreign code, -extern functions with bodies defined in Rust code _can be called by foreign code_. -They are defined in the same way as any other Rust function, +providing the opposite functionality to [external blocks](#external-blocks). +Whereas external blocks allow Rust code to call foreign code, +extern functions with bodies defined in Rust code _can be called by foreign +code_. They are defined in the same way as any other Rust function, except that they have the `extern` modifier. ~~~ @@ -1011,7 +1012,8 @@ let fptr: *u8 = new_vec; ~~~ The primary motivation for extern functions is -to create callbacks for foreign functions that expect to receive function pointers. +to create callbacks for foreign functions that expect to receive function +pointers. ### Type definitions @@ -1308,64 +1310,61 @@ impl Seq for u32 { } ~~~~ -### Foreign modules +### External blocks ~~~ {.ebnf .gram} -foreign_mod_item : "extern mod" ident '{' foreign_mod '} ; -foreign_mod : [ foreign_fn ] * ; +extern_block_item : "extern" '{' extern_block '} ; +extern_block : [ foreign_fn ] * ; ~~~ -Foreign modules form the basis for Rust's foreign function interface. A -foreign module describes functions in external, non-Rust -libraries. -Functions within foreign modules are declared in the same way as other Rust functions, -with the exception that they may not have a body and are instead terminated by a semicolon. +External blocks form the basis for Rust's foreign function interface. +Declarations in an external block describe symbols +in external, non-Rust libraries. + +Functions within external blocks +are declared in the same way as other Rust functions, +with the exception that they may not have a body +and are instead terminated by a semicolon. ~~~ # use core::libc::{c_char, FILE}; # #[nolink] -extern mod c { +extern { fn fopen(filename: *c_char, mode: *c_char) -> *FILE; } ~~~ -Functions within foreign modules may be called by Rust code, just like functions defined in Rust. -The Rust compiler automatically translates between the Rust ABI and the foreign ABI. - -The name of the foreign module has special meaning to the Rust compiler in -that it will treat the module name as the name of a library to link to, -performing the linking as appropriate for the target platform. The name -given for the foreign module will be transformed in a platform-specific way -to determine the name of the library. For example, on Linux the name of the -foreign module is prefixed with 'lib' and suffixed with '.so', so the -foreign mod 'rustrt' would be linked to a library named 'librustrt.so'. +Functions within external blocks may be called by Rust code, +just like functions defined in Rust. +The Rust compiler automatically translates +between the Rust ABI and the foreign ABI. -A number of [attributes](#attributes) control the behavior of foreign -modules. +A number of [attributes](#attributes) control the behavior of external +blocks. -By default foreign modules assume that the library they are calling use the -standard C "cdecl" ABI. Other ABIs may be specified using the `abi` -attribute as in +By default external blocks assume +that the library they are calling uses the standard C "cdecl" ABI. +Other ABIs may be specified using the `abi` attribute as in ~~~{.xfail-test} // Interface to the Windows API #[abi = "stdcall"] -extern mod kernel32 { } +extern { } ~~~ -The `link_name` attribute allows the default library naming behavior to -be overridden by explicitly specifying the name of the library. +The `link_name` attribute allows the name of the library to be specified. ~~~{.xfail-test} #[link_name = "crypto"] -extern mod mycrypto { } +extern { } ~~~ -The `nolink` attribute tells the Rust compiler not to do any linking for the foreign module. -This is particularly useful for creating foreign -modules for libc, which tends to not follow standard library naming -conventions and is linked to all Rust programs anyway. +The `nolink` attribute tells the Rust compiler +not to do any linking for the external block. +This is particularly useful for creating external blocks for libc, +which tends to not follow standard library naming conventions +and is linked to all Rust programs anyway. ## Attributes @@ -1425,6 +1424,8 @@ names are effectively reserved. Some significant attributes include: * The `test` attribute, for marking functions as unit tests. * The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint checks. Lint checks supported by the compiler can be found via `rustc -W help`. +* The `deriving` attribute, for automatically generating + implementations of certain traits. Other attributes may be added or removed during development of the language. @@ -1467,8 +1468,8 @@ A complete list of the built-in language items follows: : Elements can be subtracted. `mul` : Elements can be multiplied. -`quot` - : Elements have a quotient operation. +`div` + : Elements have a division operation. `rem` : Elements have a remainder operation. `neg` @@ -1526,6 +1527,47 @@ A complete list of the built-in language items follows: > **Note:** This list is likely to become out of date. We should auto-generate it > from `librustc/middle/lang_items.rs`. +### Deriving + +The `deriving` attribute allows certain traits to be automatically +implemented for data structures. For example, the following will +create an `impl` for the `Eq` and `Clone` traits for `Foo`, the type +parameter `T` will be given the `Eq` or `Clone` constraints for the +appropriate `impl`: + +~~~ +#[deriving(Eq, Clone)] +struct Foo { + a: int, + b: T +} +~~~ + +The generated `impl` for `Eq` is equivalent to + +~~~ +# struct Foo { a: int, b: T } +impl Eq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.a == other.a && self.b == other.b + } + + fn ne(&self, other: &Foo) -> bool { + self.a != other.a || self.b != other.b + } +} +~~~ + +Supported traits for `deriving` are: + +* Comparison traits: `Eq`, `TotalEq`, `Ord`, `TotalOrd`. +* Serialization: `Encodable`, `Decodable`. These require `std`. +* `Clone`, to perform deep copies. +* `IterBytes`, to iterate over the bytes in a data type. +* `Rand`, to create a random instance of a data type. +* `ToStr`, to convert to a string. For a type with this instance, + `obj.to_str()` has the same output as `fmt!("%?", obj)`. + # Statements and expressions Rust is _primarily_ an expression language. This means that most forms of @@ -1857,7 +1899,7 @@ The default meaning of the operators on standard types is given here. Calls the `mul` method on the `core::ops::Mul` trait. `/` : Quotient. - Calls the `quot` method on the `core::ops::Quot` trait. + Calls the `div` method on the `core::ops::Div` trait. `%` : Remainder. Calls the `rem` method on the `core::ops::Rem` trait. @@ -1946,35 +1988,6 @@ fn avg(v: &[float]) -> float { } ~~~~ -#### Swap expressions - -A _swap expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) followed by a bi-directional arrow (`<->`) and another [lvalue](#lvalues-rvalues-and-temporaries). - -Evaluating a swap expression causes, as a side effect, the values held in the left-hand-side and right-hand-side [lvalues](#lvalues-rvalues-and-temporaries) to be exchanged indivisibly. - -Evaluating a swap expression neither changes reference counts, -nor deeply copies any owned structure pointed to by the moved [rvalue](#lvalues-rvalues-and-temporaries). -Instead, the swap expression represents an indivisible *exchange of ownership*, -between the right-hand-side and the left-hand-side of the expression. -No allocation or destruction is entailed. - -An example of three different swap expressions: - -~~~~~~~~ -# let mut x = &mut [0]; -# let mut a = &mut [0]; -# let i = 0; -# struct S1 { z: int }; -# struct S2 { c: int }; -# let mut y = S1{z: 0}; -# let mut b = S2{c: 0}; - -x <-> a; -x[i] <-> a[i]; -y.z <-> b.c; -~~~~~~~~ - - #### Assignment expressions An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an @@ -2015,7 +2028,7 @@ as == != && || -= <-> += ~~~~ Operators at the same precedence level are evaluated left-to-right. @@ -2393,7 +2406,7 @@ variables in the arm's block, and control enters the block. An example of an `match` expression: -~~~~ {.xfail-test} +~~~~ # fn process_pair(a: int, b: int) { } # fn process_ten() { } @@ -3351,4 +3364,3 @@ Additional specific influences can be seen from the following languages: * The typeclass system of Haskell. * The lexical identifier rule of Python. * The block syntax of Ruby. - diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 127f81589234f..b2c2a8824eee6 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -150,35 +150,33 @@ wrapping `malloc` and `free`: ~~~~ use core::libc::{c_void, size_t, malloc, free}; - -#[abi = "rust-intrinsic"] -extern "rust-intrinsic" mod rusti { - fn init() -> T; -} +use core::unstable::intrinsics; +use core::util; // a wrapper around the handle returned by the foreign code pub struct Unique { priv ptr: *mut T } -pub impl<'self, T: Owned> Unique { +pub impl Unique { fn new(value: T) -> Unique { unsafe { let ptr = malloc(core::sys::size_of::() as size_t) as *mut T; assert!(!ptr::is_null(ptr)); - *ptr = value; + // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it + intrinsics::move_val_init(&mut *ptr, value); Unique{ptr: ptr} } } - // the 'self lifetime results in the same semantics as `&*x` with ~T - fn borrow(&self) -> &'self T { - unsafe { cast::transmute(self.ptr) } + // the 'r lifetime results in the same semantics as `&*x` with ~T + fn borrow<'r>(&'r self) -> &'r T { + unsafe { cast::copy_lifetime(self, &*self.ptr) } } - // the 'self lifetime results in the same semantics as `&mut *x` with ~T - fn borrow_mut(&mut self) -> &'self mut T { - unsafe { cast::transmute(self.ptr) } + // the 'r lifetime results in the same semantics as `&mut *x` with ~T + fn borrow_mut<'r>(&'r mut self) -> &'r mut T { + unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) } } } @@ -186,8 +184,9 @@ pub impl<'self, T: Owned> Unique { impl Drop for Unique { fn finalize(&self) { unsafe { - let mut x = rusti::init(); // dummy value to swap in - x <-> *self.ptr; // moving the object out is needed to call the destructor + let mut x = intrinsics::init(); // dummy value to swap in + // moving the object out is needed to call the destructor + util::replace_ptr(self.ptr, x); free(self.ptr as *c_void) } } @@ -238,7 +237,8 @@ convention to use: ~~~~ #[cfg(target_os = "win32")] #[abi = "stdcall"] -extern mod kernel32 { +#[link_name = "kernel32"] +extern { fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int; } ~~~~ diff --git a/doc/tutorial-macros.md b/doc/tutorial-macros.md index 24e9f4abc38e6..63fa7e06bae77 100644 --- a/doc/tutorial-macros.md +++ b/doc/tutorial-macros.md @@ -402,4 +402,3 @@ tricky. Invoking the `log_syntax!` macro can help elucidate intermediate states, invoking `trace_macros!(true)` will automatically print those intermediate states out, and passing the flag `--pretty expanded` as a command-line argument to the compiler will show the result of expansion. - diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index bed696748306e..053d9e6d98813 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -511,4 +511,3 @@ The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures one end of the communication channel. As a result, both parent and child can send and receive data to and from the other. - diff --git a/doc/tutorial.md b/doc/tutorial.md index 07eb3bc7681d7..4a680d0130325 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -129,7 +129,7 @@ we have a file `hello.rs` containing this program: ~~~~ fn main() { - io::println("hello?"); + println("hello?"); } ~~~~ @@ -139,12 +139,12 @@ Windows) which, upon running, will likely do exactly what you expect. The Rust compiler tries to provide useful information when it encounters an error. If you introduce an error into the program (for example, by changing -`io::println` to some nonexistent function), and then compile it, you'll see +`println` to some nonexistent function), and then compile it, you'll see an error message like this: ~~~~ {.notrust} -hello.rs:2:4: 2:16 error: unresolved name: io::print_with_unicorns -hello.rs:2 io::print_with_unicorns("hello?"); +hello.rs:2:4: 2:16 error: unresolved name: print_with_unicorns +hello.rs:2 print_with_unicorns("hello?"); ^~~~~~~~~~~~~~~~~~~~~~~ ~~~~ @@ -227,7 +227,7 @@ let hi = "hi"; let mut count = 0; while count < 10 { - io::println(fmt!("count: %?", count)); + println(fmt!("count: %?", count)); count += 1; } ~~~~ @@ -400,10 +400,10 @@ don't match the types of the arguments. ~~~~ # let mystery_object = (); -io::println(fmt!("%s is %d", "the answer", 43)); +println(fmt!("%s is %d", "the answer", 43)); // %? will conveniently print any type -io::println(fmt!("what is this thing: %?", mystery_object)); +println(fmt!("what is this thing: %?", mystery_object)); ~~~~ [pf]: http://en.cppreference.com/w/cpp/io/c/fprintf @@ -422,11 +422,11 @@ compulsory, an `if` can have an optional `else` clause, and multiple ~~~~ if false { - io::println("that's odd"); + println("that's odd"); } else if true { - io::println("right"); + println("right"); } else { - io::println("neither true nor false"); + println("neither true nor false"); } ~~~~ @@ -454,10 +454,10 @@ executes its corresponding arm. ~~~~ # let my_number = 1; match my_number { - 0 => io::println("zero"), - 1 | 2 => io::println("one or two"), - 3..10 => io::println("three to ten"), - _ => io::println("something else") + 0 => println("zero"), + 1 | 2 => println("one or two"), + 3..10 => println("three to ten"), + _ => println("something else") } ~~~~ @@ -483,8 +483,8 @@ commas are optional. ~~~ # let my_number = 1; match my_number { - 0 => { io::println("zero") } - _ => { io::println("something else") } + 0 => { println("zero") } + _ => { println("something else") } } ~~~ @@ -560,7 +560,7 @@ let mut x = 5; loop { x += x - 3; if x % 5 == 0 { break; } - io::println(int::to_str(x)); + println(int::to_str(x)); } ~~~~ @@ -614,8 +614,8 @@ origin.y += 1.0; // ERROR: assigning to immutable field # struct Point { x: float, y: float } # let mypoint = Point { x: 0.0, y: 0.0 }; match mypoint { - Point { x: 0.0, y: yy } => { io::println(yy.to_str()); } - Point { x: xx, y: yy } => { io::println(xx.to_str() + " " + yy.to_str()); } + Point { x: 0.0, y: yy } => { println(yy.to_str()); } + Point { x: xx, y: yy } => { println(xx.to_str() + " " + yy.to_str()); } } ~~~~ @@ -630,7 +630,7 @@ reuses the field name as the binding name. # struct Point { x: float, y: float } # let mypoint = Point { x: 0.0, y: 0.0 }; match mypoint { - Point { x, _ } => { io::println(x.to_str()) } + Point { x, _ } => { println(x.to_str()) } } ~~~ @@ -1006,9 +1006,9 @@ let mut d = @mut 5; // mutable variable, mutable box d = @mut 15; ~~~~ -A mutable variable and an immutable variable can refer to the same box, given -that their types are compatible. Mutability of a box is a property of its type, -however, so for example a mutable handle to an immutable box cannot be +A mutable variable and an immutable variable can refer to the same box, given +that their types are compatible. Mutability of a box is a property of its type, +however, so for example a mutable handle to an immutable box cannot be assigned a reference to a mutable box. ~~~~ @@ -1041,7 +1041,7 @@ let y = x.clone(); // y is a newly allocated box let z = x; // no new memory allocated, x can no longer be used ~~~~ -Since in owned boxes mutability is a property of the owner, not the +Since in owned boxes mutability is a property of the owner, not the box, mutable boxes may become immutable when they are moved, and vice-versa. ~~~~ @@ -1231,7 +1231,7 @@ something silly like ~~~ # struct Point { x: float, y: float } let point = &@~Point { x: 10f, y: 20f }; -io::println(fmt!("%f", point.x)); +println(fmt!("%f", point.x)); ~~~ The indexing operator (`[]`) also auto-dereferences. @@ -1373,7 +1373,6 @@ and [`core::str`]. Here are some examples. [`core::str`]: core/str.html ~~~ -# use core::io::println; # enum Crayon { # Almond, AntiqueBrass, Apricot, # Aquamarine, Asparagus, AtomicTangerine, @@ -1428,7 +1427,6 @@ Rust also supports _closures_, functions that can access variables in the enclosing scope. ~~~~ -# use println = core::io::println; fn call_closure_with_ten(b: &fn(int)) { b(10); } let captured_var = 20; @@ -1490,7 +1488,7 @@ fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str { fn main() { let shout = mk_appender(~"!"); - io::println(shout(~"hey ho, let's go")); + println(shout(~"hey ho, let's go")); } ~~~~ @@ -1632,7 +1630,6 @@ And using this function to iterate over a vector: ~~~~ # use each = core::vec::each; -# use println = core::io::println; each([2, 4, 8, 5, 16], |n| { if *n % 2 != 0 { println("found odd number!"); @@ -1649,7 +1646,6 @@ to the next iteration, write `loop`. ~~~~ # use each = core::vec::each; -# use println = core::io::println; for each([2, 4, 8, 5, 16]) |n| { if *n % 2 != 0 { println("found odd number!"); @@ -1982,7 +1978,7 @@ struct TimeBomb { impl Drop for TimeBomb { fn finalize(&self) { for old_iter::repeat(self.explosivity) { - io::println("blam!"); + println("blam!"); } } } @@ -2014,11 +2010,11 @@ and `~str`. ~~~~ # trait Printable { fn print(&self); } impl Printable for int { - fn print(&self) { io::println(fmt!("%d", *self)) } + fn print(&self) { println(fmt!("%d", *self)) } } impl Printable for ~str { - fn print(&self) { io::println(*self) } + fn print(&self) { println(*self) } } # 1.print(); @@ -2294,6 +2290,27 @@ let nonsense = mycircle.radius() * mycircle.area(); > ***Note:*** Trait inheritance does not actually work with objects yet +## Deriving implementations for traits + +A small number of traits in `core` and `std` can have implementations +that can be automatically derived. These instances are specified by +placing the `deriving` attribute on a data type declaration. For +example, the following will mean that `Circle` has an implementation +for `Eq` and can be used with the equality operators, and that a value +of type `ABC` can be randomly generated and converted to a string: + +~~~ +#[deriving(Eq)] +struct Circle { radius: float } + +#[deriving(Rand, ToStr)] +enum ABC { A, B, C } +~~~ + +The full list of derivable traits is `Eq`, `TotalEq`, `Ord`, +`TotalOrd`, `Encodable` `Decodable`, `Clone`, `IterBytes`, `Rand` and +`ToStr`. + # Modules and crates The Rust namespace is arranged in a hierarchy of modules. Each source @@ -2307,7 +2324,7 @@ mod farm { } fn main() { - io::println(farm::chicken()); + println(farm::chicken()); } ~~~~ @@ -2507,7 +2524,7 @@ pub fn explore() -> &str { "world" } ~~~~ {.xfail-test} // main.rs extern mod world; -fn main() { io::println(~"hello " + world::explore()); } +fn main() { println(~"hello " + world::explore()); } ~~~~ Now compile and run like this (adjust to your platform if necessary): diff --git a/doc/version_info.html.template b/doc/version_info.html.template index 9376b29bcdf63..aa44097a337e9 100644 --- a/doc/version_info.html.template +++ b/doc/version_info.html.template @@ -7,4 +7,3 @@ - diff --git a/mk/clean.mk b/mk/clean.mk index 30897eea45793..660793b1c347e 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -48,7 +48,7 @@ clean-misc: $(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF) $(Q)rm -Rf $(DOCS) $(Q)rm -Rf $(GENERATED) - $(Q)rm -f tmp/*.log tmp/*.rc tmp/*.rs tmp/*.ok + $(Q)rm -f tmp/* $(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist $(Q)rm -Rf $(foreach ext, \ html aux cp fn ky log pdf pg toc tp vr cps, \ diff --git a/mk/docs.mk b/mk/docs.mk index 6873d433e951f..f49c75d6acb01 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -16,15 +16,8 @@ DOCS := ###################################################################### -# Pandoc (reference-manual related) +# Docs, from pandoc, rustdoc (which runs pandoc), and node ###################################################################### -ifeq ($(CFG_PANDOC),) - $(info cfg: no pandoc found, omitting doc/rust.pdf) -else - - ifeq ($(CFG_NODE),) - $(info cfg: no node found, omitting doc/tutorial.html) - else doc/rust.css: rust.css @$(call E, cp: $@) @@ -34,6 +27,18 @@ doc/manual.css: manual.css @$(call E, cp: $@) $(Q)cp -a $< $@ 2> /dev/null +ifeq ($(CFG_PANDOC),) + $(info cfg: no pandoc found, omitting docs) + NO_DOCS = 1 +endif + +ifeq ($(CFG_NODE),) + $(info cfg: no node found, omitting docs) + NO_DOCS = 1 +endif + +ifneq ($(NO_DOCS),1) + DOCS += doc/rust.html doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css @$(call E, pandoc: $@) @@ -47,19 +52,8 @@ doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css --css=manual.css \ --include-before-body=doc/version_info.html \ --output=$@ - endif - ifeq ($(CFG_PDFLATEX),) - $(info cfg: no pdflatex found, omitting doc/rust.pdf) - else - ifeq ($(CFG_XETEX),) - $(info cfg: no xetex found, disabling doc/rust.pdf) - else - ifeq ($(CFG_LUATEX),) - $(info cfg: lacking luatex, disabling pdflatex) - else - -DOCS += doc/rust.pdf +DOCS += doc/rust.tex doc/rust.tex: rust.md doc/version.md @$(call E, pandoc: $@) $(Q)$(CFG_NODE) $(S)doc/prep.js $< | \ @@ -70,17 +64,6 @@ doc/rust.tex: rust.md doc/version.md --from=markdown --to=latex \ --output=$@ -doc/rust.pdf: doc/rust.tex - @$(call E, pdflatex: $@) - $(Q)$(CFG_PDFLATEX) \ - -interaction=batchmode \ - -output-directory=doc \ - $< - - endif - endif - endif - DOCS += doc/rustpkg.html doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css @$(call E, pandoc: $@) @@ -95,13 +78,6 @@ doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css --include-before-body=doc/version_info.html \ --output=$@ -###################################################################### -# Node (tutorial related) -###################################################################### - ifeq ($(CFG_NODE),) - $(info cfg: no node found, omitting doc/tutorial.html) - else - DOCS += doc/tutorial.html doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css @$(call E, pandoc: $@) @@ -153,9 +129,29 @@ doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css --include-before-body=doc/version_info.html \ --output=$@ + ifeq ($(CFG_PDFLATEX),) + $(info cfg: no pdflatex found, omitting doc/rust.pdf) + else + ifeq ($(CFG_XETEX),) + $(info cfg: no xetex found, disabling doc/rust.pdf) + else + ifeq ($(CFG_LUATEX),) + $(info cfg: lacking luatex, disabling pdflatex) + else + +DOCS += doc/rust.pdf +doc/rust.pdf: doc/rust.tex + @$(call E, pdflatex: $@) + $(Q)$(CFG_PDFLATEX) \ + -interaction=batchmode \ + -output-directory=doc \ + $< + + endif + endif endif -endif +endif # No pandoc / node ###################################################################### # LLnextgen (grammar analysis from refman) diff --git a/mk/host.mk b/mk/host.mk index 13a8a5401172a..92c6ffbbe172f 100644 --- a/mk/host.mk +++ b/mk/host.mk @@ -29,7 +29,9 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ + @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -39,7 +41,9 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ + @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \ @@ -51,7 +55,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \ @@ -59,13 +64,15 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4)) $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \ - $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ # Subtle: We do not let the shell expand $(CORELIB_DSYM_GLOB) directly rather @@ -82,7 +89,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)) \ - $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \ @@ -91,14 +99,16 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(HLIB$(2)_H_$(4))/libcore.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/libstd.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -106,15 +116,25 @@ $$(HLIB$(2)_H_$(4))/librustc.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ $$(HLIB$(2)_H_$(4))/libstd.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ +$$(HBIN$(2)_H_$(4))/: + mkdir -p $$@ + +ifneq ($(CFG_LIBDIR),bin) +$$(HLIB$(2)_H_$(4))/: + mkdir -p $$@ +endif + endef $(foreach t,$(CFG_HOST_TRIPLES), \ diff --git a/mk/install.mk b/mk/install.mk index a84f527a165b4..47fcb224a7348 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -154,3 +154,76 @@ uninstall: done $(Q)rm -Rf $(PHL)/rustc $(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1 + +# target platform specific variables +# for arm-linux-androidabi +define DEF_ADB_DEVICE_STATUS +CFG_ADB_DEVICE_STATUS=$(1) +endef + +$(foreach target,$(CFG_TARGET_TRIPLES), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring adb,$(CFG_ADB)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(info install: install-runtime-target for $(target) enabled \ + $(info install: android device attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ + $(info install: install-runtime-target for $(target) disabled \ + $(info install: android device not attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ + ), \ + $(info install: install-runtime-target for $(target) disabled \ + $(info install: adb not found) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ + ), \ + ) \ +) + +ifeq (install-runtime-target,$(firstword $(MAKECMDGOALS))) +$(eval $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)):;@:) +L_TOKEN := $(word 2,$(MAKECMDGOALS)) +ifeq ($(L_TOKEN),) +CFG_RUNTIME_PUSH_DIR=/system/lib +else +CFG_RUNTIME_PUSH_DIR=$(L_TOKEN) +endif + +ifeq ($(CFG_ADB_DEVICE_STATUS),true) +ifdef VERBOSE + ADB = adb $(1) + ADB_PUSH = adb push $(1) $(2) + ADB_SHELL = adb shell $(1) $(2) +else + ADB = $(Q)$(call E, adb $(1)) && adb $(1) 1>/dev/null + ADB_PUSH = $(Q)$(call E, adb push $(1)) && adb push $(1) $(2) 1>/dev/null + ADB_SHELL = $(Q)$(call E, adb shell $(1) $(2)) && adb shell $(1) $(2) 1>/dev/null +endif + +define INSTALL_RUNTIME_TARGET_N +install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2)) + $(Q)$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CORELIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) +endef + +define INSTALL_RUNTIME_TARGET_CLEANUP_N +install-runtime-target-$(1)-cleanup: + $(Q)$(call ADB,remount) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CFG_RUNTIME_$(1))) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CORELIB_GLOB_$(1))) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1))) +endef + +$(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD_TRIPLE))) +$(eval $(call INSTALL_RUNTIME_TARGET_CLEANUP_N,arm-linux-androideabi)) + +install-runtime-target: \ + install-runtime-target-arm-linux-androideabi-cleanup \ + install-runtime-target-arm-linux-androideabi-host-$(CFG_BUILD_TRIPLE) +else +install-runtime-target: + @echo "No device to install runtime library" + @echo +endif +endif diff --git a/mk/platform.mk b/mk/platform.mk index 1e102587bf4a0..efba83e6ad4c7 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -11,7 +11,7 @@ # Create variables HOST_ containing the host part # of each target triple. For example, the triple i686-darwin-macos -# would create a variable HOST_i686-darwin-macos with the value +# would create a variable HOST_i686-darwin-macos with the value # i386. define DEF_HOST_VAR HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1)))) @@ -247,12 +247,12 @@ AR_mips-unknown-linux-gnu=mips-linux-gnu-ar CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM -CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 +CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32 CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive -CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive -Wl,-znoexecstack +CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def CFG_INSTALL_NAME_mips-unknown-linux-gnu = CFG_LIBUV_LINK_FLAGS_mips-unknown-linux-gnu = @@ -276,8 +276,8 @@ CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -march=i686 CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 := -CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 := -CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 := +CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 := +CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 := CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def CFG_INSTALL_NAME_i686-pc-mingw32 = CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi diff --git a/mk/rt.mk b/mk/rt.mk index 015992abf7821..ab91dca62182c 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -1,27 +1,27 @@ # This is a procedure to define the targets for building -# the runtime. +# the runtime. # # Argument 1 is the target triple. # # This is not really the right place to explain this, but # for those of you who are not Makefile gurus, let me briefly -# cover the $ expansion system in use here, because it +# cover the $ expansion system in use here, because it # confused me for a while! The variable DEF_RUNTIME_TARGETS # will be defined once and then expanded with different # values substituted for $(1) each time it is called. -# That resulting text is then eval'd. +# That resulting text is then eval'd. # # For most variables, you could use a single $ sign. The result # is that the substitution would occur when the CALL occurs, # I believe. The problem is that the automatic variables $< and $@ # need to be expanded-per-rule. Therefore, for those variables at -# least, you need $$< and $$@ in the variable text. This way, after +# least, you need $$< and $$@ in the variable text. This way, after # the CALL substitution occurs, you will have $< and $@. This text # will then be evaluated, and all will work as you like. # # Reader beware, this explanantion could be wrong, but it seems to -# fit the experimental data (i.e., I was able to get the system -# working under these assumptions). +# fit the experimental data (i.e., I was able to get the system +# working under these assumptions). # Hack for passing flags into LIBUV, see below. LIBUV_FLAGS_i386 = -m32 -fPIC @@ -169,8 +169,8 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) else ifeq ($(OSTYPE_$(1)), linux-androideabi) $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ - LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ + CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ AR="$$(AR_$(1))" \ @@ -181,8 +181,8 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) else $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ - LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ + CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ AR="$$(AR_$(1))" \ diff --git a/mk/stage0.mk b/mk/stage0.mk index 7b5cbef1d72c3..ac1b3e86ac918 100644 --- a/mk/stage0.mk +++ b/mk/stage0.mk @@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \ $(S)src/etc/get-snapshot.py $(MKFILE_DEPS) @$(call E, fetch: $@) # Note: the variable "SNAPSHOT_FILE" is generally not set, and so -# we generally only pass one argument to this script. +# we generally only pass one argument to this script. ifdef CFG_ENABLE_LOCAL_RUST $(Q)$(S)src/etc/local_stage0.sh $(CFG_BUILD_TRIPLE) $(CFG_LOCAL_RUST_ROOT) -else +else $(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD_TRIPLE) $(SNAPSHOT_FILE) ifdef CFG_ENABLE_PAX_FLAGS @$(call E, apply PaX flags: $@) @"$(CFG_PAXCTL)" -cm "$@" endif -endif +endif $(Q)touch $@ # Host libs will be extracted by the above rule diff --git a/mk/target.mk b/mk/target.mk index fba1a6e0ee591..3cecc3940e62f 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -18,25 +18,29 @@ define TARGET_STAGE_N $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \ - rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a + rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \ - rt/$(2)/$(CFG_RUNTIME_$(2)) + rt/$(2)/$(CFG_RUNTIME_$(2)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)): \ $$(CORELIB_CRATE) $$(CORELIB_INPUTS) \ - $$(TSREQ$(1)_T_$(2)_H_$(3)) + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \ $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \ - $$(TSREQ$(1)_T_$(2)_H_$(3)) + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ @@ -44,7 +48,8 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \ $$(TSREQ$(1)_T_$(2)_H_$(3)) \ $$(TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3)) \ - $$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) + $$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@ @@ -52,20 +57,23 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ ifneq ($$(findstring $(2),$$(CFG_HOST_TRIPLES)),) $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \ - rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) + rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \ $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \ - $$(DRIVER_CRATE) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) + $$(DRIVER_CRATE) \ + $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \ + | $$(TBIN$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$< ifdef CFG_ENABLE_PAX_FLAGS @@ -75,6 +83,14 @@ endif endif +$$(TBIN$(1)_T_$(2)_H_$(3))/: + mkdir -p $$@ + +ifneq ($(CFG_LIBDIR),bin) +$$(TLIB$(1)_T_$(2)_H_$(3))/: + mkdir -p $$@ +endif + endef # In principle, each host can build each target: diff --git a/mk/tests.mk b/mk/tests.mk index f96b7325f60d4..8ac2ad68e3ab8 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -92,6 +92,43 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(eval $(call DEF_TARGET_COMMANDS,$(target)))) +# Target platform specific variables +# for arm-linux-androidabi +define DEF_ADB_DEVICE_STATUS +CFG_ADB_DEVICE_STATUS=$(1) +endef + +$(foreach target,$(CFG_TARGET_TRIPLES), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring adb,$(CFG_ADB)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(info check: $(target) test enabled \ + $(info check: android device attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ + $(info check: $(target) test disabled \ + $(info check: android device not attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ + ), \ + $(info check: $(target) test disabled \ + $(info check: adb not found) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ + ), \ + ) \ +) + +ifeq ($(CFG_ADB_DEVICE_STATUS),true) +CFG_ADB_TEST_DIR=/data/tmp + +$(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \ + $(shell adb remount 1>/dev/null) \ + $(shell adb shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ + $(shell adb push $(CFG_ANDROID_CROSS_PATH)/arm-linux-androideabi/lib/armv7-a/libgnustl_shared.so \ + $(CFG_ADB_TEST_DIR) 1>/dev/null) \ + ) +else +CFG_ADB_TEST_DIR= +endif + ###################################################################### # Main test targets @@ -179,9 +216,9 @@ tidy: $(Q)find $(S)src/etc -name '*.py' \ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py $(Q)echo $(ALL_CS) \ - | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py + | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py $(Q)echo $(ALL_HS) \ - | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py + | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py endif @@ -319,11 +356,53 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ && touch $$@ endef +define DEF_TEST_CRATE_RULES_arm-linux-androideabi +check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)) + +$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ + $(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2)) + @$$(call E, run: $$< via adb) + @$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR) + @$(CFG_ADB) shell LD_LIBRARY_PATH=$(CFG_ADB_TEST_DIR) \ + $(CFG_ADB_TEST_DIR)/`echo $$< | sed 's/.*\///'` \ + --logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log > \ + tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp + @cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp + @touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log + @$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/ + @$(CFG_ADB) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log + @if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + then \ + rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + touch $$@; \ + else \ + rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + exit 101; \ + fi +endef + +define DEF_TEST_CRATE_RULES_null +check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)) + +$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ + $(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2)) + @$$(call E, run: skipped $$< ) + @touch $$@ +endef + $(foreach host,$(CFG_HOST_TRIPLES), \ $(foreach target,$(CFG_TARGET_TRIPLES), \ $(foreach stage,$(STAGES), \ $(foreach crate, $(TEST_CRATES), \ - $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))))))) + $(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \ + $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring $(CFG_ADB_DEVICE_STATUS),"true"), \ + $(eval $(call DEF_TEST_CRATE_RULES_arm-linux-androideabi,$(stage),$(target),$(host),$(crate))), \ + $(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \ + ), \ + $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \ + )))))) ###################################################################### @@ -420,6 +499,9 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ + --target $(2) \ + --adb-path=$(CFG_ADB) \ + --adb-test-dir=$(CFG_ADB_TEST_DIR) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) @@ -454,7 +536,7 @@ ifeq ($$(CTEST_DISABLE_$(4)),) $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) - @$$(call E, run $(4): $$<) + @$$(call E, run $(4) [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ @@ -465,7 +547,7 @@ else $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) - @$$(call E, run $(4): $$<) + @$$(call E, run $(4) [$(2)]: $$<) @$$(call E, warning: tests disabled: $$(CTEST_DISABLE_$(4))) touch $$@ @@ -506,7 +588,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4 $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(PRETTY_DEPS_$(4)) - @$$(call E, run pretty-rpass: $$<) + @$$(call E, run pretty-rpass [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ @@ -533,7 +615,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3) $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ doc-$(4)-extract$(3) - @$$(call E, run doc-$(4): $$<) + @$$(call E, run doc-$(4) [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \ @@ -709,4 +791,3 @@ endef $(foreach host,$(CFG_HOST_TRIPLES), \ $(eval $(call DEF_CHECK_FAST_FOR_H,$(host)))) - diff --git a/mk/tools.mk b/mk/tools.mk index f2bc23633aeb5..2900aa711dc6d 100644 --- a/mk/tools.mk +++ b/mk/tools.mk @@ -111,6 +111,9 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \ $$(TSREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \ + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \ + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@ diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index e515ef302f658..38289f6274180 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -64,6 +64,18 @@ pub struct config { // Run tests using the new runtime newrt: bool, + // Target system to be tested + target: ~str, + + // Extra parameter to run adb on arm-linux-androideabi + adb_path: ~str, + + // Extra parameter to run test sute on arm-linux-androideabi + adb_test_dir: ~str, + + // status whether android device available or not + adb_device_status: bool, + // Explain what's going on verbose: bool diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 4392ce7ba2891..7f691cc199567 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -12,7 +12,6 @@ #[allow(vecs_implicitly_copyable)]; #[allow(non_camel_case_types)]; -#[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; extern mod std(vers = "0.7-pre"); @@ -60,7 +59,11 @@ pub fn parse_config(args: ~[~str]) -> config { getopts::optflag(~"verbose"), getopts::optopt(~"logfile"), getopts::optflag(~"jit"), - getopts::optflag(~"newrt")]; + getopts::optflag(~"newrt"), + getopts::optopt(~"target"), + getopts::optopt(~"adb-path"), + getopts::optopt(~"adb-test-dir") + ]; assert!(!args.is_empty()); let args_ = vec::tail(args); @@ -93,6 +96,18 @@ pub fn parse_config(args: ~[~str]) -> config { rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"), jit: getopts::opt_present(matches, ~"jit"), newrt: getopts::opt_present(matches, ~"newrt"), + target: opt_str(getopts::opt_maybe_str(matches, ~"target")), + adb_path: opt_str(getopts::opt_maybe_str(matches, ~"adb-path")), + adb_test_dir: opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")), + adb_device_status: + if (opt_str(getopts::opt_maybe_str(matches, ~"target")) == + ~"arm-linux-androideabi") { + if (opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"(none)" && + opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"") { true } + else { false } + } else { false }, verbose: getopts::opt_present(matches, ~"verbose") } } @@ -113,6 +128,10 @@ pub fn log_config(config: config) { logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags))); logv(c, fmt!("jit: %b", config.jit)); logv(c, fmt!("newrt: %b", config.newrt)); + logv(c, fmt!("target: %s", config.target)); + logv(c, fmt!("adb_path: %s", config.adb_path)); + logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir)); + logv(c, fmt!("adb_device_status: %b", config.adb_device_status)); logv(c, fmt!("verbose: %b", config.verbose)); logv(c, fmt!("\n")); } @@ -223,10 +242,3 @@ pub fn make_test_closure(config: config, testfile: &Path) -> test::TestFn { let testfile = testfile.to_str(); test::DynTestFn(|| runtest::run(config, testfile)) } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index b0d04c6739b4a..7e617aa000648 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -82,17 +82,16 @@ pub fn load_props(testfile: &Path) -> TestProps { } pub fn is_test_ignored(config: config, testfile: &Path) -> bool { - let mut found = false; for iter_header(testfile) |ln| { if parse_name_directive(ln, ~"xfail-test") { return true; } if parse_name_directive(ln, xfail_target()) { return true; } if config.mode == common::mode_pretty && parse_name_directive(ln, ~"xfail-pretty") { return true; } }; - return found; + return false; fn xfail_target() -> ~str { - ~"xfail-" + str::from_slice(os::SYSNAME) + ~"xfail-" + str::to_owned(os::SYSNAME) } } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index fef4cabf7fd6d..62c2612f2dda9 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -77,8 +77,20 @@ fn run_rfail_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"run-fail test isn't valgrind-clean!", ProcRes); } - check_correct_failure_status(ProcRes); - check_error_patterns(props, testfile, ProcRes); + match config.target { + + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { + check_correct_failure_status(ProcRes); + check_error_patterns(props, testfile, ProcRes); + } + } + + _=> { + check_correct_failure_status(ProcRes); + check_error_patterns(props, testfile, ProcRes); + } + } } fn check_correct_failure_status(ProcRes: ProcRes) { @@ -106,7 +118,7 @@ fn run_rpass_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"test run failed!", ProcRes); } } else { - let mut ProcRes = jit_test(config, props, testfile); + let ProcRes = jit_test(config, props, testfile); if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", ProcRes); } } @@ -359,7 +371,7 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], was_expected = true; } - if !was_expected && is_compiler_error_or_warning(str::from_slice(line)) { + if !was_expected && is_compiler_error_or_warning(str::to_owned(line)) { fatal_ProcRes(fmt!("unexpected compiler error or warning: '%s'", line), ProcRes); @@ -483,10 +495,23 @@ fn exec_compiled_test(config: config, props: TestProps, props.exec_env }; - compose_and_run(config, testfile, - make_run_args(config, props, testfile), - env, - config.run_lib_path, None) + match config.target { + + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { + _arm_exec_compiled_test(config, props, testfile) + } else { + _dummy_exec_compiled_test(config, props, testfile) + } + } + + _=> { + compose_and_run(config, testfile, + make_run_args(config, props, testfile), + env, + config.run_lib_path, None) + } + } } fn compose_and_run_compiler( @@ -516,6 +541,17 @@ fn compose_and_run_compiler( abs_ab.to_str()), auxres); } + + match config.target { + + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { + _arm_push_aux_shared_library(config, testfile); + } + } + + _=> { } + } } compose_and_run(config, testfile, args, ~[], @@ -560,7 +596,7 @@ fn make_lib_name(config: config, auxfile: &Path, testfile: &Path) -> Path { fn make_exe_name(config: config, testfile: &Path) -> Path { Path(output_base_name(config, testfile).to_str() + - str::from_slice(os::EXE_SUFFIX)) + str::to_owned(os::EXE_SUFFIX)) } fn make_run_args(config: config, _props: TestProps, testfile: &Path) -> @@ -700,3 +736,108 @@ stderr:\n\ io::stdout().write_str(msg); fail!(); } + +fn _arm_exec_compiled_test(config: config, props: TestProps, + testfile: &Path) -> ProcRes { + + let args = make_run_args(config, props, testfile); + let cmdline = make_cmdline(~"", args.prog, args.args); + + // get bare program string + let mut tvec = ~[]; + let tstr = args.prog; + for str::each_split_char(tstr, '/') |ts| { tvec.push(ts.to_owned()) } + let prog_short = tvec.pop(); + + // copy to target + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", args.prog, config.adb_test_dir], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, args.prog, + copy_result.out, copy_result.err)); + } + + // execute program + logv(config, fmt!("executing (%s) %s", config.target, cmdline)); + + // adb shell dose not forward stdout and stderr of internal result + // to stdout and stderr separately but to stdout only + let mut newargs_out = ~[]; + let mut newargs_err = ~[]; + let subargs = args.args; + newargs_out.push(~"shell"); + newargs_err.push(~"shell"); + + let mut newcmd_out = ~""; + let mut newcmd_err = ~""; + + newcmd_out.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); + + newcmd_err.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); + + for vec::each(subargs) |tv| { + newcmd_out.push_str(" "); + newcmd_err.push_str(" "); + newcmd_out.push_str(tv.to_owned()); + newcmd_err.push_str(tv.to_owned()); + } + + newcmd_out.push_str(" 2>/dev/null"); + newcmd_err.push_str(" 1>/dev/null"); + + newargs_out.push(newcmd_out); + newargs_err.push(newcmd_err); + + let exe_result_out = procsrv::run(~"", config.adb_path, + newargs_out, ~[(~"",~"")], Some(~"")); + let exe_result_err = procsrv::run(~"", config.adb_path, + newargs_err, ~[(~"",~"")], Some(~"")); + + dump_output(config, testfile, exe_result_out.out, exe_result_err.out); + + match exe_result_err.out { + ~"" => ProcRes {status: exe_result_out.status, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline }, + _ => ProcRes {status: 101, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline } + } +} + +fn _dummy_exec_compiled_test(config: config, props: TestProps, + testfile: &Path) -> ProcRes { + + let args = make_run_args(config, props, testfile); + let cmdline = make_cmdline(~"", args.prog, args.args); + + match config.mode { + mode_run_fail => ProcRes {status: 101, stdout: ~"", + stderr: ~"", cmdline: cmdline}, + _ => ProcRes {status: 0, stdout: ~"", + stderr: ~"", cmdline: cmdline} + } +} + +fn _arm_push_aux_shared_library(config: config, testfile: &Path) { + let tstr = aux_output_dir_name(config, testfile).to_str(); + + for os::list_dir_path(&Path(tstr)).each |file| { + + if (file.filetype() == Some(~".so")) { + + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", file.to_str(), config.adb_test_dir], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, file.to_str(), + copy_result.out, copy_result.err)); + } + } + } +} diff --git a/src/driver/driver.rs b/src/driver/driver.rs index d3ab066929731..70dc9e895c01e 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[no_core]; -extern mod core(vers = "0.7-pre"); - #[cfg(rustpkg)] extern mod this(name = "rustpkg", vers = "0.7-pre"); diff --git a/src/etc/check-links.pl b/src/etc/check-links.pl index a280ed55ba93f..6492be53d3481 100755 --- a/src/etc/check-links.pl +++ b/src/etc/check-links.pl @@ -9,7 +9,7 @@ my $i = 0; foreach $line (@lines) { $i++; - if ($line =~ m/id="([^"]+)"/) { + if ($line =~ m/id="([^"]+)"/) { $anchors->{$1} = $i; } } @@ -17,10 +17,9 @@ $i = 0; foreach $line (@lines) { $i++; - while ($line =~ m/href="#([^"]+)"/g) { + while ($line =~ m/href="#([^"]+)"/g) { if (! exists($anchors->{$1})) { print "$file:$i: $1 referenced\n"; } } } - diff --git a/src/etc/gedit/readme.txt b/src/etc/gedit/readme.txt index 735b023627662..e394f1916088f 100644 --- a/src/etc/gedit/readme.txt +++ b/src/etc/gedit/readme.txt @@ -8,4 +8,3 @@ Instructions for Ubuntu Linux 12.04+ 2) Copy the included "share" folder into "~/.local/" 3) Open a shell in "~/.local/share/" and run "update-mime-database mime" - diff --git a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang index 0b23808b76524..a413d0a906222 100644 --- a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang +++ b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang @@ -123,11 +123,11 @@ mode_t ssize_t - + self - + true false @@ -261,4 +261,3 @@ - diff --git a/src/etc/gedit/share/mime/packages/rust.xml b/src/etc/gedit/share/mime/packages/rust.xml index 65168aae1d909..d75cffe960073 100644 --- a/src/etc/gedit/share/mime/packages/rust.xml +++ b/src/etc/gedit/share/mime/packages/rust.xml @@ -2,6 +2,6 @@ Rust Source - + diff --git a/src/etc/indenter b/src/etc/indenter index 017cb926981fb..1a3a446533572 100755 --- a/src/etc/indenter +++ b/src/etc/indenter @@ -14,4 +14,3 @@ while (<>) { $indent -= 1; } } - diff --git a/src/etc/latest-unix-snaps.py b/src/etc/latest-unix-snaps.py index 7a2ddba3a16aa..7cecf83716160 100755 --- a/src/etc/latest-unix-snaps.py +++ b/src/etc/latest-unix-snaps.py @@ -52,5 +52,3 @@ def download_new_file (date, rev, platform, hsh): for ff in newestSet["files"]: download_new_file (newestSet["date"], newestSet["rev"], ff["platform"], ff["hash"]) - - diff --git a/src/etc/libc.c b/src/etc/libc.c index 9acc122f32b99..e341f495eebb9 100644 --- a/src/etc/libc.c +++ b/src/etc/libc.c @@ -243,4 +243,3 @@ int main() { extra_consts(); printf("}\n"); } - diff --git a/src/etc/licenseck.py b/src/etc/licenseck.py index 973b7deb960db..1e0c541cd8927 100644 --- a/src/etc/licenseck.py +++ b/src/etc/licenseck.py @@ -96,4 +96,3 @@ def check_license(name, contents): return True return False - diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index 5898bc561aac3..8d2fd887e3ff7 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -1,13 +1,13 @@ #!/bin/sh -TARG_DIR=$1 +TARG_DIR=$1 PREFIX=$2 BINDIR=bin LIBDIR=lib OS=`uname -s` -case $OS in +case $OS in ("Linux"|"FreeBSD") BIN_SUF= LIB_SUF=.so diff --git a/src/etc/mirror-all-snapshots.py b/src/etc/mirror-all-snapshots.py index f1fce7a94b5b6..3b5f66c411730 100644 --- a/src/etc/mirror-all-snapshots.py +++ b/src/etc/mirror-all-snapshots.py @@ -33,6 +33,3 @@ print("got download with ok hash") else: raise Exception("bad hash on download") - - - diff --git a/src/etc/monodebug.pl b/src/etc/monodebug.pl index 324c576a4bda8..a2d27591cad93 100755 --- a/src/etc/monodebug.pl +++ b/src/etc/monodebug.pl @@ -77,4 +77,3 @@ } print "\n"; } - diff --git a/src/etc/sugarise-doc-comments.py b/src/etc/sugarise-doc-comments.py index 6399cff6b880d..7bd4175fbf0db 100755 --- a/src/etc/sugarise-doc-comments.py +++ b/src/etc/sugarise-doc-comments.py @@ -80,4 +80,3 @@ def sugarise_file(path): for (dirpath, dirnames, filenames) in os.walk('.'): for name in fnmatch.filter(filenames, '*.r[sc]'): sugarise_file(os.path.join(dirpath, name)) - diff --git a/src/etc/tidy.py b/src/etc/tidy.py index a5cf6141567be..06fcb5cb94586 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -81,4 +81,3 @@ def do_license_check(name, contents): sys.exit(err) - diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 864cf3daee07e..afb3d16848085 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -235,6 +235,10 @@ def emit_decomp_module(f, canon, compat): rf = open(r, "w") (canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt") + +# Explain that the source code was generated by this script. +rf.write('// The following code was generated by "src/etc/unicode.py"\n\n') + emit_property_module(rf, "general_category", gencats) #emit_decomp_module(rf, canon_decomp, compat_decomp) diff --git a/src/etc/vim/after/ftplugin/rust.vim b/src/etc/vim/after/ftplugin/rust.vim index f0f1c85ee9720..a053f8b40f863 100644 --- a/src/etc/vim/after/ftplugin/rust.vim +++ b/src/etc/vim/after/ftplugin/rust.vim @@ -1,5 +1,5 @@ "Highlight the 100th text column "Feature became available in v7.3 if version >= 703 - set colorcolumn=100 + setlocal colorcolumn=100 endif diff --git a/src/etc/vim/after/syntax/rust.vim b/src/etc/vim/after/syntax/rust.vim index 58a623cb4e478..75afe3d03684f 100644 --- a/src/etc/vim/after/syntax/rust.vim +++ b/src/etc/vim/after/syntax/rust.vim @@ -1,4 +1,4 @@ -if exists('g:no_rust_conceal') || !has('conceal') || &enc != 'utf-8' +if !exists('g:rust_conceal') || !has('conceal') || &enc != 'utf-8' finish endif diff --git a/src/etc/vim/indent/rust.vim b/src/etc/vim/indent/rust.vim index 43fd917fc97bb..8d973c9a87069 100644 --- a/src/etc/vim/indent/rust.vim +++ b/src/etc/vim/indent/rust.vim @@ -5,4 +5,7 @@ if exists("b:did_indent") endif let b:did_indent = 1 -setlocal smartindent + +setlocal cindent +setlocal cinoptions=L0,(0,Ws,JN +setlocal cinkeys=0{,0},!^F,o,O diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index eab3627ae16d1..3b5324f5cced3 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -29,7 +29,7 @@ syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:spac syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained " Reserved words -syn keyword rustKeyword m32 m64 m128 f80 f16 f128 be +"syn keyword rustKeyword m32 m64 m128 f80 f16 f128 be " These are obsolete syn keyword rustType int uint float char bool u8 u16 u32 u64 f32 syn keyword rustType f64 i8 i16 i32 i64 str Self diff --git a/src/etc/x86.supp b/src/etc/x86.supp index 417f4c9d2c199..def1c5a53c1fd 100644 --- a/src/etc/x86.supp +++ b/src/etc/x86.supp @@ -366,7 +366,7 @@ ... } -{ +{ llvm-user-new-leak Memcheck:Leak fun:_Znwj @@ -401,7 +401,7 @@ Helgrind:Race fun:_ZN15lock_and_signal27lock_held_by_current_threadEv ... -} +} { lock_and_signal-probably-threadsafe-access-outside-of-lock2 diff --git a/src/etc/ziggurat_tables.py b/src/etc/ziggurat_tables.py new file mode 100755 index 0000000000000..c8f873037d8cc --- /dev/null +++ b/src/etc/ziggurat_tables.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# xfail-license + +# This creates the tables used for distributions implemented using the +# ziggurat algorithm in `core::rand::distributions;`. They are +# (basically) the tables as used in the ZIGNOR variant (Doornik 2005). +# They are changed rarely, so the generated file should be checked in +# to git. +# +# It creates 3 tables: X as in the paper, F which is f(x_i), and +# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached +# values which is not done in that paper (but is done in other +# variants). Note that the adZigR table is unnecessary because of +# algebra. +# +# It is designed to be compatible with Python 2 and 3. + +from math import exp, sqrt, log, floor +import random + +# The order should match the return value of `tables` +TABLE_NAMES = ['X', 'F', 'F_DIFF'] + +# The actual length of the table is 1 more, to stop +# index-out-of-bounds errors. This should match the bitwise operation +# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and +# *_V constants below depend on this value. +TABLE_LEN = 256 + +# equivalent to `zigNorInit` in Doornik2005, but generalised to any +# distribution. r = dR, v = dV, f = probability density function, +# f_inv = inverse of f +def tables(r, v, f, f_inv): + # compute the x_i + xvec = [0]*(TABLE_LEN+1) + + xvec[0] = v / f(r) + xvec[1] = r + + for i in range(2, TABLE_LEN): + last = xvec[i-1] + xvec[i] = f_inv(v / last + f(last)) + + # cache the f's + fvec = [0]*(TABLE_LEN+1) + fdiff = [0]*(TABLE_LEN+1) + for i in range(TABLE_LEN+1): + fvec[i] = f(xvec[i]) + if i > 0: + fdiff[i] = fvec[i] - fvec[i-1] + + return xvec, fvec, fdiff + +# Distributions +# N(0, 1) +def norm_f(x): + return exp(-x*x/2.0) +def norm_f_inv(y): + return sqrt(-2.0*log(y)) + +NORM_R = 3.6541528853610088 +NORM_V = 0.00492867323399 + +NORM = tables(NORM_R, NORM_V, + norm_f, norm_f_inv) + +# Exp(1) +def exp_f(x): + return exp(-x) +def exp_f_inv(y): + return -log(y) + +EXP_R = 7.69711747013104972 +EXP_V = 0.0039496598225815571993 + +EXP = tables(EXP_R, EXP_V, + exp_f, exp_f_inv) + + +# Output the tables/constants/types + +def render_static(name, type, value): + # no space or + return 'pub static %s: %s =%s;\n' % (name, type, value) + +# static `name`: [`type`, .. `len(values)`] = +# [values[0], ..., values[3], +# values[4], ..., values[7], +# ... ]; +def render_table(name, values): + rows = [] + # 4 values on each row + for i in range(0, len(values), 4): + row = values[i:i+4] + rows.append(', '.join('%.18f' % f for f in row)) + + rendered = '\n [%s]' % ',\n '.join(rows) + return render_static(name, '[f64, .. %d]' % len(values), rendered) + + +with open('ziggurat_tables.rs', 'w') as f: + f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &\'static [f64, .. %d]; +''' % (TABLE_LEN + 1)) + for name, tables, r in [('NORM', NORM, NORM_R), + ('EXP', EXP, EXP_R)]: + f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r)) + for (tabname, table) in zip(TABLE_NAMES, tables): + f.write(render_table('ZIG_%s_%s' % (name, tabname), table)) diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs index 9f59f1d8fe48d..d0f9a4ff90f1e 100644 --- a/src/libcore/at_vec.rs +++ b/src/libcore/at_vec.rs @@ -11,8 +11,10 @@ //! Managed vectors use cast::transmute; +use container::Container; use kinds::Copy; use old_iter; +use old_iter::BaseIter; use option::Option; use sys; use uint; @@ -29,9 +31,9 @@ pub mod rustrt { #[abi = "cdecl"] #[link_name = "rustrt"] pub extern { - pub unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc, - ++v: **vec::raw::VecRepr, - ++n: libc::size_t); + pub unsafe fn vec_reserve_shared_actual(t: *sys::TypeDesc, + v: **vec::raw::VecRepr, + n: libc::size_t); } } @@ -52,7 +54,7 @@ pub fn capacity(v: @[T]) -> uint { * # Arguments * * * size - An initial size of the vector to reserve - * * builder - A function that will construct the vector. It recieves + * * builder - A function that will construct the vector. It receives * as an argument a function that will push an element * onto the vector being constructed. */ @@ -60,7 +62,7 @@ pub fn capacity(v: @[T]) -> uint { pub fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { let mut vec: @[A] = @[]; unsafe { raw::reserve(&mut vec, size); } - builder(|+x| unsafe { raw::push(&mut vec, x) }); + builder(|x| unsafe { raw::push(&mut vec, x) }); return unsafe { transmute(vec) }; } @@ -70,7 +72,7 @@ pub fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { * * # Arguments * - * * builder - A function that will construct the vector. It recieves + * * builder - A function that will construct the vector. It receives * as an argument a function that will push an element * onto the vector being constructed. */ @@ -87,7 +89,7 @@ pub fn build(builder: &fn(push: &fn(v: A))) -> @[A] { * # Arguments * * * size - An option, maybe containing initial size of the vector to reserve - * * builder - A function that will construct the vector. It recieves + * * builder - A function that will construct the vector. It receives * as an argument a function that will push an element * onto the vector being constructed. */ @@ -102,7 +104,7 @@ pub fn build_sized_opt(size: Option, #[inline(always)] pub fn append(lhs: @[T], rhs: &const [T]) -> @[T] { do build_sized(lhs.len() + rhs.len()) |push| { - for vec::each(lhs) |x| { push(*x); } + for lhs.each |x| { push(*x); } for uint::range(0, rhs.len()) |i| { push(rhs[i]); } } } @@ -111,7 +113,7 @@ pub fn append(lhs: @[T], rhs: &const [T]) -> @[T] { /// Apply a function to each element of a vector and return the results pub fn map(v: &[T], f: &fn(x: &T) -> U) -> @[U] { do build_sized(v.len()) |push| { - for vec::each(v) |elem| { + for v.each |elem| { push(f(elem)); } } @@ -166,7 +168,7 @@ pub fn from_slice(v: &[T]) -> @[T] { from_fn(v.len(), |i| v[i]) } -#[cfg(notest)] +#[cfg(not(test))] pub mod traits { use at_vec::append; use kinds::Copy; diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 6c60cec2595ef..76a8f456cd5f3 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -10,7 +10,7 @@ //! Boolean logic -#[cfg(notest)] +#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering}; use option::{None, Option, Some}; use from_str::FromStr; @@ -75,7 +75,7 @@ pub fn all_values(blk: &fn(v: bool)) { #[inline(always)] pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for bool { #[inline(always)] fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) } @@ -87,13 +87,13 @@ impl Ord for bool { fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for bool { #[inline(always)] fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for bool { #[inline(always)] fn eq(&self, other: &bool) -> bool { (*self) == (*other) } @@ -108,8 +108,6 @@ mod tests { #[test] fn test_bool_from_str() { - use from_str::FromStr; - do all_values |v| { assert!(Some(v) == FromStr::from_str(to_str(v))) } diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 6fb737d37709f..7451353458e28 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -17,37 +17,27 @@ pub mod rusti { #[abi = "rust-intrinsic"] #[link_name = "rusti"] pub extern "rust-intrinsic" { - fn forget(+x: T); + fn forget(x: T); - #[cfg(stage0)] - fn reinterpret_cast(&&e: T) -> U; - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn transmute(e: T) -> U; } } /// Casts the value at `src` to U. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn reinterpret_cast(src: &T) -> U { - rusti::reinterpret_cast(*src) -} - -/// Unsafely copies and casts the value at `src` to U, even if the value is -/// noncopyable. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] +#[cfg(not(stage0))] pub unsafe fn transmute_copy(src: &T) -> U { - rusti::reinterpret_cast(*src) + let mut dest: U = unstable::intrinsics::uninit(); + { + let dest_ptr: *mut u8 = rusti::transmute(&mut dest); + let src_ptr: *u8 = rusti::transmute(src); + unstable::intrinsics::memmove64(dest_ptr, + src_ptr, + sys::size_of::() as u64); + } + dest } -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(stage0)] pub unsafe fn transmute_copy(src: &T) -> U { let mut dest: U = unstable::intrinsics::init(); { @@ -88,17 +78,6 @@ pub unsafe fn bump_box_refcount(t: @T) { forget(t); } * assert!(transmute("L") == ~[76u8, 0u8]); */ #[inline(always)] -#[cfg(stage0)] -pub unsafe fn transmute(thing: L) -> G { - let newthing: G = reinterpret_cast(&thing); - forget(thing); - newthing -} - -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub unsafe fn transmute(thing: L) -> G { rusti::transmute(thing) } @@ -143,6 +122,12 @@ pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T { transmute_region(ptr) } +/// Transforms lifetime of the second pointer to match the first. +#[inline(always)] +pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T { + transmute_mut_region(ptr) +} + /// Transforms lifetime of the second pointer to match the first. #[inline(always)] pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { @@ -159,15 +144,6 @@ mod tests { use cast::{bump_box_refcount, transmute}; #[test] - #[cfg(stage0)] - fn test_reinterpret_cast() { - assert!(1u == unsafe { ::cast::reinterpret_cast(&1) }); - } - - #[test] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn test_transmute_copy() { assert!(1u == unsafe { ::cast::transmute_copy(&1) }); } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 27e03d2bf3103..6f0e03fb89501 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -12,6 +12,7 @@ use cast::transmute_mut; use prelude::*; +use util::replace; /* A dynamic, mutable location. @@ -19,6 +20,7 @@ A dynamic, mutable location. Similar to a mutable option type, but friendlier. */ +#[mutable] pub struct Cell { priv value: Option } @@ -42,23 +44,21 @@ pub fn empty_cell() -> Cell { pub impl Cell { /// Yields the value, failing if the cell is empty. fn take(&self) -> T { - let mut self = unsafe { transmute_mut(self) }; - if self.is_empty() { + let this = unsafe { transmute_mut(self) }; + if this.is_empty() { fail!(~"attempt to take an empty cell"); } - let mut value = None; - value <-> self.value; - value.unwrap() + replace(&mut this.value, None).unwrap() } /// Returns the value, failing if the cell is full. fn put_back(&self, value: T) { - let mut self = unsafe { transmute_mut(self) }; - if !self.is_empty() { + let this = unsafe { transmute_mut(self) }; + if !this.is_empty() { fail!(~"attempt to put a value back into a full cell"); } - self.value = Some(value); + this.value = Some(value); } /// Returns true if the cell is empty and false if the cell is full. diff --git a/src/libcore/char.rs b/src/libcore/char.rs index ef2bd91e97313..a9c46b81f862e 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,14 +10,15 @@ //! Utilities for manipulating the char type +#[cfg(not(test))] use cmp::Ord; use option::{None, Option, Some}; use str; use u32; use uint; -use unicode; +use unicode::{derived_property, general_category}; -#[cfg(notest)] use cmp::Eq; +#[cfg(not(test))] use cmp::Eq; /* Lu Uppercase_Letter an uppercase letter @@ -52,10 +53,9 @@ use unicode; Cn Unassigned a reserved unassigned code point or a noncharacter */ -pub use is_alphabetic = unicode::derived_property::Alphabetic; -pub use is_XID_start = unicode::derived_property::XID_Start; -pub use is_XID_continue = unicode::derived_property::XID_Continue; - +pub fn is_alphabetic(c: char) -> bool { derived_property::Alphabetic(c) } +pub fn is_XID_start(c: char) -> bool { derived_property::XID_Start(c) } +pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) } /** * Indicates whether a character is in lower case, defined @@ -63,7 +63,7 @@ pub use is_XID_continue = unicode::derived_property::XID_Continue; */ #[inline(always)] pub fn is_lowercase(c: char) -> bool { - return unicode::general_category::Ll(c); + return general_category::Ll(c); } /** @@ -72,7 +72,7 @@ pub fn is_lowercase(c: char) -> bool { */ #[inline(always)] pub fn is_uppercase(c: char) -> bool { - return unicode::general_category::Lu(c); + return general_category::Lu(c); } /** @@ -83,9 +83,9 @@ pub fn is_uppercase(c: char) -> bool { #[inline(always)] pub fn is_whitespace(c: char) -> bool { return ('\x09' <= c && c <= '\x0d') - || unicode::general_category::Zs(c) - || unicode::general_category::Zl(c) - || unicode::general_category::Zp(c); + || general_category::Zs(c) + || general_category::Zl(c) + || general_category::Zp(c); } /** @@ -95,18 +95,18 @@ pub fn is_whitespace(c: char) -> bool { */ #[inline(always)] pub fn is_alphanumeric(c: char) -> bool { - return unicode::derived_property::Alphabetic(c) || - unicode::general_category::Nd(c) || - unicode::general_category::Nl(c) || - unicode::general_category::No(c); + return derived_property::Alphabetic(c) || + general_category::Nd(c) || + general_category::Nl(c) || + general_category::No(c); } /// Indicates whether the character is numeric (Nd, Nl, or No) #[inline(always)] pub fn is_digit(c: char) -> bool { - return unicode::general_category::Nd(c) || - unicode::general_category::Nl(c) || - unicode::general_category::No(c); + return general_category::Nd(c) || + general_category::Nl(c) || + general_category::No(c); } /** @@ -244,7 +244,7 @@ pub fn len_utf8_bytes(c: char) -> uint { else { fail!(~"invalid character!") } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for char { #[inline(always)] fn eq(&self, other: &char) -> bool { (*self) == (*other) } @@ -252,7 +252,7 @@ impl Eq for char { fn ne(&self, other: &char) -> bool { (*self) != (*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for char { #[inline(always)] fn lt(&self, other: &char) -> bool { *self < *other } diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index a07c6b4811b6c..a5df97e3d574f 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -15,8 +15,9 @@ use ptr::mut_null; use repr::BoxRepr; use sys::TypeDesc; use cast::transmute; +#[cfg(not(test))] use unstable::lang::clear_task_borrow_list; -#[cfg(notest)] use ptr::to_unsafe_ptr; +#[cfg(not(test))] use ptr::to_unsafe_ptr; /** * Runtime structures @@ -126,24 +127,59 @@ struct AnnihilateStats { n_bytes_freed: uint } -unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { +#[cfg(stage0)] +unsafe fn each_live_alloc(read_next_before: bool, + f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { + //! Walks the internal list of allocations + use managed; let task: *Task = transmute(rustrt::rust_get_task()); let box = (*task).boxed_region.live_allocs; let mut box: *mut BoxRepr = transmute(copy box); while box != mut_null() { - let next = transmute(copy (*box).header.next); + let next_before = transmute(copy (*box).header.next); let uniq = (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; - if ! f(box, uniq) { - break + if !f(box, uniq) { + return; } - box = next + if read_next_before { + box = next_before; + } else { + box = transmute(copy (*box).header.next); + } } } +#[cfg(not(stage0))] +unsafe fn each_live_alloc(read_next_before: bool, + f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) -> bool { + //! Walks the internal list of allocations + + use managed; + + let task: *Task = transmute(rustrt::rust_get_task()); + let box = (*task).boxed_region.live_allocs; + let mut box: *mut BoxRepr = transmute(copy box); + while box != mut_null() { + let next_before = transmute(copy (*box).header.next); + let uniq = + (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; + + if !f(box, uniq) { + return false; + } + + if read_next_before { + box = next_before; + } else { + box = transmute(copy (*box).header.next); + } + } + return true; +} #[cfg(unix)] fn debug_mem() -> bool { @@ -156,7 +192,7 @@ fn debug_mem() -> bool { } /// Destroys all managed memory (i.e. @ boxes) held by the current task. -#[cfg(notest)] +#[cfg(not(test))] #[lang="annihilate"] pub unsafe fn annihilate() { use unstable::lang::local_free; @@ -172,8 +208,15 @@ pub unsafe fn annihilate() { n_bytes_freed: 0 }; + // Quick hack: we need to free this list upon task exit, and this + // is a convenient place to do it. + clear_task_borrow_list(); + // Pass 1: Make all boxes immortal. - for each_live_alloc |box, uniq| { + // + // In this pass, nothing gets freed, so it does not matter whether + // we read the next field before or after the callback. + for each_live_alloc(true) |box, uniq| { stats.n_total_boxes += 1; if uniq { stats.n_unique_boxes += 1; @@ -183,7 +226,11 @@ pub unsafe fn annihilate() { } // Pass 2: Drop all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, unique-managed boxes may get freed, but not + // managed boxes, so we must read the `next` field *after* the + // callback, as the original value may have been freed. + for each_live_alloc(false) |box, uniq| { if !uniq { let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); @@ -192,7 +239,12 @@ pub unsafe fn annihilate() { } // Pass 3: Free all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, managed boxes may get freed (but not + // unique-managed boxes, though I think that none of those are + // left), so we must read the `next` field before, since it will + // not be valid after. + for each_live_alloc(true) |box, uniq| { if !uniq { stats.n_bytes_freed += (*((*box).header.type_desc)).size @@ -226,4 +278,3 @@ pub mod rustrt { pub unsafe fn rust_get_task() -> *c_void; } } - diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b933b60a39f1f..80f1f05961a5d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -66,6 +66,13 @@ totaleq_impl!(uint) totaleq_impl!(char) +/// Trait for testing approximate equality +pub trait ApproxEq { + fn approx_epsilon() -> Eps; + fn approx_eq(&self, other: &Self) -> bool; + fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool; +} + #[deriving(Clone, Eq)] pub enum Ordering { Less = -1, Equal = 0, Greater = 1 } diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs index 50a3bba049bbb..f4eb856865d07 100644 --- a/src/libcore/comm.rs +++ b/src/libcore/comm.rs @@ -12,14 +12,16 @@ Message passing */ -use cast; +use cast::{transmute, transmute_mut}; +use container::Container; use either::{Either, Left, Right}; use kinds::Owned; use option::{Option, Some, None}; use uint; -use unstable; use vec; -use unstable::Exclusive; +use vec::OwnedVector; +use util::replace; +use unstable::sync::{Exclusive, exclusive}; use pipes::{recv, try_recv, wait_many, peek, PacketHeader}; @@ -118,13 +120,15 @@ pub mod streamp { } /// An endpoint that can send many messages. +#[unsafe_mut_field(endp)] pub struct Chan { - mut endp: Option> + endp: Option> } /// An endpoint that can receive many messages. +#[unsafe_mut_field(endp)] pub struct Port { - mut endp: Option>, + endp: Option>, } /** Creates a `(Port, Chan)` pair. @@ -135,30 +139,37 @@ These allow sending or receiving an unlimited number of messages. pub fn stream() -> (Port, Chan) { let (c, s) = streamp::init(); - (Port { endp: Some(s) }, Chan { endp: Some(c) }) + (Port { + endp: Some(s) + }, Chan { + endp: Some(c) + }) } impl GenericChan for Chan { #[inline(always)] fn send(&self, x: T) { - let mut endp = None; - endp <-> self.endp; - self.endp = Some( - streamp::client::data(endp.unwrap(), x)) + unsafe { + let self_endp = transmute_mut(&self.endp); + let endp = replace(self_endp, None); + *self_endp = Some(streamp::client::data(endp.unwrap(), x)) + } } } impl GenericSmartChan for Chan { #[inline(always)] fn try_send(&self, x: T) -> bool { - let mut endp = None; - endp <-> self.endp; - match streamp::client::try_data(endp.unwrap(), x) { - Some(next) => { - self.endp = Some(next); - true + unsafe { + let self_endp = transmute_mut(&self.endp); + let endp = replace(self_endp, None); + match streamp::client::try_data(endp.unwrap(), x) { + Some(next) => { + *self_endp = Some(next); + true + } + None => false } - None => false } } } @@ -166,23 +177,27 @@ impl GenericSmartChan for Chan { impl GenericPort for Port { #[inline(always)] fn recv(&self) -> T { - let mut endp = None; - endp <-> self.endp; - let streamp::data(x, endp) = recv(endp.unwrap()); - self.endp = Some(endp); - x + unsafe { + let self_endp = transmute_mut(&self.endp); + let endp = replace(self_endp, None); + let streamp::data(x, endp) = recv(endp.unwrap()); + *self_endp = Some(endp); + x + } } #[inline(always)] fn try_recv(&self) -> Option { - let mut endp = None; - endp <-> self.endp; - match try_recv(endp.unwrap()) { - Some(streamp::data(x, endp)) => { - self.endp = Some(endp); - Some(x) + unsafe { + let self_endp = transmute_mut(&self.endp); + let endp = replace(self_endp, None); + match try_recv(endp.unwrap()) { + Some(streamp::data(x, endp)) => { + *self_endp = Some(endp); + Some(x) + } + None => None } - None => None } } } @@ -190,35 +205,35 @@ impl GenericPort for Port { impl Peekable for Port { #[inline(always)] fn peek(&self) -> bool { - let mut endp = None; - endp <-> self.endp; - let peek = match &endp { - &Some(ref endp) => peek(endp), - &None => fail!(~"peeking empty stream") - }; - self.endp <-> endp; - peek + unsafe { + let self_endp = transmute_mut(&self.endp); + let mut endp = replace(self_endp, None); + let peek = match endp { + Some(ref mut endp) => peek(endp), + None => fail!(~"peeking empty stream") + }; + *self_endp = endp; + peek + } } } impl Selectable for Port { - fn header(&self) -> *PacketHeader { - unsafe { + fn header(&mut self) -> *mut PacketHeader { match self.endp { - Some(ref endp) => endp.header(), - None => fail!(~"peeking empty stream") + Some(ref mut endp) => endp.header(), + None => fail!(~"peeking empty stream") } - } } } /// Treat many ports as one. +#[unsafe_mut_field(ports)] pub struct PortSet { - mut ports: ~[Port], + ports: ~[Port], } pub impl PortSet { - fn new() -> PortSet { PortSet { ports: ~[] @@ -226,7 +241,10 @@ pub impl PortSet { } fn add(&self, port: Port) { - self.ports.push(port) + unsafe { + let self_ports = transmute_mut(&self.ports); + self_ports.push(port) + } } fn chan(&self) -> Chan { @@ -238,25 +256,27 @@ pub impl PortSet { impl GenericPort for PortSet { fn try_recv(&self) -> Option { - let mut result = None; - // we have to swap the ports array so we aren't borrowing - // aliasable mutable memory. - let mut ports = ~[]; - ports <-> self.ports; - while result.is_none() && ports.len() > 0 { - let i = wait_many(ports); - match ports[i].try_recv() { - Some(m) => { - result = Some(m); - } - None => { - // Remove this port. - let _ = ports.swap_remove(i); + unsafe { + let self_ports = transmute_mut(&self.ports); + let mut result = None; + // we have to swap the ports array so we aren't borrowing + // aliasable mutable memory. + let mut ports = replace(self_ports, ~[]); + while result.is_none() && ports.len() > 0 { + let i = wait_many(ports); + match ports[i].try_recv() { + Some(m) => { + result = Some(m); + } + None => { + // Remove this port. + let _ = ports.swap_remove(i); + } } } + *self_ports = ports; + result } - ports <-> self.ports; - result } fn recv(&self) -> T { self.try_recv().expect("port_set: endpoints closed") @@ -268,10 +288,9 @@ impl Peekable for PortSet { // It'd be nice to use self.port.each, but that version isn't // pure. for uint::range(0, vec::uniq_len(&const self.ports)) |i| { - // XXX: Botch pending demuting. - unsafe { - let port: &Port = cast::transmute(&mut self.ports[i]); - if port.peek() { return true } + let port: &Port = &self.ports[i]; + if port.peek() { + return true; } } false @@ -286,7 +305,7 @@ pub struct SharedChan { impl SharedChan { /// Converts a `chan` into a `shared_chan`. pub fn new(c: Chan) -> SharedChan { - SharedChan { ch: unstable::exclusive(c) } + SharedChan { ch: exclusive(c) } } } @@ -294,8 +313,7 @@ impl GenericChan for SharedChan { fn send(&self, x: T) { let mut xx = Some(x); do self.ch.with_imm |chan| { - let mut x = None; - x <-> xx; + let x = replace(&mut xx, None); chan.send(x.unwrap()) } } @@ -305,8 +323,7 @@ impl GenericSmartChan for SharedChan { fn try_send(&self, x: T) -> bool { let mut xx = Some(x); do self.ch.with_imm |chan| { - let mut x = None; - x <-> xx; + let x = replace(&mut xx, None); chan.try_send(x.unwrap()) } } @@ -327,23 +344,20 @@ impl ::clone::Clone for SharedChan { #[allow(non_camel_case_types)] pub mod oneshot { priv use core::kinds::Owned; - use ptr::to_unsafe_ptr; + use ptr::to_mut_unsafe_ptr; pub fn init() -> (client::Oneshot, server::Oneshot) { pub use core::pipes::HasBuffer; - let buffer = - ~::core::pipes::Buffer{ + let buffer = ~::core::pipes::Buffer { header: ::core::pipes::BufferHeader(), - data: __Buffer{ + data: __Buffer { Oneshot: ::core::pipes::mk_packet::>() }, }; do ::core::pipes::entangle_buffer(buffer) |buffer, data| { - { - data.Oneshot.set_buffer(buffer); - to_unsafe_ptr(&data.Oneshot) - } + data.Oneshot.set_buffer(buffer); + to_mut_unsafe_ptr(&mut data.Oneshot) } } #[allow(non_camel_case_types)] @@ -497,48 +511,66 @@ pub fn try_send_one(chan: ChanOne, data: T) -> bool { /// Returns the index of an endpoint that is ready to receive. -pub fn selecti(endpoints: &[T]) -> uint { +pub fn selecti(endpoints: &mut [T]) -> uint { wait_many(endpoints) } /// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i(a: &A, b: &B) -> - Either<(), ()> { - match wait_many([a.header(), b.header()]) { - 0 => Left(()), - 1 => Right(()), - _ => fail!(~"wait returned unexpected index") +pub fn select2i(a: &mut A, b: &mut B) + -> Either<(), ()> { + let mut endpoints = [ a.header(), b.header() ]; + match wait_many(endpoints) { + 0 => Left(()), + 1 => Right(()), + _ => fail!(~"wait returned unexpected index"), } } /// Receive a message from one of two endpoints. pub trait Select2 { /// Receive a message or return `None` if a connection closes. - fn try_select(&self) -> Either, Option>; + fn try_select(&mut self) -> Either, Option>; /// Receive a message or fail if a connection closes. - fn select(&self) -> Either; + fn select(&mut self) -> Either; } -impl, - Right: Selectable + GenericPort> - Select2 for (Left, Right) { - - fn select(&self) -> Either { - match *self { - (ref lp, ref rp) => match select2i(lp, rp) { - Left(()) => Left (lp.recv()), - Right(()) => Right(rp.recv()) - } +impl, + Right:Selectable + GenericPort> + Select2 + for (Left, Right) { + fn select(&mut self) -> Either { + // XXX: Bad borrow check workaround. + unsafe { + let this: &(Left, Right) = transmute(self); + match *this { + (ref lp, ref rp) => { + let lp: &mut Left = transmute(lp); + let rp: &mut Right = transmute(rp); + match select2i(lp, rp) { + Left(()) => Left(lp.recv()), + Right(()) => Right(rp.recv()), + } + } + } } } - fn try_select(&self) -> Either, Option> { - match *self { - (ref lp, ref rp) => match select2i(lp, rp) { - Left(()) => Left (lp.try_recv()), - Right(()) => Right(rp.try_recv()) - } + fn try_select(&mut self) -> Either, Option> { + // XXX: Bad borrow check workaround. + unsafe { + let this: &(Left, Right) = transmute(self); + match *this { + (ref lp, ref rp) => { + let lp: &mut Left = transmute(lp); + let rp: &mut Right = transmute(rp); + match select2i(lp, rp) { + Left(()) => Left (lp.try_recv()), + Right(()) => Right(rp.try_recv()), + } + } + } } } } @@ -546,7 +578,7 @@ impl fail!(), - _ => () + let mut tuple = (p1, p2); + match tuple.select() { + Right(_) => fail!(), + _ => (), } c2.send(123); diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index dc6c80228dd74..baa6722b1936e 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -11,8 +11,7 @@ /*! Condition handling */ use prelude::*; -use task; -use task::local_data::{local_data_pop, local_data_set}; +use local_data::{local_data_pop, local_data_set}; // helper for transmutation, shown below. type RustClosure = (int, int); @@ -24,14 +23,14 @@ pub struct Handler { pub struct Condition<'self, T, U> { name: &'static str, - key: task::local_data::LocalDataKey<'self, Handler> + key: local_data::LocalDataKey<'self, Handler> } pub impl<'self, T, U> Condition<'self, T, U> { fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { unsafe { let p : *RustClosure = ::cast::transmute(&h); - let prev = task::local_data::local_data_get(self.key); + let prev = local_data::local_data_get(self.key); let h = @Handler { handle: *p, prev: prev }; Trap { cond: self, handler: h } } @@ -192,4 +191,27 @@ mod test { assert!(trapped); } + + // Issue #6009 + mod m { + condition! { + sadness: int -> int; + } + + mod n { + use super::sadness; + + #[test] + fn test_conditions_are_public() { + let mut trapped = false; + do sadness::cond.trap(|_| { + trapped = true; + 0 + }).in { + sadness::cond.raise(0); + } + assert!(trapped); + } + } + } } diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 88c78aebfc5c7..1d5d77649549e 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -25,28 +25,43 @@ pub trait Mutable: Container { fn clear(&mut self); } -#[cfg(stage0)] pub trait Map: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; // Visits all keys and values - fn each(&self, f: &fn(&K, &V) -> bool); + #[cfg(stage0)] + fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool); + // Visits all keys and values + #[cfg(not(stage0))] + fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool) -> bool; /// Visit all keys + #[cfg(stage0)] fn each_key(&self, f: &fn(&K) -> bool); + /// Visit all keys + #[cfg(not(stage0))] + fn each_key(&self, f: &fn(&K) -> bool) -> bool; /// Visit all values - fn each_value(&self, f: &fn(&V) -> bool); + #[cfg(stage0)] + fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool); + /// Visit all values + #[cfg(not(stage0))] + fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool; /// Iterate over the map and mutate the contained values + #[cfg(stage0)] fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool); + /// Iterate over the map and mutate the contained values + #[cfg(not(stage0))] + fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool; /// Return a reference to the value corresponding to the key - fn find(&self, key: &K) -> Option<&'self V>; + fn find<'a>(&'a self, key: &K) -> Option<&'a V>; /// Return a mutable reference to the value corresponding to the key - fn find_mut(&mut self, key: &K) -> Option<&'self mut V>; + fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V>; /// Insert a key-value pair into the map. An existing value for a /// key is replaced by the new value. Return true if the key did @@ -56,43 +71,53 @@ pub trait Map: Mutable { /// Remove a key-value pair from the map. Return true if the key /// was present in the map, otherwise false. fn remove(&mut self, key: &K) -> bool; + + /// Insert a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise None is returned. + fn swap(&mut self, k: K, v: V) -> Option; + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + fn pop(&mut self, k: &K) -> Option; } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -pub trait Map: Mutable { - /// Return true if the map contains a value for the specified key - fn contains_key(&self, key: &K) -> bool; +#[cfg(stage0)] +pub trait Set: Mutable { + /// Return true if the set contains a value + fn contains(&self, value: &T) -> bool; - // Visits all keys and values - fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool); + /// Add a value to the set. Return true if the value was not already + /// present in the set. + fn insert(&mut self, value: T) -> bool; - /// Visit all keys - fn each_key(&self, f: &fn(&K) -> bool); + /// Remove a value from the set. Return true if the value was + /// present in the set. + fn remove(&mut self, value: &T) -> bool; - /// Visit all values - fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool); + /// Return true if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + fn is_disjoint(&self, other: &Self) -> bool; - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool); + /// Return true if the set is a subset of another + fn is_subset(&self, other: &Self) -> bool; - /// Return a reference to the value corresponding to the key - fn find<'a>(&'a self, key: &K) -> Option<&'a V>; + /// Return true if the set is a superset of another + fn is_superset(&self, other: &Self) -> bool; - /// Return a mutable reference to the value corresponding to the key - fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V>; + /// Visit the values representing the difference + fn difference(&self, other: &Self, f: &fn(&T) -> bool); - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, key: K, value: V) -> bool; + /// Visit the values representing the symmetric difference + fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool); - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, key: &K) -> bool; + /// Visit the values representing the intersection + fn intersection(&self, other: &Self, f: &fn(&T) -> bool); + + /// Visit the values representing the union + fn union(&self, other: &Self, f: &fn(&T) -> bool); } +#[cfg(not(stage0))] pub trait Set: Mutable { /// Return true if the set contains a value fn contains(&self, value: &T) -> bool; @@ -116,14 +141,14 @@ pub trait Set: Mutable { fn is_superset(&self, other: &Self) -> bool; /// Visit the values representing the difference - fn difference(&self, other: &Self, f: &fn(&T) -> bool); + fn difference(&self, other: &Self, f: &fn(&T) -> bool) -> bool; /// Visit the values representing the symmetric difference - fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool); + fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool) -> bool; /// Visit the values representing the intersection - fn intersection(&self, other: &Self, f: &fn(&T) -> bool); + fn intersection(&self, other: &Self, f: &fn(&T) -> bool) -> bool; /// Visit the values representing the union - fn union(&self, other: &Self, f: &fn(&T) -> bool); + fn union(&self, other: &Self, f: &fn(&T) -> bool) -> bool; } diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f9a56f613d542..96b5e1b781de4 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -60,10 +60,7 @@ they contained the following prologue: // Don't link to core. We are core. #[no_core]; -#[warn(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; -#[allow(deprecated_mutable_fields)]; -#[allow(deprecated_drop)]; // Make core testable by not duplicating lang items. See #2912 #[cfg(test)] extern mod realcore(name = "core", vers = "0.7-pre"); @@ -71,50 +68,6 @@ they contained the following prologue: #[cfg(test)] pub use ops = realcore::ops; #[cfg(test)] pub use cmp = realcore::cmp; -/* Reexported core operators */ - -pub use kinds::{Const, Copy, Owned, Durable}; -pub use ops::{Drop}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; -pub use ops::{BitAnd, BitOr, BitXor}; -pub use ops::{Shl, Shr, Index}; - - -/* Reexported types and traits */ - -pub use option::{Option, Some, None}; -pub use result::{Result, Ok, Err}; - -pub use path::Path; -pub use path::GenericPath; -pub use path::WindowsPath; -pub use path::PosixPath; - -pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; -pub use str::{StrSlice}; -pub use container::{Container, Mutable}; -pub use vec::{CopyableVector, ImmutableVector}; -pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; -pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector}; -pub use old_iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; -pub use old_iter::{CopyableOrderedIter, CopyableNonstrictIter}; -pub use old_iter::{ExtendedMutableIter}; -pub use iter::Times; - -pub use num::{Num, NumCast}; -pub use num::{Orderable, Signed, Unsigned, Round}; -pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; -pub use num::{Integer, Fractional, Real, RealExt}; -pub use num::{Bitwise, BitCount, Bounded}; -pub use num::{Primitive, Int, Float}; - -pub use ptr::Ptr; -pub use to_str::ToStr; -pub use clone::Clone; - // On Linux, link to the runtime with -lrt. #[cfg(target_os = "linux")] #[doc(hidden)] @@ -125,6 +78,9 @@ pub mod linkhack { } } +// Internal macros +mod macros; + /* The Prelude. */ pub mod prelude; @@ -179,9 +135,9 @@ pub mod managed; /* Core language traits */ -#[cfg(notest)] pub mod kinds; -#[cfg(notest)] pub mod ops; -#[cfg(notest)] pub mod cmp; +#[cfg(not(test))] pub mod kinds; +#[cfg(not(test))] pub mod ops; +#[cfg(not(test))] pub mod cmp; /* Common traits */ @@ -216,6 +172,7 @@ pub mod trie; pub mod task; pub mod comm; pub mod pipes; +pub mod local_data; /* Runtime and platform support */ @@ -228,7 +185,6 @@ pub mod rand; pub mod run; pub mod sys; pub mod cast; -pub mod flate; pub mod repr; pub mod cleanup; pub mod reflect; @@ -240,16 +196,17 @@ pub mod util; /* Unsupported interfaces */ // Private APIs +#[path = "unstable/mod.rs"] pub mod unstable; /* For internal use, not exported */ -pub mod unicode; +mod unicode; #[path = "num/cmath.rs"] -pub mod cmath; -pub mod stackwalk; +mod cmath; +mod stackwalk; #[path = "rt/mod.rs"] -pub mod rt; +mod rt; // A curious inner-module that's not exported that contains the binding // 'core' so that macro-expanded references to core::error and such @@ -264,12 +221,3 @@ mod core { pub use sys; pub use pipes; } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/either.rs b/src/libcore/either.rs index 92f850cddd6d1..1e29311e645f1 100644 --- a/src/libcore/either.rs +++ b/src/libcore/either.rs @@ -10,11 +10,14 @@ //! A type that represents one of two alternatives +use container::Container; use cmp::Eq; use kinds::Copy; +use old_iter::BaseIter; use result::Result; use result; use vec; +use vec::OwnedVector; /// The either type #[deriving(Clone, Eq)] @@ -44,7 +47,7 @@ pub fn lefts(eithers: &[Either]) -> ~[T] { //! Extracts from a vector of either all the left values do vec::build_sized(eithers.len()) |push| { - for vec::each(eithers) |elt| { + for eithers.each |elt| { match *elt { Left(ref l) => { push(*l); } _ => { /* fallthrough */ } @@ -57,7 +60,7 @@ pub fn rights(eithers: &[Either]) -> ~[U] { //! Extracts from a vector of either all the right values do vec::build_sized(eithers.len()) |push| { - for vec::each(eithers) |elt| { + for eithers.each |elt| { match *elt { Right(ref r) => { push(*r); } _ => { /* fallthrough */ } @@ -263,13 +266,3 @@ fn test_partition_empty() { assert_eq!(vec::len(lefts), 0u); assert_eq!(vec::len(rights), 0u); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/gc.rs b/src/libcore/gc.rs index 0d0a98359d14c..6a427297cc22d 100644 --- a/src/libcore/gc.rs +++ b/src/libcore/gc.rs @@ -44,7 +44,7 @@ use libc::{size_t, uintptr_t}; use option::{None, Option, Some}; use ptr; use hashmap::HashSet; -use stackwalk; +use stackwalk::walk_stack; use sys; pub use stackwalk::Word; @@ -129,7 +129,7 @@ type Visitor<'self> = &'self fn(root: **Word, tydesc: *Word) -> bool; // Walks the list of roots for the given safe point, and calls visitor // on each root. -unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { +unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { let fp_bytes: *u8 = cast::transmute(fp); let sp_meta: *u32 = cast::transmute(sp.sp_meta); @@ -155,7 +155,7 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { } else { ptr::null() }; - if !visitor(root, tydesc) { return; } + if !visitor(root, tydesc) { return false; } } sri += 1; } @@ -168,6 +168,16 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { } rri += 1; } + return true; +} + +#[cfg(stage0)] +unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { + _walk_safe_point(fp, sp, visitor); +} +#[cfg(not(stage0))] +unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { + _walk_safe_point(fp, sp, visitor) } // Is fp contained in segment? @@ -222,7 +232,7 @@ static need_cleanup: Memory = exchange_heap | stack; // Walks stack, searching for roots of the requested type, and passes // each root to the visitor. -unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { +unsafe fn _walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) -> bool { let mut segment = rustrt::rust_get_stack_segment(); let mut last_ret: *Word = ptr::null(); // To avoid collecting memory used by the GC itself, skip stack @@ -230,7 +240,7 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { // frame is marked by a sentinel, which is a box pointer stored on // the stack. let mut reached_sentinel = ptr::is_null(sentinel); - for stackwalk::walk_stack |frame| { + for walk_stack |frame| { let pc = last_ret; let Segment {segment: next_segment, boundary: boundary} = find_segment_for_frame(frame.fp, segment); @@ -274,14 +284,14 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { // Root is a generic box. let refcount = **root; if mem | task_local_heap != 0 && refcount != -1 { - if !visitor(root, tydesc) { return; } + if !visitor(root, tydesc) { return false; } } else if mem | exchange_heap != 0 && refcount == -1 { - if !visitor(root, tydesc) { return; } + if !visitor(root, tydesc) { return false; } } } else { // Root is a non-immediate. if mem | stack != 0 { - if !visitor(root, tydesc) { return; } + if !visitor(root, tydesc) { return false; } } } } @@ -290,8 +300,17 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { } reached_sentinel = delay_reached_sentinel; } + return true; } +#[cfg(stage0)] +unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { + _walk_gc_roots(mem, sentinel, visitor); +} +#[cfg(not(stage0))] +unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) -> bool { + _walk_gc_roots(mem, sentinel, visitor) +} pub fn gc() { unsafe { // Abort when GC is disabled. diff --git a/src/libcore/hash.rs b/src/libcore/hash.rs index ba1f8cebdb01c..cb02364d725f8 100644 --- a/src/libcore/hash.rs +++ b/src/libcore/hash.rs @@ -19,11 +19,16 @@ * CPRNG like rand::rng. */ -use io; -use io::Writer; +#[cfg(stage0)] +use cast; +use container::Container; +use old_iter::BaseIter; +use rt::io::Writer; use to_bytes::IterBytes; use uint; -use vec; + +// Alias `SipState` to `State`. +pub use State = hash::SipState; /** * Types that can meaningfully be hashed should implement this. @@ -65,20 +70,32 @@ impl HashUtil for A { /// Streaming hash-functions should implement this. pub trait Streaming { - fn input(&self, (&const [u8])); + fn input(&mut self, &[u8]); // These can be refactored some when we have default methods. - fn result_bytes(&self) -> ~[u8]; - fn result_str(&self) -> ~str; - fn result_u64(&self) -> u64; - fn reset(&self); + fn result_bytes(&mut self) -> ~[u8]; + fn result_str(&mut self) -> ~str; + fn result_u64(&mut self) -> u64; + fn reset(&mut self); +} + +// XXX: Ugly workaround for bootstrapping. +#[cfg(stage0)] +fn transmute_for_stage0<'a>(bytes: &'a [const u8]) -> &'a [u8] { + unsafe { + cast::transmute(bytes) + } +} +#[cfg(not(stage0))] +fn transmute_for_stage0<'a>(bytes: &'a [u8]) -> &'a [u8] { + bytes } impl Hash for A { #[inline(always)] fn hash_keyed(&self, k0: u64, k1: u64) -> u64 { - let s = &State(k0, k1); + let mut s = State::new(k0, k1); for self.iter_bytes(true) |bytes| { - s.input(bytes); + s.input(transmute_for_stage0(bytes)); } s.result_u64() } @@ -86,32 +103,56 @@ impl Hash for A { fn hash_keyed_2(a: &A, b: &B, k0: u64, k1: u64) -> u64 { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } + let mut s = State::new(k0, k1); + for a.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for b.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } s.result_u64() } fn hash_keyed_3(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } + let mut s = State::new(k0, k1); + for a.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for b.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for c.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } s.result_u64() } fn hash_keyed_4(a: &A, b: &B, c: &C, d: &D, k0: u64, k1: u64) - -> u64 { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } - for d.iter_bytes(true) |bytes| { s.input(bytes); } + D: IterBytes>( + a: &A, + b: &B, + c: &C, + d: &D, + k0: u64, + k1: u64) + -> u64 { + let mut s = State::new(k0, k1); + for a.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for b.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for c.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for d.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } s.result_u64() } @@ -119,58 +160,68 @@ fn hash_keyed_5(a: &A, b: &B, c: &C, d: &D, e: &E, - k0: u64, k1: u64) -> u64 { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } - for d.iter_bytes(true) |bytes| { s.input(bytes); } - for e.iter_bytes(true) |bytes| { s.input(bytes); } + E: IterBytes>( + a: &A, + b: &B, + c: &C, + d: &D, + e: &E, + k0: u64, + k1: u64) + -> u64 { + let mut s = State::new(k0, k1); + for a.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for b.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for c.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for d.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } + for e.iter_bytes(true) |bytes| { + s.input(transmute_for_stage0(bytes)); + } s.result_u64() } -// Implement State as SipState - -pub type State = SipState; - -#[inline(always)] -pub fn State(k0: u64, k1: u64) -> State { - SipState(k0, k1) -} - #[inline(always)] pub fn default_state() -> State { - State(0,0) + State::new(0, 0) } struct SipState { k0: u64, k1: u64, - mut length: uint, // how many bytes we've processed - mut v0: u64, // hash state - mut v1: u64, - mut v2: u64, - mut v3: u64, - mut tail: [u8, ..8], // unprocessed bytes - mut ntail: uint, // how many bytes in tail are valid + length: uint, // how many bytes we've processed + v0: u64, // hash state + v1: u64, + v2: u64, + v3: u64, + tail: [u8, ..8], // unprocessed bytes + ntail: uint, // how many bytes in tail are valid } -#[inline(always)] -fn SipState(key0: u64, key1: u64) -> SipState { - let state = SipState { - k0 : key0, - k1 : key1, - mut length : 0u, - mut v0 : 0u64, - mut v1 : 0u64, - mut v2 : 0u64, - mut v3 : 0u64, - mut tail : [0u8,0,0,0,0,0,0,0], - mut ntail : 0u, - }; - (&state).reset(); - state +impl SipState { + #[inline(always)] + fn new(key0: u64, key1: u64) -> SipState { + let mut state = SipState { + k0: key0, + k1: key1, + length: 0, + v0: 0, + v1: 0, + v2: 0, + v3: 0, + tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ], + ntail: 0, + }; + state.reset(); + state + } } // sadly, these macro definitions can't appear later, @@ -207,12 +258,10 @@ macro_rules! compress ( ) -impl io::Writer for SipState { - +impl Writer for SipState { // Methods for io::writer #[inline(always)] - fn write(&self, msg: &const [u8]) { - + fn write(&mut self, msg: &[u8]) { let length = msg.len(); self.length += length; @@ -272,29 +321,19 @@ impl io::Writer for SipState { self.ntail = left; } - fn seek(&self, _x: int, _s: io::SeekStyle) { - fail!(); - } - fn tell(&self) -> uint { - self.length - } - fn flush(&self) -> int { - 0 - } - fn get_type(&self) -> io::WriterType { - io::File + fn flush(&mut self) { + // No-op } } impl Streaming for SipState { - #[inline(always)] - fn input(&self, buf: &const [u8]) { + fn input(&mut self, buf: &[u8]) { self.write(buf); } #[inline(always)] - fn result_u64(&self) -> u64 { + fn result_u64(&mut self) -> u64 { let mut v0 = self.v0; let mut v1 = self.v1; let mut v2 = self.v2; @@ -324,7 +363,7 @@ impl Streaming for SipState { return (v0 ^ v1 ^ v2 ^ v3); } - fn result_bytes(&self) -> ~[u8] { + fn result_bytes(&mut self) -> ~[u8] { let h = self.result_u64(); ~[(h >> 0) as u8, (h >> 8) as u8, @@ -337,17 +376,17 @@ impl Streaming for SipState { ] } - fn result_str(&self) -> ~str { + fn result_str(&mut self) -> ~str { let r = self.result_bytes(); let mut s = ~""; - for vec::each(r) |b| { + for r.each |b| { s += uint::to_str_radix(*b as uint, 16u); } s } #[inline(always)] - fn reset(&self) { + fn reset(&mut self) { self.length = 0; self.v0 = self.k0 ^ 0x736f6d6570736575; self.v1 = self.k1 ^ 0x646f72616e646f6d; @@ -435,12 +474,12 @@ mod tests { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; let mut buf : ~[u8] = ~[]; let mut t = 0; - let stream_inc = &State(k0,k1); - let stream_full = &State(k0,k1); + let mut stream_inc = SipState::new(k0, k1); + let mut stream_full = SipState::new(k0, k1); - fn to_hex_str(r: &[u8, ..8]) -> ~str { + fn to_hex_str(r: &[u8, ..8]) -> ~str { let mut s = ~""; - for vec::each(*r) |b| { + for (*r).each |b| { s += uint::to_str_radix(*b as uint, 16u); } s @@ -529,4 +568,4 @@ mod tests { val & !(0xff << (byte * 8)) } } -} \ No newline at end of file +} diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 41f4f34dc1971..590d4ab3bcb40 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -24,7 +24,8 @@ use rand::RngUtil; use rand; use uint; use vec; -use util::unreachable; +use kinds::Copy; +use util::{replace, unreachable}; static INITIAL_CAPACITY: uint = 32u; // 2^5 @@ -55,7 +56,7 @@ fn resize_at(capacity: uint) -> uint { pub fn linear_map_with_capacity( initial_capacity: uint) -> HashMap { - let r = rand::task_rng(); + let mut r = rand::task_rng(); linear_map_with_capacity_and_keys(r.gen(), r.gen(), initial_capacity) } @@ -87,18 +88,32 @@ priv impl HashMap { } #[inline(always)] + #[cfg(stage0)] fn bucket_sequence(&self, hash: uint, - op: &fn(uint) -> bool) -> uint { + op: &fn(uint) -> bool) { let start_idx = self.to_bucket(hash); let len_buckets = self.buckets.len(); let mut idx = start_idx; loop { - if !op(idx) { - return idx; + if !op(idx) { return; } + idx = self.next_bucket(idx, len_buckets); + if idx == start_idx { + return; } + } + } + #[inline(always)] + #[cfg(not(stage0))] + fn bucket_sequence(&self, hash: uint, + op: &fn(uint) -> bool) -> bool { + let start_idx = self.to_bucket(hash); + let len_buckets = self.buckets.len(); + let mut idx = start_idx; + loop { + if !op(idx) { return false; } idx = self.next_bucket(idx, len_buckets); if idx == start_idx { - return start_idx; + return true; } } } @@ -121,14 +136,14 @@ priv impl HashMap { hash: uint, k: &K) -> SearchResult { - let _ = for self.bucket_sequence(hash) |i| { + for self.bucket_sequence(hash) |i| { match self.buckets[i] { Some(ref bkt) => if bkt.hash == hash && *k == bkt.key { return FoundEntry(i); }, None => return FoundHole(i) } - }; + } TableFull } @@ -137,7 +152,7 @@ priv impl HashMap { hash: uint, k: &Q) -> SearchResult { - let _ = for self.bucket_sequence(hash) |i| { + for self.bucket_sequence(hash) |i| { match self.buckets[i] { Some(ref bkt) => { if bkt.hash == hash && k.equiv(&bkt.key) { @@ -146,7 +161,7 @@ priv impl HashMap { }, None => return FoundHole(i) } - }; + } TableFull } @@ -161,16 +176,13 @@ priv impl HashMap { /// Expands the capacity of the array and re-insert each of the /// existing buckets. fn resize(&mut self, new_capacity: uint) { - let old_capacity = self.buckets.len(); self.resize_at = resize_at(new_capacity); - let mut old_buckets = vec::from_fn(new_capacity, |_| None); - self.buckets <-> old_buckets; + let old_buckets = replace(&mut self.buckets, + vec::from_fn(new_capacity, |_| None)); self.size = 0; - for uint::range(0, old_capacity) |i| { - let mut bucket = None; - bucket <-> old_buckets[i]; + do vec::consume(old_buckets) |_, bucket| { self.insert_opt_bucket(bucket); } } @@ -184,18 +196,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn value_for_bucket(&self, idx: uint) -> &'self V { - match self.buckets[idx] { - Some(ref bkt) => &bkt.value, - None => fail!(~"HashMap::find: internal logic error"), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { match self.buckets[idx] { @@ -204,18 +204,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V { - match self.buckets[idx] { - Some(ref mut bkt) => &mut bkt.value, - None => unreachable() - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { match self.buckets[idx] { @@ -227,7 +215,7 @@ priv impl HashMap { /// Inserts the key value pair into the buckets. /// Assumes that there will be a bucket. /// True if there was no previous entry with that key - fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool { + fn insert_internal(&mut self, hash: uint, k: K, v: V) -> Option { match self.bucket_for_key_with_hash(hash, &k) { TableFull => { fail!(~"Internal logic error"); } FoundHole(idx) => { @@ -236,14 +224,19 @@ priv impl HashMap { self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; - true + None } FoundEntry(idx) => { debug!("insert overwrite (%?->%?) at idx %?, hash %?", k, v, idx, hash); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - false + match self.buckets[idx] { + None => { fail!(~"insert_internal: Internal logic error") } + Some(ref mut b) => { + b.hash = hash; + b.key = k; + Some(replace(&mut b.value, v)) + } + } } } } @@ -269,13 +262,11 @@ priv impl HashMap { }; let len_buckets = self.buckets.len(); - let mut bucket = None; - self.buckets[idx] <-> bucket; + let bucket = replace(&mut self.buckets[idx], None); let value = match bucket { None => None, - Some(bucket) => { - let Bucket{value: value, _} = bucket; + Some(Bucket{value, _}) => { Some(value) }, }; @@ -285,8 +276,7 @@ priv impl HashMap { let size = self.size - 1; idx = self.next_bucket(idx, len_buckets); while self.buckets[idx].is_some() { - let mut bucket = None; - bucket <-> self.buckets[idx]; + let bucket = replace(&mut self.buckets[idx], None); self.insert_opt_bucket(bucket); idx = self.next_bucket(idx, len_buckets); } @@ -330,7 +320,7 @@ impl Map for HashMap { /// Visit all key-value pairs #[cfg(stage0)] - fn each(&self, blk: &fn(&'self K, &'self V) -> bool) { + fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) { for uint::range(0, self.buckets.len()) |i| { for self.buckets[i].each |bucket| { if !blk(&bucket.key, &bucket.value) { @@ -341,39 +331,44 @@ impl Map for HashMap { } /// Visit all key-value pairs - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each<'a>(&'a self, blk: &fn(&'a K, &'a V) -> bool) { + #[cfg(not(stage0))] + fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) -> bool { for uint::range(0, self.buckets.len()) |i| { for self.buckets[i].each |bucket| { if !blk(&bucket.key, &bucket.value) { - return; + return false; } } } + return true; } /// Visit all keys + #[cfg(stage0)] fn each_key(&self, blk: &fn(k: &K) -> bool) { self.each(|k, _| blk(k)) } + /// Visit all keys + #[cfg(not(stage0))] + fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { + self.each(|k, _| blk(k)) + } + /// Visit all values #[cfg(stage0)] - fn each_value(&self, blk: &fn(v: &V) -> bool) { + fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) { self.each(|_, v| blk(v)) } /// Visit all values - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) { + #[cfg(not(stage0))] + fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { self.each(|_, v| blk(v)) } /// Iterate over the map and mutate the contained values + #[cfg(stage0)] fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) { for uint::range(0, self.buckets.len()) |i| { match self.buckets[i] { @@ -385,19 +380,21 @@ impl Map for HashMap { } } - /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, k: &K) -> Option<&'self V> { - match self.bucket_for_key(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, + /// Iterate over the map and mutate the contained values + #[cfg(not(stage0))] + fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) -> bool { + for uint::range(0, self.buckets.len()) |i| { + match self.buckets[i] { + Some(Bucket{key: ref key, value: ref mut value, _}) => { + if !blk(key, value) { return false; } + } + None => () + } } + return true; } /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, k: &K) -> Option<&'a V> { match self.bucket_for_key(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), @@ -407,34 +404,44 @@ impl Map for HashMap { /// Return a mutable reference to the value corresponding to the key #[cfg(stage0)] - fn find_mut(&mut self, k: &K) -> Option<&'self mut V> { + fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { let idx = match self.bucket_for_key(k) { FoundEntry(idx) => idx, TableFull | FoundHole(_) => return None }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + unsafe { Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) } } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] + #[cfg(not(stage0))] fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { let idx = match self.bucket_for_key(k) { FoundEntry(idx) => idx, TableFull | FoundHole(_) => return None }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) - } + Some(self.mut_value_for_bucket(idx)) } /// Insert a key-value pair into the map. An existing value for a /// key is replaced by the new value. Return true if the key did /// not already exist in the map. fn insert(&mut self, k: K, v: V) -> bool { + self.swap(k, v).is_none() + } + + /// Remove a key-value pair from the map. Return true if the key + /// was present in the map, otherwise false. + fn remove(&mut self, k: &K) -> bool { + self.pop(k).is_some() + } + + /// Insert a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise None is returned. + fn swap(&mut self, k: K, v: V) -> Option { + // this could be faster. + if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is @@ -449,10 +456,11 @@ impl Map for HashMap { self.insert_internal(hash, k, v) } - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, k: &K) -> bool { - self.pop(k).is_some() + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + fn pop(&mut self, k: &K) -> Option { + let hash = k.hash_keyed(self.k0, self.k1) as uint; + self.pop_internal(hash, k) } } @@ -476,35 +484,10 @@ pub impl HashMap { } } - fn pop(&mut self, k: &K) -> Option { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.pop_internal(hash, k) - } - - fn swap(&mut self, k: K, v: V) -> Option { - // this could be faster. - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let old_value = self.pop_internal(hash, &k); - - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - self.insert_internal(hash, k, v); - - old_value - } - /// Return the value corresponding to the key in the map, or insert /// and return the value if it doesn't exist. #[cfg(stage0)] - fn find_or_insert(&mut self, k: K, v: V) -> &'self V { + fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is @@ -527,16 +510,14 @@ pub impl HashMap { }, }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + unsafe { ::cast::transmute_region(self.value_for_bucket(idx)) } } /// Return the value corresponding to the key in the map, or insert /// and return the value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] + #[cfg(not(stage0))] fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -560,15 +541,13 @@ pub impl HashMap { }, }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } + self.value_for_bucket(idx) } /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. #[cfg(stage0)] - fn find_or_insert_with(&mut self, k: K, f: &fn(&K) -> V) -> &'self V { + fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is @@ -592,16 +571,14 @@ pub impl HashMap { }, }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + unsafe { ::cast::transmute_region(self.value_for_bucket(idx)) } } /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] + #[cfg(not(stage0))] fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -626,38 +603,23 @@ pub impl HashMap { }, }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } + self.value_for_bucket(idx) } fn consume(&mut self, f: &fn(K, V)) { - let mut buckets = ~[]; - self.buckets <-> buckets; + let buckets = replace(&mut self.buckets, ~[]); self.size = 0; do vec::consume(buckets) |_, bucket| { match bucket { None => {}, - Some(bucket) => { - let Bucket{key: key, value: value, _} = bucket; + Some(Bucket{key, value, _}) => { f(key, value) } } } } - #[cfg(stage0)] - fn get(&self, k: &K) -> &'self V { - match self.find(k) { - Some(v) => v, - None => fail!(fmt!("No entry found for key: %?", k)), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, k: &K) -> &'a V { match self.find(k) { Some(v) => v, @@ -676,24 +638,23 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, using /// equivalence - #[cfg(stage0)] - fn find_equiv>(&self, k: &Q) -> Option<&'self V> { + fn find_equiv<'a, Q:Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { match self.bucket_for_key_equiv(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), TableFull | FoundHole(_) => None, } } +} - /// Return the value corresponding to the key in the map, using - /// equivalence - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn find_equiv<'a, Q:Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { - match self.bucket_for_key_equiv(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } +pub impl HashMap { + /// Like `find`, but returns a copy of the value. + fn find_copy(&self, k: &K) -> Option { + self.find(k).map_consume(|v| copy *v) + } + + /// Like `get`, but returns a copy of the value. + fn get_copy(&self, k: &K) -> V { + copy *self.get(k) } } @@ -720,7 +681,10 @@ pub struct HashSet { impl BaseIter for HashSet { /// Visit all values in order + #[cfg(stage0)] fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) } + #[cfg(not(stage0))] + fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } fn size_hint(&self) -> Option { Some(self.len()) } } @@ -771,6 +735,7 @@ impl Set for HashSet { } /// Visit the values representing the difference + #[cfg(stage0)] fn difference(&self, other: &HashSet, f: &fn(&T) -> bool) { for self.each |v| { if !other.contains(v) { @@ -779,7 +744,14 @@ impl Set for HashSet { } } + /// Visit the values representing the difference + #[cfg(not(stage0))] + fn difference(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { + self.each(|v| other.contains(v) || f(v)) + } + /// Visit the values representing the symmetric difference + #[cfg(stage0)] fn symmetric_difference(&self, other: &HashSet, f: &fn(&T) -> bool) { @@ -787,7 +759,16 @@ impl Set for HashSet { other.difference(self, f); } + /// Visit the values representing the symmetric difference + #[cfg(not(stage0))] + fn symmetric_difference(&self, + other: &HashSet, + f: &fn(&T) -> bool) -> bool { + self.difference(other, f) && other.difference(self, f) + } + /// Visit the values representing the intersection + #[cfg(stage0)] fn intersection(&self, other: &HashSet, f: &fn(&T) -> bool) { for self.each |v| { if other.contains(v) { @@ -796,7 +777,14 @@ impl Set for HashSet { } } + /// Visit the values representing the intersection + #[cfg(not(stage0))] + fn intersection(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { + self.each(|v| !other.contains(v) || f(v)) + } + /// Visit the values representing the union + #[cfg(stage0)] fn union(&self, other: &HashSet, f: &fn(&T) -> bool) { for self.each |v| { if !f(v) { return } @@ -808,6 +796,12 @@ impl Set for HashSet { } } } + + /// Visit the values representing the union + #[cfg(not(stage0))] + fn union(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { + self.each(f) && other.each(|v| self.contains(v) || f(v)) + } } pub impl HashSet { @@ -833,7 +827,7 @@ pub impl HashSet { } } -#[test] +#[cfg(test)] mod test_map { use container::{Container, Map, Set}; use option::{None, Some}; @@ -1009,7 +1003,7 @@ mod test_map { } } -#[test] +#[cfg(test)] mod test_set { use super::*; use container::{Container, Map, Set}; diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 35ffd88c8f477..ab5db67ddb6ff 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -16,6 +16,7 @@ Basic input/output use result::Result; +use container::Container; use int; use libc; use libc::{c_int, c_long, c_void, size_t, ssize_t}; @@ -24,11 +25,15 @@ use os; use cast; use path::Path; use ops::Drop; +use old_iter::{BaseIter, CopyableIter}; use ptr; use result; use str; +use str::StrSlice; +use to_str::ToStr; use uint; use vec; +use vec::{OwnedVector, OwnedCopyableVector}; #[allow(non_camel_case_types)] // not sure what to do about this pub type fd_t = c_int; @@ -247,7 +252,10 @@ pub trait ReaderUtil { * * None right now. */ + #[cfg(stage0)] fn each_byte(&self, it: &fn(int) -> bool); + #[cfg(not(stage0))] + fn each_byte(&self, it: &fn(int) -> bool) -> bool; /** * Iterate over every char until EOF or the iterator breaks. @@ -256,7 +264,10 @@ pub trait ReaderUtil { * * None right now. */ + #[cfg(stage0)] fn each_char(&self, it: &fn(char) -> bool); + #[cfg(not(stage0))] + fn each_char(&self, it: &fn(char) -> bool) -> bool; /** * Iterate over every line until EOF or the iterator breaks. @@ -265,7 +276,10 @@ pub trait ReaderUtil { * * None right now. */ + #[cfg(stage0)] fn each_line(&self, it: &fn(&str) -> bool); + #[cfg(not(stage0))] + fn each_line(&self, it: &fn(&str) -> bool) -> bool; /** * Reads all of the lines in the stream. @@ -676,18 +690,35 @@ impl ReaderUtil for T { bytes } + #[cfg(stage0)] fn each_byte(&self, it: &fn(int) -> bool) { while !self.eof() { if !it(self.read_byte()) { break; } } } + #[cfg(not(stage0))] + fn each_byte(&self, it: &fn(int) -> bool) -> bool { + while !self.eof() { + if !it(self.read_byte()) { return false; } + } + return true; + } + #[cfg(stage0)] fn each_char(&self, it: &fn(char) -> bool) { while !self.eof() { if !it(self.read_char()) { break; } } } + #[cfg(not(stage0))] + fn each_char(&self, it: &fn(char) -> bool) -> bool { + while !self.eof() { + if !it(self.read_char()) { return false; } + } + return true; + } + #[cfg(stage0)] fn each_line(&self, it: &fn(s: &str) -> bool) { while !self.eof() { // include the \n, so that we can distinguish an entirely empty @@ -707,11 +738,32 @@ impl ReaderUtil for T { if !it(line) { break; } } } + #[cfg(not(stage0))] + fn each_line(&self, it: &fn(s: &str) -> bool) -> bool { + while !self.eof() { + // include the \n, so that we can distinguish an entirely empty + // line read after "...\n", and the trailing empty line in + // "...\n\n". + let mut line = self.read_until('\n' as u8, true); + + // blank line at the end of the reader is ignored + if self.eof() && line.is_empty() { break; } + + // trim the \n, so that each_line is consistent with read_line + let n = str::len(line); + if line[n-1] == '\n' as u8 { + unsafe { str::raw::set_len(&mut line, n-1); } + } + + if !it(line) { return false; } + } + return true; + } fn read_lines(&self) -> ~[~str] { do vec::build |push| { for self.each_line |line| { - push(str::from_slice(line)); + push(str::to_owned(line)); } } } @@ -868,9 +920,19 @@ impl Reader for *libc::FILE { assert!(buf_len >= len); let count = libc::fread(buf_p as *mut c_void, 1u as size_t, - len as size_t, *self); + len as size_t, *self) as uint; + if count < len { + match libc::ferror(*self) { + 0 => (), + _ => { + error!("error reading buffer"); + error!("%s", os::last_os_error()); + fail!(); + } + } + } - count as uint + count } } } @@ -973,36 +1035,50 @@ pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { // Byte readers pub struct BytesReader<'self> { bytes: &'self [u8], - mut pos: uint + pos: @mut uint } impl<'self> Reader for BytesReader<'self> { fn read(&self, bytes: &mut [u8], len: uint) -> uint { - let count = uint::min(len, self.bytes.len() - self.pos); + let count = uint::min(len, self.bytes.len() - *self.pos); - let view = vec::slice(self.bytes, self.pos, self.bytes.len()); + let view = vec::slice(self.bytes, *self.pos, self.bytes.len()); vec::bytes::copy_memory(bytes, view, count); - self.pos += count; + *self.pos += count; count } + fn read_byte(&self) -> int { - if self.pos == self.bytes.len() { return -1; } - let b = self.bytes[self.pos]; - self.pos += 1u; - return b as int; + if *self.pos == self.bytes.len() { + return -1; + } + + let b = self.bytes[*self.pos]; + *self.pos += 1u; + b as int } - fn eof(&self) -> bool { self.pos == self.bytes.len() } + + fn eof(&self) -> bool { + *self.pos == self.bytes.len() + } + fn seek(&self, offset: int, whence: SeekStyle) { - let pos = self.pos; - self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence); + let pos = *self.pos; + *self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence); + } + + fn tell(&self) -> uint { + *self.pos } - fn tell(&self) -> uint { self.pos } } -pub fn with_bytes_reader(bytes: &[u8], f: &fn(@Reader) -> t) -> t { - f(@BytesReader { bytes: bytes, pos: 0u } as @Reader) +pub fn with_bytes_reader(bytes: &[u8], f: &fn(@Reader) -> T) -> T { + f(@BytesReader { + bytes: bytes, + pos: @mut 0 + } as @Reader) } pub fn with_str_reader(s: &str, f: &fn(@Reader) -> T) -> T { @@ -1022,7 +1098,7 @@ pub enum WriterType { Screen, File } pub trait Writer { /// Write all of the given bytes. - fn write(&self, v: &const [u8]); + fn write(&self, v: &[u8]); /// Move the current position within the stream. The second parameter /// determines the position that the first parameter is relative to. @@ -1039,7 +1115,7 @@ pub trait Writer { } impl Writer for @Writer { - fn write(&self, v: &const [u8]) { self.write(v) } + fn write(&self, v: &[u8]) { self.write(v) } fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) } fn tell(&self) -> uint { self.tell() } fn flush(&self) -> int { self.flush() } @@ -1047,7 +1123,7 @@ impl Writer for @Writer { } impl Writer for Wrapper { - fn write(&self, bs: &const [u8]) { self.base.write(bs); } + fn write(&self, bs: &[u8]) { self.base.write(bs); } fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); } fn tell(&self) -> uint { self.base.tell() } fn flush(&self) -> int { self.base.flush() } @@ -1055,7 +1131,7 @@ impl Writer for Wrapper { } impl Writer for *libc::FILE { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { unsafe { do vec::as_const_buf(v) |vbuf, len| { let nout = libc::fwrite(vbuf as *c_void, @@ -1105,7 +1181,7 @@ pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer { } impl Writer for fd_t { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { unsafe { let mut count = 0u; do vec::as_const_buf(v) |vbuf, len| { @@ -1176,7 +1252,7 @@ pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) fn wb() -> c_int { O_WRONLY as c_int } let mut fflags: c_int = wb(); - for vec::each(flags) |f| { + for flags.each |f| { match *f { Append => fflags |= O_APPEND as c_int, Create => fflags |= O_CREAT as c_int, @@ -1262,7 +1338,7 @@ pub fn u64_to_be_bytes(n: u64, size: uint, } } -pub fn u64_from_be_bytes(data: &const [u8], +pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 { @@ -1488,49 +1564,70 @@ pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> { pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) } pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) } -pub fn print(s: &str) { stdout().write_str(s); } -pub fn println(s: &str) { stdout().write_line(s); } +pub fn print(s: &str) { + stdout().write_str(s); +} + +pub fn println(s: &str) { + stdout().write_line(s); +} pub struct BytesWriter { - mut bytes: ~[u8], - mut pos: uint, + bytes: @mut ~[u8], + pos: @mut uint, } impl Writer for BytesWriter { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { let v_len = v.len(); - let bytes_len = vec::uniq_len(&const self.bytes); - let count = uint::max(bytes_len, self.pos + v_len); - vec::reserve(&mut self.bytes, count); + let bytes = &mut *self.bytes; + let count = uint::max(bytes.len(), *self.pos + v_len); + vec::reserve(bytes, count); unsafe { - vec::raw::set_len(&mut self.bytes, count); - let view = vec::mut_slice(self.bytes, self.pos, count); + // Silly stage0 borrow check workaround... + let casted: &mut ~[u8] = cast::transmute_copy(&bytes); + vec::raw::set_len(casted, count); + + let view = vec::mut_slice(*bytes, *self.pos, count); vec::bytes::copy_memory(view, v, v_len); } - self.pos += v_len; + *self.pos += v_len; } + fn seek(&self, offset: int, whence: SeekStyle) { - let pos = self.pos; - let len = vec::uniq_len(&const self.bytes); - self.pos = seek_in_buf(offset, pos, len, whence); + let pos = *self.pos; + let len = vec::uniq_len(&const *self.bytes); + *self.pos = seek_in_buf(offset, pos, len, whence); + } + + fn tell(&self) -> uint { + *self.pos + } + + fn flush(&self) -> int { + 0 + } + + fn get_type(&self) -> WriterType { + File } - fn tell(&self) -> uint { self.pos } - fn flush(&self) -> int { 0 } - fn get_type(&self) -> WriterType { File } } pub fn BytesWriter() -> BytesWriter { - BytesWriter { bytes: ~[], mut pos: 0u } + BytesWriter { + bytes: @mut ~[], + pos: @mut 0 + } } pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { let wr = @BytesWriter(); f(wr as @Writer); - let @BytesWriter{bytes, _} = wr; - return bytes; + let @BytesWriter { bytes, _ } = wr; + copy *bytes } pub fn with_str_writer(f: &fn(@Writer)) -> ~str { @@ -1540,7 +1637,9 @@ pub fn with_str_writer(f: &fn(@Writer)) -> ~str { v.push(0); assert!(str::is_utf8(v)); - unsafe { ::cast::transmute(v) } + unsafe { + ::cast::transmute(v) + } } // Utility functions @@ -1839,15 +1938,15 @@ mod tests { fn bytes_buffer_overwrite() { let wr = BytesWriter(); wr.write(~[0u8, 1u8, 2u8, 3u8]); - assert!(wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); + assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); wr.seek(-2, SeekCur); wr.write(~[4u8, 5u8, 6u8, 7u8]); - assert!(wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]); + assert!(*wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]); wr.seek(-2, SeekEnd); wr.write(~[8u8]); wr.seek(1, SeekSet); wr.write(~[9u8]); - assert!(wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]); + assert!(*wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]); } #[test] @@ -1954,13 +2053,3 @@ mod tests { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 7476531ef944c..cfc9afb737c5f 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -17,8 +17,7 @@ breaking out of iteration. The adaptors in the module work with any such iterato tied to specific traits. For example: ~~~~ -use core::iter::iter_to_vec; -println(iter_to_vec(|f| uint::range(0, 20, f)).to_str()); +println(iter::to_vec(|f| uint::range(0, 20, f)).to_str()); ~~~~ An external iterator object implementing the interface in the `iterator` module can be used as an @@ -41,9 +40,18 @@ much easier to implement. */ +#[cfg(not(stage0))] use cmp::Ord; +#[cfg(not(stage0))] use option::{Option, Some, None}; +#[cfg(not(stage0))] use vec::OwnedVector; + +#[cfg(stage0)] pub trait Times { fn times(&self, it: &fn() -> bool); } +#[cfg(not(stage0))] +pub trait Times { + fn times(&self, it: &fn() -> bool) -> bool; +} /** * Transform an internal iterator into an owned vector. @@ -52,12 +60,13 @@ pub trait Times { * * ~~~ * let xs = ~[1, 2, 3]; - * let ys = do iter_to_vec |f| { xs.each(|x| f(*x)) }; + * let ys = do iter::to_vec |f| { xs.each(|x| f(*x)) }; * assert_eq!(xs, ys); * ~~~ */ #[inline(always)] -pub fn iter_to_vec(iter: &fn(f: &fn(T) -> bool)) -> ~[T] { +#[cfg(not(stage0))] +pub fn to_vec(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] { let mut v = ~[]; for iter |x| { v.push(x) } v @@ -75,13 +84,15 @@ pub fn iter_to_vec(iter: &fn(f: &fn(T) -> bool)) -> ~[T] { * ~~~~ */ #[inline(always)] -pub fn any(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { +#[cfg(not(stage0))] +pub fn any(predicate: &fn(T) -> bool, + iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { for iter |x| { if predicate(x) { - return true + return true; } } - false + return false; } /** @@ -95,13 +106,110 @@ pub fn any(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { * ~~~~ */ #[inline(always)] -pub fn all(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { +#[cfg(stage0)] +pub fn all(predicate: &fn(T) -> bool, + iter: &fn(f: &fn(T) -> bool)) -> bool { for iter |x| { if !predicate(x) { - return false + return false; + } + } + return true; +} + +/** + * Return true if `predicate` is true for all values yielded by an internal iterator. + * + * # Example: + * + * ~~~~ + * assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f))); + * assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f))); + * ~~~~ + */ +#[inline(always)] +#[cfg(not(stage0))] +pub fn all(predicate: &fn(T) -> bool, + iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { + // If we ever break, iter will return false, so this will only return true + // if predicate returns true for everything. + iter(|x| predicate(x)) +} + +/** + * Return the first element where `predicate` returns `true`. Return `None` if no element is found. + * + * # Example: + * + * ~~~~ + * let xs = ~[1u, 2, 3, 4, 5, 6]; + * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + * ~~~~ + */ +#[inline(always)] +#[cfg(not(stage0))] +pub fn find(predicate: &fn(&T) -> bool, + iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { + for iter |x| { + if predicate(&x) { + return Some(x); + } + } + None +} + +/** + * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + * ~~~~ + */ +#[inline] +#[cfg(not(stage0))] +pub fn max(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x > *y { + *y = x; + } + } + None => result = Some(x) } } - true + result +} + +/** + * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &-5); + * ~~~~ + */ +#[inline] +#[cfg(not(stage0))] +pub fn min(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x < *y { + *y = x; + } + } + None => result = Some(x) + } + } + result } #[cfg(test)] @@ -110,9 +218,9 @@ mod tests { use prelude::*; #[test] - fn test_iter_to_vec() { + fn test_to_vec() { let xs = ~[1, 2, 3]; - let ys = do iter_to_vec |f| { xs.each(|x| f(*x)) }; + let ys = do to_vec |f| { xs.each(|x| f(*x)) }; assert_eq!(xs, ys); } @@ -128,4 +236,22 @@ mod tests { assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); } + + #[test] + fn test_find() { + let xs = ~[1u, 2, 3, 4, 5, 6]; + assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + } + + #[test] + fn test_max() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + } + + #[test] + fn test_min() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); + } } diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 8bbf843085809..40c9637f692bc 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -29,7 +29,7 @@ pub trait Iterator { /// /// In the future these will be default methods instead of a utility trait. pub trait IteratorUtil { - fn chain(self, other: Self) -> ChainIterator; + fn chain>(self, other: U) -> ChainIterator; fn zip>(self, other: U) -> ZipIterator; // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; @@ -41,7 +41,10 @@ pub trait IteratorUtil { fn take(self, n: uint) -> TakeIterator; fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option) -> ScanIterator<'r, A, B, Self, St>; + #[cfg(stage0)] fn advance(&mut self, f: &fn(A) -> bool); + #[cfg(not(stage0))] + fn advance(&mut self, f: &fn(A) -> bool) -> bool; } /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also @@ -50,7 +53,7 @@ pub trait IteratorUtil { /// In the future these will be default methods instead of a utility trait. impl> IteratorUtil for T { #[inline(always)] - fn chain(self, other: T) -> ChainIterator { + fn chain>(self, other: U) -> ChainIterator { ChainIterator{a: self, b: other, flag: false} } @@ -103,25 +106,40 @@ impl> IteratorUtil for T { /// A shim implementing the `for` loop iteration protocol for iterator objects #[inline] + #[cfg(stage0)] fn advance(&mut self, f: &fn(A) -> bool) { loop { match self.next() { Some(x) => { - if !f(x) { return } + if !f(x) { return; } } - None => return + None => { return; } + } + } + } + + /// A shim implementing the `for` loop iteration protocol for iterator objects + #[inline] + #[cfg(not(stage0))] + fn advance(&mut self, f: &fn(A) -> bool) -> bool { + loop { + match self.next() { + Some(x) => { + if !f(x) { return false; } + } + None => { return true; } } } } } -pub struct ChainIterator { +pub struct ChainIterator { priv a: T, - priv b: T, + priv b: U, priv flag: bool } -impl> Iterator for ChainIterator { +impl, U: Iterator> Iterator for ChainIterator { #[inline] fn next(&mut self) -> Option { if self.flag { @@ -378,14 +396,14 @@ mod tests { #[test] fn test_counter_to_vec() { let mut it = Counter::new(0, 5).take(10); - let xs = iter::iter_to_vec(|f| it.advance(f)); + let xs = iter::to_vec(|f| it.advance(f)); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } #[test] fn test_iterator_chain() { let xs = [0u, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; + let ys = [30u, 40, 50, 60]; let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; let mut it = xs.iter().chain(ys.iter()); let mut i = 0; @@ -394,6 +412,15 @@ mod tests { i += 1; } assert_eq!(i, expected.len()); + + let ys = Counter::new(30u, 10).take(4); + let mut it = xs.iter().transform(|&x| x).chain(ys); + let mut i = 0; + for it.advance |x: uint| { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); } #[test] diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index 82ba0d42ce094..eeafc4cf786a5 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -30,8 +30,6 @@ The 4 kinds are * Const - types that are deeply immutable. Const types are used for freezable data structures. -* Durable - types that do not contain borrowed pointers. - `Copy` types include both implicitly copyable types that the compiler will copy automatically and non-implicitly copyable types that require the `copy` keyword to copy. Types that do not implement `Copy` may @@ -55,6 +53,7 @@ pub trait Const { } #[lang="durable"] +#[cfg(stage0)] pub trait Durable { // Empty. } diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index 44864630f9873..7ae3f0fd2d462 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -104,6 +104,7 @@ pub use libc::funcs::posix88::unistd::*; pub use libc::funcs::posix01::stat_::*; pub use libc::funcs::posix01::unistd::*; +pub use libc::funcs::posix01::glob::*; pub use libc::funcs::posix08::unistd::*; pub use libc::funcs::bsd44::*; @@ -210,7 +211,21 @@ pub mod types { #[cfg(target_os = "android")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, size_t}; + pub struct glob_t { + gl_pathc: size_t, + gl_pathv: **c_char, + gl_offs: size_t, + + __unused1: *c_void, + __unused2: *c_void, + __unused3: *c_void, + __unused4: *c_void, + __unused5: *c_void, + } + } } #[cfg(target_arch = "x86")] @@ -253,8 +268,7 @@ pub mod types { pub type ssize_t = i32; } pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_short, c_long, - time_t}; + use libc::types::os::arch::c95::{c_short, c_long, c_ulong, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; @@ -262,6 +276,9 @@ pub mod types { pub type nlink_t = u32; pub type blksize_t = i32; pub type blkcnt_t = i32; + + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "arm")] pub struct stat { st_dev: dev_t, __pad1: c_short, @@ -284,6 +301,30 @@ pub mod types { __unused4: c_long, __unused5: c_long, } + + #[cfg(target_arch = "mips")] + pub struct stat { + st_dev: c_ulong, + st_pad1: [c_long, ..3], + st_ino: ino_t, + st_mode: mode_t, + st_nlink: nlink_t, + st_uid: uid_t, + st_gid: gid_t, + st_rdev: c_ulong, + st_pad2: [c_long, ..2], + st_size: off_t, + st_pad3: c_long, + st_atime: time_t, + st_atime_nsec: c_long, + st_mtime: time_t, + st_mtime_nsec: c_long, + st_ctime: time_t, + st_ctime_nsec: c_long, + st_blksize: blksize_t, + st_blocks: blkcnt_t, + st_pad5: [c_long, ..14], + } } pub mod posix08 {} pub mod bsd44 {} @@ -369,7 +410,25 @@ pub mod types { #[cfg(target_os = "freebsd")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + pub struct glob_t { + gl_pathc: size_t, + __unused1: size_t, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } + } } #[cfg(target_arch = "x86_64")] @@ -549,12 +608,16 @@ pub mod types { pub type LPWSTR = *mut WCHAR; pub type LPSTR = *mut CHAR; + pub type LPTSTR = *mut CHAR; // Not really, but opaque to us. pub type LPSECURITY_ATTRIBUTES = LPVOID; pub type LPVOID = *mut c_void; + pub type LPBYTE = *mut BYTE; pub type LPWORD = *mut WORD; + pub type LPDWORD = *mut DWORD; + pub type LPHANDLE = *mut HANDLE; pub type LRESULT = LONG_PTR; pub type PBOOL = *mut BOOL; @@ -563,6 +626,36 @@ pub mod types { pub type time64_t = i64; pub type int64 = i64; + + pub struct STARTUPINFO { + cb: DWORD, + lpReserved: LPTSTR, + lpDesktop: LPTSTR, + lpTitle: LPTSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountCharts: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE + } + pub type LPSTARTUPINFO = *mut STARTUPINFO; + + pub struct PROCESS_INFORMATION { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD + } + pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; } } } @@ -571,6 +664,23 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + pub struct glob_t { + gl_pathc: size_t, + __unused1: c_int, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } } } @@ -798,6 +908,11 @@ pub mod consts { pub mod bsd44 { } pub mod extra { + use libc::types::os::arch::extra::{DWORD, BOOL}; + + pub static TRUE : BOOL = 1; + pub static FALSE : BOOL = 0; + pub static O_TEXT : int = 16384; pub static O_BINARY : int = 32768; pub static O_NOINHERIT: int = 128; @@ -805,6 +920,50 @@ pub mod consts { pub static ERROR_SUCCESS : int = 0; pub static ERROR_INSUFFICIENT_BUFFER : int = 122; pub static INVALID_HANDLE_VALUE: int = -1; + + pub static DELETE : DWORD = 0x00010000; + pub static READ_CONTROL : DWORD = 0x00020000; + pub static SYNCHRONIZE : DWORD = 0x00100000; + pub static WRITE_DAC : DWORD = 0x00040000; + pub static WRITE_OWNER : DWORD = 0x00080000; + + pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080; + pub static PROCESS_CREATE_THREAD : DWORD = 0x0002; + pub static PROCESS_DUP_HANDLE : DWORD = 0x0040; + pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400; + pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000; + pub static PROCESS_SET_INFORMATION : DWORD = 0x0200; + pub static PROCESS_SET_QUOTA : DWORD = 0x0100; + pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800; + pub static PROCESS_TERMINATE : DWORD = 0x0001; + pub static PROCESS_VM_OPERATION : DWORD = 0x0008; + pub static PROCESS_VM_READ : DWORD = 0x0010; + pub static PROCESS_VM_WRITE : DWORD = 0x0020; + + pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040; + pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080; + pub static STARTF_PREVENTPINNING : DWORD = 0x00002000; + pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020; + pub static STARTF_TITLEISAPPID : DWORD = 0x00001000; + pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800; + pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008; + pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010; + pub static STARTF_USEHOTKEY : DWORD = 0x00000200; + pub static STARTF_USEPOSITION : DWORD = 0x00000004; + pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001; + pub static STARTF_USESIZE : DWORD = 0x00000002; + pub static STARTF_USESTDHANDLES : DWORD = 0x00000100; + + pub static WAIT_ABANDONED : DWORD = 0x00000080; + pub static WAIT_OBJECT_0 : DWORD = 0x00000000; + pub static WAIT_TIMEOUT : DWORD = 0x00000102; + pub static WAIT_FAILED : DWORD = -1; + + pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; + pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; + + pub static INFINITE : DWORD = -1; + pub static STILL_ACTIVE : DWORD = 259; } } @@ -831,6 +990,9 @@ pub mod consts { } pub mod c99 { } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "arm")] pub mod posix88 { pub static O_RDONLY : int = 0; pub static O_WRONLY : int = 1; @@ -875,18 +1037,84 @@ pub mod consts { pub static SIGALRM : int = 14; pub static SIGTERM : int = 15; } + #[cfg(target_arch = "mips")] + pub mod posix88 { + pub static O_RDONLY : int = 0; + pub static O_WRONLY : int = 1; + pub static O_RDWR : int = 2; + pub static O_APPEND : int = 8; + pub static O_CREAT : int = 256; + pub static O_EXCL : int = 1024; + pub static O_TRUNC : int = 512; + pub static S_IFIFO : int = 4096; + pub static S_IFCHR : int = 8192; + pub static S_IFBLK : int = 24576; + pub static S_IFDIR : int = 16384; + pub static S_IFREG : int = 32768; + pub static S_IFMT : int = 61440; + pub static S_IEXEC : int = 64; + pub static S_IWRITE : int = 128; + pub static S_IREAD : int = 256; + pub static S_IRWXU : int = 448; + pub static S_IXUSR : int = 64; + pub static S_IWUSR : int = 128; + pub static S_IRUSR : int = 256; + pub static F_OK : int = 0; + pub static R_OK : int = 4; + pub static W_OK : int = 2; + pub static X_OK : int = 1; + pub static STDIN_FILENO : int = 0; + pub static STDOUT_FILENO : int = 1; + pub static STDERR_FILENO : int = 2; + pub static F_LOCK : int = 1; + pub static F_TEST : int = 3; + pub static F_TLOCK : int = 2; + pub static F_ULOCK : int = 0; + pub static SIGHUP : int = 1; + pub static SIGINT : int = 2; + pub static SIGQUIT : int = 3; + pub static SIGILL : int = 4; + pub static SIGABRT : int = 6; + pub static SIGFPE : int = 8; + pub static SIGKILL : int = 9; + pub static SIGSEGV : int = 11; + pub static SIGPIPE : int = 13; + pub static SIGALRM : int = 14; + pub static SIGTERM : int = 15; + } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_ERR : int = 1 << 0; + pub static GLOB_MARK : int = 1 << 1; + pub static GLOB_NOSORT : int = 1 << 2; + pub static GLOB_DOOFFS : int = 1 << 3; + pub static GLOB_NOCHECK : int = 1 << 4; + pub static GLOB_APPEND : int = 1 << 5; + pub static GLOB_NOESCAPE : int = 1 << 6; + + pub static GLOB_NOSPACE : int = 1; + pub static GLOB_ABORTED : int = 2; + pub static GLOB_NOMATCH : int = 3; } pub mod posix08 { } pub mod bsd44 { } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "arm")] pub mod extra { pub static O_RSYNC : int = 1052672; pub static O_DSYNC : int = 4096; pub static O_SYNC : int = 1052672; } + #[cfg(target_arch = "mips")] + pub mod extra { + pub static O_RSYNC : int = 16400; + pub static O_DSYNC : int = 16; + pub static O_SYNC : int = 16400; + } } #[cfg(target_os = "freebsd")] @@ -956,6 +1184,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1036,6 +1276,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1606,6 +1858,21 @@ pub mod funcs { -> pid_t; } } + + #[nolink] + #[abi = "cdecl"] + pub mod glob { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int}; + use libc::types::os::common::posix01::{glob_t}; + + pub extern { + unsafe fn glob(pattern: *c_char, flags: c_int, + errfunc: *c_void, // XXX callback + pglob: *mut glob_t); + unsafe fn globfree(pglob: *mut glob_t); + } + } } #[cfg(target_os = "win32")] @@ -1615,6 +1882,9 @@ pub mod funcs { pub mod unistd { } + + pub mod glob { + } } @@ -1647,12 +1917,24 @@ pub mod funcs { unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int, sizep: *mut size_t) -> c_int; + + unsafe fn getdtablesize() -> c_int; } } #[cfg(target_os = "linux")] #[cfg(target_os = "android")] + pub mod bsd44 { + use libc::types::os::arch::c95::{c_int}; + + #[abi = "cdecl"] + pub extern { + unsafe fn getdtablesize() -> c_int; + } + } + + #[cfg(target_os = "win32")] pub mod bsd44 { } @@ -1686,9 +1968,11 @@ pub mod funcs { pub mod kernel32 { use libc::types::os::arch::c95::{c_uint}; use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; - use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH}; - use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES}; - use libc::types::os::arch::extra::{HANDLE}; + use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR, + LPTSTR, LPTCH, LPDWORD, LPVOID}; + use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO, + LPPROCESS_INFORMATION}; + use libc::types::os::arch::extra::{HANDLE, LPHANDLE}; #[abi = "stdcall"] pub extern "stdcall" { @@ -1725,29 +2009,46 @@ pub mod funcs { findFileData: HANDLE) -> BOOL; unsafe fn FindClose(findFile: HANDLE) -> BOOL; + unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD) -> BOOL; unsafe fn CloseHandle(hObject: HANDLE) -> BOOL; + unsafe fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + unsafe fn GetCurrentProcess() -> HANDLE; + unsafe fn CreateProcessA(lpApplicationName: LPCTSTR, + lpCommandLine: LPTSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCTSTR, + lpStartupInfo: LPSTARTUPINFO, + lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL; + unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; + unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; } } pub mod msvcrt { - use libc::types::os::arch::c95::c_int; + use libc::types::os::arch::c95::{c_int, c_long}; #[abi = "cdecl"] #[nolink] pub extern { #[link_name = "_commit"] unsafe fn commit(fd: c_int) -> c_int; + + #[link_name = "_get_osfhandle"] + unsafe fn get_osfhandle(fd: c_int) -> c_long; } } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/task/local_data.rs b/src/libcore/local_data.rs similarity index 92% rename from src/libcore/task/local_data.rs rename to src/libcore/local_data.rs index 6050aca6dc1f5..d4b02a0ad9bbf 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/local_data.rs @@ -27,8 +27,7 @@ magic. */ use prelude::*; -use task::local_data_priv::{local_get, local_pop, local_modify, local_set}; -use task::rt; +use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; /** * Indexes a task-local data slot. The function's code pointer is used for @@ -50,38 +49,38 @@ pub type LocalDataKey<'self,T> = &'self fn(v: @T); * Remove a task-local data value from the table, returning the * reference that was originally created to insert it. */ -pub unsafe fn local_data_pop( +pub unsafe fn local_data_pop( key: LocalDataKey) -> Option<@T> { - local_pop(rt::rust_get_task(), key) + local_pop(Handle::new(), key) } /** * Retrieve a task-local data value. It will also be kept alive in the * table until explicitly removed. */ -pub unsafe fn local_data_get( +pub unsafe fn local_data_get( key: LocalDataKey) -> Option<@T> { - local_get(rt::rust_get_task(), key) + local_get(Handle::new(), key) } /** * Store a value in task-local data. If this key already has a value, * that value is overwritten (and its destructor is run). */ -pub unsafe fn local_data_set( +pub unsafe fn local_data_set( key: LocalDataKey, data: @T) { - local_set(rt::rust_get_task(), key, data) + local_set(Handle::new(), key, data) } /** * Modify a task-local data value. If the function returns 'None', the * data is removed (and its reference dropped). */ -pub unsafe fn local_data_modify( +pub unsafe fn local_data_modify( key: LocalDataKey, modify_fn: &fn(Option<@T>) -> Option<@T>) { - local_modify(rt::rust_get_task(), key, modify_fn) + local_modify(Handle::new(), key, modify_fn) } #[test] @@ -216,3 +215,12 @@ fn test_tls_cleanup_on_failure() { fail!(); } } + +#[test] +fn test_static_pointer() { + unsafe { + fn key(_x: @&'static int) { } + static VALUE: int = 0; + local_data_set(key, @&VALUE); + } +} \ No newline at end of file diff --git a/src/libcore/logging.rs b/src/libcore/logging.rs index ba976de50ab48..cea827298af06 100644 --- a/src/libcore/logging.rs +++ b/src/libcore/logging.rs @@ -42,9 +42,10 @@ pub fn console_off() { } } -#[cfg(notest)] +#[cfg(not(test))] #[lang="log_type"] pub fn log_type(level: u32, object: &T) { + use container::Container; use cast::transmute; use io; use libc; @@ -59,4 +60,3 @@ pub fn log_type(level: u32, object: &T) { rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len); } } - diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs new file mode 100644 index 0000000000000..b19a753b71577 --- /dev/null +++ b/src/libcore/macros.rs @@ -0,0 +1,39 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_escape]; + +// Some basic logging +macro_rules! rtdebug_ ( + ($( $arg:expr),+) => ( { + dumb_println(fmt!( $($arg),+ )); + + fn dumb_println(s: &str) { + use io::WriterUtil; + let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + dbg.write_str(s); + dbg.write_str("\n"); + } + + } ) +) + +// An alternate version with no output, for turning off logging +macro_rules! rtdebug ( + ($( $arg:expr),+) => ( $(let _ = $arg)*; ) +) + +macro_rules! abort( + ($( $msg:expr),+) => ( { + rtdebug!($($msg),+); + + unsafe { ::libc::abort(); } + } ) +) diff --git a/src/libcore/managed.rs b/src/libcore/managed.rs index debca1ead82f8..d2bb88ca30202 100644 --- a/src/libcore/managed.rs +++ b/src/libcore/managed.rs @@ -12,7 +12,7 @@ use ptr::to_unsafe_ptr; -#[cfg(notest)] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::{Eq, Ord}; pub mod raw { use intrinsic::TyDesc; @@ -49,7 +49,7 @@ pub fn mut_ptr_eq(a: @mut T, b: @mut T) -> bool { a_ptr == b_ptr } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for @T { #[inline(always)] fn eq(&self, other: &@T) -> bool { *(*self) == *(*other) } @@ -57,7 +57,7 @@ impl Eq for @T { fn ne(&self, other: &@T) -> bool { *(*self) != *(*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for @mut T { #[inline(always)] fn eq(&self, other: &@mut T) -> bool { *(*self) == *(*other) } @@ -65,7 +65,7 @@ impl Eq for @mut T { fn ne(&self, other: &@mut T) -> bool { *(*self) != *(*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for @T { #[inline(always)] fn lt(&self, other: &@T) -> bool { *(*self) < *(*other) } @@ -77,7 +77,7 @@ impl Ord for @T { fn gt(&self, other: &@T) -> bool { *(*self) > *(*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for @mut T { #[inline(always)] fn lt(&self, other: &@mut T) -> bool { *(*self) < *(*other) } diff --git a/src/libcore/nil.rs b/src/libcore/nil.rs index 6b8c390fc2575..833bd3459cebf 100644 --- a/src/libcore/nil.rs +++ b/src/libcore/nil.rs @@ -14,10 +14,10 @@ Functions for the unit type. */ -#[cfg(notest)] +#[cfg(not(test))] use prelude::*; -#[cfg(notest)] +#[cfg(not(test))] impl Eq for () { #[inline(always)] fn eq(&self, _other: &()) -> bool { true } @@ -25,7 +25,7 @@ impl Eq for () { fn ne(&self, _other: &()) -> bool { false } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for () { #[inline(always)] fn lt(&self, _other: &()) -> bool { false } @@ -37,13 +37,13 @@ impl Ord for () { fn gt(&self, _other: &()) -> bool { false } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for () { #[inline(always)] fn cmp(&self, _other: &()) -> Ordering { Equal } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalEq for () { #[inline(always)] fn equals(&self, _other: &()) -> bool { true } diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs index 30b0c54dc2dc2..a80703fafa3d2 100644 --- a/src/libcore/num/cmath.rs +++ b/src/libcore/num/cmath.rs @@ -33,7 +33,8 @@ pub mod c_double_utils { unsafe fn erf(n: c_double) -> c_double; unsafe fn erfc(n: c_double) -> c_double; unsafe fn exp(n: c_double) -> c_double; - unsafe fn expm1(n: c_double) -> c_double; + // rename: for consistency with underscore usage elsewhere + #[link_name="expm1"] unsafe fn exp_m1(n: c_double) -> c_double; unsafe fn exp2(n: c_double) -> c_double; #[link_name="fabs"] unsafe fn abs(n: c_double) -> c_double; // rename: for clarity and consistency with add/sub/mul/div @@ -63,7 +64,7 @@ pub mod c_double_utils { // renamed: "logb" /often/ is confused for log2 by beginners #[link_name="logb"] unsafe fn log_radix(n: c_double) -> c_double; // renamed: to be consitent with log as ln - #[link_name="log1p"] unsafe fn ln1p(n: c_double) -> c_double; + #[link_name="log1p"] unsafe fn ln_1p(n: c_double) -> c_double; unsafe fn log10(n: c_double) -> c_double; unsafe fn log2(n: c_double) -> c_double; #[link_name="ilogb"] unsafe fn ilog_radix(n: c_double) -> c_int; @@ -117,7 +118,7 @@ pub mod c_float_utils { #[link_name="erff"] unsafe fn erf(n: c_float) -> c_float; #[link_name="erfcf"] unsafe fn erfc(n: c_float) -> c_float; #[link_name="expf"] unsafe fn exp(n: c_float) -> c_float; - #[link_name="expm1f"]unsafe fn expm1(n: c_float) -> c_float; + #[link_name="expm1f"]unsafe fn exp_m1(n: c_float) -> c_float; #[link_name="exp2f"] unsafe fn exp2(n: c_float) -> c_float; #[link_name="fabsf"] unsafe fn abs(n: c_float) -> c_float; #[link_name="fdimf"] @@ -148,7 +149,7 @@ pub mod c_float_utils { #[link_name="logf"] unsafe fn ln(n: c_float) -> c_float; #[link_name="logbf"] unsafe fn log_radix(n: c_float) -> c_float; - #[link_name="log1pf"] unsafe fn ln1p(n: c_float) -> c_float; + #[link_name="log1pf"] unsafe fn ln_1p(n: c_float) -> c_float; #[link_name="log2f"] unsafe fn log2(n: c_float) -> c_float; #[link_name="log10f"] unsafe fn log10(n: c_float) -> c_float; #[link_name="ilogbf"] unsafe fn ilog_radix(n: c_float) -> c_int; @@ -267,14 +268,3 @@ pub mod c_double_targ_consts { } */ - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// - diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index e687f482fa98c..a872a6388ba46 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,8 +10,8 @@ //! Operations and constants for `f32` -use from_str; use num::{Zero, One, strconv}; +use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; use prelude::*; pub use cmath::c_float_targ_consts::*; @@ -83,7 +83,7 @@ delegate!( fn cosh(n: c_float) -> c_float = c_float_utils::cosh, fn erf(n: c_float) -> c_float = c_float_utils::erf, fn erfc(n: c_float) -> c_float = c_float_utils::erfc, - fn expm1(n: c_float) -> c_float = c_float_utils::expm1, + fn exp_m1(n: c_float) -> c_float = c_float_utils::exp_m1, fn abs_sub(a: c_float, b: c_float) -> c_float = c_float_utils::abs_sub, fn fmax(a: c_float, b: c_float) -> c_float = c_float_utils::fmax, fn fmin(a: c_float, b: c_float) -> c_float = c_float_utils::fmin, @@ -93,7 +93,7 @@ delegate!( fn ldexp(x: c_float, n: c_int) -> c_float = c_float_utils::ldexp, fn lgamma(n: c_float, sign: &mut c_int) -> c_float = c_float_utils::lgamma, fn log_radix(n: c_float) -> c_float = c_float_utils::log_radix, - fn ln1p(n: c_float) -> c_float = c_float_utils::ln1p, + fn ln_1p(n: c_float) -> c_float = c_float_utils::ln_1p, fn ilog_radix(n: c_float) -> c_int = c_float_utils::ilog_radix, fn modf(n: c_float, iptr: &mut c_float) -> c_float = c_float_utils::modf, fn round(n: c_float) -> c_float = c_float_utils::round, @@ -123,7 +123,7 @@ pub fn sub(x: f32, y: f32) -> f32 { return x - y; } pub fn mul(x: f32, y: f32) -> f32 { return x * y; } #[inline(always)] -pub fn quot(x: f32, y: f32) -> f32 { return x / y; } +pub fn div(x: f32, y: f32) -> f32 { return x / y; } #[inline(always)] pub fn rem(x: f32, y: f32) -> f32 { return x % y; } @@ -196,14 +196,9 @@ pub mod consts { pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[inline(always)] -pub fn logarithm(n: f32, b: f32) -> f32 { - return log2(n) / log2(b); -} - impl Num for f32 {} -#[cfg(notest)] +#[cfg(not(test))] impl Eq for f32 { #[inline(always)] fn eq(&self, other: &f32) -> bool { (*self) == (*other) } @@ -211,7 +206,23 @@ impl Eq for f32 { fn ne(&self, other: &f32) -> bool { (*self) != (*other) } } -#[cfg(notest)] +#[cfg(not(test))] +impl ApproxEq for f32 { + #[inline(always)] + fn approx_epsilon() -> f32 { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &f32) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + +#[cfg(not(test))] impl Ord for f32 { #[inline(always)] fn lt(&self, other: &f32) -> bool { (*self) < (*other) } @@ -261,47 +272,37 @@ impl One for f32 { fn one() -> f32 { 1.0 } } -#[cfg(notest)] +#[cfg(not(test))] impl Add for f32 { #[inline(always)] fn add(&self, other: &f32) -> f32 { *self + *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Sub for f32 { #[inline(always)] fn sub(&self, other: &f32) -> f32 { *self - *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Mul for f32 { #[inline(always)] fn mul(&self, other: &f32) -> f32 { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(not(test))] impl Div for f32 { #[inline(always)] fn div(&self, other: &f32) -> f32 { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for f32 { - #[inline(always)] - fn quot(&self, other: &f32) -> f32 { *self / *other } -} -#[cfg(stage0,notest)] -impl Modulo for f32 { - #[inline(always)] - fn modulo(&self, other: &f32) -> f32 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(not(test))] impl Rem for f32 { #[inline(always)] fn rem(&self, other: &f32) -> f32 { *self % *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Neg for f32 { #[inline(always)] fn neg(&self) -> f32 { -*self } @@ -312,6 +313,13 @@ impl Signed for f32 { #[inline(always)] fn abs(&self) -> f32 { abs(*self) } + /// + /// The positive difference of two numbers. Returns `0.0` if the number is less than or + /// equal to `other`, otherwise the difference between`self` and `other` is returned. + /// + #[inline(always)] + fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) } + /// /// # Returns /// @@ -408,21 +416,27 @@ impl Trigonometric for f32 { } impl Exponential for f32 { + /// Returns the exponential of the number #[inline(always)] fn exp(&self) -> f32 { exp(*self) } + /// Returns 2 raised to the power of the number #[inline(always)] fn exp2(&self) -> f32 { exp2(*self) } + /// Returns the natural logarithm of the number #[inline(always)] - fn expm1(&self) -> f32 { expm1(*self) } + fn ln(&self) -> f32 { ln(*self) } + /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self) -> f32 { ln(*self) } + fn log(&self, base: f32) -> f32 { self.ln() / base.ln() } + /// Returns the base 2 logarithm of the number #[inline(always)] fn log2(&self) -> f32 { log2(*self) } + /// Returns the base 10 logarithm of the number #[inline(always)] fn log10(&self) -> f32 { log10(*self) } } @@ -499,13 +513,13 @@ impl Real for f32 { #[inline(always)] fn log10_e() -> f32 { 0.434294481903251827651128918916605082 } - /// log(2.0) + /// ln(2.0) #[inline(always)] - fn log_2() -> f32 { 0.693147180559945309417232121458176568 } + fn ln_2() -> f32 { 0.693147180559945309417232121458176568 } - /// log(10.0) + /// ln(10.0) #[inline(always)] - fn log_10() -> f32 { 2.30258509299404568401799145468436421 } + fn ln_10() -> f32 { 2.30258509299404568401799145468436421 } /// Converts to degrees, assuming the number is in radians #[inline(always)] @@ -545,9 +559,46 @@ impl Float for f32 { #[inline(always)] fn neg_zero() -> f32 { -0.0 } + /// Returns `true` if the number is NaN #[inline(always)] fn is_NaN(&self) -> bool { *self != *self } + /// Returns `true` if the number is infinite + #[inline(always)] + fn is_infinite(&self) -> bool { + *self == Float::infinity() || *self == Float::neg_infinity() + } + + /// Returns `true` if the number is neither infinite or NaN + #[inline(always)] + fn is_finite(&self) -> bool { + !(self.is_NaN() || self.is_infinite()) + } + + /// Returns `true` if the number is neither zero, infinite, subnormal or NaN + #[inline(always)] + fn is_normal(&self) -> bool { + self.classify() == FPNormal + } + + /// Returns the floating point category of the number. If only one property is going to + /// be tested, it is generally faster to use the specific predicate instead. + fn classify(&self) -> FPCategory { + static EXP_MASK: u32 = 0x7f800000; + static MAN_MASK: u32 = 0x007fffff; + + match ( + unsafe { ::cast::transmute::(*self) } & MAN_MASK, + unsafe { ::cast::transmute::(*self) } & EXP_MASK, + ) { + (0, 0) => FPZero, + (_, 0) => FPSubnormal, + (0, EXP_MASK) => FPInfinite, + (_, EXP_MASK) => FPNaN, + _ => FPNormal, + } + } + #[inline(always)] fn mantissa_digits() -> uint { 24 } @@ -569,17 +620,19 @@ impl Float for f32 { #[inline(always)] fn max_10_exp() -> int { 38 } - /// Returns `true` if the number is infinite + /// + /// Returns the exponential of the number, minus `1`, in a way that is accurate + /// even if the number is close to zero + /// #[inline(always)] - fn is_infinite(&self) -> bool { - *self == Float::infinity() || *self == Float::neg_infinity() - } + fn exp_m1(&self) -> f32 { exp_m1(*self) } - /// Returns `true` if the number is finite + /// + /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately + /// than if the operations were performed separately + /// #[inline(always)] - fn is_finite(&self) -> bool { - !(self.is_NaN() || self.is_infinite()) - } + fn ln_1p(&self) -> f32 { ln_1p(*self) } /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This @@ -803,7 +856,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for f32 { +impl FromStr for f32 { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } @@ -818,18 +871,10 @@ impl num::FromStrRadix for f32 { #[cfg(test)] mod tests { use f32::*; + use num::*; use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f32, 2f32); @@ -859,95 +904,95 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.3f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.5f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.7f32.floor(), 1.0f32); - assert_fuzzy_eq!(0.0f32.floor(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).floor(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).floor(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).floor(), -2.0f32); - assert_fuzzy_eq!((-1.5f32).floor(), -2.0f32); - assert_fuzzy_eq!((-1.7f32).floor(), -2.0f32); + assert_approx_eq!(1.0f32.floor(), 1.0f32); + assert_approx_eq!(1.3f32.floor(), 1.0f32); + assert_approx_eq!(1.5f32.floor(), 1.0f32); + assert_approx_eq!(1.7f32.floor(), 1.0f32); + assert_approx_eq!(0.0f32.floor(), 0.0f32); + assert_approx_eq!((-0.0f32).floor(), -0.0f32); + assert_approx_eq!((-1.0f32).floor(), -1.0f32); + assert_approx_eq!((-1.3f32).floor(), -2.0f32); + assert_approx_eq!((-1.5f32).floor(), -2.0f32); + assert_approx_eq!((-1.7f32).floor(), -2.0f32); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f32.ceil(), 1.0f32); - assert_fuzzy_eq!(1.3f32.ceil(), 2.0f32); - assert_fuzzy_eq!(1.5f32.ceil(), 2.0f32); - assert_fuzzy_eq!(1.7f32.ceil(), 2.0f32); - assert_fuzzy_eq!(0.0f32.ceil(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).ceil(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.7f32).ceil(), -1.0f32); + assert_approx_eq!(1.0f32.ceil(), 1.0f32); + assert_approx_eq!(1.3f32.ceil(), 2.0f32); + assert_approx_eq!(1.5f32.ceil(), 2.0f32); + assert_approx_eq!(1.7f32.ceil(), 2.0f32); + assert_approx_eq!(0.0f32.ceil(), 0.0f32); + assert_approx_eq!((-0.0f32).ceil(), -0.0f32); + assert_approx_eq!((-1.0f32).ceil(), -1.0f32); + assert_approx_eq!((-1.3f32).ceil(), -1.0f32); + assert_approx_eq!((-1.5f32).ceil(), -1.0f32); + assert_approx_eq!((-1.7f32).ceil(), -1.0f32); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f32.round(), 1.0f32); - assert_fuzzy_eq!(1.3f32.round(), 1.0f32); - assert_fuzzy_eq!(1.5f32.round(), 2.0f32); - assert_fuzzy_eq!(1.7f32.round(), 2.0f32); - assert_fuzzy_eq!(0.0f32.round(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).round(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).round(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).round(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).round(), -2.0f32); - assert_fuzzy_eq!((-1.7f32).round(), -2.0f32); + assert_approx_eq!(1.0f32.round(), 1.0f32); + assert_approx_eq!(1.3f32.round(), 1.0f32); + assert_approx_eq!(1.5f32.round(), 2.0f32); + assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(0.0f32.round(), 0.0f32); + assert_approx_eq!((-0.0f32).round(), -0.0f32); + assert_approx_eq!((-1.0f32).round(), -1.0f32); + assert_approx_eq!((-1.3f32).round(), -1.0f32); + assert_approx_eq!((-1.5f32).round(), -2.0f32); + assert_approx_eq!((-1.7f32).round(), -2.0f32); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.3f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.5f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.7f32.trunc(), 1.0f32); - assert_fuzzy_eq!(0.0f32.trunc(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).trunc(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.7f32).trunc(), -1.0f32); + assert_approx_eq!(1.0f32.trunc(), 1.0f32); + assert_approx_eq!(1.3f32.trunc(), 1.0f32); + assert_approx_eq!(1.5f32.trunc(), 1.0f32); + assert_approx_eq!(1.7f32.trunc(), 1.0f32); + assert_approx_eq!(0.0f32.trunc(), 0.0f32); + assert_approx_eq!((-0.0f32).trunc(), -0.0f32); + assert_approx_eq!((-1.0f32).trunc(), -1.0f32); + assert_approx_eq!((-1.3f32).trunc(), -1.0f32); + assert_approx_eq!((-1.5f32).trunc(), -1.0f32); + assert_approx_eq!((-1.7f32).trunc(), -1.0f32); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f32.fract(), 0.0f32); - assert_fuzzy_eq!(1.3f32.fract(), 0.3f32); - assert_fuzzy_eq!(1.5f32.fract(), 0.5f32); - assert_fuzzy_eq!(1.7f32.fract(), 0.7f32); - assert_fuzzy_eq!(0.0f32.fract(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).fract(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).fract(), -0.0f32); - assert_fuzzy_eq!((-1.3f32).fract(), -0.3f32); - assert_fuzzy_eq!((-1.5f32).fract(), -0.5f32); - assert_fuzzy_eq!((-1.7f32).fract(), -0.7f32); + assert_approx_eq!(1.0f32.fract(), 0.0f32); + assert_approx_eq!(1.3f32.fract(), 0.3f32); + assert_approx_eq!(1.5f32.fract(), 0.5f32); + assert_approx_eq!(1.7f32.fract(), 0.7f32); + assert_approx_eq!(0.0f32.fract(), 0.0f32); + assert_approx_eq!((-0.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.3f32).fract(), -0.3f32); + assert_approx_eq!((-1.5f32).fract(), -0.5f32); + assert_approx_eq!((-1.7f32).fract(), -0.7f32); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2f32 * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f32.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f32.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f32.log()); + assert_approx_eq!(Real::two_pi::(), 2f32 * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); + assert_approx_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f32.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::ln_2::(), 2f32.ln()); + assert_approx_eq!(Real::ln_10::(), 10f32.ln()); } #[test] - pub fn test_signed() { + pub fn test_abs() { assert_eq!(infinity.abs(), infinity); assert_eq!(1f32.abs(), 1f32); assert_eq!(0f32.abs(), 0f32); @@ -956,7 +1001,24 @@ mod tests { assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f32/neg_infinity).abs(), 0f32); assert!(NaN.abs().is_NaN()); + } + + #[test] + fn test_abs_sub() { + assert_eq!((-1f32).abs_sub(&1f32), 0f32); + assert_eq!(1f32.abs_sub(&1f32), 0f32); + assert_eq!(1f32.abs_sub(&0f32), 1f32); + assert_eq!(1f32.abs_sub(&-1f32), 2f32); + assert_eq!(neg_infinity.abs_sub(&0f32), 0f32); + assert_eq!(infinity.abs_sub(&1f32), infinity); + assert_eq!(0f32.abs_sub(&neg_infinity), infinity); + assert_eq!(0f32.abs_sub(&infinity), 0f32); + assert!(NaN.abs_sub(&-1f32).is_NaN()); + assert!(1f32.abs_sub(&NaN).is_NaN()); + } + #[test] + fn test_signum() { assert_eq!(infinity.signum(), 1f32); assert_eq!(1f32.signum(), 1f32); assert_eq!(0f32.signum(), 1f32); @@ -965,7 +1027,10 @@ mod tests { assert_eq!(neg_infinity.signum(), -1f32); assert_eq!((1f32/neg_infinity).signum(), -1f32); assert!(NaN.signum().is_NaN()); + } + #[test] + fn test_is_positive() { assert!(infinity.is_positive()); assert!(1f32.is_positive()); assert!(0f32.is_positive()); @@ -974,7 +1039,10 @@ mod tests { assert!(!neg_infinity.is_positive()); assert!(!(1f32/neg_infinity).is_positive()); assert!(!NaN.is_positive()); + } + #[test] + fn test_is_negative() { assert!(!infinity.is_negative()); assert!(!1f32.is_negative()); assert!(!0f32.is_negative()); @@ -985,19 +1053,42 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f32.approx_eq(&1f32)); + assert!(0.9999999f32.approx_eq(&1f32)); + assert!(1.000001f32.approx_eq_eps(&1f32, &1.0e-5)); + assert!(1.0000001f32.approx_eq_eps(&1f32, &1.0e-6)); + assert!(!1.0000001f32.approx_eq_eps(&1f32, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); assert_eq!(Primitive::bytes::(), sys::size_of::()); } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// + #[test] + fn test_is_normal() { + assert!(!Float::NaN::().is_normal()); + assert!(!Float::infinity::().is_normal()); + assert!(!Float::neg_infinity::().is_normal()); + assert!(!Zero::zero::().is_normal()); + assert!(!Float::neg_zero::().is_normal()); + assert!(1f32.is_normal()); + assert!(1e-37f32.is_normal()); + assert!(!1e-38f32.is_normal()); + } + + #[test] + fn test_classify() { + assert_eq!(Float::NaN::().classify(), FPNaN); + assert_eq!(Float::infinity::().classify(), FPInfinite); + assert_eq!(Float::neg_infinity::().classify(), FPInfinite); + assert_eq!(Zero::zero::().classify(), FPZero); + assert_eq!(Float::neg_zero::().classify(), FPZero); + assert_eq!(1f32.classify(), FPNormal); + assert_eq!(1e-37f32.classify(), FPNormal); + assert_eq!(1e-38f32.classify(), FPSubnormal); + } +} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d00e6ae2c0d79..8a17ae91934bb 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,9 +10,9 @@ //! Operations and constants for `f64` -use from_str; use libc::c_int; use num::{Zero, One, strconv}; +use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; use prelude::*; pub use cmath::c_double_targ_consts::*; @@ -85,7 +85,7 @@ delegate!( fn cosh(n: c_double) -> c_double = c_double_utils::cosh, fn erf(n: c_double) -> c_double = c_double_utils::erf, fn erfc(n: c_double) -> c_double = c_double_utils::erfc, - fn expm1(n: c_double) -> c_double = c_double_utils::expm1, + fn exp_m1(n: c_double) -> c_double = c_double_utils::exp_m1, fn abs_sub(a: c_double, b: c_double) -> c_double = c_double_utils::abs_sub, fn fmax(a: c_double, b: c_double) -> c_double = c_double_utils::fmax, fn fmin(a: c_double, b: c_double) -> c_double = c_double_utils::fmin, @@ -95,7 +95,7 @@ delegate!( fn ldexp(x: c_double, n: c_int) -> c_double = c_double_utils::ldexp, fn lgamma(n: c_double, sign: &mut c_int) -> c_double = c_double_utils::lgamma, fn log_radix(n: c_double) -> c_double = c_double_utils::log_radix, - fn ln1p(n: c_double) -> c_double = c_double_utils::ln1p, + fn ln_1p(n: c_double) -> c_double = c_double_utils::ln_1p, fn ilog_radix(n: c_double) -> c_int = c_double_utils::ilog_radix, fn modf(n: c_double, iptr: &mut c_double) -> c_double = c_double_utils::modf, fn round(n: c_double) -> c_double = c_double_utils::round, @@ -149,7 +149,7 @@ pub fn sub(x: f64, y: f64) -> f64 { return x - y; } pub fn mul(x: f64, y: f64) -> f64 { return x * y; } #[inline(always)] -pub fn quot(x: f64, y: f64) -> f64 { return x / y; } +pub fn div(x: f64, y: f64) -> f64 { return x / y; } #[inline(always)] pub fn rem(x: f64, y: f64) -> f64 { return x % y; } @@ -219,14 +219,9 @@ pub mod consts { pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[inline(always)] -pub fn logarithm(n: f64, b: f64) -> f64 { - return log2(n) / log2(b); -} - impl Num for f64 {} -#[cfg(notest)] +#[cfg(not(test))] impl Eq for f64 { #[inline(always)] fn eq(&self, other: &f64) -> bool { (*self) == (*other) } @@ -234,7 +229,23 @@ impl Eq for f64 { fn ne(&self, other: &f64) -> bool { (*self) != (*other) } } -#[cfg(notest)] +#[cfg(not(test))] +impl ApproxEq for f64 { + #[inline(always)] + fn approx_epsilon() -> f64 { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &f64) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + +#[cfg(not(test))] impl Ord for f64 { #[inline(always)] fn lt(&self, other: &f64) -> bool { (*self) < (*other) } @@ -284,37 +295,28 @@ impl One for f64 { fn one() -> f64 { 1.0 } } -#[cfg(notest)] +#[cfg(not(test))] impl Add for f64 { fn add(&self, other: &f64) -> f64 { *self + *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Sub for f64 { fn sub(&self, other: &f64) -> f64 { *self - *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Mul for f64 { fn mul(&self, other: &f64) -> f64 { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(not(test))] impl Div for f64 { fn div(&self, other: &f64) -> f64 { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for f64 { - #[inline(always)] - fn quot(&self, other: &f64) -> f64 { *self / *other } -} -#[cfg(stage0,notest)] -impl Modulo for f64 { - fn modulo(&self, other: &f64) -> f64 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(not(test))] impl Rem for f64 { #[inline(always)] fn rem(&self, other: &f64) -> f64 { *self % *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Neg for f64 { fn neg(&self) -> f64 { -*self } } @@ -324,6 +326,13 @@ impl Signed for f64 { #[inline(always)] fn abs(&self) -> f64 { abs(*self) } + /// + /// The positive difference of two numbers. Returns `0.0` if the number is less than or + /// equal to `other`, otherwise the difference between`self` and `other` is returned. + /// + #[inline(always)] + fn abs_sub(&self, other: &f64) -> f64 { abs_sub(*self, *other) } + /// /// # Returns /// @@ -420,21 +429,27 @@ impl Trigonometric for f64 { } impl Exponential for f64 { + /// Returns the exponential of the number #[inline(always)] fn exp(&self) -> f64 { exp(*self) } + /// Returns 2 raised to the power of the number #[inline(always)] fn exp2(&self) -> f64 { exp2(*self) } + /// Returns the natural logarithm of the number #[inline(always)] - fn expm1(&self) -> f64 { expm1(*self) } + fn ln(&self) -> f64 { ln(*self) } + /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self) -> f64 { ln(*self) } + fn log(&self, base: f64) -> f64 { self.ln() / base.ln() } + /// Returns the base 2 logarithm of the number #[inline(always)] fn log2(&self) -> f64 { log2(*self) } + /// Returns the base 10 logarithm of the number #[inline(always)] fn log10(&self) -> f64 { log10(*self) } } @@ -511,13 +526,13 @@ impl Real for f64 { #[inline(always)] fn log10_e() -> f64 { 0.434294481903251827651128918916605082 } - /// log(2.0) + /// ln(2.0) #[inline(always)] - fn log_2() -> f64 { 0.693147180559945309417232121458176568 } + fn ln_2() -> f64 { 0.693147180559945309417232121458176568 } - /// log(10.0) + /// ln(10.0) #[inline(always)] - fn log_10() -> f64 { 2.30258509299404568401799145468436421 } + fn ln_10() -> f64 { 2.30258509299404568401799145468436421 } /// Converts to degrees, assuming the number is in radians #[inline(always)] @@ -587,6 +602,7 @@ impl Float for f64 { #[inline(always)] fn neg_zero() -> f64 { -0.0 } + /// Returns `true` if the number is NaN #[inline(always)] fn is_NaN(&self) -> bool { *self != *self } @@ -596,12 +612,36 @@ impl Float for f64 { *self == Float::infinity() || *self == Float::neg_infinity() } - /// Returns `true` if the number is finite + /// Returns `true` if the number is neither infinite or NaN #[inline(always)] fn is_finite(&self) -> bool { !(self.is_NaN() || self.is_infinite()) } + /// Returns `true` if the number is neither zero, infinite, subnormal or NaN + #[inline(always)] + fn is_normal(&self) -> bool { + self.classify() == FPNormal + } + + /// Returns the floating point category of the number. If only one property is going to + /// be tested, it is generally faster to use the specific predicate instead. + fn classify(&self) -> FPCategory { + static EXP_MASK: u64 = 0x7ff0000000000000; + static MAN_MASK: u64 = 0x000fffffffffffff; + + match ( + unsafe { ::cast::transmute::(*self) } & MAN_MASK, + unsafe { ::cast::transmute::(*self) } & EXP_MASK, + ) { + (0, 0) => FPZero, + (_, 0) => FPSubnormal, + (0, EXP_MASK) => FPInfinite, + (_, EXP_MASK) => FPNaN, + _ => FPNormal, + } + } + #[inline(always)] fn mantissa_digits() -> uint { 53 } @@ -623,6 +663,20 @@ impl Float for f64 { #[inline(always)] fn max_10_exp() -> int { 308 } + /// + /// Returns the exponential of the number, minus `1`, in a way that is accurate + /// even if the number is close to zero + /// + #[inline(always)] + fn exp_m1(&self) -> f64 { exp_m1(*self) } + + /// + /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately + /// than if the operations were performed separately + /// + #[inline(always)] + fn ln_1p(&self) -> f64 { ln_1p(*self) } + /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This /// produces a more accurate result with better performance than a separate multiplication @@ -845,7 +899,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for f64 { +impl FromStr for f64 { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } @@ -860,19 +914,10 @@ impl num::FromStrRadix for f64 { #[cfg(test)] mod tests { use f64::*; + use num::*; use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. \ - Found: %? and expected %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f64, 2f64); @@ -906,95 +951,95 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.3f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.5f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.7f64.floor(), 1.0f64); - assert_fuzzy_eq!(0.0f64.floor(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).floor(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).floor(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).floor(), -2.0f64); - assert_fuzzy_eq!((-1.5f64).floor(), -2.0f64); - assert_fuzzy_eq!((-1.7f64).floor(), -2.0f64); + assert_approx_eq!(1.0f64.floor(), 1.0f64); + assert_approx_eq!(1.3f64.floor(), 1.0f64); + assert_approx_eq!(1.5f64.floor(), 1.0f64); + assert_approx_eq!(1.7f64.floor(), 1.0f64); + assert_approx_eq!(0.0f64.floor(), 0.0f64); + assert_approx_eq!((-0.0f64).floor(), -0.0f64); + assert_approx_eq!((-1.0f64).floor(), -1.0f64); + assert_approx_eq!((-1.3f64).floor(), -2.0f64); + assert_approx_eq!((-1.5f64).floor(), -2.0f64); + assert_approx_eq!((-1.7f64).floor(), -2.0f64); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f64.ceil(), 1.0f64); - assert_fuzzy_eq!(1.3f64.ceil(), 2.0f64); - assert_fuzzy_eq!(1.5f64.ceil(), 2.0f64); - assert_fuzzy_eq!(1.7f64.ceil(), 2.0f64); - assert_fuzzy_eq!(0.0f64.ceil(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).ceil(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.7f64).ceil(), -1.0f64); + assert_approx_eq!(1.0f64.ceil(), 1.0f64); + assert_approx_eq!(1.3f64.ceil(), 2.0f64); + assert_approx_eq!(1.5f64.ceil(), 2.0f64); + assert_approx_eq!(1.7f64.ceil(), 2.0f64); + assert_approx_eq!(0.0f64.ceil(), 0.0f64); + assert_approx_eq!((-0.0f64).ceil(), -0.0f64); + assert_approx_eq!((-1.0f64).ceil(), -1.0f64); + assert_approx_eq!((-1.3f64).ceil(), -1.0f64); + assert_approx_eq!((-1.5f64).ceil(), -1.0f64); + assert_approx_eq!((-1.7f64).ceil(), -1.0f64); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f64.round(), 1.0f64); - assert_fuzzy_eq!(1.3f64.round(), 1.0f64); - assert_fuzzy_eq!(1.5f64.round(), 2.0f64); - assert_fuzzy_eq!(1.7f64.round(), 2.0f64); - assert_fuzzy_eq!(0.0f64.round(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).round(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).round(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).round(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).round(), -2.0f64); - assert_fuzzy_eq!((-1.7f64).round(), -2.0f64); + assert_approx_eq!(1.0f64.round(), 1.0f64); + assert_approx_eq!(1.3f64.round(), 1.0f64); + assert_approx_eq!(1.5f64.round(), 2.0f64); + assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(0.0f64.round(), 0.0f64); + assert_approx_eq!((-0.0f64).round(), -0.0f64); + assert_approx_eq!((-1.0f64).round(), -1.0f64); + assert_approx_eq!((-1.3f64).round(), -1.0f64); + assert_approx_eq!((-1.5f64).round(), -2.0f64); + assert_approx_eq!((-1.7f64).round(), -2.0f64); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.3f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.5f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.7f64.trunc(), 1.0f64); - assert_fuzzy_eq!(0.0f64.trunc(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).trunc(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.7f64).trunc(), -1.0f64); + assert_approx_eq!(1.0f64.trunc(), 1.0f64); + assert_approx_eq!(1.3f64.trunc(), 1.0f64); + assert_approx_eq!(1.5f64.trunc(), 1.0f64); + assert_approx_eq!(1.7f64.trunc(), 1.0f64); + assert_approx_eq!(0.0f64.trunc(), 0.0f64); + assert_approx_eq!((-0.0f64).trunc(), -0.0f64); + assert_approx_eq!((-1.0f64).trunc(), -1.0f64); + assert_approx_eq!((-1.3f64).trunc(), -1.0f64); + assert_approx_eq!((-1.5f64).trunc(), -1.0f64); + assert_approx_eq!((-1.7f64).trunc(), -1.0f64); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f64.fract(), 0.0f64); - assert_fuzzy_eq!(1.3f64.fract(), 0.3f64); - assert_fuzzy_eq!(1.5f64.fract(), 0.5f64); - assert_fuzzy_eq!(1.7f64.fract(), 0.7f64); - assert_fuzzy_eq!(0.0f64.fract(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).fract(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).fract(), -0.0f64); - assert_fuzzy_eq!((-1.3f64).fract(), -0.3f64); - assert_fuzzy_eq!((-1.5f64).fract(), -0.5f64); - assert_fuzzy_eq!((-1.7f64).fract(), -0.7f64); + assert_approx_eq!(1.0f64.fract(), 0.0f64); + assert_approx_eq!(1.3f64.fract(), 0.3f64); + assert_approx_eq!(1.5f64.fract(), 0.5f64); + assert_approx_eq!(1.7f64.fract(), 0.7f64); + assert_approx_eq!(0.0f64.fract(), 0.0f64); + assert_approx_eq!((-0.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.3f64).fract(), -0.3f64); + assert_approx_eq!((-1.5f64).fract(), -0.5f64); + assert_approx_eq!((-1.7f64).fract(), -0.7f64); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2.0 * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f64.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f64.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f64.log()); + assert_approx_eq!(Real::two_pi::(), 2.0 * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); + assert_approx_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f64.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::ln_2::(), 2f64.ln()); + assert_approx_eq!(Real::ln_10::(), 10f64.ln()); } #[test] - pub fn test_signed() { + pub fn test_abs() { assert_eq!(infinity.abs(), infinity); assert_eq!(1f64.abs(), 1f64); assert_eq!(0f64.abs(), 0f64); @@ -1003,7 +1048,24 @@ mod tests { assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f64/neg_infinity).abs(), 0f64); assert!(NaN.abs().is_NaN()); + } + + #[test] + fn test_abs_sub() { + assert_eq!((-1f64).abs_sub(&1f64), 0f64); + assert_eq!(1f64.abs_sub(&1f64), 0f64); + assert_eq!(1f64.abs_sub(&0f64), 1f64); + assert_eq!(1f64.abs_sub(&-1f64), 2f64); + assert_eq!(neg_infinity.abs_sub(&0f64), 0f64); + assert_eq!(infinity.abs_sub(&1f64), infinity); + assert_eq!(0f64.abs_sub(&neg_infinity), infinity); + assert_eq!(0f64.abs_sub(&infinity), 0f64); + assert!(NaN.abs_sub(&-1f64).is_NaN()); + assert!(1f64.abs_sub(&NaN).is_NaN()); + } + #[test] + fn test_signum() { assert_eq!(infinity.signum(), 1f64); assert_eq!(1f64.signum(), 1f64); assert_eq!(0f64.signum(), 1f64); @@ -1012,7 +1074,10 @@ mod tests { assert_eq!(neg_infinity.signum(), -1f64); assert_eq!((1f64/neg_infinity).signum(), -1f64); assert!(NaN.signum().is_NaN()); + } + #[test] + fn test_is_positive() { assert!(infinity.is_positive()); assert!(1f64.is_positive()); assert!(0f64.is_positive()); @@ -1021,7 +1086,10 @@ mod tests { assert!(!neg_infinity.is_positive()); assert!(!(1f64/neg_infinity).is_positive()); assert!(!NaN.is_positive()); + } + #[test] + fn test_is_negative() { assert!(!infinity.is_negative()); assert!(!1f64.is_negative()); assert!(!0f64.is_negative()); @@ -1032,19 +1100,41 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f64.approx_eq(&1f64)); + assert!(0.9999999f64.approx_eq(&1f64)); + assert!(1.000001f64.approx_eq_eps(&1f64, &1.0e-5)); + assert!(1.0000001f64.approx_eq_eps(&1f64, &1.0e-6)); + assert!(!1.0000001f64.approx_eq_eps(&1f64, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); assert_eq!(Primitive::bytes::(), sys::size_of::()); } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// + #[test] + fn test_is_normal() { + assert!(!Float::NaN::().is_normal()); + assert!(!Float::infinity::().is_normal()); + assert!(!Float::neg_infinity::().is_normal()); + assert!(!Zero::zero::().is_normal()); + assert!(!Float::neg_zero::().is_normal()); + assert!(1f64.is_normal()); + assert!(1e-307f64.is_normal()); + assert!(!1e-308f64.is_normal()); + } + + #[test] + fn test_classify() { + assert_eq!(Float::NaN::().classify(), FPNaN); + assert_eq!(Float::infinity::().classify(), FPInfinite); + assert_eq!(Float::neg_infinity::().classify(), FPInfinite); + assert_eq!(Zero::zero::().classify(), FPZero); + assert_eq!(Float::neg_zero::().classify(), FPZero); + assert_eq!(1e-307f64.classify(), FPNormal); + assert_eq!(1e-308f64.classify(), FPSubnormal); + } +} diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 3aa8848cdbed2..e6a2ed7ea9759 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -20,17 +20,16 @@ // PORT this must match in width according to architecture -use from_str; use libc::c_int; use num::{Zero, One, strconv}; +use num::FPCategory; use prelude::*; -pub use f64::{add, sub, mul, quot, rem, lt, le, eq, ne, ge, gt}; -pub use f64::logarithm; +pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor}; -pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub}; +pub use f64::{erf, erfc, exp, exp_m1, exp2, abs_sub}; pub use f64::{mul_add, fmax, fmin, next_after, frexp, hypot, ldexp}; -pub use f64::{lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix}; +pub use f64::{lgamma, ln, log_radix, ln_1p, log10, log2, ilog_radix}; pub use f64::{modf, pow, powi, round, sinh, tanh, tgamma, trunc}; pub use f64::{j0, j1, jn, y0, y1, yn}; @@ -289,7 +288,7 @@ pub fn from_str_radix(num: &str, radix: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for float { +impl FromStr for float { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } @@ -364,7 +363,7 @@ pub fn tan(x: float) -> float { impl Num for float {} -#[cfg(notest)] +#[cfg(not(test))] impl Eq for float { #[inline(always)] fn eq(&self, other: &float) -> bool { (*self) == (*other) } @@ -372,7 +371,23 @@ impl Eq for float { fn ne(&self, other: &float) -> bool { (*self) != (*other) } } -#[cfg(notest)] +#[cfg(not(test))] +impl ApproxEq for float { + #[inline(always)] + fn approx_epsilon() -> float { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &float) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &float, approx_epsilon: &float) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + +#[cfg(not(test))] impl Ord for float { #[inline(always)] fn lt(&self, other: &float) -> bool { (*self) < (*other) } @@ -518,31 +533,37 @@ impl Trigonometric for float { } impl Exponential for float { + /// Returns the exponential of the number #[inline(always)] fn exp(&self) -> float { (*self as f64).exp() as float } + /// Returns 2 raised to the power of the number #[inline(always)] fn exp2(&self) -> float { (*self as f64).exp2() as float } + /// Returns the natural logarithm of the number #[inline(always)] - fn expm1(&self) -> float { - (*self as f64).expm1() as float + fn ln(&self) -> float { + (*self as f64).ln() as float } + /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self) -> float { - (*self as f64).log() as float + fn log(&self, base: float) -> float { + (*self as f64).log(base as f64) as float } + /// Returns the base 2 logarithm of the number #[inline(always)] fn log2(&self) -> float { (*self as f64).log2() as float } + /// Returns the base 10 logarithm of the number #[inline(always)] fn log10(&self) -> float { (*self as f64).log10() as float @@ -627,13 +648,13 @@ impl Real for float { #[inline(always)] fn log10_e() -> float { 0.434294481903251827651128918916605082 } - /// log(2.0) + /// ln(2.0) #[inline(always)] - fn log_2() -> float { 0.693147180559945309417232121458176568 } + fn ln_2() -> float { 0.693147180559945309417232121458176568 } - /// log(10.0) + /// ln(10.0) #[inline(always)] - fn log_10() -> float { 2.30258509299404568401799145468436421 } + fn ln_10() -> float { 2.30258509299404568401799145468436421 } /// Converts to degrees, assuming the number is in radians #[inline(always)] @@ -674,45 +695,36 @@ impl RealExt for float { fn yn(&self, n: int) -> float { yn(n as c_int, *self as f64) as float } } -#[cfg(notest)] +#[cfg(not(test))] impl Add for float { #[inline(always)] fn add(&self, other: &float) -> float { *self + *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Sub for float { #[inline(always)] fn sub(&self, other: &float) -> float { *self - *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Mul for float { #[inline(always)] fn mul(&self, other: &float) -> float { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(not(test))] impl Div for float { #[inline(always)] fn div(&self, other: &float) -> float { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for float { - #[inline(always)] - fn quot(&self, other: &float) -> float { *self / *other } -} -#[cfg(stage0,notest)] -impl Modulo for float { - #[inline(always)] - fn modulo(&self, other: &float) -> float { *self % *other } -} -#[cfg(not(stage0),notest)] + +#[cfg(not(test))] impl Rem for float { #[inline(always)] fn rem(&self, other: &float) -> float { *self % *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Neg for float { #[inline(always)] fn neg(&self) -> float { -*self } @@ -723,6 +735,15 @@ impl Signed for float { #[inline(always)] fn abs(&self) -> float { abs(*self) } + /// + /// The positive difference of two numbers. Returns `0.0` if the number is less than or + /// equal to `other`, otherwise the difference between`self` and `other` is returned. + /// + #[inline(always)] + fn abs_sub(&self, other: &float) -> float { + (*self as f64).abs_sub(&(*other as f64)) as float + } + /// /// # Returns /// @@ -762,19 +783,37 @@ impl Primitive for float { impl Float for float { #[inline(always)] - fn NaN() -> float { 0.0 / 0.0 } + fn NaN() -> float { Float::NaN::() as float } + + #[inline(always)] + fn infinity() -> float { Float::infinity::() as float } + + #[inline(always)] + fn neg_infinity() -> float { Float::neg_infinity::() as float } + + #[inline(always)] + fn neg_zero() -> float { Float::neg_zero::() as float } + + /// Returns `true` if the number is NaN + #[inline(always)] + fn is_NaN(&self) -> bool { (*self as f64).is_NaN() } + /// Returns `true` if the number is infinite #[inline(always)] - fn infinity() -> float { 1.0 / 0.0 } + fn is_infinite(&self) -> bool { (*self as f64).is_infinite() } + /// Returns `true` if the number is neither infinite or NaN #[inline(always)] - fn neg_infinity() -> float { -1.0 / 0.0 } + fn is_finite(&self) -> bool { (*self as f64).is_finite() } + /// Returns `true` if the number is neither zero, infinite, subnormal or NaN #[inline(always)] - fn neg_zero() -> float { -0.0 } + fn is_normal(&self) -> bool { (*self as f64).is_normal() } + /// Returns the floating point category of the number. If only one property is going to + /// be tested, it is generally faster to use the specific predicate instead. #[inline(always)] - fn is_NaN(&self) -> bool { *self != *self } + fn classify(&self) -> FPCategory { (*self as f64).classify() } #[inline(always)] fn mantissa_digits() -> uint { Float::mantissa_digits::() } @@ -797,17 +836,21 @@ impl Float for float { #[inline(always)] fn max_10_exp() -> int { Float::max_10_exp::() } - /// Returns `true` if the number is infinite + /// + /// Returns the exponential of the number, minus `1`, in a way that is accurate + /// even if the number is close to zero + /// #[inline(always)] - fn is_infinite(&self) -> bool { - *self == Float::infinity() || *self == Float::neg_infinity() + fn exp_m1(&self) -> float { + (*self as f64).exp_m1() as float } - /// Returns `true` if the number is finite + /// + /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately + /// than if the operations were performed separately + /// #[inline(always)] - fn is_finite(&self) -> bool { - !(self.is_NaN() || self.is_infinite()) - } + fn ln_1p(&self) -> float { (*self as f64).ln_1p() as float } /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This @@ -828,18 +871,10 @@ impl Float for float { #[cfg(test)] mod tests { + use num::*; use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f, 2f); @@ -869,95 +904,95 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f.floor(), 1.0f); - assert_fuzzy_eq!(1.3f.floor(), 1.0f); - assert_fuzzy_eq!(1.5f.floor(), 1.0f); - assert_fuzzy_eq!(1.7f.floor(), 1.0f); - assert_fuzzy_eq!(0.0f.floor(), 0.0f); - assert_fuzzy_eq!((-0.0f).floor(), -0.0f); - assert_fuzzy_eq!((-1.0f).floor(), -1.0f); - assert_fuzzy_eq!((-1.3f).floor(), -2.0f); - assert_fuzzy_eq!((-1.5f).floor(), -2.0f); - assert_fuzzy_eq!((-1.7f).floor(), -2.0f); + assert_approx_eq!(1.0f.floor(), 1.0f); + assert_approx_eq!(1.3f.floor(), 1.0f); + assert_approx_eq!(1.5f.floor(), 1.0f); + assert_approx_eq!(1.7f.floor(), 1.0f); + assert_approx_eq!(0.0f.floor(), 0.0f); + assert_approx_eq!((-0.0f).floor(), -0.0f); + assert_approx_eq!((-1.0f).floor(), -1.0f); + assert_approx_eq!((-1.3f).floor(), -2.0f); + assert_approx_eq!((-1.5f).floor(), -2.0f); + assert_approx_eq!((-1.7f).floor(), -2.0f); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f.ceil(), 1.0f); - assert_fuzzy_eq!(1.3f.ceil(), 2.0f); - assert_fuzzy_eq!(1.5f.ceil(), 2.0f); - assert_fuzzy_eq!(1.7f.ceil(), 2.0f); - assert_fuzzy_eq!(0.0f.ceil(), 0.0f); - assert_fuzzy_eq!((-0.0f).ceil(), -0.0f); - assert_fuzzy_eq!((-1.0f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.3f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.5f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.7f).ceil(), -1.0f); + assert_approx_eq!(1.0f.ceil(), 1.0f); + assert_approx_eq!(1.3f.ceil(), 2.0f); + assert_approx_eq!(1.5f.ceil(), 2.0f); + assert_approx_eq!(1.7f.ceil(), 2.0f); + assert_approx_eq!(0.0f.ceil(), 0.0f); + assert_approx_eq!((-0.0f).ceil(), -0.0f); + assert_approx_eq!((-1.0f).ceil(), -1.0f); + assert_approx_eq!((-1.3f).ceil(), -1.0f); + assert_approx_eq!((-1.5f).ceil(), -1.0f); + assert_approx_eq!((-1.7f).ceil(), -1.0f); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f.round(), 1.0f); - assert_fuzzy_eq!(1.3f.round(), 1.0f); - assert_fuzzy_eq!(1.5f.round(), 2.0f); - assert_fuzzy_eq!(1.7f.round(), 2.0f); - assert_fuzzy_eq!(0.0f.round(), 0.0f); - assert_fuzzy_eq!((-0.0f).round(), -0.0f); - assert_fuzzy_eq!((-1.0f).round(), -1.0f); - assert_fuzzy_eq!((-1.3f).round(), -1.0f); - assert_fuzzy_eq!((-1.5f).round(), -2.0f); - assert_fuzzy_eq!((-1.7f).round(), -2.0f); + assert_approx_eq!(1.0f.round(), 1.0f); + assert_approx_eq!(1.3f.round(), 1.0f); + assert_approx_eq!(1.5f.round(), 2.0f); + assert_approx_eq!(1.7f.round(), 2.0f); + assert_approx_eq!(0.0f.round(), 0.0f); + assert_approx_eq!((-0.0f).round(), -0.0f); + assert_approx_eq!((-1.0f).round(), -1.0f); + assert_approx_eq!((-1.3f).round(), -1.0f); + assert_approx_eq!((-1.5f).round(), -2.0f); + assert_approx_eq!((-1.7f).round(), -2.0f); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f.trunc(), 1.0f); - assert_fuzzy_eq!(1.3f.trunc(), 1.0f); - assert_fuzzy_eq!(1.5f.trunc(), 1.0f); - assert_fuzzy_eq!(1.7f.trunc(), 1.0f); - assert_fuzzy_eq!(0.0f.trunc(), 0.0f); - assert_fuzzy_eq!((-0.0f).trunc(), -0.0f); - assert_fuzzy_eq!((-1.0f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.3f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.5f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.7f).trunc(), -1.0f); + assert_approx_eq!(1.0f.trunc(), 1.0f); + assert_approx_eq!(1.3f.trunc(), 1.0f); + assert_approx_eq!(1.5f.trunc(), 1.0f); + assert_approx_eq!(1.7f.trunc(), 1.0f); + assert_approx_eq!(0.0f.trunc(), 0.0f); + assert_approx_eq!((-0.0f).trunc(), -0.0f); + assert_approx_eq!((-1.0f).trunc(), -1.0f); + assert_approx_eq!((-1.3f).trunc(), -1.0f); + assert_approx_eq!((-1.5f).trunc(), -1.0f); + assert_approx_eq!((-1.7f).trunc(), -1.0f); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f.fract(), 0.0f); - assert_fuzzy_eq!(1.3f.fract(), 0.3f); - assert_fuzzy_eq!(1.5f.fract(), 0.5f); - assert_fuzzy_eq!(1.7f.fract(), 0.7f); - assert_fuzzy_eq!(0.0f.fract(), 0.0f); - assert_fuzzy_eq!((-0.0f).fract(), -0.0f); - assert_fuzzy_eq!((-1.0f).fract(), -0.0f); - assert_fuzzy_eq!((-1.3f).fract(), -0.3f); - assert_fuzzy_eq!((-1.5f).fract(), -0.5f); - assert_fuzzy_eq!((-1.7f).fract(), -0.7f); + assert_approx_eq!(1.0f.fract(), 0.0f); + assert_approx_eq!(1.3f.fract(), 0.3f); + assert_approx_eq!(1.5f.fract(), 0.5f); + assert_approx_eq!(1.7f.fract(), 0.7f); + assert_approx_eq!(0.0f.fract(), 0.0f); + assert_approx_eq!((-0.0f).fract(), -0.0f); + assert_approx_eq!((-1.0f).fract(), -0.0f); + assert_approx_eq!((-1.3f).fract(), -0.3f); + assert_approx_eq!((-1.5f).fract(), -0.5f); + assert_approx_eq!((-1.7f).fract(), -0.7f); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2f * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f.log()); + assert_approx_eq!(Real::two_pi::(), 2f * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); + assert_approx_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::ln_2::(), 2f.ln()); + assert_approx_eq!(Real::ln_10::(), 10f.ln()); } #[test] - fn test_signed() { + fn test_abs() { assert_eq!(infinity.abs(), infinity); assert_eq!(1f.abs(), 1f); assert_eq!(0f.abs(), 0f); @@ -966,7 +1001,24 @@ mod tests { assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f/neg_infinity).abs(), 0f); assert!(NaN.abs().is_NaN()); + } + + #[test] + fn test_abs_sub() { + assert_eq!((-1f).abs_sub(&1f), 0f); + assert_eq!(1f.abs_sub(&1f), 0f); + assert_eq!(1f.abs_sub(&0f), 1f); + assert_eq!(1f.abs_sub(&-1f), 2f); + assert_eq!(neg_infinity.abs_sub(&0f), 0f); + assert_eq!(infinity.abs_sub(&1f), infinity); + assert_eq!(0f.abs_sub(&neg_infinity), infinity); + assert_eq!(0f.abs_sub(&infinity), 0f); + assert!(NaN.abs_sub(&-1f).is_NaN()); + assert!(1f.abs_sub(&NaN).is_NaN()); + } + #[test] + fn test_signum() { assert_eq!(infinity.signum(), 1f); assert_eq!(1f.signum(), 1f); assert_eq!(0f.signum(), 1f); @@ -975,7 +1027,10 @@ mod tests { assert_eq!(neg_infinity.signum(), -1f); assert_eq!((1f/neg_infinity).signum(), -1f); assert!(NaN.signum().is_NaN()); + } + #[test] + fn test_is_positive() { assert!(infinity.is_positive()); assert!(1f.is_positive()); assert!(0f.is_positive()); @@ -984,7 +1039,10 @@ mod tests { assert!(!neg_infinity.is_positive()); assert!(!(1f/neg_infinity).is_positive()); assert!(!NaN.is_positive()); + } + #[test] + fn test_is_negative() { assert!(!infinity.is_negative()); assert!(!1f.is_negative()); assert!(!0f.is_negative()); @@ -995,12 +1053,45 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f.approx_eq(&1f)); + assert!(0.9999999f.approx_eq(&1f)); + assert!(1.000001f.approx_eq_eps(&1f, &1.0e-5)); + assert!(1.0000001f.approx_eq_eps(&1f, &1.0e-6)); + assert!(!1.0000001f.approx_eq_eps(&1f, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); assert_eq!(Primitive::bytes::(), sys::size_of::()); } + #[test] + fn test_is_normal() { + assert!(!Float::NaN::().is_normal()); + assert!(!Float::infinity::().is_normal()); + assert!(!Float::neg_infinity::().is_normal()); + assert!(!Zero::zero::().is_normal()); + assert!(!Float::neg_zero::().is_normal()); + assert!(1f.is_normal()); + assert!(1e-307f.is_normal()); + assert!(!1e-308f.is_normal()); + } + + #[test] + fn test_classify() { + assert_eq!(Float::NaN::().classify(), FPNaN); + assert_eq!(Float::infinity::().classify(), FPInfinite); + assert_eq!(Float::neg_infinity::().classify(), FPInfinite); + assert_eq!(Zero::zero::().classify(), FPZero); + assert_eq!(Float::neg_zero::().classify(), FPZero); + assert_eq!(1f.classify(), FPNormal); + assert_eq!(1e-307f.classify(), FPNormal); + assert_eq!(1e-308f.classify(), FPSubnormal); + } + #[test] pub fn test_to_str_exact_do_decimal() { let s = to_str_exact(5.0, 4u); @@ -1143,13 +1234,3 @@ mod tests { assert_eq!(to_str_digits(-infinity, 10u), ~"-inf"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index ec38a32c039d6..f2bba6a463904 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -10,7 +10,6 @@ use T = self::inst::T; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; @@ -30,7 +29,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } /// /// Returns the remainder of y / x. @@ -87,38 +86,63 @@ pub fn gt(x: T, y: T) -> bool { x > y } /// #[inline(always)] /// Iterate over the range [`start`,`start`+`step`..`stop`) -pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) { +pub fn _range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) -> bool { let mut i = start; if step == 0 { fail!(~"range_step called with step == 0"); } else if step > 0 { // ascending while i < stop { - if !it(i) { break } + if !it(i) { return false; } // avoiding overflow. break if i + step > max_value - if i > max_value - step { break; } + if i > max_value - step { return true; } i += step; } } else { // descending while i > stop { - if !it(i) { break } + if !it(i) { return false; } // avoiding underflow. break if i + step < min_value - if i < min_value - step { break; } + if i < min_value - step { return true; } i += step; } } + return true; +} + +#[cfg(stage0)] +pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) { + _range_step(start, stop, step, it); +} +#[cfg(not(stage0))] +pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) -> bool { + _range_step(start, stop, step, it) } #[inline(always)] +#[cfg(stage0)] /// Iterate over the range [`lo`..`hi`) pub fn range(lo: T, hi: T, it: &fn(T) -> bool) { range_step(lo, hi, 1 as T, it); } #[inline(always)] +#[cfg(not(stage0))] +/// Iterate over the range [`lo`..`hi`) +pub fn range(lo: T, hi: T, it: &fn(T) -> bool) -> bool { + range_step(lo, hi, 1 as T, it) +} + +#[inline(always)] +#[cfg(stage0)] /// Iterate over the range [`hi`..`lo`) pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) { range_step(hi, lo, -1 as T, it); } +#[inline(always)] +#[cfg(not(stage0))] +/// Iterate over the range [`hi`..`lo`) +pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) -> bool { + range_step(hi, lo, -1 as T, it) +} /// Computes the bitwise complement #[inline(always)] @@ -132,7 +156,7 @@ pub fn abs(i: T) -> T { i.abs() } impl Num for T {} -#[cfg(notest)] +#[cfg(not(test))] impl Ord for T { #[inline(always)] fn lt(&self, other: &T) -> bool { return (*self) < (*other); } @@ -144,7 +168,7 @@ impl Ord for T { fn gt(&self, other: &T) -> bool { return (*self) > (*other); } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for T { #[inline(always)] fn eq(&self, other: &T) -> bool { return (*self) == (*other); } @@ -183,34 +207,29 @@ impl One for T { fn one() -> T { 1 } } -#[cfg(notest)] +#[cfg(not(test))] impl Add for T { #[inline(always)] fn add(&self, other: &T) -> T { *self + *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Sub for T { #[inline(always)] fn sub(&self, other: &T) -> T { *self - *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(not(test))] impl Div for T { - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} -#[cfg(not(stage0),notest)] -impl Quot for T { /// - /// Returns the integer quotient, truncated towards 0. As this behaviour reflects - /// the underlying machine implementation it is more efficient than `Natural::div`. + /// Integer division, truncated towards 0. As this behaviour reflects the underlying + /// machine implementation it is more efficient than `Integer::div_floor`. /// /// # Examples /// @@ -227,15 +246,10 @@ impl Quot for T { /// ~~~ /// #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } + fn div(&self, other: &T) -> T { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(not(test))] impl Rem for T { /// /// Returns the integer remainder after division, satisfying: @@ -262,7 +276,7 @@ impl Rem for T { fn rem(&self, other: &T) -> T { *self % *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Neg for T { #[inline(always)] fn neg(&self) -> T { -*self } @@ -275,6 +289,15 @@ impl Signed for T { if self.is_negative() { -*self } else { *self } } + /// + /// The positive difference of two numbers. Returns `0` if the number is less than or + /// equal to `other`, otherwise the difference between`self` and `other` is returned. + /// + #[inline(always)] + fn abs_sub(&self, other: &T) -> T { + if *self <= *other { 0 } else { *self - *other } + } + /// /// # Returns /// @@ -307,25 +330,25 @@ impl Integer for T { /// # Examples /// /// ~~~ - /// assert!(( 8).div( 3) == 2); - /// assert!(( 8).div(-3) == -3); - /// assert!((-8).div( 3) == -3); - /// assert!((-8).div(-3) == 2); - /// - /// assert!(( 1).div( 2) == 0); - /// assert!(( 1).div(-2) == -1); - /// assert!((-1).div( 2) == -1); - /// assert!((-1).div(-2) == 0); + /// assert!(( 8).div_floor( 3) == 2); + /// assert!(( 8).div_floor(-3) == -3); + /// assert!((-8).div_floor( 3) == -3); + /// assert!((-8).div_floor(-3) == 2); + /// + /// assert!(( 1).div_floor( 2) == 0); + /// assert!(( 1).div_floor(-2) == -1); + /// assert!((-1).div_floor( 2) == -1); + /// assert!((-1).div_floor(-2) == 0); /// ~~~ /// #[inline(always)] - fn div(&self, other: &T) -> T { + fn div_floor(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => q - 1, - (q, _) => q, + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => d - 1, + (d, _) => d, } } @@ -333,25 +356,25 @@ impl Integer for T { /// Integer modulo, satisfying: /// /// ~~~ - /// assert!(n.div(d) * d + n.modulo(d) == n) + /// assert!(n.div_floor(d) * d + n.mod_floor(d) == n) /// ~~~ /// /// # Examples /// /// ~~~ - /// assert!(( 8).modulo( 3) == 2); - /// assert!(( 8).modulo(-3) == -1); - /// assert!((-8).modulo( 3) == 1); - /// assert!((-8).modulo(-3) == -2); - /// - /// assert!(( 1).modulo( 2) == 1); - /// assert!(( 1).modulo(-2) == -1); - /// assert!((-1).modulo( 2) == 1); - /// assert!((-1).modulo(-2) == -1); + /// assert!(( 8).mod_floor( 3) == 2); + /// assert!(( 8).mod_floor(-3) == -1); + /// assert!((-8).mod_floor( 3) == 1); + /// assert!((-8).mod_floor(-3) == -2); + /// + /// assert!(( 1).mod_floor( 2) == 1); + /// assert!(( 1).mod_floor(-2) == -1); + /// assert!((-1).mod_floor( 2) == 1); + /// assert!((-1).mod_floor(-2) == -1); /// ~~~ /// #[inline(always)] - fn modulo(&self, other: &T) -> T { + fn mod_floor(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) match *self % *other { @@ -361,21 +384,21 @@ impl Integer for T { } } - /// Calculates `div` and `modulo` simultaneously + /// Calculates `div_floor` and `mod_floor` simultaneously #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { + fn div_mod_floor(&self, other: &T) -> (T,T) { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (q - 1, r + *other), - (q, r) => (q, r), + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => (d - 1, r + *other), + (d, r) => (d, r), } } - /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_rem(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } @@ -419,37 +442,37 @@ impl Integer for T { impl Bitwise for T {} -#[cfg(notest)] +#[cfg(not(test))] impl BitOr for T { #[inline(always)] fn bitor(&self, other: &T) -> T { *self | *other } } -#[cfg(notest)] +#[cfg(not(test))] impl BitAnd for T { #[inline(always)] fn bitand(&self, other: &T) -> T { *self & *other } } -#[cfg(notest)] +#[cfg(not(test))] impl BitXor for T { #[inline(always)] fn bitxor(&self, other: &T) -> T { *self ^ *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Shl for T { #[inline(always)] fn shl(&self, other: &T) -> T { *self << *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Shr for T { #[inline(always)] fn shr(&self, other: &T) -> T { *self >> *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Not for T { #[inline(always)] fn not(&self) -> T { !*self } @@ -565,21 +588,38 @@ mod tests { } #[test] - pub fn test_signed() { + pub fn test_abs() { assert_eq!((1 as T).abs(), 1 as T); assert_eq!((0 as T).abs(), 0 as T); assert_eq!((-1 as T).abs(), 1 as T); + } + #[test] + fn test_abs_sub() { + assert_eq!((-1 as T).abs_sub(&(1 as T)), 0 as T); + assert_eq!((1 as T).abs_sub(&(1 as T)), 0 as T); + assert_eq!((1 as T).abs_sub(&(0 as T)), 1 as T); + assert_eq!((1 as T).abs_sub(&(-1 as T)), 2 as T); + } + + #[test] + fn test_signum() { assert_eq!((1 as T).signum(), 1 as T); assert_eq!((0 as T).signum(), 0 as T); assert_eq!((-0 as T).signum(), 0 as T); assert_eq!((-1 as T).signum(), -1 as T); + } + #[test] + fn test_is_positive() { assert!((1 as T).is_positive()); assert!(!(0 as T).is_positive()); assert!(!(-0 as T).is_positive()); assert!(!(-1 as T).is_positive()); + } + #[test] + fn test_is_negative() { assert!(!(1 as T).is_negative()); assert!(!(0 as T).is_negative()); assert!(!(-0 as T).is_negative()); @@ -599,42 +639,42 @@ mod tests { } #[test] - fn test_quot_rem() { - fn test_nd_qr(nd: (T,T), qr: (T,T)) { + fn test_div_rem() { + fn test_nd_dr(nd: (T,T), qr: (T,T)) { let (n,d) = nd; - let separate_quot_rem = (n / d, n % d); - let combined_quot_rem = n.quot_rem(&d); + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); - assert_eq!(separate_quot_rem, qr); - assert_eq!(combined_quot_rem, qr); + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); - test_division_rule(nd, separate_quot_rem); - test_division_rule(nd, combined_quot_rem); + test_division_rule(nd, separate_div_rem); + test_division_rule(nd, combined_div_rem); } - test_nd_qr(( 8, 3), ( 2, 2)); - test_nd_qr(( 8, -3), (-2, 2)); - test_nd_qr((-8, 3), (-2, -2)); - test_nd_qr((-8, -3), ( 2, -2)); + test_nd_dr(( 8, 3), ( 2, 2)); + test_nd_dr(( 8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), ( 2, -2)); - test_nd_qr(( 1, 2), ( 0, 1)); - test_nd_qr(( 1, -2), ( 0, 1)); - test_nd_qr((-1, 2), ( 0, -1)); - test_nd_qr((-1, -2), ( 0, -1)); + test_nd_dr(( 1, 2), ( 0, 1)); + test_nd_dr(( 1, -2), ( 0, 1)); + test_nd_dr((-1, 2), ( 0, -1)); + test_nd_dr((-1, -2), ( 0, -1)); } #[test] - fn test_div_mod() { + fn test_div_mod_floor() { fn test_nd_dm(nd: (T,T), dm: (T,T)) { let (n,d) = nd; - let separate_div_mod = (n.div(&d), n.modulo(&d)); - let combined_div_mod = n.div_mod(&d); + let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); + let combined_div_mod_floor = n.div_mod_floor(&d); - assert_eq!(separate_div_mod, dm); - assert_eq!(combined_div_mod, dm); + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); - test_division_rule(nd, separate_div_mod); - test_division_rule(nd, combined_div_mod); + test_division_rule(nd, separate_div_mod_floor); + test_division_rule(nd, combined_div_mod_floor); } test_nd_dm(( 8, 3), ( 2, 2)); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 3e43ebfef1222..50ba55039d408 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -9,15 +9,8 @@ // except according to those terms. //! An interface for numeric types -use cmp::{Eq, Ord}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(not(stage0))] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use cmp::{Eq, ApproxEq, Ord}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; use kinds::Copy; @@ -32,7 +25,7 @@ pub trait Num: Eq + Zero + One + Add + Sub + Mul - + Quot + + Div + Rem {} pub trait IntConvertible { @@ -62,7 +55,9 @@ pub trait One { pub trait Signed: Num + Neg { fn abs(&self) -> Self; + fn abs_sub(&self, other: &Self) -> Self; fn signum(&self) -> Self; + fn is_positive(&self) -> bool; fn is_negative(&self) -> bool; } @@ -76,12 +71,13 @@ pub fn abs>(v: T) -> T { pub trait Integer: Num + Orderable - + Quot + + Div + Rem { - fn div(&self, other: &Self) -> Self; - fn modulo(&self, other: &Self) -> Self; - fn div_mod(&self, other: &Self) -> (Self,Self); - fn quot_rem(&self, other: &Self) -> (Self,Self); + fn div_rem(&self, other: &Self) -> (Self,Self); + + fn div_floor(&self, other: &Self) -> Self; + fn mod_floor(&self, other: &Self) -> Self; + fn div_mod_floor(&self, other: &Self) -> (Self,Self); fn gcd(&self, other: &Self) -> Self; fn lcm(&self, other: &Self) -> Self; @@ -102,7 +98,7 @@ pub trait Round { pub trait Fractional: Num + Orderable + Round - + Quot { + + Div { fn recip(&self) -> Self; } @@ -127,8 +123,8 @@ pub trait Trigonometric { pub trait Exponential { fn exp(&self) -> Self; fn exp2(&self) -> Self; - fn expm1(&self) -> Self; - fn log(&self) -> Self; + fn ln(&self) -> Self; + fn log(&self, base: Self) -> Self; fn log2(&self) -> Self; fn log10(&self) -> Self; } @@ -164,8 +160,8 @@ pub trait Real: Signed fn e() -> Self; fn log2_e() -> Self; fn log10_e() -> Self; - fn log_2() -> Self; - fn log_10() -> Self; + fn ln_2() -> Self; + fn ln_10() -> Self; // Angular conversions fn to_degrees(&self) -> Self; @@ -226,7 +222,7 @@ pub trait Primitive: Num + Add + Sub + Mul - + Quot + + Div + Rem { // FIXME (#5527): These should be associated constants fn bits() -> uint; @@ -241,12 +237,30 @@ pub trait Int: Integer + Bitwise + BitCount {} +/// +/// Used for representing the classification of floating point numbers +/// +#[deriving(Eq)] +pub enum FPCategory { + /// "Not a Number", often obtained by dividing by zero + FPNaN, + /// Positive or negative infinity + FPInfinite , + /// Positive or negative zero + FPZero, + /// De-normalized floating point representation (less precise than `FPNormal`) + FPSubnormal, + /// A regular floating point number + FPNormal, +} + /// /// Primitive floating point numbers /// pub trait Float: Real + Signed - + Primitive { + + Primitive + + ApproxEq { // FIXME (#5527): These should be associated constants fn NaN() -> Self; fn infinity() -> Self; @@ -256,6 +270,8 @@ pub trait Float: Real fn is_NaN(&self) -> bool; fn is_infinite(&self) -> bool; fn is_finite(&self) -> bool; + fn is_normal(&self) -> bool; + fn classify(&self) -> FPCategory; fn mantissa_digits() -> uint; fn digits() -> uint; @@ -265,6 +281,8 @@ pub trait Float: Real fn min_10_exp() -> int; fn max_10_exp() -> int; + fn exp_m1(&self) -> Self; + fn ln_1p(&self) -> Self; fn mul_add(&self, a: Self, b: Self) -> Self; fn next_after(&self, other: Self) -> Self; } @@ -371,7 +389,7 @@ pub trait FromStrRadix { /// - If code written to use this function doesn't care about it, it's /// probably assuming that `x^0` always equals `1`. /// -pub fn pow_with_uint+Mul>( +pub fn pow_with_uint+Mul>( radix: uint, pow: uint) -> T { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -392,34 +410,18 @@ pub fn pow_with_uint+Mul>( } /// Helper function for testing numeric operations -#[cfg(stage0,test)] -pub fn test_num(ten: T, two: T) { - assert_eq!(ten.add(&two), cast(12)); - assert_eq!(ten.sub(&two), cast(8)); - assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); - assert_eq!(ten.modulo(&two), cast(0)); - - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.modulo(&two), ten % two); -} -#[cfg(stage1,test)] -#[cfg(stage2,test)] -#[cfg(stage3,test)] +#[cfg(test)] pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.quot(&two), cast(5)); + assert_eq!(ten.div(&two), cast(5)); assert_eq!(ten.rem(&two), cast(0)); assert_eq!(ten.add(&two), ten + two); assert_eq!(ten.sub(&two), ten - two); assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.quot(&two), ten / two); + assert_eq!(ten.div(&two), ten / two); assert_eq!(ten.rem(&two), ten % two); } diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 2f3cd92dac09e..5ed99a8399559 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -8,22 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use container::Container; use core::cmp::{Ord, Eq}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; use str; use kinds::Copy; use vec; +use vec::{CopyableVector, ImmutableVector}; +use vec::OwnedVector; use num::{NumCast, Zero, One, cast, pow_with_uint}; use f64; @@ -67,7 +61,7 @@ fn is_neg_inf(num: &T) -> bool { } #[inline(always)] -fn is_neg_zero>(num: &T) -> bool { +fn is_neg_zero>(num: &T) -> bool { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -180,7 +174,7 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; * - Fails if `radix` < 2 or `radix` > 36. */ pub fn to_str_bytes_common+Neg+Rem+Mul>( + Div+Neg+Rem+Mul>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { if (radix as int) < 2 { @@ -388,7 +382,7 @@ pub fn to_str_bytes_common+Neg+Rem+Mul>( + Div+Neg+Rem+Mul>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { let (bytes, special) = to_str_bytes_common(num, radix, @@ -441,7 +435,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; * - Fails if `radix` > 18 and `special == true` due to conflict * between digit and lowest first character in `inf` and `NaN`, the `'i'`. */ -pub fn from_str_bytes_common+ +pub fn from_str_bytes_common+ Mul+Sub+Neg+Add+ NumStrConv>( buf: &[u8], radix: uint, negative: bool, fractional: bool, @@ -495,11 +489,11 @@ pub fn from_str_bytes_common+ } } - let (start, accum_positive) = match buf[0] { - '-' as u8 if !negative => return None, - '-' as u8 => (1u, false), - '+' as u8 => (1u, true), - _ => (0u, true) + let (start, accum_positive) = match buf[0] as char { + '-' if !negative => return None, + '-' => (1u, false), + '+' => (1u, true), + _ => (0u, true) }; // Initialize accumulator with signed zero for floating point parsing to @@ -638,7 +632,7 @@ pub fn from_str_bytes_common+ * `from_str_bytes_common()`, for details see there. */ #[inline(always)] -pub fn from_str_common+Mul+ +pub fn from_str_common+Mul+ Sub+Neg+Add+NumStrConv>( buf: &str, radix: uint, negative: bool, fractional: bool, special: bool, exponent: ExponentFormat, empty_zero: bool, diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 3dfdd22c42dc1..1c115ee507203 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -11,7 +11,6 @@ use T = self::inst::T; use T_SIGNED = self::inst::T_SIGNED; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; @@ -31,7 +30,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } #[inline(always)] pub fn rem(x: T, y: T) -> T { x % y } @@ -52,43 +51,69 @@ pub fn gt(x: T, y: T) -> bool { x > y } /// /// Iterate over the range [`start`,`start`+`step`..`stop`) /// -pub fn range_step(start: T, - stop: T, - step: T_SIGNED, - it: &fn(T) -> bool) { +pub fn _range_step(start: T, + stop: T, + step: T_SIGNED, + it: &fn(T) -> bool) -> bool { let mut i = start; if step == 0 { fail!(~"range_step called with step == 0"); } if step >= 0 { while i < stop { - if !it(i) { break } + if !it(i) { return false; } // avoiding overflow. break if i + step > max_value - if i > max_value - (step as T) { break; } + if i > max_value - (step as T) { return true; } i += step as T; } } else { while i > stop { - if !it(i) { break } + if !it(i) { return false; } // avoiding underflow. break if i + step < min_value - if i < min_value + ((-step) as T) { break; } + if i < min_value + ((-step) as T) { return true; } i -= -step as T; } } + return true; +} + +#[cfg(stage0)] +pub fn range_step(start: T, stop: T, step: T_SIGNED, it: &fn(T) -> bool) { + _range_step(start, stop, step, it); +} +#[cfg(not(stage0))] +pub fn range_step(start: T, stop: T, step: T_SIGNED, it: &fn(T) -> bool) -> bool { + _range_step(start, stop, step, it) } #[inline(always)] +#[cfg(stage0)] /// Iterate over the range [`lo`..`hi`) pub fn range(lo: T, hi: T, it: &fn(T) -> bool) { range_step(lo, hi, 1 as T_SIGNED, it); } #[inline(always)] +#[cfg(not(stage0))] +/// Iterate over the range [`lo`..`hi`) +pub fn range(lo: T, hi: T, it: &fn(T) -> bool) -> bool { + range_step(lo, hi, 1 as T_SIGNED, it) +} + +#[inline(always)] +#[cfg(stage0)] /// Iterate over the range [`hi`..`lo`) pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) { range_step(hi, lo, -1 as T_SIGNED, it); } +#[inline(always)] +#[cfg(not(stage0))] +/// Iterate over the range [`hi`..`lo`) +pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) -> bool { + range_step(hi, lo, -1 as T_SIGNED, it) +} + /// Computes the bitwise complement #[inline(always)] pub fn compl(i: T) -> T { @@ -97,7 +122,7 @@ pub fn compl(i: T) -> T { impl Num for T {} -#[cfg(notest)] +#[cfg(not(test))] impl Ord for T { #[inline(always)] fn lt(&self, other: &T) -> bool { (*self) < (*other) } @@ -109,7 +134,7 @@ impl Ord for T { fn gt(&self, other: &T) -> bool { (*self) > (*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for T { #[inline(always)] fn eq(&self, other: &T) -> bool { return (*self) == (*other); } @@ -148,47 +173,37 @@ impl One for T { fn one() -> T { 1 } } -#[cfg(notest)] +#[cfg(not(test))] impl Add for T { #[inline(always)] fn add(&self, other: &T) -> T { *self + *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Sub for T { #[inline(always)] fn sub(&self, other: &T) -> T { *self - *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(not(test))] impl Div for T { #[inline(always)] fn div(&self, other: &T) -> T { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for T { - #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } -} -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(not(test))] impl Rem for T { #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Neg for T { #[inline(always)] fn neg(&self) -> T { -*self } @@ -197,23 +212,23 @@ impl Neg for T { impl Unsigned for T {} impl Integer for T { - /// Unsigned integer division. Returns the same result as `quot` (`/`). + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } + fn div_rem(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) + } - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + /// Unsigned integer division. Returns the same result as `div` (`/`). #[inline(always)] - fn modulo(&self, other: &T) -> T { *self / *other } + fn div_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `div` and `modulo` simultaneously + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } + fn mod_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div_floor` and `modulo_floor` simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_mod_floor(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } @@ -251,37 +266,37 @@ impl Integer for T { impl Bitwise for T {} -#[cfg(notest)] +#[cfg(not(test))] impl BitOr for T { #[inline(always)] fn bitor(&self, other: &T) -> T { *self | *other } } -#[cfg(notest)] +#[cfg(not(test))] impl BitAnd for T { #[inline(always)] fn bitand(&self, other: &T) -> T { *self & *other } } -#[cfg(notest)] +#[cfg(not(test))] impl BitXor for T { #[inline(always)] fn bitxor(&self, other: &T) -> T { *self ^ *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Shl for T { #[inline(always)] fn shl(&self, other: &T) -> T { *self << *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Shr for T { #[inline(always)] fn shr(&self, other: &T) -> T { *self >> *other } } -#[cfg(notest)] +#[cfg(not(test))] impl Not for T { #[inline(always)] fn not(&self) -> T { !*self } diff --git a/src/libcore/num/uint-template/uint.rs b/src/libcore/num/uint-template/uint.rs index de882f1ee7a1f..d8a4ec19304f3 100644 --- a/src/libcore/num/uint-template/uint.rs +++ b/src/libcore/num/uint-template/uint.rs @@ -154,6 +154,7 @@ pub mod inst { return true; } + #[cfg(stage0)] impl iter::Times for uint { #[inline(always)] /// @@ -175,6 +176,29 @@ pub mod inst { } } + #[cfg(not(stage0))] + impl iter::Times for uint { + #[inline(always)] + /// + /// A convenience form for basic iteration. Given a uint `x`, + /// `for x.times { ... }` executes the given block x times. + /// + /// Equivalent to `for uint::range(0, x) |_| { ... }`. + /// + /// Not defined on all integer types to permit unambiguous + /// use with integer literals of inferred integer-type as + /// the self-value (eg. `for 100.times { ... }`). + /// + fn times(&self, it: &fn() -> bool) -> bool { + let mut i = *self; + while i > 0 { + if !it() { return false; } + i -= 1; + } + return true; + } + } + /// Returns the smallest power of 2 greater than or equal to `n` #[inline(always)] pub fn next_power_of_two(n: uint) -> uint { diff --git a/src/libcore/old_iter.rs b/src/libcore/old_iter.rs index 98b847c75b408..13d8fd2665491 100644 --- a/src/libcore/old_iter.rs +++ b/src/libcore/old_iter.rs @@ -22,21 +22,40 @@ use vec; /// A function used to initialize the elements of a sequence pub type InitOp<'self,T> = &'self fn(uint) -> T; +#[cfg(stage0)] pub trait BaseIter { fn each(&self, blk: &fn(v: &A) -> bool); fn size_hint(&self) -> Option; } +#[cfg(not(stage0))] +pub trait BaseIter { + fn each(&self, blk: &fn(v: &A) -> bool) -> bool; + fn size_hint(&self) -> Option; +} +#[cfg(stage0)] pub trait ReverseIter: BaseIter { fn each_reverse(&self, blk: &fn(&A) -> bool); } +#[cfg(not(stage0))] +pub trait ReverseIter: BaseIter { + fn each_reverse(&self, blk: &fn(&A) -> bool) -> bool; +} +#[cfg(stage0)] pub trait MutableIter: BaseIter { fn each_mut(&mut self, blk: &fn(&mut A) -> bool); } +#[cfg(not(stage0))] +pub trait MutableIter: BaseIter { + fn each_mut(&mut self, blk: &fn(&mut A) -> bool) -> bool; +} pub trait ExtendedIter { + #[cfg(stage0)] fn eachi(&self, blk: &fn(uint, v: &A) -> bool); + #[cfg(not(stage0))] + fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool; fn all(&self, blk: &fn(&A) -> bool) -> bool; fn any(&self, blk: &fn(&A) -> bool) -> bool; fn foldl(&self, b0: B, blk: &fn(&B, &A) -> B) -> B; @@ -45,9 +64,14 @@ pub trait ExtendedIter { fn flat_map_to_vec>(&self, op: &fn(&A) -> IB) -> ~[B]; } +#[cfg(stage0)] pub trait ExtendedMutableIter { fn eachi_mut(&mut self, blk: &fn(uint, &mut A) -> bool); } +#[cfg(not(stage0))] +pub trait ExtendedMutableIter { + fn eachi_mut(&mut self, blk: &fn(uint, &mut A) -> bool) -> bool; +} pub trait EqIter { fn contains(&self, x: &A) -> bool; @@ -69,7 +93,7 @@ pub trait CopyableNonstrictIter { // Like "each", but copies out the value. If the receiver is mutated while // iterating over it, the semantics must not be memory-unsafe but are // otherwise undefined. - fn each_val(&const self, f: &fn(A) -> bool); + fn each_val(&const self, f: &fn(A) -> bool) -> bool; } // A trait for sequences that can be built by imperatively pushing elements @@ -92,56 +116,72 @@ pub trait Buildable { } #[inline(always)] -pub fn eachi>(self: &IA, blk: &fn(uint, &A) -> bool) { +pub fn _eachi>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { let mut i = 0; - for self.each |a| { - if !blk(i, a) { break; } + for this.each |a| { + if !blk(i, a) { + return false; + } i += 1; } + return true; +} + +#[cfg(stage0)] +pub fn eachi>(this: &IA, blk: &fn(uint, &A) -> bool) { + _eachi(this, blk); +} +#[cfg(not(stage0))] +pub fn eachi>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { + _eachi(this, blk) } #[inline(always)] -pub fn all>(self: &IA, blk: &fn(&A) -> bool) -> bool { - for self.each |a| { - if !blk(a) { return false; } +pub fn all>(this: &IA, blk: &fn(&A) -> bool) -> bool { + for this.each |a| { + if !blk(a) { + return false; + } } return true; } #[inline(always)] -pub fn any>(self: &IA, blk: &fn(&A) -> bool) -> bool { - for self.each |a| { - if blk(a) { return true; } +pub fn any>(this: &IA, blk: &fn(&A) -> bool) -> bool { + for this.each |a| { + if blk(a) { + return true; + } } return false; } #[inline(always)] -pub fn filter_to_vec>(self: &IA, +pub fn filter_to_vec>(this: &IA, prd: &fn(&A) -> bool) -> ~[A] { - do vec::build_sized_opt(self.size_hint()) |push| { - for self.each |a| { + do vec::build_sized_opt(this.size_hint()) |push| { + for this.each |a| { if prd(a) { push(*a); } } } } #[inline(always)] -pub fn map_to_vec>(self: &IA, op: &fn(&A) -> B) -> ~[B] { - do vec::build_sized_opt(self.size_hint()) |push| { - for self.each |a| { +pub fn map_to_vec>(this: &IA, op: &fn(&A) -> B) -> ~[B] { + do vec::build_sized_opt(this.size_hint()) |push| { + for this.each |a| { push(op(a)); } } } #[inline(always)] -pub fn flat_map_to_vec,IB:BaseIter>(self: &IA, +pub fn flat_map_to_vec,IB:BaseIter>(this: &IA, op: &fn(&A) -> IB) -> ~[B] { do vec::build |push| { - for self.each |a| { + for this.each |a| { for op(a).each |&b| { push(b); } @@ -150,31 +190,31 @@ pub fn flat_map_to_vec,IB:BaseIter>(self: &IA, } #[inline(always)] -pub fn foldl>(self: &IA, b0: B, blk: &fn(&B, &A) -> B) +pub fn foldl>(this: &IA, b0: B, blk: &fn(&B, &A) -> B) -> B { let mut b = b0; - for self.each |a| { + for this.each |a| { b = blk(&b, a); } b } #[inline(always)] -pub fn to_vec>(self: &IA) -> ~[A] { - map_to_vec(self, |&x| x) +pub fn to_vec>(this: &IA) -> ~[A] { + map_to_vec(this, |&x| x) } #[inline(always)] -pub fn contains>(self: &IA, x: &A) -> bool { - for self.each |a| { +pub fn contains>(this: &IA, x: &A) -> bool { + for this.each |a| { if *a == *x { return true; } } return false; } #[inline(always)] -pub fn count>(self: &IA, x: &A) -> uint { - do foldl(self, 0) |count, value| { +pub fn count>(this: &IA, x: &A) -> uint { + do foldl(this, 0) |count, value| { if *value == *x { *count + 1 } else { @@ -184,10 +224,10 @@ pub fn count>(self: &IA, x: &A) -> uint { } #[inline(always)] -pub fn position>(self: &IA, f: &fn(&A) -> bool) +pub fn position>(this: &IA, f: &fn(&A) -> bool) -> Option { let mut i = 0; - for self.each |a| { + for this.each |a| { if f(a) { return Some(i); } i += 1; } @@ -199,6 +239,7 @@ pub fn position>(self: &IA, f: &fn(&A) -> bool) // it would have to be implemented with foldr, which is too inefficient. #[inline(always)] +#[cfg(stage0)] pub fn repeat(times: uint, blk: &fn() -> bool) { let mut i = 0; while i < times { @@ -206,10 +247,20 @@ pub fn repeat(times: uint, blk: &fn() -> bool) { i += 1; } } +#[inline(always)] +#[cfg(not(stage0))] +pub fn repeat(times: uint, blk: &fn() -> bool) -> bool { + let mut i = 0; + while i < times { + if !blk() { return false; } + i += 1; + } + return true; +} #[inline(always)] -pub fn min>(self: &IA) -> A { - match do foldl::,IA>(self, None) |a, b| { +pub fn min>(this: &IA) -> A { + match do foldl::,IA>(this, None) |a, b| { match a { &Some(ref a_) if *a_ < *b => { *(a) @@ -223,8 +274,8 @@ pub fn min>(self: &IA) -> A { } #[inline(always)] -pub fn max>(self: &IA) -> A { - match do foldl::,IA>(self, None) |a, b| { +pub fn max>(this: &IA) -> A { + match do foldl::,IA>(this, None) |a, b| { match a { &Some(ref a_) if *a_ > *b => { *(a) @@ -238,9 +289,9 @@ pub fn max>(self: &IA) -> A { } #[inline(always)] -pub fn find>(self: &IA, f: &fn(&A) -> bool) +pub fn find>(this: &IA, f: &fn(&A) -> bool) -> Option { - for self.each |i| { + for this.each |i| { if f(i) { return Some(*i) } } return None; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 1aa7aada05c88..47ff45be68726 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -31,23 +31,11 @@ pub trait Mul { } #[lang="div"] -#[cfg(stage0)] pub trait Div { fn div(&self, rhs: &RHS) -> Result; } -#[lang="quot"] -#[cfg(not(stage0))] -pub trait Quot { - fn quot(&self, rhs: &RHS) -> Result; -} -#[lang="modulo"] -#[cfg(stage0)] -pub trait Modulo { - fn modulo(&self, rhs: &RHS) -> Result; -} #[lang="rem"] -#[cfg(not(stage0))] pub trait Rem { fn rem(&self, rhs: &RHS) -> Result; } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 17192b4257b16..e171552af4c74 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -48,6 +48,7 @@ use util; use num::Zero; use old_iter::{BaseIter, MutableIter, ExtendedIter}; use old_iter; +use str::StrSlice; #[cfg(test)] use str; @@ -100,19 +101,16 @@ impl> Add, Option> for Option { impl BaseIter for Option { /// Performs an operation on the contained value by reference - #[cfg(stage0)] #[inline(always)] - fn each(&self, f: &fn(x: &'self T) -> bool) { + #[cfg(stage0)] + fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) { match *self { None => (), Some(ref t) => { f(t); } } } - /// Performs an operation on the contained value by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] - fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) { - match *self { None => (), Some(ref t) => { f(t); } } + #[cfg(not(stage0))] + fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) -> bool { + match *self { None => true, Some(ref t) => { f(t) } } } #[inline(always)] @@ -124,23 +122,25 @@ impl BaseIter for Option { impl MutableIter for Option { #[cfg(stage0)] #[inline(always)] - fn each_mut(&mut self, f: &fn(&'self mut T) -> bool) { + fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) { match *self { None => (), Some(ref mut t) => { f(t); } } } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] + #[cfg(not(stage0))] #[inline(always)] - fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) { - match *self { None => (), Some(ref mut t) => { f(t); } } + fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) -> bool { + match *self { None => true, Some(ref mut t) => { f(t) } } } } impl ExtendedIter for Option { + #[cfg(stage0)] pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { old_iter::eachi(self, blk) } + #[cfg(not(stage0))] + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { + old_iter::eachi(self, blk) + } pub fn all(&self, blk: &fn(&A) -> bool) -> bool { old_iter::all(self, blk) } @@ -200,35 +200,12 @@ pub impl Option { * Update an optional value by optionally running its content by reference * through a function that returns an option. */ - #[cfg(stage0)] - #[inline(always)] - fn chain_ref(&self, f: &fn(x: &'self T) -> Option) -> Option { - match *self { Some(ref x) => f(x), None => None } - } - - /** - * Update an optional value by optionally running its content by reference - * through a function that returns an option. - */ - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option) -> Option { match *self { Some(ref x) => f(x), None => None } } /// Maps a `some` value from one type to another by reference - #[cfg(stage0)] - #[inline(always)] - fn map(&self, f: &fn(&'self T) -> U) -> Option { - match *self { Some(ref x) => Some(f(x)), None => None } - } - - /// Maps a `some` value from one type to another by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option { match *self { Some(ref x) => Some(f(x)), None => None } @@ -242,16 +219,6 @@ pub impl Option { } /// Applies a function to the contained value or returns a default - #[cfg(stage0)] - #[inline(always)] - fn map_default(&self, def: U, f: &fn(&'self T) -> U) -> U { - match *self { None => def, Some(ref t) => f(t) } - } - - /// Applies a function to the contained value or returns a default - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { match *self { None => def, Some(ref t) => f(t) } @@ -295,32 +262,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_ref(&self) -> &'self T { - match *self { - Some(ref x) => x, - None => fail!(~"option::get_ref none") - } - } - - /** - Gets an immutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_ref<'a>(&'a self) -> &'a T { match *self { Some(ref x) => x, @@ -343,32 +284,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_mut_ref(&mut self) -> &'self mut T { - match *self { - Some(ref mut x) => x, - None => fail!(~"option::get_mut_ref none") - } - } - - /** - Gets a mutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { Some(ref mut x) => x, @@ -565,11 +480,3 @@ fn test_get_or_zero() { let no_stuff: Option = None; assert!(no_stuff.get_or_zero() == 0); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/os.rs b/src/libcore/os.rs index f1962eeaa23d0..3e87f4f8dbb16 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -36,8 +36,8 @@ use option::{Some, None}; use prelude::*; use ptr; use str; -use task; use uint; +use unstable::finally::Finally; use vec; pub use libc::fclose; @@ -152,7 +152,7 @@ FIXME #4726: It would probably be appropriate to make this a real global */ fn with_env_lock(f: &fn() -> T) -> T { use unstable::global::global_data_clone_create; - use unstable::{Exclusive, exclusive}; + use unstable::sync::{Exclusive, exclusive}; struct SharedValue(()); type ValueMutex = Exclusive; @@ -196,10 +196,10 @@ pub fn env() -> ~[(~str,~str)] { } #[cfg(unix)] unsafe fn get_env_pairs() -> ~[~str] { - extern mod rustrt { + extern { unsafe fn rust_env_pairs() -> **libc::c_char; } - let environ = rustrt::rust_env_pairs(); + let environ = rust_env_pairs(); if (environ as uint == 0) { fail!(fmt!("os::env() failure getting env string from OS: %s", os::last_os_error())); @@ -351,13 +351,16 @@ pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int { } } -pub struct Pipe { mut in: c_int, mut out: c_int } +pub struct Pipe { + in: c_int, + out: c_int +} #[cfg(unix)] pub fn pipe() -> Pipe { unsafe { let mut fds = Pipe {in: 0 as c_int, - out: 0 as c_int }; + out: 0 as c_int }; assert!((libc::pipe(&mut fds.in) == (0 as c_int))); return Pipe {in: fds.in, out: fds.out}; } @@ -372,7 +375,7 @@ pub fn pipe() -> Pipe { // inheritance has to be handled in a different way that I do not // fully understand. Here we explicitly make the pipe non-inheritable, // which means to pass it to a subprocess they need to be duplicated - // first, as in rust_run_program. + // first, as in core::run. let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int }; let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, @@ -392,8 +395,8 @@ fn dup2(src: c_int, dst: c_int) -> c_int { pub fn dll_filename(base: &str) -> ~str { - return str::from_slice(DLL_PREFIX) + str::from_slice(base) + - str::from_slice(DLL_SUFFIX) + return str::to_owned(DLL_PREFIX) + str::to_owned(base) + + str::to_owned(DLL_SUFFIX) } @@ -546,6 +549,7 @@ pub fn tmpdir() -> Path { } } /// Recursively walk a directory structure +#[cfg(stage0)] pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) { walk_dir_(p, f); @@ -573,6 +577,14 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) { return keepgoing; } } +/// Recursively walk a directory structure +#[cfg(not(stage0))] +pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { + list_dir(p).each(|q| { + let path = &p.push(*q); + f(path) && (!path_is_dir(path) || walk_dir(path, f)) + }) +} /// Indicates whether a path represents a directory pub fn path_is_dir(p: &Path) -> bool { @@ -673,9 +685,8 @@ pub fn list_dir(p: &Path) -> ~[~str] { unsafe fn get_list(p: &Path) -> ~[~str] { use libc::{dirent_t}; use libc::{opendir, readdir, closedir}; - extern mod rustrt { - unsafe fn rust_list_dir_val(ptr: *dirent_t) - -> *libc::c_char; + extern { + unsafe fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; } let input = p.to_str(); let mut strings = ~[]; @@ -686,10 +697,8 @@ pub fn list_dir(p: &Path) -> ~[~str] { debug!("os::list_dir -- opendir() SUCCESS"); let mut entry_ptr = readdir(dir_ptr); while (entry_ptr as uint != 0) { - strings.push( - str::raw::from_c_str( - rustrt::rust_list_dir_val( - entry_ptr))); + strings.push(str::raw::from_c_str(rust_list_dir_val( + entry_ptr))); entry_ptr = readdir(dir_ptr); } closedir(dir_ptr); @@ -717,7 +726,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { }; use unstable::exchange_alloc::{malloc_raw, free_raw}; #[nolink] - extern mod rustrt { + extern { unsafe fn rust_list_dir_wfd_size() -> libc::size_t; unsafe fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) -> *u16; @@ -725,8 +734,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { fn star(p: &Path) -> Path { p.push("*") } do as_utf16_p(star(p).to_str()) |path_ptr| { let mut strings = ~[]; - let wfd_ptr = malloc_raw( - rustrt::rust_list_dir_wfd_size() as uint); + let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); let find_handle = FindFirstFileW( path_ptr, @@ -734,8 +742,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { if find_handle as int != INVALID_HANDLE_VALUE { let mut more_files = 1 as libc::c_int; while more_files != 0 { - let fp_buf = rustrt::rust_list_dir_wfd_fp_buf( - wfd_ptr); + let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); if fp_buf as uint == 0 { fail!(~"os::list_dir() failure:"+ ~" got null ptr from wfd"); @@ -771,6 +778,28 @@ pub fn list_dir_path(p: &Path) -> ~[~Path] { list_dir(p).map(|f| ~p.push(*f)) } +/// Removes a directory at the specified path, after removing +/// all its contents. Use carefully! +pub fn remove_dir_recursive(p: &Path) -> bool { + let mut error_happened = false; + for walk_dir(p) |inner| { + if !error_happened { + if path_is_dir(inner) { + if !remove_dir_recursive(inner) { + error_happened = true; + } + } + else { + if !remove_file(inner) { + error_happened = true; + } + } + } + }; + // Directory should now be empty + !error_happened && remove_dir(p) +} + /// Removes a directory at the specified path pub fn remove_dir(p: &Path) -> bool { return rmdir(p); @@ -818,6 +847,36 @@ pub fn change_dir(p: &Path) -> bool { } } +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use unstable::global::global_data_clone_create; + use unstable::sync::{Exclusive, exclusive}; + + fn key(_: Exclusive<()>) { } + + let result = unsafe { + global_data_clone_create(key, || { + ~exclusive(()) + }) + }; + + do result.with_imm() |_| { + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } + } +} + /// Copies a file from one location to another pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); @@ -846,6 +905,10 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { if istream as uint == 0u { return false; } + // Preserve permissions + let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ + for source file"); + let ostream = do as_c_charp(to.to_str()) |top| { do as_c_charp("w+b") |modebuf| { libc::fopen(top, modebuf) @@ -877,6 +940,15 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { } fclose(istream); fclose(ostream); + + // Give the new file the old file's permissions + unsafe { + if do str::as_c_str(to.to_str()) |to_buf| { + libc::chmod(to_buf, from_mode as mode_t) + } != 0 { + return false; // should be a condition... + } + } return ok; } } @@ -959,10 +1031,10 @@ pub fn last_os_error() -> ~str { #[cfg(target_os = "macos")] #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] - fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { #[nolink] extern { - unsafe fn strerror_r(errnum: c_int, buf: *c_char, + unsafe fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } unsafe { @@ -974,10 +1046,10 @@ pub fn last_os_error() -> ~str { // and requires macros to instead use the POSIX compliant variant. // So we just use __xpg_strerror_r which is always POSIX compliant #[cfg(target_os = "linux")] - fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { #[nolink] extern { - unsafe fn __xpg_strerror_r(errnum: c_int, buf: *c_char, + unsafe fn __xpg_strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } unsafe { @@ -987,7 +1059,7 @@ pub fn last_os_error() -> ~str { let mut buf = [0 as c_char, ..TMPBUF_SZ]; unsafe { - let err = strerror_r(errno() as c_int, &buf[0], + let err = strerror_r(errno() as c_int, &mut buf[0], TMPBUF_SZ as size_t); if err < 0 { fail!(~"strerror_r failure"); @@ -1139,7 +1211,7 @@ fn overridden_arg_key(_v: @OverriddenArgs) {} pub fn args() -> ~[~str] { unsafe { - match task::local_data::local_data_get(overridden_arg_key) { + match local_data::local_data_get(overridden_arg_key) { None => real_args(), Some(args) => copy args.val } @@ -1149,8 +1221,90 @@ pub fn args() -> ~[~str] { pub fn set_args(new_args: ~[~str]) { unsafe { let overridden_args = @OverriddenArgs { val: copy new_args }; - task::local_data::local_data_set(overridden_arg_key, overridden_args); + local_data::local_data_set(overridden_arg_key, overridden_args); + } +} + +// FIXME #6100 we should really use an internal implementation of this - using +// the POSIX glob functions isn't portable to windows, probably has slight +// inconsistencies even where it is implemented, and makes extending +// functionality a lot more difficult +// FIXME #6101 also provide a non-allocating version - each_glob or so? +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "freebsd")] +#[cfg(target_os = "macos")] +pub fn glob(pattern: &str) -> ~[Path] { + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + gl_pathv: ptr::null(), + gl_offs: 0, + __unused1: ptr::null(), + __unused2: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + } } + + #[cfg(target_os = "freebsd")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + #[cfg(target_os = "macos")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + let mut g = default_glob_t(); + do str::as_c_str(pattern) |c_pattern| { + unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } + }; + do(|| { + let paths = unsafe { + vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint) + }; + do paths.map |&c_str| { + Path(unsafe { str::raw::from_c_str(c_str) }) + } + }).finally { + unsafe { libc::globfree(&mut g) }; + } +} + +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "win32")] +pub fn glob(pattern: &str) -> ~[Path] { + fail!(~"glob() is unimplemented on Windows") } #[cfg(target_os = "macos")] @@ -1284,7 +1438,7 @@ mod tests { } fn make_rand_name() -> ~str { - let rng = rand::rng(); + let mut rng = rand::rng(); let n = ~"TEST" + rng.gen_str(10u); assert!(getenv(n).is_none()); n @@ -1340,7 +1494,7 @@ mod tests { fn test_env_getenv() { let e = env(); assert!(vec::len(e) > 0u); - for vec::each(e) |p| { + for e.each |p| { let (n, v) = copy *p; debug!(copy n); let v2 = getenv(n); @@ -1432,7 +1586,7 @@ mod tests { // Just assuming that we've got some contents in the current directory assert!((vec::len(dirs) > 0u)); - for vec::each(dirs) |dir| { + for dirs.each |dir| { debug!(copy *dir); } } @@ -1481,6 +1635,7 @@ mod tests { == buf.len() as size_t)) } assert!((libc::fclose(ostream) == (0u as c_int))); + let in_mode = in.get_mode(); let rs = os::copy_file(&in, &out); if (!os::path_exists(&in)) { fail!(fmt!("%s doesn't exist", in.to_str())); @@ -1488,6 +1643,7 @@ mod tests { assert!((rs)); let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]); assert!((rslt == 0)); + assert!(out.get_mode() == in_mode); assert!((remove_file(&in))); assert!((remove_file(&out))); } diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs index c483ec79e21d9..3262fb4afdcf6 100644 --- a/src/libcore/owned.rs +++ b/src/libcore/owned.rs @@ -10,9 +10,9 @@ //! Operations on unique pointer types -#[cfg(notest)] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::{Eq, Ord}; -#[cfg(notest)] +#[cfg(not(test))] impl Eq for ~T { #[inline(always)] fn eq(&self, other: &~T) -> bool { *(*self) == *(*other) } @@ -20,7 +20,7 @@ impl Eq for ~T { fn ne(&self, other: &~T) -> bool { *(*self) != *(*other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for ~T { #[inline(always)] fn lt(&self, other: &~T) -> bool { *(*self) < *(*other) } @@ -31,4 +31,3 @@ impl Ord for ~T { #[inline(always)] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } - diff --git a/src/libcore/path.rs b/src/libcore/path.rs index a87fd90f4e27a..2015c5474be32 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -14,12 +14,16 @@ Cross-platform file path handling */ +use container::Container; use cmp::Eq; use libc; use option::{None, Option, Some}; use str; +use str::StrSlice; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; +use old_iter::BaseIter; +use vec::OwnedVector; #[cfg(windows)] pub use Path = self::WindowsPath; @@ -122,7 +126,6 @@ pub trait GenericPath { mod stat { #[cfg(target_arch = "x86")] #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] pub mod arch { use libc; @@ -152,6 +155,36 @@ mod stat { } } + #[cfg(target_arch = "mips")] + pub mod arch { + use libc; + + pub fn default_stat() -> libc::stat { + libc::stat { + st_dev: 0, + st_pad1: [0, ..3], + st_ino: 0, + st_mode: 0, + st_nlink: 0, + st_uid: 0, + st_gid: 0, + st_rdev: 0, + st_pad2: [0, ..2], + st_size: 0, + st_pad3: 0, + st_atime: 0, + st_atime_nsec: 0, + st_mtime: 0, + st_mtime_nsec: 0, + st_ctime: 0, + st_ctime_nsec: 0, + st_blksize: 0, + st_blocks: 0, + st_pad5: [0, ..14], + } + } + } + #[cfg(target_arch = "x86_64")] pub mod arch { use libc; @@ -477,7 +510,7 @@ impl GenericPath for PosixPath { fn with_filestem(&self, s: &str) -> PosixPath { match self.filetype() { None => self.with_filename(s), - Some(ref t) => self.with_filename(str::from_slice(s) + *t) + Some(ref t) => self.with_filename(str::to_owned(s) + *t) } } @@ -488,7 +521,7 @@ impl GenericPath for PosixPath { Some(ref s) => self.with_filename(*s) } } else { - let t = ~"." + str::from_slice(t); + let t = ~"." + str::to_owned(t); match self.filestem() { None => self.with_filename(t), Some(ref s) => self.with_filename(*s + t) @@ -621,7 +654,7 @@ impl GenericPath for WindowsPath { None => { host = None; device = None; - rest = str::from_slice(s); + rest = str::to_owned(s); } } } @@ -694,7 +727,7 @@ impl GenericPath for WindowsPath { fn with_filestem(&self, s: &str) -> WindowsPath { match self.filetype() { None => self.with_filename(s), - Some(ref t) => self.with_filename(str::from_slice(s) + *t) + Some(ref t) => self.with_filename(str::to_owned(s) + *t) } } @@ -705,7 +738,7 @@ impl GenericPath for WindowsPath { Some(ref s) => self.with_filename(*s) } } else { - let t = ~"." + str::from_slice(t); + let t = ~"." + str::to_owned(t); match self.filestem() { None => self.with_filename(t), Some(ref s) => @@ -956,7 +989,7 @@ mod tests { fn test_posix_paths() { fn t(wp: &PosixPath, s: &str) { let ss = wp.to_str(); - let sss = str::from_slice(s); + let sss = str::to_owned(s); if (ss != sss) { debug!("got %s", ss); debug!("expected %s", sss); @@ -1014,7 +1047,7 @@ mod tests { fn test_normalize() { fn t(wp: &PosixPath, s: &str) { let ss = wp.to_str(); - let sss = str::from_slice(s); + let sss = str::to_owned(s); if (ss != sss) { debug!("got %s", ss); debug!("expected %s", sss); @@ -1077,7 +1110,7 @@ mod tests { fn test_windows_paths() { fn t(wp: &WindowsPath, s: &str) { let ss = wp.to_str(); - let sss = str::from_slice(s); + let sss = str::to_owned(s); if (ss != sss) { debug!("got %s", ss); debug!("expected %s", sss); diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 95b24d20a4bc2..fb80a43347e01 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -82,15 +82,21 @@ bounded and unbounded protocols allows for less code duplication. */ +use container::Container; use cast::{forget, transmute, transmute_copy}; use either::{Either, Left, Right}; use kinds::Owned; use libc; +use ops::Drop; use option::{None, Option, Some}; +use unstable::finally::Finally; use unstable::intrinsics; use ptr; +use ptr::Ptr; use task; use vec; +use vec::OwnedVector; +use util::replace; static SPIN_COUNT: uint = 0; @@ -109,7 +115,7 @@ enum State { pub struct BufferHeader { // Tracks whether this buffer needs to be freed. We can probably // get away with restricting it to 0 or 1, if we're careful. - mut ref_count: int, + ref_count: int, // We may want a drop, and to be careful about stringing this // thing along. @@ -128,12 +134,12 @@ pub struct Buffer { } pub struct PacketHeader { - mut state: State, - mut blocked_task: *rust_task, + state: State, + blocked_task: *rust_task, // This is a transmute_copy of a ~buffer, that can also be cast // to a buffer_header if need be. - mut buffer: *libc::c_void, + buffer: *libc::c_void, } pub fn PacketHeader() -> PacketHeader { @@ -146,14 +152,14 @@ pub fn PacketHeader() -> PacketHeader { pub impl PacketHeader { // Returns the old state. - unsafe fn mark_blocked(&self, this: *rust_task) -> State { + unsafe fn mark_blocked(&mut self, this: *rust_task) -> State { rustrt::rust_task_ref(this); let old_task = swap_task(&mut self.blocked_task, this); assert!(old_task.is_null()); swap_state_acq(&mut self.state, Blocked) } - unsafe fn unblock(&self) { + unsafe fn unblock(&mut self) { let old_task = swap_task(&mut self.blocked_task, ptr::null()); if !old_task.is_null() { rustrt::rust_task_deref(old_task) @@ -167,13 +173,13 @@ pub impl PacketHeader { // unsafe because this can do weird things to the space/time // continuum. It ends making multiple unique pointers to the same - // thing. You'll proobably want to forget them when you're done. - unsafe fn buf_header(&self) -> ~BufferHeader { + // thing. You'll probably want to forget them when you're done. + unsafe fn buf_header(&mut self) -> ~BufferHeader { assert!(self.buffer.is_not_null()); transmute_copy(&self.buffer) } - fn set_buffer(&self, b: ~Buffer) { + fn set_buffer(&mut self, b: ~Buffer) { unsafe { self.buffer = transmute_copy(&b); } @@ -182,15 +188,15 @@ pub impl PacketHeader { pub struct Packet { header: PacketHeader, - mut payload: Option, + payload: Option, } pub trait HasBuffer { - fn set_buffer(&self, b: *libc::c_void); + fn set_buffer(&mut self, b: *libc::c_void); } impl HasBuffer for Packet { - fn set_buffer(&self, b: *libc::c_void) { + fn set_buffer(&mut self, b: *libc::c_void) { self.header.buffer = b; } } @@ -202,7 +208,7 @@ pub fn mk_packet() -> Packet { } } fn unibuffer() -> ~Buffer> { - let b = ~Buffer { + let mut b = ~Buffer { header: BufferHeader(), data: Packet { header: PacketHeader(), @@ -216,22 +222,25 @@ fn unibuffer() -> ~Buffer> { b } -pub fn packet() -> *Packet { - let b = unibuffer(); - let p = ptr::to_unsafe_ptr(&(b.data)); +pub fn packet() -> *mut Packet { + let mut b = unibuffer(); + let p = ptr::to_mut_unsafe_ptr(&mut b.data); // We'll take over memory management from here. - unsafe { forget(b) } + unsafe { + forget(b); + } p } pub fn entangle_buffer( - buffer: ~Buffer, - init: &fn(*libc::c_void, x: &T) -> *Packet) - -> (SendPacketBuffered, RecvPacketBuffered) -{ - let p = init(unsafe { transmute_copy(&buffer) }, &buffer.data); - unsafe { forget(buffer) } - (SendPacketBuffered(p), RecvPacketBuffered(p)) + mut buffer: ~Buffer, + init: &fn(*libc::c_void, x: &mut T) -> *mut Packet) + -> (SendPacketBuffered, RecvPacketBuffered) { + unsafe { + let p = init(transmute_copy(&buffer), &mut buffer.data); + forget(buffer); + (SendPacketBuffered(p), RecvPacketBuffered(p)) + } } pub fn swap_task(dst: &mut *rust_task, src: *rust_task) -> *rust_task { @@ -290,7 +299,7 @@ fn swap_state_rel(dst: &mut State, src: State) -> State { } } -pub unsafe fn get_buffer(p: *PacketHeader) -> ~Buffer { +pub unsafe fn get_buffer(p: *mut PacketHeader) -> ~Buffer { transmute((*p).buf_header()) } @@ -301,13 +310,17 @@ struct BufferResource { } #[unsafe_destructor] -impl ::ops::Drop for BufferResource { +impl Drop for BufferResource { fn finalize(&self) { unsafe { - let b = move_it!(self.buffer); + let this: &mut BufferResource = transmute(self); + + let mut b = move_it!(this.buffer); //let p = ptr::to_unsafe_ptr(*b); //error!("drop %?", p); - let old_count = intrinsics::atomic_xsub_rel(&mut b.header.ref_count, 1); + let old_count = intrinsics::atomic_xsub_rel( + &mut b.header.ref_count, + 1); //let old_count = atomic_xchng_rel(b.header.ref_count, 0); if old_count == 1 { // The new count is 0. @@ -321,10 +334,12 @@ impl ::ops::Drop for BufferResource { } } -fn BufferResource(b: ~Buffer) -> BufferResource { +fn BufferResource(mut b: ~Buffer) -> BufferResource { //let p = ptr::to_unsafe_ptr(*b); //error!("take %?", p); - unsafe { intrinsics::atomic_xadd_acq(&mut b.header.ref_count, 1) }; + unsafe { + intrinsics::atomic_xadd_acq(&mut b.header.ref_count, 1); + } BufferResource { // tjc: ???? @@ -332,10 +347,12 @@ fn BufferResource(b: ~Buffer) -> BufferResource { } } -pub fn send(p: SendPacketBuffered, payload: T) -> bool { +pub fn send(mut p: SendPacketBuffered, + payload: T) + -> bool { let header = p.header(); let p_ = p.unwrap(); - let p = unsafe { &*p_ }; + let p = unsafe { &mut *p_ }; assert!(ptr::to_unsafe_ptr(&(p.header)) == header); assert!(p.payload.is_none()); p.payload = Some(payload); @@ -389,37 +406,31 @@ 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(p: RecvPacketBuffered) - -> Option -{ +pub fn try_recv(mut p: RecvPacketBuffered) + -> Option { let p_ = p.unwrap(); - let p = unsafe { &*p_ }; + let p = unsafe { &mut *p_ }; - #[unsafe_destructor] - struct DropState<'self> { - p: &'self PacketHeader, - - drop { - unsafe { - if task::failing() { - self.p.state = Terminated; - let old_task = swap_task(&mut self.p.blocked_task, - ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task); - } + do (|| { + try_recv_(p) + }).finally { + unsafe { + if task::failing() { + p.header.state = Terminated; + let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); + if !old_task.is_null() { + rustrt::rust_task_deref(old_task); } } } - }; - - let _drop_state = DropState { p: &p.header }; + } +} +fn try_recv_(p: &mut Packet) -> Option { // optimistic path match p.header.state { Full => { - let mut payload = None; - payload <-> p.payload; + let payload = replace(&mut p.payload, None); p.header.state = Empty; return Some(payload.unwrap()) }, @@ -451,7 +462,7 @@ pub fn try_recv(p: RecvPacketBuffered) Blocked); match old_state { Empty => { - debug!("no data available on %?, going to sleep.", p_); + debug!("no data available on %?, going to sleep.", p); if count == 0 { wait_event(this); } @@ -470,8 +481,7 @@ pub fn try_recv(p: RecvPacketBuffered) fail!(~"blocking on already blocked packet") }, Full => { - let mut payload = None; - payload <-> p.payload; + let payload = replace(&mut p.payload, None); let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); if !old_task.is_null() { unsafe { @@ -500,16 +510,20 @@ pub fn try_recv(p: RecvPacketBuffered) } /// Returns true if messages are available. -pub fn peek(p: &RecvPacketBuffered) -> bool { - match unsafe {(*p.header()).state} { - Empty | Terminated => false, - Blocked => fail!(~"peeking on blocked packet"), - Full => true +pub fn peek(p: &mut RecvPacketBuffered) -> bool { + unsafe { + match (*p.header()).state { + Empty | Terminated => false, + Blocked => fail!(~"peeking on blocked packet"), + Full => true + } } } -fn sender_terminate(p: *Packet) { - let p = unsafe { &*p }; +fn sender_terminate(p: *mut Packet) { + let p = unsafe { + &mut *p + }; match swap_state_rel(&mut p.header.state, Terminated) { Empty => { // The receiver will eventually clean up. @@ -538,8 +552,10 @@ fn sender_terminate(p: *Packet) { } } -fn receiver_terminate(p: *Packet) { - let p = unsafe { &*p }; +fn receiver_terminate(p: *mut Packet) { + let p = unsafe { + &mut *p + }; match swap_state_rel(&mut p.header.state, Terminated) { Empty => { assert!(p.header.blocked_task.is_null()); @@ -571,8 +587,10 @@ that vector. The index points to an endpoint that has either been closed by the sender or has a message waiting to be received. */ -pub fn wait_many(pkts: &[T]) -> uint { - let this = unsafe { rustrt::rust_get_task() }; +pub fn wait_many(pkts: &mut [T]) -> uint { + let this = unsafe { + rustrt::rust_get_task() + }; unsafe { rustrt::task_clear_event_reject(this); @@ -580,19 +598,19 @@ pub fn wait_many(pkts: &[T]) -> uint { let mut data_avail = false; let mut ready_packet = pkts.len(); - for pkts.eachi |i, p| { + for vec::eachi_mut(pkts) |i, p| { unsafe { - let p = &*p.header(); + let p = &mut *p.header(); let old = p.mark_blocked(this); match old { - Full | Terminated => { - data_avail = true; - ready_packet = i; - (*p).state = old; - break; - } - Blocked => fail!(~"blocking on blocked packet"), - Empty => () + Full | Terminated => { + data_avail = true; + ready_packet = i; + (*p).state = old; + break; + } + Blocked => fail!(~"blocking on blocked packet"), + Empty => () } } } @@ -600,7 +618,14 @@ pub fn wait_many(pkts: &[T]) -> uint { while !data_avail { debug!("sleeping on %? packets", pkts.len()); let event = wait_event(this) as *PacketHeader; - let pos = vec::position(pkts, |p| p.header() == event); + + let mut pos = None; + for vec::eachi_mut(pkts) |i, p| { + if p.header() == event { + pos = Some(i); + break; + } + }; match pos { Some(i) => { @@ -611,11 +636,15 @@ pub fn wait_many(pkts: &[T]) -> uint { } } - debug!("%?", pkts[ready_packet]); + debug!("%?", &mut pkts[ready_packet]); - for pkts.each |p| { unsafe{ (*p.header()).unblock()} } + for vec::each_mut(pkts) |p| { + unsafe { + (*p.header()).unblock() + } + } - debug!("%?, %?", ready_packet, pkts[ready_packet]); + debug!("%?, %?", ready_packet, &mut pkts[ready_packet]); unsafe { assert!((*pkts[ready_packet].header()).state == Full @@ -631,69 +660,57 @@ message. */ pub type SendPacket = SendPacketBuffered>; -pub fn SendPacket(p: *Packet) -> SendPacket { +pub fn SendPacket(p: *mut Packet) -> SendPacket { SendPacketBuffered(p) } pub struct SendPacketBuffered { - mut p: Option<*Packet>, - mut buffer: Option>, + p: Option<*mut Packet>, + buffer: Option>, } #[unsafe_destructor] -impl ::ops::Drop for SendPacketBuffered { +impl Drop for SendPacketBuffered { fn finalize(&self) { - //if self.p != none { - // debug!("drop send %?", option::get(self.p)); - //} - if self.p != None { - let mut p = None; - p <-> self.p; - sender_terminate(p.unwrap()) + unsafe { + let this: &mut SendPacketBuffered = transmute(self); + if this.p != None { + let p = replace(&mut this.p, None); + sender_terminate(p.unwrap()) + } } - //unsafe { error!("send_drop: %?", - // if self.buffer == none { - // "none" - // } else { "some" }); } } } -pub fn SendPacketBuffered(p: *Packet) - -> SendPacketBuffered { - //debug!("take send %?", p); +pub fn SendPacketBuffered(p: *mut Packet) + -> SendPacketBuffered { SendPacketBuffered { p: Some(p), buffer: unsafe { - Some(BufferResource( - get_buffer(ptr::to_unsafe_ptr(&((*p).header))))) + Some(BufferResource(get_buffer(&mut (*p).header))) } } } pub impl SendPacketBuffered { - fn unwrap(&self) -> *Packet { - let mut p = None; - p <-> self.p; - p.unwrap() + fn unwrap(&mut self) -> *mut Packet { + replace(&mut self.p, None).unwrap() } - fn header(&self) -> *PacketHeader { + fn header(&mut self) -> *mut PacketHeader { match self.p { - Some(packet) => unsafe { - let packet = &*packet; - let header = ptr::to_unsafe_ptr(&(packet.header)); - //forget(packet); - header - }, - None => fail!(~"packet already consumed") + Some(packet) => unsafe { + let packet = &mut *packet; + let header = ptr::to_mut_unsafe_ptr(&mut packet.header); + header + }, + None => fail!(~"packet already consumed") } } - fn reuse_buffer(&self) -> BufferResource { + fn reuse_buffer(&mut self) -> BufferResource { //error!("send reuse_buffer"); - let mut tmp = None; - tmp <-> self.buffer; - tmp.unwrap() + replace(&mut self.buffer, None).unwrap() } } @@ -701,69 +718,57 @@ pub impl SendPacketBuffered { /// message. pub type RecvPacket = RecvPacketBuffered>; -pub fn RecvPacket(p: *Packet) -> RecvPacket { +pub fn RecvPacket(p: *mut Packet) -> RecvPacket { RecvPacketBuffered(p) } + pub struct RecvPacketBuffered { - mut p: Option<*Packet>, - mut buffer: Option>, + p: Option<*mut Packet>, + buffer: Option>, } #[unsafe_destructor] -impl ::ops::Drop for RecvPacketBuffered { +impl Drop for RecvPacketBuffered { fn finalize(&self) { - //if self.p != none { - // debug!("drop recv %?", option::get(self.p)); - //} - if self.p != None { - let mut p = None; - p <-> self.p; - receiver_terminate(p.unwrap()) + unsafe { + let this: &mut RecvPacketBuffered = transmute(self); + if this.p != None { + let p = replace(&mut this.p, None); + receiver_terminate(p.unwrap()) + } } - //unsafe { error!("recv_drop: %?", - // if self.buffer == none { - // "none" - // } else { "some" }); } } } pub impl RecvPacketBuffered { - fn unwrap(&self) -> *Packet { - let mut p = None; - p <-> self.p; - p.unwrap() + fn unwrap(&mut self) -> *mut Packet { + replace(&mut self.p, None).unwrap() } - fn reuse_buffer(&self) -> BufferResource { - //error!("recv reuse_buffer"); - let mut tmp = None; - tmp <-> self.buffer; - tmp.unwrap() + fn reuse_buffer(&mut self) -> BufferResource { + replace(&mut self.buffer, None).unwrap() } } impl Selectable for RecvPacketBuffered { - fn header(&self) -> *PacketHeader { + fn header(&mut self) -> *mut PacketHeader { match self.p { - Some(packet) => unsafe { - let packet = &*packet; - let header = ptr::to_unsafe_ptr(&(packet.header)); - //forget(packet); - header - }, - None => fail!(~"packet already consumed") + Some(packet) => unsafe { + let packet = &mut *packet; + let header = ptr::to_mut_unsafe_ptr(&mut packet.header); + header + }, + None => fail!(~"packet already consumed") } } } -pub fn RecvPacketBuffered(p: *Packet) - -> RecvPacketBuffered { - //debug!("take recv %?", p); +pub fn RecvPacketBuffered(p: *mut Packet) + -> RecvPacketBuffered { RecvPacketBuffered { p: Some(p), buffer: unsafe { - Some(BufferResource( - get_buffer(ptr::to_unsafe_ptr(&((*p).header))))) + Some(BufferResource(get_buffer(&mut (*p).header))) } } } @@ -802,51 +807,55 @@ this case, `select2` may return either `left` or `right`. */ pub fn select2( - a: RecvPacketBuffered, - b: RecvPacketBuffered) + mut a: RecvPacketBuffered, + mut b: RecvPacketBuffered) -> Either<(Option, RecvPacketBuffered), - (RecvPacketBuffered, Option)> -{ - let i = wait_many([a.header(), b.header()]); - + (RecvPacketBuffered, Option)> { + let mut endpoints = [ a.header(), b.header() ]; + let i = wait_many(endpoints); match i { - 0 => Left((try_recv(a), b)), - 1 => Right((a, try_recv(b))), - _ => fail!(~"select2 return an invalid packet") + 0 => Left((try_recv(a), b)), + 1 => Right((a, try_recv(b))), + _ => fail!(~"select2 return an invalid packet") } } pub trait Selectable { - fn header(&self) -> *PacketHeader; + fn header(&mut self) -> *mut PacketHeader; } -impl Selectable for *PacketHeader { - fn header(&self) -> *PacketHeader { *self } +impl Selectable for *mut PacketHeader { + fn header(&mut self) -> *mut PacketHeader { *self } } /// Returns the index of an endpoint that is ready to receive. -pub fn selecti(endpoints: &[T]) -> uint { +pub fn selecti(endpoints: &mut [T]) -> uint { wait_many(endpoints) } /// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i(a: &A, b: &B) -> - Either<(), ()> { - match wait_many([a.header(), b.header()]) { - 0 => Left(()), - 1 => Right(()), - _ => fail!(~"wait returned unexpected index") +pub fn select2i(a: &mut A, b: &mut B) + -> Either<(), ()> { + let mut endpoints = [ a.header(), b.header() ]; + match wait_many(endpoints) { + 0 => Left(()), + 1 => Right(()), + _ => fail!(~"wait returned unexpected index") } } -/** Waits on a set of endpoints. Returns a message, its index, and a - list of the remaining endpoints. +/// Waits on a set of endpoints. Returns a message, its index, and a +/// list of the remaining endpoints. +pub fn select(mut endpoints: ~[RecvPacketBuffered]) + -> (uint, + Option, + ~[RecvPacketBuffered]) { + let mut endpoint_headers = ~[]; + for vec::each_mut(endpoints) |endpoint| { + endpoint_headers.push(endpoint.header()); + } -*/ -pub fn select(endpoints: ~[RecvPacketBuffered]) - -> (uint, Option, ~[RecvPacketBuffered]) -{ - let ready = wait_many(endpoints.map(|p| p.header())); + let ready = wait_many(endpoint_headers); let mut remaining = endpoints; let port = remaining.swap_remove(ready); let result = try_recv(port); @@ -875,9 +884,10 @@ mod test { c1.send(~"abc"); - match (p1, p2).select() { - Right(_) => fail!(), - _ => () + let mut tuple = (p1, p2); + match tuple.select() { + Right(_) => fail!(), + _ => (), } c2.send(123); diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 9a2e480ce6e54..22172db930223 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -13,11 +13,8 @@ /* Reexported core operators */ pub use either::{Either, Left, Right}; -pub use kinds::{Const, Copy, Owned, Durable}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; +pub use kinds::{Const, Copy, Owned}; +pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; pub use ops::{Shl, Shr, Index}; @@ -31,7 +28,7 @@ pub use io::{print, println}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; @@ -51,6 +48,7 @@ pub use path::WindowsPath; pub use ptr::Ptr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; pub use str::{StrSlice, OwnedStr}; +pub use from_str::{FromStr}; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; @@ -83,6 +81,7 @@ pub use io; pub use iter; pub use old_iter; pub use libc; +pub use local_data; pub use num; pub use ops; pub use option; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 86b36834bbd6e..0aff6e06e69bd 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -15,7 +15,7 @@ use libc; use libc::{c_void, size_t}; use sys; -#[cfg(notest)] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::{Eq, Ord}; use uint; pub mod libc_ { @@ -243,7 +243,7 @@ impl Ptr for *mut T { } // Equality for pointers -#[cfg(notest)] +#[cfg(not(test))] impl Eq for *const T { #[inline(always)] fn eq(&self, other: &*const T) -> bool { @@ -258,7 +258,7 @@ impl Eq for *const T { } // Comparison for pointers -#[cfg(notest)] +#[cfg(not(test))] impl Ord for *const T { #[inline(always)] fn lt(&self, other: &*const T) -> bool { @@ -295,35 +295,35 @@ impl Ord for *const T { } // Equality for region pointers -#[cfg(notest)] -impl<'self,T:Eq> Eq for &'self const T { +#[cfg(not(test))] +impl<'self,T:Eq> Eq for &'self T { #[inline(always)] - fn eq(&self, other: & &'self const T) -> bool { + fn eq(&self, other: & &'self T) -> bool { return *(*self) == *(*other); } #[inline(always)] - fn ne(&self, other: & &'self const T) -> bool { + fn ne(&self, other: & &'self T) -> bool { return *(*self) != *(*other); } } // Comparison for region pointers -#[cfg(notest)] -impl<'self,T:Ord> Ord for &'self const T { +#[cfg(not(test))] +impl<'self,T:Ord> Ord for &'self T { #[inline(always)] - fn lt(&self, other: & &'self const T) -> bool { + fn lt(&self, other: & &'self T) -> bool { *(*self) < *(*other) } #[inline(always)] - fn le(&self, other: & &'self const T) -> bool { + fn le(&self, other: & &'self T) -> bool { *(*self) <= *(*other) } #[inline(always)] - fn ge(&self, other: & &'self const T) -> bool { + fn ge(&self, other: & &'self T) -> bool { *(*self) >= *(*other) } #[inline(always)] - fn gt(&self, other: & &'self const T) -> bool { + fn gt(&self, other: & &'self T) -> bool { *(*self) > *(*other) } } @@ -336,7 +336,10 @@ pub mod ptr_tests { #[test] fn test() { unsafe { - struct Pair {mut fst: int, mut snd: int}; + struct Pair { + fst: int, + snd: int + }; let mut p = Pair {fst: 10, snd: 20}; let pptr: *mut Pair = &mut p; let iptr: *mut int = cast::transmute(pptr); @@ -350,7 +353,7 @@ pub mod ptr_tests { assert!((p.fst == 50)); assert!((p.snd == 60)); - let mut v0 = ~[32000u16, 32001u16, 32002u16]; + let v0 = ~[32000u16, 32001u16, 32002u16]; let mut v1 = ~[0u16, 0u16, 0u16]; copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1u), diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 9fa099cabbfe9..daf0b9d094aca 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -16,6 +16,9 @@ and so can be used to generate any type that implements `Rand`. Type inference means that often a simple call to `rand::random()` or `rng.gen()` will suffice, but sometimes an annotation is required, e.g. `rand::random::()`. +See the `distributions` submodule for sampling random numbers from +distributions like normal and exponential. + # Examples ~~~ use core::rand::RngUtil; @@ -40,21 +43,23 @@ fn main () { use int; use prelude::*; use str; -use task; use u32; use uint; use util; use vec; use libc::size_t; +#[path="rand/distributions.rs"] +pub mod distributions; + /// A type that can be randomly generated using an Rng pub trait Rand { - fn rand(rng: &R) -> Self; + fn rand(rng: &mut R) -> Self; } impl Rand for int { #[inline] - fn rand(rng: &R) -> int { + fn rand(rng: &mut R) -> int { if int::bits == 32 { rng.next() as int } else { @@ -65,35 +70,35 @@ impl Rand for int { impl Rand for i8 { #[inline] - fn rand(rng: &R) -> i8 { + fn rand(rng: &mut R) -> i8 { rng.next() as i8 } } impl Rand for i16 { #[inline] - fn rand(rng: &R) -> i16 { + fn rand(rng: &mut R) -> i16 { rng.next() as i16 } } impl Rand for i32 { #[inline] - fn rand(rng: &R) -> i32 { + fn rand(rng: &mut R) -> i32 { rng.next() as i32 } } impl Rand for i64 { #[inline] - fn rand(rng: &R) -> i64 { + fn rand(rng: &mut R) -> i64 { (rng.next() as i64 << 32) | rng.next() as i64 } } impl Rand for uint { #[inline] - fn rand(rng: &R) -> uint { + fn rand(rng: &mut R) -> uint { if uint::bits == 32 { rng.next() as uint } else { @@ -104,42 +109,42 @@ impl Rand for uint { impl Rand for u8 { #[inline] - fn rand(rng: &R) -> u8 { + fn rand(rng: &mut R) -> u8 { rng.next() as u8 } } impl Rand for u16 { #[inline] - fn rand(rng: &R) -> u16 { + fn rand(rng: &mut R) -> u16 { rng.next() as u16 } } impl Rand for u32 { #[inline] - fn rand(rng: &R) -> u32 { + fn rand(rng: &mut R) -> u32 { rng.next() } } impl Rand for u64 { #[inline] - fn rand(rng: &R) -> u64 { + fn rand(rng: &mut R) -> u64 { (rng.next() as u64 << 32) | rng.next() as u64 } } impl Rand for float { #[inline] - fn rand(rng: &R) -> float { + fn rand(rng: &mut R) -> float { rng.gen::() as float } } impl Rand for f32 { #[inline] - fn rand(rng: &R) -> f32 { + fn rand(rng: &mut R) -> f32 { rng.gen::() as f32 } } @@ -147,7 +152,7 @@ impl Rand for f32 { static scale : f64 = (u32::max_value as f64) + 1.0f64; impl Rand for f64 { #[inline] - fn rand(rng: &R) -> f64 { + fn rand(rng: &mut R) -> f64 { let u1 = rng.next() as f64; let u2 = rng.next() as f64; let u3 = rng.next() as f64; @@ -158,14 +163,14 @@ impl Rand for f64 { impl Rand for char { #[inline] - fn rand(rng: &R) -> char { + fn rand(rng: &mut R) -> char { rng.next() as char } } impl Rand for bool { #[inline] - fn rand(rng: &R) -> bool { + fn rand(rng: &mut R) -> bool { rng.next() & 1u32 == 1u32 } } @@ -179,7 +184,7 @@ macro_rules! tuple_impl { > Rand for ( $( $tyvar ),* , ) { #[inline] - fn rand(_rng: &R) -> ( $( $tyvar ),* , ) { + fn rand(_rng: &mut R) -> ( $( $tyvar ),* , ) { ( // use the $tyvar's to get the appropriate number of // repeats (they're not actually needed) @@ -195,7 +200,7 @@ macro_rules! tuple_impl { impl Rand for () { #[inline] - fn rand(_: &R) -> () { () } + fn rand(_: &mut R) -> () { () } } tuple_impl!{A} tuple_impl!{A, B} @@ -210,7 +215,7 @@ tuple_impl!{A, B, C, D, E, F, G, H, I, J} impl Rand for Option { #[inline] - fn rand(rng: &R) -> Option { + fn rand(rng: &mut R) -> Option { if rng.gen() { Some(rng.gen()) } else { @@ -221,12 +226,12 @@ impl Rand for Option { impl Rand for ~T { #[inline] - fn rand(rng: &R) -> ~T { ~rng.gen() } + fn rand(rng: &mut R) -> ~T { ~rng.gen() } } impl Rand for @T { #[inline] - fn rand(rng: &R) -> @T { @rng.gen() } + fn rand(rng: &mut R) -> @T { @rng.gen() } } #[abi = "cdecl"] @@ -242,7 +247,7 @@ pub mod rustrt { /// A random number generator pub trait Rng { /// Return the next random integer - pub fn next(&self) -> u32; + pub fn next(&mut self) -> u32; } /// A value with a particular weight compared to other values @@ -253,21 +258,21 @@ pub struct Weighted { pub trait RngUtil { /// Return a random value of a Rand type - fn gen(&self) -> T; + fn gen(&mut self) -> T; /** * Return a int randomly chosen from the range [start, end), * failing if start >= end */ - fn gen_int_range(&self, start: int, end: int) -> int; + fn gen_int_range(&mut self, start: int, end: int) -> int; /** * Return a uint randomly chosen from the range [start, end), * failing if start >= end */ - fn gen_uint_range(&self, start: uint, end: uint) -> uint; + fn gen_uint_range(&mut self, start: uint, end: uint) -> uint; /** * Return a char randomly chosen from chars, failing if chars is empty */ - fn gen_char_from(&self, chars: &str) -> char; + fn gen_char_from(&mut self, chars: &str) -> char; /** * Return a bool with a 1 in n chance of true * @@ -283,7 +288,7 @@ pub trait RngUtil { * } * ~~~ */ - fn gen_weighted_bool(&self, n: uint) -> bool; + fn gen_weighted_bool(&mut self, n: uint) -> bool; /** * Return a random string of the specified length composed of A-Z,a-z,0-9 * @@ -299,7 +304,7 @@ pub trait RngUtil { * } * ~~~ */ - fn gen_str(&self, len: uint) -> ~str; + fn gen_str(&mut self, len: uint) -> ~str; /** * Return a random byte string of the specified length * @@ -315,7 +320,7 @@ pub trait RngUtil { * } * ~~~ */ - fn gen_bytes(&self, len: uint) -> ~[u8]; + fn gen_bytes(&mut self, len: uint) -> ~[u8]; /** * Choose an item randomly, failing if values is empty * @@ -331,9 +336,9 @@ pub trait RngUtil { * } * ~~~ */ - fn choose(&self, values: &[T]) -> T; + fn choose(&mut self, values: &[T]) -> T; /// Choose Some(item) randomly, returning None if values is empty - fn choose_option(&self, values: &[T]) -> Option; + fn choose_option(&mut self, values: &[T]) -> Option; /** * Choose an item respecting the relative weights, failing if the sum of * the weights is 0 @@ -353,7 +358,7 @@ pub trait RngUtil { * } * ~~~ */ - fn choose_weighted(&self, v : &[Weighted]) -> T; + fn choose_weighted(&mut self, v : &[Weighted]) -> T; /** * Choose Some(item) respecting the relative weights, returning none if * the sum of the weights is 0 @@ -373,7 +378,8 @@ pub trait RngUtil { * } * ~~~ */ - fn choose_weighted_option(&self, v: &[Weighted]) -> Option; + fn choose_weighted_option(&mut self, v: &[Weighted]) + -> Option; /** * Return a vec containing copies of the items, in order, where * the weight of the item determines how many copies there are @@ -393,7 +399,7 @@ pub trait RngUtil { * } * ~~~ */ - fn weighted_vec(&self, v: &[Weighted]) -> ~[T]; + fn weighted_vec(&mut self, v: &[Weighted]) -> ~[T]; /** * Shuffle a vec * @@ -409,7 +415,7 @@ pub trait RngUtil { * } * ~~~ */ - fn shuffle(&self, values: &[T]) -> ~[T]; + fn shuffle(&mut self, values: &[T]) -> ~[T]; /** * Shuffle a mutable vec in place * @@ -429,14 +435,14 @@ pub trait RngUtil { * } * ~~~ */ - fn shuffle_mut(&self, values: &mut [T]); + fn shuffle_mut(&mut self, values: &mut [T]); } /// Extension methods for random number generators impl RngUtil for R { /// Return a random value for a Rand type #[inline(always)] - fn gen(&self) -> T { + fn gen(&mut self) -> T { Rand::rand(self) } @@ -444,7 +450,7 @@ impl RngUtil for R { * Return an int randomly chosen from the range [start, end), * failing if start >= end */ - fn gen_int_range(&self, start: int, end: int) -> int { + fn gen_int_range(&mut self, start: int, end: int) -> int { assert!(start < end); start + int::abs(self.gen::() % (end - start)) } @@ -453,7 +459,7 @@ impl RngUtil for R { * Return a uint randomly chosen from the range [start, end), * failing if start >= end */ - fn gen_uint_range(&self, start: uint, end: uint) -> uint { + fn gen_uint_range(&mut self, start: uint, end: uint) -> uint { assert!(start < end); start + (self.gen::() % (end - start)) } @@ -461,7 +467,7 @@ impl RngUtil for R { /** * Return a char randomly chosen from chars, failing if chars is empty */ - fn gen_char_from(&self, chars: &str) -> char { + fn gen_char_from(&mut self, chars: &str) -> char { assert!(!chars.is_empty()); let mut cs = ~[]; for str::each_char(chars) |c| { cs.push(c) } @@ -469,7 +475,7 @@ impl RngUtil for R { } /// Return a bool with a 1-in-n chance of true - fn gen_weighted_bool(&self, n: uint) -> bool { + fn gen_weighted_bool(&mut self, n: uint) -> bool { if n == 0u { true } else { @@ -480,7 +486,7 @@ impl RngUtil for R { /** * Return a random string of the specified length composed of A-Z,a-z,0-9 */ - fn gen_str(&self, len: uint) -> ~str { + fn gen_str(&mut self, len: uint) -> ~str { let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz\ 0123456789"; @@ -494,19 +500,19 @@ impl RngUtil for R { } /// Return a random byte string of the specified length - fn gen_bytes(&self, len: uint) -> ~[u8] { + fn gen_bytes(&mut self, len: uint) -> ~[u8] { do vec::from_fn(len) |_i| { self.gen() } } /// Choose an item randomly, failing if values is empty - fn choose(&self, values: &[T]) -> T { + fn choose(&mut self, values: &[T]) -> T { self.choose_option(values).get() } /// Choose Some(item) randomly, returning None if values is empty - fn choose_option(&self, values: &[T]) -> Option { + fn choose_option(&mut self, values: &[T]) -> Option { if values.is_empty() { None } else { @@ -517,7 +523,7 @@ impl RngUtil for R { * Choose an item respecting the relative weights, failing if the sum of * the weights is 0 */ - fn choose_weighted(&self, v : &[Weighted]) -> T { + fn choose_weighted(&mut self, v: &[Weighted]) -> T { self.choose_weighted_option(v).get() } @@ -525,7 +531,8 @@ impl RngUtil for R { * Choose Some(item) respecting the relative weights, returning none if * the sum of the weights is 0 */ - fn choose_weighted_option(&self, v: &[Weighted]) -> Option { + fn choose_weighted_option(&mut self, v: &[Weighted]) + -> Option { let mut total = 0u; for v.each |item| { total += item.weight; @@ -548,7 +555,7 @@ impl RngUtil for R { * Return a vec containing copies of the items, in order, where * the weight of the item determines how many copies there are */ - fn weighted_vec(&self, v: &[Weighted]) -> ~[T] { + fn weighted_vec(&mut self, v: &[Weighted]) -> ~[T] { let mut r = ~[]; for v.each |item| { for uint::range(0u, item.weight) |_i| { @@ -559,14 +566,14 @@ impl RngUtil for R { } /// Shuffle a vec - fn shuffle(&self, values: &[T]) -> ~[T] { - let mut m = vec::from_slice(values); + fn shuffle(&mut self, values: &[T]) -> ~[T] { + let mut m = vec::to_owned(values); self.shuffle_mut(m); m } /// Shuffle a mutable vec in place - fn shuffle_mut(&self, values: &mut [T]) { + fn shuffle_mut(&mut self, values: &mut [T]) { let mut i = values.len(); while i >= 2u { // invariant: elements with index >= i have been locked in place. @@ -588,12 +595,12 @@ static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; /// A random number generator that uses the [ISAAC /// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). pub struct IsaacRng { - priv mut cnt: u32, - priv mut rsl: [u32, .. RAND_SIZE], - priv mut mem: [u32, .. RAND_SIZE], - priv mut a: u32, - priv mut b: u32, - priv mut c: u32 + priv cnt: u32, + priv rsl: [u32, .. RAND_SIZE], + priv mem: [u32, .. RAND_SIZE], + priv a: u32, + priv b: u32, + priv c: u32 } pub impl IsaacRng { @@ -641,7 +648,7 @@ pub impl IsaacRng { /// Initialises `self`. If `use_rsl` is true, then use the current value /// of `rsl` as a seed, otherwise construct one algorithmically (not /// randomly). - priv fn init(&self, use_rsl: bool) { + priv fn init(&mut self, use_rsl: bool) { macro_rules! init_mut_many ( ($( $var:ident ),* = $val:expr ) => { let mut $( $var = $val ),*; @@ -699,16 +706,16 @@ pub impl IsaacRng { /// Refills the output buffer (`self.rsl`) #[inline] - priv fn isaac(&self) { + priv fn isaac(&mut self) { self.c += 1; // abbreviations let mut a = self.a, b = self.b + self.c; - let mem = &mut self.mem; - let rsl = &mut self.rsl; static midpoint: uint = RAND_SIZE as uint / 2; - macro_rules! ind (($x:expr) => { mem[($x >> 2) & (RAND_SIZE - 1)] }); + macro_rules! ind (($x:expr) => { + self.mem[($x >> 2) & (RAND_SIZE - 1)] + }); macro_rules! rngstep( ($j:expr, $shift:expr) => {{ let base = base + $j; @@ -718,13 +725,13 @@ pub impl IsaacRng { a << $shift as uint }; - let x = mem[base + mr_offset]; - a = (a ^ mix) + mem[base + m2_offset]; + let x = self.mem[base + mr_offset]; + a = (a ^ mix) + self.mem[base + m2_offset]; let y = ind!(x) + a + b; - mem[base + mr_offset] = y; + self.mem[base + mr_offset] = y; b = ind!(y >> RAND_SIZE_LEN) + x; - rsl[base + mr_offset] = b; + self.rsl[base + mr_offset] = b; }} ); @@ -745,7 +752,7 @@ pub impl IsaacRng { impl Rng for IsaacRng { #[inline(always)] - fn next(&self) -> u32 { + fn next(&mut self) -> u32 { if self.cnt == 0 { // make some more numbers self.isaac(); @@ -759,15 +766,15 @@ impl Rng for IsaacRng { /// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for /// cryptographic purposes. pub struct XorShiftRng { - priv mut x: u32, - priv mut y: u32, - priv mut z: u32, - priv mut w: u32, + priv x: u32, + priv y: u32, + priv z: u32, + priv w: u32, } impl Rng for XorShiftRng { #[inline] - pub fn next(&self) -> u32 { + pub fn next(&mut self) -> u32 { let x = self.x; let t = x ^ (x << 11); self.x = self.y; @@ -783,7 +790,10 @@ pub impl XorShiftRng { /// Create an xor shift random number generator with a default seed. fn new() -> XorShiftRng { // constants taken from http://en.wikipedia.org/wiki/Xorshift - XorShiftRng::new_seeded(123456789u32, 362436069u32, 521288629u32, 88675123u32) + XorShiftRng::new_seeded(123456789u32, + 362436069u32, + 521288629u32, + 88675123u32) } /** @@ -792,7 +802,12 @@ pub impl XorShiftRng { * all other generators constructed with the same seed. */ fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { - XorShiftRng { x: x, y: y, z: z, w: w } + XorShiftRng { + x: x, + y: y, + z: z, + w: w, + } } } @@ -809,7 +824,7 @@ pub fn seed() -> ~[u8] { } // used to make space in TLS for a random number generator -fn tls_rng_state(_v: @IsaacRng) {} +fn tls_rng_state(_v: @@mut IsaacRng) {} /** * Gives back a lazily initialized task-local random number generator, @@ -817,16 +832,16 @@ fn tls_rng_state(_v: @IsaacRng) {} * `task_rng().gen::()`. */ #[inline] -pub fn task_rng() -> @IsaacRng { - let r : Option<@IsaacRng>; +pub fn task_rng() -> @@mut IsaacRng { + let r : Option<@@mut IsaacRng>; unsafe { - r = task::local_data::local_data_get(tls_rng_state); + r = local_data::local_data_get(tls_rng_state); } match r { None => { unsafe { - let rng = @IsaacRng::new_seeded(seed()); - task::local_data::local_data_set(tls_rng_state, rng); + let rng = @@mut IsaacRng::new_seeded(seed()); + local_data::local_data_set(tls_rng_state, rng); rng } } @@ -835,9 +850,13 @@ pub fn task_rng() -> @IsaacRng { } // Allow direct chaining with `task_rng` -impl Rng for @R { +impl Rng for @@mut R { #[inline(always)] - fn next(&self) -> u32 { (**self).next() } + fn next(&mut self) -> u32 { + match *self { + @@ref mut r => r.next() + } + } } /** @@ -846,7 +865,9 @@ impl Rng for @R { */ #[inline] pub fn random() -> T { - (*task_rng()).gen() + match *task_rng() { + @ref mut r => r.gen() + } } #[cfg(test)] @@ -857,8 +878,8 @@ mod tests { #[test] fn test_rng_seeded() { let seed = seed(); - let ra = IsaacRng::new_seeded(seed); - let rb = IsaacRng::new_seeded(seed); + let mut ra = IsaacRng::new_seeded(seed); + let mut rb = IsaacRng::new_seeded(seed); assert!(ra.gen_str(100u) == rb.gen_str(100u)); } @@ -866,15 +887,15 @@ mod tests { fn test_rng_seeded_custom_seed() { // much shorter than generated seeds which are 1024 bytes let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let ra = IsaacRng::new_seeded(seed); - let rb = IsaacRng::new_seeded(seed); + let mut ra = IsaacRng::new_seeded(seed); + let mut rb = IsaacRng::new_seeded(seed); assert!(ra.gen_str(100u) == rb.gen_str(100u)); } #[test] fn test_rng_seeded_custom_seed2() { let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let ra = IsaacRng::new_seeded(seed); + let mut ra = IsaacRng::new_seeded(seed); // Regression test that isaac is actually using the above vector let r = ra.next(); error!("%?", r); @@ -884,7 +905,7 @@ mod tests { #[test] fn test_gen_int_range() { - let r = rng(); + let mut r = rng(); let a = r.gen_int_range(-3, 42); assert!(a >= -3 && a < 42); assert!(r.gen_int_range(0, 1) == 0); @@ -895,12 +916,13 @@ mod tests { #[should_fail] #[ignore(cfg(windows))] fn test_gen_int_from_fail() { - rng().gen_int_range(5, -2); + let mut r = rng(); + r.gen_int_range(5, -2); } #[test] fn test_gen_uint_range() { - let r = rng(); + let mut r = rng(); let a = r.gen_uint_range(3u, 42u); assert!(a >= 3u && a < 42u); assert!(r.gen_uint_range(0u, 1u) == 0u); @@ -911,12 +933,13 @@ mod tests { #[should_fail] #[ignore(cfg(windows))] fn test_gen_uint_range_fail() { - rng().gen_uint_range(5u, 2u); + let mut r = rng(); + r.gen_uint_range(5u, 2u); } #[test] fn test_gen_float() { - let r = rng(); + let mut r = rng(); let a = r.gen::(); let b = r.gen::(); debug!((a, b)); @@ -924,14 +947,14 @@ mod tests { #[test] fn test_gen_weighted_bool() { - let r = rng(); + let mut r = rng(); assert!(r.gen_weighted_bool(0u) == true); assert!(r.gen_weighted_bool(1u) == true); } #[test] fn test_gen_str() { - let r = rng(); + let mut r = rng(); debug!(r.gen_str(10u)); debug!(r.gen_str(10u)); debug!(r.gen_str(10u)); @@ -942,7 +965,7 @@ mod tests { #[test] fn test_gen_bytes() { - let r = rng(); + let mut r = rng(); assert!(r.gen_bytes(0u).len() == 0u); assert!(r.gen_bytes(10u).len() == 10u); assert!(r.gen_bytes(16u).len() == 16u); @@ -950,13 +973,13 @@ mod tests { #[test] fn test_choose() { - let r = rng(); + let mut r = rng(); assert!(r.choose([1, 1, 1]) == 1); } #[test] fn test_choose_option() { - let r = rng(); + let mut r = rng(); let x: Option = r.choose_option([]); assert!(x.is_none()); assert!(r.choose_option([1, 1, 1]) == Some(1)); @@ -964,7 +987,7 @@ mod tests { #[test] fn test_choose_weighted() { - let r = rng(); + let mut r = rng(); assert!(r.choose_weighted(~[ Weighted { weight: 1u, item: 42 }, ]) == 42); @@ -976,7 +999,7 @@ mod tests { #[test] fn test_choose_weighted_option() { - let r = rng(); + let mut r = rng(); assert!(r.choose_weighted_option(~[ Weighted { weight: 1u, item: 42 }, ]) == Some(42)); @@ -990,7 +1013,7 @@ mod tests { #[test] fn test_weighted_vec() { - let r = rng(); + let mut r = rng(); let empty: ~[int] = ~[]; assert!(r.weighted_vec(~[]) == empty); assert!(r.weighted_vec(~[ @@ -1002,7 +1025,7 @@ mod tests { #[test] fn test_shuffle() { - let r = rng(); + let mut r = rng(); let empty: ~[int] = ~[]; assert!(r.shuffle(~[]) == empty); assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); @@ -1010,7 +1033,7 @@ mod tests { #[test] fn test_task_rng() { - let r = task_rng(); + let mut r = task_rng(); r.gen::(); assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); assert!(r.gen_uint_range(0u, 1u) == 0u); @@ -1057,7 +1080,7 @@ mod tests { let rt_rng = do vec::as_imm_buf(seed) |p, sz| { rustrt::rand_new_seeded(p, sz as size_t) }; - let rng = IsaacRng::new_seeded(seed); + let mut rng = IsaacRng::new_seeded(seed); for 10000.times { assert_eq!(rng.next(), rustrt::rand_next(rt_rng)); @@ -1067,12 +1090,3 @@ mod tests { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/rand/distributions.rs b/src/libcore/rand/distributions.rs new file mode 100644 index 0000000000000..72cff5111e762 --- /dev/null +++ b/src/libcore/rand/distributions.rs @@ -0,0 +1,148 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sampling from random distributions + +// Some implementations use the Ziggurat method +// https://en.wikipedia.org/wiki/Ziggurat_algorithm +// +// The version used here is ZIGNOR [Doornik 2005, "An Improved +// Ziggurat Method to Generate Normal Random Samples"] which is slower +// (about double, it generates an extra random number) than the +// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for +// Generating Random Variables"], but more robust. If one wanted, one +// could implement VIZIGNOR the ZIGNOR paper for more speed. + +use prelude::*; +use rand::{Rng,Rand}; + +mod ziggurat_tables; + +// inlining should mean there is no performance penalty for this +#[inline(always)] +fn ziggurat(rng: &mut R, + center_u: bool, + X: ziggurat_tables::ZigTable, + F: ziggurat_tables::ZigTable, + F_DIFF: ziggurat_tables::ZigTable, + pdf: &'static fn(f64) -> f64, // probability density function + zero_case: &'static fn(&mut R, f64) -> f64) -> f64 { + loop { + let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()}; + let i: uint = rng.gen::() & 0xff; + let x = u * X[i]; + + let test_x = if center_u {f64::abs(x)} else {x}; + + // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i]) + if test_x < X[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) { + return x; + } + } +} + +/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a +/// standard normal, or Gaussian). Multiplying the generated values by the +/// desired standard deviation `sigma` then adding the desired mean `mu` will +/// give N(mu, sigma^2) distributed random numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::StandardNormal; +/// +/// fn main() { +/// let normal = 2.0 + (*rand::random::()) * 3.0; +/// println(fmt!("%f is from a N(2, 9) distribution", normal)) +/// } +/// ~~~ +pub struct StandardNormal(f64); + +impl Rand for StandardNormal { + fn rand(rng: &mut R) -> StandardNormal { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp((-x*x/2.0) as f64) as f64 + } + #[inline(always)] + fn zero_case(rng: &mut R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // 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 = 1.0, y = 0.0; + + // XXX infinities? + while -2.0*y < x * x { + x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R; + y = f64::ln(rng.gen()); + } + if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x} + } + + StandardNormal(ziggurat( + rng, + true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF, + pdf, zero_case)) + } +} + +/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by +/// the desired rate `lambda` will give Exp(lambda) distributed random +/// numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::Exp1; +/// +/// fn main() { +/// let exp2 = (*rand::random::()) * 0.5; +/// println(fmt!("%f is from a Exp(2) distribution", exp2)); +/// } +/// ~~~ +pub struct Exp1(f64); + +// This could be done via `-f64::ln(rng.gen::())` but that is slower. +impl Rand for Exp1 { + #[inline] + fn rand(rng: &mut R) -> Exp1 { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp(-x) + } + #[inline(always)] + fn zero_case(rng: &mut R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen()) + } + + Exp1(ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF, + pdf, zero_case)) + } +} diff --git a/src/libcore/rand/ziggurat_tables.rs b/src/libcore/rand/ziggurat_tables.rs new file mode 100644 index 0000000000000..aca2457cac42c --- /dev/null +++ b/src/libcore/rand/ziggurat_tables.rs @@ -0,0 +1,412 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64, .. 257]; +pub static ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64, .. 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64, .. 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub static ZIG_NORM_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000782818165911943, 0.001348786815607765, 0.001428899847265509, + 0.001484430705892882, 0.001528472172127356, 0.001565707298030807, 0.001598388670308183, + 0.001627786418212004, 0.001654692743837703, 0.001679637706201265, 0.001702994844613767, + 0.001725038123187510, 0.001745974954326004, 0.001765966477270568, 0.001785140598493315, + 0.001803600702759419, 0.001821431661060659, 0.001838704088536796, 0.001855477433793579, + 0.001871802266665008, 0.001887722003144375, 0.001903274226858077, 0.001918491715965767, + 0.001933403251421835, 0.001948034260540625, 0.001962407334827158, 0.001976542650643127, + 0.001990458313945481, 0.002004170645086643, 0.002017694415851860, 0.002031043048104267, + 0.002044228781321551, 0.002057262814738517, 0.002070155428613822, 0.002082916088226049, + 0.002095553533492583, 0.002108075856553551, 0.002120490569226280, 0.002132804661891696, + 0.002145024655099026, 0.002157156644953973, 0.002169206343177243, 0.002181179112575302, + 0.002193079998548175, 0.002204913757158977, 0.002216684880213121, 0.002228397617726446, + 0.002240055998106505, 0.002251663846325885, 0.002263224800326716, 0.002274742325862292, + 0.002286219729956393, 0.002297660173134250, 0.002309066680560787, 0.002320442152205823, + 0.002331789372137141, 0.002343111017035562, 0.002354409664009627, 0.002365687797781804, + 0.002376947817308683, 0.002388192041889739, 0.002399422716815966, 0.002410642018598946, + 0.002421852059823287, 0.002433054893654529, 0.002444252518034679, 0.002455446879594508, + 0.002466639877306970, 0.002477833365903986, 0.002489029159078809, 0.002500229032490808, + 0.002511434726590794, 0.002522647949281448, 0.002533870378427505, 0.002545103664226889, + 0.002556349431455662, 0.002567609281597438, 0.002578884794865288, 0.002590177532127119, + 0.002601489036740262, 0.002612820836305291, 0.002624174444343735, 0.002635551361907296, + 0.002646953079123743, 0.002658381076686089, 0.002669836827288052, 0.002681321797012387, + 0.002692837446676144, 0.002704385233135737, 0.002715966610556786, 0.002727583031652520, + 0.002739235948893221, 0.002750926815690169, 0.002762657087557796, 0.002774428223256353, + 0.002786241685917290, 0.002798098944155558, 0.002810001473169871, 0.002821950755833219, + 0.002833948283778004, 0.002845995558475284, 0.002858094092312607, 0.002870245409671041, + 0.002882451048004164, 0.002894712558920987, 0.002907031509275432, 0.002919409482262880, + 0.002931848078526783, 0.002944348917277934, 0.002956913637427061, 0.002969543898733384, + 0.002982241382970874, 0.002995007795115689, 0.003007844864553855, 0.003020754346314269, + 0.003033738022328147, 0.003046797702715820, 0.003059935227105459, 0.003073152465984053, + 0.003086451322084072, 0.003099833731808721, 0.003113301666695822, 0.003126857134927052, + 0.003140502182881588, 0.003154238896738770, 0.003168069404132778, 0.003181995875862154, + 0.003196020527657495, 0.003210145622009941, 0.003224373470066433, 0.003238706433592253, + 0.003253146927007733, 0.003267697419501892, 0.003282360437226572, 0.003297138565578506, + 0.003312034451571411, 0.003327050806304299, 0.003342190407532641, 0.003357456102345890, + 0.003372850809960137, 0.003388377524629727, 0.003404039318688046, 0.003419839345721265, + 0.003435780843885239, 0.003451867139373843, 0.003468101650046629, 0.003484487889225119, + 0.003501029469670069, 0.003517730107746697, 0.003534593627793237, 0.003551623966702611, + 0.003568825178730639, 0.003586201440546166, 0.003603757056536316, 0.003621496464384588, + 0.003639424240937217, 0.003657545108379068, 0.003675863940735269, 0.003694385770723563, + 0.003713115796977806, 0.003732059391668707, 0.003751222108547281, 0.003770609691440940, + 0.003790228083232539, 0.003810083435355216, 0.003830182117840641, 0.003850530729957835, + 0.003871136111486317, 0.003892005354668437, 0.003913145816891062, 0.003934565134149914, + 0.003956271235355358, 0.003978272357543333, 0.004000577062061084, 0.004023194251800533, + 0.004046133189565926, 0.004069403517661885, 0.004093015278800460, 0.004116978938436600, + 0.004141305408647655, 0.004166006073685835, 0.004191092817346642, 0.004216578052307351, + 0.004242474751606884, 0.004268796482457593, 0.004295557442594244, 0.004322772499391836, + 0.004350457232007221, 0.004378627976825644, 0.004407301876525049, 0.004436496933105327, + 0.004466232065271192, 0.004496527170598785, 0.004527403192966406, 0.004558882195791591, + 0.004590987441673855, 0.004623743479123199, 0.004657176237135574, 0.004691313128472929, + 0.004726183162616859, 0.004761817069491636, 0.004798247435199299, 0.004835508851176451, + 0.004873638078381815, 0.004912674228345848, 0.004952658963181422, 0.004993636716962402, + 0.005035654941235035, 0.005078764377854039, 0.005123019362831771, 0.005168478165478940, + 0.005215203367812893, 0.005263262290042703, 0.005312727468930079, 0.005363677197016692, + 0.005416196132139284, 0.005470375988385734, 0.005526316321746716, 0.005584125426278286, + 0.005643921359735682, 0.005705833121505521, 0.005770002010457520, 0.005836583196307310, + 0.005905747545561058, 0.005977683752542928, 0.006052600837980204, 0.006130731092920838, + 0.006212333565464245, 0.006297698213369562, 0.006387150879090475, 0.006481059288027780, + 0.006579840329791975, 0.006683968961788356, 0.006793989182803495, 0.006910527673723577, + 0.007034310911336661, 0.007166186857056056, 0.007307152748134871, 0.007458391141830445, + 0.007621317291194862, 0.007797642342679434, 0.007989459040836144, 0.008199360125510702, + 0.008430605346682607, 0.008687362737884952, 0.008975066840784529, 0.009300967772353674, + 0.009675004947253041, 0.010111261142904171, 0.010630518154258861, 0.011265064987797335, + 0.012068570920629962, 0.013138877484087819, 0.014680138359337902, 0.017222609470315398, + 0.022898298717268672]; +pub static ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64, .. 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64, .. 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; +pub static ZIG_EXP_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000287067661533533, 0.000513134928485678, 0.000569030497974398, + 0.000609667963417335, 0.000642831049855169, 0.000671465984262828, 0.000697030342996893, + 0.000720360862708599, 0.000741986223663093, 0.000762263730113694, 0.000781447246315807, + 0.000799724254382053, 0.000817237547791934, 0.000834098656693235, 0.000850396538527769, + 0.000866203416804620, 0.000881578828420777, 0.000896572504999613, 0.000911226471926952, + 0.000925576608509206, 0.000939653828282008, 0.000953484986066785, 0.000967093584871414, + 0.000980500333784669, 0.000993723593313716, 0.001006779734568374, 0.001019683431705467, + 0.001032447902101660, 0.001045085105172934, 0.001057605908173612, 0.001070020225402434, + 0.001082337135821582, 0.001094564983022843, 0.001106711460658764, 0.001118783685829211, + 0.001130788262427001, 0.001142731336065933, 0.001154618641914802, 0.001166455546523074, + 0.001178247084534012, 0.001189997991027938, 0.001201712730115490, 0.001213395520299268, + 0.001225050357040701, 0.001236681032901414, 0.001248291155571943, 0.001259884164055092, + 0.001271463343231895, 0.001283031837006378, 0.001294592660197942, 0.001306148709326875, + 0.001317702772419903, 0.001329257537945404, 0.001340815602974395, 0.001352379480650950, + 0.001363951607045839, 0.001375534347457789, 0.001387130002219621, 0.001398740812059381, + 0.001410368963061376, 0.001422016591266340, 0.001433685786946429, 0.001445378598586011, + 0.001457097036596827, 0.001468843076792140, 0.001480618663643060, 0.001492425713336909, + 0.001504266116655995, 0.001516141741693663, 0.001528054436422108, 0.001540006031125918, + 0.001551998340713470, 0.001564033166917514, 0.001576112300394977, 0.001588237522735750, + 0.001600410608388780, 0.001612633326513305, 0.001624907442762655, 0.001637234721007311, + 0.001649616925003372, 0.001662055820012304, 0.001674553174376953, 0.001687110761059388, + 0.001699730359144919, 0.001712413755316500, 0.001725162745304071, 0.001737979135312442, + 0.001750864743431488, 0.001763821401032123, 0.001776850954151601, 0.001789955264870927, + 0.001803136212688003, 0.001816395695889220, 0.001829735632922019, 0.001843157963772116, + 0.001856664651347151, 0.001870257682870316, 0.001883939071285826, 0.001897710856679738, + 0.001911575107717528, 0.001925533923102574, 0.001939589433056721, 0.001953743800826108, + 0.001967999224215228, 0.001982357937151347, 0.001996822211282223, 0.002011394357609747, + 0.002026076728162574, 0.002040871717710169, 0.002055781765521847, 0.002070809357173103, + 0.002085957026402963, 0.002101227357025226, 0.002116622984897121, 0.002132146599948981, + 0.002147800948277823, 0.002163588834309782, 0.002179513123034188, 0.002195576742314159, + 0.002211782685277469, 0.002228134012792427, 0.002244633856033434, 0.002261285419141418, + 0.002278091981983449, 0.002295056903017983, 0.002312183622271174, 0.002329475664429648, + 0.002346936642057179, 0.002364570258941101, 0.002382380313575932, 0.002400370702791893, + 0.002418545425535629, 0.002436908586812392, 0.002455464401797752, 0.002474217200128692, + 0.002493171430384328, 0.002512331664766249, 0.002531702603989994, 0.002551289082400404, + 0.002571096073321844, 0.002591128694658967, 0.002611392214760672, 0.002631892058563845, + 0.002652633814032662, 0.002673623238910738, 0.002694866267805934, 0.002716369019626269, + 0.002738137805389534, 0.002760179136428037, 0.002782499733014893, 0.002805106533435520, + 0.002828006703534697, 0.002851207646767162, 0.002874717014785921, 0.002898542718600849, + 0.002922692940346749, 0.002947176145699226, 0.002972001096982591, 0.002997176867015228, + 0.003022712853742948, 0.003048618795714386, 0.003074904788455568, 0.003101581301807876, + 0.003128659198296080, 0.003156149752600867, 0.003184064672214937, 0.003212416119368622, + 0.003241216734320596, 0.003270479660111680, 0.003300218568896729, 0.003330447689969929, + 0.003361181839619420, 0.003392436452949343, 0.003424227617828290, 0.003456572111131984, + 0.003489487437467131, 0.003522991870580083, 0.003557104497672658, 0.003591845266868621, + 0.003627235038102472, 0.003663295637722386, 0.003700049917134574, 0.003737521815846301, + 0.003775736429304177, 0.003814720081962375, 0.003854500406067995, 0.003895106426696382, + 0.003936568653631844, 0.003978919180756157, 0.004022191793678687, 0.004066422086428989, + 0.004111647588127876, 0.004157907900659452, 0.004205244848493050, 0.004253702641940915, + 0.004303328055299205, 0.004354170621502118, 0.004406282845128784, 0.004459720435841752, + 0.004514542564613699, 0.004570812145417769, 0.004628596145424491, 0.004687965927177740, + 0.004748997626717266, 0.004811772572194672, 0.004876377748206484, 0.004942906311860507, + 0.005011458167522187, 0.005082140608288488, 0.005155069033533799, 0.005230367753417398, + 0.005308170893076836, 0.005388623411430704, 0.005471882252147620, 0.005558117647517014, + 0.005647514599798176, 0.005740274569295156, 0.005836617404105682, 0.005936783553485037, + 0.006041036615386131, 0.006149666279423593, 0.006262991739818591, 0.006381365669577810, + 0.006505178868201678, 0.006634865721946159, 0.006770910649812723, 0.006913855752425535, + 0.007064309938019209, 0.007222959874423007, 0.007390583214465396, 0.007568064673498798, + 0.007756415714389786, 0.007956798835585532, 0.008170557788458321, 0.008399255510700199, + 0.008644722212900025, 0.008909116987305010, 0.009195007664428712, 0.009505475652925033, + 0.009844255532840629, 0.010215923852312625, 0.010626158965710175, 0.011082105722287849, + 0.011592898788496009, 0.012170432837851575, 0.012830529553771619, 0.013594766864701180, + 0.014493463190219380, 0.015570784932380066, 0.016894014550512759, 0.018571645120042057, + 0.020792203980939394, 0.023918831757214210, 0.028765597544542998, 0.037673750936428774, + 0.061856319137823523]; diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 9a0526b4351ba..30f60dce04113 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -15,7 +15,7 @@ Runtime type reflection */ use intrinsic::{TyDesc, TyVisitor}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use libc::c_void; use sys; use vec; @@ -394,17 +394,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - self.align(align); - if ! self.inner.visit_enter_enum(n_variants, sz, align) { - return false; - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) @@ -420,7 +409,6 @@ impl TyVisitor for MovePtrAdaptor { disr_val: int, n_fields: uint, name: &str) -> bool { - self.inner.push_ptr(); // NOTE remove after next snapshot if ! self.inner.visit_enter_enum_variant(variant, disr_val, n_fields, name) { return false; @@ -428,15 +416,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_enum_variant_field(i, inner) { return false; } - unsafe { self.bump((*inner).size); } - true - } - - #[cfg(not(stage0))] fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { self.inner.push_ptr(); self.bump(offset); @@ -453,21 +432,9 @@ impl TyVisitor for MovePtrAdaptor { n_fields, name) { return false; } - self.inner.pop_ptr(); // NOTE remove after next snapshot - true - } - - #[cfg(stage0)] - fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - if ! self.inner.visit_leave_enum(n_variants, sz, align) { - return false; - } - self.bump(sz); true } - #[cfg(not(stage0))] fn visit_leave_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) -> bool { diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 03e44e00d8831..0bf8635d1c8f3 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -18,18 +18,18 @@ use cast::transmute; use char; use intrinsic; use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use io::{Writer, WriterUtil}; use libc::c_void; use managed; use ptr; -#[cfg(stage0)] use sys; use reflect; use reflect::{MovePtr, align}; +use str::StrSlice; use to_str::ToStr; -use vec::UnboxedVecRepr; use vec::raw::{VecRepr, SliceRepr}; use vec; +use vec::{OwnedVector, UnboxedVecRepr}; #[cfg(test)] use io; @@ -138,14 +138,6 @@ impl Repr for char { // New implementation using reflect::MovePtr -#[cfg(stage0)] -enum VariantState { - Degenerate, - TagMatch, - TagMismatch, -} - -#[cfg(not(stage0))] enum VariantState { SearchingFor(int), Matched, @@ -153,28 +145,30 @@ enum VariantState { } pub struct ReprVisitor { - mut ptr: *c_void, - mut ptr_stk: ~[*c_void], - mut var_stk: ~[VariantState], + ptr: @mut *c_void, + ptr_stk: @mut ~[*c_void], + var_stk: @mut ~[VariantState], writer: @Writer } pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor { - ReprVisitor { ptr: ptr, - ptr_stk: ~[], - var_stk: ~[], - writer: writer } + ReprVisitor { + ptr: @mut ptr, + ptr_stk: @mut ~[], + var_stk: @mut ~[], + writer: writer, + } } impl MovePtr for ReprVisitor { #[inline(always)] fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) { - self.ptr = adjustment(self.ptr); + *self.ptr = adjustment(*self.ptr); } fn push_ptr(&self) { - self.ptr_stk.push(self.ptr); + self.ptr_stk.push(*self.ptr); } fn pop_ptr(&self) { - self.ptr = self.ptr_stk.pop(); + *self.ptr = self.ptr_stk.pop(); } } @@ -185,26 +179,14 @@ pub impl ReprVisitor { #[inline(always)] fn get(&self, f: &fn(&T)) -> bool { unsafe { - f(transmute::<*c_void,&T>(copy self.ptr)); + f(transmute::<*c_void,&T>(*self.ptr)); } true } - #[cfg(stage0)] #[inline(always)] - fn bump(&self, sz: uint) { - do self.move_ptr() |p| { - ((p as uint) + sz) as *c_void - }; - } - - #[cfg(stage0)] #[inline(always)] - fn bump_past(&self) { - self.bump(sys::size_of::()); - } - #[inline(always)] fn visit_inner(&self, inner: *TyDesc) -> bool { - self.visit_ptr_inner(self.ptr, inner) + self.visit_ptr_inner(*self.ptr, inner) } #[inline(always)] @@ -467,60 +449,19 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, - _sz: uint, _align: uint) -> bool { - if n_variants == 1 { - self.var_stk.push(Degenerate) - } else { - self.var_stk.push(TagMatch) - } - true - } - - #[cfg(not(stage0))] - fn visit_enter_enum(&self, _n_variants: uint, + fn visit_enter_enum(&self, + _n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, - _sz: uint, _align: uint) -> bool { - let disr = unsafe { get_disr(transmute(self.ptr)) }; - self.var_stk.push(SearchingFor(disr)); - true - } - - #[cfg(stage0)] - fn visit_enter_enum_variant(&self, _variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - let mut write = false; - match self.var_stk.pop() { - Degenerate => { - write = true; - self.var_stk.push(Degenerate); - } - TagMatch | TagMismatch => { - do self.get::() |t| { - if disr_val == *t { - write = true; - self.var_stk.push(TagMatch); - } else { - self.var_stk.push(TagMismatch); - } - }; - self.bump_past::(); - } - } - - if write { - self.writer.write_str(name); - if n_fields > 0 { - self.writer.write_char('('); - } - } + _sz: uint, + _align: uint) -> bool { + let var_stk: &mut ~[VariantState] = self.var_stk; + let disr = unsafe { + get_disr(transmute(*self.ptr)) + }; + var_stk.push(SearchingFor(disr)); true } - #[cfg(not(stage0))] fn visit_enter_enum_variant(&self, _variant: uint, disr_val: int, n_fields: uint, @@ -549,25 +490,12 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if i != 0 { - self.writer.write_str(", "); - } - if ! self.visit_inner(inner) { - return false; - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] - fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { + fn visit_enum_variant_field(&self, + i: uint, + _offset: uint, + inner: *TyDesc) + -> bool { + match self.var_stk[vec::uniq_len(&const *self.var_stk) - 1] { Matched => { if i != 0 { self.writer.write_str(", "); @@ -581,28 +509,11 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum_variant(&self, _variant: uint, - _disr_val: int, - n_fields: uint, - _name: &str) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if n_fields > 0 { - self.writer.write_char(')'); - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, n_fields: uint, _name: &str) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { + match self.var_stk[vec::uniq_len(&const *self.var_stk) - 1] { Matched => { if n_fields > 0 { self.writer.write_char(')'); @@ -613,18 +524,14 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum(&self, _n_variants: uint, - _sz: uint, _align: uint) -> bool { - self.var_stk.pop(); - true - } - - #[cfg(not(stage0))] - fn visit_leave_enum(&self, _n_variants: uint, + fn visit_leave_enum(&self, + _n_variants: uint, _get_disr: extern unsafe fn(ptr: *Opaque) -> int, - _sz: uint, _align: uint) -> bool { - match self.var_stk.pop() { + _sz: uint, + _align: uint) + -> bool { + let var_stk: &mut ~[VariantState] = self.var_stk; + match var_stk.pop() { SearchingFor(*) => fail!(~"enum value matched no variant"), _ => true } @@ -673,7 +580,7 @@ pub fn write_repr(writer: @Writer, object: &T) { } } -#[test] +#[cfg(test)] struct P {a: int, b: float} #[test] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9171c5167bc7b..b7de667878399 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -17,7 +17,9 @@ use either; use either::Either; use kinds::Copy; use option::{None, Option, Some}; +use old_iter::BaseIter; use vec; +use vec::OwnedVector; /// The result type #[deriving(Clone, Eq)] @@ -226,13 +228,6 @@ pub fn map_err(res: &Result, op: &fn(&E) -> F) } pub impl Result { - #[cfg(stage0)] - #[inline(always)] - fn get_ref(&self) -> &'self T { get_ref(self) } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } @@ -307,7 +302,7 @@ pub fn map_vec( ts: &[T], op: &fn(&T) -> Result) -> Result<~[V],U> { let mut vs: ~[V] = vec::with_capacity(vec::len(ts)); - for vec::each(ts) |t| { + for ts.each |t| { match op(t) { Ok(copy v) => vs.push(v), Err(copy u) => return Err(u) diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs index 4714be9e3d520..9c1e566f218f6 100644 --- a/src/libcore/rt/context.rs +++ b/src/libcore/rt/context.rs @@ -207,4 +207,3 @@ pub fn mut_offset(ptr: *mut T, count: int) -> *mut T { use core::sys::size_of; (ptr as int + count * (size_of::() as int)) as *mut T } - diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs index 92e2ec51306e2..1d7ff17314901 100644 --- a/src/libcore/rt/env.rs +++ b/src/libcore/rt/env.rs @@ -31,8 +31,10 @@ pub struct Environment { argc: c_int, /// The argv value passed to main argv: **c_char, - /// Print GC debugging info - debug_mem: bool + /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) + debug_mem: bool, + /// Print GC debugging info (true if env var RUST_DEBUG_BORROW is set) + debug_borrow: bool, } /// Get the global environment settings diff --git a/src/libcore/rt/io/comm_adapters.rs b/src/libcore/rt/io/comm_adapters.rs index 1d6893b3ca616..7e891f1718e21 100644 --- a/src/libcore/rt/io/comm_adapters.rs +++ b/src/libcore/rt/io/comm_adapters.rs @@ -56,4 +56,3 @@ impl WriterChan { impl GenericChan<~[u8]> for WriterChan { fn send(&self, _x: ~[u8]) { fail!() } } - diff --git a/src/libcore/rt/io/util.rs b/src/libcore/rt/io/extensions.rs similarity index 99% rename from src/libcore/rt/io/util.rs rename to src/libcore/rt/io/extensions.rs index cff224a80bee2..bb025b0ccb6d5 100644 --- a/src/libcore/rt/io/util.rs +++ b/src/libcore/rt/io/extensions.rs @@ -11,7 +11,7 @@ //! Utility mixins that apply to all Readers and Writers // XXX: Not sure how this should be structured -// XXX: Iteration should probably be considered seperately +// XXX: Iteration should probably be considered separately pub trait ReaderUtil { diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs index e041183b58452..85dc180452ffc 100644 --- a/src/libcore/rt/io/file.rs +++ b/src/libcore/rt/io/file.rs @@ -9,13 +9,9 @@ // except according to those terms. use prelude::*; -use super::misc::PathLike; +use super::support::PathLike; use super::{Reader, Writer, Seek, Close}; -use super::{IoError, SeekStyle}; - -/// Open a file with the default FileMode and FileAccess -/// # XXX are there sane defaults here? -pub fn open_file(_path: &P) -> FileStream { fail!() } +use super::SeekStyle; /// # XXX /// * Ugh, this is ridiculous. What is the best way to represent these options? @@ -46,7 +42,7 @@ impl FileStream { pub fn open(_path: &P, _mode: FileMode, _access: FileAccess - ) -> Result { + ) -> Option { fail!() } } diff --git a/src/libcore/rt/io/mem.rs b/src/libcore/rt/io/mem.rs index 600968a3c7105..06e1466831df0 100644 --- a/src/libcore/rt/io/mem.rs +++ b/src/libcore/rt/io/mem.rs @@ -17,7 +17,7 @@ use prelude::*; use super::*; - +use cmp::min; /// Writes to an owned, growable byte vector pub struct MemWriter { @@ -29,13 +29,15 @@ impl MemWriter { } impl Writer for MemWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + self.buf.push_all(buf) + } fn flush(&mut self) { /* no-op */ } } impl Seek for MemWriter { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.buf.len() as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -77,13 +79,27 @@ impl MemReader { } impl Reader for MemReader { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option { + { if self.eof() { return None; } } + + 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); + assert!(input.len() == output.len()); + vec::bytes::copy_memory(output, input, write_len); + } + self.pos += write_len; + assert!(self.pos <= self.buf.len()); - fn eof(&mut self) -> bool { fail!() } + return Some(write_len); + } + + fn eof(&mut self) -> bool { self.pos == self.buf.len() } } impl Seek for MemReader { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.pos as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -163,4 +179,43 @@ impl<'self> Seek for BufReader<'self> { fn tell(&self) -> u64 { fail!() } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} \ No newline at end of file +} + +#[cfg(test)] +mod test { + use prelude::*; + use super::*; + + #[test] + fn test_mem_writer() { + let mut writer = MemWriter::new(); + assert!(writer.tell() == 0); + writer.write([0]); + assert!(writer.tell() == 1); + writer.write([1, 2, 3]); + writer.write([4, 5, 6, 7]); + assert!(writer.tell() == 8); + assert!(writer.inner() == ~[0, 1, 2, 3, 4, 5 , 6, 7]); + } + + #[test] + fn test_mem_reader() { + let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert!(reader.read(buf) == Some(0)); + assert!(reader.tell() == 0); + let mut buf = [0]; + assert!(reader.read(buf) == Some(1)); + assert!(reader.tell() == 1); + assert!(buf == [0]); + let mut buf = [0, ..4]; + assert!(reader.read(buf) == Some(4)); + assert!(reader.tell() == 5); + assert!(buf == [1, 2, 3, 4]); + assert!(reader.read(buf) == Some(3)); + assert!(buf.slice(0, 3) == [5, 6, 7]); + assert!(reader.eof()); + assert!(reader.read(buf) == None); + assert!(reader.eof()); + } +} diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index b035532144c44..fea32bc5b7509 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -11,7 +11,13 @@ /*! Synchronous I/O This module defines the Rust interface for synchronous I/O. -It supports file access, +It models byte-oriented input and output with the Reader and Writer traits. +Types that implement both `Reader` and `Writer` and called 'streams', +and automatically implement trait `Stream`. +Implementations are provided for common I/O streams like +file, TCP, UDP, Unix domain sockets. +Readers and Writers may be composed to add capabilities like string +parsing, encoding, and compression. This will likely live in core::io, not core::rt::io. @@ -27,44 +33,177 @@ Some examples of obvious things you might want to do * Read a complete file to a string, (converting newlines?) - let contents = open("message.txt").read_to_str(); // read_to_str?? + let contents = File::open("message.txt").read_to_str(); // read_to_str?? * Write a line to a file - let file = FileStream::open("message.txt", Create, Write); + let file = File::open("message.txt", Create, Write); file.write_line("hello, file!"); * Iterate over the lines of a file + do File::open("message.txt").each_line |line| { + println(line) + } + * Pull the lines of a file into a vector of strings + let lines = File::open("message.txt").line_iter().to_vec(); + +* Make an simple HTTP request + + let socket = TcpStream::open("localhost:8080"); + socket.write_line("GET / HTTP/1.0"); + socket.write_line(""); + let response = socket.read_to_end(); + * Connect based on URL? Requires thinking about where the URL type lives and how to make protocol handlers extensible, e.g. the "tcp" protocol yields a `TcpStream`. - connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /"); + connect("tcp://localhost:8080"); # Terms -* reader -* writer -* stream -* Blocking vs. non-blocking -* synchrony and asynchrony - -I tend to call this implementation non-blocking, because performing I/O -doesn't block the progress of other tasks. Is that how we want to present -it, 'synchronous but non-blocking'? +* Reader - An I/O source, reads bytes into a buffer +* Writer - An I/O sink, writes bytes from a buffer +* Stream - Typical I/O sources like files and sockets are both Readers and Writers, + and are collectively referred to a `streams`. +* Decorator - A Reader or Writer that composes with others to add additional capabilities + such as encoding or decoding + +# Blocking and synchrony + +When discussing I/O you often hear the terms 'synchronous' and +'asynchronous', along with 'blocking' and 'non-blocking' compared and +contrasted. A synchronous I/O interface performs each I/O operation to +completion before proceeding to the next. Synchronous interfaces are +usually used in imperative style as a sequence of commands. An +asynchronous interface allows multiple I/O requests to be issued +simultaneously, without waiting for each to complete before proceeding +to the next. + +Asynchronous interfaces are used to achieve 'non-blocking' I/O. In +traditional single-threaded systems, performing a synchronous I/O +operation means that the program stops all activity (it 'blocks') +until the I/O is complete. Blocking is bad for performance when +there are other computations that could be done. + +Asynchronous interfaces are most often associated with the callback +(continuation-passing) style popularised by node.js. Such systems rely +on all computations being run inside an event loop which maintains a +list of all pending I/O events; when one completes the registered +callback is run and the code that made the I/O request continiues. +Such interfaces achieve non-blocking at the expense of being more +difficult to reason about. + +Rust's I/O interface is synchronous - easy to read - and non-blocking by default. + +Remember that Rust tasks are 'green threads', lightweight threads that +are multiplexed onto a single operating system thread. If that system +thread blocks then no other task may proceed. Rust tasks are +relatively cheap to create, so as long as other tasks are free to +execute then non-blocking code may be written by simply creating a new +task. + +When discussing blocking in regards to Rust's I/O model, we are +concerned with whether performing I/O blocks other Rust tasks from +proceeding. In other words, when a task calls `read`, it must then +wait (or 'sleep', or 'block') until the call to `read` is complete. +During this time, other tasks may or may not be executed, depending on +how `read` is implemented. + + +Rust's default I/O implementation is non-blocking; by cooperating +directly with the task scheduler it arranges to never block progress +of *other* tasks. Under the hood, Rust uses asynchronous I/O via a +per-scheduler (and hence per-thread) event loop. Synchronous I/O +requests are implemented by descheduling the running task and +performing an asynchronous request; the task is only resumed once the +asynchronous request completes. + +For blocking (but possibly more efficient) implementations, look +in the `io::native` module. # Error Handling +I/O is an area where nearly every operation can result in unexpected +errors. It should allow errors to be handled efficiently. +It needs to be convenient to use I/O when you don't care +about dealing with specific errors. + +Rust's I/O employs a combination of techniques to reduce boilerplate +while still providing feedback about errors. The basic strategy: + +* Errors are fatal by default, resulting in task failure +* Errors raise the `io_error` conditon which provides an opportunity to inspect + an IoError object containing details. +* Return values must have a sensible null or zero value which is returned + if a condition is handled successfully. This may be an `Option`, an empty + vector, or other designated error value. +* Common traits are implemented for `Option`, e.g. `impl Reader for Option`, + so that nullable values do not have to be 'unwrapped' before use. + +These features combine in the API to allow for expressions like +`File::new("diary.txt").write_line("met a girl")` without having to +worry about whether "diary.txt" exists or whether the write +succeeds. As written, if either `new` or `write_line` encounters +an error the task will fail. + +If you wanted to handle the error though you might write + + let mut error = None; + do io_error::cond(|e: IoError| { + error = Some(e); + }).in { + File::new("diary.txt").write_line("met a girl"); + } + + if error.is_some() { + println("failed to write my diary"); + } + +XXX: Need better condition handling syntax + +In this case the condition handler will have the opportunity to +inspect the IoError raised by either the call to `new` or the call to +`write_line`, but then execution will continue. + +So what actually happens if `new` encounters an error? To understand +that it's important to know that what `new` returns is not a `File` +but an `Option`. If the file does not open, and the condition +is handled, then `new` will simply return `None`. Because there is an +implementation of `Writer` (the trait required ultimately required for +types to implement `write_line`) there is no need to inspect or unwrap +the `Option` and we simply call `write_line` on it. If `new` +returned a `None` then the followup call to `write_line` will also +raise an error. + +## Concerns about this strategy + +This structure will encourage a programming style that is prone +to errors similar to null pointer dereferences. +In particular code written to ignore errors and expect conditions to be unhandled +will start passing around null or zero objects when wrapped in a condition handler. + +* XXX: How should we use condition handlers that return values? + + +# Issues withi/o scheduler affinity, work stealing, task pinning + # Resource management * `close` vs. RAII -# Paths and URLs +# Paths, URLs and overloaded constructors + + + +# Scope -# std +In scope for core + +* Url? Some I/O things don't belong in core @@ -73,7 +212,12 @@ Some I/O things don't belong in core - http - flate -# XXX +Out of scope + +* Async I/O. We'll probably want it eventually + + +# XXX Questions and issues * Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose. Overloading would be nice. @@ -83,6 +227,7 @@ Some I/O things don't belong in core * fsync * relationship with filesystem querying, Directory, File types etc. * Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic? +* Can Port and Chan be implementations of a generic Reader/Writer? * Trait for things that are both readers and writers, Stream? * How to handle newline conversion * String conversion @@ -92,6 +237,7 @@ Some I/O things don't belong in core * Do we need `close` at all? dtors might be good enough * How does I/O relate to the Iterator trait? * std::base64 filters +* Using conditions is a big unknown since we don't have much experience with them */ @@ -104,46 +250,51 @@ pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; -pub use self::file::open_file; pub use self::file::FileStream; -pub use self::net::Listener; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; // Some extension traits that all Readers and Writers get. -pub use self::util::ReaderUtil; -pub use self::util::ReaderByteConversions; -pub use self::util::WriterByteConversions; +pub use self::extensions::ReaderUtil; +pub use self::extensions::ReaderByteConversions; +pub use self::extensions::WriterByteConversions; /// Synchronous, non-blocking file I/O. pub mod file; /// Synchronous, non-blocking network I/O. -#[path = "net/mod.rs"] -pub mod net; +pub mod net { + pub mod tcp; + pub mod udp; + pub mod ip; + #[cfg(unix)] + pub mod unix; + pub mod http; +} /// Readers and Writers for memory buffers and strings. -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; +/// Implementations for Option +#[cfg(not(stage0))] // Requires condition! fixes +mod option; + /// Basic stream compression. XXX: Belongs with other flate code -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod flate; /// Interop between byte streams and pipes. Not sure where it belongs -#[cfg(not(stage0))] // XXX " pub mod comm_adapters; /// Extension traits -mod util; +mod extensions; /// Non-I/O things needed by the I/O module -mod misc; +mod support; /// Thread-blocking implementations pub mod native { @@ -173,18 +324,21 @@ pub struct IoError { detail: Option<~str> } +#[deriving(Eq)] pub enum IoErrorKind { FileNotFound, FilePermission, ConnectionFailed, Closed, - OtherIoError + OtherIoError, + PreviousIoError } // XXX: Can't put doc comments on macros // Raised by `I/O` operations on error. condition! { - io_error: super::IoError -> (); + // FIXME (#6009): uncomment `pub` after expansion support lands. + /*pub*/ io_error: super::IoError -> (); } pub trait Reader { @@ -211,9 +365,9 @@ pub trait Reader { /// println(reader.read_line()); /// } /// - /// # XXX + /// # Failue /// - /// What does this return if the Reader is in an error state? + /// Returns `true` on failure. fn eof(&mut self) -> bool; } @@ -253,9 +407,30 @@ pub enum SeekStyle { /// * Are `u64` and `i64` the right choices? pub trait Seek { fn tell(&self) -> u64; + + /// Seek to an offset in a stream + /// + /// A successful seek clears the EOF indicator. + /// + /// # XXX + /// + /// * What is the behavior when seeking past the end of a stream? fn seek(&mut self, pos: i64, style: SeekStyle); } +/// A listener is a value that listens for connections +pub trait Listener { + /// Wait for and accept an incoming connection + /// + /// Returns `None` on timeout. + /// + /// # Failure + /// + /// Raises `io_error` condition. If the condition is handled, + /// then `accept` returns `None`. + fn accept(&mut self) -> Option; +} + /// Common trait for decorator types. /// /// Provides accessors to get the inner, 'decorated' values. The I/O library @@ -281,3 +456,16 @@ pub trait Decorator { /// Take a mutable reference to the decorated value fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T; } + +pub fn standard_error(kind: IoErrorKind) -> IoError { + match kind { + PreviousIoError => { + IoError { + kind: PreviousIoError, + desc: "Failing due to a previous I/O error", + detail: None + } + } + _ => fail!() + } +} diff --git a/src/libcore/rt/io/net/ip.rs b/src/libcore/rt/io/net/ip.rs index d9b7f4e6e4011..df1dfe4d38ad1 100644 --- a/src/libcore/rt/io/net/ip.rs +++ b/src/libcore/rt/io/net/ip.rs @@ -12,4 +12,3 @@ pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), Ipv6 } - diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs index e3f71dca8c827..c95b4344fe75d 100644 --- a/src/libcore/rt/io/net/tcp.rs +++ b/src/libcore/rt/io/net/tcp.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; pub struct TcpStream; impl TcpStream { - pub fn connect(_addr: IpAddr) -> Result { + pub fn connect(_addr: IpAddr) -> Option { fail!() } } @@ -40,7 +39,7 @@ impl Close for TcpStream { pub struct TcpListener; impl TcpListener { - pub fn new(_addr: IpAddr) -> TcpListener { + pub fn bind(_addr: IpAddr) -> Option { fail!() } } @@ -48,3 +47,28 @@ impl TcpListener { impl Listener for TcpListener { fn accept(&mut self) -> Option { fail!() } } + +#[cfg(test)] +mod test { + + #[test] #[ignore] + fn smoke_test() { + /*do run_in_newsched_task { + let addr = next_test_ip4(); + + do spawn_immediately { + let listener = TcpListener::bind(addr); + do listener.accept() { + let mut buf = [0]; + listener.read(buf); + assert!(buf[0] == 99); + } + } + + do spawn_immediately { + let stream = TcpStream::connect(addr); + stream.write([99]); + } + }*/ + } +} diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index f76bb58a45eb9..1f1254a7029f0 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; pub struct UdpStream; impl UdpStream { - pub fn connect(_addr: IpAddr) -> Result { + pub fn connect(_addr: IpAddr) -> Option { fail!() } } @@ -40,7 +39,7 @@ impl Close for UdpStream { pub struct UdpListener; impl UdpListener { - pub fn new(_addr: IpAddr) -> UdpListener { + pub fn bind(_addr: IpAddr) -> Option { fail!() } } @@ -48,4 +47,3 @@ impl UdpListener { impl Listener for UdpListener { fn accept(&mut self) -> Option { fail!() } } - diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index 35eabe21b2a6b..f449a857467cc 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; -use super::super::misc::PathLike; +use super::super::support::PathLike; pub struct UnixStream; impl UnixStream { - pub fn connect(_path: &P) -> Result { + pub fn connect(_path: &P) -> Option { fail!() } } @@ -40,7 +39,7 @@ impl Close for UnixStream { pub struct UnixListener; impl UnixListener { - pub fn new(_path: &P) -> UnixListener { + pub fn bind(_path: &P) -> Option { fail!() } } @@ -48,4 +47,3 @@ impl UnixListener { impl Listener for UnixListener { fn accept(&mut self) -> Option { fail!() } } - diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs new file mode 100644 index 0000000000000..95f8711cb5bd5 --- /dev/null +++ b/src/libcore/rt/io/option.rs @@ -0,0 +1,153 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementations of I/O traits for the Option type +//! +//! I/O constructors return option types to allow errors to be handled. +//! These implementations allow e.g. `Option` to be used +//! as a `Reader` without unwrapping the option first. +//! +//! # XXX Seek and Close + +use option::*; +use super::{Reader, Writer, Listener}; +use super::{standard_error, PreviousIoError, io_error, IoError}; + +fn prev_io_error() -> IoError { + standard_error(PreviousIoError) +} + +impl Writer for Option { + fn write(&mut self, buf: &[u8]) { + match *self { + Some(ref mut writer) => writer.write(buf), + None => io_error::cond.raise(prev_io_error()) + } + } + + fn flush(&mut self) { + match *self { + Some(ref mut writer) => writer.flush(), + None => io_error::cond.raise(prev_io_error()) + } + } +} + +impl Reader for Option { + fn read(&mut self, buf: &mut [u8]) -> Option { + match *self { + Some(ref mut reader) => reader.read(buf), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } + + fn eof(&mut self) -> bool { + match *self { + Some(ref mut reader) => reader.eof(), + None => { + io_error::cond.raise(prev_io_error()); + true + } + } + } +} + +impl, S> Listener for Option { + fn accept(&mut self) -> Option { + match *self { + Some(ref mut listener) => listener.accept(), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } +} + +#[cfg(test)] +mod test { + use option::*; + use super::super::mem::*; + use rt::test::*; + use super::super::{PreviousIoError, io_error}; + + #[test] + fn test_option_writer() { + do run_in_newsched_task { + let mut writer: Option = Some(MemWriter::new()); + writer.write([0, 1, 2]); + writer.flush(); + assert!(writer.unwrap().inner() == ~[0, 1, 2]); + } + } + + #[test] + fn test_option_writer_error() { + do run_in_newsched_task { + let mut writer: Option = None; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.write([0, 0, 0]); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.flush(); + } + assert!(called); + } + } + + #[test] + fn test_option_reader() { + do run_in_newsched_task { + let mut reader: Option = Some(MemReader::new(~[0, 1, 2, 3])); + let mut buf = [0, 0]; + reader.read(buf); + assert!(buf == [0, 1]); + assert!(!reader.eof()); + } + } + + #[test] + fn test_option_reader_error() { + let mut reader: Option = None; + let mut buf = []; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + reader.read(buf); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + assert!(reader.eof()); + } + assert!(called); + } +} diff --git a/src/libcore/rt/io/misc.rs b/src/libcore/rt/io/support.rs similarity index 100% rename from src/libcore/rt/io/misc.rs rename to src/libcore/rt/io/support.rs diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs new file mode 100644 index 0000000000000..6bf228a1b2201 --- /dev/null +++ b/src/libcore/rt/local_heap.rs @@ -0,0 +1,80 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The local, garbage collected heap + +use libc::{c_void, uintptr_t, size_t}; +use ops::Drop; + +type MemoryRegion = c_void; +type BoxedRegion = c_void; + +pub type OpaqueBox = c_void; +pub type TypeDesc = c_void; + +pub struct LocalHeap { + memory_region: *MemoryRegion, + boxed_region: *BoxedRegion +} + +impl LocalHeap { + pub fn new() -> LocalHeap { + unsafe { + // Don't need synchronization for the single-threaded local heap + let synchronized = false as uintptr_t; + // XXX: These usually come from the environment + let detailed_leaks = false as uintptr_t; + let poison_on_free = false as uintptr_t; + let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free); + assert!(region.is_not_null()); + let boxed = rust_new_boxed_region(region, poison_on_free); + assert!(boxed.is_not_null()); + LocalHeap { + memory_region: region, + boxed_region: boxed + } + } + } + + pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox { + unsafe { + return rust_boxed_region_malloc(self.boxed_region, td, size as size_t); + } + } + + pub fn free(&mut self, box: *OpaqueBox) { + unsafe { + return rust_boxed_region_free(self.boxed_region, box); + } + } +} + +impl Drop for LocalHeap { + fn finalize(&self) { + unsafe { + rust_delete_boxed_region(self.boxed_region); + rust_delete_memory_region(self.memory_region); + } + } +} + +extern { + fn rust_new_memory_region(synchronized: uintptr_t, + detailed_leaks: uintptr_t, + poison_on_free: uintptr_t) -> *MemoryRegion; + fn rust_delete_memory_region(region: *MemoryRegion); + fn rust_new_boxed_region(region: *MemoryRegion, + poison_on_free: uintptr_t) -> *BoxedRegion; + fn rust_delete_boxed_region(region: *BoxedRegion); + fn rust_boxed_region_malloc(region: *BoxedRegion, + td: *TypeDesc, + size: size_t) -> *OpaqueBox; + fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); +} diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs new file mode 100644 index 0000000000000..01bef5e245888 --- /dev/null +++ b/src/libcore/rt/local_services.rs @@ -0,0 +1,232 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Language-level runtime services that should reasonably expected +//! to be available 'everywhere'. Local heaps, GC, unwinding, +//! local storage, and logging. Even a 'freestanding' Rust would likely want +//! to implement this. + +//! Local services may exist in at least three different contexts: +//! when running as a task, when running in the scheduler's context, +//! or when running outside of a scheduler but with local services +//! (freestanding rust with local services?). + +use prelude::*; +use libc::{c_void, uintptr_t}; +use cast::transmute; +use super::sched::local_sched; +use super::local_heap::LocalHeap; + +pub struct LocalServices { + heap: LocalHeap, + gc: GarbageCollector, + storage: LocalStorage, + logger: Logger, + unwinder: Option, + destroyed: bool +} + +pub struct GarbageCollector; +pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); +pub struct Logger; + +pub struct Unwinder { + unwinding: bool, +} + +impl LocalServices { + pub fn new() -> LocalServices { + LocalServices { + heap: LocalHeap::new(), + gc: GarbageCollector, + storage: LocalStorage(ptr::null(), None), + logger: Logger, + unwinder: Some(Unwinder { unwinding: false }), + destroyed: false + } + } + + pub fn without_unwinding() -> LocalServices { + LocalServices { + heap: LocalHeap::new(), + gc: GarbageCollector, + storage: LocalStorage(ptr::null(), None), + logger: Logger, + unwinder: None, + destroyed: false + } + } + + pub fn run(&mut self, f: &fn()) { + // This is just an assertion that `run` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + + match self.unwinder { + Some(ref mut unwinder) => { + // If there's an unwinder then set up the catch block + unwinder.try(f); + } + None => { + // Otherwise, just run the body + f() + } + } + self.destroy(); + } + + /// Must be called manually before finalization to clean up + /// thread-local resources. Some of the routines here expect + /// LocalServices to be available recursively so this must be + /// called unsafely, without removing LocalServices from + /// thread-local-storage. + fn destroy(&mut self) { + // This is just an assertion that `destroy` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + match self.storage { + LocalStorage(ptr, Some(ref dtor)) => { + (*dtor)(ptr) + } + _ => () + } + self.destroyed = true; + } +} + +impl Drop for LocalServices { + fn finalize(&self) { assert!(self.destroyed) } +} + +// Just a sanity check to make sure we are catching a Rust-thrown exception +static UNWIND_TOKEN: uintptr_t = 839147; + +impl Unwinder { + pub fn try(&mut self, f: &fn()) { + use sys::Closure; + + unsafe { + let closure: Closure = transmute(f); + let code = transmute(closure.code); + let env = transmute(closure.env); + + let token = rust_try(try_fn, code, env); + assert!(token == 0 || token == UNWIND_TOKEN); + } + + extern fn try_fn(code: *c_void, env: *c_void) { + unsafe { + let closure: Closure = Closure { + code: transmute(code), + env: transmute(env), + }; + let closure: &fn() = transmute(closure); + closure(); + } + } + + extern { + #[rust_stack] + fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; + } + } + + pub fn begin_unwind(&mut self) -> ! { + self.unwinding = true; + unsafe { + rust_begin_unwind(UNWIND_TOKEN); + return transmute(()); + } + extern { + fn rust_begin_unwind(token: uintptr_t); + } + } +} + +/// Borrow a pointer to the installed local services. +/// Fails (likely aborting the process) if local services are not available. +pub fn borrow_local_services(f: &fn(&mut LocalServices)) { + do local_sched::borrow |sched| { + match sched.current_task { + Some(~ref mut task) => { + f(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } + } +} + +pub unsafe fn unsafe_borrow_local_services() -> &mut LocalServices { + use cast::transmute_mut_region; + + match local_sched::unsafe_borrow().current_task { + Some(~ref mut task) => { + transmute_mut_region(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } +} + +#[cfg(test)] +mod test { + use rt::test::*; + + #[test] + fn local_heap() { + do run_in_newsched_task() { + let a = @5; + let b = a; + assert!(*a == 5); + assert!(*b == 5); + } + } + + #[test] + fn tls() { + use local_data::*; + do run_in_newsched_task() { + unsafe { + fn key(_x: @~str) { } + local_data_set(key, @~"data"); + assert!(*local_data_get(key).get() == ~"data"); + fn key2(_x: @~str) { } + local_data_set(key2, @~"data"); + assert!(*local_data_get(key2).get() == ~"data"); + } + } + } + + #[test] + fn unwind() { + do run_in_newsched_task() { + let result = spawntask_try(||()); + assert!(result.is_ok()); + let result = spawntask_try(|| fail!()); + assert!(result.is_err()); + } + } + + #[test] + fn rng() { + do run_in_newsched_task() { + use rand::{rng, Rng}; + let mut r = rng(); + let _ = r.next(); + } + } +} diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index e93e0c6fc6cc9..fbbc82743407c 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -8,29 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! The Rust runtime, including the scheduler and I/O interface */ + #[doc(hidden)]; use libc::c_char; - -// Some basic logging -macro_rules! rtdebug_ ( - ($( $arg:expr),+) => ( { - dumb_println(fmt!( $($arg),+ )); - - fn dumb_println(s: &str) { - use io::WriterUtil; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - } - - } ) -) - -// An alternate version with no output, for turning off logging -macro_rules! rtdebug ( - ($( $arg:expr),+) => ( $(let _ = $arg)*; ) -) +use ptr::Ptr; #[path = "sched/mod.rs"] mod sched; @@ -48,52 +31,50 @@ mod stack; mod context; mod thread; pub mod env; +pub mod local_services; +mod local_heap; -#[cfg(stage0)] -pub fn start(main: *u8, _argc: int, _argv: *c_char, _crate_map: *u8) -> int { - use self::sched::{Scheduler, Task}; - use self::uvio::UvEventLoop; - - let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_); - let main_task = ~do Task::new(&mut sched.stack_pool) { - // XXX: Can't call a C function pointer from Rust yet - unsafe { rust_call_nullary_fn(main) }; - }; - sched.task_queue.push_back(main_task); - sched.run(); - return 0; - - extern { - fn rust_call_nullary_fn(f: *u8); - } -} +/// Tools for testing the runtime +#[cfg(test)] +pub mod test; -#[cfg(not(stage0))] pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { + use self::sched::{Scheduler, Task}; use self::uvio::UvEventLoop; + use sys::Closure; + use ptr; + use cast; let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_); + let main_task = ~do Task::new(&mut sched.stack_pool) { - // XXX: Can't call a C function pointer from Rust yet - unsafe { rust_call_nullary_fn(main) }; + + unsafe { + // `main` is an `fn() -> ()` that doesn't take an environment + // XXX: Could also call this as an `extern "Rust" fn` once they work + let main = Closure { + code: main as *(), + env: ptr::null(), + }; + let mainfn: &fn() = cast::transmute(main); + + mainfn(); + } }; + sched.task_queue.push_back(main_task); sched.run(); - return 0; - extern { - fn rust_call_nullary_fn(f: *u8); - } + return 0; } /// Possible contexts in which Rust code may be executing. /// Different runtime services are available depending on context. #[deriving(Eq)] pub enum RuntimeContext { - // Only default services, e.g. exchange heap + // Only the exchange heap is available GlobalContext, // The scheduler may be accessed SchedulerContext, @@ -160,24 +141,3 @@ fn test_context() { sched.run(); } } - -// For setting up tests of the new scheduler -#[cfg(test)] -pub fn run_in_newsched_task(f: ~fn()) { - use cell::Cell; - use unstable::run_in_bare_thread; - use self::sched::Task; - use self::uvio::UvEventLoop; - - let f = Cell(Cell(f)); - - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let f = f.take(); - let task = ~do Task::new(&mut sched.stack_pool) { - (f.take())(); - }; - sched.task_queue.push_back(task); - sched.run(); - } -} diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs index 66eb79ba6ae4e..fd64438c61b46 100644 --- a/src/libcore/rt/rtio.rs +++ b/src/libcore/rt/rtio.rs @@ -24,11 +24,6 @@ pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); /// The asynchronous I/O services. Not all event loops may provide one - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject>; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; } diff --git a/src/libcore/rt/sched/local_sched.rs b/src/libcore/rt/sched/local_sched.rs index 2d1e06163beb8..a7e02f30e0167 100644 --- a/src/libcore/rt/sched/local_sched.rs +++ b/src/libcore/rt/sched/local_sched.rs @@ -143,4 +143,3 @@ fn borrow_smoke_test() { } let _scheduler = take(); } - diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 28946281628b1..ba057254583b0 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -16,6 +16,7 @@ use super::work_queue::WorkQueue; use super::stack::{StackPool, StackSegment}; use super::rtio::{EventLoop, EventLoopObject}; use super::context::Context; +use super::local_services::LocalServices; use cell::Cell; #[cfg(test)] use super::uvio::UvEventLoop; @@ -38,7 +39,7 @@ pub struct Scheduler { /// Always valid when a task is executing, otherwise not priv saved_context: Context, /// The currently executing task - priv current_task: Option<~Task>, + current_task: Option<~Task>, /// An action performed after a context switch on behalf of the /// code running before the context switch priv cleanup_job: Option @@ -117,15 +118,15 @@ pub impl Scheduler { fn resume_task_from_queue(~self) -> bool { assert!(!self.in_task_context()); - let mut self = self; - match self.task_queue.pop_front() { + let mut this = self; + match this.task_queue.pop_front() { Some(task) => { - self.resume_task_immediately(task); + this.resume_task_immediately(task); return true; } None => { rtdebug!("no tasks in queue"); - local_sched::put(self); + local_sched::put(this); return false; } } @@ -136,7 +137,6 @@ pub impl Scheduler { /// Called by a running task to end execution, after which it will /// be recycled by the scheduler for reuse in a new task. fn terminate_current_task(~self) { - let mut self = self; assert!(self.in_task_context()); rtdebug!("ending running task"); @@ -148,11 +148,10 @@ pub impl Scheduler { } } - // Control never reaches here + abort!("control reached end of task"); } fn schedule_new_task(~self, task: ~Task) { - let mut self = self; assert!(self.in_task_context()); do self.switch_running_tasks_and_then(task) |last_task| { @@ -166,16 +165,16 @@ pub impl Scheduler { // Core scheduling ops fn resume_task_immediately(~self, task: ~Task) { - let mut self = self; - assert!(!self.in_task_context()); + let mut this = self; + assert!(!this.in_task_context()); rtdebug!("scheduling a task"); // Store the task in the scheduler so it can be grabbed later - self.current_task = Some(task); - self.enqueue_cleanup_job(DoNothing); + this.current_task = Some(task); + this.enqueue_cleanup_job(DoNothing); - local_sched::put(self); + local_sched::put(this); // Take pointers to both the task and scheduler's saved registers. unsafe { @@ -204,17 +203,17 @@ pub impl Scheduler { /// running task. It gets transmuted to the scheduler's lifetime /// and called while the task is blocked. fn deschedule_running_task_and_then(~self, f: &fn(~Task)) { - let mut self = self; - assert!(self.in_task_context()); + let mut this = self; + assert!(this.in_task_context()); rtdebug!("blocking task"); - let blocked_task = self.current_task.swap_unwrap(); + let blocked_task = this.current_task.swap_unwrap(); let f_fake_region = unsafe { transmute::<&fn(~Task), &fn(~Task)>(f) }; let f_opaque = ClosureConverter::from_fn(f_fake_region); - self.enqueue_cleanup_job(GiveTask(blocked_task, f_opaque)); + this.enqueue_cleanup_job(GiveTask(blocked_task, f_opaque)); - local_sched::put(self); + local_sched::put(this); let sched = unsafe { local_sched::unsafe_borrow() }; let (sched_context, last_task_context, _) = sched.get_contexts(); @@ -230,18 +229,18 @@ pub impl Scheduler { /// You would want to think hard about doing this, e.g. if there are /// pending I/O events it would be a bad idea. fn switch_running_tasks_and_then(~self, next_task: ~Task, f: &fn(~Task)) { - let mut self = self; - assert!(self.in_task_context()); + let mut this = self; + assert!(this.in_task_context()); rtdebug!("switching tasks"); - let old_running_task = self.current_task.swap_unwrap(); + let old_running_task = this.current_task.swap_unwrap(); let f_fake_region = unsafe { transmute::<&fn(~Task), &fn(~Task)>(f) }; let f_opaque = ClosureConverter::from_fn(f_fake_region); - self.enqueue_cleanup_job(GiveTask(old_running_task, f_opaque)); - self.current_task = Some(next_task); + this.enqueue_cleanup_job(GiveTask(old_running_task, f_opaque)); + this.current_task = Some(next_task); - local_sched::put(self); + local_sched::put(this); unsafe { let sched = local_sched::unsafe_borrow(); @@ -304,7 +303,7 @@ pub impl Scheduler { unsafe { let last_task = transmute::, Option<&mut Task>>(last_task); let last_task_context = match last_task { - Some(ref t) => Some(&mut t.saved_context), None => None + Some(t) => Some(&mut t.saved_context), None => None }; let next_task_context = match self.current_task { Some(ref mut t) => Some(&mut t.saved_context), None => None @@ -326,10 +325,18 @@ pub struct Task { /// These are always valid when the task is not running, unless /// the task is dead priv saved_context: Context, + /// The heap, GC, unwinding, local storage, logging + local_services: LocalServices } pub impl Task { fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task { + Task::with_local(stack_pool, LocalServices::new(), start) + } + + fn with_local(stack_pool: &mut StackPool, + local_services: LocalServices, + start: ~fn()) -> Task { let start = Task::build_start_wrapper(start); let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE); // NB: Context holds a pointer to that ~fn @@ -337,6 +344,7 @@ pub impl Task { return Task { current_stack_segment: stack, saved_context: initial_context, + local_services: local_services }; } @@ -349,9 +357,12 @@ pub impl Task { unsafe { let sched = local_sched::unsafe_borrow(); sched.run_cleanup_job(); - } - start(); + let sched = local_sched::unsafe_borrow(); + let task = sched.current_task.get_mut_ref(); + // FIXME #6141: shouldn't neet to put `start()` in another closure + task.local_services.run(||start()); + } let sched = local_sched::take(); sched.terminate_current_task(); diff --git a/src/libcore/rt/stack.rs b/src/libcore/rt/stack.rs index 9eca3bda0473c..3a4e9307d3b50 100644 --- a/src/libcore/rt/stack.rs +++ b/src/libcore/rt/stack.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use container::Container; +use ptr::Ptr; use vec; pub struct StackSegment { diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs new file mode 100644 index 0000000000000..0c6843c605d15 --- /dev/null +++ b/src/libcore/rt/test.rs @@ -0,0 +1,120 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::Cell; +use result::{Result, Ok, Err}; +use super::io::net::ip::{IpAddr, Ipv4}; +use rt::local_services::LocalServices; + +/// Creates a new scheduler in a new thread and runs a task in it, +/// then waits for the scheduler to exit. Failure of the task +/// will abort the process. +pub fn run_in_newsched_task(f: ~fn()) { + use unstable::run_in_bare_thread; + use super::sched::Task; + use super::uvio::UvEventLoop; + + let f = Cell(f); + + do run_in_bare_thread { + let mut sched = ~UvEventLoop::new_scheduler(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f.take()); + sched.task_queue.push_back(task); + sched.run(); + } +} + +/// Test tasks will abort on failure instead of unwinding +pub fn spawntask(f: ~fn()) { + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + let sched = local_sched::take(); + sched.schedule_new_task(task.take()); + } +} + +/// Create a new task and run it right now. Aborts on failure +pub fn spawntask_immediately(f: ~fn()) { + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(task.take()); + } + } +} + +/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed +pub fn spawntask_try(f: ~fn()) -> Result<(), ()> { + use cell::Cell; + use super::sched::*; + use task; + use unstable::finally::Finally; + + // Our status variables will be filled in from the scheduler context + let mut failed = false; + let failed_ptr: *mut bool = &mut failed; + + // Switch to the scheduler + let f = Cell(Cell(f)); + let sched = local_sched::take(); + do sched.deschedule_running_task_and_then() |old_task| { + let old_task = Cell(old_task); + let f = f.take(); + let mut sched = local_sched::take(); + let new_task = ~do Task::new(&mut sched.stack_pool) { + do (|| { + (f.take())() + }).finally { + // Check for failure then resume the parent task + unsafe { *failed_ptr = task::failing(); } + let sched = local_sched::take(); + do sched.switch_running_tasks_and_then(old_task.take()) |new_task| { + let new_task = Cell(new_task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(new_task.take()); + } + } + } + }; + + sched.resume_task_immediately(new_task); + } + + if !failed { Ok(()) } else { Err(()) } +} + +/// Get a port number, starting at 9600, for use in tests +pub fn next_test_port() -> u16 { + unsafe { + return rust_dbg_next_port() as u16; + } + extern { + fn rust_dbg_next_port() -> ::libc::uintptr_t; + } +} + +/// Get a unique localhost:port pair starting at 9600 +pub fn next_test_ip4() -> IpAddr { + Ipv4(127, 0, 0, 1, next_test_port()) +} diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs index cb7925abdcdf7..6499f0a3efdcf 100644 --- a/src/libcore/rt/uv/mod.rs +++ b/src/libcore/rt/uv/mod.rs @@ -34,11 +34,13 @@ via `close` and `delete` methods. */ +use container::Container; use option::*; use str::raw::from_c_str; use to_str::ToStr; use vec; use ptr; +use ptr::Ptr; use libc::{c_void, c_int, size_t, malloc, free}; use cast::transmute; use ptr::null; @@ -301,7 +303,8 @@ struct WatcherData { write_cb: Option, connect_cb: Option, close_cb: Option, - alloc_cb: Option + alloc_cb: Option, + buf: Option } pub fn install_watcher_data>(watcher: &mut W) { @@ -311,7 +314,8 @@ pub fn install_watcher_data>(watcher: &mut W) { write_cb: None, connect_cb: None, close_cb: None, - alloc_cb: None + alloc_cb: None, + buf: None }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(watcher.native_handle(), data); diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index bcfe8b2cfdf9f..3e6aa657c57dd 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -19,12 +19,10 @@ use super::{Loop, Watcher, Request, UvError, Buf, Callback, NativeHandle, NullCa vec_to_uv_buf, vec_from_uv_buf}; use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6}; -#[cfg(test)] -use unstable::run_in_bare_thread; -#[cfg(test)] -use super::super::thread::Thread; -#[cfg(test)] -use cell::Cell; +#[cfg(test)] use cell::Cell; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::super::thread::Thread; +#[cfg(test)] use super::super::test::*; fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in)) { match addr { @@ -109,21 +107,25 @@ pub impl StreamWatcher { let req = WriteRequest::new(); let buf = vec_to_uv_buf(msg); - // XXX: Allocation - let bufs = ~[buf]; + assert!(data.buf.is_none()); + data.buf = Some(buf); + let bufs = [buf]; unsafe { assert!(0 == uvll::write(req.native_handle(), self.native_handle(), - &bufs, write_cb)); + bufs, write_cb)); } - // XXX: Freeing immediately after write. Is this ok? - let _v = vec_from_uv_buf(buf); extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap(); + let cb = { + let data = get_watcher_data(&mut stream_watcher); + let _vec = vec_from_uv_buf(data.buf.swap_unwrap()); + let cb = data.write_cb.swap_unwrap(); + cb + }; let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -139,8 +141,8 @@ pub impl StreamWatcher { fn close(self, cb: NullCallback) { { - let mut self = self; - let data = get_watcher_data(&mut self); + let mut this = self; + let data = get_watcher_data(&mut this); assert!(data.close_cb.is_none()); data.close_cb = Some(cb); } @@ -150,8 +152,7 @@ pub impl StreamWatcher { extern fn close_cb(handle: *uvll::uv_stream_t) { let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); { - let mut data = get_watcher_data(&mut stream_watcher); - data.close_cb.swap_unwrap()(); + get_watcher_data(&mut stream_watcher).close_cb.swap_unwrap()(); } drop_watcher_data(&mut stream_watcher); unsafe { free_handle(handle as *c_void) } @@ -212,8 +213,7 @@ pub impl TcpWatcher { assert!(get_watcher_data(self).connect_cb.is_none()); get_watcher_data(self).connect_cb = Some(cb); - let mut connect_watcher = ConnectRequest::new(); - let connect_handle = connect_watcher.native_handle(); + let connect_handle = ConnectRequest::new().native_handle(); match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { @@ -361,7 +361,7 @@ fn connect_close() { let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; // Connect to a port where nobody is listening - let addr = Ipv4(127, 0, 0, 1, 2923); + let addr = next_test_ip4(); do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); @@ -373,47 +373,13 @@ fn connect_close() { } } -#[test] -#[ignore(reason = "need a server to connect to")] -fn connect_read() { - do run_in_bare_thread() { - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2924); - do tcp_watcher.connect(addr) |stream_watcher, status| { - let mut stream_watcher = stream_watcher; - rtdebug!("tcp_watcher.connect!"); - assert!(status.is_none()); - let alloc: AllocCallback = |size| { - vec_to_uv_buf(vec::from_elem(size, 0)) - }; - do stream_watcher.read_start(alloc) - |stream_watcher, _nread, buf, status| { - - let buf = vec_from_uv_buf(buf); - rtdebug!("read cb!"); - if status.is_none() { - let _bytes = buf.unwrap(); - rtdebug!("%s", bytes.slice(0, nread as uint).to_str()); - } else { - rtdebug!("status after read: %s", status.get().to_str()); - rtdebug!("closing"); - stream_watcher.close(||()); - } - } - } - loop_.run(); - loop_.close(); - } -} - #[test] fn listen() { do run_in_bare_thread() { static MAX: int = 10; let mut loop_ = Loop::new(); let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2925); + let addr = next_test_ip4(); server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); @@ -422,7 +388,7 @@ fn listen() { assert!(status.is_none()); let mut server_stream_watcher = server_stream_watcher; let mut loop_ = loop_; - let mut client_tcp_watcher = TcpWatcher::new(&mut loop_); + let client_tcp_watcher = TcpWatcher::new(&mut loop_); let mut client_tcp_watcher = client_tcp_watcher.as_stream(); server_stream_watcher.accept(client_tcp_watcher); let count_cell = Cell(0); diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index abdd8d6619a8a..24bffd8d1cd24 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -15,14 +15,15 @@ use super::io::net::ip::IpAddr; use super::uv::*; use super::rtio::*; use ops::Drop; +use old_iter::CopyableIter; use cell::{Cell, empty_cell}; use cast::transmute; use super::sched::{Scheduler, local_sched}; -#[cfg(test)] use super::io::net::ip::Ipv4; -#[cfg(test)] use super::sched::Task; -#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use container::Container; #[cfg(test)] use uint; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::test::*; pub struct UvEventLoop { uvio: UvIoFactory @@ -44,11 +45,10 @@ pub impl UvEventLoop { impl Drop for UvEventLoop { fn finalize(&self) { // XXX: Need mutable finalizer - let self = unsafe { + let this = unsafe { transmute::<&UvEventLoop, &mut UvEventLoop>(self) }; - let mut uv_loop = self.uvio.uv_loop(); - uv_loop.close(); + this.uvio.uv_loop().close(); } } @@ -69,14 +69,6 @@ impl EventLoop for UvEventLoop { } } - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject> { - Some(&mut self.uvio) - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { Some(&mut self.uvio) } @@ -99,14 +91,6 @@ fn test_callback_run_once() { pub struct UvIoFactory(Loop); pub impl UvIoFactory { - #[cfg(stage0)] - fn uv_loop(&mut self) -> &'self mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { match self { &UvIoFactory(ref mut ptr) => ptr } } @@ -206,9 +190,8 @@ impl TcpListener for UvTcpListener { let maybe_stream = if status.is_none() { let mut server_stream_watcher = server_stream_watcher; let mut loop_ = loop_from_watcher(&server_stream_watcher); - let mut client_tcp_watcher = TcpWatcher::new(&mut loop_); - let client_tcp_watcher = client_tcp_watcher.as_stream(); - // XXX: Need's to be surfaced in interface + let client_tcp_watcher = TcpWatcher::new(&mut loop_).as_stream(); + // XXX: Needs to be surfaced in interface server_stream_watcher.accept(client_tcp_watcher); Some(~UvStream::new(client_tcp_watcher)) } else { @@ -335,38 +318,22 @@ impl Stream for UvStream { } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_io_no_connect() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = Ipv4(127, 0, 0, 1, 2926); - let maybe_chan = io.connect(addr); - assert!(maybe_chan.is_none()); - }; - sched.task_queue.push_back(task); - sched.run(); + do run_in_newsched_task { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let addr = next_test_ip4(); + let maybe_chan = io.connect(addr); + assert!(maybe_chan.is_none()); } } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_tcp_server_and_client() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2929); - - let client_task = ~do Task::new(&mut sched.stack_pool) { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - } - }; + do run_in_newsched_task { + let addr = next_test_ip4(); - let server_task = ~do Task::new(&mut sched.stack_pool) { + // Start the server first so it's listening when we connect + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); @@ -381,32 +348,25 @@ fn test_simple_tcp_server_and_client() { stream.close(); listener.close(); } - }; + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); + do spawntask_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } + } } } #[test] #[ignore(reason = "busted")] fn test_read_and_block() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2930); + do run_in_newsched_task { + let addr = next_test_ip4(); - let client_task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - }; - - let server_task = ~do Task::new(&mut sched.stack_pool) { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); @@ -442,36 +402,58 @@ fn test_read_and_block() { stream.close(); listener.close(); - }; + } + + do spawntask_immediately { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); } } -#[test] #[ignore(reason = "needs server")] +#[test] fn test_read_read_read() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2931); + do run_in_newsched_task { + let addr = next_test_ip4(); + static MAX: uint = 500000; + + do spawntask_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut listener = io.bind(addr).unwrap(); + let mut stream = listener.listen().unwrap(); + let buf = [1, .. 2048]; + let mut total_bytes_written = 0; + while total_bytes_written < MAX { + stream.write(buf); + total_bytes_written += buf.len(); + } + stream.close(); + listener.close(); + } + } - let client_task = ~do Task::new(&mut sched.stack_pool) { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; - while total_bytes_read < 500000000 { + while total_bytes_read < MAX { let nread = stream.read(buf).unwrap(); rtdebug!("read %u bytes", nread as uint); total_bytes_read += nread; + for uint::range(0, nread) |i| { + assert!(buf[i] == 1); + } } - rtdebug_!("read %u bytes total", total_bytes_read as uint); + rtdebug!("read %u bytes total", total_bytes_read as uint); stream.close(); - }; - - sched.task_queue.push_back(client_task); - sched.run(); + } } } diff --git a/src/libcore/rt/uvll.rs b/src/libcore/rt/uvll.rs index c9a696fcd15ca..4bff3bff7d3ae 100644 --- a/src/libcore/rt/uvll.rs +++ b/src/libcore/rt/uvll.rs @@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { return rust_uv_accept(server as *c_void, client as *c_void); } -pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(*buf_in); - let buf_cnt = vec::len(*buf_in) as i32; +pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = vec::len(buf_in) as i32; return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); } pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { @@ -393,24 +393,26 @@ extern { // FIXME ref #2064 fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, - ++after_cb: *u8, - ++addr: *sockaddr_in) -> c_int; + after_cb: *u8, + addr: *sockaddr_in) -> c_int; // FIXME ref #2064 - fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, ++addr: *sockaddr_in) -> c_int; + fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; // FIXME ref #2064 fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, - ++after_cb: *u8, - ++addr: *sockaddr_in6) -> c_int; + after_cb: *u8, + addr: *sockaddr_in6) -> c_int; // FIXME ref #2064 - fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, ++addr: *sockaddr_in6) -> c_int; - fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, ++name: *sockaddr_in) -> c_int; - fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, ++name: *sockaddr_in6) ->c_int; + fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int; + fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, + name: *sockaddr_in) -> c_int; + fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, + name: *sockaddr_in6) ->c_int; fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; fn rust_uv_write(req: *c_void, stream: *c_void, - ++buf_in: *uv_buf_t, + buf_in: *uv_buf_t, buf_cnt: c_int, cb: *u8) -> c_int; fn rust_uv_read_start(stream: *c_void, @@ -426,7 +428,7 @@ extern { fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; - fn rust_uv_free_base_of_buf(++buf: uv_buf_t); + fn rust_uv_free_base_of_buf(buf: uv_buf_t); fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; @@ -436,6 +438,6 @@ extern { fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void); fn rust_uv_get_data_for_req(req: *c_void) -> *c_void; fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); - fn rust_uv_get_base_from_buf(++buf: uv_buf_t) -> *u8; - fn rust_uv_get_len_from_buf(++buf: uv_buf_t) -> size_t; + fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; + fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; } diff --git a/src/libcore/rt/work_queue.rs b/src/libcore/rt/work_queue.rs index dfa88b783c59f..495cd75a0bf8e 100644 --- a/src/libcore/rt/work_queue.rs +++ b/src/libcore/rt/work_queue.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use container::Container; use option::*; +use vec::OwnedVector; pub struct WorkQueue { priv queue: ~[T] diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 37401788ca2d1..c865e77cc6b78 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -22,31 +22,6 @@ use str; use task; use vec; -pub mod rustrt { - use libc::{c_int, c_void}; - use libc; - use run; - - #[abi = "cdecl"] - pub extern { - unsafe fn rust_run_program(argv: **libc::c_char, - envp: *c_void, - dir: *libc::c_char, - in_fd: c_int, - out_fd: c_int, - err_fd: c_int) -> run::RunProgramResult; - unsafe fn rust_process_wait(pid: c_int) -> c_int; - } -} - -pub struct RunProgramResult { - // the process id of the program, or -1 if in case of errors - pid: pid_t, - // a handle to the process - on unix this will always be NULL, but on windows it will be a - // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. - handle: *(), -} - /// A value representing a child process pub struct Program { priv pid: pid_t, @@ -191,26 +166,267 @@ pub fn spawn_process(prog: &str, args: &[~str], return res.pid; } +struct RunProgramResult { + // the process id of the program (this should never be negative) + pid: pid_t, + // a handle to the process - on unix this will always be NULL, but on windows it will be a + // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. + handle: *(), +} + +#[cfg(windows)] fn spawn_process_internal(prog: &str, args: &[~str], env: &Option<~[(~str,~str)]>, dir: &Option<~str>, in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessA + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + unsafe { - do with_argv(prog, args) |argv| { - do with_envp(env) |envp| { - do with_dirp(dir) |dirp| { - rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd) + + let mut si = zeroed_startupinfo(); + si.cb = sys::size_of::() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE; + if orig_std_in == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE; + if orig_std_out == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE; + if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let cmd = make_command_line(prog, args); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + do with_envp(env) |envp| { + do with_dirp(dir) |dirp| { + do str::as_c_str(cmd) |cmdp| { + let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), + ptr::mut_null(), ptr::mut_null(), TRUE, + 0, envp, dirp, &mut si, &mut pi); + if created == FALSE { + create_err = Some(os::last_os_error()); + } } } } + + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + for create_err.each |msg| { + fail!(fmt!("failure in CreateProcess: %s", *msg)); + } + + // We close the thread handle because we don't care about keeping the thread id valid, + // and we aren't keeping the thread handle around to be able to close it later. We don't + // close the process handle however because we want the process id to stay valid at least + // until the calling code closes the process handle. + CloseHandle(pi.hThread); + + RunProgramResult { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *() + } + } +} + +#[cfg(windows)] +fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { + libc::types::os::arch::extra::STARTUPINFO { + cb: 0, + lpReserved: ptr::mut_null(), + lpDesktop: ptr::mut_null(), + lpTitle: ptr::mut_null(), + dwX: 0, + dwY: 0, + dwXSize: 0, + dwYSize: 0, + dwXCountChars: 0, + dwYCountCharts: 0, + dwFillAttribute: 0, + dwFlags: 0, + wShowWindow: 0, + cbReserved2: 0, + lpReserved2: ptr::mut_null(), + hStdInput: ptr::mut_null(), + hStdOutput: ptr::mut_null(), + hStdError: ptr::mut_null() + } +} + +#[cfg(windows)] +fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { + libc::types::os::arch::extra::PROCESS_INFORMATION { + hProcess: ptr::mut_null(), + hThread: ptr::mut_null(), + dwProcessId: 0, + dwThreadId: 0 + } +} + +// FIXME: this is only pub so it can be tested (see issue #4536) +#[cfg(windows)] +pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { + + let mut cmd = ~""; + append_arg(&mut cmd, prog); + for args.each |arg| { + cmd.push_char(' '); + append_arg(&mut cmd, *arg); + } + return cmd; + + fn append_arg(cmd: &mut ~str, arg: &str) { + let quote = arg.any(|c| c == ' ' || c == '\t'); + if quote { + cmd.push_char('"'); + } + for uint::range(0, arg.len()) |i| { + append_char_at(cmd, arg, i); + } + if quote { + cmd.push_char('"'); + } + } + + fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) { + match arg[i] as char { + '"' => { + // Escape quotes. + cmd.push_str("\\\""); + } + '\\' => { + if backslash_run_ends_in_quote(arg, i) { + // Double all backslashes that are in runs before quotes. + cmd.push_str("\\\\"); + } else { + // Pass other backslashes through unescaped. + cmd.push_char('\\'); + } + } + c => { + cmd.push_char(c); + } + } + } + + fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool { + while i < s.len() && s[i] as char == '\\' { + i += 1; + } + return i < s.len() && s[i] as char == '"'; } } +#[cfg(unix)] +fn spawn_process_internal(prog: &str, args: &[~str], + env: &Option<~[(~str,~str)]>, + dir: &Option<~str>, + in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; + use libc::funcs::bsd44::getdtablesize; + + mod rustrt { + use libc::c_void; + + #[abi = "cdecl"] + pub extern { + unsafe fn rust_unset_sigprocmask(); + unsafe fn rust_set_environ(envp: *c_void); + } + } + + unsafe { + + let pid = fork(); + if pid < 0 { + fail!(fmt!("failure in fork: %s", os::last_os_error())); + } else if pid > 0 { + return RunProgramResult {pid: pid, handle: ptr::null()}; + } + + rustrt::rust_unset_sigprocmask(); + + if in_fd > 0 && dup2(in_fd, 0) == -1 { + fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error())); + } + if out_fd > 0 && dup2(out_fd, 1) == -1 { + fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error())); + } + if err_fd > 0 && dup2(err_fd, 2) == -1 { + fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error())); + } + // close all other fds + for int::range_rev(getdtablesize() as int - 1, 2) |fd| { + close(fd as c_int); + } + + for dir.each |dir| { + do str::as_c_str(*dir) |dirp| { + if chdir(dirp) == -1 { + fail!(fmt!("failure in chdir: %s", os::last_os_error())); + } + } + } + + do with_envp(env) |envp| { + if !envp.is_null() { + rustrt::rust_set_environ(envp); + } + do with_argv(prog, args) |argv| { + execvp(*argv, argv); + // execvp only returns if an error occurred + fail!(fmt!("failure in execvp: %s", os::last_os_error())); + } + } + } +} + +#[cfg(unix)] fn with_argv(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T { let mut argptrs = str::as_c_str(prog, |b| ~[b]); let mut tmps = ~[]; - for vec::each(args) |arg| { + for args.each |arg| { let t = @copy *arg; tmps.push(t); argptrs.push_all(str::as_c_str(*t, |b| ~[b])); @@ -229,7 +445,7 @@ fn with_envp(env: &Option<~[(~str,~str)]>, let mut tmps = ~[]; let mut ptrs = ~[]; - for vec::each(*es) |e| { + for (*es).each |e| { let (k,v) = copy *e; let t = @(fmt!("%s=%s", k, v)); tmps.push(t); @@ -246,7 +462,7 @@ fn with_envp(env: &Option<~[(~str,~str)]>, #[cfg(windows)] fn with_envp(env: &Option<~[(~str,~str)]>, - cb: &fn(*c_void) -> T) -> T { + cb: &fn(*mut c_void) -> T) -> T { // On win32 we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. @@ -254,7 +470,7 @@ fn with_envp(env: &Option<~[(~str,~str)]>, match *env { Some(ref es) if !vec::is_empty(*es) => { let mut blk : ~[u8] = ~[]; - for vec::each(*es) |e| { + for (*es).each |e| { let (k,v) = copy *e; let t = fmt!("%s=%s", k, v); let mut v : ~[u8] = ::cast::transmute(t); @@ -264,11 +480,12 @@ fn with_envp(env: &Option<~[(~str,~str)]>, blk += ~[0_u8]; vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p))) } - _ => cb(ptr::null()) + _ => cb(ptr::mut_null()) } } } +#[cfg(windows)] fn with_dirp(d: &Option<~str>, cb: &fn(*libc::c_char) -> T) -> T { match *d { @@ -312,8 +529,6 @@ priv fn free_handle(_handle: *()) { pub fn run_program(prog: &str, args: &[~str]) -> int { let res = spawn_process_internal(prog, args, &None, &None, 0i32, 0i32, 0i32); - if res.pid == -1 as pid_t { fail!(); } - let code = waitpid(res.pid); free_handle(res.handle); return code; @@ -345,7 +560,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program { pipe_err.out); unsafe { - if res.pid == -1 as pid_t { fail!(); } libc::close(pipe_input.in); libc::close(pipe_output.out); libc::close(pipe_err.out); @@ -398,13 +612,6 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput { os::close(pipe_in.in); os::close(pipe_out.out); os::close(pipe_err.out); - if res.pid == -1i32 { - os::close(pipe_in.out); - os::close(pipe_out.in); - os::close(pipe_err.in); - fail!(); - } - os::close(pipe_in.out); // Spawn two entire schedulers to read both stdout and sterr @@ -485,11 +692,46 @@ pub fn waitpid(pid: pid_t) -> int { #[cfg(windows)] fn waitpid_os(pid: pid_t) -> int { - let status = unsafe { rustrt::rust_process_wait(pid) }; - if status < 0 { - fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error())); + + use libc::types::os::arch::extra::DWORD; + use libc::consts::os::extra::{ + SYNCHRONIZE, + PROCESS_QUERY_INFORMATION, + FALSE, + STILL_ACTIVE, + INFINITE, + WAIT_FAILED + }; + use libc::funcs::extra::kernel32::{ + OpenProcess, + GetExitCodeProcess, + CloseHandle, + WaitForSingleObject + }; + + unsafe { + + let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + fail!(fmt!("failure in OpenProcess: %s", os::last_os_error())); + } + + loop { + let mut status = 0; + if GetExitCodeProcess(proc, &mut status) == FALSE { + CloseHandle(proc); + fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error())); + } + if status != STILL_ACTIVE { + CloseHandle(proc); + return status as int; + } + if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED { + CloseHandle(proc); + fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error())); + } + } } - return status as int; } #[cfg(unix)] @@ -536,13 +778,32 @@ pub fn waitpid(pid: pid_t) -> int { #[cfg(test)] mod tests { - use libc; use option::None; use os; - use path::Path; use run::{readclose, writeclose}; use run; + #[test] + #[cfg(windows)] + fn test_make_command_line() { + assert_eq!( + run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]), + ~"prog aaa bbb ccc" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]), + ~"\"C:\\Program Files\\blah\\blah.exe\" aaa" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]), + ~"\"C:\\Program Files\\test\" aa\\\"bb" + ); + assert_eq!( + run::make_command_line("echo", [~"a b c"]), + ~"echo \"a b c\"" + ); + } + // Regression test for memory leaks #[test] fn test_leaks() { @@ -593,57 +854,4 @@ mod tests { fn waitpid_non_existant_pid() { run::waitpid(123456789); // assume that this pid doesn't exist } - - #[test] - fn test_destroy_once() { - let mut p = run::start_program("echo", []); - p.destroy(); // this shouldn't crash (and nor should the destructor) - } - - #[test] - fn test_destroy_twice() { - let mut p = run::start_program("echo", []); - p.destroy(); // this shouldnt crash... - p.destroy(); // ...and nor should this (and nor should the destructor) - } - - #[cfg(unix)] // there is no way to sleep on windows from inside libcore... - fn test_destroy_actually_kills(force: bool) { - let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force)); - - os::remove_file(&path); - - let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str()); - let mut p = run::start_program("sh", [~"-c", cmd]); - - p.destroy(); // destroy the program before it has a chance to echo its message - - unsafe { - // wait to ensure the program is really destroyed and not just waiting itself - libc::sleep(10); - } - - // the program should not have had chance to echo its message - assert!(!path.exists()); - } - - #[test] - #[cfg(unix)] - fn test_unforced_destroy_actually_kills() { - test_destroy_actually_kills(false); - } - - #[test] - #[cfg(unix)] - fn test_forced_destroy_actually_kills() { - test_destroy_actually_kills(true); - } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs index ebf36e4e09ab4..e86416f249902 100644 --- a/src/libcore/stackwalk.rs +++ b/src/libcore/stackwalk.rs @@ -24,6 +24,7 @@ pub fn Frame(fp: *Word) -> Frame { } } +#[cfg(stage0)] pub fn walk_stack(visit: &fn(Frame) -> bool) { debug!("beginning stack walk"); @@ -51,6 +52,35 @@ pub fn walk_stack(visit: &fn(Frame) -> bool) { } } } +#[cfg(not(stage0))] +pub fn walk_stack(visit: &fn(Frame) -> bool) -> bool { + + debug!("beginning stack walk"); + + do frame_address |frame_pointer| { + let mut frame_address: *Word = unsafe { + transmute(frame_pointer) + }; + loop { + let fr = Frame(frame_address); + + debug!("frame: %x", unsafe { transmute(fr.fp) }); + visit(fr); + + unsafe { + let next_fp: **Word = transmute(frame_address); + frame_address = *next_fp; + if *frame_address == 0u { + debug!("encountered task_start_wrapper. ending walk"); + // This is the task_start_wrapper_frame. There is + // no stack beneath it and it is a foreign frame. + break; + } + } + } + } + return true; +} #[test] fn test_simple() { @@ -64,7 +94,7 @@ fn test_simple_deep() { if i == 0 { return } for walk_stack |_frame| { - breakpoint(); + // Would be nice to test something here... } run(i - 1); } @@ -72,31 +102,15 @@ fn test_simple_deep() { run(10); } -fn breakpoint() { - unsafe { - rustrt::rust_dbg_breakpoint() - } -} - fn frame_address(f: &fn(x: *u8)) { unsafe { rusti::frame_address(f) } } -pub mod rustrt { - pub extern { - pub unsafe fn rust_dbg_breakpoint(); - } -} - pub mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { - #[cfg(stage0)] pub fn frame_address(f: &once fn(x: *u8)); - #[cfg(not(stage0))] - pub fn frame_address(+f: &once fn(x: *u8)); } } - diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 064bffa00561f..d31152e1e1c66 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -23,16 +23,21 @@ use cast; use char; use clone::Clone; use cmp::{TotalOrd, Ordering, Less, Equal, Greater}; +use container::Container; +use iter::Times; +use iterator::Iterator; use libc; use option::{None, Option, Some}; -use iterator::Iterator; +use old_iter::{BaseIter, EqIter}; use ptr; +use ptr::Ptr; use str; +use to_str::ToStr; use uint; use vec; -use to_str::ToStr; +use vec::{OwnedVector, OwnedCopyableVector}; -#[cfg(notest)] use cmp::{Eq, Ord, Equiv, TotalEq}; +#[cfg(not(test))] use cmp::{Eq, Ord, Equiv, TotalEq}; /* Section: Creating a string @@ -77,21 +82,22 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { } /// Copy a slice into a new unique str -pub fn from_slice(s: &str) -> ~str { +#[inline(always)] +pub fn to_owned(s: &str) -> ~str { unsafe { raw::slice_bytes_owned(s, 0, len(s)) } } impl ToStr for ~str { #[inline(always)] - fn to_str(&self) -> ~str { from_slice(*self) } + fn to_str(&self) -> ~str { to_owned(*self) } } impl<'self> ToStr for &'self str { #[inline(always)] - fn to_str(&self) -> ~str { from_slice(*self) } + fn to_str(&self) -> ~str { to_owned(*self) } } impl ToStr for @str { #[inline(always)] - fn to_str(&self) -> ~str { from_slice(*self) } + fn to_str(&self) -> ~str { to_owned(*self) } } /** @@ -188,7 +194,7 @@ pub fn from_char(ch: char) -> ~str { pub fn from_chars(chs: &[char]) -> ~str { let mut buf = ~""; reserve(&mut buf, chs.len()); - for vec::each(chs) |ch| { + for chs.each |ch| { push_char(&mut buf, *ch); } buf @@ -240,38 +246,132 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str { /// Concatenate a vector of strings pub fn concat(v: &[~str]) -> ~str { - let mut s: ~str = ~""; - for vec::each(v) |ss| { - push_str(&mut s, *ss); + if v.is_empty() { return ~""; } + + let mut len = 0; + for v.each |ss| { + len += ss.len(); + } + let mut s = ~""; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect(v: &[~str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return concat(v); } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect_slices(v: &[&str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else if seplen > 0 { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Given a string, make a new string with repeated copies of it pub fn repeat(ss: &str, nn: uint) -> ~str { - let mut acc = ~""; - for nn.times { acc += ss; } - acc + do as_buf(ss) |buf, len| { + let mut ret = ~""; + // ignore the NULL terminator + let len = len - 1; + reserve(&mut ret, nn * len); + + unsafe { + do as_buf(ret) |rbuf, _len| { + let mut rbuf = ::cast::transmute_mut_unsafe(rbuf); + + for nn.times { + ptr::copy_memory(rbuf, buf, len); + rbuf = rbuf.offset(len); + } + } + raw::set_len(&mut ret, nn * len); + } + ret + } } /* @@ -416,7 +516,7 @@ Section: Transforming strings */ pub fn to_bytes(s: &str) -> ~[u8] { unsafe { - let mut v: ~[u8] = ::cast::transmute(from_slice(s)); + let mut v: ~[u8] = ::cast::transmute(to_owned(s)); vec::raw::set_len(&mut v, len(s)); v } @@ -471,14 +571,30 @@ pub fn slice<'a>(s: &'a str, begin: uint, end: uint) -> &'a str { } /// Splits a string into substrings at each occurrence of a given character +#[cfg(stage0)] pub fn each_split_char<'a>(s: &'a str, sep: char, it: &fn(&'a str) -> bool) { + each_split_char_inner(s, sep, len(s), true, true, it); +} + +/// Splits a string into substrings at each occurrence of a given character +#[cfg(not(stage0))] +pub fn each_split_char<'a>(s: &'a str, sep: char, + it: &fn(&'a str) -> bool) -> bool { each_split_char_inner(s, sep, len(s), true, true, it) } /// Like `each_split_char`, but a trailing empty string is omitted +#[cfg(stage0)] pub fn each_split_char_no_trailing<'a>(s: &'a str, sep: char, it: &fn(&'a str) -> bool) { + each_split_char_inner(s, sep, len(s), true, false, it); +} +/// Like `each_split_char`, but a trailing empty string is omitted +#[cfg(not(stage0))] +pub fn each_split_char_no_trailing<'a>(s: &'a str, + sep: char, + it: &fn(&'a str) -> bool) -> bool { each_split_char_inner(s, sep, len(s), true, false, it) } @@ -488,17 +604,39 @@ pub fn each_split_char_no_trailing<'a>(s: &'a str, * * The character must be a valid UTF-8/ASCII character */ +#[cfg(stage0)] pub fn each_splitn_char<'a>(s: &'a str, sep: char, count: uint, it: &fn(&'a str) -> bool) { + each_split_char_inner(s, sep, count, true, true, it); +} +/** + * Splits a string into substrings at each occurrence of a given + * character up to 'count' times. + * + * The character must be a valid UTF-8/ASCII character + */ +#[cfg(not(stage0))] +pub fn each_splitn_char<'a>(s: &'a str, + sep: char, + count: uint, + it: &fn(&'a str) -> bool) -> bool { each_split_char_inner(s, sep, count, true, true, it) } /// Like `each_split_char`, but omits empty strings +#[cfg(stage0)] pub fn each_split_char_nonempty<'a>(s: &'a str, sep: char, it: &fn(&'a str) -> bool) { + each_split_char_inner(s, sep, len(s), false, false, it); +} +/// Like `each_split_char`, but omits empty strings +#[cfg(not(stage0))] +pub fn each_split_char_nonempty<'a>(s: &'a str, + sep: char, + it: &fn(&'a str) -> bool) -> bool { each_split_char_inner(s, sep, len(s), false, false, it) } @@ -507,7 +645,7 @@ fn each_split_char_inner<'a>(s: &'a str, count: uint, allow_empty: bool, allow_trailing_empty: bool, - it: &fn(&'a str) -> bool) { + it: &fn(&'a str) -> bool) -> bool { if sep < 128u as char { let b = sep as u8, l = len(s); let mut done = 0u; @@ -515,7 +653,9 @@ fn each_split_char_inner<'a>(s: &'a str, while i < l && done < count { if s[i] == b { if allow_empty || start < i { - if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { return; } + if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { + return false; + } } start = i + 1u; done += 1u; @@ -524,24 +664,41 @@ fn each_split_char_inner<'a>(s: &'a str, } // only slice a non-empty trailing substring if allow_trailing_empty || start < l { - if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return; } + if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return false; } } - } else { - each_split_inner(s, |cur| cur == sep, count, allow_empty, allow_trailing_empty, it) + return true; } + return each_split_inner(s, |cur| cur == sep, count, + allow_empty, allow_trailing_empty, it) } /// Splits a string into substrings using a character function +#[cfg(stage0)] pub fn each_split<'a>(s: &'a str, sepfn: &fn(char) -> bool, it: &fn(&'a str) -> bool) { + each_split_inner(s, sepfn, len(s), true, true, it); +} +/// Splits a string into substrings using a character function +#[cfg(not(stage0))] +pub fn each_split<'a>(s: &'a str, + sepfn: &fn(char) -> bool, + it: &fn(&'a str) -> bool) -> bool { each_split_inner(s, sepfn, len(s), true, true, it) } /// Like `each_split`, but a trailing empty string is omitted +#[cfg(stage0)] pub fn each_split_no_trailing<'a>(s: &'a str, sepfn: &fn(char) -> bool, it: &fn(&'a str) -> bool) { + each_split_inner(s, sepfn, len(s), true, false, it); +} +/// Like `each_split`, but a trailing empty string is omitted +#[cfg(not(stage0))] +pub fn each_split_no_trailing<'a>(s: &'a str, + sepfn: &fn(char) -> bool, + it: &fn(&'a str) -> bool) -> bool { each_split_inner(s, sepfn, len(s), true, false, it) } @@ -549,17 +706,37 @@ pub fn each_split_no_trailing<'a>(s: &'a str, * Splits a string into substrings using a character function, cutting at * most `count` times. */ +#[cfg(stage0)] pub fn each_splitn<'a>(s: &'a str, sepfn: &fn(char) -> bool, count: uint, it: &fn(&'a str) -> bool) { + each_split_inner(s, sepfn, count, true, true, it); +} +/** + * Splits a string into substrings using a character function, cutting at + * most `count` times. + */ +#[cfg(not(stage0))] +pub fn each_splitn<'a>(s: &'a str, + sepfn: &fn(char) -> bool, + count: uint, + it: &fn(&'a str) -> bool) -> bool { each_split_inner(s, sepfn, count, true, true, it) } /// Like `each_split`, but omits empty strings +#[cfg(stage0)] pub fn each_split_nonempty<'a>(s: &'a str, sepfn: &fn(char) -> bool, it: &fn(&'a str) -> bool) { + each_split_inner(s, sepfn, len(s), false, false, it); +} +/// Like `each_split`, but omits empty strings +#[cfg(not(stage0))] +pub fn each_split_nonempty<'a>(s: &'a str, + sepfn: &fn(char) -> bool, + it: &fn(&'a str) -> bool) -> bool { each_split_inner(s, sepfn, len(s), false, false, it) } @@ -568,14 +745,16 @@ fn each_split_inner<'a>(s: &'a str, count: uint, allow_empty: bool, allow_trailing_empty: bool, - it: &fn(&'a str) -> bool) { + it: &fn(&'a str) -> bool) -> bool { let l = len(s); let mut i = 0u, start = 0u, done = 0u; while i < l && done < count { let CharRange {ch, next} = char_range_at(s, i); if sepfn(ch) { if allow_empty || start < i { - if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { return; } + if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { + return false; + } } start = next; done += 1u; @@ -583,12 +762,15 @@ fn each_split_inner<'a>(s: &'a str, i = next; } if allow_trailing_empty || start < l { - if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return; } + if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return false; } } + return true; } // See Issue #1932 for why this is a naive search -fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, f: &fn(uint, uint) -> bool) { +#[cfg(stage0)] +fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, + f: &fn(uint, uint) -> bool) { let sep_len = len(sep), l = len(s); assert!(sep_len > 0u); let mut i = 0u, match_start = 0u, match_i = 0u; @@ -614,7 +796,38 @@ fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, f: &fn(uint, uint) -> bool) { } } } +// See Issue #1932 for why this is a naive search +#[cfg(not(stage0))] +fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, + f: &fn(uint, uint) -> bool) -> bool { + let sep_len = len(sep), l = len(s); + assert!(sep_len > 0u); + let mut i = 0u, match_start = 0u, match_i = 0u; + + while i < l { + if s[i] == sep[match_i] { + if match_i == 0u { match_start = i; } + match_i += 1u; + // Found a match + if match_i == sep_len { + if !f(match_start, i + 1u) { return false; } + match_i = 0u; + } + i += 1u; + } else { + // Failed match, backtrack + if match_i > 0u { + match_i = 0u; + i = match_start + 1u; + } else { + i += 1u; + } + } + } + return true; +} +#[cfg(stage0)] fn iter_between_matches<'a,'b>(s: &'a str, sep: &'b str, f: &fn(uint, uint) -> bool) { @@ -625,6 +838,17 @@ fn iter_between_matches<'a,'b>(s: &'a str, } f(last_end, len(s)); } +#[cfg(not(stage0))] +fn iter_between_matches<'a,'b>(s: &'a str, + sep: &'b str, + f: &fn(uint, uint) -> bool) -> bool { + let mut last_end = 0u; + for iter_matches(s, sep) |from, to| { + if !f(last_end, from) { return false; } + last_end = to; + } + return f(last_end, len(s)); +} /** * Splits a string into a vector of the substrings separated by a given string @@ -637,6 +861,7 @@ fn iter_between_matches<'a,'b>(s: &'a str, * assert!(v == ["", "XXX", "YYY", ""]); * ~~~ */ +#[cfg(stage0)] pub fn each_split_str<'a,'b>(s: &'a str, sep: &'b str, it: &fn(&'a str) -> bool) { @@ -644,7 +869,28 @@ pub fn each_split_str<'a,'b>(s: &'a str, if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return; } } } +/** + * Splits a string into a vector of the substrings separated by a given string + * + * # Example + * + * ~~~ + * let mut v = ~[]; + * for each_split_str(".XXX.YYY.", ".") |subs| { v.push(subs); } + * assert!(v == ["", "XXX", "YYY", ""]); + * ~~~ + */ +#[cfg(not(stage0))] +pub fn each_split_str<'a,'b>(s: &'a str, + sep: &'b str, + it: &fn(&'a str) -> bool) -> bool { + for iter_between_matches(s, sep) |from, to| { + if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; } + } + return true; +} +#[cfg(stage0)] pub fn each_split_str_nonempty<'a,'b>(s: &'a str, sep: &'b str, it: &fn(&'a str) -> bool) { @@ -655,6 +901,18 @@ pub fn each_split_str_nonempty<'a,'b>(s: &'a str, } } +#[cfg(not(stage0))] +pub fn each_split_str_nonempty<'a,'b>(s: &'a str, + sep: &'b str, + it: &fn(&'a str) -> bool) -> bool { + for iter_between_matches(s, sep) |from, to| { + if to > from { + if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; } + } + } + return true; +} + /// Levenshtein Distance between two strings pub fn levdistance(s: &str, t: &str) -> uint { @@ -692,7 +950,15 @@ pub fn levdistance(s: &str, t: &str) -> uint { /** * Splits a string into substrings separated by LF ('\n'). */ +#[cfg(stage0)] pub fn each_line<'a>(s: &'a str, it: &fn(&'a str) -> bool) { + each_split_char_no_trailing(s, '\n', it); +} +/** + * Splits a string into substrings separated by LF ('\n'). + */ +#[cfg(not(stage0))] +pub fn each_line<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { each_split_char_no_trailing(s, '\n', it) } @@ -700,6 +966,7 @@ pub fn each_line<'a>(s: &'a str, it: &fn(&'a str) -> bool) { * Splits a string into substrings separated by LF ('\n') * and/or CR LF ("\r\n") */ +#[cfg(stage0)] pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) { for each_line(s) |s| { let l = s.len(); @@ -710,9 +977,31 @@ pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) { } } } +/** + * Splits a string into substrings separated by LF ('\n') + * and/or CR LF ("\r\n") + */ +#[cfg(not(stage0))] +pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { + for each_line(s) |s| { + let l = s.len(); + if l > 0u && s[l - 1u] == '\r' as u8 { + if !it( unsafe { raw::slice_bytes(s, 0, l - 1) } ) { return false; } + } else { + if !it( s ) { return false; } + } + } + return true; +} /// Splits a string into substrings separated by whitespace +#[cfg(stage0)] pub fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool) { + each_split_nonempty(s, char::is_whitespace, it); +} +/// Splits a string into substrings separated by whitespace +#[cfg(not(stage0))] +pub fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { each_split_nonempty(s, char::is_whitespace, it) } @@ -725,9 +1014,9 @@ pub fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool) { * Fails during iteration if the string contains a non-whitespace * sequence longer than the limit. */ -pub fn each_split_within<'a>(ss: &'a str, - lim: uint, - it: &fn(&'a str) -> bool) { +pub fn _each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) -> bool { // Just for fun, let's write this as an state machine: enum SplitWithinState { @@ -785,6 +1074,20 @@ pub fn each_split_within<'a>(ss: &'a str, machine(fake_i, ' '); fake_i += 1; } + return cont; +} + +#[cfg(stage0)] +pub fn each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) { + _each_split_within(ss, lim, it); +} +#[cfg(not(stage0))] +pub fn each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) -> bool { + _each_split_within(ss, lim, it) } /** @@ -818,8 +1121,9 @@ Section: Comparing strings */ /// Bytewise slice equality -#[cfg(notest)] +#[cfg(not(test))] #[lang="str_eq"] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -836,6 +1140,7 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } #[cfg(test)] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -852,17 +1157,20 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } /// Bytewise string equality -#[cfg(notest)] +#[cfg(not(test))] #[lang="uniq_str_eq"] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } #[cfg(test)] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } +#[inline] fn cmp(a: &str, b: &str) -> Ordering { let low = uint::min(a.len(), b.len()); @@ -877,22 +1185,26 @@ fn cmp(a: &str, b: &str) -> Ordering { a.len().cmp(&b.len()) } -#[cfg(notest)] +#[cfg(not(test))] impl<'self> TotalOrd for &'self str { + #[inline] fn cmp(&self, other: & &'self str) -> Ordering { cmp(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for ~str { + #[inline] fn cmp(&self, other: &~str) -> Ordering { cmp(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for @str { + #[inline] fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) } } /// Bytewise slice less than +#[inline] fn lt(a: &str, b: &str) -> bool { let (a_len, b_len) = (a.len(), b.len()); let end = uint::min(a_len, b_len); @@ -909,21 +1221,24 @@ fn lt(a: &str, b: &str) -> bool { } /// Bytewise less than or equal +#[inline] pub fn le(a: &str, b: &str) -> bool { !lt(b, a) } /// Bytewise greater than or equal +#[inline] fn ge(a: &str, b: &str) -> bool { !lt(a, b) } /// Bytewise greater than +#[inline] fn gt(a: &str, b: &str) -> bool { !le(a, b) } -#[cfg(notest)] +#[cfg(not(test))] impl<'self> Eq for &'self str { #[inline(always)] fn eq(&self, other: & &'self str) -> bool { @@ -933,7 +1248,7 @@ impl<'self> Eq for &'self str { fn ne(&self, other: & &'self str) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for ~str { #[inline(always)] fn eq(&self, other: &~str) -> bool { @@ -943,7 +1258,7 @@ impl Eq for ~str { fn ne(&self, other: &~str) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for @str { #[inline(always)] fn eq(&self, other: &@str) -> bool { @@ -953,7 +1268,7 @@ impl Eq for @str { fn ne(&self, other: &@str) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl<'self> TotalEq for &'self str { #[inline(always)] fn equals(&self, other: & &'self str) -> bool { @@ -961,7 +1276,7 @@ impl<'self> TotalEq for &'self str { } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalEq for ~str { #[inline(always)] fn equals(&self, other: &~str) -> bool { @@ -969,7 +1284,7 @@ impl TotalEq for ~str { } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalEq for @str { #[inline(always)] fn equals(&self, other: &@str) -> bool { @@ -977,7 +1292,7 @@ impl TotalEq for @str { } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for ~str { #[inline(always)] fn lt(&self, other: &~str) -> bool { lt((*self), (*other)) } @@ -989,7 +1304,7 @@ impl Ord for ~str { fn gt(&self, other: &~str) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl<'self> Ord for &'self str { #[inline(always)] fn lt(&self, other: & &'self str) -> bool { lt((*self), (*other)) } @@ -1001,7 +1316,7 @@ impl<'self> Ord for &'self str { fn gt(&self, other: & &'self str) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for @str { #[inline(always)] fn lt(&self, other: &@str) -> bool { lt((*self), (*other)) } @@ -1013,7 +1328,7 @@ impl Ord for @str { fn gt(&self, other: &@str) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl<'self> Equiv<~str> for &'self str { #[inline(always)] fn equiv(&self, other: &~str) -> bool { eq_slice(*self, *other) } @@ -1051,12 +1366,20 @@ pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str { /// Iterate over the bytes in a string #[inline(always)] +#[cfg(stage0)] pub fn each(s: &str, it: &fn(u8) -> bool) { eachi(s, |_i, b| it(b)) } +/// Iterate over the bytes in a string +#[inline(always)] +#[cfg(not(stage0))] +pub fn each(s: &str, it: &fn(u8) -> bool) -> bool { + eachi(s, |_i, b| it(b)) +} /// Iterate over the bytes in a string, with indices #[inline(always)] +#[cfg(stage0)] pub fn eachi(s: &str, it: &fn(uint, u8) -> bool) { let mut pos = 0; let len = s.len(); @@ -1067,14 +1390,36 @@ pub fn eachi(s: &str, it: &fn(uint, u8) -> bool) { } } +/// Iterate over the bytes in a string, with indices +#[inline(always)] +#[cfg(not(stage0))] +pub fn eachi(s: &str, it: &fn(uint, u8) -> bool) -> bool { + let mut pos = 0; + let len = s.len(); + + while pos < len { + if !it(pos, s[pos]) { return false; } + pos += 1; + } + return true; +} + /// Iterate over the bytes in a string in reverse #[inline(always)] +#[cfg(stage0)] pub fn each_reverse(s: &str, it: &fn(u8) -> bool) { eachi_reverse(s, |_i, b| it(b) ) } +/// Iterate over the bytes in a string in reverse +#[inline(always)] +#[cfg(not(stage0))] +pub fn each_reverse(s: &str, it: &fn(u8) -> bool) -> bool { + eachi_reverse(s, |_i, b| it(b) ) +} /// Iterate over the bytes in a string in reverse, with indices #[inline(always)] +#[cfg(stage0)] pub fn eachi_reverse(s: &str, it: &fn(uint, u8) -> bool) { let mut pos = s.len(); while pos > 0 { @@ -1082,9 +1427,21 @@ pub fn eachi_reverse(s: &str, it: &fn(uint, u8) -> bool) { if !it(pos, s[pos]) { break; } } } +/// Iterate over the bytes in a string in reverse, with indices +#[inline(always)] +#[cfg(not(stage0))] +pub fn eachi_reverse(s: &str, it: &fn(uint, u8) -> bool) -> bool { + let mut pos = s.len(); + while pos > 0 { + pos -= 1; + if !it(pos, s[pos]) { return false; } + } + return true; +} /// Iterate over each char of a string, without allocating #[inline(always)] +#[cfg(stage0)] pub fn each_char(s: &str, it: &fn(char) -> bool) { let mut i = 0; let len = len(s); @@ -1094,9 +1451,23 @@ pub fn each_char(s: &str, it: &fn(char) -> bool) { i = next; } } +/// Iterate over each char of a string, without allocating +#[inline(always)] +#[cfg(not(stage0))] +pub fn each_char(s: &str, it: &fn(char) -> bool) -> bool { + let mut i = 0; + let len = len(s); + while i < len { + let CharRange {ch, next} = char_range_at(s, i); + if !it(ch) { return false; } + i = next; + } + return true; +} /// Iterates over the chars in a string, with indices #[inline(always)] +#[cfg(stage0)] pub fn each_chari(s: &str, it: &fn(uint, char) -> bool) { let mut pos = 0; let mut ch_pos = 0u; @@ -1108,15 +1479,38 @@ pub fn each_chari(s: &str, it: &fn(uint, char) -> bool) { ch_pos += 1u; } } +/// Iterates over the chars in a string, with indices +#[inline(always)] +#[cfg(not(stage0))] +pub fn each_chari(s: &str, it: &fn(uint, char) -> bool) -> bool { + let mut pos = 0; + let mut ch_pos = 0u; + let len = s.len(); + while pos < len { + let CharRange {ch, next} = char_range_at(s, pos); + pos = next; + if !it(ch_pos, ch) { return false; } + ch_pos += 1u; + } + return true; +} /// Iterates over the chars in a string in reverse #[inline(always)] +#[cfg(stage0)] pub fn each_char_reverse(s: &str, it: &fn(char) -> bool) { each_chari_reverse(s, |_, c| it(c)) } +/// Iterates over the chars in a string in reverse +#[inline(always)] +#[cfg(not(stage0))] +pub fn each_char_reverse(s: &str, it: &fn(char) -> bool) -> bool { + each_chari_reverse(s, |_, c| it(c)) +} // Iterates over the chars in a string in reverse, with indices #[inline(always)] +#[cfg(stage0)] pub fn each_chari_reverse(s: &str, it: &fn(uint, char) -> bool) { let mut pos = s.len(); let mut ch_pos = s.char_len(); @@ -1129,6 +1523,21 @@ pub fn each_chari_reverse(s: &str, it: &fn(uint, char) -> bool) { } } +// Iterates over the chars in a string in reverse, with indices +#[inline(always)] +#[cfg(not(stage0))] +pub fn each_chari_reverse(s: &str, it: &fn(uint, char) -> bool) -> bool { + let mut pos = s.len(); + let mut ch_pos = s.char_len(); + while pos > 0 { + let CharRange {ch, next} = char_range_at_reverse(s, pos); + pos = next; + ch_pos -= 1; + + if !it(ch_pos, ch) { return false; } + } + return true; +} /* Section: Searching @@ -1595,6 +2004,7 @@ Section: String properties */ /// Returns true if the string has length 0 +#[inline(always)] pub fn is_empty(s: &str) -> bool { len(s) == 0u } /** @@ -1616,11 +2026,13 @@ fn is_alphanumeric(s: &str) -> bool { } /// Returns the string length/size in bytes not counting the null terminator +#[inline(always)] pub fn len(s: &str) -> uint { do as_buf(s) |_p, n| { n - 1u } } /// Returns the number of characters that a string holds +#[inline(always)] pub fn char_len(s: &str) -> uint { count_chars(s, 0u, len(s)) } /* @@ -1752,7 +2164,8 @@ pub fn count_chars(s: &str, start: uint, end: uint) -> uint { return len; } -/// Counts the number of bytes taken by the `n` in `s` starting from `start`. +/// 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!(is_char_boundary(s, start)); let mut end = start, cnt = n; @@ -1988,6 +2401,7 @@ static tag_six_b: uint = 252u; * let i = str::as_bytes("Hello World") { |bytes| vec::len(bytes) }; * ~~~ */ +#[inline] pub fn as_bytes(s: &const ~str, f: &fn(&~[u8]) -> T) -> T { unsafe { let v: *~[u8] = cast::transmute(copy s); @@ -2023,12 +2437,13 @@ pub fn as_bytes_slice<'a>(s: &'a str) -> &'a [u8] { * let s = str::as_c_str("PATH", { |path| libc::getenv(path) }); * ~~~ */ +#[inline] pub fn as_c_str(s: &str, f: &fn(*libc::c_char) -> T) -> T { do as_buf(s) |buf, len| { // NB: len includes the trailing null. assert!(len > 0); if unsafe { *(ptr::offset(buf,len-1)) != 0 } { - as_c_str(from_slice(s), f) + as_c_str(to_owned(s), f) } else { f(buf as *libc::c_char) } @@ -2099,6 +2514,7 @@ pub fn subslice_offset(outer: &str, inner: &str) -> uint { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve(s: &mut ~str, n: uint) { unsafe { let v: *mut ~[u8] = cast::transmute(s); @@ -2126,6 +2542,7 @@ pub fn reserve(s: &mut ~str, n: uint) { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve_at_least(s: &mut ~str, n: uint) { reserve(s, uint::next_power_of_two(n + 1u) - 1u) } @@ -2292,7 +2709,7 @@ pub mod raw { unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) { let new_len = s.len() + bytes.len(); reserve_at_least(&mut *s, new_len); - for vec::each(bytes) |byte| { push_byte(&mut *s, *byte); } + for bytes.each |byte| { push_byte(&mut *s, *byte); } } /// Removes the last byte from a string and returns it. (Not UTF-8 safe). @@ -2314,6 +2731,7 @@ pub mod raw { } /// Sets the length of the string and adds the null terminator + #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { let v: **mut vec::raw::VecRepr = cast::transmute(v); let repr: *mut vec::raw::VecRepr = *v; @@ -2335,7 +2753,7 @@ pub mod raw { } -#[cfg(notest)] +#[cfg(not(test))] pub mod traits { use ops::Add; use str::append; @@ -2356,18 +2774,23 @@ pub trait StrSlice<'self> { fn any(&self, it: &fn(char) -> bool) -> bool; fn contains<'a>(&self, needle: &'a str) -> bool; fn contains_char(&self, needle: char) -> bool; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn char_iter(&self) -> StrCharIterator<'self>; - fn each(&self, it: &fn(u8) -> bool); - fn eachi(&self, it: &fn(uint, u8) -> bool); - fn each_reverse(&self, it: &fn(u8) -> bool); - fn eachi_reverse(&self, it: &fn(uint, u8) -> bool); - fn each_char(&self, it: &fn(char) -> bool); - fn each_chari(&self, it: &fn(uint, char) -> bool); - fn each_char_reverse(&self, it: &fn(char) -> bool); - fn each_chari_reverse(&self, it: &fn(uint, char) -> bool); + #[cfg(stage0)] fn each(&self, it: &fn(u8) -> bool); + #[cfg(not(stage0))] fn each(&self, it: &fn(u8) -> bool) -> bool; + #[cfg(stage0)] fn eachi(&self, it: &fn(uint, u8) -> bool); + #[cfg(not(stage0))] fn eachi(&self, it: &fn(uint, u8) -> bool) -> bool; + #[cfg(stage0)] fn each_reverse(&self, it: &fn(u8) -> bool); + #[cfg(not(stage0))] fn each_reverse(&self, it: &fn(u8) -> bool) -> bool; + #[cfg(stage0)] fn eachi_reverse(&self, it: &fn(uint, u8) -> bool); + #[cfg(not(stage0))] fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) -> bool; + #[cfg(stage0)] fn each_char(&self, it: &fn(char) -> bool); + #[cfg(not(stage0))] fn each_char(&self, it: &fn(char) -> bool) -> bool; + #[cfg(stage0)] fn each_chari(&self, it: &fn(uint, char) -> bool); + #[cfg(not(stage0))] fn each_chari(&self, it: &fn(uint, char) -> bool) -> bool; + #[cfg(stage0)] fn each_char_reverse(&self, it: &fn(char) -> bool); + #[cfg(not(stage0))] fn each_char_reverse(&self, it: &fn(char) -> bool) -> bool; + #[cfg(stage0)] fn each_chari_reverse(&self, it: &fn(uint, char) -> bool); + #[cfg(not(stage0))] fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) -> bool; fn ends_with(&self, needle: &str) -> bool; fn is_empty(&self) -> bool; fn is_whitespace(&self) -> bool; @@ -2375,9 +2798,18 @@ pub trait StrSlice<'self> { fn len(&self) -> uint; fn char_len(&self) -> uint; fn slice(&self, begin: uint, end: uint) -> &'self str; + #[cfg(stage0)] fn each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool); + #[cfg(not(stage0))] + fn each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool) -> bool; + #[cfg(stage0)] fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool); + #[cfg(not(stage0))] + fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) -> bool; + #[cfg(stage0)] fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool); + #[cfg(not(stage0))] + fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool; fn starts_with<'a>(&self, needle: &'a str) -> bool; fn substr(&self, begin: uint, n: uint) -> &'self str; fn escape_default(&self) -> ~str; @@ -2420,9 +2852,6 @@ impl<'self> StrSlice<'self> for &'self str { contains_char(*self, needle) } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline] fn char_iter(&self) -> StrCharIterator<'self> { StrCharIterator { @@ -2433,39 +2862,86 @@ impl<'self> StrSlice<'self> for &'self str { /// Iterate over the bytes in a string #[inline] + #[cfg(stage0)] fn each(&self, it: &fn(u8) -> bool) { each(*self, it) } + /// Iterate over the bytes in a string + #[inline] + #[cfg(not(stage0))] + fn each(&self, it: &fn(u8) -> bool) -> bool { each(*self, it) } /// Iterate over the bytes in a string, with indices #[inline] + #[cfg(stage0)] fn eachi(&self, it: &fn(uint, u8) -> bool) { eachi(*self, it) } + /// Iterate over the bytes in a string, with indices + #[inline] + #[cfg(not(stage0))] + fn eachi(&self, it: &fn(uint, u8) -> bool) -> bool { eachi(*self, it) } /// Iterate over the bytes in a string #[inline] - fn each_reverse(&self, it: &fn(u8) -> bool) { - each_reverse(*self, it) - } + #[cfg(stage0)] + fn each_reverse(&self, it: &fn(u8) -> bool) { each_reverse(*self, it) } + /// Iterate over the bytes in a string + #[inline] + #[cfg(not(stage0))] + fn each_reverse(&self, it: &fn(u8) -> bool) -> bool { each_reverse(*self, it) } /// Iterate over the bytes in a string, with indices #[inline] + #[cfg(stage0)] fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) { eachi_reverse(*self, it) } + /// Iterate over the bytes in a string, with indices + #[inline] + #[cfg(not(stage0))] + fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) -> bool { + eachi_reverse(*self, it) + } /// Iterate over the chars in a string #[inline] + #[cfg(stage0)] fn each_char(&self, it: &fn(char) -> bool) { each_char(*self, it) } + /// Iterate over the chars in a string + #[inline] + #[cfg(not(stage0))] + fn each_char(&self, it: &fn(char) -> bool) -> bool { each_char(*self, it) } /// Iterate over the chars in a string, with indices #[inline] + #[cfg(stage0)] fn each_chari(&self, it: &fn(uint, char) -> bool) { each_chari(*self, it) } + /// Iterate over the chars in a string, with indices + #[inline] + #[cfg(not(stage0))] + fn each_chari(&self, it: &fn(uint, char) -> bool) -> bool { + each_chari(*self, it) + } /// Iterate over the chars in a string in reverse #[inline] + #[cfg(stage0)] fn each_char_reverse(&self, it: &fn(char) -> bool) { each_char_reverse(*self, it) } + /// Iterate over the chars in a string in reverse + #[inline] + #[cfg(not(stage0))] + fn each_char_reverse(&self, it: &fn(char) -> bool) -> bool { + each_char_reverse(*self, it) + } /// Iterate over the chars in a string in reverse, with indices from the /// end #[inline] + #[cfg(stage0)] fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) { each_chari_reverse(*self, it) } + /// Iterate over the chars in a string in reverse, with indices from the + /// end + #[inline] + #[cfg(not(stage0))] + fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) -> bool { + each_chari_reverse(*self, it) + } /// Returns true if one string ends with another #[inline] fn ends_with(&self, needle: &str) -> bool { @@ -2489,7 +2965,7 @@ impl<'self> StrSlice<'self> for &'self str { #[inline] fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) } /// Returns the size in bytes not counting the null terminator - #[inline] + #[inline(always)] fn len(&self) -> uint { len(*self) } /// Returns the number of characters that a string holds #[inline] @@ -2507,24 +2983,50 @@ impl<'self> StrSlice<'self> for &'self str { } /// Splits a string into substrings using a character function #[inline] + #[cfg(stage0)] fn each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool) { each_split(*self, sepfn, it) } + /// Splits a string into substrings using a character function + #[inline] + #[cfg(not(stage0))] + fn each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool) -> bool { + each_split(*self, sepfn, it) + } /** * Splits a string into substrings at each occurrence of a given character */ #[inline] + #[cfg(stage0)] fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) { each_split_char(*self, sep, it) } + /** + * Splits a string into substrings at each occurrence of a given character + */ + #[inline] + #[cfg(not(stage0))] + fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) -> bool { + each_split_char(*self, sep, it) + } /** * Splits a string into a vector of the substrings separated by a given * string */ #[inline] + #[cfg(stage0)] fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) { each_split_str(*self, sep, it) } + /** + * Splits a string into a vector of the substrings separated by a given + * string + */ + #[inline] + #[cfg(not(stage0))] + fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool { + each_split_str(*self, sep, it) + } /// Returns true if one string starts with another #[inline] fn starts_with<'a>(&self, needle: &'a str) -> bool { @@ -2572,7 +3074,7 @@ impl<'self> StrSlice<'self> for &'self str { #[inline] - fn to_owned(&self) -> ~str { from_slice(*self) } + fn to_owned(&self) -> ~str { to_owned(*self) } #[inline] fn to_managed(&self) -> @str { @@ -2599,10 +3101,11 @@ pub trait OwnedStr { } impl OwnedStr for ~str { + #[inline] fn push_str(&mut self, v: &str) { push_str(self, v); } - + #[inline] fn push_char(&mut self, c: char) { push_char(self, c); } @@ -2611,21 +3114,15 @@ impl OwnedStr for ~str { impl Clone for ~str { #[inline(always)] fn clone(&self) -> ~str { - from_slice(*self) + to_owned(*self) } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub struct StrCharIterator<'self> { priv index: uint, priv string: &'self str, } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self> Iterator for StrCharIterator<'self> { #[inline] fn next(&mut self) -> Option { @@ -2641,13 +3138,16 @@ impl<'self> Iterator for StrCharIterator<'self> { #[cfg(test)] mod tests { + use container::Container; use char; use option::Some; use libc::c_char; use libc; + use old_iter::BaseIter; use ptr; use str::*; use vec; + use vec::ImmutableVector; use cmp::{TotalOrd, Less, Equal, Greater}; #[test] @@ -2912,7 +3412,7 @@ mod tests { let lf = ~"\nMary had a little lamb\nLittle lamb\n"; let crlf = ~"\r\nMary had a little lamb\r\nLittle lamb\r\n"; - fn t(s: &str, f: &fn(&str, &fn(&str) -> bool), u: &[~str]) { + fn t(s: &str, f: &fn(&str, &fn(&str) -> bool) -> bool, u: &[~str]) { let mut v = ~[]; for f(s) |s| { v.push(s.to_owned()) } assert!(vec::all2(v, u, |a,b| a == b)); @@ -2932,7 +3432,7 @@ mod tests { #[test] fn test_words () { - fn t(s: &str, f: &fn(&str, &fn(&str) -> bool), u: &[~str]) { + fn t(s: &str, f: &fn(&str, &fn(&str) -> bool) -> bool, u: &[~str]) { let mut v = ~[]; for f(s) |s| { v.push(s.to_owned()) } assert!(vec::all2(v, u, |a,b| a == b)); @@ -3677,7 +4177,7 @@ mod tests { 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16, 0x000a_u16 ]) ]; - for vec::each(pairs) |p| { + for pairs.each |p| { let (s, u) = copy *p; assert!(to_utf16(s) == u); assert!(from_utf16(u) == s); diff --git a/src/libcore/str/ascii.rs b/src/libcore/str/ascii.rs index 9180c995ca28c..4e239c4c82c7d 100644 --- a/src/libcore/str/ascii.rs +++ b/src/libcore/str/ascii.rs @@ -8,9 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Operations on ASCII strings and characters. + use to_str::{ToStr,ToStrConsume}; use str; +use str::StrSlice; use cast; +use old_iter::BaseIter; +use vec::{CopyableVector, ImmutableVector, OwnedVector}; /// Datatype to hold one ascii character. It is 8 bit long. #[deriving(Clone, Eq)] diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 8cad0a2288642..4eca7ebbb371e 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -10,6 +10,7 @@ //! Misc low level stuff +use option::{Some, None}; use cast; use cmp::{Eq, Ord}; use gc; @@ -199,36 +200,33 @@ impl FailWithCause for &'static str { } } -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { +// FIXME #4427: Temporary until rt::rt_fail_ goes away +pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + + match context() { + OldTaskContext => { unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) + gc::cleanup_stack_for_failure(); + rustrt::rust_upcall_fail(msg, file, line); + cast::transmute(()) + } + } + _ => { + // XXX: Need to print the failure message + gc::cleanup_stack_for_failure(); + unsafe { + let local_services = unsafe_borrow_local_services(); + match local_services.unwinder { + Some(ref mut unwinder) => unwinder.begin_unwind(), + None => abort!("failure without unwinder. aborting process") + } } } } } -// FIXME #4427: Temporary until rt::rt_fail_ goes away -pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { - unsafe { - gc::cleanup_stack_for_failure(); - rustrt::rust_upcall_fail(msg, file, line); - cast::transmute(()) - } -} - -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { - let (msg, file) = (msg.to_owned(), file.to_owned()); - begin_unwind(~"assertion failed: " + msg, file, line) -} - #[cfg(test)] mod tests { use cast; @@ -343,11 +341,3 @@ mod tests { #[should_fail] fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs index 67bc3adeb41c0..a30db039f30d7 100644 --- a/src/libcore/task/local_data_priv.rs +++ b/src/libcore/task/local_data_priv.rs @@ -15,18 +15,42 @@ use cmp::Eq; use libc; use prelude::*; use task::rt; -use task::local_data::LocalDataKey; +use local_data::LocalDataKey; use super::rt::rust_task; +use rt::local_services::LocalStorage; + +pub enum Handle { + OldHandle(*rust_task), + NewHandle(*mut LocalStorage) +} + +impl Handle { + pub fn new() -> Handle { + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + unsafe { + match context() { + OldTaskContext => { + OldHandle(rt::rust_get_task()) + } + _ => { + let local_services = unsafe_borrow_local_services(); + NewHandle(&mut local_services.storage) + } + } + } + } +} pub trait LocalData { } -impl LocalData for @T { } +impl LocalData for @T { } impl Eq for @LocalData { fn eq(&self, other: &@LocalData) -> bool { unsafe { - let ptr_a: (uint, uint) = cast::transmute(*self); - let ptr_b: (uint, uint) = cast::transmute(*other); + let ptr_a: &(uint, uint) = cast::transmute(self); + let ptr_b: &(uint, uint) = cast::transmute(other); return ptr_a == ptr_b; } } @@ -39,7 +63,7 @@ type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData); // Has to be a pointer at outermost layer; the foreign call returns void *. type TaskLocalMap = @mut ~[Option]; -extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { +fn cleanup_task_local_map(map_ptr: *libc::c_void) { unsafe { assert!(!map_ptr.is_null()); // Get and keep the single reference that was created at the @@ -50,8 +74,19 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { } // Gets the map from the runtime. Lazily initialises if not done so already. +unsafe fn get_local_map(handle: Handle) -> TaskLocalMap { + match handle { + OldHandle(task) => get_task_local_map(task), + NewHandle(local_storage) => get_newsched_local_map(local_storage) + } +} + unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { + extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) { + cleanup_task_local_map(map_ptr); + } + // Relies on the runtime initialising the pointer to null. // Note: The map's box lives in TLS invisibly referenced once. Each time // we retrieve it for get/set, we make another reference, which get/set @@ -60,7 +95,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { if map_ptr.is_null() { let map: TaskLocalMap = @mut ~[]; rt::rust_set_task_local_data(task, cast::transmute(map)); - rt::rust_task_local_data_atexit(task, cleanup_task_local_map); + rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb); // Also need to reference it an extra time to keep it for now. let nonmut = cast::transmute::]>(map); @@ -75,15 +110,36 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { } } -unsafe fn key_to_key_value(key: LocalDataKey) -> *libc::c_void { +unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap { + match &mut *local { + &LocalStorage(map_ptr, Some(_)) => { + assert!(map_ptr.is_not_null()); + let map = cast::transmute(map_ptr); + let nonmut = cast::transmute::]>(map); + cast::bump_box_refcount(nonmut); + return map; + } + &LocalStorage(ref mut map_ptr, ref mut at_exit) => { + assert!((*map_ptr).is_null()); + let map: TaskLocalMap = @mut ~[]; + *map_ptr = cast::transmute(map); + let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p); + *at_exit = Some(at_exit_fn); + return map; + } + } +} + +unsafe fn key_to_key_value(key: LocalDataKey) -> *libc::c_void { // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. - // Use reintepret_cast -- transmute would leak (forget) the closure. + // Use reinterpret_cast -- transmute would leak (forget) the closure. let pair: (*libc::c_void, *libc::c_void) = cast::transmute_copy(&key); pair.first() } // If returning Some(..), returns with @T with the map's reference. Careful! -unsafe fn local_data_lookup( +unsafe fn local_data_lookup( map: TaskLocalMap, key: LocalDataKey) -> Option<(uint, *libc::c_void)> { @@ -101,11 +157,11 @@ unsafe fn local_data_lookup( } } -unsafe fn local_get_helper( - task: *rust_task, key: LocalDataKey, +unsafe fn local_get_helper( + handle: Handle, key: LocalDataKey, do_pop: bool) -> Option<@T> { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Interpreturn our findings from the map do local_data_lookup(map, key).map |result| { // A reference count magically appears on 'data' out of thin air. It @@ -123,24 +179,24 @@ unsafe fn local_get_helper( } -pub unsafe fn local_pop( - task: *rust_task, +pub unsafe fn local_pop( + handle: Handle, key: LocalDataKey) -> Option<@T> { - local_get_helper(task, key, true) + local_get_helper(handle, key, true) } -pub unsafe fn local_get( - task: *rust_task, +pub unsafe fn local_get( + handle: Handle, key: LocalDataKey) -> Option<@T> { - local_get_helper(task, key, false) + local_get_helper(handle, key, false) } -pub unsafe fn local_set( - task: *rust_task, key: LocalDataKey, data: @T) { +pub unsafe fn local_set( + handle: Handle, key: LocalDataKey, data: @T) { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Store key+data as *voids. Data is invisibly referenced once; key isn't. let keyval = key_to_key_value(key); // We keep the data in two forms: one as an unsafe pointer, so we can get @@ -148,7 +204,7 @@ pub unsafe fn local_set( // own on it can be dropped when the box is destroyed. The unsafe pointer // does not have a reference associated with it, so it may become invalid // when the box is destroyed. - let data_ptr = cast::transmute(data); + let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data); let data_box = @data as @LocalData; // Construct new entry to store in the map. let new_entry = Some((keyval, data_ptr, data_box)); @@ -169,13 +225,13 @@ pub unsafe fn local_set( } } -pub unsafe fn local_modify( - task: *rust_task, key: LocalDataKey, +pub unsafe fn local_modify( + handle: Handle, key: LocalDataKey, modify_fn: &fn(Option<@T>) -> Option<@T>) { // Could be more efficient by doing the lookup work, but this is easy. - let newdata = modify_fn(local_pop(task, key)); + let newdata = modify_fn(local_pop(handle, key)); if newdata.is_some() { - local_set(task, key, newdata.unwrap()); + local_set(handle, key, newdata.unwrap()); } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 96429932b184a..1518f80a125a9 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -39,14 +39,14 @@ use result::Result; use comm::{stream, Chan, GenericChan, GenericPort, Port}; use prelude::*; use result; -use task::rt::{task_id, sched_id, rust_task}; +use task::rt::{task_id, sched_id}; use util; use util::replace; +use unstable::finally::Finally; #[cfg(test)] use comm::SharedChan; mod local_data_priv; -pub mod local_data; pub mod rt; pub mod spawn; @@ -155,7 +155,7 @@ pub struct SchedOpts { pub struct TaskOpts { linked: bool, supervised: bool, - mut notify_chan: Option>, + notify_chan: Option>, sched: SchedOpts } @@ -175,9 +175,9 @@ pub struct TaskOpts { // FIXME (#3724): Replace the 'consumed' bit with move mode on self pub struct TaskBuilder { opts: TaskOpts, - mut gen_body: Option<~fn(v: ~fn()) -> ~fn()>, + gen_body: Option<~fn(v: ~fn()) -> ~fn()>, can_not_copy: Option, - mut consumed: bool, + consumed: bool, } /** @@ -190,13 +190,13 @@ pub fn task() -> TaskBuilder { opts: default_task_opts(), gen_body: None, can_not_copy: None, - mut consumed: false, + consumed: false, } } #[doc(hidden)] // FIXME #3538 priv impl TaskBuilder { - fn consume(&self) -> TaskBuilder { + fn consume(&mut self) -> TaskBuilder { if self.consumed { fail!(~"Cannot copy a task_builder"); // Fake move mode on self } @@ -218,57 +218,25 @@ priv impl TaskBuilder { } pub impl TaskBuilder { - /** - * Decouple the child task's failure from the parent's. If either fails, - * the other will not be killed. - */ - fn unlinked(&self) -> TaskBuilder { - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: false, - supervised: self.opts.supervised, - notify_chan: notify_chan, - sched: self.opts.sched - }, - can_not_copy: None, - .. self.consume() - } + /// Decouple the child task's failure from the parent's. If either fails, + /// the other will not be killed. + fn unlinked(&mut self) { + self.opts.linked = false; } - /** - * Unidirectionally link the child task's failure with the parent's. The - * child's failure will not kill the parent, but the parent's will kill - * the child. - */ - fn supervised(&self) -> TaskBuilder { - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: false, - supervised: true, - notify_chan: notify_chan, - sched: self.opts.sched - }, - can_not_copy: None, - .. self.consume() - } + + /// Unidirectionally link the child task's failure with the parent's. The + /// child's failure will not kill the parent, but the parent's will kill + /// the child. + fn supervised(&mut self) { + self.opts.supervised = true; + self.opts.linked = false; } - /** - * Link the child task's and parent task's failures. If either fails, the - * other will be killed. - */ - fn linked(&self) -> TaskBuilder { - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: true, - supervised: false, - notify_chan: notify_chan, - sched: self.opts.sched - }, - can_not_copy: None, - .. self.consume() - } + + /// Link the child task's and parent task's failures. If either fails, the + /// other will be killed. + fn linked(&mut self) { + self.opts.linked = true; + self.opts.supervised = false; } /** @@ -288,7 +256,7 @@ pub impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - fn future_result(&self, blk: &fn(v: Port)) -> TaskBuilder { + fn future_result(&mut self, blk: &fn(v: Port)) { // FIXME (#3725): Once linked failure and notification are // handled in the library, I can imagine implementing this by just // registering an arbitrary number of task::on_exit handlers and @@ -304,30 +272,12 @@ pub impl TaskBuilder { blk(notify_pipe_po); // Reconfigure self to use a notify channel. - TaskBuilder { - opts: TaskOpts { - linked: self.opts.linked, - supervised: self.opts.supervised, - notify_chan: Some(notify_pipe_ch), - sched: self.opts.sched - }, - can_not_copy: None, - .. self.consume() - } + self.opts.notify_chan = Some(notify_pipe_ch); } + /// Configure a custom scheduler mode for the task. - fn sched_mode(&self, mode: SchedMode) -> TaskBuilder { - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: self.opts.linked, - supervised: self.opts.supervised, - notify_chan: notify_chan, - sched: SchedOpts { mode: mode, foreign_stack_size: None} - }, - can_not_copy: None, - .. self.consume() - } + fn sched_mode(&mut self, mode: SchedMode) { + self.opts.sched.mode = mode; } /** @@ -342,7 +292,7 @@ pub impl TaskBuilder { * generator by applying the task body which results from the * existing body generator to the new body generator. */ - fn add_wrapper(&self, wrapper: ~fn(v: ~fn()) -> ~fn()) -> TaskBuilder { + fn add_wrapper(&mut self, wrapper: ~fn(v: ~fn()) -> ~fn()) { let prev_gen_body = replace(&mut self.gen_body, None); let prev_gen_body = match prev_gen_body { Some(gen) => gen, @@ -359,18 +309,7 @@ pub impl TaskBuilder { }; f }; - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: self.opts.linked, - supervised: self.opts.supervised, - notify_chan: notify_chan, - sched: self.opts.sched - }, - gen_body: Some(next_gen_body), - can_not_copy: None, - .. self.consume() - } + self.gen_body = Some(next_gen_body); } /** @@ -385,7 +324,7 @@ pub impl TaskBuilder { * When spawning into a new scheduler, the number of threads requested * must be greater than zero. */ - fn spawn(&self, f: ~fn()) { + fn spawn(&mut self, f: ~fn()) { let gen_body = replace(&mut self.gen_body, None); let notify_chan = replace(&mut self.opts.notify_chan, None); let x = self.consume(); @@ -405,8 +344,9 @@ pub impl TaskBuilder { }; spawn::spawn_raw(opts, f); } + /// Runs a task, while transfering ownership of one argument to the child. - fn spawn_with(&self, arg: A, f: ~fn(v: A)) { + fn spawn_with(&mut self, arg: A, f: ~fn(v: A)) { let arg = Cell(arg); do self.spawn { f(arg.take()); @@ -426,16 +366,16 @@ pub impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - fn try(&self, f: ~fn() -> T) -> Result { + fn try(&mut self, f: ~fn() -> T) -> Result { let (po, ch) = stream::(); let mut result = None; - let fr_task_builder = self.future_result(|+r| { - result = Some(r); - }); - do fr_task_builder.spawn || { + self.future_result(|r| { result = Some(r); }); + + do self.spawn { ch.send(f()); } + match result.unwrap().recv() { Success => result::Ok(po.recv()), Failure => result::Err(()) @@ -467,26 +407,23 @@ pub fn default_task_opts() -> TaskOpts { /* Spawn convenience functions */ +/// Creates and executes a new child task +/// +/// Sets up a new task with its own call stack and schedules it to run +/// the provided unique closure. +/// +/// This function is equivalent to `task().spawn(f)`. pub fn spawn(f: ~fn()) { - /*! - * Creates and executes a new child task - * - * Sets up a new task with its own call stack and schedules it to run - * the provided unique closure. - * - * This function is equivalent to `task().spawn(f)`. - */ - - task().spawn(f) + let mut task = task(); + task.spawn(f) } +/// Creates a child task unlinked from the current one. If either this +/// task or the child task fails, the other will not be killed. pub fn spawn_unlinked(f: ~fn()) { - /*! - * Creates a child task unlinked from the current one. If either this - * task or the child task fails, the other will not be killed. - */ - - task().unlinked().spawn(f) + let mut task = task(); + task.unlinked(); + task.spawn(f) } pub fn spawn_supervised(f: ~fn()) { @@ -496,7 +433,9 @@ pub fn spawn_supervised(f: ~fn()) { * the child will be killed. */ - task().supervised().spawn(f) + let mut task = task(); + task.supervised(); + task.spawn(f) } pub fn spawn_with(arg: A, f: ~fn(v: A)) { @@ -510,7 +449,8 @@ pub fn spawn_with(arg: A, f: ~fn(v: A)) { * This function is equivalent to `task().spawn_with(arg, f)`. */ - task().spawn_with(arg, f) + let mut task = task(); + task.spawn_with(arg, f) } pub fn spawn_sched(mode: SchedMode, f: ~fn()) { @@ -526,7 +466,9 @@ pub fn spawn_sched(mode: SchedMode, f: ~fn()) { * greater than zero. */ - task().sched_mode(mode).spawn(f) + let mut task = task(); + task.sched_mode(mode); + task.spawn(f) } pub fn try(f: ~fn() -> T) -> Result { @@ -537,7 +479,9 @@ pub fn try(f: ~fn() -> T) -> Result { * This is equivalent to task().supervised().try. */ - task().supervised().try(f) + let mut task = task(); + task.supervised(); + task.try(f) } @@ -558,8 +502,31 @@ pub fn yield() { pub fn failing() -> bool { //! True if the running task has failed - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) + use rt::{context, OldTaskContext}; + use rt::local_services::borrow_local_services; + + match context() { + OldTaskContext => { + unsafe { + rt::rust_task_is_unwinding(rt::rust_get_task()) + } + } + _ => { + let mut unwinding = false; + do borrow_local_services |local| { + unwinding = match local.unwinder { + Some(unwinder) => { + unwinder.unwinding + } + None => { + // Because there is no unwinder we can't be unwinding. + // (The process will abort on failure) + false + } + } + } + return unwinding; + } } } @@ -591,48 +558,24 @@ pub fn get_scheduler() -> Scheduler { * ~~~ */ pub unsafe fn unkillable(f: &fn() -> U) -> U { - struct AllowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_kill(self.t); - } - } - } - - fn AllowFailure(t: *rust_task) -> AllowFailure{ - AllowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = AllowFailure(t); - rt::rust_task_inhibit_kill(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + f() + }).finally { + rt::rust_task_allow_kill(t); + } } /// The inverse of unkillable. Only ever to be used nested in unkillable(). pub unsafe fn rekillable(f: &fn() -> U) -> U { - struct DisallowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_inhibit_kill(self.t); - } - } - } - - fn DisallowFailure(t: *rust_task) -> DisallowFailure { - DisallowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = DisallowFailure(t); - rt::rust_task_allow_kill(t); - f() + do (|| { + rt::rust_task_allow_kill(t); + f() + }).finally { + rt::rust_task_inhibit_kill(t); + } } /** @@ -640,37 +583,26 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { * For use with exclusive ARCs, which use pthread mutexes directly. */ pub unsafe fn atomically(f: &fn() -> U) -> U { - struct DeferInterrupts { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_yield(self.t); - rt::rust_task_allow_kill(self.t); - } - } - } - - fn DeferInterrupts(t: *rust_task) -> DeferInterrupts { - DeferInterrupts { - t: t - } - } - let t = rt::rust_get_task(); - let _interrupts = DeferInterrupts(t); - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + rt::rust_task_inhibit_yield(t); + f() + }).finally { + rt::rust_task_allow_yield(t); + rt::rust_task_allow_kill(t); + } } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_cant_dup_task_builder() { - let b = task().unlinked(); - do b.spawn { } + let mut builder = task(); + builder.unlinked(); + do builder.spawn {} // FIXME(#3724): For now, this is a -runtime- failure, because we haven't // got move mode on self. When 3724 is fixed, this test should fail to // compile instead, and should go in tests/compile-fail. - do b.spawn { } // b should have been consumed by the previous call + do builder.spawn {} // b should have been consumed by the previous call } // The following 8 tests test the following 2^3 combinations: @@ -713,43 +645,31 @@ fn test_spawn_unlinked_sup_fail_down() { #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_up() { // child fails; parent fails let (po, _ch) = stream::<()>(); + // Unidirectional "parenting" shouldn't override bidirectional linked. // We have to cheat with opts - the interface doesn't support them because // they don't make sense (redundant with task().supervised()). - let opts = { - let mut opts = default_task_opts(); - opts.linked = true; - opts.supervised = true; - opts - }; + let mut b0 = task(); + b0.opts.linked = true; + b0.opts.supervised = true; - let b0 = task(); - let b1 = TaskBuilder { - opts: opts, - can_not_copy: None, - .. b0 - }; - do b1.spawn { fail!(); } + do b0.spawn { + fail!(); + } po.recv(); // We should get punted awake } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_down() { // parent fails; child fails // We have to cheat with opts - the interface doesn't support them because // they don't make sense (redundant with task().supervised()). - let opts = { - let mut opts = default_task_opts(); - opts.linked = true; - opts.supervised = true; - opts - }; - - let b0 = task(); - let b1 = TaskBuilder { - opts: opts, - can_not_copy: None, - .. b0 - }; - do b1.spawn { loop { task::yield(); } } + let mut b0 = task(); + b0.opts.linked = true; + b0.opts.supervised = true; + do b0.spawn { + loop { + task::yield(); + } + } fail!(); // *both* mechanisms would be wrong if this didn't kill the child } #[test] #[should_fail] #[ignore(cfg(windows))] @@ -768,7 +688,13 @@ fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails // Make sure the above test is the same as this one. - do task().linked().spawn { loop { task::yield(); } } + let mut builder = task(); + builder.linked(); + do builder.spawn { + loop { + task::yield(); + } + } fail!(); } @@ -826,32 +752,33 @@ fn test_spawn_linked_sup_propagate_sibling() { #[test] fn test_run_basic() { let (po, ch) = stream::<()>(); - do task().spawn { + let mut builder = task(); + do builder.spawn { ch.send(()); } po.recv(); } -#[test] +#[cfg(test)] struct Wrapper { - mut f: Option> + f: Option> } #[test] fn test_add_wrapper() { let (po, ch) = stream::<()>(); - let b0 = task(); - let ch = Wrapper { f: Some(ch) }; - let b1 = do b0.add_wrapper |body| { - let ch = Wrapper { f: Some(ch.f.swap_unwrap()) }; + let mut b0 = task(); + let ch = Cell(ch); + do b0.add_wrapper |body| { + let ch = Cell(ch.take()); let result: ~fn() = || { - let ch = ch.f.swap_unwrap(); + let ch = ch.take(); body(); ch.send(()); }; result }; - do b1.spawn { } + do b0.spawn { } po.recv(); } @@ -859,12 +786,16 @@ fn test_add_wrapper() { #[ignore(cfg(windows))] fn test_future_result() { let mut result = None; - do task().future_result(|+r| { result = Some(r); }).spawn { } + let mut builder = task(); + builder.future_result(|r| result = Some(r)); + do builder.spawn {} assert!(result.unwrap().recv() == Success); result = None; - do task().future_result(|+r| - { result = Some(r); }).unlinked().spawn { + let mut builder = task(); + builder.future_result(|r| result = Some(r)); + builder.unlinked(); + do builder.spawn { fail!(); } assert!(result.unwrap().recv() == Failure); @@ -872,7 +803,9 @@ fn test_future_result() { #[test] #[should_fail] #[ignore(cfg(windows))] fn test_back_to_the_future_result() { - let _ = task().future_result(util::ignore).future_result(util::ignore); + let mut builder = task(); + builder.future_result(util::ignore); + builder.future_result(util::ignore); } #[test] @@ -934,12 +867,12 @@ fn test_spawn_sched_childs_on_default_sched() { // Assuming tests run on the default scheduler let default_id = unsafe { rt::rust_get_sched_id() }; - let ch = Wrapper { f: Some(ch) }; + let ch = Cell(ch); do spawn_sched(SingleThreaded) { let parent_sched_id = unsafe { rt::rust_get_sched_id() }; - let ch = Wrapper { f: Some(ch.f.swap_unwrap()) }; + let ch = Cell(ch.take()); do spawn { - let ch = ch.f.swap_unwrap(); + let ch = ch.take(); let child_sched_id = unsafe { rt::rust_get_sched_id() }; assert!(parent_sched_id != child_sched_id); assert!(child_sched_id == default_id); @@ -1047,7 +980,8 @@ fn test_avoid_copying_the_body_spawn() { #[test] fn test_avoid_copying_the_body_task_spawn() { do avoid_copying_the_body |f| { - do task().spawn || { + let mut builder = task(); + do builder.spawn || { f(); } } @@ -1074,7 +1008,9 @@ fn test_avoid_copying_the_body_unlinked() { #[test] fn test_platform_thread() { let (po, ch) = stream(); - do task().sched_mode(PlatformThread).spawn { + let mut builder = task(); + builder.sched_mode(PlatformThread); + do builder.spawn { ch.send(()); } po.recv(); @@ -1229,7 +1165,7 @@ fn test_spawn_thread_on_demand() { #[test] fn test_simple_newsched_spawn() { - use rt::run_in_newsched_task; + use rt::test::run_in_newsched_task; do run_in_newsched_task { spawn(||()) diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 507643ea5ec30..9a1689ca05614 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -72,15 +72,15 @@ #[doc(hidden)]; // FIXME #3538 +use cast::transmute; use cast; use cell::Cell; use container::Map; use comm::{Chan, GenericChan}; use prelude::*; -use unstable; use ptr; use hashmap::HashSet; -use task::local_data_priv::{local_get, local_set}; +use task::local_data_priv::{local_get, local_set, OldHandle}; use task::rt::rust_task; use task::rt; use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; @@ -89,6 +89,7 @@ use task::{ExistingScheduler, SchedulerHandle}; use task::unkillable; use uint; use util; +use unstable::sync::{Exclusive, exclusive}; #[cfg(test)] use task::default_task_opts; @@ -109,20 +110,25 @@ fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) { let was_present = tasks.remove(&task); assert!(was_present); } +#[cfg(stage0)] pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) { tasks.each(|k| blk(*k)) } +#[cfg(not(stage0))] +pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) -> bool { + tasks.each(|k| blk(*k)) +} // One of these per group of linked-failure tasks. struct TaskGroupData { // All tasks which might kill this group. When this is empty, the group // can be "GC"ed (i.e., its link in the ancestor list can be removed). - mut members: TaskSet, + members: TaskSet, // All tasks unidirectionally supervised by (directly or transitively) // tasks in this group. - mut descendants: TaskSet, + descendants: TaskSet, } -type TaskGroupArc = unstable::Exclusive>; +type TaskGroupArc = Exclusive>; type TaskGroupInner<'self> = &'self mut Option; @@ -145,14 +151,14 @@ struct AncestorNode { // Hence we assert that this counter monotonically decreases as we // approach the tail of the list. // FIXME(#3068): Make the generation counter togglable with #[cfg(debug)]. - generation: uint, - // Should really be an immutable non-option. This way appeases borrowck. - mut parent_group: Option, + generation: uint, + // Should really be a non-option. This way appeases borrowck. + parent_group: Option, // Recursive rest of the list. - mut ancestors: AncestorList, + ancestors: AncestorList, } -struct AncestorList(Option>); +struct AncestorList(Option>); // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety. #[inline(always)] @@ -161,7 +167,7 @@ fn access_group(x: &TaskGroupArc, blk: &fn(TaskGroupInner) -> U) -> U { } #[inline(always)] -fn access_ancestors(x: &unstable::Exclusive, +fn access_ancestors(x: &Exclusive, blk: &fn(x: &mut AncestorNode) -> U) -> U { x.with(blk) } @@ -301,22 +307,26 @@ fn each_ancestor(list: &mut AncestorList, // One of these per task. struct TCB { - me: *rust_task, + me: *rust_task, // List of tasks with whose fates this one's is intertwined. - tasks: TaskGroupArc, // 'none' means the group has failed. + tasks: TaskGroupArc, // 'none' means the group has failed. // Lists of tasks who will kill us if they fail, but whom we won't kill. - mut ancestors: AncestorList, - is_main: bool, - notifier: Option, + ancestors: AncestorList, + is_main: bool, + notifier: Option, } impl Drop for TCB { // Runs on task exit. fn finalize(&self) { unsafe { + let this: &mut TCB = transmute(self); + // If we are failing, the whole taskgroup needs to die. if rt::rust_task_is_unwinding(self.me) { - for self.notifier.each |x| { x.failed = true; } + for this.notifier.each_mut |x| { + x.failed = true; + } // Take everybody down with us. do access_group(&self.tasks) |tg| { kill_taskgroup(tg, self.me, self.is_main); @@ -331,16 +341,21 @@ impl Drop for TCB { // with our own taskgroup, so long as both happen before we die. // We remove ourself from every ancestor we can, so no cleanup; no // break. - for each_ancestor(&mut self.ancestors, None) |ancestor_group| { + for each_ancestor(&mut this.ancestors, None) |ancestor_group| { leave_taskgroup(ancestor_group, self.me, false); }; } } } -fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList, - is_main: bool, notifier: Option) -> TCB { - for notifier.each |x| { x.failed = false; } +fn TCB(me: *rust_task, + tasks: TaskGroupArc, + ancestors: AncestorList, + is_main: bool, + mut notifier: Option) -> TCB { + for notifier.each_mut |x| { + x.failed = false; + } TCB { me: me, @@ -353,7 +368,7 @@ fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList, struct AutoNotify { notify_chan: Chan, - mut failed: bool, + failed: bool, } impl Drop for AutoNotify { @@ -375,9 +390,12 @@ fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task, let newstate = util::replace(&mut *state, None); // If 'None', the group was failing. Can't enlist. if newstate.is_some() { - let group = newstate.unwrap(); - taskset_insert(if is_member { &mut group.members } - else { &mut group.descendants }, me); + let mut group = newstate.unwrap(); + taskset_insert(if is_member { + &mut group.members + } else { + &mut group.descendants + }, me); *state = Some(group); true } else { @@ -391,9 +409,12 @@ fn leave_taskgroup(state: TaskGroupInner, me: *rust_task, let newstate = util::replace(&mut *state, None); // If 'None', already failing and we've already gotten a kill signal. if newstate.is_some() { - let group = newstate.unwrap(); - taskset_remove(if is_member { &mut group.members } - else { &mut group.descendants }, me); + let mut group = newstate.unwrap(); + taskset_remove(if is_member { + &mut group.members + } else { + &mut group.descendants + }, me); *state = Some(group); } } @@ -451,23 +472,30 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) /*##################################################################* * Step 1. Get spawner's taskgroup info. *##################################################################*/ - let spawner_group = match local_get(spawner, taskgroup_key!()) { - None => { - // Main task, doing first spawn ever. Lazily initialise here. - let mut members = new_taskset(); - taskset_insert(&mut members, spawner); - let tasks = unstable::exclusive(Some(TaskGroupData { - members: members, - descendants: new_taskset(), - })); - // Main task/group has no ancestors, no notifier, etc. - let group = - @TCB(spawner, tasks, AncestorList(None), true, None); - local_set(spawner, taskgroup_key!(), group); - group - } - Some(group) => group - }; + let spawner_group: @@mut TCB = + match local_get(OldHandle(spawner), taskgroup_key!()) { + None => { + // Main task, doing first spawn ever. Lazily initialise + // here. + let mut members = new_taskset(); + taskset_insert(&mut members, spawner); + let tasks = exclusive(Some(TaskGroupData { + members: members, + descendants: new_taskset(), + })); + // Main task/group has no ancestors, no notifier, etc. + let group = @@mut TCB(spawner, + tasks, + AncestorList(None), + true, + None); + local_set(OldHandle(spawner), taskgroup_key!(), group); + group + } + Some(group) => group + }; + let spawner_group: &mut TCB = *spawner_group; + /*##################################################################* * Step 2. Process spawn options for child. *##################################################################*/ @@ -480,7 +508,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) (g, a, spawner_group.is_main) } else { // Child is in a separate group from spawner. - let g = unstable::exclusive(Some(TaskGroupData { + let g = exclusive(Some(TaskGroupData { members: new_taskset(), descendants: new_taskset(), })); @@ -500,7 +528,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) }; assert!(new_generation < uint::max_value); // Build a new node in the ancestor list. - AncestorList(Some(unstable::exclusive(AncestorNode { + AncestorList(Some(exclusive(AncestorNode { generation: new_generation, parent_group: Some(spawner_group.tasks.clone()), ancestors: old_ancestors, @@ -557,7 +585,7 @@ fn spawn_raw_newsched(_opts: TaskOpts, f: ~fn()) { sched.schedule_new_task(task); } -fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) { +fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { let (child_tg, ancestors, is_main) = gen_child_taskgroup(opts.linked, opts.supervised); @@ -624,10 +652,13 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) { }; if enlist_many(child, &child_arc, &mut ancestors) { - let group = @TCB(child, child_arc, ancestors, - is_main, notifier); + let group = @@mut TCB(child, + child_arc, + ancestors, + is_main, + notifier); unsafe { - local_set(child, taskgroup_key!(), group); + local_set(OldHandle(child), taskgroup_key!(), group); } // Run the child's body. @@ -659,13 +690,11 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) { }; // Attempt to join every ancestor group. result = - for each_ancestor(ancestors, Some(bail)) |ancestor_tg| { + each_ancestor(ancestors, Some(bail), |ancestor_tg| { // Enlist as a descendant, not as an actual member. // Descendants don't kill ancestor groups on failure. - if !enlist_in_taskgroup(ancestor_tg, child, false) { - break; - } - }; + enlist_in_taskgroup(ancestor_tg, child, false) + }); // If any ancestor group fails, need to exit this group too. if !result { do access_group(child_arc) |child_tg| { diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs index 7b4b6994e50a5..6cc621e3419ad 100644 --- a/src/libcore/to_bytes.rs +++ b/src/libcore/to_bytes.rs @@ -17,9 +17,15 @@ The `ToBytes` and `IterBytes` traits use io; use io::Writer; use option::{None, Option, Some}; +use old_iter::BaseIter; use str; -pub type Cb<'self> = &'self fn(buf: &const [u8]) -> bool; +pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; + +#[cfg(stage0)] +pub trait IterBytes { + fn iter_bytes(&self, lsb0: bool, f: Cb); +} /** * A trait to implement in order to make a type hashable; @@ -28,6 +34,7 @@ pub type Cb<'self> = &'self fn(buf: &const [u8]) -> bool; * modified when default methods and trait inheritence are * completed. */ +#[cfg(not(stage0))] pub trait IterBytes { /** * Call the provided callback `f` one or more times with @@ -43,9 +50,10 @@ pub trait IterBytes { * left-to-right in declaration order, regardless of * underlying memory endianness. */ - fn iter_bytes(&self, lsb0: bool, f: Cb); + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool; } +#[cfg(stage0)] impl IterBytes for bool { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) { @@ -54,7 +62,17 @@ impl IterBytes for bool { ]); } } +#[cfg(not(stage0))] +impl IterBytes for bool { + #[inline(always)] + fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { + f([ + *self as u8 + ]) + } +} +#[cfg(stage0)] impl IterBytes for u8 { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) { @@ -63,7 +81,17 @@ impl IterBytes for u8 { ]); } } +#[cfg(not(stage0))] +impl IterBytes for u8 { + #[inline(always)] + fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { + f([ + *self + ]) + } +} +#[cfg(stage0)] impl IterBytes for u16 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -80,7 +108,25 @@ impl IterBytes for u16 { } } } +#[cfg(not(stage0))] +impl IterBytes for u16 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + if lsb0 { + f([ + *self as u8, + (*self >> 8) as u8 + ]) + } else { + f([ + (*self >> 8) as u8, + *self as u8 + ]) + } + } +} +#[cfg(stage0)] impl IterBytes for u32 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -101,7 +147,29 @@ impl IterBytes for u32 { } } } +#[cfg(not(stage0))] +impl IterBytes for u32 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + if lsb0 { + f([ + *self as u8, + (*self >> 8) as u8, + (*self >> 16) as u8, + (*self >> 24) as u8, + ]) + } else { + f([ + (*self >> 24) as u8, + (*self >> 16) as u8, + (*self >> 8) as u8, + *self as u8 + ]) + } + } +} +#[cfg(stage0)] impl IterBytes for u64 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -130,73 +198,157 @@ impl IterBytes for u64 { } } } +#[cfg(not(stage0))] +impl IterBytes for u64 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + if lsb0 { + f([ + *self as u8, + (*self >> 8) as u8, + (*self >> 16) as u8, + (*self >> 24) as u8, + (*self >> 32) as u8, + (*self >> 40) as u8, + (*self >> 48) as u8, + (*self >> 56) as u8 + ]) + } else { + f([ + (*self >> 56) as u8, + (*self >> 48) as u8, + (*self >> 40) as u8, + (*self >> 32) as u8, + (*self >> 24) as u8, + (*self >> 16) as u8, + (*self >> 8) as u8, + *self as u8 + ]) + } + } +} +#[cfg(stage0)] impl IterBytes for i8 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for i8 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u8).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for i16 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as u16).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for i16 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u16).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for i32 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as u32).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for i32 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u32).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for i64 { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as u64).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for i64 { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u64).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for char { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as u32).iter_bytes(lsb0, f) } } - -#[cfg(target_word_size = "32")] -pub mod x32 { - use to_bytes::{Cb, IterBytes}; - - impl IterBytes for uint { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) { - (*self as u32).iter_bytes(lsb0, f) - } +#[cfg(not(stage0))] +impl IterBytes for char { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u32).iter_bytes(lsb0, f) } } -#[cfg(target_word_size = "64")] -pub mod x64 { - use to_bytes::{Cb, IterBytes}; +#[cfg(target_word_size = "32", stage0)] +impl IterBytes for uint { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) { + (*self as u32).iter_bytes(lsb0, f) + } +} +#[cfg(target_word_size = "32", not(stage0))] +impl IterBytes for uint { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u32).iter_bytes(lsb0, f) + } +} - impl IterBytes for uint { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) { - (*self as u64).iter_bytes(lsb0, f) - } +#[cfg(target_word_size = "64", stage0)] +impl IterBytes for uint { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) { + (*self as u64).iter_bytes(lsb0, f) + } +} +#[cfg(target_word_size = "64", not(stage0))] +impl IterBytes for uint { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as u64).iter_bytes(lsb0, f) } } +#[cfg(stage0)] impl IterBytes for int { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as uint).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for int { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl<'self,A:IterBytes> IterBytes for &'self [A] { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -207,7 +359,15 @@ impl<'self,A:IterBytes> IterBytes for &'self [A] { } } } +#[cfg(not(stage0))] +impl<'self,A:IterBytes> IterBytes for &'self [A] { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + self.each(|elt| elt.iter_bytes(lsb0, |b| f(b))) + } +} +#[cfg(stage0)] impl IterBytes for (A,B) { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -218,7 +378,17 @@ impl IterBytes for (A,B) { } } } +#[cfg(not(stage0))] +impl IterBytes for (A,B) { + #[inline(always)] + 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) } + } + } +} +#[cfg(stage0)] impl IterBytes for (A,B,C) { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -229,26 +399,57 @@ impl IterBytes for (A,B,C) { } } } +#[cfg(not(stage0))] +impl IterBytes for (A,B,C) { + #[inline(always)] + 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) + } + } + } +} // Move this to vec, probably. fn borrow<'x,A>(a: &'x [A]) -> &'x [A] { a } +#[cfg(stage0)] impl IterBytes for ~[A] { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { borrow(*self).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for ~[A] { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + borrow(*self).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for @[A] { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { borrow(*self).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for @[A] { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + borrow(*self).iter_bytes(lsb0, f) + } +} + +// NOTE: remove all of these after a snapshot, the new for-loop iteration +// protocol makes these unnecessary. +#[cfg(stage0)] pub fn iter_bytes_2(a: &A, b: &B, lsb0: bool, z: Cb) { let mut flag = true; @@ -256,11 +457,17 @@ pub fn iter_bytes_2(a: &A, b: &B, if !flag { return; } b.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); } +#[cfg(not(stage0))] +pub fn iter_bytes_2(a: &A, b: &B, + lsb0: bool, z: Cb) -> bool { + a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) +} +#[cfg(stage0)] pub fn iter_bytes_3(a: &A, b: &B, c: &C, - lsb0: bool, z: Cb) { + B: IterBytes, + C: IterBytes>(a: &A, b: &B, c: &C, + lsb0: bool, z: Cb) { let mut flag = true; a.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); if !flag { return; } @@ -268,7 +475,14 @@ pub fn iter_bytes_3(a: &A, b: &B, c: &C, lsb0: bool, z: Cb) -> bool { + a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) +} +#[cfg(stage0)] pub fn iter_bytes_4(a: &A, b: &B, c: &C, - d: &D, e: &E, - lsb0: bool, z: Cb) { - let mut flag = true; - a.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - b.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - c.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - d.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - e.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); + D: IterBytes>(a: &A, b: &B, c: &C, + d: &D, + lsb0: bool, z: Cb) -> bool { + a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) && + d.iter_bytes(lsb0, z) } -pub fn iter_bytes_6(a: &A, b: &B, c: &C, - d: &D, e: &E, f: &F, + E: IterBytes>(a: &A, b: &B, c: &C, + d: &D, e: &E, lsb0: bool, z: Cb) { let mut flag = true; a.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); @@ -322,36 +527,20 @@ pub fn iter_bytes_6(a: &A, b: &B, c: &C, - d: &D, e: &E, f: &F, - g: &G, - lsb0: bool, z: Cb) { - let mut flag = true; - a.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - b.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - c.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - d.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - e.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - f.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); - if !flag { return; } - g.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag}); + E: IterBytes>(a: &A, b: &B, c: &C, + d: &D, e: &E, + lsb0: bool, z: Cb) -> bool { + a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) && + d.iter_bytes(lsb0, z) && e.iter_bytes(lsb0, z) } +#[cfg(stage0)] impl<'self> IterBytes for &'self str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) { @@ -360,7 +549,17 @@ impl<'self> IterBytes for &'self str { } } } +#[cfg(not(stage0))] +impl<'self> IterBytes for &'self str { + #[inline(always)] + fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { + do str::byte_slice(*self) |bytes| { + f(bytes) + } + } +} +#[cfg(stage0)] impl IterBytes for ~str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) { @@ -369,7 +568,17 @@ impl IterBytes for ~str { } } } +#[cfg(not(stage0))] +impl IterBytes for ~str { + #[inline(always)] + fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { + do str::byte_slice(*self) |bytes| { + f(bytes) + } + } +} +#[cfg(stage0)] impl IterBytes for @str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) { @@ -378,7 +587,17 @@ impl IterBytes for @str { } } } +#[cfg(not(stage0))] +impl IterBytes for @str { + #[inline(always)] + fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { + do str::byte_slice(*self) |bytes| { + f(bytes) + } + } +} +#[cfg(stage0)] impl IterBytes for Option { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { @@ -388,39 +607,82 @@ impl IterBytes for Option { } } } +#[cfg(not(stage0))] +impl IterBytes for Option { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + match *self { + Some(ref a) => 0u8.iter_bytes(lsb0, f) && a.iter_bytes(lsb0, f), + None => 1u8.iter_bytes(lsb0, f) + } + } +} +#[cfg(stage0)] impl<'self,A:IterBytes> IterBytes for &'self A { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (**self).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl<'self,A:IterBytes> IterBytes for &'self A { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (**self).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for @A { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (**self).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl IterBytes for @A { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (**self).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl IterBytes for ~A { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (**self).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl IterBytes for ~A { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (**self).iter_bytes(lsb0, f) + } +} // NB: raw-pointer IterBytes does _not_ dereference // to the target; it just gives you the pointer-bytes. +#[cfg(stage0)] impl IterBytes for *const A { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: Cb) { (*self as uint).iter_bytes(lsb0, f); } } +// NB: raw-pointer IterBytes does _not_ dereference +// to the target; it just gives you the pointer-bytes. +#[cfg(not(stage0))] +impl IterBytes for *const A { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} - -trait ToBytes { +pub trait ToBytes { fn to_bytes(&self, lsb0: bool) -> ~[u8]; } diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs index 7f8e6915add16..365cb847740b2 100644 --- a/src/libcore/to_str.rs +++ b/src/libcore/to_str.rs @@ -14,7 +14,13 @@ The `ToStr` trait for converting to strings */ -use str; +use str::OwnedStr; +use hashmap::HashMap; +use hashmap::HashSet; +use container::Map; +use hash::Hash; +use cmp::Eq; +use old_iter::BaseIter; pub trait ToStr { fn to_str(&self) -> ~str; @@ -46,6 +52,44 @@ impl ToStr for (A,) { } } +impl ToStr for HashMap { + #[inline(always)] + fn to_str(&self) -> ~str { + let mut acc = ~"{", first = true; + for self.each |key, value| { + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(key.to_str()); + acc.push_str(": "); + acc.push_str(value.to_str()); + } + acc.push_char('}'); + acc + } +} + +impl ToStr for HashSet { + #[inline(always)] + fn to_str(&self) -> ~str { + let mut acc = ~"{", first = true; + for self.each |element| { + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(element.to_str()); + } + acc.push_char('}'); + acc + } +} + impl ToStr for (A, B) { #[inline(always)] fn to_str(&self) -> ~str { @@ -58,6 +102,7 @@ impl ToStr for (A, B) { } } } + impl ToStr for (A, B, C) { #[inline(always)] fn to_str(&self) -> ~str { @@ -80,11 +125,15 @@ impl<'self,A:ToStr> ToStr for &'self [A] { fn to_str(&self) -> ~str { let mut acc = ~"[", first = true; for self.each |elt| { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(elt.to_str()); } - str::push_char(&mut acc, ']'); + acc.push_char(']'); acc } } @@ -94,11 +143,15 @@ impl ToStr for ~[A] { fn to_str(&self) -> ~str { let mut acc = ~"[", first = true; for self.each |elt| { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(elt.to_str()); } - str::push_char(&mut acc, ']'); + acc.push_char(']'); acc } } @@ -108,11 +161,15 @@ impl ToStr for @[A] { fn to_str(&self) -> ~str { let mut acc = ~"[", first = true; for self.each |elt| { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(elt.to_str()); } - str::push_char(&mut acc, ']'); + acc.push_char(']'); acc } } @@ -120,6 +177,9 @@ impl ToStr for @[A] { #[cfg(test)] #[allow(non_implicitly_copyable_typarams)] mod tests { + use hashmap::HashMap; + use hashmap::HashSet; + use container::Set; #[test] fn test_simple_types() { assert!(1i.to_str() == ~"1"); @@ -149,4 +209,32 @@ mod tests { assert!((~[~[], ~[1], ~[1, 1]]).to_str() == ~"[[], [1], [1, 1]]"); } + + #[test] + fn test_hashmap() { + let mut table: HashMap = HashMap::new(); + let empty: HashMap = HashMap::new(); + + table.insert(3, 4); + table.insert(1, 2); + + let table_str = table.to_str(); + + assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}"); + assert!(empty.to_str() == ~"{}"); + } + + #[test] + fn test_hashset() { + let mut set: HashSet = HashSet::new(); + let empty_set: HashSet = HashSet::new(); + + set.insert(1); + set.insert(2); + + let set_str = set.to_str(); + + assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}"); + assert!(empty_set.to_str() == ~"{}"); + } } diff --git a/src/libcore/trie.rs b/src/libcore/trie.rs index f4e9ddbdd90a1..05ef1cf433faf 100644 --- a/src/libcore/trie.rs +++ b/src/libcore/trie.rs @@ -11,6 +11,7 @@ //! An ordered map and set for integer keys implemented as a radix trie use prelude::*; +use util::{swap, replace}; // FIXME: #5244: need to manually update the TrieNode constructor static SHIFT: uint = 4; @@ -57,73 +58,60 @@ impl Map for TrieMap { /// Visit all key-value pairs in order #[inline(always)] #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) { + fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each(f); } /// Visit all key-value pairs in order #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { - self.root.each(f); + #[cfg(not(stage0))] + fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { + self.root.each(f) } /// Visit all keys in order #[inline(always)] + #[cfg(stage0)] fn each_key(&self, f: &fn(&uint) -> bool) { self.each(|k, _| f(k)) } + /// Visit all keys in order + #[inline(always)] + #[cfg(not(stage0))] + fn each_key(&self, f: &fn(&uint) -> bool) -> bool { + self.each(|k, _| f(k)) + } + /// Visit all values in order #[inline(always)] #[cfg(stage0)] - fn each_value(&self, f: &fn(&T) -> bool) { + fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) { self.each(|_, v| f(v)) } /// Visit all values in order #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) { + #[cfg(not(stage0))] + fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) -> bool { self.each(|_, v| f(v)) } /// Iterate over the map and mutate the contained values #[inline(always)] + #[cfg(stage0)] fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) { self.root.mutate_values(f); } - /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(hint)] - fn find(&self, key: &uint) -> Option<&'self T> { - let mut node: &'self TrieNode = &self.root; - let mut idx = 0; - loop { - match node.children[chunk(*key, idx)] { - Internal(ref x) => node = &**x, - External(stored, ref value) => { - if stored == *key { - return Some(value) - } else { - return None - } - } - Nothing => return None - } - idx += 1; - } + /// Iterate over the map and mutate the contained values + #[inline(always)] + #[cfg(not(stage0))] + fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) -> bool { + self.root.mutate_values(f) } /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(hint)] fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { let mut node: &'a TrieNode = &self.root; @@ -145,16 +133,6 @@ impl Map for TrieMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(always)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut T> { - find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) @@ -165,21 +143,33 @@ impl Map for TrieMap { /// not already exist in the map. #[inline(always)] fn insert(&mut self, key: uint, value: T) -> bool { - let ret = insert(&mut self.root.count, - &mut self.root.children[chunk(key, 0)], - key, value, 1); - if ret { self.length += 1 } - ret + self.swap(key, value).is_none() } /// Remove a key-value pair from the map. Return true if the key /// was present in the map, otherwise false. #[inline(always)] fn remove(&mut self, key: &uint) -> bool { + self.pop(key).is_some() + } + + /// Insert a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise None is returned. + fn swap(&mut self, key: uint, value: T) -> Option { + let ret = insert(&mut self.root.count, + &mut self.root.children[chunk(key, 0)], + key, value, 1); + if ret.is_none() { self.length += 1 } + ret + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + fn pop(&mut self, key: &uint) -> Option { let ret = remove(&mut self.root.count, &mut self.root.children[chunk(*key, 0)], *key, 1); - if ret { self.length -= 1 } + if ret.is_some() { self.length -= 1 } ret } } @@ -194,30 +184,42 @@ pub impl TrieMap { /// Visit all key-value pairs in reverse order #[inline(always)] #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) { + fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each_reverse(f); } /// Visit all key-value pairs in reverse order #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { - self.root.each_reverse(f); + #[cfg(not(stage0))] + fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { + self.root.each_reverse(f) } /// Visit all keys in reverse order #[inline(always)] + #[cfg(stage0)] fn each_key_reverse(&self, f: &fn(&uint) -> bool) { self.each_reverse(|k, _| f(k)) } + /// Visit all keys in reverse order + #[inline(always)] + #[cfg(not(stage0))] + fn each_key_reverse(&self, f: &fn(&uint) -> bool) -> bool { + self.each_reverse(|k, _| f(k)) + } /// Visit all values in reverse order #[inline(always)] + #[cfg(stage0)] fn each_value_reverse(&self, f: &fn(&T) -> bool) { self.each_reverse(|_, v| f(v)) } + /// Visit all values in reverse order + #[inline(always)] + #[cfg(not(stage0))] + fn each_value_reverse(&self, f: &fn(&T) -> bool) -> bool { + self.each_reverse(|_, v| f(v)) + } } pub struct TrieSet { @@ -227,7 +229,10 @@ pub struct TrieSet { impl BaseIter for TrieSet { /// Visit all values in order #[inline(always)] + #[cfg(stage0)] fn each(&self, f: &fn(&uint) -> bool) { self.map.each_key(f) } + #[cfg(not(stage0))] + fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } } @@ -235,9 +240,14 @@ impl BaseIter for TrieSet { impl ReverseIter for TrieSet { /// Visit all values in reverse order #[inline(always)] + #[cfg(stage0)] fn each_reverse(&self, f: &fn(&uint) -> bool) { self.map.each_key_reverse(f) } + #[cfg(not(stage0))] + fn each_reverse(&self, f: &fn(&uint) -> bool) -> bool { + self.map.each_key_reverse(f) + } } impl Container for TrieSet { @@ -298,21 +308,6 @@ impl TrieNode { } impl TrieNode { - #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) -> bool { - for uint::range(0, self.children.len()) |idx| { - match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { @@ -324,21 +319,6 @@ impl TrieNode { true } - #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self 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 }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] 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] { @@ -371,9 +351,9 @@ fn chunk(n: uint, idx: uint) -> uint { (n >> sh) & MASK } -fn find_mut<'r, T>(child: &'r mut Child, key: uint, idx: uint) - -> Option<&'r mut T> { - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker +#[cfg(stage0)] +fn find_mut<'r, T>(child: &'r mut Child, key: uint, idx: uint) -> Option<&'r mut T> { + unsafe { (match *child { External(_, ref value) => Some(cast::transmute_mut(value)), Internal(ref x) => find_mut(cast::transmute_mut(&x.children[chunk(key, idx)]), @@ -383,15 +363,25 @@ fn find_mut<'r, T>(child: &'r mut Child, key: uint, idx: uint) } } +#[cfg(not(stage0))] +fn find_mut<'r, T>(child: &'r mut Child, key: uint, idx: uint) -> Option<&'r mut T> { + match *child { + External(_, ref mut value) => Some(value), + Internal(ref mut x) => find_mut(&mut x.children[chunk(key, idx)], key, idx + 1), + Nothing => None + } +} + fn insert(count: &mut uint, child: &mut Child, key: uint, value: T, - idx: uint) -> bool { + idx: uint) -> Option { let mut tmp = Nothing; - tmp <-> *child; - let mut added = false; + let ret; + swap(&mut tmp, child); *child = match tmp { External(stored_key, stored_value) => { if stored_key == key { + ret = Some(stored_value); External(stored_key, value) } else { // conflict - split the node @@ -399,46 +389,49 @@ fn insert(count: &mut uint, child: &mut Child, key: uint, value: T, insert(&mut new.count, &mut new.children[chunk(stored_key, idx)], stored_key, stored_value, idx + 1); - insert(&mut new.count, &mut new.children[chunk(key, idx)], key, - value, idx + 1); - added = true; + ret = insert(&mut new.count, &mut new.children[chunk(key, idx)], + key, value, idx + 1); Internal(new) } } Internal(x) => { let mut x = x; - added = insert(&mut x.count, &mut x.children[chunk(key, idx)], key, - value, idx + 1); + ret = insert(&mut x.count, &mut x.children[chunk(key, idx)], key, + value, idx + 1); Internal(x) } Nothing => { *count += 1; - added = true; + ret = None; External(key, value) } }; - added + return ret; } fn remove(count: &mut uint, child: &mut Child, key: uint, - idx: uint) -> bool { + idx: uint) -> Option { let (ret, this) = match *child { - External(stored, _) => { - if stored == key { (true, true) } else { (false, false) } + External(stored, _) if stored == key => { + match replace(child, Nothing) { + External(_, value) => (Some(value), true), + _ => fail!() + } } + External(*) => (None, false), Internal(ref mut x) => { let ret = remove(&mut x.count, &mut x.children[chunk(key, idx)], key, idx + 1); (ret, x.count == 0) } - Nothing => (false, false) + Nothing => (None, false) }; if this { *child = Nothing; *count -= 1; } - ret + return ret; } #[cfg(test)] @@ -611,4 +604,20 @@ mod tests { i += 1; } } + + #[test] + fn test_swap() { + let mut m = TrieMap::new(); + assert!(m.swap(1, 2) == None); + assert!(m.swap(1, 3) == Some(2)); + assert!(m.swap(1, 4) == Some(3)); + } + + #[test] + fn test_pop() { + let mut m = TrieMap::new(); + m.insert(1, 2); + assert!(m.pop(&1) == Some(2)); + assert!(m.pop(&1) == None); + } } diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index a2b6f0eb1a714..b29a4e55426df 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -14,7 +14,7 @@ use clone::Clone; use kinds::Copy; use vec; -#[cfg(notest)] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::{Eq, Ord}; pub trait CopyableTuple { fn first(&self) -> T; @@ -56,39 +56,11 @@ impl Clone for (T, U) { } } -#[cfg(stage0)] -pub trait ImmutableTuple { - fn first_ref(&self) -> &'self T; - fn second_ref(&self) -> &'self U; -} - -#[cfg(stage0)] -impl ImmutableTuple for (T, U) { - #[inline(always)] - fn first_ref(&self) -> &'self T { - match *self { - (ref t, _) => t, - } - } - #[inline(always)] - fn second_ref(&self) -> &'self U { - match *self { - (_, ref u) => u, - } - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableTuple { fn first_ref<'a>(&'a self) -> &'a T; fn second_ref<'a>(&'a self) -> &'a U; } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl ImmutableTuple for (T, U) { #[inline(always)] fn first_ref<'a>(&'a self) -> &'a T { @@ -150,7 +122,7 @@ impl ExtendedTupleOps for (~[A], ~[B]) { } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for (A,) { #[inline(always)] fn eq(&self, other: &(A,)) -> bool { @@ -166,7 +138,7 @@ impl Eq for (A,) { fn ne(&self, other: &(A,)) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for (A,) { #[inline(always)] fn lt(&self, other: &(A,)) -> bool { @@ -189,7 +161,7 @@ impl Ord for (A,) { fn gt(&self, other: &(A,)) -> bool { other.lt(&(*self)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for (A, B) { #[inline(always)] fn eq(&self, other: &(A, B)) -> bool { @@ -205,7 +177,7 @@ impl Eq for (A, B) { fn ne(&self, other: &(A, B)) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for (A, B) { #[inline(always)] fn lt(&self, other: &(A, B)) -> bool { @@ -230,7 +202,7 @@ impl Ord for (A, B) { fn gt(&self, other: &(A, B)) -> bool { (*other).lt(&(*self)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for (A, B, C) { #[inline(always)] fn eq(&self, other: &(A, B, C)) -> bool { @@ -247,7 +219,7 @@ impl Eq for (A, B, C) { fn ne(&self, other: &(A, B, C)) -> bool { !(*self).eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for (A, B, C) { #[inline(always)] fn lt(&self, other: &(A, B, C)) -> bool { diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs index a13d66c48ee0c..d6e2c5eee6aca 100644 --- a/src/libcore/unicode.rs +++ b/src/libcore/unicode.rs @@ -10,6 +10,8 @@ #[doc(hidden)]; // FIXME #3538 +// The following code was generated by "src/etc/unicode.py" + pub mod general_category { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { @@ -2640,4 +2642,3 @@ pub mod derived_property { bsearch_range_table(c, XID_Start_table) } } - diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs deleted file mode 100644 index 4a69de26f6b13..0000000000000 --- a/src/libcore/unstable.rs +++ /dev/null @@ -1,339 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; - -use cast; -use libc; -use comm::{GenericChan, GenericPort}; -use prelude::*; -use task; -use task::atomically; -use self::finally::Finally; - -#[path = "unstable/at_exit.rs"] -pub mod at_exit; -#[path = "unstable/global.rs"] -pub mod global; -#[path = "unstable/finally.rs"] -pub mod finally; -#[path = "unstable/weak_task.rs"] -pub mod weak_task; -#[path = "unstable/exchange_alloc.rs"] -pub mod exchange_alloc; -#[path = "unstable/intrinsics.rs"] -pub mod intrinsics; -#[path = "unstable/extfmt.rs"] -pub mod extfmt; -#[path = "unstable/lang.rs"] -#[cfg(notest)] -pub mod lang; - -mod rustrt { - use unstable::{raw_thread, rust_little_lock}; - - pub extern { - pub unsafe fn rust_create_little_lock() -> rust_little_lock; - pub unsafe fn rust_destroy_little_lock(lock: rust_little_lock); - pub unsafe fn rust_lock_little_lock(lock: rust_little_lock); - pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock); - - pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; - pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); - } -} - -#[allow(non_camel_case_types)] // runtime type -pub type raw_thread = libc::c_void; - -/** - -Start a new thread outside of the current runtime context and wait -for it to terminate. - -The executing thread has no access to a task pointer and will be using -a normal large stack. -*/ -pub fn run_in_bare_thread(f: ~fn()) { - let (port, chan) = comm::stream(); - // FIXME #4525: Unfortunate that this creates an extra scheduler but it's - // necessary since rust_raw_thread_join_delete is blocking - do task::spawn_sched(task::SingleThreaded) { - unsafe { - let closure: &fn() = || { - f() - }; - let thread = rustrt::rust_raw_thread_start(&closure); - rustrt::rust_raw_thread_join_delete(thread); - chan.send(()); - } - } - port.recv(); -} - -#[test] -fn test_run_in_bare_thread() { - let i = 100; - do run_in_bare_thread { - assert!(i == 100); - } -} - -#[test] -fn test_run_in_bare_thread_exchange() { - // Does the exchange heap work without the runtime? - let i = ~100; - do run_in_bare_thread { - assert!(i == ~100); - } -} - -fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { - unsafe { - let old = intrinsics::atomic_cxchg(address, oldval, newval); - old == oldval - } -} - -/**************************************************************************** - * Shared state & exclusive ARC - ****************************************************************************/ - -struct ArcData { - count: libc::intptr_t, - // FIXME(#3224) should be able to make this non-option to save memory - data: Option, -} - -struct ArcDestruct { - data: *libc::c_void, -} - -#[unsafe_destructor] -impl Drop for ArcDestruct{ - fn finalize(&self) { - unsafe { - do task::unkillable { - let mut data: ~ArcData = cast::transmute(self.data); - let new_count = - intrinsics::atomic_xsub(&mut data.count, 1) - 1; - assert!(new_count >= 0); - if new_count == 0 { - // drop glue takes over. - } else { - cast::forget(data); - } - } - } - } -} - -fn ArcDestruct(data: *libc::c_void) -> ArcDestruct { - ArcDestruct { - data: data - } -} - -/** - * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc. - * - * Data races between tasks can result in crashes and, with sufficient - * cleverness, arbitrary type coercion. - */ -pub type SharedMutableState = ArcDestruct; - -pub unsafe fn shared_mutable_state(data: T) -> - SharedMutableState { - let data = ~ArcData { count: 1, data: Some(data) }; - let ptr = cast::transmute(data); - ArcDestruct(ptr) -} - -#[inline(always)] -pub unsafe fn get_shared_mutable_state( - rc: *SharedMutableState) -> *mut T -{ - let ptr: ~ArcData = cast::transmute((*rc).data); - assert!(ptr.count > 0); - let r = cast::transmute(ptr.data.get_ref()); - cast::forget(ptr); - return r; -} -#[inline(always)] -pub unsafe fn get_shared_immutable_state<'a,T:Owned>( - rc: &'a SharedMutableState) -> &'a T { - let ptr: ~ArcData = cast::transmute((*rc).data); - assert!(ptr.count > 0); - // Cast us back into the correct region - let r = cast::transmute_region(ptr.data.get_ref()); - cast::forget(ptr); - return r; -} - -pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) - -> SharedMutableState { - let mut ptr: ~ArcData = cast::transmute((*rc).data); - let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; - assert!(new_count >= 2); - cast::forget(ptr); - ArcDestruct((*rc).data) -} - -impl Clone for SharedMutableState { - fn clone(&self) -> SharedMutableState { - unsafe { - clone_shared_mutable_state(self) - } - } -} - -/****************************************************************************/ - -#[allow(non_camel_case_types)] // runtime type -pub type rust_little_lock = *libc::c_void; - -struct LittleLock { - l: rust_little_lock, -} - -impl Drop for LittleLock { - fn finalize(&self) { - unsafe { - rustrt::rust_destroy_little_lock(self.l); - } - } -} - -fn LittleLock() -> LittleLock { - unsafe { - LittleLock { - l: rustrt::rust_create_little_lock() - } - } -} - -pub impl LittleLock { - #[inline(always)] - unsafe fn lock(&self, f: &fn() -> T) -> T { - do atomically { - rustrt::rust_lock_little_lock(self.l); - do (|| { - f() - }).finally { - rustrt::rust_unlock_little_lock(self.l); - } - } - } -} - -struct ExData { lock: LittleLock, failed: bool, data: T, } -/** - * An arc over mutable data that is protected by a lock. For library use only. - */ -pub struct Exclusive { x: SharedMutableState> } - -pub fn exclusive(user_data: T) -> Exclusive { - let data = ExData { - lock: LittleLock(), failed: false, data: user_data - }; - Exclusive { x: unsafe { shared_mutable_state(data) } } -} - -impl Clone for Exclusive { - // Duplicate an exclusive ARC, as std::arc::clone. - fn clone(&self) -> Exclusive { - Exclusive { x: unsafe { clone_shared_mutable_state(&self.x) } } - } -} - -pub impl Exclusive { - // Exactly like std::arc::mutex_arc,access(), but with the little_lock - // instead of a proper mutex. Same reason for being unsafe. - // - // Currently, scheduling operations (i.e., yielding, receiving on a pipe, - // accessing the provided condition variable) are prohibited while inside - // the exclusive. Supporting that is a work in progress. - #[inline(always)] - unsafe fn with(&self, f: &fn(x: &mut T) -> U) -> U { - let rec = get_shared_mutable_state(&self.x); - do (*rec).lock.lock { - if (*rec).failed { - fail!( - ~"Poisoned exclusive - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result - } - } - - #[inline(always)] - unsafe fn with_imm(&self, f: &fn(x: &T) -> U) -> U { - do self.with |x| { - f(cast::transmute_immut(x)) - } - } -} - -#[cfg(test)] -mod tests { - use comm; - use super::exclusive; - use task; - use uint; - - #[test] - fn exclusive_arc() { - let mut futures = ~[]; - - let num_tasks = 10; - let count = 10; - - let total = exclusive(~0); - - for uint::range(0, num_tasks) |_i| { - let total = total.clone(); - let (port, chan) = comm::stream(); - futures.push(port); - - do task::spawn || { - for uint::range(0, count) |_i| { - do total.with |count| { - **count += 1; - } - } - chan.send(()); - } - }; - - for futures.each |f| { f.recv() } - - do total.with |total| { - assert!(**total == num_tasks * count) - }; - } - - #[test] #[should_fail] #[ignore(cfg(windows))] - fn exclusive_poison() { - // Tests that if one task fails inside of an exclusive, subsequent - // accesses will also fail. - let x = exclusive(1); - let x2 = x.clone(); - do task::try || { - do x2.with |one| { - assert!(*one == 2); - } - }; - do x.with |one| { - assert!(*one == 1); - } - } -} diff --git a/src/libcore/unstable/at_exit.rs b/src/libcore/unstable/at_exit.rs index bc4ec620aa86a..39c930d415f1c 100644 --- a/src/libcore/unstable/at_exit.rs +++ b/src/libcore/unstable/at_exit.rs @@ -62,14 +62,17 @@ fn exit_runner(exit_fns: *ExitFunctions) { // give us ownership of the array of functions let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; // Let's not make any promises about execution order - rand::rng().shuffle_mut(exit_fns_vec); + let mut rng = rand::rng(); + rng.shuffle_mut(exit_fns_vec); debug!("running %u exit functions", exit_fns_vec.len()); while !exit_fns_vec.is_empty() { match exit_fns_vec.pop() { ~f => { - task::task().supervised().spawn(f); + let mut task = task::task(); + task.supervised(); + task.spawn(f); } } } diff --git a/src/libcore/unstable/exchange_alloc.rs b/src/libcore/unstable/exchange_alloc.rs index 8ca5486d92992..57ed579e88dda 100644 --- a/src/libcore/unstable/exchange_alloc.rs +++ b/src/libcore/unstable/exchange_alloc.rs @@ -81,4 +81,3 @@ extern { #[rust_stack] fn rust_get_exchange_count_ptr() -> *mut int; } - diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs index b812be5575a4a..11ac8c14fe46d 100644 --- a/src/libcore/unstable/extfmt.rs +++ b/src/libcore/unstable/extfmt.rs @@ -257,12 +257,12 @@ pub mod ct { let mut flags = ~[]; while i < lim { - let f = match s[i] { - '-' as u8 => FlagLeftJustify, - '0' as u8 => FlagLeftZeroPad, - ' ' as u8 => FlagSpaceForSign, - '+' as u8 => FlagSignAlways, - '#' as u8 => FlagAlternate, + let f = match s[i] as char { + '-' => FlagLeftJustify, + '0' => FlagLeftZeroPad, + ' ' => FlagSpaceForSign, + '+' => FlagSignAlways, + '#' => FlagAlternate, _ => break }; @@ -313,18 +313,18 @@ pub mod ct { // FIXME (#2249): Do we really want two signed types here? // How important is it to be printf compatible? - let t = match s[i] { - 'b' as u8 => TyBool, - 's' as u8 => TyStr, - 'c' as u8 => TyChar, - 'd' as u8 | 'i' as u8 => TyInt(Signed), - 'u' as u8 => TyInt(Unsigned), - 'x' as u8 => TyHex(CaseLower), - 'X' as u8 => TyHex(CaseUpper), - 't' as u8 => TyBits, - 'o' as u8 => TyOctal, - 'f' as u8 => TyFloat, - '?' as u8 => TyPoly, + let t = match s[i] as char { + 'b' => TyBool, + 's' => TyStr, + 'c' => TyChar, + 'd' | 'i' => TyInt(Signed), + 'u' => TyInt(Unsigned), + 'x' => TyHex(CaseLower), + 'X' => TyHex(CaseUpper), + 't' => TyBits, + 'o' => TyOctal, + 'f' => TyFloat, + '?' => TyPoly, _ => err(~"unknown type in conversion: " + s.substr(i, 1)) }; @@ -501,7 +501,7 @@ pub mod rt { pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) { let radix = 10; let prec = get_int_precision(cv); - let mut s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec); + let s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec); let head = if i >= 0 { if have_flag(cv.flags, flag_sign_always) { @@ -516,7 +516,7 @@ pub mod rt { } pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) { let prec = get_int_precision(cv); - let mut rs = + let rs = match cv.ty { TyDefault => uint_to_str_prec(u, 10, prec), TyHexLower => uint_to_str_prec(u, 16, prec), @@ -559,7 +559,7 @@ pub mod rt { CountIs(c) => (float::to_str_exact, c as uint), CountImplied => (float::to_str_digits, 6u) }; - let mut s = to_str(f, digits); + let s = to_str(f, digits); let head = if 0.0 <= f { if have_flag(cv.flags, flag_sign_always) { Some('+') @@ -688,11 +688,3 @@ mod test { let _s = fmt!("%s", s); } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/global.rs b/src/libcore/unstable/global.rs index eac686e28d1c6..88433f9cefe51 100644 --- a/src/libcore/unstable/global.rs +++ b/src/libcore/unstable/global.rs @@ -31,14 +31,13 @@ use kinds::Owned; use libc::{c_void}; use option::{Option, Some, None}; use ops::Drop; -use unstable::{Exclusive, exclusive}; +use unstable::sync::{Exclusive, exclusive}; use unstable::at_exit::at_exit; use unstable::intrinsics::atomic_cxchg; use hashmap::HashMap; use sys::Closure; -#[cfg(test)] use unstable::{SharedMutableState, shared_mutable_state}; -#[cfg(test)] use unstable::get_shared_immutable_state; +#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox}; #[cfg(test)] use task::spawn; #[cfg(test)] use uint; @@ -234,18 +233,16 @@ extern { #[test] fn test_clone_rc() { - type MyType = SharedMutableState; - - fn key(_v: SharedMutableState) { } + fn key(_v: UnsafeAtomicRcBox) { } for uint::range(0, 100) |_| { do spawn { unsafe { let val = do global_data_clone_create(key) { - ~shared_mutable_state(10) + ~UnsafeAtomicRcBox::new(10) }; - assert!(get_shared_immutable_state(&val) == &10); + assert!(val.get() == &10); } } } @@ -253,18 +250,12 @@ fn test_clone_rc() { #[test] fn test_modify() { - type MyType = SharedMutableState; - - fn key(_v: SharedMutableState) { } + fn key(_v: UnsafeAtomicRcBox) { } unsafe { do global_data_modify(key) |v| { match v { - None => { - unsafe { - Some(~shared_mutable_state(10)) - } - } + None => { Some(~UnsafeAtomicRcBox::new(10)) } _ => fail!() } } @@ -272,7 +263,7 @@ fn test_modify() { do global_data_modify(key) |v| { match v { Some(sms) => { - let v = get_shared_immutable_state(sms); + let v = sms.get(); assert!(*v == 10); None }, @@ -282,11 +273,7 @@ fn test_modify() { do global_data_modify(key) |v| { match v { - None => { - unsafe { - Some(~shared_mutable_state(10)) - } - } + None => { Some(~UnsafeAtomicRcBox::new(10)) } _ => fail!() } } diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs index b58429a10aad5..b8c0c4e4a9292 100644 --- a/src/libcore/unstable/intrinsics.rs +++ b/src/libcore/unstable/intrinsics.rs @@ -20,6 +20,16 @@ pub extern "rust-intrinsic" { pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; + #[cfg(not(stage0))] + pub fn atomic_load(src: &int) -> int; + #[cfg(not(stage0))] + pub fn atomic_load_acq(src: &int) -> int; + + #[cfg(not(stage0))] + pub fn atomic_store(dst: &mut int, val: int); + #[cfg(not(stage0))] + pub fn atomic_store_rel(dst: &mut int, val: int); + pub fn atomic_xchg(dst: &mut int, src: int) -> int; pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; @@ -34,21 +44,25 @@ pub extern "rust-intrinsic" { pub fn size_of() -> uint; - pub fn move_val(dst: &mut T, +src: T); - pub fn move_val_init(dst: &mut T, +src: T); + pub fn move_val(dst: &mut T, src: T); + pub fn move_val_init(dst: &mut T, src: T); pub fn min_align_of() -> uint; pub fn pref_align_of() -> uint; pub fn get_tydesc() -> *(); - pub fn init() -> T; + /// init is unsafe because it returns a zeroed-out datum, + /// which is unsafe unless T is POD. We don't have a POD + /// kind yet. (See #4074) + pub unsafe fn init() -> T; - pub fn forget(_: T) -> (); + #[cfg(not(stage0))] + pub unsafe fn uninit() -> T; - // XXX: intrinsic uses legacy modes - #[cfg(stage0)] - fn reinterpret_cast(&&src: T) -> U; + /// forget is unsafe because the caller is responsible for + /// ensuring the argument is deallocated already + pub unsafe fn forget(_: T) -> (); pub fn needs_drop() -> bool; diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 611862a79e7e0..8153c2d43d998 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -10,24 +10,29 @@ //! Runtime calls emitted by the compiler. +use uint; use cast::transmute; -use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; +use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; use managed::raw::BoxRepr; use str; use sys; use unstable::exchange_alloc; use cast::transmute; +use rt::{context, OldTaskContext}; +use rt::local_services::borrow_local_services; +use option::{Option, Some, None}; +use io; #[allow(non_camel_case_types)] pub type rust_task = c_void; -#[cfg(target_word_size = "32")] -pub static FROZEN_BIT: uint = 0x80000000; -#[cfg(target_word_size = "64")] -pub static FROZEN_BIT: uint = 0x8000000000000000; +pub static FROZEN_BIT: uint = 1 << (uint::bits - 1); +pub static MUT_BIT: uint = 1 << (uint::bits - 2); +static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; pub mod rustrt { - use libc::{c_char, uintptr_t}; + use unstable::lang::rust_task; + use libc::{c_void, c_char, uintptr_t}; pub extern { #[rust_stack] @@ -43,6 +48,17 @@ pub mod rustrt { #[fast_ffi] unsafe fn rust_upcall_free_noswitch(ptr: *c_char); + + #[rust_stack] + fn rust_take_task_borrow_list(task: *rust_task) -> *c_void; + + #[rust_stack] + fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); + + #[rust_stack] + fn rust_try_get_task() -> *rust_task; + + fn rust_dbg_breakpoint(); } } @@ -53,7 +69,7 @@ pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { #[lang="fail_bounds_check"] pub fn fail_bounds_check(file: *c_char, line: size_t, - index: size_t, len: size_t) { + index: size_t, len: size_t) { let msg = fmt!("index out of bounds: the len is %d but the index is %d", len as int, index as int); do str::as_buf(msg) |p, _len| { @@ -61,11 +77,74 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } -pub fn fail_borrowed() { - let msg = "borrowed"; - do str::as_buf(msg) |msg_p, _| { - do str::as_buf("???") |file_p, _| { - fail_(msg_p as *c_char, file_p as *c_char, 0); +#[deriving(Eq)] +struct BorrowRecord { + box: *mut BoxRepr, + file: *c_char, + line: size_t +} + +fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { + unsafe { + let cur_task: *rust_task = rustrt::rust_try_get_task(); + if cur_task.is_not_null() { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { + None + } else { + let v: ~[BorrowRecord] = transmute(ptr); + Some(v) + } + } else { + None + } + } +} + +fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { + unsafe { + let cur_task: *rust_task = rustrt::rust_try_get_task(); + if cur_task.is_not_null() { + let mut borrow_list: ~[BorrowRecord] = { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { ~[] } else { transmute(ptr) } + }; + borrow_list = f(borrow_list); + rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); + } + } +} + +pub unsafe fn clear_task_borrow_list() { + // pub because it is used by the box annihilator. + let _ = try_take_task_borrow_list(); +} + +unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { + debug_borrow("fail_borrowed: ", box, 0, 0, file, line); + + match try_take_task_borrow_list() { + None => { // not recording borrows + let msg = "borrowed"; + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line); + } + } + Some(borrow_list) => { // recording borrows + let mut msg = ~"borrowed"; + let mut sep = " at "; + for borrow_list.each_reverse |entry| { + if entry.box == box { + str::push_str(&mut msg, sep); + let filename = str::raw::from_c_str(entry.file); + str::push_str(&mut msg, filename); + str::push_str(&mut msg, fmt!(":%u", entry.line as uint)); + sep = " and at "; + } + } + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } } } } @@ -77,6 +156,77 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { transmute(exchange_alloc::malloc(transmute(td), transmute(size))) } +/// Because this code is so perf. sensitive, use a static constant so that +/// debug printouts are compiled out most of the time. +static ENABLE_DEBUG: bool = false; + +#[inline] +unsafe fn debug_borrow(tag: &'static str, + p: *const T, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { + //! A useful debugging function that prints a pointer + tag + newline + //! without allocating memory. + + if ENABLE_DEBUG && ::rt::env::get().debug_borrow { + debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); + } + + unsafe fn debug_borrow_slow(tag: &'static str, + p: *const T, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { + let dbg = STDERR_FILENO as io::fd_t; + dbg.write_str(tag); + dbg.write_hex(p as uint); + dbg.write_str(" "); + dbg.write_hex(old_bits); + dbg.write_str(" "); + dbg.write_hex(new_bits); + dbg.write_str(" "); + dbg.write_cstr(filename); + dbg.write_str(":"); + dbg.write_hex(line as uint); + dbg.write_str("\n"); + } +} + +trait DebugPrints { + fn write_hex(&self, val: uint); + unsafe fn write_cstr(&self, str: *c_char); +} + +impl DebugPrints for io::fd_t { + fn write_hex(&self, mut i: uint) { + let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'a', 'b', 'c', 'd', 'e', 'f']; + static uint_nibbles: uint = ::uint::bytes << 1; + let mut buffer = [0_u8, ..uint_nibbles+1]; + let mut c = uint_nibbles; + while c > 0 { + c -= 1; + buffer[c] = letters[i & 0xF] as u8; + i >>= 4; + } + self.write(buffer.slice(0, uint_nibbles)); + } + + unsafe fn write_cstr(&self, p: *c_char) { + use libc::strlen; + use vec; + + let len = strlen(p); + let p: *u8 = transmute(p); + do vec::raw::buf_as_slice(p, len as uint) |s| { + self.write(s); + } + } +} + // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. @@ -87,20 +237,39 @@ pub unsafe fn exchange_free(ptr: *c_char) { } #[lang="malloc"] -#[inline(always)] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - return rustrt::rust_upcall_malloc_noswitch(td, size); + match context() { + OldTaskContext => { + return rustrt::rust_upcall_malloc_noswitch(td, size); + } + _ => { + let mut alloc = ::ptr::null(); + do borrow_local_services |srv| { + alloc = srv.heap.alloc(td as *c_void, size as uint) as *c_char; + } + return alloc; + } + } } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. #[lang="free"] -#[inline(always)] pub unsafe fn local_free(ptr: *c_char) { - rustrt::rust_upcall_free_noswitch(ptr); + match context() { + OldTaskContext => { + rustrt::rust_upcall_free_noswitch(ptr); + } + _ => { + do borrow_local_services |srv| { + srv.heap.free(ptr as *c_void); + } + } + } } +#[cfg(stage0)] #[lang="borrow_as_imm"] #[inline(always)] pub unsafe fn borrow_as_imm(a: *u8) { @@ -108,6 +277,86 @@ pub unsafe fn borrow_as_imm(a: *u8) { (*a).header.ref_count |= FROZEN_BIT; } +#[cfg(not(stage0))] +#[lang="borrow_as_imm"] +#[inline(always)] +pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { + let a: *mut BoxRepr = transmute(a); + let old_ref_count = (*a).header.ref_count; + let new_ref_count = old_ref_count | FROZEN_BIT; + + debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line); + + if (old_ref_count & MUT_BIT) != 0 { + fail_borrowed(a, file, line); + } + + (*a).header.ref_count = new_ref_count; + + old_ref_count +} + +#[cfg(not(stage0))] +#[lang="borrow_as_mut"] +#[inline(always)] +pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { + let a: *mut BoxRepr = transmute(a); + let old_ref_count = (*a).header.ref_count; + let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT; + + debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line); + + if (old_ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { + fail_borrowed(a, file, line); + } + + (*a).header.ref_count = new_ref_count; + + old_ref_count +} + + +#[cfg(not(stage0))] +#[lang="record_borrow"] +pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, + file: *c_char, line: size_t) { + if (old_ref_count & ALL_BITS) == 0 { + // was not borrowed before + let a: *mut BoxRepr = transmute(a); + debug_borrow("record_borrow:", a, old_ref_count, 0, file, line); + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + borrow_list.push(BorrowRecord {box: a, file: file, line: line}); + borrow_list + } + } +} + +#[cfg(not(stage0))] +#[lang="unrecord_borrow"] +pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, + file: *c_char, line: size_t) { + if (old_ref_count & ALL_BITS) == 0 { + // was not borrowed before, so we should find the record at + // the end of the list + let a: *mut BoxRepr = transmute(a); + debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + assert!(!borrow_list.is_empty()); + let br = borrow_list.pop(); + if br.box != a || br.file != file || br.line != line { + let err = fmt!("wrong borrow found, br=%?", br); + do str::as_buf(err) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } + } + borrow_list + } + } +} + +#[cfg(stage0)] #[lang="return_to_mut"] #[inline(always)] pub unsafe fn return_to_mut(a: *u8) { @@ -119,12 +368,49 @@ pub unsafe fn return_to_mut(a: *u8) { } } +#[cfg(not(stage0))] +#[lang="return_to_mut"] +#[inline(always)] +pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, + file: *c_char, line: size_t) { + // Sometimes the box is null, if it is conditionally frozen. + // See e.g. #4904. + if !a.is_null() { + let a: *mut BoxRepr = transmute(a); + let old_ref_count = (*a).header.ref_count; + let new_ref_count = + (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS); + + debug_borrow("return_to_mut:", + a, old_ref_count, new_ref_count, file, line); + + (*a).header.ref_count = new_ref_count; + } +} + +#[cfg(stage0)] #[lang="check_not_borrowed"] #[inline(always)] pub unsafe fn check_not_borrowed(a: *u8) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { - fail_borrowed(); + do str::as_buf("XXX") |file_p, _| { + fail_borrowed(a, file_p as *c_char, 0); + } + } +} + +#[cfg(not(stage0))] +#[lang="check_not_borrowed"] +#[inline(always)] +pub unsafe fn check_not_borrowed(a: *u8, + file: *c_char, + line: size_t) { + let a: *mut BoxRepr = transmute(a); + let ref_count = (*a).header.ref_count; + debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line); + if (ref_count & FROZEN_BIT) != 0 { + fail_borrowed(a, file, line); } } @@ -135,32 +421,6 @@ pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str { } #[lang="start"] -#[cfg(stage0)] -pub fn start(main: *u8, argc: int, argv: *c_char, - crate_map: *u8) -> int { - use libc::getenv; - use rt::start; - - unsafe { - let use_old_rt = do str::as_c_str("RUST_NEWRT") |s| { - getenv(s).is_null() - }; - if use_old_rt { - return rust_start(main as *c_void, argc as c_int, argv, - crate_map as *c_void) as int; - } else { - return start(main, argc, argv, crate_map); - } - } - - extern { - fn rust_start(main: *c_void, argc: c_int, argv: *c_char, - crate_map: *c_void) -> c_int; - } -} - -#[lang="start"] -#[cfg(not(stage0))] pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *u8) -> int { use libc::getenv; @@ -183,11 +443,3 @@ pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *c_void) -> c_int; } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/mod.rs b/src/libcore/unstable/mod.rs new file mode 100644 index 0000000000000..bef7a7f87d3bd --- /dev/null +++ b/src/libcore/unstable/mod.rs @@ -0,0 +1,78 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(hidden)]; + +use libc; +use comm::{GenericChan, GenericPort}; +use prelude::*; +use task; + +pub mod at_exit; +pub mod global; +pub mod finally; +pub mod weak_task; +pub mod exchange_alloc; +pub mod intrinsics; +pub mod simd; +pub mod extfmt; +#[cfg(not(test))] +pub mod lang; +pub mod sync; + +/** + +Start a new thread outside of the current runtime context and wait +for it to terminate. + +The executing thread has no access to a task pointer and will be using +a normal large stack. +*/ +pub fn run_in_bare_thread(f: ~fn()) { + let (port, chan) = comm::stream(); + // FIXME #4525: Unfortunate that this creates an extra scheduler but it's + // necessary since rust_raw_thread_join_delete is blocking + do task::spawn_sched(task::SingleThreaded) { + unsafe { + let closure: &fn() = || { + f() + }; + let thread = rust_raw_thread_start(&closure); + rust_raw_thread_join_delete(thread); + chan.send(()); + } + } + port.recv(); +} + +#[test] +fn test_run_in_bare_thread() { + let i = 100; + do run_in_bare_thread { + assert!(i == 100); + } +} + +#[test] +fn test_run_in_bare_thread_exchange() { + // Does the exchange heap work without the runtime? + let i = ~100; + do run_in_bare_thread { + assert!(i == ~100); + } +} + +#[allow(non_camel_case_types)] // runtime type +pub type raw_thread = libc::c_void; + +extern { + fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; + fn rust_raw_thread_join_delete(thread: *raw_thread); +} diff --git a/src/libcore/unstable/simd.rs b/src/libcore/unstable/simd.rs new file mode 100644 index 0000000000000..a05f6e8af5a64 --- /dev/null +++ b/src/libcore/unstable/simd.rs @@ -0,0 +1,43 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! SIMD vectors + +#[allow(non_camel_case_types)]; + +#[simd] +pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); + +#[simd] +pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +#[simd] +pub struct i32x4(i32, i32, i32, i32); + +#[simd] +pub struct i64x2(i64, i64); + +#[simd] +pub struct u8x16(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8); + +#[simd] +pub struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16); + +#[simd] +pub struct u32x4(u32, u32, u32, u32); + +#[simd] +pub struct u64x2(u64, u64); + +#[simd] +pub struct f32x4(f32, f32, f32, f32); + +#[simd] +pub struct f64x2(f64, f64); diff --git a/src/libcore/unstable/sync.rs b/src/libcore/unstable/sync.rs new file mode 100644 index 0000000000000..e22046f04f95b --- /dev/null +++ b/src/libcore/unstable/sync.rs @@ -0,0 +1,286 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cast; +use libc; +use option::*; +use task; +use task::atomically; +use unstable::finally::Finally; +use unstable::intrinsics; +use ops::Drop; +use clone::Clone; +use kinds::Owned; + +/// An atomically reference counted pointer. +/// +/// Enforces no shared-memory safety. +pub struct UnsafeAtomicRcBox { + data: *mut libc::c_void, +} + +struct AtomicRcBoxData { + count: int, + data: Option, +} + +impl UnsafeAtomicRcBox { + pub fn new(data: T) -> UnsafeAtomicRcBox { + unsafe { + let data = ~AtomicRcBoxData { count: 1, data: Some(data) }; + let ptr = cast::transmute(data); + return UnsafeAtomicRcBox { data: ptr }; + } + } + + #[inline(always)] + #[cfg(stage0)] + pub unsafe fn get(&self) -> *mut T + { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + assert!(data.count > 0); + let r: *mut T = cast::transmute(data.data.get_mut_ref()); + cast::forget(data); + return r; + } + + #[inline(always)] + #[cfg(not(stage0))] + pub unsafe fn get(&self) -> *mut T + { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + assert!(data.count > 0); + let r: *mut T = data.data.get_mut_ref(); + cast::forget(data); + return r; + } + + #[inline(always)] + #[cfg(stage0)] + pub unsafe fn get_immut(&self) -> *T + { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + assert!(data.count > 0); + let r: *T = cast::transmute(data.data.get_mut_ref()); + cast::forget(data); + return r; + } + + #[inline(always)] + #[cfg(not(stage0))] + pub unsafe fn get_immut(&self) -> *T + { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + assert!(data.count > 0); + let r: *T = cast::transmute_immut(data.data.get_mut_ref()); + cast::forget(data); + return r; + } +} + +impl Clone for UnsafeAtomicRcBox { + fn clone(&self) -> UnsafeAtomicRcBox { + unsafe { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1; + assert!(new_count >= 2); + cast::forget(data); + return UnsafeAtomicRcBox { data: self.data }; + } + } +} + +#[unsafe_destructor] +impl Drop for UnsafeAtomicRcBox{ + fn finalize(&self) { + unsafe { + do task::unkillable { + let mut data: ~AtomicRcBoxData = cast::transmute(self.data); + let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1; + assert!(new_count >= 0); + if new_count == 0 { + // drop glue takes over. + } else { + cast::forget(data); + } + } + } + } +} + + +/****************************************************************************/ + +#[allow(non_camel_case_types)] // runtime type +pub type rust_little_lock = *libc::c_void; + +struct LittleLock { + l: rust_little_lock, +} + +impl Drop for LittleLock { + fn finalize(&self) { + unsafe { + rust_destroy_little_lock(self.l); + } + } +} + +fn LittleLock() -> LittleLock { + unsafe { + LittleLock { + l: rust_create_little_lock() + } + } +} + +pub impl LittleLock { + #[inline(always)] + unsafe fn lock(&self, f: &fn() -> T) -> T { + do atomically { + rust_lock_little_lock(self.l); + do (|| { + f() + }).finally { + rust_unlock_little_lock(self.l); + } + } + } +} + +struct ExData { + lock: LittleLock, + failed: bool, + data: T, +} + +/** + * An arc over mutable data that is protected by a lock. For library use only. + */ +pub struct Exclusive { + x: UnsafeAtomicRcBox> +} + +pub fn exclusive(user_data: T) -> Exclusive { + let data = ExData { + lock: LittleLock(), + failed: false, + data: user_data + }; + Exclusive { + x: UnsafeAtomicRcBox::new(data) + } +} + +impl Clone for Exclusive { + // Duplicate an exclusive ARC, as std::arc::clone. + fn clone(&self) -> Exclusive { + Exclusive { x: self.x.clone() } + } +} + +pub impl Exclusive { + // Exactly like std::arc::mutex_arc,access(), but with the little_lock + // instead of a proper mutex. Same reason for being unsafe. + // + // Currently, scheduling operations (i.e., yielding, receiving on a pipe, + // accessing the provided condition variable) are prohibited while inside + // the exclusive. Supporting that is a work in progress. + #[inline(always)] + unsafe fn with(&self, f: &fn(x: &mut T) -> U) -> U { + let rec = self.x.get(); + do (*rec).lock.lock { + if (*rec).failed { + fail!( + ~"Poisoned exclusive - another task failed inside!"); + } + (*rec).failed = true; + let result = f(&mut (*rec).data); + (*rec).failed = false; + result + } + } + + #[inline(always)] + unsafe fn with_imm(&self, f: &fn(x: &T) -> U) -> U { + do self.with |x| { + f(cast::transmute_immut(x)) + } + } +} + +fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { + unsafe { + let old = intrinsics::atomic_cxchg(address, oldval, newval); + old == oldval + } +} + +extern { + fn rust_create_little_lock() -> rust_little_lock; + fn rust_destroy_little_lock(lock: rust_little_lock); + fn rust_lock_little_lock(lock: rust_little_lock); + fn rust_unlock_little_lock(lock: rust_little_lock); +} + +#[cfg(test)] +mod tests { + use comm; + use super::exclusive; + use task; + use uint; + + #[test] + fn exclusive_arc() { + let mut futures = ~[]; + + let num_tasks = 10; + let count = 10; + + let total = exclusive(~0); + + for uint::range(0, num_tasks) |_i| { + let total = total.clone(); + let (port, chan) = comm::stream(); + futures.push(port); + + do task::spawn || { + for uint::range(0, count) |_i| { + do total.with |count| { + **count += 1; + } + } + chan.send(()); + } + }; + + for futures.each |f| { f.recv() } + + do total.with |total| { + assert!(**total == num_tasks * count) + }; + } + + #[test] #[should_fail] #[ignore(cfg(windows))] + fn exclusive_poison() { + // Tests that if one task fails inside of an exclusive, subsequent + // accesses will also fail. + let x = exclusive(1); + let x2 = x.clone(); + do task::try || { + do x2.with |one| { + assert!(*one == 2); + } + }; + do x.with |one| { + assert!(*one == 1); + } + } +} diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs index 7a30bb92111b1..d5c5230cef819 100644 --- a/src/libcore/unstable/weak_task.rs +++ b/src/libcore/unstable/weak_task.rs @@ -72,7 +72,9 @@ fn create_global_service() -> ~WeakTaskService { let chan = SharedChan::new(chan); let chan_clone = chan.clone(); - do task().unlinked().spawn { + let mut task = task(); + task.unlinked(); + do task.spawn { debug!("running global weak task service"); let port = Cell(port.take()); do (|| { @@ -190,11 +192,13 @@ fn test_select_stream_and_oneshot() { use either::{Left, Right}; let (port, chan) = stream(); + let port = Cell(port); let (waitport, waitchan) = stream(); do spawn { unsafe { - do weaken_task |signal| { - match select2i(&port, &signal) { + do weaken_task |mut signal| { + let mut port = port.take(); + match select2i(&mut port, &mut signal) { Left(*) => (), Right(*) => fail!() } @@ -205,4 +209,3 @@ fn test_select_stream_and_oneshot() { chan.send(()); waitport.recv(); } - diff --git a/src/libcore/util.rs b/src/libcore/util.rs index a08e38c021fad..ba176872b9a49 100644 --- a/src/libcore/util.rs +++ b/src/libcore/util.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -15,6 +15,7 @@ Miscellaneous helpers for common patterns. */ use prelude::*; +use unstable::intrinsics; /// The identity function. #[inline(always)] @@ -26,19 +27,20 @@ pub fn ignore(_x: T) { } /// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the /// original value of `*ptr`. +/// +/// NB: This function accepts `@mut T` and not `&mut T` to avoid +/// an obvious borrowck hazard. Typically passing in `&mut T` will +/// cause borrow check errors because it freezes whatever location +/// that `&mut T` is stored in (either statically or dynamically). #[inline(always)] -pub fn with( - ptr: &mut T, - new_value: T, +pub fn with( + ptr: @mut T, + value: T, op: &fn() -> R) -> R { - // NDM: if swap operator were defined somewhat differently, - // we wouldn't need to copy... - - let old_value = *ptr; - *ptr = new_value; + let prev = replace(ptr, value); let result = op(); - *ptr = old_value; + *ptr = prev; return result; } @@ -48,7 +50,55 @@ pub fn with( */ #[inline(always)] pub fn swap(x: &mut T, y: &mut T) { - *x <-> *y; + unsafe { + swap_ptr(ptr::to_mut_unsafe_ptr(x), ptr::to_mut_unsafe_ptr(y)); + } +} + +/** + * Swap the values at two mutable locations of the same type, without + * deinitialising or copying either one. + */ +#[inline] +#[cfg(not(stage0))] +pub unsafe fn swap_ptr(x: *mut T, y: *mut T) { + if x == y { return } + + // Give ourselves some scratch space to work with + let mut tmp: T = intrinsics::uninit(); + let t = ptr::to_mut_unsafe_ptr(&mut tmp); + + // Perform the swap + ptr::copy_memory(t, x, 1); + ptr::copy_memory(x, y, 1); + ptr::copy_memory(y, t, 1); + + // y and t now point to the same thing, but we need to completely forget t + // because it's no longer relevant. + cast::forget(tmp); +} + +/** + * Swap the values at two mutable locations of the same type, without + * deinitialising or copying either one. + */ +#[inline] +#[cfg(stage0)] +pub unsafe fn swap_ptr(x: *mut T, y: *mut T) { + if x == y { return } + + // Give ourselves some scratch space to work with + let mut tmp: T = intrinsics::init(); + let t = ptr::to_mut_unsafe_ptr(&mut tmp); + + // Perform the swap + ptr::copy_memory(t, x, 1); + ptr::copy_memory(x, y, 1); + ptr::copy_memory(y, t, 1); + + // y and t now point to the same thing, but we need to completely forget t + // because it's no longer relevant. + cast::forget(tmp); } /** @@ -56,10 +106,19 @@ pub fn swap(x: &mut T, y: &mut T) { * value, without deinitialising or copying either one. */ #[inline(always)] -pub fn replace(dest: &mut T, src: T) -> T { - let mut tmp = src; - swap(dest, &mut tmp); - tmp +pub fn replace(dest: &mut T, mut src: T) -> T { + swap(dest, &mut src); + src +} + +/** + * Replace the value at a mutable location with a new one, returning the old + * value, without deinitialising or copying either one. + */ +#[inline(always)] +pub unsafe fn replace_ptr(dest: *mut T, mut src: T) -> T { + swap_ptr(dest, ptr::to_mut_unsafe_ptr(&mut src)); + src } /// A non-copyable dummy type. @@ -73,6 +132,20 @@ impl Drop for NonCopyable { pub fn NonCopyable() -> NonCopyable { NonCopyable { i: () } } + +/// A type with no inhabitants +pub enum Void { } + +pub impl Void { + /// A utility function for ignoring this uninhabited type + fn uninhabited(&self) -> ! { + match *self { + // Nothing to match on + } + } +} + + /** A utility function for indicating unreachable code. It will fail if executed. This is occasionally useful to put after loops that never diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 86767dc5bad85..89f5b73953af9 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -19,21 +19,21 @@ use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; use old_iter::BaseIter; use old_iter; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use iterator::Iterator; use kinds::Copy; use libc; +use old_iter::{BaseIter, CopyableIter}; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; use ptr; +use ptr::Ptr; use sys; use uint; use unstable::intrinsics; use vec; +use util; -#[cfg(notest)] use cmp::Equiv; +#[cfg(not(test))] use cmp::Equiv; pub mod rustrt { use libc; @@ -45,13 +45,13 @@ pub mod rustrt { // These names are terrible. reserve_shared applies // to ~[] and reserve_shared_actual applies to @[]. #[fast_ffi] - unsafe fn vec_reserve_shared(++t: *sys::TypeDesc, - ++v: **raw::VecRepr, - ++n: libc::size_t); + unsafe fn vec_reserve_shared(t: *sys::TypeDesc, + v: **raw::VecRepr, + n: libc::size_t); #[fast_ffi] - unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc, - ++v: **raw::VecRepr, - ++n: libc::size_t); + unsafe fn vec_reserve_shared_actual(t: *sys::TypeDesc, + v: **raw::VecRepr, + n: libc::size_t); } } @@ -137,9 +137,9 @@ pub fn uniq_len(v: &const ~[T]) -> uint { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value returned by the function `op`. */ pub fn from_fn(n_elts: uint, op: old_iter::InitOp) -> ~[T] { @@ -159,9 +159,9 @@ pub fn from_fn(n_elts: uint, op: old_iter::InitOp) -> ~[T] { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value `t`. */ pub fn from_elem(n_elts: uint, t: T) -> ~[T] { @@ -169,7 +169,7 @@ pub fn from_elem(n_elts: uint, t: T) -> ~[T] { } /// Creates a new unique vector with the same contents as the slice -pub fn from_slice(t: &[T]) -> ~[T] { +pub fn to_owned(t: &[T]) -> ~[T] { from_fn(t.len(), |i| t[i]) } @@ -222,7 +222,7 @@ pub fn build(builder: &fn(push: &fn(v: A))) -> ~[A] { * # Arguments * * * size - An option, maybe containing initial size of the vector to reserve - * * builder - A function that will construct the vector. It recieves + * * builder - A function that will construct the vector. It receives * as an argument a function that will push an element * onto the vector being constructed. */ @@ -473,7 +473,7 @@ pub fn shift(v: &mut ~[T]) -> T { let next_ln = v.len() - 1; // Save the last element. We're going to overwrite its position - let mut work_elt = v.pop(); + 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 @@ -504,16 +504,14 @@ pub fn shift(v: &mut ~[T]) -> T { // 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); - *vp <-> work_elt; - work_elt + util::replace_ptr(vp, work_elt) } } /// Prepend an element to the vector pub fn unshift(v: &mut ~[T], x: T) { - let mut vv = ~[x]; - *v <-> vv; + let vv = util::replace(v, ~[x]); v.push_all_move(vv); } @@ -526,7 +524,7 @@ pub fn insert(v: &mut ~[T], i: uint, x: T) { v.push(x); let mut j = len; while j > i { - v[j] <-> v[j - 1]; + swap(*v, j, j - 1); j -= 1; } } @@ -539,7 +537,7 @@ pub fn remove(v: &mut ~[T], i: uint) -> T { let mut j = i; while j < len - 1 { - v[j] <-> v[j + 1]; + swap(*v, j, j + 1); j += 1; } v.pop() @@ -553,10 +551,9 @@ pub fn consume(mut v: ~[T], f: &fn(uint, v: T)) { // holes we create in the vector. That ensures that, if the // iterator fails then we won't try to clean up the consumed // elements during unwinding - let mut x = intrinsics::init(); + let x = intrinsics::init(); let p = ptr::mut_offset(p, i); - x <-> *p; - f(i, x); + f(i, util::replace_ptr(p, x)); } } @@ -575,10 +572,9 @@ pub fn consume_reverse(mut v: ~[T], f: &fn(uint, v: T)) { // holes we create in the vector. That ensures that, if the // iterator fails then we won't try to clean up the consumed // elements during unwinding - let mut x = intrinsics::init(); + let x = intrinsics::init(); let p = ptr::mut_offset(p, i); - x <-> *p; - f(i, x); + f(i, util::replace_ptr(p, x)); } } @@ -587,6 +583,21 @@ pub fn consume_reverse(mut v: ~[T], f: &fn(uint, v: T)) { } /// Remove the last element from a vector and return it +#[cfg(not(stage0))] +pub fn pop(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 = util::replace_ptr(valptr, intrinsics::uninit()); + raw::set_len(v, ln - 1u); + val + } +} + +#[cfg(stage0)] pub fn pop(v: &mut ~[T]) -> T { let ln = v.len(); if ln == 0 { @@ -594,9 +605,7 @@ pub fn pop(v: &mut ~[T]) -> T { } let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); unsafe { - // FIXME #4204: Should be uninit() - we don't need this zeroed - let mut val = intrinsics::init(); - val <-> *valptr; + let val = util::replace_ptr(valptr, intrinsics::init()); raw::set_len(v, ln - 1u); val } @@ -614,7 +623,7 @@ pub fn swap_remove(v: &mut ~[T], index: uint) -> T { fail!(fmt!("vec::swap_remove - index %u >= length %u", index, ln)); } if index < ln - 1 { - v[index] <-> v[ln - 1]; + swap(*v, index, ln - 1); } v.pop() } @@ -663,15 +672,32 @@ pub fn push_all(v: &mut ~[T], rhs: &const [T]) { } #[inline(always)] +#[cfg(not(stage0))] +pub fn push_all_move(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 = util::replace_ptr(ptr::mut_offset(p, i), + intrinsics::uninit()); + push(&mut *v, x); + } + } + raw::set_len(&mut rhs, 0); + } +} + +#[inline(always)] +#[cfg(stage0)] pub fn push_all_move(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| { - // FIXME #4204 Should be uninit() - don't need to zero - let mut x = intrinsics::init(); - x <-> *ptr::mut_offset(p, i); + let x = util::replace_ptr(ptr::mut_offset(p, i), + intrinsics::init()); push(&mut *v, x); } } @@ -680,15 +706,29 @@ pub fn push_all_move(v: &mut ~[T], mut rhs: ~[T]) { } /// Shorten a vector, dropping excess elements. +#[cfg(not(stage0))] +pub fn truncate(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| { + util::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + } + } + } + unsafe { raw::set_len(&mut *v, newlen); } +} + +/// Shorten a vector, dropping excess elements. +#[cfg(stage0)] pub fn truncate(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| { - // FIXME #4204 Should be uninit() - don't need to zero - let mut dropped = intrinsics::init(); - dropped <-> *ptr::mut_offset(p, i); + util::replace_ptr(ptr::mut_offset(p, i), intrinsics::init()); } } } @@ -699,6 +739,7 @@ pub fn truncate(v: &mut ~[T], newlen: uint) { * Remove consecutive repeated elements from a vector; if the vector is * sorted, this removes all duplicates. */ +#[cfg(not(stage0))] pub fn dedup(v: &mut ~[T]) { unsafe { if v.len() < 1 { return; } @@ -712,16 +753,52 @@ pub fn dedup(v: &mut ~[T]) { // last_written < next_to_read < ln if *ptr::mut_offset(p, next_to_read) == *ptr::mut_offset(p, last_written) { - // FIXME #4204 Should be uninit() - don't need to - // zero - let mut dropped = intrinsics::init(); - dropped <-> *ptr::mut_offset(p, next_to_read); + util::replace_ptr(ptr::mut_offset(p, next_to_read), + intrinsics::uninit()); } else { last_written += 1; // last_written <= next_to_read < ln if next_to_read != last_written { - *ptr::mut_offset(p, last_written) <-> - *ptr::mut_offset(p, next_to_read); + util::swap_ptr(ptr::mut_offset(p, last_written), + ptr::mut_offset(p, next_to_read)); + } + } + // last_written <= next_to_read < ln + next_to_read += 1; + // last_written < next_to_read <= ln + } + } + // last_written < next_to_read == ln + raw::set_len(v, last_written + 1); + } +} + +/** + * Remove consecutive repeated elements from a vector; if the vector is + * sorted, this removes all duplicates. + */ +#[cfg(stage0)] +pub fn dedup(v: &mut ~[T]) { + unsafe { + if v.len() < 1 { return; } + let mut last_written = 0, 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) + let p = p as *mut T; + // last_written < next_to_read <= ln + while next_to_read < ln { + // last_written < next_to_read < ln + if *ptr::mut_offset(p, next_to_read) == + *ptr::mut_offset(p, last_written) { + util::replace_ptr(ptr::mut_offset(p, next_to_read), + intrinsics::init()); + } else { + last_written += 1; + // last_written <= next_to_read < ln + if next_to_read != last_written { + util::swap_ptr(ptr::mut_offset(p, last_written), + ptr::mut_offset(p, next_to_read)); } } // last_written <= next_to_read < ln @@ -946,7 +1023,7 @@ pub fn retain(v: &mut ~[T], f: &fn(t: &T) -> bool) { if !f(&v[i]) { deleted += 1; } else if deleted > 0 { - v[i - deleted] <-> v[i]; + swap(*v, i - deleted, i); } } @@ -994,7 +1071,7 @@ pub fn connect(v: &[~[T]], sep: &T) -> ~[T] { * ~~~ * */ -pub fn foldl(z: T, v: &[U], p: &fn(t: T, u: &U) -> T) -> T { +pub fn foldl<'a, T, U>(z: T, v: &'a [U], p: &fn(t: T, u: &'a U) -> T) -> T { let mut accum = z; let mut i = 0; let l = v.len(); @@ -1026,12 +1103,13 @@ pub fn foldl(z: T, v: &[U], p: &fn(t: T, u: &U) -> T) -> T { * ~~~ * */ -pub fn foldr(v: &[T], z: U, p: &fn(t: &T, u: U) -> U) -> U { - let mut accum = z; - for v.each_reverse |elt| { - accum = p(elt, accum); +pub fn foldr<'a, T, U>(v: &'a [T], mut z: U, p: &fn(t: &'a T, u: U) -> U) -> U { + let mut i = v.len(); + while i > 0 { + i -= 1; + z = p(&v[i], z); } - accum + return z; } /** @@ -1346,15 +1424,25 @@ pub fn zip(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] { * * a - The index of the first element * * b - The index of the second element */ +#[inline(always)] pub fn swap(v: &mut [T], a: uint, b: uint) { - v[a] <-> v[b]; + unsafe { + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap + let pa: *mut T = ptr::to_mut_unsafe_ptr(&mut v[a]); + let pb: *mut T = ptr::to_mut_unsafe_ptr(&mut v[b]); + util::swap_ptr(pa, pb); + } } /// Reverse the order of elements in a vector, in place pub fn reverse(v: &mut [T]) { let mut i: uint = 0; let ln = len::(v); - while i < ln / 2 { v[i] <-> v[ln - i - 1]; i += 1; } + while i < ln / 2 { + swap(v, i, ln - i - 1); + i += 1; + } } /// Returns a vector with the order of elements reversed @@ -1406,13 +1494,14 @@ pub fn reversed(v: &const [T]) -> ~[T] { * ~~~ */ #[inline(always)] -pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) { +pub fn _each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { // ^^^^ // NB---this CANNOT be &const [T]! The reason // is that you are passing it to `f()` using // an immutable. - do vec::as_imm_buf(v) |p, n| { + let mut broke = false; + do as_imm_buf(v) |p, n| { let mut n = n; let mut p = p; while n > 0u { @@ -1423,42 +1512,69 @@ pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) { } n -= 1u; } + broke = n > 0; } + return true; } +#[cfg(stage0)] +pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) { _each(v, f); } +#[cfg(not(stage0))] +pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { _each(v, f) } + /// Like `each()`, but for the case where you have /// a vector with mutable contents and you would like /// to mutate the contents as you iterate. #[inline(always)] -pub fn each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) { - do vec::as_mut_buf(v) |p, n| { +pub fn _each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) -> bool { + let mut broke = false; + do as_mut_buf(v) |p, n| { let mut n = n; let mut p = p; while n > 0 { unsafe { let q: &'r mut T = cast::transmute_mut_region(&mut *p); - if !f(q) { - break; - } + if !f(q) { break; } p = p.offset(1); } n -= 1; } + broke = n > 0; } + return broke; +} + +#[cfg(stage0)] +pub fn each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) { + _each_mut(v, f); +} +#[cfg(not(stage0))] +pub fn each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) -> bool { + _each_mut(v, f) } /// Like `each()`, but for the case where you have a vector that *may or may /// not* have mutable contents. #[inline(always)] -pub fn each_const(v: &const [T], f: &fn(elem: &const T) -> bool) { +pub fn _each_const(v: &const [T], f: &fn(elem: &const T) -> bool) -> bool { let mut i = 0; let n = v.len(); while i < n { if !f(&const v[i]) { - return; + return false; } i += 1; } + return true; +} + +#[cfg(stage0)] +pub fn each_const(v: &const [t], f: &fn(elem: &const t) -> bool) { + _each_const(v, f); +} +#[cfg(not(stage0))] +pub fn each_const(v: &const [t], f: &fn(elem: &const t) -> bool) -> bool { + _each_const(v, f) } /** @@ -1467,12 +1583,20 @@ pub fn each_const(v: &const [T], f: &fn(elem: &const T) -> bool) { * Return true to continue, false to break. */ #[inline(always)] -pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) { +pub fn _eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { let mut i = 0; for each(v) |p| { - if !f(i, p) { return; } + if !f(i, p) { return false; } i += 1; } + return true; +} + +#[cfg(stage0)] +pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) { _eachi(v, f); } +#[cfg(not(stage0))] +pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { + _eachi(v, f) } /** @@ -1481,14 +1605,26 @@ pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) { * Return true to continue, false to break. */ #[inline(always)] -pub fn eachi_mut<'r,T>(v: &'r mut [T], f: &fn(uint, v: &'r mut T) -> bool) { +pub fn _eachi_mut<'r,T>(v: &'r mut [T], + f: &fn(uint, v: &'r mut T) -> bool) -> bool { let mut i = 0; for each_mut(v) |p| { if !f(i, p) { - return; + return false; } i += 1; } + return true; +} + +#[cfg(stage0)] +pub fn eachi_mut<'r,T>(v: &'r mut [T], f: &fn(uint, v: &'r mut T) -> bool) { + _eachi_mut(v, f); +} +#[cfg(not(stage0))] +pub fn eachi_mut<'r,T>(v: &'r mut [T], + f: &fn(uint, v: &'r mut T) -> bool) -> bool { + _eachi_mut(v, f) } /** @@ -1497,8 +1633,17 @@ pub fn eachi_mut<'r,T>(v: &'r mut [T], f: &fn(uint, v: &'r mut T) -> bool) { * Return true to continue, false to break. */ #[inline(always)] +pub fn _each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) -> bool { + _eachi_reverse(v, |_i, v| blk(v)) +} + +#[cfg(stage0)] pub fn each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) { - eachi_reverse(v, |_i, v| blk(v)) + _each_reverse(v, blk); +} +#[cfg(not(stage0))] +pub fn each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) -> bool { + _each_reverse(v, blk) } /** @@ -1507,14 +1652,26 @@ pub fn each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) { * Return true to continue, false to break. */ #[inline(always)] -pub fn eachi_reverse<'r,T>(v: &'r [T], blk: &fn(i: uint, v: &'r T) -> bool) { +pub fn _eachi_reverse<'r,T>(v: &'r [T], + blk: &fn(i: uint, v: &'r T) -> bool) -> bool { let mut i = v.len(); while i > 0 { i -= 1; if !blk(i, &v[i]) { - return; + return false; } } + return true; +} + +#[cfg(stage0)] +pub fn eachi_reverse<'r,T>(v: &'r [T], blk: &fn(i: uint, v: &'r T) -> bool) { + _eachi_reverse(v, blk); +} +#[cfg(not(stage0))] +pub fn eachi_reverse<'r,T>(v: &'r [T], + blk: &fn(i: uint, v: &'r T) -> bool) -> bool { + _eachi_reverse(v, blk) } /** @@ -1525,13 +1682,52 @@ pub fn eachi_reverse<'r,T>(v: &'r [T], blk: &fn(i: uint, v: &'r T) -> bool) { * Both vectors must have the same length */ #[inline] -pub fn each2(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) { - assert!(len(v1) == len(v2)); - for uint::range(0u, len(v1)) |i| { +pub fn _each2(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) -> bool { + assert!(v1.len() == v2.len()); + for uint::range(0u, v1.len()) |i| { if !f(&v1[i], &v2[i]) { - return; + return false; } } + return true; +} + +#[cfg(stage0)] +pub fn each2(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) { + _each2(v1, v2, f); +} +#[cfg(not(stage0))] +pub fn each2(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) -> bool { + _each2(v1, v2, f) +} + +/** + * + * Iterates over two vector with mutable. + * + * # Failure + * + * Both vectors must have the same length + */ +#[inline] +pub fn _each2_mut(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) -> bool) -> bool { + assert!(v1.len() == v2.len()); + for uint::range(0u, v1.len()) |i| { + if !f(&mut v1[i], &mut v2[i]) { + return false; + } + } + return true; +} + +#[cfg(stage0)] +pub fn each2_mut(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) -> bool) { + _each2_mut(v1, v2, f); +} + +#[cfg(not(stage0))] +pub fn each2_mut(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) -> bool) -> bool { + _each2_mut(v1, v2, f) } /** @@ -1544,7 +1740,8 @@ pub fn each2(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) { * The total number of permutations produced is `len(v)!`. If `v` contains * repeated elements, then some permutations are repeated. */ -pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { +#[cfg(not(stage0))] +pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) -> bool { let ln = len(v); if ln <= 1 { put(v); @@ -1558,24 +1755,37 @@ pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { rest.push_all(const_slice(v, i+1u, ln)); for each_permutation(rest) |permutation| { if !put(append(~[elt], permutation)) { - return; + return false; } } i += 1u; } } + return true; } -// see doc below -#[cfg(stage0)] // XXX: lifetimes! -pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { +/** + * Iterate over all contiguous windows of length `n` of the vector `v`. + * + * # Example + * + * Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`, `[3,4]`) + * + * ~~~ + * for windowed(2, &[1,2,3,4]) |v| { + * io::println(fmt!("%?", v)); + * } + * ~~~ + * + */ +#[cfg(stage0)] +pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) { assert!(1u <= n); if n > v.len() { return; } for uint::range(0, v.len() - n + 1) |i| { - if !it(v.slice(i, i+n)) { return } + if !it(v.slice(i, i + n)) { return } } } - /** * Iterate over all contiguous windows of length `n` of the vector `v`. * @@ -1590,15 +1800,14 @@ pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { * ~~~ * */ -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) { +#[cfg(not(stage0))] +pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) -> bool { assert!(1u <= n); - if n > v.len() { return; } + if n > v.len() { return true; } for uint::range(0, v.len() - n + 1) |i| { - if !it(v.slice(i, i + n)) { return } + if !it(v.slice(i, i + n)) { return false; } } + return true; } /** @@ -1671,7 +1880,7 @@ fn equals(a: &[T], b: &[T]) -> bool { true } -#[cfg(notest)] +#[cfg(not(test))] impl<'self,T:Eq> Eq for &'self [T] { #[inline(always)] fn eq(&self, other: & &'self [T]) -> bool { eq(*self, *other) } @@ -1679,7 +1888,7 @@ impl<'self,T:Eq> Eq for &'self [T] { fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for ~[T] { #[inline(always)] fn eq(&self, other: &~[T]) -> bool { eq(*self, *other) } @@ -1687,7 +1896,7 @@ impl Eq for ~[T] { fn ne(&self, other: &~[T]) -> bool { !self.eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl Eq for @[T] { #[inline(always)] fn eq(&self, other: &@[T]) -> bool { eq(*self, *other) } @@ -1695,25 +1904,25 @@ impl Eq for @[T] { fn ne(&self, other: &@[T]) -> bool { !self.eq(other) } } -#[cfg(notest)] +#[cfg(not(test))] impl<'self,T:TotalEq> TotalEq for &'self [T] { #[inline(always)] fn equals(&self, other: & &'self [T]) -> bool { equals(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalEq for ~[T] { #[inline(always)] fn equals(&self, other: &~[T]) -> bool { equals(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalEq for @[T] { #[inline(always)] fn equals(&self, other: &@[T]) -> bool { equals(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl<'self,T:Eq> Equiv<~[T]> for &'self [T] { #[inline(always)] fn equiv(&self, other: &~[T]) -> bool { eq(*self, *other) } @@ -1735,19 +1944,19 @@ fn cmp(a: &[T], b: &[T]) -> Ordering { a.len().cmp(&b.len()) } -#[cfg(notest)] +#[cfg(not(test))] impl<'self,T:TotalOrd> TotalOrd for &'self [T] { #[inline(always)] fn cmp(&self, other: & &'self [T]) -> Ordering { cmp(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for ~[T] { #[inline(always)] fn cmp(&self, other: &~[T]) -> Ordering { cmp(*self, *other) } } -#[cfg(notest)] +#[cfg(not(test))] impl TotalOrd for @[T] { #[inline(always)] fn cmp(&self, other: &@[T]) -> Ordering { cmp(*self, *other) } @@ -1772,7 +1981,7 @@ fn le(a: &[T], b: &[T]) -> bool { !lt(b, a) } fn ge(a: &[T], b: &[T]) -> bool { !lt(a, b) } fn gt(a: &[T], b: &[T]) -> bool { lt(b, a) } -#[cfg(notest)] +#[cfg(not(test))] impl<'self,T:Ord> Ord for &'self [T] { #[inline(always)] fn lt(&self, other: & &'self [T]) -> bool { lt((*self), (*other)) } @@ -1784,7 +1993,7 @@ impl<'self,T:Ord> Ord for &'self [T] { fn gt(&self, other: & &'self [T]) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for ~[T] { #[inline(always)] fn lt(&self, other: &~[T]) -> bool { lt((*self), (*other)) } @@ -1796,7 +2005,7 @@ impl Ord for ~[T] { fn gt(&self, other: &~[T]) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] impl Ord for @[T] { #[inline(always)] fn lt(&self, other: &@[T]) -> bool { lt((*self), (*other)) } @@ -1808,7 +2017,7 @@ impl Ord for @[T] { fn gt(&self, other: &@[T]) -> bool { gt((*self), (*other)) } } -#[cfg(notest)] +#[cfg(not(test))] pub mod traits { use kinds::Copy; use ops::Add; @@ -1837,167 +2046,20 @@ pub trait CopyableVector { } /// Extension methods for vectors -impl<'self,T:Copy> CopyableVector for &'self const [T] { +impl<'self,T:Copy> CopyableVector for &'self [T] { /// Returns a copy of `v`. #[inline] fn to_owned(&self) -> ~[T] { let mut result = ~[]; - // FIXME: #4568 - unsafe { - reserve(&mut result, self.len()); - for self.each |e| { - result.push(copy *e); - } + reserve(&mut result, self.len()); + for self.each |e| { + result.push(copy *e); } result } } -#[cfg(stage0)] -pub trait ImmutableVector { - fn slice(&self, start: uint, end: uint) -> &'self [T]; - fn head(&self) -> &'self T; - fn head_opt(&self) -> Option<&'self T>; - fn tail(&self) -> &'self [T]; - fn tailn(&self, n: uint) -> &'self [T]; - fn init(&self) -> &'self [T]; - fn initn(&self, n: uint) -> &'self [T]; - fn last(&self) -> &'self T; - fn last_opt(&self) -> Option<&'self T>; - fn each_reverse(&self, blk: &fn(&T) -> bool); - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool); - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U; - fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U]; - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U]; - unsafe fn unsafe_ref(&self, index: uint) -> *T; -} - -/// Extension methods for vectors -#[cfg(stage0)] -impl<'self,T> ImmutableVector 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) - } - - /// Returns the first element of a vector, failing if the vector is empty. - #[inline] - fn head(&self) -> &'self T { head(*self) } - - /// Returns the first element of a vector - #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } - - /// Returns all but the first element of a vector - #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } - - /// Returns all but the first `n' elements of a vector - #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } - - /// Returns all but the last elemnt of a vector - #[inline] - fn init(&self) -> &'self [T] { init(*self) } - - /// Returns all but the last `n' elemnts of a vector - #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last(&self) -> &'self T { last(*self) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } - - /// Iterates over a vector's elements in reverse. - #[inline] - fn each_reverse(&self, blk: &fn(&T) -> bool) { - each_reverse(*self, blk) - } - - /// Iterates over a vector's elements and indices in reverse. - #[inline] - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) { - eachi_reverse(*self, blk) - } - - /// Reduce a vector from right to left - #[inline] - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U { - foldr(*self, z, p) - } - - /// Apply a function to each element of a vector and return the results - #[inline] - fn map(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } - - /** - * Apply a function to the index and value of each element in the vector - * and return the results - */ - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { - mapi(*self, f) - } - - #[inline] - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U] { - let mut r = ~[]; - let mut i = 0; - while i < self.len() { - r.push(f(&self[i])); - i += 1; - } - r - } - - /** - * Returns true if the function returns true for all elements. - * - * If the vector is empty, true is returned. - */ - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool { - alli(*self, f) - } - /** - * Apply a function to each element of a vector and return a concatenation - * of each result vector - */ - #[inline] - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U] { - flat_map(*self, f) - } - /** - * Apply a function to each element of a vector and return the results - * - * If function `f` returns `none` then that element is excluded from - * the resulting vector. - */ - #[inline] - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U] { - filter_mapped(*self, f) - } - - /// Returns a pointer to the element at the given index, without doing - /// bounds checking. - #[inline(always)] - unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableVector<'self, T> { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn iter(self) -> VecIterator<'self, T>; @@ -2009,9 +2071,15 @@ pub trait ImmutableVector<'self, T> { fn initn(&self, n: uint) -> &'self [T]; fn last(&self) -> &'self T; fn last_opt(&self) -> Option<&'self T>; + #[cfg(stage0)] fn each_reverse(&self, blk: &fn(&T) -> bool); + #[cfg(not(stage0))] + fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool; + #[cfg(stage0)] fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool); - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U; + #[cfg(not(stage0))] + fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool; + fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U; fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U]; @@ -2022,9 +2090,6 @@ pub trait ImmutableVector<'self, T> { } /// Extension methods for vectors -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Return a slice that points into another slice. #[inline] @@ -2075,19 +2140,33 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Iterates over a vector's elements in reverse. #[inline] + #[cfg(stage0)] fn each_reverse(&self, blk: &fn(&T) -> bool) { each_reverse(*self, blk) } + /// Iterates over a vector's elements in reverse. + #[inline] + #[cfg(not(stage0))] + fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool { + each_reverse(*self, blk) + } /// Iterates over a vector's elements and indices in reverse. + #[cfg(stage0)] #[inline] fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) { eachi_reverse(*self, blk) } + /// Iterates over a vector's elements and indices in reverse. + #[cfg(not(stage0))] + #[inline] + fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool { + eachi_reverse(*self, blk) + } /// Reduce a vector from right to left #[inline] - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U { + fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U { foldr(*self, z, p) } @@ -2431,6 +2510,7 @@ pub mod raw { use sys; use unstable::intrinsics; use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, len, with_capacity}; + use util; /// The internal representation of a (boxed) vector pub struct VecRepr { @@ -2528,8 +2608,7 @@ pub mod raw { pub unsafe fn init_elem(v: &mut [T], i: uint, val: T) { let mut box = Some(val); do as_mut_buf(v) |p, _len| { - let mut box2 = None; - box2 <-> box; + let box2 = util::replace(&mut box, None); intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)), box2.unwrap()); } @@ -2634,102 +2713,82 @@ pub mod bytes { // ___________________________________________________________________________ // ITERATION TRAIT METHODS -#[cfg(stage0)] impl<'self,A> old_iter::BaseIter for &'self [A] { + #[cfg(stage0)] #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -impl<'self,A> old_iter::BaseIter for &'self [A] { + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { + each(*self, blk) + } + #[cfg(not(stage0))] #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { + each(*self, blk) + } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } } // FIXME(#4148): This should be redundant -#[cfg(stage0)] impl old_iter::BaseIter for ~[A] { + #[cfg(stage0)] #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -impl old_iter::BaseIter for ~[A] { + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { + each(*self, blk) + } + #[cfg(not(stage0))] #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { + each(*self, blk) + } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } } // FIXME(#4148): This should be redundant -#[cfg(stage0)] impl old_iter::BaseIter for @[A] { + #[cfg(stage0)] #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -impl old_iter::BaseIter for @[A] { + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { + each(*self, blk) + } + #[cfg(not(stage0))] #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { + each(*self, blk) + } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } } -#[cfg(stage0)] impl<'self,A> old_iter::MutableIter for &'self mut [A] { + #[cfg(stage0)] #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { each_mut(*self, blk) } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -impl<'self,A> old_iter::MutableIter for &'self mut [A] { + #[cfg(not(stage0))] #[inline(always)] - fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) -> bool { each_mut(*self, blk) } } // FIXME(#4148): This should be redundant -#[cfg(stage0)] impl old_iter::MutableIter for ~[A] { + #[cfg(stage0)] #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { each_mut(*self, blk) } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -impl old_iter::MutableIter for ~[A] { + #[cfg(not(stage0))] #[inline(always)] - fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) -> bool { each_mut(*self, blk) } } // FIXME(#4148): This should be redundant +#[cfg(stage0)] impl old_iter::MutableIter for @mut [A] { #[inline(always)] fn each_mut(&mut self, blk: &fn(v: &mut A) -> bool) { @@ -2737,10 +2796,23 @@ impl old_iter::MutableIter for @mut [A] { } } +#[cfg(not(stage0))] +impl old_iter::MutableIter for @mut [A] { + #[inline(always)] + fn each_mut(&mut self, blk: &fn(v: &mut A) -> bool) -> bool { + each_mut(*self, blk) + } +} + impl<'self,A> old_iter::ExtendedIter for &'self [A] { + #[cfg(stage0)] pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { old_iter::eachi(self, blk) } + #[cfg(not(stage0))] + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { + old_iter::eachi(self, blk) + } pub fn all(&self, blk: &fn(&A) -> bool) -> bool { old_iter::all(self, blk) } @@ -2764,16 +2836,27 @@ impl<'self,A> old_iter::ExtendedIter for &'self [A] { impl<'self,A> old_iter::ExtendedMutableIter for &'self mut [A] { #[inline(always)] + #[cfg(stage0)] pub fn eachi_mut(&mut self, blk: &fn(uint, v: &mut A) -> bool) { eachi_mut(*self, blk) } + #[inline(always)] + #[cfg(not(stage0))] + pub fn eachi_mut(&mut self, blk: &fn(uint, v: &mut A) -> bool) -> bool { + eachi_mut(*self, blk) + } } // FIXME(#4148): This should be redundant impl old_iter::ExtendedIter for ~[A] { + #[cfg(stage0)] pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { old_iter::eachi(self, blk) } + #[cfg(not(stage0))] + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { + old_iter::eachi(self, blk) + } pub fn all(&self, blk: &fn(&A) -> bool) -> bool { old_iter::all(self, blk) } @@ -2797,9 +2880,14 @@ impl old_iter::ExtendedIter for ~[A] { // FIXME(#4148): This should be redundant impl old_iter::ExtendedIter for @[A] { + #[cfg(stage0)] pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { old_iter::eachi(self, blk) } + #[cfg(not(stage0))] + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { + old_iter::eachi(self, blk) + } pub fn all(&self, blk: &fn(&A) -> bool) -> bool { old_iter::all(self, blk) } @@ -2888,34 +2976,37 @@ impl old_iter::CopyableOrderedIter for @[A] { } impl<'self,A:Copy> old_iter::CopyableNonstrictIter for &'self [A] { - fn each_val(&const self, f: &fn(A) -> bool) { + fn each_val(&const self, f: &fn(A) -> bool) -> bool { let mut i = 0; while i < self.len() { - if !f(copy self[i]) { break; } + if !f(copy self[i]) { return false; } i += 1; } + return true; } } // FIXME(#4148): This should be redundant impl old_iter::CopyableNonstrictIter for ~[A] { - fn each_val(&const self, f: &fn(A) -> bool) { + fn each_val(&const self, f: &fn(A) -> bool) -> bool { let mut i = 0; while i < uniq_len(self) { - if !f(copy self[i]) { break; } + if !f(copy self[i]) { return false; } i += 1; } + return true; } } // FIXME(#4148): This should be redundant impl old_iter::CopyableNonstrictIter for @[A] { - fn each_val(&const self, f: &fn(A) -> bool) { + fn each_val(&const self, f: &fn(A) -> bool) -> bool { let mut i = 0; while i < self.len() { - if !f(copy self[i]) { break; } + if !f(copy self[i]) { return false; } i += 1; } + return true; } } @@ -2927,18 +3018,12 @@ impl Clone for ~[A] { } // could be implemented with &[T] with .slice(), but this avoids bounds checks -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub struct VecIterator<'self, T> { priv ptr: *T, priv end: *T, priv lifetime: &'self T // FIXME: #5922 } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self, T> Iterator<&'self T> for VecIterator<'self, T> { #[inline] fn next(&mut self) -> Option<&'self T> { @@ -3244,8 +3329,9 @@ mod tests { #[test] fn test_swap_remove_noncopyable() { // Tests that we don't accidentally run destructors twice. - let mut v = ~[::unstable::exclusive(()), ::unstable::exclusive(()), - ::unstable::exclusive(())]; + let mut v = ~[::unstable::sync::exclusive(()), + ::unstable::sync::exclusive(()), + ::unstable::sync::exclusive(())]; let mut _e = v.swap_remove(0); assert!(v.len() == 2); _e = v.swap_remove(1); @@ -3510,7 +3596,7 @@ mod tests { fn sub(a: int, b: &int) -> int { a - *b } - let mut v = ~[1, 2, 3, 4]; + let v = ~[1, 2, 3, 4]; let sum = foldl(0, v, sub); assert!(sum == -10); } @@ -3520,7 +3606,7 @@ mod tests { fn sub(a: &int, b: int) -> int { *a - b } - let mut v = ~[1, 2, 3, 4]; + let v = ~[1, 2, 3, 4]; let sum = foldr(v, 0, sub); assert!(sum == -2); } @@ -3533,7 +3619,7 @@ mod tests { } #[test] - fn test_iter_nonempty() { + fn test_each_nonempty() { let mut i = 0; for each(~[1, 2, 3]) |v| { i += *v; @@ -3542,7 +3628,7 @@ mod tests { } #[test] - fn test_iteri() { + fn test_eachi() { let mut i = 0; for eachi(~[1, 2, 3]) |j, v| { if i == 0 { assert!(*v == 1); } @@ -3594,19 +3680,19 @@ mod tests { let mut results: ~[~[int]]; results = ~[]; - for each_permutation(~[]) |v| { results.push(from_slice(v)); } + for each_permutation(~[]) |v| { results.push(to_owned(v)); } assert!(results == ~[~[]]); results = ~[]; - for each_permutation(~[7]) |v| { results.push(from_slice(v)); } + for each_permutation(~[7]) |v| { results.push(to_owned(v)); } assert!(results == ~[~[7]]); results = ~[]; - for each_permutation(~[1,1]) |v| { results.push(from_slice(v)); } + for each_permutation(~[1,1]) |v| { results.push(to_owned(v)); } assert!(results == ~[~[1,1],~[1,1]]); results = ~[]; - for each_permutation(~[5,2,0]) |v| { results.push(from_slice(v)); } + for each_permutation(~[5,2,0]) |v| { results.push(to_owned(v)); } assert!(results == ~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]); } @@ -3684,7 +3770,7 @@ mod tests { assert!(position_between(~[], 0u, 0u, f).is_none()); fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(position_between(v, 0u, 0u, f).is_none()); assert!(position_between(v, 0u, 1u, f).is_none()); @@ -3713,7 +3799,7 @@ mod tests { fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(find(v, f) == Some((1, 'b'))); assert!(find(v, g).is_none()); @@ -3724,7 +3810,7 @@ mod tests { assert!(find_between(~[], 0u, 0u, f).is_none()); fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(find_between(v, 0u, 0u, f).is_none()); assert!(find_between(v, 0u, 1u, f).is_none()); @@ -3753,7 +3839,7 @@ mod tests { fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(position(v, f) == Some(1u)); assert!(position(v, g).is_none()); @@ -3764,7 +3850,7 @@ mod tests { assert!(rposition_between(~[], 0u, 0u, f).is_none()); fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(rposition_between(v, 0u, 0u, f).is_none()); assert!(rposition_between(v, 0u, 1u, f).is_none()); @@ -3793,7 +3879,7 @@ mod tests { fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(rfind(v, f) == Some((3, 'b'))); assert!(rfind(v, g).is_none()); @@ -3804,7 +3890,7 @@ mod tests { assert!(rfind_between(~[], 0u, 0u, f).is_none()); fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let mut v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert!(rfind_between(v, 0u, 0u, f).is_none()); assert!(rfind_between(v, 0u, 1u, f).is_none()); @@ -4273,7 +4359,7 @@ mod tests { #[ignore(windows)] #[should_fail] fn test_map_fail() { - let mut v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; + let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; do map(v) |_elt| { if i == 2 { @@ -4542,7 +4628,7 @@ mod tests { } i += 0; false - } + }; } #[test] @@ -4557,7 +4643,7 @@ mod tests { } i += 0; false - } + }; } #[test] @@ -4637,4 +4723,14 @@ mod tests { i += 1; } } + + #[test] + fn test_each_val() { + use old_iter::CopyableNonstrictIter; + let mut i = 0; + for [1, 2, 3].each_val |v| { + i += v; + } + assert!(i == 6); + } } diff --git a/src/libfuzzer/fuzzer.rc b/src/libfuzzer/fuzzer.rc index fc1efd3313cbc..c75dc2979f1c0 100644 --- a/src/libfuzzer/fuzzer.rc +++ b/src/libfuzzer/fuzzer.rc @@ -263,7 +263,7 @@ pub fn under(n: uint, it: &fn(uint)) { while i < n { it(i); i += 1u; } } -pub fn as_str(f: @fn(+x: @io::Writer)) -> ~str { +pub fn as_str(f: @fn(x: @io::Writer)) -> ~str { io::with_str_writer(f) } @@ -316,7 +316,7 @@ pub fn check_variants_T(crate: @ast::crate, if L < 100 { do under(uint::min(L, 20)) |i| { error!("Replacing... #%?", uint::to_str(i)); - let fname = str::from_slice(filename.to_str()); + let fname = str::to_owned(filename.to_str()); do under(uint::min(L, 30)) |j| { let fname = fname.to_str(); error!("With... %?", stringifier(things[j], intr)); @@ -693,10 +693,3 @@ pub fn main() { error!("Fuzzer done"); } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librust/rust.rc b/src/librust/rust.rc index ff15fc12ff479..92510be56c3a8 100644 --- a/src/librust/rust.rc +++ b/src/librust/rust.rc @@ -20,6 +20,11 @@ #[license = "MIT/ASL2"]; #[crate_type = "lib"]; +extern mod rustpkg(vers = "0.7-pre"); +extern mod rustdoc(vers = "0.7-pre"); +extern mod rusti(vers = "0.7-pre"); +extern mod rustc(vers = "0.7-pre"); + use core::run; enum ValidUsage { @@ -36,13 +41,13 @@ impl ValidUsage { } enum Action<'self> { - Exec(&'self str), - Call(&'self fn(args: &[~str]) -> ValidUsage) + Call(&'self fn(args: &[~str]) -> ValidUsage), + CallMain(&'static str, &'self fn()), } enum UsageSource<'self> { - UsgExec(&'self str), - UsgStr(&'self str) + UsgStr(&'self str), + UsgCall(&'self fn()), } struct Command<'self> { @@ -55,9 +60,9 @@ struct Command<'self> { static commands: &'static [Command<'static>] = &[ Command{ cmd: "build", - action: Exec("rustc"), + action: CallMain("rustc", rustc::main), usage_line: "compile rust source files", - usage_full: UsgExec("rustc --help") + usage_full: UsgCall(rustc_help), }, Command{ cmd: "run", @@ -81,21 +86,21 @@ static commands: &'static [Command<'static>] = &[ }, Command{ cmd: "doc", - action: Exec("rustdoc"), + action: CallMain("rustdoc", rustdoc::main), usage_line: "generate documentation from doc comments", - usage_full: UsgExec("rustdoc --help") + usage_full: UsgCall(rustdoc::config::usage), }, Command{ cmd: "pkg", - action: Exec("rustpkg"), + action: CallMain("rustpkg", rustpkg::main), usage_line: "download, build, install rust packages", - usage_full: UsgExec("rustpkg --help") + usage_full: UsgCall(rustpkg::usage::general), }, Command{ cmd: "sketch", - action: Exec("rusti"), + action: CallMain("rusti", rusti::main), usage_line: "run a rust interpreter", - usage_full: UsgStr("\nUsage:\trusti") + usage_full: UsgStr("\nUsage:\trusti"), }, Command{ cmd: "help", @@ -109,6 +114,10 @@ static commands: &'static [Command<'static>] = &[ } ]; +fn rustc_help() { + rustc::usage(copy os::args()[0]) +} + fn find_cmd(command_string: &str) -> Option { do commands.find |command| { command.cmd == command_string @@ -120,20 +129,14 @@ fn cmd_help(args: &[~str]) -> ValidUsage { match find_cmd(command_string) { Some(command) => { match command.action { - Exec(s) => io::println(fmt!( + CallMain(prog, _) => io::println(fmt!( "The %s command is an alias for the %s program.", - command.cmd, s)), + command.cmd, prog)), _ => () } match command.usage_full { - UsgStr(msg) => io::println(fmt!("%s\n", msg)), - UsgExec(commandline) => { - let mut words = ~[]; - for str::each_word(commandline) |word| { words.push(word.to_owned()) } - let words = words; - let (prog, args) = (words.head(), words.tail()); - run::run_program(*prog, args); - } + UsgStr(msg) => io::println(fmt!("%s\n", msg)), + UsgCall(f) => f(), } Valid }, @@ -151,17 +154,12 @@ fn cmd_test(args: &[~str]) -> ValidUsage { match args { [filename] => { let test_exec = Path(filename).filestem().unwrap() + "test~"; - if run::run_program("rustc", [ - ~"--test", - filename.to_owned(), - ~"-o", - test_exec.to_owned() - ]) == 0 { - run::run_program(~"./" + test_exec, []); - } + invoke("rustc", &[~"--test", filename.to_owned(), + ~"-o", test_exec.to_owned()], rustc::main); + run::run_program(~"./" + test_exec, []); Valid } - _ => Invalid + _ => Invalid } } @@ -169,32 +167,27 @@ fn cmd_run(args: &[~str]) -> ValidUsage { match args { [filename, ..prog_args] => { let exec = Path(filename).filestem().unwrap() + "~"; - if run::run_program("rustc", [ - filename.to_owned(), - ~"-o", - exec.to_owned() - ]) == 0 { - run::run_program(~"./"+exec, prog_args); - } + invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()], + rustc::main); + run::run_program(~"./"+exec, prog_args); Valid } - _ => Invalid + _ => Invalid } } +fn invoke(prog: &str, args: &[~str], f: &fn()) { + let mut osargs = ~[prog.to_owned()]; + osargs.push_all_move(args.to_owned()); + os::set_args(osargs); + f(); +} + fn do_command(command: &Command, args: &[~str]) -> ValidUsage { match command.action { Call(f) => f(args), - Exec(commandline) => { - let mut words = ~[]; - for str::each_word(commandline) |word| { words.push(word.to_owned()) } - let words = words; - let (prog, prog_args) = (words.head(), words.tail()); - let exitstatus = run::run_program( - *prog, - vec::append(vec::from_slice(prog_args), args) - ); - os::set_exit_status(exitstatus); + CallMain(prog, f) => { + invoke(prog, args, f); Valid } } @@ -232,11 +225,9 @@ pub fn main() { let args = os_args.tail(); if !args.is_empty() { - for commands.each |command| { - if command.cmd == *args.head() { - let result = do_command(command, args.tail()); - if result.is_valid() { return; } - } + for find_cmd(*args.head()).each |command| { + let result = do_command(command, args.tail()); + if result.is_valid() { return; } } } diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs index 70a029ede6f8d..e722e1a33c62b 100644 --- a/src/librustc/back/abi.rs +++ b/src/librustc/back/abi.rs @@ -57,6 +57,13 @@ pub static n_tydesc_fields: uint = 8u; pub static fn_field_code: uint = 0u; pub static fn_field_box: uint = 1u; +// The three fields of a trait object/trait instance: vtable, box, and type +// description. +pub static trt_field_vtable: uint = 0u; +pub static trt_field_box: uint = 1u; +// This field is only present in unique trait objects, so it comes last. +pub static trt_field_tydesc: uint = 2u; + pub static vec_elt_fill: uint = 0u; pub static vec_elt_alloc: uint = 1u; @@ -77,12 +84,3 @@ pub fn bzero_glue_name() -> ~str { return ~"rust_bzero_glue"; } pub fn yield_glue_name() -> ~str { return ~"rust_yield_glue"; } pub fn no_op_type_glue_name() -> ~str { return ~"rust_no_op_type_glue"; } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/arm.rs b/src/librustc/back/arm.rs index 97c3a588a7fc8..dfe5751f21b83 100644 --- a/src/librustc/back/arm.rs +++ b/src/librustc/back/arm.rs @@ -72,14 +72,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-marm"] }; } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 8c442f2d5c9f3..0e2739e40a999 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -22,9 +22,9 @@ use util::ppaux; use core::hash::Streaming; use core::hash; -use core::io::WriterUtil; use core::libc::{c_int, c_uint}; use core::os::consts::{macos, freebsd, linux, android, win32}; +use core::rt::io::Writer; use core::run; use syntax::ast; use syntax::ast_map::{path, path_mod, path_name}; @@ -41,6 +41,11 @@ pub enum output_type { output_type_exe, } +fn write_string(writer: &mut W, string: &str) { + let buffer = str::as_bytes_slice(string); + writer.write(buffer); +} + pub fn llvm_err(sess: Session, msg: ~str) -> ! { unsafe { let cstr = llvm::LLVMRustGetLastError(); @@ -152,9 +157,9 @@ pub mod jit { code: entry, env: ptr::null() }; - let func: &fn(argv: ~[@~str]) = cast::transmute(closure); + let func: &fn() = cast::transmute(closure); - func(~[sess.opts.binary]); + func(); } } } @@ -458,9 +463,11 @@ pub mod write { * */ -pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, - symbol_hasher: &hash::State) -> LinkMeta { - +pub fn build_link_meta(sess: Session, + c: &ast::crate, + output: &Path, + symbol_hasher: &mut hash::State) + -> LinkMeta { struct ProvidedMetas { name: Option<@str>, vers: Option<@str>, @@ -498,7 +505,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, } // This calculates CMH as defined above - fn crate_meta_extras_hash(symbol_hasher: &hash::State, + fn crate_meta_extras_hash(symbol_hasher: &mut hash::State, cmh_items: ~[@ast::meta_item], dep_hashes: ~[~str]) -> @str { fn len_and_str(s: &str) -> ~str { @@ -511,17 +518,17 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, let cmh_items = attr::sort_meta_items(cmh_items); - fn hash(symbol_hasher: &hash::State, m: &@ast::meta_item) { + fn hash(symbol_hasher: &mut hash::State, m: &@ast::meta_item) { match m.node { ast::meta_name_value(key, value) => { - symbol_hasher.write_str(len_and_str(*key)); - symbol_hasher.write_str(len_and_str_lit(value)); + write_string(symbol_hasher, len_and_str(*key)); + write_string(symbol_hasher, len_and_str_lit(value)); } ast::meta_word(name) => { - symbol_hasher.write_str(len_and_str(*name)); + write_string(symbol_hasher, len_and_str(*name)); } ast::meta_list(name, ref mis) => { - symbol_hasher.write_str(len_and_str(*name)); + write_string(symbol_hasher, len_and_str(*name)); for mis.each |m_| { hash(symbol_hasher, m_); } @@ -535,7 +542,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, } for dep_hashes.each |dh| { - symbol_hasher.write_str(len_and_str(*dh)); + write_string(symbol_hasher, len_and_str(*dh)); } // tjc: allocation is unfortunate; need to change core::hash @@ -596,23 +603,26 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, } } -pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str { +pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str { symbol_hasher.result_str() } // This calculates STH for a symbol, as defined above -pub fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &hash::State, t: ty::t, - link_meta: LinkMeta) -> @str { +pub fn symbol_hash(tcx: ty::ctxt, + symbol_hasher: &mut hash::State, + t: ty::t, + link_meta: LinkMeta) + -> @str { // NB: do *not* use abbrevs here as we want the symbol names // to be independent of one another in the crate. symbol_hasher.reset(); - symbol_hasher.write_str(link_meta.name); - symbol_hasher.write_str(~"-"); - symbol_hasher.write_str(link_meta.extras_hash); - symbol_hasher.write_str(~"-"); - symbol_hasher.write_str(encoder::encoded_ty(tcx, t)); + write_string(symbol_hasher, link_meta.name); + write_string(symbol_hasher, ~"-"); + write_string(symbol_hasher, link_meta.extras_hash); + write_string(symbol_hasher, ~"-"); + write_string(symbol_hasher, encoder::encoded_ty(tcx, t)); let mut hash = truncated_hash_result(symbol_hasher); // Prefix with _ so that it never blends into adjacent digits str::unshift_char(&mut hash, '_'); @@ -688,8 +698,8 @@ pub fn exported_name(sess: Session, vers: &str) -> ~str { return mangle(sess, vec::append_one( - vec::append_one(path, path_name(sess.ident_of(hash.to_owned()))), - path_name(sess.ident_of(vers.to_owned())))); + vec::append_one(path, path_name(sess.ident_of(hash))), + path_name(sess.ident_of(vers)))); } pub fn mangle_exported_name(ccx: @CrateContext, @@ -707,14 +717,14 @@ pub fn mangle_internal_name_by_type_only(ccx: @CrateContext, let s = ppaux::ty_to_short_str(ccx.tcx, t); let hash = get_symbol_hash(ccx, t); return mangle(ccx.sess, - ~[path_name(ccx.sess.ident_of(name.to_owned())), + ~[path_name(ccx.sess.ident_of(name)), path_name(ccx.sess.ident_of(s)), - path_name(ccx.sess.ident_of(hash.to_owned()))]); + path_name(ccx.sess.ident_of(hash))]); } pub fn mangle_internal_name_by_path_and_seq(ccx: @CrateContext, path: path, - flav: ~str) -> ~str { + flav: &str) -> ~str { return mangle(ccx.sess, vec::append_one(path, path_name((ccx.names)(flav)))); } @@ -723,7 +733,7 @@ pub fn mangle_internal_name_by_path(ccx: @CrateContext, path: path) -> ~str { return mangle(ccx.sess, path); } -pub fn mangle_internal_name_by_seq(ccx: @CrateContext, flav: ~str) -> ~str { +pub fn mangle_internal_name_by_seq(ccx: @CrateContext, flav: &str) -> ~str { return fmt!("%s_%u", flav, (ccx.names)(flav).repr); } @@ -737,8 +747,8 @@ pub fn output_dll_filename(os: session::os, lm: LinkMeta) -> ~str { session::os_android => (android::DLL_PREFIX, android::DLL_SUFFIX), session::os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX), }; - return str::from_slice(dll_prefix) + libname + - str::from_slice(dll_suffix); + return str::to_owned(dll_prefix) + libname + + str::to_owned(dll_suffix); } // If the user wants an exe generated we need to invoke @@ -747,6 +757,79 @@ pub fn link_binary(sess: Session, obj_filename: &Path, out_filename: &Path, lm: LinkMeta) { + // In the future, FreeBSD will use clang as default compiler. + // It would be flexible to use cc (system's default C compiler) + // instead of hard-coded gcc. + // For win32, there is no cc command, + // so we add a condition to make it use gcc. + let cc_prog: ~str = match sess.opts.linker { + Some(copy linker) => linker, + None => { + if sess.targ_cfg.os == session::os_android { + match &sess.opts.android_cross_path { + &Some(copy path) => { + fmt!("%s/bin/arm-linux-androideabi-gcc", path) + } + &None => { + sess.fatal(~"need Android NDK path for linking \ + (--android-cross-path)") + } + } + } else if sess.targ_cfg.os == session::os_win32 { + ~"gcc" + } else { + ~"cc" + } + } + }; + // The invocations of cc share some flags across platforms + + + let output = if *sess.building_library { + let long_libname = output_dll_filename(sess.targ_cfg.os, lm); + debug!("link_meta.name: %s", lm.name); + debug!("long_libname: %s", long_libname); + debug!("out_filename: %s", out_filename.to_str()); + debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); + + out_filename.dir_path().push(long_libname) + } else { + /*bad*/copy *out_filename + }; + + debug!("output: %s", output.to_str()); + let cc_args = link_args(sess, obj_filename, out_filename, lm); + debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); + // We run 'cc' here + let prog = run::program_output(cc_prog, cc_args); + if 0 != prog.status { + sess.err(fmt!("linking with `%s` failed with code %d", + cc_prog, prog.status)); + sess.note(fmt!("%s arguments: %s", + cc_prog, str::connect(cc_args, ~" "))); + sess.note(prog.err + prog.out); + sess.abort_if_errors(); + } + + // Clean up on Darwin + if sess.targ_cfg.os == session::os_macos { + run::run_program(~"dsymutil", ~[output.to_str()]); + } + + // Remove the temporary object file if we aren't saving temps + if !sess.opts.save_temps { + if ! os::remove_file(obj_filename) { + sess.warn(fmt!("failed to delete object file `%s`", + obj_filename.to_str())); + } + } +} + +pub fn link_args(sess: Session, + obj_filename: &Path, + out_filename: &Path, + lm:LinkMeta) -> ~[~str] { + // Converts a library file-stem into a cc -l argument fn unlib(config: @session::config, stem: ~str) -> ~str { if stem.starts_with("lib") && @@ -757,48 +840,23 @@ pub fn link_binary(sess: Session, } } + let output = if *sess.building_library { let long_libname = output_dll_filename(sess.targ_cfg.os, lm); - debug!("link_meta.name: %s", lm.name); - debug!("long_libname: %s", long_libname); - debug!("out_filename: %s", out_filename.to_str()); - debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); - out_filename.dir_path().push(long_libname) } else { /*bad*/copy *out_filename }; - debug!("output: %s", output.to_str()); - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str(); - // In the future, FreeBSD will use clang as default compiler. - // It would be flexible to use cc (system's default C compiler) - // instead of hard-coded gcc. - // For win32, there is no cc command, - // so we add a condition to make it use gcc. - let cc_prog: ~str = if sess.targ_cfg.os == session::os_android { - match &sess.opts.android_cross_path { - &Some(copy path) => { - fmt!("%s/bin/arm-linux-androideabi-gcc", path) - } - &None => { - sess.fatal(~"need Android NDK path for linking \ - (--android-cross-path)") - } - } - } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } - else { ~"cc" }; - // The invocations of cc share some flags across platforms + let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - let mut cc_args = - vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - cc_args.push(~"-o"); - cc_args.push(output.to_str()); - cc_args.push(obj_filename.to_str()); + args.push(~"-o"); + args.push(output.to_str()); + args.push(obj_filename.to_str()); let lib_cmd; let os = sess.targ_cfg.os; @@ -813,23 +871,23 @@ pub fn link_binary(sess: Session, let cstore = sess.cstore; for cstore::get_used_crate_files(cstore).each |cratepath| { if cratepath.filetype() == Some(~".rlib") { - cc_args.push(cratepath.to_str()); + args.push(cratepath.to_str()); loop; } let dir = cratepath.dirname(); - if dir != ~"" { cc_args.push(~"-L" + dir); } + if dir != ~"" { args.push(~"-L" + dir); } let libarg = unlib(sess.targ_cfg, cratepath.filestem().get()); - cc_args.push(~"-l" + libarg); + args.push(~"-l" + libarg); } let ula = cstore::get_used_link_args(cstore); - for ula.each |arg| { cc_args.push(/*bad*/copy *arg); } + for ula.each |arg| { args.push(/*bad*/copy *arg); } // Add all the link args for external crates. do cstore::iter_crate_data(cstore) |crate_num, _| { let link_args = csearch::get_link_args_for_crate(cstore, crate_num); do vec::consume(link_args) |_, link_arg| { - cc_args.push(link_arg); + args.push(link_arg); } } @@ -842,20 +900,20 @@ pub fn link_binary(sess: Session, // forces to make sure that library can be found at runtime. for sess.opts.addl_lib_search_paths.each |path| { - cc_args.push(~"-L" + path.to_str()); + args.push(~"-L" + path.to_str()); } // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); - for used_libs.each |l| { cc_args.push(~"-l" + *l); } + for used_libs.each |l| { args.push(~"-l" + *l); } if *sess.building_library { - cc_args.push(lib_cmd); + args.push(lib_cmd); // On mac we need to tell the linker to let this library // be rpathed if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-install_name,@rpath/" + args.push(~"-Wl,-install_name,@rpath/" + output.filename().get()); } } @@ -863,27 +921,27 @@ pub fn link_binary(sess: Session, // On linux librt and libdl are an indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically if sess.targ_cfg.os == session::os_linux { - cc_args.push_all(~[~"-lrt", ~"-ldl"]); + args.push_all(~[~"-lrt", ~"-ldl"]); // LLVM implements the `frem` instruction as a call to `fmod`, // which lives in libm. Similar to above, on some linuxes we // have to be explicit about linking to it. See #2510 - cc_args.push(~"-lm"); + args.push(~"-lm"); } else if sess.targ_cfg.os == session::os_android { - cc_args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", + args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]); - cc_args.push(~"-lm"); + args.push(~"-lm"); } if sess.targ_cfg.os == session::os_freebsd { - cc_args.push_all(~[~"-pthread", ~"-lrt", - ~"-L/usr/local/lib", ~"-lexecinfo", - ~"-L/usr/local/lib/gcc46", - ~"-L/usr/local/lib/gcc44", ~"-lstdc++", - ~"-Wl,-z,origin", - ~"-Wl,-rpath,/usr/local/lib/gcc46", - ~"-Wl,-rpath,/usr/local/lib/gcc44"]); + args.push_all(~[~"-pthread", ~"-lrt", + ~"-L/usr/local/lib", ~"-lexecinfo", + ~"-L/usr/local/lib/gcc46", + ~"-L/usr/local/lib/gcc44", ~"-lstdc++", + ~"-Wl,-z,origin", + ~"-Wl,-rpath,/usr/local/lib/gcc46", + ~"-Wl,-rpath,/usr/local/lib/gcc44"]); } // OS X 10.6 introduced 'compact unwind info', which is produced by the @@ -891,50 +949,21 @@ pub fn link_binary(sess: Session, // understand how to unwind our __morestack frame, so we have to turn it // off. This has impacted some other projects like GHC. if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-no_compact_unwind"); + args.push(~"-Wl,-no_compact_unwind"); } // Stack growth requires statically linking a __morestack function - cc_args.push(~"-lmorestack"); + args.push(~"-lmorestack"); // Always want the runtime linked in - cc_args.push(~"-lrustrt"); + args.push(~"-lrustrt"); // FIXME (#2397): At some point we want to rpath our guesses as to where // extern libraries might live, based on the addl_lib_search_paths - cc_args.push_all(rpath::get_rpath_flags(sess, &output)); - - debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); - // We run 'cc' here - let prog = run::program_output(cc_prog, cc_args); - if 0 != prog.status { - sess.err(fmt!("linking with `%s` failed with code %d", - cc_prog, prog.status)); - sess.note(fmt!("%s arguments: %s", - cc_prog, str::connect(cc_args, ~" "))); - sess.note(prog.err + prog.out); - sess.abort_if_errors(); - } + args.push_all(rpath::get_rpath_flags(sess, &output)); - // Clean up on Darwin - if sess.targ_cfg.os == session::os_macos { - run::run_program(~"dsymutil", ~[output.to_str()]); - } + // Finally add all the linker arguments provided on the command line + args.push_all(sess.opts.linker_args); - // Remove the temporary object file if we aren't saving temps - if !sess.opts.save_temps { - if ! os::remove_file(obj_filename) { - sess.warn(fmt!("failed to delete object file `%s`", - obj_filename.to_str())); - } - } + return args; } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs index 93c1879eb0f4b..b15306a56b0b9 100644 --- a/src/librustc/back/mips.rs +++ b/src/librustc/back/mips.rs @@ -72,14 +72,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[] }; } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index fab19b681740c..fceff55abf8d4 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -40,7 +40,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) // where rustrt is and we know every rust program needs it let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess)); - let rpaths = get_rpaths(os, &sysroot, output, libs, + let rpaths = get_rpaths(os, sysroot, output, libs, sess.opts.target_triple); rpaths_to_flags(rpaths) } diff --git a/src/librustc/back/upcall.rs b/src/librustc/back/upcall.rs index 4cdd279e2fc25..4d2ea4eb4a642 100644 --- a/src/librustc/back/upcall.rs +++ b/src/librustc/back/upcall.rs @@ -34,9 +34,9 @@ pub fn declare_upcalls(targ_cfg: @session::config, fn nothrow(f: ValueRef) -> ValueRef { base::set_no_unwind(f); f } - let d: &fn(+a: ~str, +b: ~[TypeRef], +c: TypeRef) -> ValueRef = + let d: &fn(a: ~str, b: ~[TypeRef], c: TypeRef) -> ValueRef = |a,b,c| decl(llmod, ~"upcall_", a, b, c); - let dv: &fn(+a: ~str, +b: ~[TypeRef]) -> ValueRef = + let dv: &fn(a: ~str, b: ~[TypeRef]) -> ValueRef = |a,b| decl(llmod, ~"upcall_", a, b, T_void()); let int_t = T_int(targ_cfg); @@ -59,12 +59,3 @@ pub fn declare_upcalls(targ_cfg: @session::config, nothrow(dv(~"reset_stack_limit", ~[])) } } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs index 2cc812c3d4105..759f5f63c9ec2 100644 --- a/src/librustc/back/x86.rs +++ b/src/librustc/back/x86.rs @@ -55,13 +55,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-m32"] }; } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs index b68073974dcf9..ed6f1d285147e 100644 --- a/src/librustc/back/x86_64.rs +++ b/src/librustc/back/x86_64.rs @@ -63,13 +63,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-m64"] }; } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 2e64c0c45bffe..f54879b36bdb3 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -91,9 +91,9 @@ pub fn default_configuration(sess: Session, argv0: @~str, input: &input) -> }; return ~[ // Target bindings. - attr::mk_word_item(@str::from_slice(os::FAMILY)), + attr::mk_word_item(@str::to_owned(os::FAMILY)), mk(@~"target_os", @tos), - mk(@~"target_family", @str::from_slice(os::FAMILY)), + mk(@~"target_family", @str::to_owned(os::FAMILY)), mk(@~"target_arch", @arch), mk(@~"target_endian", @end), mk(@~"target_word_size", @wordsz), @@ -119,9 +119,8 @@ pub fn build_configuration(sess: Session, argv0: @~str, input: &input) -> let default_cfg = default_configuration(sess, argv0, input); let user_cfg = /*bad*/copy sess.opts.cfg; // If the user wants a test runner, then add the test cfg - let user_cfg = append_configuration( - user_cfg, - if sess.opts.test { ~"test" } else { ~"notest" }); + let user_cfg = if sess.opts.test { append_configuration(user_cfg, ~"test") } + else { user_cfg }; // If the user requested GC, then add the GC cfg let user_cfg = append_configuration( user_cfg, @@ -183,16 +182,16 @@ pub fn compile_rest(sess: Session, *sess.building_library = session::building_library( sess.opts.crate_type, crate, sess.opts.test); + crate = time(time_passes, ~"expansion", || + syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg, + crate)); + crate = time(time_passes, ~"configuration", || front::config::strip_unconfigured_items(crate)); crate = time(time_passes, ~"maybe building test harness", || front::test::modify_for_testing(sess, crate)); - crate = time(time_passes, ~"expansion", || - syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg, - crate)); - if upto == cu_expand { return (crate, None); } crate = time(time_passes, ~"intrinsic injection", || @@ -225,6 +224,9 @@ pub fn compile_rest(sess: Session, time(time_passes, ~"resolution", || middle::resolve::resolve_crate(sess, lang_items, crate)); + time(time_passes, ~"looking for entry point", + || middle::entry::find_entry_point(sess, crate, ast_map)); + let freevars = time(time_passes, ~"freevar finding", || freevars::annotate_freevars(def_map, crate)); @@ -234,7 +236,6 @@ pub fn compile_rest(sess: Session, let rp_set = time(time_passes, ~"region parameterization inference", || middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); - let outputs = outputs.get(); let (llmod, link_meta) = { @@ -263,7 +264,7 @@ pub fn compile_rest(sess: Session, middle::check_loop::check_crate(ty_cx, crate)); let middle::moves::MoveMaps {moves_map, variable_moves_map, - capture_map} = + moved_variables_set, capture_map} = time(time_passes, ~"compute moves", || middle::moves::compute_moves(ty_cx, method_map, crate)); @@ -271,20 +272,19 @@ pub fn compile_rest(sess: Session, middle::check_match::check_crate(ty_cx, method_map, moves_map, crate)); - let last_use_map = - time(time_passes, ~"liveness checking", || - middle::liveness::check_crate(ty_cx, method_map, - variable_moves_map, - capture_map, crate)); + time(time_passes, ~"liveness checking", || + middle::liveness::check_crate(ty_cx, method_map, + variable_moves_map, + capture_map, crate)); - let (root_map, mutbl_map, write_guard_map) = + let (root_map, write_guard_map) = time(time_passes, ~"borrow checking", || middle::borrowck::check_crate(ty_cx, method_map, - moves_map, capture_map, - crate)); + moves_map, moved_variables_set, + capture_map, crate)); time(time_passes, ~"kind checking", || - kind::check_crate(ty_cx, method_map, last_use_map, crate)); + kind::check_crate(ty_cx, method_map, crate)); time(time_passes, ~"lint checking", || lint::check_crate(ty_cx, crate)); @@ -292,9 +292,7 @@ pub fn compile_rest(sess: Session, if upto == cu_no_trans { return (crate, Some(ty_cx)); } let maps = astencode::Maps { - mutbl_map: mutbl_map, root_map: root_map, - last_use_map: last_use_map, method_map: method_map, vtable_map: vtable_map, write_guard_map: write_guard_map, @@ -309,6 +307,11 @@ pub fn compile_rest(sess: Session, }; + if (sess.opts.debugging_opts & session::print_link_args) != 0 { + io::println(str::connect(link::link_args(sess, + &outputs.obj_filename, &outputs.out_filename, link_meta), " ")); + } + // NB: Android hack if sess.targ_cfg.arch == abi::Arm && (sess.opts.output_type == link::output_type_object || @@ -599,15 +602,10 @@ pub fn build_session_options(binary: @~str, link::output_type_bitcode } else { link::output_type_exe }; let sysroot_opt = getopts::opt_maybe_str(matches, ~"sysroot"); - let sysroot_opt = sysroot_opt.map(|m| Path(*m)); + let sysroot_opt = sysroot_opt.map(|m| @Path(*m)); let target_opt = getopts::opt_maybe_str(matches, ~"target"); let target_feature_opt = getopts::opt_maybe_str(matches, ~"target-feature"); let save_temps = getopts::opt_present(matches, ~"save-temps"); - match output_type { - // unless we're emitting huamn-readable assembly, omit comments. - link::output_type_llvm_assembly | link::output_type_assembly => (), - _ => debugging_opts |= session::no_asm_comments - } let opt_level = { if (debugging_opts & session::no_opt) != 0 { No @@ -634,7 +632,7 @@ pub fn build_session_options(binary: @~str, let extra_debuginfo = debugging_opts & session::extra_debug_info != 0; let debuginfo = debugging_opts & session::debug_info != 0 || extra_debuginfo; - let static = debugging_opts & session::static != 0; + let statik = debugging_opts & session::statik != 0; let target = match target_opt { None => host_triple(), @@ -645,16 +643,24 @@ pub fn build_session_options(binary: @~str, Some(s) => s }; - let addl_lib_search_paths = - getopts::opt_strs(matches, ~"L") - .map(|s| Path(*s)); + let addl_lib_search_paths = getopts::opt_strs(matches, ~"L").map(|s| Path(*s)); + let linker = getopts::opt_maybe_str(matches, ~"linker"); + let linker_args = getopts::opt_strs(matches, ~"link-args").flat_map( |a| { + let mut args = ~[]; + for str::each_split_char(*a, ' ') |arg| { + args.push(str::to_owned(arg)); + } + args + }); + let cfg = parse_cfgspecs(getopts::opt_strs(matches, ~"cfg"), demitter); let test = opt_present(matches, ~"test"); let android_cross_path = getopts::opt_maybe_str( matches, ~"android-cross-path"); + let sopts = @session::options { crate_type: crate_type, - is_static: static, + is_static: statik, gc: gc, optimize: opt_level, debuginfo: debuginfo, @@ -664,6 +670,8 @@ pub fn build_session_options(binary: @~str, jit: jit, output_type: output_type, addl_lib_search_paths: addl_lib_search_paths, + linker: linker, + linker_args: linker_args, maybe_sysroot: sysroot_opt, target_triple: target, target_feature: target_feature, @@ -737,62 +745,65 @@ pub fn parse_pretty(sess: Session, name: &str) -> pp_mode { // rustc command line options pub fn optgroups() -> ~[getopts::groups::OptGroup] { ~[ - optflag(~"", ~"bin", ~"Compile an executable crate (default)"), - optflag(~"c", ~"", ~"Compile and assemble, but do not link"), - optmulti(~"", ~"cfg", ~"Configure the compilation - environment", ~"SPEC"), - optflag(~"", ~"emit-llvm", - ~"Produce an LLVM bitcode file"), - optflag(~"h", ~"help",~"Display this message"), - optmulti(~"L", ~"", ~"Add a directory to the library search path", - ~"PATH"), - optflag(~"", ~"lib", ~"Compile a library crate"), - optflag(~"", ~"ls", ~"List the symbols defined by a library crate"), - optflag(~"", ~"no-trans", - ~"Run all passes except translation; no output"), - optflag(~"O", ~"", ~"Equivalent to --opt-level=2"), - optopt(~"o", ~"", ~"Write output to ", ~"FILENAME"), - optopt(~"", ~"opt-level", - ~"Optimize with possible levels 0-3", ~"LEVEL"), - optopt( ~"", ~"out-dir", - ~"Write output to compiler-chosen filename - in ", ~"DIR"), - optflag(~"", ~"parse-only", - ~"Parse only; do not compile, assemble, or link"), - optflagopt(~"", ~"pretty", - ~"Pretty-print the input instead of compiling; + optflag("", "bin", "Compile an executable crate (default)"), + optflag("c", "", "Compile and assemble, but do not link"), + optmulti("", "cfg", "Configure the compilation + environment", "SPEC"), + optflag("", "emit-llvm", + "Produce an LLVM bitcode file"), + optflag("h", "help","Display this message"), + optmulti("L", "", "Add a directory to the library search path", + "PATH"), + optflag("", "lib", "Compile a library crate"), + optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"), + optmulti("", "link-args", "FLAGS is a space-separated list of flags + passed to the linker", "FLAGS"), + optflag("", "ls", "List the symbols defined by a library crate"), + optflag("", "no-trans", + "Run all passes except translation; no output"), + optflag("O", "", "Equivalent to --opt-level=2"), + optopt("o", "", "Write output to ", "FILENAME"), + optopt("", "opt-level", + "Optimize with possible levels 0-3", "LEVEL"), + optopt( "", "out-dir", + "Write output to compiler-chosen filename + in ", "DIR"), + optflag("", "parse-only", + "Parse only; do not compile, assemble, or link"), + optflagopt("", "pretty", + "Pretty-print the input instead of compiling; valid types are: normal (un-annotated source), expanded (crates expanded), typed (crates expanded, with type annotations), or identified (fully parenthesized, - AST nodes and blocks with IDs)", ~"TYPE"), - optflag(~"S", ~"", ~"Compile only; do not assemble or link"), - optflag(~"", ~"save-temps", - ~"Write intermediate files (.bc, .opt.bc, .o) + AST nodes and blocks with IDs)", "TYPE"), + optflag("S", "", "Compile only; do not assemble or link"), + optflag("", "save-temps", + "Write intermediate files (.bc, .opt.bc, .o) in addition to normal output"), - optopt(~"", ~"sysroot", - ~"Override the system root", ~"PATH"), - optflag(~"", ~"test", ~"Build a test harness"), - optopt(~"", ~"target", - ~"Target triple cpu-manufacturer-kernel[-os] + optopt("", "sysroot", + "Override the system root", "PATH"), + optflag("", "test", "Build a test harness"), + optopt("", "target", + "Target triple cpu-manufacturer-kernel[-os] to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/ - for detail)", ~"TRIPLE"), - optopt(~"", ~"target-feature", - ~"Target specific attributes (llc -mattr=help - for detail)", ~"FEATURE"), - optopt(~"", ~"android-cross-path", - ~"The path to the Android NDK", "PATH"), - optmulti(~"W", ~"warn", - ~"Set lint warnings", ~"OPT"), - optmulti(~"A", ~"allow", - ~"Set lint allowed", ~"OPT"), - optmulti(~"D", ~"deny", - ~"Set lint denied", ~"OPT"), - optmulti(~"F", ~"forbid", - ~"Set lint forbidden", ~"OPT"), - optmulti(~"Z", ~"", ~"Set internal debugging options", "FLAG"), - optflag( ~"v", ~"version", - ~"Print version info and exit"), + for detail)", "TRIPLE"), + optopt("", "target-feature", + "Target specific attributes (llc -mattr=help + for detail)", "FEATURE"), + optopt("", "android-cross-path", + "The path to the Android NDK", "PATH"), + optmulti("W", "warn", + "Set lint warnings", "OPT"), + optmulti("A", "allow", + "Set lint allowed", "OPT"), + optmulti("D", "deny", + "Set lint denied", "OPT"), + optmulti("F", "forbid", + "Set lint forbidden", "OPT"), + optmulti("Z", "", "Set internal debugging options", "FLAG"), + optflag( "v", "version", + "Print version info and exit"), ] } @@ -936,11 +947,3 @@ mod test { assert!((vec::len(test_items) == 1u)); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 55c81e6d17b20..16eec0b10dea7 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -45,7 +45,7 @@ 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 no_asm_comments: uint = 1 << 5; +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; @@ -62,7 +62,8 @@ 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 static: uint = 1 << 22; +pub static statik: uint = 1 << 22; +pub static print_link_args: uint = 1 << 23; pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"verbose", ~"in general, enable more debug printouts", verbose), @@ -72,7 +73,7 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"time-llvm-passes", ~"measure time of each LLVM pass", time_llvm_passes), (~"trans-stats", ~"gather trans statistics", trans_stats), - (~"no-asm-comments", ~"omit comments when using -S", no_asm_comments), + (~"asm-comments", ~"generate comments into the assembly (may change behavior)", asm_comments), (~"no-verify", ~"skip LLVM verification", no_verify), (~"trace", ~"emit trace logs", trace), (~"coherence", ~"perform coherence checking", coherence), @@ -90,13 +91,14 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"no-opt", ~"do not optimize, even if -O is passed", no_opt), (~"no-monomorphic-collapse", ~"do not collapse template instantiations", no_monomorphic_collapse), + (~"print-link-args", ~"Print the arguments passed to the linker", print_link_args), (~"gc", ~"Garbage collect shared data (experimental)", gc), (~"jit", ~"Execute using JIT (experimental)", jit), (~"extra-debug-info", ~"Extra debugging info (experimental)", extra_debug_info), (~"debug-info", ~"Produce debug info (experimental)", debug_info), (~"static", ~"Use or produce static libraries or binaries " + - "(experimental)", static) + "(experimental)", statik) ] } @@ -122,7 +124,9 @@ pub struct options { jit: bool, output_type: back::link::output_type, addl_lib_search_paths: ~[Path], - maybe_sysroot: Option, + linker: Option<~str>, + linker_args: ~[~str], + maybe_sysroot: Option<@Path>, target_triple: ~str, target_feature: ~str, // User-specified cfg meta items. The compiler itself will add additional @@ -172,49 +176,52 @@ pub struct Session_ { pub type Session = @Session_; pub impl Session_ { - fn span_fatal(@self, sp: span, msg: ~str) -> ! { + fn span_fatal(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_fatal(sp, msg) } - fn fatal(@self, msg: ~str) -> ! { + fn fatal(@self, msg: &str) -> ! { self.span_diagnostic.handler().fatal(msg) } - fn span_err(@self, sp: span, msg: ~str) { + fn span_err(@self, sp: span, msg: &str) { self.span_diagnostic.span_err(sp, msg) } - fn err(@self, msg: ~str) { + fn err(@self, msg: &str) { self.span_diagnostic.handler().err(msg) } + fn err_count(@self) -> uint { + self.span_diagnostic.handler().err_count() + } fn has_errors(@self) -> bool { self.span_diagnostic.handler().has_errors() } fn abort_if_errors(@self) { self.span_diagnostic.handler().abort_if_errors() } - fn span_warn(@self, sp: span, msg: ~str) { + fn span_warn(@self, sp: span, msg: &str) { self.span_diagnostic.span_warn(sp, msg) } - fn warn(@self, msg: ~str) { + fn warn(@self, msg: &str) { self.span_diagnostic.handler().warn(msg) } - fn span_note(@self, sp: span, msg: ~str) { + fn span_note(@self, sp: span, msg: &str) { self.span_diagnostic.span_note(sp, msg) } - fn note(@self, msg: ~str) { + fn note(@self, msg: &str) { self.span_diagnostic.handler().note(msg) } - fn span_bug(@self, sp: span, msg: ~str) -> ! { + fn span_bug(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_bug(sp, msg) } - fn bug(@self, msg: ~str) -> ! { + fn bug(@self, msg: &str) -> ! { self.span_diagnostic.handler().bug(msg) } - fn span_unimpl(@self, sp: span, msg: ~str) -> ! { + fn span_unimpl(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_unimpl(sp, msg) } - fn unimpl(@self, msg: ~str) -> ! { + fn unimpl(@self, msg: &str) -> ! { self.span_diagnostic.handler().unimpl(msg) } - fn span_lint_level(@self, level: lint::level, sp: span, msg: ~str) { + fn span_lint_level(@self, level: lint::level, sp: span, msg: &str) { match level { lint::allow => { }, lint::warn => self.span_warn(sp, msg), @@ -227,9 +234,10 @@ pub impl Session_ { expr_id: ast::node_id, item_id: ast::node_id, span: span, - msg: ~str) { + msg: &str) { let level = lint::get_lint_settings_level( self.lint_settings, lint_mode, expr_id, item_id); + let msg = fmt!("%s [-W %s]", msg, lint::get_lint_name(lint_mode)); self.span_lint_level(level, span, msg); } fn next_node_id(@self) -> ast::node_id { @@ -259,7 +267,7 @@ pub impl Session_ { } fn trans_stats(@self) -> bool { self.debugging_opt(trans_stats) } fn meta_stats(@self) -> bool { self.debugging_opt(meta_stats) } - fn no_asm_comments(@self) -> bool { self.debugging_opt(no_asm_comments) } + fn asm_comments(@self) -> bool { self.debugging_opt(asm_comments) } fn no_verify(@self) -> bool { self.debugging_opt(no_verify) } fn trace(@self) -> bool { self.debugging_opt(trace) } fn coherence(@self) -> bool { self.debugging_opt(coherence) } @@ -277,8 +285,8 @@ pub impl Session_ { fn str_of(@self, id: ast::ident) -> @~str { self.parse_sess.interner.get(id) } - fn ident_of(@self, st: ~str) -> ast::ident { - self.parse_sess.interner.intern(@st) + fn ident_of(@self, st: &str) -> ast::ident { + self.parse_sess.interner.intern(st) } fn intr(@self) -> @syntax::parse::token::ident_interner { self.parse_sess.interner @@ -299,6 +307,8 @@ pub fn basic_options() -> @options { jit: false, output_type: link::output_type_exe, addl_lib_search_paths: ~[], + linker: None, + linker_args: ~[], maybe_sysroot: None, target_triple: host_triple(), target_feature: ~"", @@ -426,10 +436,3 @@ mod test { assert!(building_library(lib_crate, crate, true)); } } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 75ae8724d720b..2246dd9d2f0aa 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -194,11 +194,3 @@ pub fn metas_in_cfg(cfg: ast::crate_cfg, }) }) } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/front/core_inject.rs b/src/librustc/front/core_inject.rs index ec5ba74b7cc80..5862dd00b3ce5 100644 --- a/src/librustc/front/core_inject.rs +++ b/src/librustc/front/core_inject.rs @@ -42,7 +42,7 @@ fn inject_libcore_ref(sess: Session, let n1 = sess.next_node_id(); let vi1 = @ast::view_item { node: ast::view_item_extern_mod( - sess.ident_of(~"core"), ~[], n1), + sess.ident_of("core"), ~[], n1), attrs: ~[ spanned(ast::attribute_ { style: ast::attr_inner, @@ -78,8 +78,8 @@ fn inject_libcore_ref(sess: Session, span: dummy_sp(), global: false, idents: ~[ - sess.ident_of(~"core"), - sess.ident_of(~"prelude") + sess.ident_of("core"), + sess.ident_of("prelude") ], rp: None, types: ~[] diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 452623c2742b9..ece53451ccf80 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -132,7 +132,7 @@ pub mod intrinsic { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { pub fn get_tydesc() -> *(); - pub fn visit_tydesc(++td: *TyDesc, ++tv: @TyVisitor); + pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor); } } } diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 02e2a4c8734f8..f556baee918f2 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -69,7 +69,8 @@ fn generate_test_harness(sess: session::Session, testfns: ~[] }; - cx.ext_cx.bt_push(ExpandedFrom(CallInfo { + let ext_cx = cx.ext_cx; + ext_cx.bt_push(ExpandedFrom(CallInfo { call_site: dummy_sp(), callee: NameAndSpan { name: ~"test", @@ -84,7 +85,7 @@ fn generate_test_harness(sess: session::Session, let fold = fold::make_fold(precursor); let res = @fold.fold_crate(&*crate); - cx.ext_cx.bt_pop(); + ext_cx.bt_pop(); return res; } @@ -141,7 +142,7 @@ fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold) debug!("current path: %s", ast_util::path_name_i(copy cx.path, cx.sess.parse_sess.interner)); - if is_test_fn(i) || is_bench_fn(i) { + if is_test_fn(cx, i) || is_bench_fn(i) { match i.node { ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => { let sess = cx.sess; @@ -169,7 +170,7 @@ fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold) return res; } -fn is_test_fn(i: @ast::item) -> bool { +fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { let has_test_attr = !attr::find_attrs_by_name(i.attrs, ~"test").is_empty(); @@ -188,6 +189,13 @@ fn is_test_fn(i: @ast::item) -> bool { } } + if has_test_attr && !has_test_signature(i) { + let sess = cx.sess; + sess.span_err( + i.span, + ~"functions used as tests must have signature fn() -> ()." + ); + } return has_test_attr && has_test_signature(i); } @@ -266,7 +274,7 @@ fn mk_std(cx: &TestCtxt) -> @ast::view_item { let vers = nospan(vers); let mi = ast::meta_name_value(@~"vers", vers); let mi = nospan(mi); - let id_std = cx.sess.ident_of(~"std"); + let id_std = cx.sess.ident_of("std"); let vi = if is_std(cx) { ast::view_item_use( ~[@nospan(ast::view_path_simple(id_std, @@ -314,7 +322,7 @@ fn mk_test_module(cx: &TestCtxt) -> @ast::item { attr::mk_attr(attr::mk_word_item(@~"!resolve_unexported")); let item = ast::item { - ident: cx.sess.ident_of(~"__test"), + ident: cx.sess.ident_of("__test"), attrs: ~[resolve_unexported_attr], id: cx.sess.next_node_id(), node: item_, @@ -456,11 +464,3 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr { ); e } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 31050448e7552..4c61c42a33932 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1339,13 +1339,16 @@ pub mod llvm { PointerVal: ValueRef) -> ValueRef; #[fast_ffi] pub unsafe fn LLVMBuildLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *c_char) - -> ValueRef; + PointerVal: ValueRef, + Name: *c_char) + -> ValueRef; + #[fast_ffi] pub unsafe fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, - Ptr: ValueRef) -> ValueRef; + Ptr: ValueRef) + -> ValueRef; + #[fast_ffi] pub unsafe fn LLVMBuildGEP(B: BuilderRef, Pointer: ValueRef, @@ -1561,12 +1564,29 @@ pub mod llvm { Name: *c_char) -> ValueRef; /* Atomic Operations */ - pub unsafe fn LLVMBuildAtomicCmpXchg(B: BuilderRef, LHS: ValueRef, - CMP: ValueRef, RHS: ValueRef, - ++Order: AtomicOrdering) -> ValueRef; - pub unsafe fn LLVMBuildAtomicRMW(B: BuilderRef, ++Op: AtomicBinOp, - LHS: ValueRef, RHS: ValueRef, - ++Order: AtomicOrdering) -> ValueRef; + pub unsafe fn LLVMBuildAtomicLoad(B: BuilderRef, + PointerVal: ValueRef, + Order: AtomicOrdering) + -> ValueRef; + + pub unsafe fn LLVMBuildAtomicStore(B: BuilderRef, + Val: ValueRef, + Ptr: ValueRef, + Order: AtomicOrdering) + -> ValueRef; + + pub unsafe fn LLVMBuildAtomicCmpXchg(B: BuilderRef, + LHS: ValueRef, + CMP: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering) + -> ValueRef; + pub unsafe fn LLVMBuildAtomicRMW(B: BuilderRef, + Op: AtomicBinOp, + LHS: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering) + -> ValueRef; /* Selected entries from the downcasts. */ #[fast_ffi] @@ -2196,13 +2216,3 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 8e689f3147b6b..d2b71447f4778 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -100,7 +100,6 @@ pub static tag_mod_impl_trait: uint = 0x47u; different tags. */ pub static tag_item_impl_method: uint = 0x48u; -pub static tag_item_dtor: uint = 0x49u; pub static tag_item_trait_method_self_ty: uint = 0x4b; pub static tag_item_trait_method_self_ty_region: uint = 0x4c; @@ -170,4 +169,3 @@ pub struct LinkMeta { vers: @str, extras_hash: @str } - diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 0d0f0d7ab69f3..da7a2c15f30be 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -328,11 +328,3 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { } return @mut cnum_map; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5626714260b87..d8117a87480b7 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -44,14 +44,24 @@ pub fn get_type_param_count(cstore: @mut cstore::CStore, def: ast::def_id) } /// Iterates over all the language items in the given crate. +#[cfg(stage0)] pub fn each_lang_item(cstore: @mut cstore::CStore, cnum: ast::crate_num, f: &fn(ast::node_id, uint) -> bool) { let crate_data = cstore::get_crate_data(cstore, cnum); decoder::each_lang_item(crate_data, f) } +/// Iterates over all the language items in the given crate. +#[cfg(not(stage0))] +pub fn each_lang_item(cstore: @mut cstore::CStore, + cnum: ast::crate_num, + f: &fn(ast::node_id, uint) -> bool) -> bool { + let crate_data = cstore::get_crate_data(cstore, cnum); + decoder::each_lang_item(crate_data, f) +} /// Iterates over all the paths in the given crate. +#[cfg(stage0)] pub fn each_path(cstore: @mut cstore::CStore, cnum: ast::crate_num, f: &fn(&str, decoder::def_like) -> bool) { @@ -61,6 +71,17 @@ pub fn each_path(cstore: @mut cstore::CStore, }; decoder::each_path(cstore.intr, crate_data, get_crate_data, f); } +/// Iterates over all the paths in the given crate. +#[cfg(not(stage0))] +pub fn each_path(cstore: @mut cstore::CStore, + cnum: ast::crate_num, + f: &fn(&str, decoder::def_like) -> bool) -> bool { + let crate_data = cstore::get_crate_data(cstore, cnum); + let get_crate_data: decoder::GetCrateDataCb = |cnum| { + cstore::get_crate_data(cstore, cnum) + }; + decoder::each_path(cstore.intr, crate_data, get_crate_data, f) +} pub fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path { let cstore = tcx.cstore; @@ -70,7 +91,7 @@ pub fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path { // FIXME #1920: This path is not always correct if the crate is not linked // into the root namespace. vec::append(~[ast_map::path_mod(tcx.sess.ident_of( - /*bad*/copy *cdata.name))], path) + *cdata.name))], path) } pub enum found_ast { @@ -230,13 +251,6 @@ pub fn get_impl_method(cstore: @mut cstore::CStore, decoder::get_impl_method(cstore.intr, cdata, def.node, mname) } -/* If def names a class with a dtor, return it. Otherwise, return none. */ -pub fn struct_dtor(cstore: @mut cstore::CStore, def: ast::def_id) - -> Option { - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::struct_dtor(cdata, def.node) -} - pub fn get_item_visibility(cstore: @mut cstore::CStore, def_id: ast::def_id) -> ast::visibility { @@ -250,11 +264,3 @@ pub fn get_link_args_for_crate(cstore: @mut cstore::CStore, let cdata = cstore::get_crate_data(cstore, crate_num); decoder::get_link_args_for_crate(cdata) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 05275a4c66558..21815a9ed4718 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -161,11 +161,3 @@ pub fn get_dep_hashes(cstore: &CStore) -> ~[~str] { sorted.map(|ch| /*bad*/copy *ch.hash) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cfe31360d321b..b8218bc4d4685 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -196,6 +196,7 @@ fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id { |d| parse_def_id(d))); } +#[cfg(stage0)] fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) { for reader::tagged_docs(d, tag_items_data_item_reexport) |reexport_doc| { if !f(reexport_doc) { @@ -203,17 +204,14 @@ fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) { } } } - -fn field_mutability(d: ebml::Doc) -> ast::struct_mutability { - // Use maybe_get_doc in case it's a method - reader::maybe_get_doc(d, tag_struct_mut).map_default( - ast::struct_immutable, - |d| { - match reader::doc_as_u8(*d) as char { - 'm' => ast::struct_mutable, - _ => ast::struct_immutable - } - }) +#[cfg(not(stage0))] +fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool { + for reader::tagged_docs(d, tag_items_data_item_reexport) |reexport_doc| { + if !f(reexport_doc) { + return false; + } + } + return true; } fn variant_disr_val(d: ebml::Doc) -> Option { @@ -244,8 +242,8 @@ fn doc_transformed_self_ty(doc: ebml::Doc, } } -pub fn item_type(_: ast::def_id, item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) - -> ty::t { +pub fn item_type(_item_id: ast::def_id, item: ebml::Doc, + tcx: ty::ctxt, cdata: cmd) -> ty::t { doc_type(item, tcx, cdata) } @@ -274,7 +272,8 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, fn item_ty_region_param(item: ebml::Doc) -> Option { reader::maybe_get_doc(item, tag_region_param).map(|doc| { - Decodable::decode(&reader::Decoder(*doc)) + let mut decoder = reader::Decoder(*doc); + Decodable::decode(&mut decoder) }) } @@ -305,10 +304,10 @@ fn item_path(intr: @ident_interner, item_doc: ebml::Doc) -> ast_map::path { for reader::docs(path_doc) |tag, elt_doc| { if tag == tag_path_elt_mod { let str = reader::doc_as_str(elt_doc); - result.push(ast_map::path_mod(intr.intern(@str))); + result.push(ast_map::path_mod(intr.intern(str))); } else if tag == tag_path_elt_name { let str = reader::doc_as_str(elt_doc); - result.push(ast_map::path_name(intr.intern(@str))); + result.push(ast_map::path_name(intr.intern(str))); } else { // ignore tag_path_len element } @@ -322,7 +321,7 @@ fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident { do reader::with_doc_data(name) |data| { let string = str::from_bytes_slice(data); match intr.find_equiv(&StringRef(string)) { - None => intr.intern(@(string.to_owned())), + None => intr.intern(string), Some(val) => val, } } @@ -445,22 +444,6 @@ pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, found.get() } -pub fn struct_dtor(cdata: cmd, id: ast::node_id) -> Option { - let items = reader::get_doc(reader::Doc(cdata.data), tag_items); - let mut found = None; - let cls_items = match maybe_find_item(id, items) { - Some(it) => it, - None => fail!(fmt!("struct_dtor: class id not found \ - when looking up dtor for %d", id)) - }; - for reader::tagged_docs(cls_items, tag_item_dtor) |doc| { - let doc1 = reader::get_doc(doc, tag_def_id); - let did = reader::with_doc_data(doc1, |d| parse_def_id(d)); - found = Some(translate_def_id(cdata, did)); - }; - found -} - pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str { return item_symbol(lookup_item(id, data)); } @@ -481,6 +464,7 @@ fn def_like_to_def(def_like: def_like) -> ast::def { } /// Iterates over the language items in the given crate. +#[cfg(stage0)] pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) { let root = reader::Doc(cdata.data); let lang_items = reader::get_doc(root, tag_lang_items); @@ -496,11 +480,29 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) { } } } +/// Iterates over the language items in the given crate. +#[cfg(not(stage0))] +pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool { + let root = reader::Doc(cdata.data); + let lang_items = reader::get_doc(root, tag_lang_items); + for reader::tagged_docs(lang_items, tag_lang_items_item) |item_doc| { + let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); + let id = reader::doc_as_u32(id_doc) as uint; + let node_id_doc = reader::get_doc(item_doc, + tag_lang_items_item_node_id); + let node_id = reader::doc_as_u32(node_id_doc) as ast::node_id; + + if !f(node_id, id) { + return false; + } + } + 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) -> bool) { +pub fn _each_path(intr: @ident_interner, cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like) -> bool) -> 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); @@ -582,10 +584,20 @@ pub fn each_path(intr: @ident_interner, cdata: cmd, } } - // If broken, stop here. - if broken { - return; - } + return broken; +} + +#[cfg(stage0)] +pub fn each_path(intr: @ident_interner, cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like) -> bool) { + _each_path(intr, cdata, get_crate_data, f); +} +#[cfg(not(stage0))] +pub fn each_path(intr: @ident_interner, cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like) -> bool) -> bool { + _each_path(intr, cdata, get_crate_data, f) } pub fn get_item_path(intr: @ident_interner, cdata: cmd, id: ast::node_id) @@ -607,7 +619,7 @@ pub fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt, let item_doc = lookup_item(id, cdata.data); let path = { let item_path = item_path(intr, item_doc); - vec::from_slice(item_path.init()) + vec::to_owned(item_path.init()) }; match decode_inlined_item(cdata, tcx, copy path, item_doc) { Some(ref ii) => csearch::found((/*bad*/copy *ii)), @@ -855,7 +867,7 @@ pub fn get_type_name_if_impl(intr: @ident_interner, } for reader::tagged_docs(item, tag_item_impl_type_basename) |doc| { - return Some(intr.intern(@str::from_bytes(reader::doc_data(doc)))); + return Some(intr.intern(str::from_bytes(reader::doc_data(doc)))); } return None; @@ -938,12 +950,10 @@ pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id) if f == PublicField || f == PrivateField || f == InheritedField { let name = item_name(intr, an_item); let did = item_def_id(an_item, cdata); - let mt = field_mutability(an_item); result.push(ty::field_ty { ident: name, id: did, vis: struct_field_family_to_visibility(f), - mutability: mt, }); } } @@ -953,7 +963,6 @@ pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id) ident: special_idents::unnamed_field, id: did, vis: ast::inherited, - mutability: ast::struct_immutable, }); } result @@ -1110,7 +1119,7 @@ pub fn get_crate_deps(intr: @ident_interner, data: @~[u8]) -> ~[crate_dep] { } for reader::tagged_docs(depsdoc, tag_crate_dep) |depdoc| { deps.push(crate_dep {cnum: crate_num, - name: intr.intern(@docstr(depdoc, tag_crate_dep_name)), + name: intr.intern(docstr(depdoc, tag_crate_dep_name)), vers: @docstr(depdoc, tag_crate_dep_vers), hash: @docstr(depdoc, tag_crate_dep_hash)}); crate_num += 1; @@ -1192,11 +1201,3 @@ pub fn get_link_args_for_crate(cdata: cmd) -> ~[~str] { } result } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index dd4ef0d2e688f..02f0cc6e42de5 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -20,7 +20,7 @@ use middle::ty; use middle; use util::ppaux::ty_to_str; -use core::flate; +use std::flate; use core::hash::HashUtil; use core::hashmap::HashMap; use std::serialize::Encodable; @@ -43,7 +43,7 @@ use writer = std::ebml::writer; type abbrev_map = @mut HashMap; pub type encode_inlined_item = @fn(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], ii: ast::inlined_item); @@ -91,37 +91,31 @@ pub fn reachable(ecx: @EncodeContext, id: node_id) -> bool { ecx.reachable.contains(&id) } -fn encode_name(ecx: @EncodeContext, ebml_w: &writer::Encoder, name: ident) { +fn encode_name(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + name: ident) { ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name)); } -fn encode_impl_type_basename(ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_impl_type_basename(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, name: ident) { ebml_w.wr_tagged_str(tag_item_impl_type_basename, *ecx.tcx.sess.str_of(name)); } -pub fn encode_def_id(ebml_w: &writer::Encoder, id: def_id) { +pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: def_id) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } -fn encode_region_param(ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_region_param(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, it: @ast::item) { let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); for opt_rp.each |rp| { - do ebml_w.wr_tag(tag_region_param) { - rp.encode(ebml_w); - } - } -} - -fn encode_mutability(ebml_w: &writer::Encoder, mt: struct_mutability) { - do ebml_w.wr_tag(tag_struct_mut) { - let val = match mt { - struct_immutable => 'a', - struct_mutable => 'm' - }; - ebml_w.writer.write(&[val as u8]); + ebml_w.start_tag(tag_region_param); + rp.encode(ebml_w); + ebml_w.end_tag(); } } @@ -130,8 +124,11 @@ struct entry { pos: uint } -fn add_to_index(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ident], - index: &mut ~[entry<~str>], name: ident) { +fn add_to_index(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ident], + index: &mut ~[entry<~str>], + name: ident) { let mut full_path = ~[]; full_path.push_all(path); full_path.push(name); @@ -143,11 +140,10 @@ fn add_to_index(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ident], }); } -fn encode_trait_ref(ebml_w: &writer::Encoder, +fn encode_trait_ref(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, trait_ref: &ty::TraitRef, - tag: uint) -{ + tag: uint) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -161,15 +157,17 @@ fn encode_trait_ref(ebml_w: &writer::Encoder, } // Item info table encoding -fn encode_family(ebml_w: &writer::Encoder, c: char) { +fn encode_family(ebml_w: &mut writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); ebml_w.writer.write(&[c as u8]); ebml_w.end_tag(); } -pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } +pub fn def_to_str(did: def_id) -> ~str { + fmt!("%d:%d", did.crate, did.node) +} -fn encode_ty_type_param_defs(ebml_w: &writer::Encoder, +fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, params: @~[ty::TypeParameterDef], tag: uint) { @@ -186,23 +184,24 @@ fn encode_ty_type_param_defs(ebml_w: &writer::Encoder, } } -fn encode_type_param_bounds(ebml_w: &writer::Encoder, +fn encode_type_param_bounds(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, params: &OptVec) { let ty_param_defs = - @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); + @params.map_to_vec(|param| ecx.tcx.ty_param_defs.get_copy(¶m.id)); encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, tag_items_data_item_ty_param_bounds); } - -fn encode_variant_id(ebml_w: &writer::Encoder, vid: def_id) { +fn encode_variant_id(ebml_w: &mut writer::Encoder, vid: def_id) { ebml_w.start_tag(tag_items_data_item_variant); ebml_w.writer.write(str::to_bytes(def_to_str(vid))); ebml_w.end_tag(); } -pub fn write_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { +pub fn write_type(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + typ: ty::t) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -212,7 +211,8 @@ pub fn write_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); } -pub fn write_vstore(ecx: @EncodeContext, ebml_w: &writer::Encoder, +pub fn write_vstore(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, vstore: ty::vstore) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, @@ -223,16 +223,17 @@ pub fn write_vstore(ecx: @EncodeContext, ebml_w: &writer::Encoder, tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); } -fn encode_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { +fn encode_type(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + typ: ty::t) { ebml_w.start_tag(tag_items_data_item_type); write_type(ecx, ebml_w, typ); ebml_w.end_tag(); } fn encode_transformed_self_ty(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - opt_typ: Option) -{ + ebml_w: &mut writer::Encoder, + opt_typ: Option) { for opt_typ.each |&typ| { ebml_w.start_tag(tag_item_method_transformed_self_ty); write_type(ecx, ebml_w, typ); @@ -241,9 +242,8 @@ fn encode_transformed_self_ty(ecx: @EncodeContext, } fn encode_method_fty(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - typ: &ty::BareFnTy) -{ + ebml_w: &mut writer::Encoder, + typ: &ty::BareFnTy) { ebml_w.start_tag(tag_item_method_fty); let ty_str_ctxt = @tyencode::ctxt { @@ -257,7 +257,9 @@ fn encode_method_fty(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { +fn encode_symbol(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); match ecx.item_symbols.find(&id) { Some(x) => { @@ -272,28 +274,32 @@ fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { ebml_w.end_tag(); } -fn encode_discriminant(ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_discriminant(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); + ebml_w.writer.write(str::to_bytes(*ecx.discrim_symbols.get_copy(&id))); ebml_w.end_tag(); } -fn encode_disr_val(_ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_disr_val(_: @EncodeContext, + ebml_w: &mut writer::Encoder, disr_val: int) { ebml_w.start_tag(tag_disr_val); ebml_w.writer.write(str::to_bytes(int::to_str(disr_val))); ebml_w.end_tag(); } -fn encode_parent_item(ebml_w: &writer::Encoder, id: def_id) { +fn encode_parent_item(ebml_w: &mut writer::Encoder, id: def_id) { ebml_w.start_tag(tag_items_data_parent_item); ebml_w.writer.write(str::to_bytes(def_to_str(id))); ebml_w.end_tag(); } -fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: &writer::Encoder, - id: node_id, variants: &[variant], +fn encode_enum_variant_info(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + variants: &[variant], path: &[ast_map::path_elt], index: @mut ~[entry], generics: &ast::Generics) { @@ -333,9 +339,12 @@ fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: &writer::Encoder, } } -fn encode_path(ecx: @EncodeContext, ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], name: ast_map::path_elt) { - fn encode_path_elt(ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_path(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + name: ast_map::path_elt) { + fn encode_path_elt(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, elt: ast_map::path_elt) { let (tag, name) = match elt { ast_map::path_mod(name) => (tag_path_elt_mod, name), @@ -345,17 +354,61 @@ fn encode_path(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.wr_tagged_str(tag, *ecx.tcx.sess.str_of(name)); } - do ebml_w.wr_tag(tag_path) { - ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32); - for path.each |pe| { - encode_path_elt(ecx, ebml_w, *pe); + ebml_w.start_tag(tag_path); + ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32); + for path.each |pe| { + encode_path_elt(ecx, ebml_w, *pe); + } + encode_path_elt(ecx, ebml_w, name); + ebml_w.end_tag(); +} + +fn encode_reexported_static_method(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + exp: &middle::resolve::Export2, + m: @ty::method) { + debug!("(encode static trait method) reexport '%s::%s'", + *exp.name, *ecx.tcx.sess.str_of(m.ident)); + 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(m.def_id)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_items_data_item_reexport_name); + ebml_w.wr_str(*exp.name + "::" + *ecx.tcx.sess.str_of(m.ident)); + ebml_w.end_tag(); + ebml_w.end_tag(); +} + +fn encode_reexported_static_methods(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + mod_path: &[ast_map::path_elt], + exp: &middle::resolve::Export2) { + match ecx.tcx.trait_methods_cache.find(&exp.def_id) { + Some(methods) => { + match ecx.tcx.items.find(&exp.def_id.node) { + Some(&ast_map::node_item(_, path)) => { + if mod_path != *path { + for methods.each |&m| { + if m.self_ty == ast::sty_static { + encode_reexported_static_method(ecx, + ebml_w, + exp, m); + } + } + } + } + _ => {} + } } - encode_path_elt(ecx, ebml_w, name); + _ => {} } } -fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: &writer::Encoder, - md: &_mod, id: node_id, path: &[ast_map::path_elt], +fn encode_info_for_mod(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + md: &_mod, + id: node_id, + path: &[ast_map::path_elt], name: ident) { ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(id)); @@ -401,6 +454,7 @@ fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.wr_str(*exp.name); ebml_w.end_tag(); ebml_w.end_tag(); + encode_reexported_static_methods(ecx, ebml_w, path, exp); } } None => { @@ -412,7 +466,7 @@ fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.end_tag(); } -fn encode_struct_field_family(ebml_w: &writer::Encoder, +fn encode_struct_field_family(ebml_w: &mut writer::Encoder, visibility: visibility) { encode_family(ebml_w, match visibility { public => 'g', @@ -421,7 +475,7 @@ fn encode_struct_field_family(ebml_w: &writer::Encoder, }); } -fn encode_visibility(ebml_w: &writer::Encoder, visibility: visibility) { +fn encode_visibility(ebml_w: &mut writer::Encoder, visibility: visibility) { ebml_w.start_tag(tag_items_data_item_visibility); let ch = match visibility { public => 'y', @@ -432,7 +486,7 @@ fn encode_visibility(ebml_w: &writer::Encoder, visibility: visibility) { ebml_w.end_tag(); } -fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { +fn encode_self_type(ebml_w: &mut writer::Encoder, self_type: ast::self_ty_) { ebml_w.start_tag(tag_item_trait_method_self_ty); // Encode the base self type. @@ -476,17 +530,19 @@ fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { } } -fn encode_method_sort(ebml_w: &writer::Encoder, sort: char) { +fn encode_method_sort(ebml_w: &mut writer::Encoder, sort: char) { ebml_w.start_tag(tag_item_trait_method_sort); ebml_w.writer.write(&[ sort as u8 ]); ebml_w.end_tag(); } /* Returns an index of items in this class */ -fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - fields: &[@struct_field], - global_index: @mut~[entry]) -> ~[entry] { +fn encode_info_for_struct(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + fields: &[@struct_field], + global_index: @mut ~[entry]) + -> ~[entry] { /* Each class has its own index, since different classes may have fields with the same name */ let index = @mut ~[]; @@ -494,13 +550,9 @@ fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, /* We encode both private and public fields -- need to include private fields to get the offsets right */ for fields.each |field| { - let (nm, mt, vis) = match field.node.kind { - named_field(nm, mt, vis) => (nm, mt, vis), - unnamed_field => ( - special_idents::unnamed_field, - struct_immutable, - inherited - ) + let (nm, vis) = match field.node.kind { + named_field(nm, vis) => (nm, vis), + unnamed_field => (special_idents::unnamed_field, inherited) }; let id = field.node.id; @@ -513,7 +565,6 @@ fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, encode_name(ecx, ebml_w, nm); encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); - encode_mutability(ebml_w, mt); encode_def_id(ebml_w, local_def(id)); ebml_w.end_tag(); } @@ -522,7 +573,7 @@ fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, // This is for encoding info for ctors and dtors fn encode_info_for_ctor(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, id: node_id, ident: ident, path: &[ast_map::path_elt], @@ -551,7 +602,7 @@ fn encode_info_for_ctor(ecx: @EncodeContext, } fn encode_info_for_struct_ctor(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], name: ast::ident, ctor_id: node_id, @@ -573,9 +624,8 @@ fn encode_info_for_struct_ctor(ecx: @EncodeContext, } fn encode_method_ty_fields(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - method_ty: &ty::method) -{ + ebml_w: &mut writer::Encoder, + method_ty: &ty::method) { encode_def_id(ebml_w, method_ty.def_id); encode_name(ecx, ebml_w, method_ty.ident); encode_ty_type_param_defs(ebml_w, ecx, @@ -588,7 +638,7 @@ fn encode_method_ty_fields(ecx: @EncodeContext, } fn encode_info_for_method(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, impl_path: &[ast_map::path_elt], should_inline: bool, parent_id: node_id, @@ -658,11 +708,11 @@ fn should_inline(attrs: &[attribute]) -> bool { } } - -fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, - item: @item, index: @mut ~[entry], +fn encode_info_for_item(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + item: @item, + index: @mut ~[entry], path: &[ast_map::path_elt]) { - let tcx = ecx.tcx; let must_write = match item.node { @@ -737,19 +787,21 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, } item_enum(ref enum_definition, ref generics) => { add_to_index(); - do ebml_w.wr_tag(tag_items_data_item) { - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 't'); - 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); - for (*enum_definition).variants.each |v| { - encode_variant_id(ebml_w, local_def(v.node.id)); - } - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); + + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 't'); + 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); + for (*enum_definition).variants.each |v| { + encode_variant_id(ebml_w, local_def(v.node.id)); } + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_region_param(ecx, ebml_w, item); + ebml_w.end_tag(); + encode_enum_variant_info(ecx, ebml_w, item.id, @@ -765,26 +817,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, class itself */ let idx = encode_info_for_struct(ecx, ebml_w, path, struct_def.fields, index); - /* Encode the dtor */ - for struct_def.dtor.each |dtor| { - index.push(entry {val: dtor.node.id, pos: ebml_w.writer.tell()}); - encode_info_for_ctor(ecx, - ebml_w, - dtor.node.id, - ecx.tcx.sess.ident_of( - *ecx.tcx.sess.str_of(item.ident) + - ~"_dtor"), - path, - if generics.ty_params.len() > 0u { - Some(ii_dtor(copy *dtor, - item.ident, - copy *generics, - local_def(item.id))) } - else { - None - }, - generics); - } /* Index the class*/ add_to_index(); @@ -814,22 +846,16 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, } 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)); encode_region_param(ecx, ebml_w, item); - /* Encode the dtor */ - /* Encode id for dtor */ - for struct_def.dtor.each |dtor| { - do ebml_w.wr_tag(tag_item_dtor) { - encode_def_id(ebml_w, local_def(dtor.node.id)); - } - }; /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ for struct_def.fields.each |f| { match f.node.kind { - named_field(ident, _, vis) => { + named_field(ident, vis) => { ebml_w.start_tag(tag_item_field); encode_struct_field_family(ebml_w, vis); encode_name(ecx, ebml_w, ident); @@ -988,7 +1014,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, } fn encode_info_for_foreign_item(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, nitem: @foreign_item, index: @mut ~[entry], path: ast_map::path, @@ -1021,8 +1047,10 @@ fn encode_info_for_foreign_item(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, - crate: &crate) -> ~[entry] { +fn encode_info_for_items(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + crate: &crate) + -> ~[entry] { let index = @mut ~[]; ebml_w.start_tag(tag_items_data); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); @@ -1035,10 +1063,10 @@ fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, let ebml_w = copy *ebml_w; |i, cx, v| { visit::visit_item(i, cx, v); - match *ecx.tcx.items.get(&i.id) { + match ecx.tcx.items.get_copy(&i.id) { ast_map::node_item(_, pt) => { - encode_info_for_item(ecx, &ebml_w, i, - index, *pt); + let mut ebml_w = copy ebml_w; + encode_info_for_item(ecx, &mut ebml_w, i, index, *pt); } _ => fail!(~"bad item") } @@ -1048,10 +1076,14 @@ fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, let ebml_w = copy *ebml_w; |ni, cx, v| { visit::visit_foreign_item(ni, cx, v); - match *ecx.tcx.items.get(&ni.id) { + match ecx.tcx.items.get_copy(&ni.id) { ast_map::node_foreign_item(_, abi, _, pt) => { - encode_info_for_foreign_item(ecx, &ebml_w, ni, - index, /*bad*/copy *pt, + let mut ebml_w = copy ebml_w; + encode_info_for_foreign_item(ecx, + &mut ebml_w, + ni, + index, + /*bad*/copy *pt, abi); } // case for separate item and foreign-item tables @@ -1084,7 +1116,8 @@ fn create_index(index: ~[entry]) -> return buckets_frozen; } -fn encode_index(ebml_w: &writer::Encoder, buckets: ~[@~[entry]], +fn encode_index(ebml_w: &mut writer::Encoder, + buckets: ~[@~[entry]], write_fn: &fn(@io::Writer, &T)) { let writer = ebml_w.writer; ebml_w.start_tag(tag_index); @@ -1093,7 +1126,7 @@ fn encode_index(ebml_w: &writer::Encoder, buckets: ~[@~[entry]], for buckets.each |bucket| { bucket_locs.push(ebml_w.writer.tell()); ebml_w.start_tag(tag_index_buckets_bucket); - for vec::each(**bucket) |elt| { + for (**bucket).each |elt| { ebml_w.start_tag(tag_index_buckets_bucket_elt); assert!(elt.pos < 0xffff_ffff); writer.write_be_u32(elt.pos as u32); @@ -1112,14 +1145,16 @@ fn encode_index(ebml_w: &writer::Encoder, buckets: ~[@~[entry]], ebml_w.end_tag(); } -fn write_str(writer: @io::Writer, s: ~str) { writer.write_str(s); } +fn write_str(writer: @io::Writer, s: ~str) { + writer.write_str(s); +} fn write_int(writer: @io::Writer, &n: &int) { assert!(n < 0x7fff_ffff); writer.write_be_u32(n as u32); } -fn encode_meta_item(ebml_w: &writer::Encoder, mi: @meta_item) { +fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { match mi.node { meta_word(name) => { ebml_w.start_tag(tag_meta_item_word); @@ -1156,7 +1191,7 @@ fn encode_meta_item(ebml_w: &writer::Encoder, mi: @meta_item) { } } -fn encode_attributes(ebml_w: &writer::Encoder, attrs: &[attribute]) { +fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) { ebml_w.start_tag(tag_attributes); for attrs.each |attr| { ebml_w.start_tag(tag_attribute); @@ -1221,7 +1256,7 @@ fn synthesize_crate_attrs(ecx: @EncodeContext, } fn encode_crate_deps(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, cstore: @mut cstore::CStore) { fn get_ordered_deps(ecx: @EncodeContext, cstore: @mut cstore::CStore) -> ~[decoder::crate_dep] { @@ -1262,7 +1297,7 @@ fn encode_crate_deps(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_lang_items(ecx: @EncodeContext, ebml_w: &writer::Encoder) { +fn encode_lang_items(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_lang_items); for ecx.tcx.lang_items.each_item |def_id, i| { @@ -1286,8 +1321,7 @@ fn encode_lang_items(ecx: @EncodeContext, ebml_w: &writer::Encoder) { ebml_w.end_tag(); // tag_lang_items } -fn encode_link_args(ecx: @EncodeContext, - ebml_w: &writer::Encoder) { +fn encode_link_args(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_link_args); let link_args = cstore::get_used_link_args(ecx.cstore); @@ -1300,7 +1334,8 @@ fn encode_link_args(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_crate_dep(ecx: @EncodeContext, ebml_w: &writer::Encoder, +fn encode_crate_dep(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { ebml_w.start_tag(tag_crate_dep); ebml_w.start_tag(tag_crate_dep_name); @@ -1315,7 +1350,7 @@ fn encode_crate_dep(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.end_tag(); } -fn encode_hash(ebml_w: &writer::Encoder, hash: &str) { +fn encode_hash(ebml_w: &mut writer::Encoder, hash: &str) { ebml_w.start_tag(tag_crate_hash); ebml_w.writer.write(str::to_bytes(hash)); ebml_w.end_tag(); @@ -1360,50 +1395,48 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { type_abbrevs: @mut HashMap::new() }; - let ebml_w = writer::Encoder(wr as @io::Writer); + let mut ebml_w = writer::Encoder(wr as @io::Writer); - encode_hash(&ebml_w, ecx.link_meta.extras_hash); + encode_hash(&mut ebml_w, ecx.link_meta.extras_hash); - let mut i = wr.pos; + let mut i = *wr.pos; let crate_attrs = synthesize_crate_attrs(ecx, crate); - encode_attributes(&ebml_w, crate_attrs); - ecx.stats.attr_bytes = wr.pos - i; + encode_attributes(&mut ebml_w, crate_attrs); + ecx.stats.attr_bytes = *wr.pos - i; - i = wr.pos; - encode_crate_deps(ecx, &ebml_w, ecx.cstore); - ecx.stats.dep_bytes = wr.pos - i; + i = *wr.pos; + encode_crate_deps(ecx, &mut ebml_w, ecx.cstore); + ecx.stats.dep_bytes = *wr.pos - i; // Encode the language items. - i = wr.pos; - encode_lang_items(ecx, &ebml_w); - ecx.stats.lang_item_bytes = wr.pos - i; + i = *wr.pos; + encode_lang_items(ecx, &mut ebml_w); + ecx.stats.lang_item_bytes = *wr.pos - i; // Encode the link args. - i = wr.pos; - encode_link_args(ecx, &ebml_w); - ecx.stats.link_args_bytes = wr.pos - i; + i = *wr.pos; + encode_link_args(ecx, &mut ebml_w); + ecx.stats.link_args_bytes = *wr.pos - i; // Encode and index the items. ebml_w.start_tag(tag_items); - i = wr.pos; - let items_index = encode_info_for_items(ecx, &ebml_w, crate); - ecx.stats.item_bytes = wr.pos - i; + i = *wr.pos; + let items_index = encode_info_for_items(ecx, &mut ebml_w, crate); + ecx.stats.item_bytes = *wr.pos - i; - i = wr.pos; + i = *wr.pos; let items_buckets = create_index(items_index); - encode_index(&ebml_w, items_buckets, write_int); - ecx.stats.index_bytes = wr.pos - i; + encode_index(&mut ebml_w, items_buckets, write_int); + ecx.stats.index_bytes = *wr.pos - i; ebml_w.end_tag(); - ecx.stats.total_bytes = wr.pos; + ecx.stats.total_bytes = *wr.pos; if (tcx.sess.meta_stats()) { - - do wr.bytes.each |e| { + for wr.bytes.each |e| { if *e == 0 { ecx.stats.zero_bytes += 1; } - true } io::println("metadata stats:"); @@ -1428,11 +1461,13 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { // // Should be: // - // vec::from_slice(metadata_encoding_version) + + // vec::to_owned(metadata_encoding_version) + + + let writer_bytes: &mut ~[u8] = wr.bytes; (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| { vec::slice(*bytes, 0, 8).to_vec() - }) + flate::deflate_bytes(wr.bytes) + }) + flate::deflate_bytes(*writer_bytes) } // Get the encoded string for a type @@ -1447,12 +1482,3 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { tyencode::enc_ty(wr, cx, t); } } - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index c88d5437c840e..9ef1f3e7b4161 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -20,41 +20,76 @@ pub fn pick_file(file: Path, path: &Path) -> Option { } pub trait FileSearch { - fn sysroot(&self) -> Path; - fn lib_search_paths(&self) -> ~[Path]; + fn sysroot(&self) -> @Path; + #[cfg(stage0)] + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool); + #[cfg(not(stage0))] + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool; fn get_target_lib_path(&self) -> Path; fn get_target_lib_file_path(&self, file: &Path) -> Path; } -pub fn mk_filesearch(maybe_sysroot: &Option, +pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, target_triple: &str, addl_lib_search_paths: ~[Path]) -> @FileSearch { struct FileSearchImpl { - sysroot: Path, + sysroot: @Path, addl_lib_search_paths: ~[Path], target_triple: ~str } impl FileSearch for FileSearchImpl { - fn sysroot(&self) -> Path { /*bad*/copy self.sysroot } - fn lib_search_paths(&self) -> ~[Path] { - let mut paths = /*bad*/copy self.addl_lib_search_paths; - - paths.push( - make_target_lib_path(&self.sysroot, - self.target_triple)); - match get_rustpkg_lib_path_nearest() { - result::Ok(ref p) => paths.push((/*bad*/copy *p)), - result::Err(_) => () + fn sysroot(&self) -> @Path { self.sysroot } + #[cfg(stage0)] + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) { + debug!("filesearch: searching additional lib search paths"); + // a little weird + self.addl_lib_search_paths.each(f); + + debug!("filesearch: searching target lib path"); + if !f(&make_target_lib_path(self.sysroot, + self.target_triple)) { + return; } - match get_rustpkg_lib_path() { - result::Ok(ref p) => paths.push((/*bad*/copy *p)), - result::Err(_) => () + debug!("filesearch: searching rustpkg lib path nearest"); + if match get_rustpkg_lib_path_nearest() { + result::Ok(ref p) => f(p), + result::Err(_) => true + } { + return; + } + debug!("filesearch: searching rustpkg lib path"); + match get_rustpkg_lib_path() { + result::Ok(ref p) => f(p), + result::Err(_) => true + }; + } + #[cfg(not(stage0))] + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool { + debug!("filesearch: searching additional lib search paths"); + // a little weird + self.addl_lib_search_paths.each(f); + + debug!("filesearch: searching target lib path"); + if !f(&make_target_lib_path(self.sysroot, + self.target_triple)) { + return false; } - paths + debug!("filesearch: searching rustpkg lib path nearest"); + if match get_rustpkg_lib_path_nearest() { + result::Ok(ref p) => f(p), + result::Err(_) => true + } { + return true; + } + debug!("filesearch: searching rustpkg lib path"); + match get_rustpkg_lib_path() { + result::Ok(ref p) => f(p), + result::Err(_) => true + } } fn get_target_lib_path(&self) -> Path { - make_target_lib_path(&self.sysroot, self.target_triple) + make_target_lib_path(self.sysroot, self.target_triple) } fn get_target_lib_file_path(&self, file: &Path) -> Path { self.get_target_lib_path().push_rel(file) @@ -66,13 +101,13 @@ pub fn mk_filesearch(maybe_sysroot: &Option, @FileSearchImpl { sysroot: sysroot, addl_lib_search_paths: addl_lib_search_paths, - target_triple: str::from_slice(target_triple) + target_triple: str::to_owned(target_triple) } as @FileSearch } pub fn search(filesearch: @FileSearch, pick: pick) -> Option { let mut rslt = None; - for filesearch.lib_search_paths().each |lib_search_path| { + for filesearch.for_each_lib_search_path() |lib_search_path| { debug!("searching %s", lib_search_path.to_str()); for os::list_dir_path(lib_search_path).each |path| { debug!("testing %s", path.to_str()); @@ -92,7 +127,7 @@ pub fn search(filesearch: @FileSearch, pick: pick) -> Option { pub fn relative_target_lib_path(target_triple: &str) -> Path { Path(libdir()).push_many([~"rustc", - str::from_slice(target_triple), + str::to_owned(target_triple), libdir()]) } @@ -108,10 +143,10 @@ fn get_or_default_sysroot() -> Path { } } -fn get_sysroot(maybe_sysroot: &Option) -> Path { +fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path { match *maybe_sysroot { - option::Some(ref sr) => (/*bad*/copy *sr), - option::None => get_or_default_sysroot() + option::Some(sr) => sr, + option::None => @get_or_default_sysroot() } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index d2982e58038dd..d1510f31a9ece 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -22,7 +22,7 @@ use syntax::parse::token::ident_interner; use syntax::print::pprust; use syntax::{ast, attr}; -use core::flate; +use std::flate; use core::os::consts::{macos, freebsd, linux, android, win32}; pub enum os { @@ -71,7 +71,7 @@ fn libname(cx: &Context) -> (~str, ~str) { os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX), }; - (str::from_slice(dll_prefix), str::from_slice(dll_suffix)) + (str::to_owned(dll_prefix), str::to_owned(dll_suffix)) } fn find_library_crate_aux( @@ -196,7 +196,7 @@ fn get_metadata_section(os: os, while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { let name_buf = llvm::LLVMGetSectionName(si.llsi); let name = unsafe { str::raw::from_c_str(name_buf) }; - debug!("get_matadata_section: name %s", name); + debug!("get_metadata_section: name %s", name); if name == read_meta_section_name(os) { let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; diff --git a/src/librustc/metadata/mod.rs b/src/librustc/metadata/mod.rs index 78d5be4d4ae19..24007380feec1 100644 --- a/src/librustc/metadata/mod.rs +++ b/src/librustc/metadata/mod.rs @@ -18,4 +18,3 @@ pub mod cstore; pub mod csearch; pub mod loader; pub mod filesearch; - diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 011ee115e8c15..c220ae45b1a3f 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -245,6 +245,9 @@ fn parse_region(st: @mut PState) -> ty::Region { 't' => { ty::re_static } + 'e' => { + ty::re_static + } _ => fail!(~"parse_region: bad input") } } @@ -552,28 +555,34 @@ fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef bounds: parse_bounds(st, conv)} } -fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { - let mut bounds = ~[]; +fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds { + let mut param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[] + }; loop { - bounds.push(match next(st) { - 'S' => ty::bound_owned, - 'C' => ty::bound_copy, - 'K' => ty::bound_const, - 'O' => ty::bound_durable, - 'I' => ty::bound_trait(@parse_trait_ref(st, conv)), - '.' => break, - _ => fail!(~"parse_bounds: bad bounds") - }); + match next(st) { + 'S' => { + param_bounds.builtin_bounds.add(ty::BoundOwned); + } + 'C' => { + param_bounds.builtin_bounds.add(ty::BoundCopy); + } + 'K' => { + param_bounds.builtin_bounds.add(ty::BoundConst); + } + 'O' => { + param_bounds.builtin_bounds.add(ty::BoundStatic); + } + 'I' => { + param_bounds.trait_bounds.push(@parse_trait_ref(st, conv)); + } + '.' => { + return @param_bounds; + } + _ => { + fail!(~"parse_bounds: bad bounds") + } + } } - @bounds } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 763b1984b81c8..86088646bcae3 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -17,7 +17,6 @@ use core::hashmap::HashMap; use core::io::WriterUtil; use core::io; use core::uint; -use core::vec; use syntax::abi::AbiSet; use syntax::ast; use syntax::ast::*; @@ -71,30 +70,29 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { w.write_str(result_str); } ac_use_abbrevs(abbrevs) => { - match abbrevs.find(&t) { - Some(a) => { w.write_str(*a.s); return; } - None => { - let pos = w.tell(); - enc_sty(w, cx, /*bad*/copy ty::get(t).sty); - let end = w.tell(); - let len = end - pos; - fn estimate_sz(u: uint) -> uint { - let mut n = u; - let mut len = 0u; - while n != 0u { len += 1u; n = n >> 4u; } - return len; - } - let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); - if abbrev_len < len { - // I.e. it's actually an abbreviation. - let s = ~"#" + uint::to_str_radix(pos, 16u) + ~":" + - uint::to_str_radix(len, 16u) + ~"#"; - let a = ty_abbrev { pos: pos, len: len, s: @s }; - abbrevs.insert(t, a); - } - return; + match abbrevs.find(&t) { + Some(a) => { w.write_str(*a.s); return; } + None => {} } - } + let pos = w.tell(); + enc_sty(w, cx, /*bad*/copy ty::get(t).sty); + let end = w.tell(); + let len = end - pos; + fn estimate_sz(u: uint) -> uint { + let mut n = u; + let mut len = 0u; + while n != 0u { len += 1u; n = n >> 4u; } + return len; + } + let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); + if abbrev_len < len { + // I.e. it's actually an abbreviation. + let s = ~"#" + uint::to_str_radix(pos, 16u) + ~":" + + uint::to_str_radix(len, 16u) + ~"#"; + let a = ty_abbrev { pos: pos, len: len, s: @s }; + abbrevs.insert(t, a); + } + return; } } } @@ -152,6 +150,9 @@ fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { ty::re_static => { w.write_char('t'); } + ty::re_empty => { + w.write_char('e'); + } ty::re_infer(_) => { // these should not crop up after typeck cx.diag.handler().bug(~"Cannot encode region variables"); @@ -395,19 +396,21 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { enc_ty(w, cx, fsig.output); } -fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { - for vec::each(*bs) |bound| { - match *bound { - ty::bound_owned => w.write_char('S'), - ty::bound_copy => w.write_char('C'), - ty::bound_const => w.write_char('K'), - ty::bound_durable => w.write_char('O'), - ty::bound_trait(tp) => { - w.write_char('I'); - enc_trait_ref(w, cx, tp); - } +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::BoundCopy => w.write_char('C'), + ty::BoundConst => w.write_char('K'), + ty::BoundStatic => w.write_char('O'), } } + + for bs.trait_bounds.each |&tp| { + w.write_char('I'); + enc_trait_ref(w, cx, tp); + } + w.write_char('.'); } @@ -416,13 +419,3 @@ pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { w.write_char('|'); enc_bounds(w, cx, v.bounds); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c7c9c110586c7..0afabd53ba95a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -44,9 +44,7 @@ use writer = std::ebml::writer; // Auxiliary maps of things to be encoded pub struct Maps { - mutbl_map: middle::borrowck::mutbl_map, root_map: middle::borrowck::root_map, - last_use_map: middle::liveness::last_use_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, write_guard_map: middle::borrowck::write_guard_map, @@ -78,7 +76,7 @@ trait tr_intern { // Top-level methods. pub fn encode_inlined_item(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], ii: ast::inlined_item, maps: Maps) { @@ -88,11 +86,12 @@ pub fn encode_inlined_item(ecx: @e::EncodeContext, ebml_w.writer.tell()); let id_range = ast_util::compute_id_range_for_inlined_item(&ii); - do ebml_w.wr_tag(c::tag_ast as uint) { - id_range.encode(ebml_w); - encode_ast(ebml_w, simplify_ast(&ii)); - encode_side_tables_for_ii(ecx, maps, ebml_w, &ii); - } + + ebml_w.start_tag(c::tag_ast as uint); + id_range.encode(ebml_w); + encode_ast(ebml_w, simplify_ast(&ii)); + encode_side_tables_for_ii(ecx, maps, ebml_w, &ii); + ebml_w.end_tag(); debug!("< Encoded inlined fn: %s::%s (%u)", ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner), @@ -116,8 +115,8 @@ pub fn decode_inlined_item(cdata: @cstore::crate_metadata, Some(ast_doc) => { debug!("> Decoding inlined fn: %s::?", ast_map::path_to_str(path, tcx.sess.parse_sess.interner)); - let ast_dsr = &reader::Decoder(ast_doc); - let from_id_range = Decodable::decode(ast_dsr); + let mut ast_dsr = reader::Decoder(ast_doc); + let from_id_range = Decodable::decode(&mut ast_dsr); let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range); let xcx = @ExtendedDecodeContext { dcx: dcx, @@ -151,7 +150,7 @@ pub fn decode_inlined_item(cdata: @cstore::crate_metadata, fn reserve_id_range(sess: Session, from_id_range: ast_util::id_range) -> ast_util::id_range { // Handle the case of an empty range: - if ast_util::empty(from_id_range) { return from_id_range; } + if from_id_range.empty() { return from_id_range; } let cnt = from_id_range.max - from_id_range.min; let to_id_min = sess.parse_sess.next_id; let to_id_max = sess.parse_sess.next_id + cnt; @@ -162,7 +161,6 @@ fn reserve_id_range(sess: Session, pub impl ExtendedDecodeContext { fn tr_id(&self, id: ast::node_id) -> ast::node_id { /*! - * * Translates an internal id, meaning a node id that is known * to refer to some part of the item currently being inlined, * such as a local variable or argument. All naked node-ids @@ -173,12 +171,11 @@ pub impl ExtendedDecodeContext { */ // from_id_range should be non-empty - assert!(!ast_util::empty(self.from_id_range)); + assert!(!self.from_id_range.empty()); (id - self.from_id_range.min + self.to_id_range.min) } fn tr_def_id(&self, did: ast::def_id) -> ast::def_id { /*! - * * Translates an EXTERNAL def-id, converting the crate number * from the one used in the encoded data to the current crate * numbers.. By external, I mean that it be translated to a @@ -203,7 +200,6 @@ pub impl ExtendedDecodeContext { } fn tr_intern_def_id(&self, did: ast::def_id) -> ast::def_id { /*! - * * Translates an INTERNAL def-id, meaning a def-id that is * known to refer to some part of the item currently being * inlined. In that case, we want to convert the def-id to @@ -237,22 +233,21 @@ impl tr for span { } trait def_id_encoder_helpers { - fn emit_def_id(&self, did: ast::def_id); + fn emit_def_id(&mut self, did: ast::def_id); } impl def_id_encoder_helpers for S { - fn emit_def_id(&self, did: ast::def_id) { + fn emit_def_id(&mut self, did: ast::def_id) { did.encode(self) } } trait def_id_decoder_helpers { - fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id; + fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; } impl def_id_decoder_helpers for D { - - fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id { + fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id { let did: ast::def_id = Decodable::decode(self); did.tr(xcx) } @@ -273,10 +268,10 @@ impl def_id_decoder_helpers for D { // We also have to adjust the spans: for now we just insert a dummy span, // but eventually we should add entries to the local codemap as required. -fn encode_ast(ebml_w: &writer::Encoder, item: ast::inlined_item) { - do ebml_w.wr_tag(c::tag_tree as uint) { - item.encode(ebml_w) - } +fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) { + ebml_w.start_tag(c::tag_tree as uint); + item.encode(ebml_w); + ebml_w.end_tag(); } // Produces a simplified copy of the AST which does not include things @@ -327,22 +322,13 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item { ast::ii_foreign(i) => { ast::ii_foreign(fld.fold_foreign_item(i)) } - ast::ii_dtor(ref dtor, nm, ref tps, parent_id) => { - let dtor_body = fld.fold_block(&dtor.node.body); - ast::ii_dtor( - codemap::spanned { - node: ast::struct_dtor_ { body: dtor_body, - .. /*bad*/copy (*dtor).node }, - .. (/*bad*/copy *dtor) }, - nm, /*bad*/copy *tps, parent_id) - } } } fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { let chi_doc = par_doc.get(c::tag_tree as uint); - let d = &reader::Decoder(chi_doc); - Decodable::decode(d) + let mut d = reader::Decoder(chi_doc); + Decodable::decode(&mut d) } fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) @@ -363,36 +349,19 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) ast::ii_foreign(i) => { ast::ii_foreign(fld.fold_foreign_item(i)) } - ast::ii_dtor(ref dtor, nm, ref generics, parent_id) => { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_attrs = fld.fold_attributes(/*bad*/copy (*dtor).node.attrs); - let new_generics = fold::fold_generics(generics, fld); - let dtor_id = fld.new_id((*dtor).node.id); - let new_parent = xcx.tr_def_id(parent_id); - let new_self = fld.new_id((*dtor).node.self_id); - ast::ii_dtor( - codemap::spanned { - node: ast::struct_dtor_ { id: dtor_id, - attrs: dtor_attrs, - self_id: new_self, - body: dtor_body }, - .. (/*bad*/copy *dtor) - }, - nm, new_generics, new_parent) - } } } // ______________________________________________________________________ // Encoding and decoding of ast::def -fn encode_def(ebml_w: &writer::Encoder, def: ast::def) { +fn encode_def(ebml_w: &mut writer::Encoder, def: ast::def) { def.encode(ebml_w) } fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { - let dsr = &reader::Decoder(doc); - let def: ast::def = Decodable::decode(dsr); + let mut dsr = reader::Decoder(doc); + let def: ast::def = Decodable::decode(&mut dsr); def.tr(xcx) } @@ -461,11 +430,7 @@ impl tr for ty::AutoAdjustment { impl tr for ty::AutoRef { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoRef { - ty::AutoRef { - kind: self.kind, - region: self.region.tr(xcx), - mutbl: self.mutbl, - } + self.map_region(|r| r.tr(xcx)) } } @@ -474,7 +439,7 @@ impl tr for ty::Region { match *self { ty::re_bound(br) => ty::re_bound(br.tr(xcx)), ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), - ty::re_static | ty::re_infer(*) => *self, + ty::re_empty | ty::re_static | ty::re_infer(*) => *self, ty::re_free(ref fr) => { ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), bound_region: fr.bound_region.tr(xcx)}) @@ -497,18 +462,18 @@ impl tr for ty::bound_region { // ______________________________________________________________________ // Encoding and decoding of freevar information -fn encode_freevar_entry(ebml_w: &writer::Encoder, fv: @freevar_entry) { +fn encode_freevar_entry(ebml_w: &mut writer::Encoder, fv: @freevar_entry) { (*fv).encode(ebml_w) } trait ebml_decoder_helper { - fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry; + fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) + -> freevar_entry; } impl ebml_decoder_helper for reader::Decoder { - fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry { + fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) + -> freevar_entry { let fv: freevar_entry = Decodable::decode(self); fv.tr(xcx) } @@ -527,13 +492,13 @@ impl tr for freevar_entry { // Encoding and decoding of CaptureVar information trait capture_var_helper { - fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar; + fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) + -> moves::CaptureVar; } impl capture_var_helper for reader::Decoder { - fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar { + fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) + -> moves::CaptureVar { let cvar: moves::CaptureVar = Decodable::decode(self); cvar.tr(xcx) } @@ -553,99 +518,50 @@ impl tr for moves::CaptureVar { // Encoding and decoding of method_map_entry trait read_method_map_entry_helper { - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry; + fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) + -> method_map_entry; } -#[cfg(stage0)] fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { - do ebml_w.emit_struct("method_map_entry", 3) { - do ebml_w.emit_field(~"self_arg", 0u) { + ebml_w: &mut writer::Encoder, + mme: method_map_entry) { + do ebml_w.emit_struct("method_map_entry", 3) |ebml_w| { + do ebml_w.emit_struct_field("self_arg", 0u) |ebml_w| { ebml_w.emit_arg(ecx, mme.self_arg); } - do ebml_w.emit_field(~"explicit_self", 2u) { + do ebml_w.emit_struct_field("explicit_self", 2u) |ebml_w| { mme.explicit_self.encode(ebml_w); } - do ebml_w.emit_field(~"origin", 1u) { + do ebml_w.emit_struct_field("origin", 1u) |ebml_w| { mme.origin.encode(ebml_w); } - do ebml_w.emit_field(~"self_mode", 3) { - mme.self_mode.encode(ebml_w); - } - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { - do ebml_w.emit_struct("method_map_entry", 3) { - do ebml_w.emit_struct_field("self_arg", 0u) { - ebml_w.emit_arg(ecx, mme.self_arg); - } - do ebml_w.emit_struct_field("explicit_self", 2u) { - mme.explicit_self.encode(ebml_w); - } - do ebml_w.emit_struct_field("origin", 1u) { - mme.origin.encode(ebml_w); - } - do ebml_w.emit_struct_field("self_mode", 3) { + do ebml_w.emit_struct_field("self_mode", 3) |ebml_w| { mme.self_mode.encode(ebml_w); } } } impl read_method_map_entry_helper for reader::Decoder { - #[cfg(stage0)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { - do self.read_struct("method_map_entry", 3) { - method_map_entry { - self_arg: self.read_field(~"self_arg", 0u, || { - self.read_arg(xcx) - }), - explicit_self: self.read_field(~"explicit_self", 2u, || { - let self_type: ast::self_ty_ = Decodable::decode(self); - self_type - }), - origin: self.read_field(~"origin", 1u, || { - let method_origin: method_origin = - Decodable::decode(self); - method_origin.tr(xcx) - }), - self_mode: self.read_field(~"self_mode", 3, || { - let self_mode: ty::SelfMode = Decodable::decode(self); - self_mode - }), - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { - do self.read_struct("method_map_entry", 3) { + fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) + -> method_map_entry { + do self.read_struct("method_map_entry", 3) |this| { method_map_entry { - self_arg: self.read_struct_field("self_arg", 0u, || { - self.read_arg(xcx) + self_arg: this.read_struct_field("self_arg", 0, |this| { + this.read_arg(xcx) }), - explicit_self: self.read_struct_field("explicit_self", 2, || { - let self_type: ast::self_ty_ = Decodable::decode(self); + explicit_self: this.read_struct_field("explicit_self", + 2, + |this| { + let self_type: ast::self_ty_ = Decodable::decode(this); self_type }), - origin: self.read_struct_field("origin", 1u, || { + origin: this.read_struct_field("origin", 1, |this| { let method_origin: method_origin = - Decodable::decode(self); + Decodable::decode(this); method_origin.tr(xcx) }), - self_mode: self.read_struct_field("self_mode", 3, || { - let self_mode: ty::SelfMode = Decodable::decode(self); + self_mode: this.read_struct_field("self_mode", 3, |this| { + let self_mode: ty::SelfMode = Decodable::decode(this); self_mode }), } @@ -684,88 +600,88 @@ impl tr for method_origin { // Encoding and decoding vtable_res fn encode_vtable_res(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, dr: typeck::vtable_res) { // can't autogenerate this code because automatic code of // 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) |vtable_origin| { + do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| { encode_vtable_origin(ecx, ebml_w, vtable_origin) } } fn encode_vtable_origin(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, vtable_origin: &typeck::vtable_origin) { - do ebml_w.emit_enum(~"vtable_origin") { + do ebml_w.emit_enum(~"vtable_origin") |ebml_w| { match *vtable_origin { typeck::vtable_static(def_id, ref tys, vtable_res) => { - do ebml_w.emit_enum_variant(~"vtable_static", 0u, 3u) { - do ebml_w.emit_enum_variant_arg(0u) { + do ebml_w.emit_enum_variant(~"vtable_static", 0u, 3u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { ebml_w.emit_def_id(def_id) } - do ebml_w.emit_enum_variant_arg(1u) { + do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { ebml_w.emit_tys(ecx, /*bad*/copy *tys); } - do ebml_w.emit_enum_variant_arg(2u) { + do ebml_w.emit_enum_variant_arg(2u) |ebml_w| { encode_vtable_res(ecx, ebml_w, vtable_res); } } } typeck::vtable_param(pn, bn) => { - do ebml_w.emit_enum_variant(~"vtable_param", 1u, 2u) { - do ebml_w.emit_enum_variant_arg(0u) { + do ebml_w.emit_enum_variant(~"vtable_param", 1u, 2u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { ebml_w.emit_uint(pn); } - do ebml_w.emit_enum_variant_arg(1u) { + do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { ebml_w.emit_uint(bn); } } } } } - } trait vtable_decoder_helpers { - fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) + fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res; - fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_origin; + fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { - fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) + fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { - @self.read_to_vec(|| self.read_vtable_origin(xcx) ) + @self.read_to_vec(|this| this.read_vtable_origin(xcx)) } - fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) + fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin { - do self.read_enum("vtable_origin") { - do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| { + do self.read_enum("vtable_origin") |this| { + do this.read_enum_variant(["vtable_static", "vtable_param"]) + |this, i| { match i { 0 => { typeck::vtable_static( - do self.read_enum_variant_arg(0u) { - self.read_def_id(xcx) + do this.read_enum_variant_arg(0u) |this| { + this.read_def_id(xcx) }, - do self.read_enum_variant_arg(1u) { - self.read_tys(xcx) + do this.read_enum_variant_arg(1u) |this| { + this.read_tys(xcx) }, - do self.read_enum_variant_arg(2u) { - self.read_vtable_res(xcx) + do this.read_enum_variant_arg(2u) |this| { + this.read_vtable_res(xcx) } ) } 1 => { typeck::vtable_param( - do self.read_enum_variant_arg(0u) { - self.read_uint() + do this.read_enum_variant_arg(0u) |this| { + this.read_uint() }, - do self.read_enum_variant_arg(1u) { - self.read_uint() + do this.read_enum_variant_arg(1u) |this| { + this.read_uint() } ) } @@ -796,177 +712,154 @@ impl get_ty_str_ctxt for e::EncodeContext { } trait ebml_writer_helpers { - fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg); - fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); - fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore); - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]); - fn emit_type_param_def(&self, + fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg); + fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t); + fn emit_vstore(&mut self, ecx: @e::EncodeContext, vstore: ty::vstore); + fn emit_tys(&mut self, ecx: @e::EncodeContext, tys: &[ty::t]); + fn emit_type_param_def(&mut self, ecx: @e::EncodeContext, type_param_def: &ty::TypeParameterDef); - fn emit_tpbt(&self, ecx: @e::EncodeContext, + fn emit_tpbt(&mut self, + ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty); } impl ebml_writer_helpers for writer::Encoder { - fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t) { - do self.emit_opaque { - e::write_type(ecx, self, ty) + fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t) { + do self.emit_opaque |this| { + e::write_type(ecx, this, ty) } } - fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore) { - do self.emit_opaque { - e::write_vstore(ecx, self, vstore) + fn emit_vstore(&mut self, ecx: @e::EncodeContext, vstore: ty::vstore) { + do self.emit_opaque |this| { + e::write_vstore(ecx, this, vstore) } } - fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg) { - do self.emit_opaque { - tyencode::enc_arg(self.writer, ecx.ty_str_ctxt(), arg); + fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg) { + do self.emit_opaque |this| { + tyencode::enc_arg(this.writer, ecx.ty_str_ctxt(), arg); } } - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]) { - do self.emit_from_vec(tys) |ty| { - self.emit_ty(ecx, *ty) + fn emit_tys(&mut self, ecx: @e::EncodeContext, tys: &[ty::t]) { + do self.emit_from_vec(tys) |this, ty| { + this.emit_ty(ecx, *ty) } } - fn emit_type_param_def(&self, + fn emit_type_param_def(&mut self, ecx: @e::EncodeContext, type_param_def: &ty::TypeParameterDef) { - do self.emit_opaque { - tyencode::enc_type_param_def(self.writer, ecx.ty_str_ctxt(), + do self.emit_opaque |this| { + tyencode::enc_type_param_def(this.writer, + ecx.ty_str_ctxt(), type_param_def) } } - #[cfg(stage0)] - fn emit_tpbt(&self, ecx: @e::EncodeContext, + fn emit_tpbt(&mut self, + ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 2) { - do self.emit_field(~"generics", 0) { - do self.emit_struct("Generics", 2) { - do self.emit_field(~"type_param_defs", 0) { - do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| - { - self.emit_type_param_def(ecx, type_param_def); + do self.emit_struct("ty_param_bounds_and_ty", 2) |this| { + do this.emit_struct_field(~"generics", 0) |this| { + do this.emit_struct("Generics", 2) |this| { + do this.emit_struct_field(~"type_param_defs", 0) |this| { + do this.emit_from_vec(*tpbt.generics.type_param_defs) + |this, type_param_def| { + this.emit_type_param_def(ecx, type_param_def); } } - do self.emit_field(~"region_param", 1) { - tpbt.generics.region_param.encode(self); + do this.emit_struct_field(~"region_param", 1) |this| { + tpbt.generics.region_param.encode(this); } } } - do self.emit_field(~"ty", 1) { - self.emit_ty(ecx, tpbt.ty); - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_tpbt(&self, ecx: @e::EncodeContext, - tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 2) { - do self.emit_struct_field("generics", 0) { - do self.emit_struct("Generics", 2) { - do self.emit_struct_field("type_param_defs", 0) { - do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| - { - self.emit_type_param_def(ecx, type_param_def); - } - } - do self.emit_struct_field("region_param", 1) { - tpbt.generics.region_param.encode(self); - } - } - } - do self.emit_struct_field("ty", 1) { - self.emit_ty(ecx, tpbt.ty); + do this.emit_struct_field(~"ty", 1) |this| { + this.emit_ty(ecx, tpbt.ty); } } } } trait write_tag_and_id { - fn tag(&self, tag_id: c::astencode_tag, f: &fn()); - fn id(&self, id: ast::node_id); + fn tag(&mut self, tag_id: c::astencode_tag, f: &fn(&mut Self)); + fn id(&mut self, id: ast::node_id); } impl write_tag_and_id for writer::Encoder { - fn tag(&self, tag_id: c::astencode_tag, f: &fn()) { - do self.wr_tag(tag_id as uint) { f() } + fn tag(&mut self, + tag_id: c::astencode_tag, + f: &fn(&mut writer::Encoder)) { + self.start_tag(tag_id as uint); + f(self); + self.end_tag(); } - fn id(&self, id: ast::node_id) { + fn id(&mut self, id: ast::node_id) { self.wr_tagged_u64(c::tag_table_id as uint, id as u64) } } fn encode_side_tables_for_ii(ecx: @e::EncodeContext, maps: Maps, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, ii: &ast::inlined_item) { - do ebml_w.wr_tag(c::tag_table as uint) { - let ebml_w = copy *ebml_w; - ast_util::visit_ids_for_inlined_item( - ii, - |id: ast::node_id| { - // Note: this will cause a copy of ebml_w, which is bad as - // it has mut fields. But I believe it's harmless since - // we generate balanced EBML. - /*let ebml_w = copy ebml_w;*/ - encode_side_tables_for_id(ecx, maps, &ebml_w, id) - }); - } + ebml_w.start_tag(c::tag_table as uint); + let new_ebml_w = copy *ebml_w; + ast_util::visit_ids_for_inlined_item( + ii, + |id: ast::node_id| { + // Note: this will cause a copy of ebml_w, which is bad as + // it is mutable. But I believe it's harmless since we generate + // balanced EBML. + let mut new_ebml_w = copy new_ebml_w; + encode_side_tables_for_id(ecx, maps, &mut new_ebml_w, id) + }); + ebml_w.end_tag(); } fn encode_side_tables_for_id(ecx: @e::EncodeContext, maps: Maps, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, id: ast::node_id) { let tcx = ecx.tcx; debug!("Encoding side tables for id %d", id); for tcx.def_map.find(&id).each |def| { - do ebml_w.tag(c::tag_table_def) { + do ebml_w.tag(c::tag_table_def) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { (*def).encode(ebml_w) } } } for tcx.node_types.find(&(id as uint)).each |&ty| { - do ebml_w.tag(c::tag_table_node_type) { + do ebml_w.tag(c::tag_table_node_type) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { ebml_w.emit_ty(ecx, *ty); } } } for tcx.node_type_substs.find(&id).each |tys| { - do ebml_w.tag(c::tag_table_node_type_subst) { + do ebml_w.tag(c::tag_table_node_type_subst) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - ebml_w.emit_tys(ecx, /*bad*/copy **tys) + do ebml_w.tag(c::tag_table_val) |ebml_w| { + ebml_w.emit_tys(ecx, **tys) } } } for tcx.freevars.find(&id).each |&fv| { - do ebml_w.tag(c::tag_table_freevars) { + do ebml_w.tag(c::tag_table_freevars) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(**fv) |fv_entry| { + do ebml_w.tag(c::tag_table_val) |ebml_w| { + do ebml_w.emit_from_vec(**fv) |ebml_w, fv_entry| { encode_freevar_entry(ebml_w, *fv_entry) } } @@ -975,78 +868,61 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, let lid = ast::def_id { crate: ast::local_crate, node: id }; for tcx.tcache.find(&lid).each |&tpbt| { - do ebml_w.tag(c::tag_table_tcache) { + do ebml_w.tag(c::tag_table_tcache) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { ebml_w.emit_tpbt(ecx, *tpbt); } } } for tcx.ty_param_defs.find(&id).each |&type_param_def| { - do ebml_w.tag(c::tag_table_param_defs) { + do ebml_w.tag(c::tag_table_param_defs) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { ebml_w.emit_type_param_def(ecx, type_param_def) } } } - if maps.mutbl_map.contains(&id) { - do ebml_w.tag(c::tag_table_mutbl) { - ebml_w.id(id); - } - } - - for maps.last_use_map.find(&id).each |&m| { - do ebml_w.tag(c::tag_table_last_use) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(/*bad*/ copy **m) |id| { - id.encode(ebml_w); - } - } - } - } - for maps.method_map.find(&id).each |&mme| { - do ebml_w.tag(c::tag_table_method_map) { + do ebml_w.tag(c::tag_table_method_map) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { encode_method_map_entry(ecx, ebml_w, *mme) } } } for maps.vtable_map.find(&id).each |&dr| { - do ebml_w.tag(c::tag_table_vtable_map) { + do ebml_w.tag(c::tag_table_vtable_map) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { encode_vtable_res(ecx, ebml_w, *dr); } } } for tcx.adjustments.find(&id).each |adj| { - do ebml_w.tag(c::tag_table_adjustments) { + do ebml_w.tag(c::tag_table_adjustments) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { + do ebml_w.tag(c::tag_table_val) |ebml_w| { (**adj).encode(ebml_w) } } } if maps.moves_map.contains(&id) { - do ebml_w.tag(c::tag_table_moves_map) { + do ebml_w.tag(c::tag_table_moves_map) |ebml_w| { ebml_w.id(id); } } for maps.capture_map.find(&id).each |&cap_vars| { - do ebml_w.tag(c::tag_table_capture_map) { + do ebml_w.tag(c::tag_table_capture_map) |ebml_w| { ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(*cap_vars) |cap_var| { + do ebml_w.tag(c::tag_table_val) |ebml_w| { + do ebml_w.emit_from_vec(*cap_vars) |ebml_w, cap_var| { cap_var.encode(ebml_w); } } @@ -1067,40 +943,49 @@ impl doc_decoder_helpers for ebml::Doc { } trait ebml_decoder_decoder_helpers { - fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg; - fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t; - fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; - fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef; - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) + fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg; + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t; + fn read_tys(&mut self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; + fn read_type_param_def(&mut self, xcx: @ExtendedDecodeContext) + -> ty::TypeParameterDef; + fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty; - fn convert_def_id(&self, xcx: @ExtendedDecodeContext, + fn convert_def_id(&mut self, + xcx: @ExtendedDecodeContext, source: DefIdSource, - did: ast::def_id) -> ast::def_id; + did: ast::def_id) + -> ast::def_id; } impl ebml_decoder_decoder_helpers for reader::Decoder { - fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg { - do self.read_opaque |doc| { + fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg { + do self.read_opaque |this, doc| { tydecode::parse_arg_data( - doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)) + doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)) } } - fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t { + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode // context. However, we do not bother, because region types // are not used during trans. - return do self.read_opaque |doc| { - + return do self.read_opaque |this, doc| { let ty = tydecode::parse_ty_data( - doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)); + doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)); debug!("read_ty(%s) = %s", - type_string(doc), ty_to_str(xcx.dcx.tcx, ty)); + type_string(doc), + ty_to_str(xcx.dcx.tcx, ty)); ty }; @@ -1114,69 +999,57 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { - self.read_to_vec(|| self.read_ty(xcx) ) + fn read_tys(&mut self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { + self.read_to_vec(|this| this.read_ty(xcx) ) } - fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef { - do self.read_opaque |doc| { + fn read_type_param_def(&mut self, xcx: @ExtendedDecodeContext) + -> ty::TypeParameterDef { + do self.read_opaque |this, doc| { tydecode::parse_type_param_def_data( - doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)) + doc.data, + doc.start, + xcx.dcx.cdata.cnum, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)) } } - #[cfg(stage0)] - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty - { - do self.read_struct("ty_param_bounds_and_ty", 2) { + fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext) + -> ty::ty_param_bounds_and_ty { + do self.read_struct("ty_param_bounds_and_ty", 2) |this| { ty::ty_param_bounds_and_ty { - generics: do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_field(~"region_param", 1, || { - Decodable::decode(self) - }) - } - }, - ty: self.read_field(~"ty", 1, || { - self.read_ty(xcx) - }) - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty - { - do self.read_struct("ty_param_bounds_and_ty", 2) { - ty::ty_param_bounds_and_ty { - generics: do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_struct_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_struct_field(~"region_param", 1, || { - Decodable::decode(self) - }) + generics: do this.read_struct_field("generics", 0) |this| { + do this.read_struct("Generics", 2) |this| { + ty::Generics { + type_param_defs: + this.read_struct_field("type_param_defs", + 0, + |this| { + @this.read_to_vec(|this| + this.read_type_param_def(xcx)) + }), + region_param: + this.read_struct_field("region_param", + 1, + |this| { + Decodable::decode(this) + }) + } } }, - ty: self.read_struct_field("ty", 1, || { - self.read_ty(xcx) + ty: this.read_struct_field("ty", 1, |this| { + this.read_ty(xcx) }) } } } - fn convert_def_id(&self, xcx: @ExtendedDecodeContext, + fn convert_def_id(&mut self, + xcx: @ExtendedDecodeContext, source: tydecode::DefIdSource, - did: ast::def_id) -> ast::def_id { + did: ast::def_id) + -> ast::def_id { /*! * * Converts a def-id that appears in a type. The correct @@ -1212,13 +1085,12 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, found for id %d (orig %d)", tag, id, id0); - if tag == (c::tag_table_mutbl as uint) { - dcx.maps.mutbl_map.insert(id); - } else if tag == (c::tag_table_moves_map as uint) { + if tag == (c::tag_table_moves_map as uint) { dcx.maps.moves_map.insert(id); } else { let val_doc = entry_doc.get(c::tag_table_val as uint); - let val_dsr = &reader::Decoder(val_doc); + let mut val_dsr = reader::Decoder(val_doc); + let val_dsr = &mut val_dsr; if tag == (c::tag_table_def as uint) { let def = decode_def(xcx, val_doc); dcx.tcx.def_map.insert(id, def); @@ -1231,7 +1103,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, let tys = val_dsr.read_tys(xcx); dcx.tcx.node_type_substs.insert(id, tys); } else if tag == (c::tag_table_freevars as uint) { - let fv_info = @val_dsr.read_to_vec(|| { + let fv_info = @val_dsr.read_to_vec(|val_dsr| { @val_dsr.read_freevar_entry(xcx) }); dcx.tcx.freevars.insert(id, fv_info); @@ -1242,11 +1114,6 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, } else if tag == (c::tag_table_param_defs as uint) { let bounds = val_dsr.read_type_param_def(xcx); dcx.tcx.ty_param_defs.insert(id, bounds); - } else if tag == (c::tag_table_last_use as uint) { - let ids = val_dsr.read_to_vec(|| { - xcx.tr_id(val_dsr.read_int()) - }); - dcx.maps.last_use_map.insert(id, @mut ids); } else if tag == (c::tag_table_method_map as uint) { dcx.maps.method_map.insert( id, @@ -1262,7 +1129,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, let cvars = at_vec::from_owned( val_dsr.read_to_vec( - || val_dsr.read_capture_var(xcx))); + |val_dsr| val_dsr.read_capture_var(xcx))); dcx.maps.capture_map.insert(id, cvars); } else { xcx.dcx.tcx.sess.bug( @@ -1278,17 +1145,17 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, // Testing of astencode_gen #[cfg(test)] -fn encode_item_ast(ebml_w: &writer::Encoder, item: @ast::item) { - do ebml_w.wr_tag(c::tag_tree as uint) { - (*item).encode(ebml_w) - } +fn encode_item_ast(ebml_w: &mut writer::Encoder, item: @ast::item) { + ebml_w.start_tag(c::tag_tree as uint); + (*item).encode(ebml_w); + ebml_w.end_tag(); } #[cfg(test)] fn decode_item_ast(par_doc: ebml::Doc) -> @ast::item { let chi_doc = par_doc.get(c::tag_tree as uint); - let d = &reader::Decoder(chi_doc); - @Decodable::decode(d) + let mut d = reader::Decoder(chi_doc); + @Decodable::decode(&mut d) } #[cfg(test)] @@ -1296,7 +1163,7 @@ trait fake_ext_ctxt { fn cfg(&self) -> ast::crate_cfg; fn parse_sess(&self) -> @mut parse::ParseSess; fn call_site(&self) -> span; - fn ident_of(&self, st: ~str) -> ast::ident; + fn ident_of(&self, st: &str) -> ast::ident; } #[cfg(test)] @@ -1313,8 +1180,8 @@ impl fake_ext_ctxt for fake_session { expn_info: None } } - fn ident_of(&self, st: ~str) -> ast::ident { - self.interner.intern(@st) + fn ident_of(&self, st: &str) -> ast::ident { + self.interner.intern(st) } } @@ -1329,8 +1196,8 @@ fn roundtrip(in_item: Option<@ast::item>) { let in_item = in_item.get(); let bytes = do io::with_bytes_writer |wr| { - let ebml_w = writer::Encoder(wr); - encode_item_ast(&ebml_w, in_item); + let mut ebml_w = writer::Encoder(wr); + encode_item_ast(&mut ebml_w, in_item); }; let ebml_doc = reader::Doc(@bytes); let out_item = decode_item_ast(ebml_doc); @@ -1370,7 +1237,7 @@ fn test_simplification() { let ext_cx = mk_ctxt(); let item_in = ast::ii_item(quote_item!( fn new_int_alist() -> alist { - fn eq_int(&&a: int, &&b: int) -> bool { a == b } + fn eq_int(a: int, b: int) -> bool { a == b } return alist {eq_fn: eq_int, data: ~[]}; } ).get()); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 07b6c80d4201c..2f24a8ceb2465 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -18,284 +18,203 @@ // 4. moves do not affect things loaned out in any way use middle::moves; -use middle::typeck::check::PurityState; -use middle::borrowck::{Loan, bckerr, BorrowckCtxt, inherent_mutability}; -use middle::borrowck::{ReqMaps, root_map_key, save_and_restore_managed}; -use middle::borrowck::{MoveError, MoveOk, MoveFromIllegalCmt}; -use middle::borrowck::{MoveWhileBorrowed}; -use middle::mem_categorization::{cat_arg, cat_comp, cat_deref}; -use middle::mem_categorization::{cat_local, cat_rvalue, cat_self}; -use middle::mem_categorization::{cat_special, cmt, gc_ptr, loan_path, lp_arg}; -use middle::mem_categorization::{lp_comp, lp_deref, lp_local}; +use middle::borrowck::*; +use mc = middle::mem_categorization; use middle::ty; -use util::ppaux::ty_to_str; - +use util::ppaux::Repr; use core::hashmap::HashSet; -use core::util::with; -use syntax::ast::m_mutbl; +use syntax::ast::{m_mutbl, m_imm, m_const}; use syntax::ast; use syntax::ast_util; -use syntax::codemap::span; -use syntax::print::pprust; use syntax::visit; +use syntax::codemap::span; -struct CheckLoanCtxt { +struct CheckLoanCtxt<'self> { bccx: @BorrowckCtxt, - req_maps: ReqMaps, - - reported: HashSet, - - declared_purity: @mut PurityState, - fn_args: @mut @~[ast::node_id] -} - -// if we are enforcing purity, why are we doing so? -#[deriving(Eq)] -enum purity_cause { - // enforcing purity because fn was declared pure: - pc_pure_fn, - - // enforce purity because we need to guarantee the - // validity of some alias; `bckerr` describes the - // reason we needed to enforce purity. - pc_cmt(bckerr) -} - -// if we're not pure, why? -#[deriving(Eq)] -enum impurity_cause { - // some surrounding block was marked as 'unsafe' - pc_unsafe, - - // nothing was unsafe, and nothing was pure - pc_default, + dfcx: &'self LoanDataFlow, + all_loans: &'self [Loan], + reported: @mut HashSet, } pub fn check_loans(bccx: @BorrowckCtxt, - req_maps: ReqMaps, - crate: @ast::crate) { + dfcx: &LoanDataFlow, + all_loans: &[Loan], + body: &ast::blk) { + debug!("check_loans(body id=%?)", body.node.id); + let clcx = @mut CheckLoanCtxt { bccx: bccx, - req_maps: req_maps, - reported: HashSet::new(), - declared_purity: @mut PurityState::function(ast::impure_fn, 0), - fn_args: @mut @~[] + dfcx: dfcx, + all_loans: all_loans, + reported: @mut HashSet::new(), }; + let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr, visit_local: check_loans_in_local, visit_block: check_loans_in_block, + visit_pat: check_loans_in_pat, visit_fn: check_loans_in_fn, .. *visit::default_visitor()}); - visit::visit_crate(crate, clcx, vt); + (vt.visit_block)(body, clcx, vt); } -#[deriving(Eq)] -enum assignment_type { - at_straight_up, - at_swap -} - -pub impl assignment_type { - fn checked_by_liveness(&self) -> bool { - // the liveness pass guarantees that immutable local variables - // are only assigned once; but it doesn't consider &mut - match *self { - at_straight_up => true, - at_swap => true - } - } - fn ing_form(&self, desc: ~str) -> ~str { - match *self { - at_straight_up => ~"assigning to " + desc, - at_swap => ~"swapping to and from " + desc - } - } +enum MoveError { + MoveOk, + MoveFromIllegalCmt(mc::cmt), + MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span) } -pub impl CheckLoanCtxt { +pub impl<'self> CheckLoanCtxt<'self> { fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - fn purity(&mut self, scope_id: ast::node_id) - -> Either + #[cfg(stage0)] + fn each_issued_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) { - let default_purity = match self.declared_purity.purity { - // an unsafe declaration overrides all - ast::unsafe_fn => return Right(pc_unsafe), - - // otherwise, remember what was declared as the - // default, but we must scan for requirements - // imposed by the borrow check - ast::pure_fn => Left(pc_pure_fn), - ast::extern_fn | ast::impure_fn => Right(pc_default) - }; - - // scan to see if this scope or any enclosing scope requires - // purity. if so, that overrides the declaration. - - let mut scope_id = scope_id; - loop { - match self.req_maps.pure_map.find(&scope_id) { - None => (), - Some(e) => return Left(pc_cmt(*e)) + //! Iterates over each loan that that has been issued + //! on entrance to `scope_id`, regardless of whether it is + //! actually *in scope* at that point. Sometimes loans + //! are issued for future scopes and thus they may have been + //! *issued* but not yet be in effect. + + for self.dfcx.each_bit_on_entry(scope_id) |loan_index| { + let loan = &self.all_loans[loan_index]; + if !op(loan) { + return; } - - match self.tcx().region_maps.opt_encl_scope(scope_id) { - None => return default_purity, - Some(next_scope_id) => scope_id = next_scope_id + } + } + #[cfg(not(stage0))] + fn each_issued_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) -> bool + { + //! Iterates over each loan that that has been issued + //! on entrance to `scope_id`, regardless of whether it is + //! actually *in scope* at that point. Sometimes loans + //! are issued for future scopes and thus they may have been + //! *issued* but not yet be in effect. + + for self.dfcx.each_bit_on_entry(scope_id) |loan_index| { + let loan = &self.all_loans[loan_index]; + if !op(loan) { + return false; } } + return true; } - fn walk_loans(&self, - mut scope_id: ast::node_id, - f: &fn(v: &Loan) -> bool) { + #[cfg(stage0)] + fn each_in_scope_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) + { + //! Like `each_issued_loan()`, but only considers loans that are + //! currently in scope. - loop { - for self.req_maps.req_loan_map.find(&scope_id).each |loans| { - for loans.each |loan| { - if !f(loan) { return; } + let region_maps = self.tcx().region_maps; + for self.each_issued_loan(scope_id) |loan| { + if region_maps.is_subscope_of(scope_id, loan.kill_scope) { + if !op(loan) { + return; } } - - match self.tcx().region_maps.opt_encl_scope(scope_id) { - None => return, - Some(next_scope_id) => scope_id = next_scope_id, - } } } - - fn walk_loans_of(&mut self, - scope_id: ast::node_id, - lp: @loan_path, - f: &fn(v: &Loan) -> bool) { - for self.walk_loans(scope_id) |loan| { - if loan.lp == lp { - if !f(loan) { return; } + #[cfg(not(stage0))] + fn each_in_scope_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) -> bool + { + //! Like `each_issued_loan()`, but only considers loans that are + //! currently in scope. + + let region_maps = self.tcx().region_maps; + for self.each_issued_loan(scope_id) |loan| { + if region_maps.is_subscope_of(scope_id, loan.kill_scope) { + if !op(loan) { + return false; + } } } + return true; } - // when we are in a pure context, we check each call to ensure - // that the function which is invoked is itself pure. - // - // note: we take opt_expr and expr_id separately because for - // overloaded operators the callee has an id but no expr. - // annoying. - fn check_pure_callee_or_arg(&mut self, - pc: Either, - opt_expr: Option<@ast::expr>, - callee_id: ast::node_id, - callee_span: span) { - let tcx = self.tcx(); - - debug!("check_pure_callee_or_arg(pc=%?, expr=%?, \ - callee_id=%d, ty=%s)", - pc, - opt_expr.map(|e| pprust::expr_to_str(*e, tcx.sess.intr()) ), - callee_id, - ty_to_str(self.tcx(), ty::node_id_to_type(tcx, callee_id))); - - // Purity rules: an expr B is a legal callee or argument to a - // call within a pure function A if at least one of the - // following holds: - // - // (a) A was declared pure and B is one of its arguments; - // (b) B is a stack closure; - // (c) B is a pure fn; - // (d) B is not a fn. - - match opt_expr { - Some(expr) => { - match expr.node { - ast::expr_path(_) if pc == Left(pc_pure_fn) => { - let def = *self.tcx().def_map.get(&expr.id); - let did = ast_util::def_id_of_def(def); - let is_fn_arg = - did.crate == ast::local_crate && - (*self.fn_args).contains(&(did.node)); - if is_fn_arg { return; } // case (a) above - } - ast::expr_fn_block(*) | ast::expr_loop_body(*) | - ast::expr_do_body(*) => { - if self.is_stack_closure(expr.id) { - // case (b) above - return; + #[cfg(stage0)] + fn each_in_scope_restriction(&self, + scope_id: ast::node_id, + loan_path: @LoanPath, + op: &fn(&Loan, &Restriction) -> bool) + { + //! Iterates through all the in-scope restrictions for the + //! given `loan_path` + + for self.each_in_scope_loan(scope_id) |loan| { + for loan.restrictions.each |restr| { + if restr.loan_path == loan_path { + if !op(loan, restr) { + return; + } } - } - _ => () } - } - None => () } - - let callee_ty = ty::node_id_to_type(tcx, callee_id); - match ty::get(callee_ty).sty { - ty::ty_bare_fn(ty::BareFnTy {purity: purity, _}) | - ty::ty_closure(ty::ClosureTy {purity: purity, _}) => { - match purity { - ast::pure_fn => return, // case (c) above - ast::impure_fn | ast::unsafe_fn | ast::extern_fn => { - self.report_purity_error( - pc, callee_span, - fmt!("access to %s function", - purity.to_str())); + } + #[cfg(not(stage0))] + fn each_in_scope_restriction(&self, + scope_id: ast::node_id, + loan_path: @LoanPath, + op: &fn(&Loan, &Restriction) -> bool) -> bool + { + //! Iterates through all the in-scope restrictions for the + //! given `loan_path` + + for self.each_in_scope_loan(scope_id) |loan| { + for loan.restrictions.each |restr| { + if restr.loan_path == loan_path { + if !op(loan, restr) { + return false; } } } - _ => return, // case (d) above } + return true; } - // True if the expression with the given `id` is a stack closure. - // The expression must be an expr_fn_block(*) - fn is_stack_closure(&mut self, id: ast::node_id) -> bool { - let fn_ty = ty::node_id_to_type(self.tcx(), id); - match ty::get(fn_ty).sty { - ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil, - _}) => true, - _ => false - } - } + fn loans_generated_by(&self, scope_id: ast::node_id) -> ~[uint] { + //! Returns a vector of the loans that are generated as + //! we encounter `scope_id`. - fn is_allowed_pure_arg(&mut self, expr: @ast::expr) -> bool { - return match expr.node { - ast::expr_path(_) => { - let def = *self.tcx().def_map.get(&expr.id); - let did = ast_util::def_id_of_def(def); - did.crate == ast::local_crate && - (*self.fn_args).contains(&(did.node)) - } - ast::expr_fn_block(*) => self.is_stack_closure(expr.id), - _ => false, - }; + let mut result = ~[]; + for self.dfcx.each_gen_bit(scope_id) |loan_index| { + result.push(loan_index); + } + return result; } fn check_for_conflicting_loans(&mut self, scope_id: ast::node_id) { - debug!("check_for_conflicting_loans(scope_id=%?)", scope_id); - - let new_loans = match self.req_maps.req_loan_map.find(&scope_id) { - None => return, - Some(&loans) => loans - }; - let new_loans: &mut ~[Loan] = new_loans; + //! Checks to see whether any of the loans that are issued + //! by `scope_id` conflict with loans that have already been + //! issued when we enter `scope_id` (for example, we do not + //! permit two `&mut` borrows of the same variable). - debug!("new_loans has length %?", new_loans.len()); + debug!("check_for_conflicting_loans(scope_id=%?)", scope_id); - let par_scope_id = self.tcx().region_maps.encl_scope(scope_id); - for self.walk_loans(par_scope_id) |old_loan| { - debug!("old_loan=%?", self.bccx.loan_to_repr(old_loan)); + let new_loan_indices = self.loans_generated_by(scope_id); + debug!("new_loan_indices = %?", new_loan_indices); - for new_loans.each |new_loan| { - self.report_error_if_loans_conflict(old_loan, new_loan); + for self.each_issued_loan(scope_id) |issued_loan| { + for new_loan_indices.each |&new_loan_index| { + let new_loan = &self.all_loans[new_loan_index]; + self.report_error_if_loans_conflict(issued_loan, new_loan); } } - let len = new_loans.len(); - for uint::range(0, len) |i| { - let loan_i = new_loans[i]; - for uint::range(i+1, len) |j| { - let loan_j = new_loans[j]; - self.report_error_if_loans_conflict(&loan_i, &loan_j); + for uint::range(0, new_loan_indices.len()) |i| { + let old_loan = &self.all_loans[new_loan_indices[i]]; + for uint::range(i+1, new_loan_indices.len()) |j| { + let new_loan = &self.all_loans[new_loan_indices[j]]; + self.report_error_if_loans_conflict(old_loan, new_loan); } } } @@ -303,219 +222,366 @@ pub impl CheckLoanCtxt { fn report_error_if_loans_conflict(&self, old_loan: &Loan, new_loan: &Loan) { - if old_loan.lp != new_loan.lp { - return; - } + //! Checks whether `old_loan` and `new_loan` can safely be issued + //! simultaneously. + + debug!("report_error_if_loans_conflict(old_loan=%s, new_loan=%s)", + old_loan.repr(self.tcx()), + new_loan.repr(self.tcx())); + + // Should only be called for loans that are in scope at the same time. + let region_maps = self.tcx().region_maps; + assert!(region_maps.scopes_intersect(old_loan.kill_scope, + new_loan.kill_scope)); + + self.report_error_if_loan_conflicts_with_restriction( + old_loan, new_loan, old_loan, new_loan) && + self.report_error_if_loan_conflicts_with_restriction( + new_loan, old_loan, old_loan, new_loan); + } - match (old_loan.kind, new_loan.kind) { - (PartialFreeze, PartialTake) | (PartialTake, PartialFreeze) | - (TotalFreeze, PartialFreeze) | (PartialFreeze, TotalFreeze) | - (Immobile, _) | (_, Immobile) | - (PartialFreeze, PartialFreeze) | - (PartialTake, PartialTake) | - (TotalFreeze, TotalFreeze) => { - /* ok */ - } + fn report_error_if_loan_conflicts_with_restriction(&self, + loan1: &Loan, + loan2: &Loan, + old_loan: &Loan, + new_loan: &Loan) -> bool { + //! Checks whether the restrictions introduced by `loan1` would + //! prohibit `loan2`. Returns false if an error is reported. + + debug!("report_error_if_loan_conflicts_with_restriction(\ + loan1=%s, loan2=%s)", + loan1.repr(self.tcx()), + loan2.repr(self.tcx())); + + // Restrictions that would cause the new loan to be immutable: + let illegal_if = match loan2.mutbl { + m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_MUTATE, + m_imm => RESTR_ALIAS | RESTR_FREEZE, + m_const => RESTR_ALIAS, + }; + debug!("illegal_if=%?", illegal_if); + + for loan1.restrictions.each |restr| { + if !restr.set.intersects(illegal_if) { loop; } + if restr.loan_path != loan2.loan_path { loop; } + + match (new_loan.mutbl, old_loan.mutbl) { + (m_mutbl, m_mutbl) => { + self.bccx.span_err( + new_loan.span, + fmt!("cannot borrow `%s` as mutable \ + more than once at at a time", + self.bccx.loan_path_to_str(new_loan.loan_path))); + self.bccx.span_note( + old_loan.span, + fmt!("second borrow of `%s` as mutable occurs here", + self.bccx.loan_path_to_str(new_loan.loan_path))); + return false; + } - (PartialTake, TotalFreeze) | (TotalFreeze, PartialTake) | - (TotalTake, TotalFreeze) | (TotalFreeze, TotalTake) | - (TotalTake, PartialFreeze) | (PartialFreeze, TotalTake) | - (TotalTake, PartialTake) | (PartialTake, TotalTake) | - (TotalTake, TotalTake) => { - self.bccx.span_err( - new_loan.cmt.span, - fmt!("loan of %s as %s \ - conflicts with prior loan", - self.bccx.cmt_to_str(new_loan.cmt), - self.bccx.loan_kind_to_str(new_loan.kind))); - self.bccx.span_note( - old_loan.cmt.span, - fmt!("prior loan as %s granted here", - self.bccx.loan_kind_to_str(old_loan.kind))); + _ => { + self.bccx.span_err( + new_loan.span, + fmt!("cannot borrow `%s` as %s because \ + it is also borrowed as %s" + self.bccx.loan_path_to_str(new_loan.loan_path), + self.bccx.mut_to_str(new_loan.mutbl), + self.bccx.mut_to_str(old_loan.mutbl))); + self.bccx.span_note( + old_loan.span, + fmt!("second borrow of `%s` occurs here", + self.bccx.loan_path_to_str(new_loan.loan_path))); + return false; + } } } + + true } - fn is_local_variable(&self, cmt: cmt) -> bool { + fn is_local_variable(&self, cmt: mc::cmt) -> bool { match cmt.cat { - cat_local(_) => true, + mc::cat_local(_) => true, _ => false } } - fn check_assignment(&mut self, at: assignment_type, ex: @ast::expr) { + fn check_assignment(&self, expr: @ast::expr) { // We don't use cat_expr() here because we don't want to treat // auto-ref'd parameters in overloaded operators as rvalues. - let cmt = match self.bccx.tcx.adjustments.find(&ex.id) { - None => self.bccx.cat_expr_unadjusted(ex), - Some(&adj) => self.bccx.cat_expr_autoderefd(ex, adj) + let cmt = match self.bccx.tcx.adjustments.find(&expr.id) { + None => self.bccx.cat_expr_unadjusted(expr), + Some(&adj) => self.bccx.cat_expr_autoderefd(expr, adj) }; - debug!("check_assignment(cmt=%s)", - self.bccx.cmt_to_repr(cmt)); - - if self.is_local_variable(cmt) && at.checked_by_liveness() { - // liveness guarantees that immutable local variables - // are only assigned once - } else { - match cmt.mutbl { - McDeclared | McInherited => { - // Ok, but if this loan is a mutable loan, then mark the - // loan path (if it exists) as being used. This is similar - // to the check performed in loan.rs in issue_loan(). This - // type of use of mutable is different from issuing a loan, - // however. - for cmt.lp.each |lp| { - for lp.node_id().each |&id| { - self.tcx().used_mut_nodes.insert(id); - } + debug!("check_assignment(cmt=%s)", cmt.repr(self.tcx())); + + // check that the value being assigned is declared as mutable + // and report an error otherwise. + match cmt.mutbl { + mc::McDeclared => { + // OK, but we have to mark arguments as requiring mut + // if they are assigned (other cases are handled by liveness, + // since we need to distinguish local variables assigned + // once vs those assigned multiple times) + match cmt.cat { + mc::cat_self(*) | + mc::cat_arg(*) => { + mark_variable_as_used_mut(self, cmt); } + _ => {} } - McReadOnly | McImmutable => { + } + mc::McInherited => { + // OK, but we may have to add an entry to `used_mut_nodes` + mark_variable_as_used_mut(self, cmt); + } + mc::McReadOnly | mc::McImmutable => { + // Subtle: liveness guarantees that immutable local + // variables are only assigned once, so no need to + // report an error for an assignment to a local + // variable (note also that it is not legal to borrow + // for a local variable before it has been assigned + // for the first time). + if !self.is_local_variable(cmt) { self.bccx.span_err( - ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - return; + expr.span, + fmt!("cannot assign to %s %s" + cmt.mutbl.to_user_str(), + self.bccx.cmt_to_str(cmt))); } + return; } } - // if this is a pure function, only loan-able state can be - // assigned, because it is uniquely tied to this function and - // is not visible from the outside - let purity = self.purity(ex.id); - match purity { - Right(_) => (), - Left(pc_cmt(_)) => { - // Subtle: Issue #3162. If we are enforcing purity - // because there is a reference to aliasable, mutable data - // that we require to be immutable, we can't allow writes - // even to data owned by the current stack frame. This is - // because that aliasable data might have been located on - // the current stack frame, we don't know. - self.report_purity_error( - purity, - ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - } - Left(pc_pure_fn) => { - if cmt.lp.is_none() { - self.report_purity_error( - purity, ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - } - } + if check_for_aliasable_mutable_writes(self, expr, cmt) { + check_for_assignment_to_restricted_or_frozen_location( + self, expr, cmt); } - // check for a conflicting loan as well, except in the case of - // taking a mutable ref. that will create a loan of its own - // which will be checked for compat separately in - // check_for_conflicting_loans() - for cmt.lp.each |lp| { - self.check_for_loan_conflicting_with_assignment( - at, ex, cmt, *lp); - } + fn mark_variable_as_used_mut(this: &CheckLoanCtxt, + cmt: mc::cmt) { + //! If the mutability of the `cmt` being written is inherited + //! from a local variable, liveness will + //! not have been able to detect that this variable's mutability + //! is important, so we must add the variable to the + //! `used_mut_nodes` table here. + + let mut cmt = cmt; + loop { + debug!("mark_writes_through_upvars_as_used_mut(cmt=%s)", + cmt.repr(this.tcx())); + match cmt.cat { + mc::cat_local(id) | + mc::cat_arg(id) | + mc::cat_self(id) => { + this.tcx().used_mut_nodes.insert(id); + return; + } - self.bccx.add_to_mutbl_map(cmt); + mc::cat_stack_upvar(b) => { + cmt = b; + } - // Check for and insert write guards as necessary. - self.add_write_guards_if_necessary(cmt); - } + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_deref(_, _, mc::unsafe_ptr(*)) | + mc::cat_deref(_, _, mc::gc_ptr(*)) | + mc::cat_deref(_, _, mc::region_ptr(*)) => { + assert_eq!(cmt.mutbl, mc::McDeclared); + return; + } - fn add_write_guards_if_necessary(&mut self, cmt: cmt) { - match cmt.cat { - cat_deref(base, deref_count, ptr_kind) => { - self.add_write_guards_if_necessary(base); - - match ptr_kind { - gc_ptr(ast::m_mutbl) => { - let key = root_map_key { - id: base.id, - derefs: deref_count - }; - self.bccx.write_guard_map.insert(key); + mc::cat_discr(b, _) | + mc::cat_deref(b, _, mc::uniq_ptr(*)) => { + assert_eq!(cmt.mutbl, mc::McInherited); + cmt = b; + } + + mc::cat_interior(b, _) => { + if cmt.mutbl == mc::McInherited { + cmt = b; + } else { + return; // field declared as mutable or some such + } } - _ => {} } } - cat_comp(base, _) => { - self.add_write_guards_if_necessary(base); - } - _ => {} } - } - fn check_for_loan_conflicting_with_assignment(&mut self, - at: assignment_type, - ex: @ast::expr, - cmt: cmt, - lp: @loan_path) { - for self.walk_loans_of(ex.id, lp) |loan| { - match loan.kind { - Immobile => { /* ok */ } - TotalFreeze | PartialFreeze | - TotalTake | PartialTake => { - self.bccx.span_err( - ex.span, - fmt!("%s prohibited due to outstanding loan", - at.ing_form(self.bccx.cmt_to_str(cmt)))); - self.bccx.span_note( - loan.cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan.cmt))); - return; + fn check_for_aliasable_mutable_writes(this: &CheckLoanCtxt, + expr: @ast::expr, + cmt: mc::cmt) -> bool { + //! Safety checks related to writes to aliasable, mutable locations + + let guarantor = cmt.guarantor(); + debug!("check_for_aliasable_mutable_writes(cmt=%s, guarantor=%s)", + cmt.repr(this.tcx()), guarantor.repr(this.tcx())); + match guarantor.cat { + mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => { + // Statically prohibit writes to `&mut` when aliasable + + match b.freely_aliasable() { + None => {} + Some(cause) => { + this.bccx.report_aliasability_violation( + expr.span, + MutabilityViolation, + cause); + } + } } + + mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => { + // Dynamically check writes to `@mut` + + let key = root_map_key { + id: guarantor.id, + derefs: deref_count + }; + debug!("Inserting write guard at %?", key); + this.bccx.write_guard_map.insert(key); + } + + _ => {} } - } - // Subtle: if the mutability of the component being assigned - // is inherited from the thing that the component is embedded - // within, then we have to check whether that thing has been - // loaned out as immutable! An example: - // let mut x = {f: Some(3)}; - // let y = &x; // x loaned out as immutable - // x.f = none; // changes type of y.f, which appears to be imm - match *lp { - lp_comp(lp_base, ck) if inherent_mutability(ck) != m_mutbl => { - self.check_for_loan_conflicting_with_assignment( - at, ex, cmt, lp_base); - } - lp_comp(*) | lp_self | lp_local(*) | lp_arg(*) | lp_deref(*) => () + return true; // no errors reported } - } - fn report_purity_error(&mut self, pc: Either, - sp: span, msg: ~str) { - match pc { - Right(pc_default) => { fail!(~"pc_default should be filtered sooner") } - Right(pc_unsafe) => { - // this error was prevented by being marked as unsafe, so flag the - // definition as having contributed to the validity of the program - let def = self.declared_purity.def; - debug!("flagging %? as a used unsafe source", def); - self.tcx().used_unsafe.insert(def); - } - Left(pc_pure_fn) => { - self.tcx().sess.span_err( - sp, - fmt!("%s prohibited in pure context", msg)); - } - Left(pc_cmt(ref e)) => { - if self.reported.insert((*e).cmt.id) { - self.tcx().sess.span_err( - (*e).cmt.span, - fmt!("illegal borrow unless pure: %s", - self.bccx.bckerr_to_str((*e)))); - self.bccx.note_and_explain_bckerr((*e)); - self.tcx().sess.span_note( - sp, - fmt!("impure due to %s", msg)); + fn check_for_assignment_to_restricted_or_frozen_location( + this: &CheckLoanCtxt, + expr: @ast::expr, + cmt: mc::cmt) -> bool + { + //! Check for assignments that violate the terms of an + //! outstanding loan. + + let loan_path = match opt_loan_path(cmt) { + Some(lp) => lp, + None => { return true; /* no loan path, can't be any loans */ } + }; + + // Start by searching for an assignment to a *restricted* + // location. Here is one example of the kind of error caught + // by this check: + // + // let mut v = ~[1, 2, 3]; + // let p = &v; + // v = ~[4]; + // + // In this case, creating `p` triggers a RESTR_MUTATE + // restriction on the path `v`. + // + // Here is a second, more subtle example: + // + // let mut v = ~[1, 2, 3]; + // let p = &const v[0]; + // v[0] = 4; // OK + // v[1] = 5; // OK + // v = ~[4, 5, 3]; // Error + // + // In this case, `p` is pointing to `v[0]`, and it is a + // `const` pointer in any case. So the first two + // assignments are legal (and would be permitted by this + // check). However, the final assignment (which is + // logically equivalent) is forbidden, because it would + // cause the existing `v` array to be freed, thus + // invalidating `p`. In the code, this error results + // because `gather_loans::restrictions` adds a + // `RESTR_MUTATE` restriction whenever the contents of an + // owned pointer are borrowed, and hence while `v[*]` is not + // restricted from being written, `v` is. + for this.each_in_scope_restriction(expr.id, loan_path) + |loan, restr| + { + if restr.set.intersects(RESTR_MUTATE) { + this.report_illegal_mutation(expr, loan_path, loan); + return false; + } + } + + // The previous code handled assignments to paths that + // have been restricted. This covers paths that have been + // directly lent out and their base paths, but does not + // cover random extensions of those paths. For example, + // the following program is not declared illegal by the + // previous check: + // + // let mut v = ~[1, 2, 3]; + // let p = &v; + // v[0] = 4; // declared error by loop below, not code above + // + // The reason that this passes the previous check whereas + // an assignment like `v = ~[4]` fails is because the assignment + // here is to `v[*]`, and the existing restrictions were issued + // for `v`, not `v[*]`. + // + // So in this loop, we walk back up the loan path so long + // as the mutability of the path is dependent on a super + // path, and check that the super path was not lent out as + // mutable or immutable (a const loan is ok). + // + // Note that we are *not* checking for any and all + // restrictions. We are only interested in the pointers + // that the user created, whereas we add restrictions for + // all kinds of paths that are not directly aliased. If we checked + // for all restrictions, and not just loans, then the following + // valid program would be considered illegal: + // + // let mut v = ~[1, 2, 3]; + // let p = &const v[0]; + // v[1] = 5; // ok + // + // Here the restriction that `v` not be mutated would be misapplied + // to block the subpath `v[1]`. + let full_loan_path = loan_path; + let mut loan_path = loan_path; + loop { + match *loan_path { + // Peel back one layer if `loan_path` has + // inherited mutability + LpExtend(lp_base, mc::McInherited, _) => { + loan_path = lp_base; + } + + // Otherwise stop iterating + LpExtend(_, mc::McDeclared, _) | + LpExtend(_, mc::McImmutable, _) | + LpExtend(_, mc::McReadOnly, _) | + LpVar(_) => { + return true; + } + } + + // Check for a non-const loan of `loan_path` + for this.each_in_scope_loan(expr.id) |loan| { + if loan.loan_path == loan_path && loan.mutbl != m_const { + this.report_illegal_mutation(expr, full_loan_path, loan); + return false; + } + } } - } } } - fn check_move_out_from_expr(@mut self, ex: @ast::expr) { + fn report_illegal_mutation(&self, + expr: @ast::expr, + loan_path: &LoanPath, + loan: &Loan) { + self.bccx.span_err( + expr.span, + fmt!("cannot assign to `%s` because it is borrowed", + self.bccx.loan_path_to_str(loan_path))); + self.bccx.span_note( + loan.span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); + } + + fn check_move_out_from_expr(&self, ex: @ast::expr) { match ex.node { ast::expr_paren(*) => { /* In the case of an expr_paren(), the expression inside @@ -529,52 +595,57 @@ pub impl CheckLoanCtxt { MoveFromIllegalCmt(_) => { self.bccx.span_err( cmt.span, - fmt!("moving out of %s", + fmt!("cannot move out of %s", self.bccx.cmt_to_str(cmt))); } - MoveWhileBorrowed(_, loan_cmt) => { + MoveWhileBorrowed(loan_path, loan_span) => { self.bccx.span_err( cmt.span, - fmt!("moving out of %s prohibited \ - due to outstanding loan", - self.bccx.cmt_to_str(cmt))); + fmt!("cannot move out of `%s` \ + because it is borrowed", + self.bccx.loan_path_to_str(loan_path))); self.bccx.span_note( - loan_cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan_cmt))); + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } } } - fn analyze_move_out_from_cmt(&mut self, cmt: cmt) -> MoveError { - debug!("check_move_out_from_cmt(cmt=%s)", - self.bccx.cmt_to_repr(cmt)); + fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError { + debug!("check_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx())); match cmt.cat { - // Rvalues, locals, and arguments can be moved: - cat_rvalue | cat_local(_) | cat_arg(_) | cat_self(_) => {} - - // We allow moving out of static items because the old code - // did. This seems consistent with permitting moves out of - // rvalues, I guess. - cat_special(sk_static_item) => {} - - cat_deref(_, _, unsafe_ptr) => {} - - // Nothing else. - _ => { - return MoveFromIllegalCmt(cmt); - } + // Rvalues, locals, and arguments can be moved: + mc::cat_rvalue | mc::cat_local(_) | + mc::cat_arg(_) | mc::cat_self(_) => {} + + // 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 + // moved, like `None::<~int>`. The type of this constant + // is technically `Option<~int>`, which moves, but we know + // that the content of static items will never actually + // contain allocated pointers, so we can just memcpy it. + mc::cat_static_item => {} + + mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {} + + // Nothing else. + _ => { + return MoveFromIllegalCmt(cmt); + } } - self.bccx.add_to_mutbl_map(cmt); + // FIXME(#4384) inadequare if/when we permit `move a.b` // check for a conflicting loan: - for cmt.lp.each |lp| { - for self.walk_loans_of(cmt.id, *lp) |loan| { - return MoveWhileBorrowed(cmt, loan.cmt); + for opt_loan_path(cmt).each |&lp| { + for self.each_in_scope_restriction(cmt.id, lp) |loan, _| { + // Any restriction prevents moves. + return MoveWhileBorrowed(loan.loan_path, loan.span); } } @@ -582,140 +653,80 @@ pub impl CheckLoanCtxt { } fn check_call(&mut self, - expr: @ast::expr, - callee: Option<@ast::expr>, - callee_id: ast::node_id, - callee_span: span, - args: &[@ast::expr]) { - let pc = self.purity(expr.id); - match pc { - // no purity, no need to check for anything - Right(pc_default) => return, - - // some form of purity, definitely need to check - Left(_) => (), - - // Unsafe trumped. To see if the unsafe is necessary, see what the - // purity would have been without a trump, and if it's some form - // of purity then we need to go ahead with the check - Right(pc_unsafe) => { - match do with(&mut self.declared_purity.purity, - ast::impure_fn) { self.purity(expr.id) } { - Right(pc_unsafe) => fail!(~"unsafe can't trump twice"), - Right(pc_default) => return, - Left(_) => () - } - } - - } - self.check_pure_callee_or_arg( - pc, callee, callee_id, callee_span); - for args.each |arg| { - self.check_pure_callee_or_arg( - pc, Some(*arg), arg.id, arg.span); - } + _expr: @ast::expr, + _callee: Option<@ast::expr>, + _callee_id: ast::node_id, + _callee_span: span, + _args: &[@ast::expr]) + { + // NB: This call to check for conflicting loans is not truly + // necessary, because the callee_id never issues new loans. + // However, I added it for consistency and lest the system + // should change in the future. + // + // FIXME(#6268) nested method calls + // self.check_for_conflicting_loans(callee_id); } } -fn check_loans_in_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - sp: span, - id: ast::node_id, - self: @mut CheckLoanCtxt, - visitor: visit::vt<@mut CheckLoanCtxt>) { - let is_stack_closure = self.is_stack_closure(id); - let fty = ty::node_id_to_type(self.tcx(), id); - - let declared_purity, src; +fn check_loans_in_fn<'a>(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + this: @mut CheckLoanCtxt<'a>, + visitor: visit::vt<@mut CheckLoanCtxt<'a>>) { match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { - declared_purity = ty::ty_fn_purity(fty); - src = id; + visit::fk_item_fn(*) | + visit::fk_method(*) => { + // Don't process nested items. + return; } - visit::fk_anon(*) | visit::fk_fn_block(*) => { + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + let fty = ty::node_id_to_type(this.tcx(), id); let fty_sigil = ty::ty_closure_sigil(fty); - check_moves_from_captured_variables(self, id, fty_sigil); - let pair = ty::determine_inherited_purity( - (self.declared_purity.purity, self.declared_purity.def), - (ty::ty_fn_purity(fty), id), - fty_sigil); - declared_purity = pair.first(); - src = pair.second(); + check_moves_from_captured_variables(this, id, fty_sigil); } } - debug!("purity on entry=%?", copy self.declared_purity); - do save_and_restore_managed(self.declared_purity) { - do save_and_restore_managed(self.fn_args) { - self.declared_purity = @mut PurityState::function(declared_purity, src); - - match *fk { - visit::fk_anon(*) | - visit::fk_fn_block(*) if is_stack_closure => { - // inherits the fn_args from enclosing ctxt - } - visit::fk_anon(*) | visit::fk_fn_block(*) | - visit::fk_method(*) | visit::fk_item_fn(*) | - visit::fk_dtor(*) => { - let mut fn_args = ~[]; - for decl.inputs.each |input| { - // For the purposes of purity, only consider function- - // typed bindings in trivial patterns to be function - // arguments. For example, do not allow `f` and `g` in - // (f, g): (&fn(), &fn()) to be called. - match input.pat.node { - ast::pat_ident(_, _, None) => { - fn_args.push(input.pat.id); - } - _ => {} // Ignore this argument. - } - } - *self.fn_args = @fn_args; - } - } - - visit::visit_fn(fk, decl, body, sp, id, self, visitor); - } - } - debug!("purity on exit=%?", copy self.declared_purity); + visit::visit_fn(fk, decl, body, sp, id, this, visitor); - fn check_moves_from_captured_variables(self: @mut CheckLoanCtxt, + fn check_moves_from_captured_variables(this: @mut CheckLoanCtxt, id: ast::node_id, fty_sigil: ast::Sigil) { match fty_sigil { ast::ManagedSigil | ast::OwnedSigil => { - let cap_vars = self.bccx.capture_map.get(&id); + let cap_vars = this.bccx.capture_map.get(&id); for cap_vars.each |cap_var| { match cap_var.mode { moves::CapRef | moves::CapCopy => { loop; } moves::CapMove => { } } let def_id = ast_util::def_id_of_def(cap_var.def).node; - let ty = ty::node_id_to_type(self.tcx(), def_id); - let cmt = self.bccx.cat_def(id, cap_var.span, + let ty = ty::node_id_to_type(this.tcx(), def_id); + let cmt = this.bccx.cat_def(id, cap_var.span, ty, cap_var.def); - let move_err = self.analyze_move_out_from_cmt(cmt); + let move_err = this.analyze_move_out_from_cmt(cmt); match move_err { MoveOk => {} MoveFromIllegalCmt(move_cmt) => { - self.bccx.span_err( + this.bccx.span_err( cap_var.span, fmt!("illegal by-move capture of %s", - self.bccx.cmt_to_str(move_cmt))); + this.bccx.cmt_to_str(move_cmt))); } - MoveWhileBorrowed(move_cmt, loan_cmt) => { - self.bccx.span_err( + MoveWhileBorrowed(loan_path, loan_span) => { + this.bccx.span_err( cap_var.span, - fmt!("by-move capture of %s prohibited \ - due to outstanding loan", - self.bccx.cmt_to_str(move_cmt))); - self.bccx.span_note( - loan_cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan_cmt))); + fmt!("cannot move `%s` into closure \ + because it is borrowed", + this.bccx.loan_path_to_str(loan_path))); + this.bccx.span_note( + loan_span, + fmt!("borrow of `%s` occurs here", + this.bccx.loan_path_to_str(loan_path))); } } } @@ -726,82 +737,83 @@ fn check_loans_in_fn(fk: &visit::fn_kind, } } -fn check_loans_in_local(local: @ast::local, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { - visit::visit_local(local, self, vt); +fn check_loans_in_local<'a>(local: @ast::local, + this: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) { + visit::visit_local(local, this, vt); } -fn check_loans_in_expr(expr: @ast::expr, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { - debug!("check_loans_in_expr(expr=%?/%s)", - expr.id, pprust::expr_to_str(expr, self.tcx().sess.intr())); +fn check_loans_in_expr<'a>(expr: @ast::expr, + this: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) { + debug!("check_loans_in_expr(expr=%s)", + expr.repr(this.tcx())); - self.check_for_conflicting_loans(expr.id); + visit::visit_expr(expr, this, vt); - if self.bccx.moves_map.contains(&expr.id) { - self.check_move_out_from_expr(expr); + this.check_for_conflicting_loans(expr.id); + + if this.bccx.moves_map.contains(&expr.id) { + this.check_move_out_from_expr(expr); } match expr.node { - ast::expr_swap(l, r) => { - self.check_assignment(at_swap, l); - self.check_assignment(at_swap, r); - } ast::expr_assign(dest, _) | ast::expr_assign_op(_, dest, _) => { - self.check_assignment(at_straight_up, dest); + this.check_assignment(dest); } ast::expr_call(f, ref args, _) => { - self.check_call(expr, Some(f), f.id, f.span, *args); + this.check_call(expr, Some(f), f.id, f.span, *args); } ast::expr_method_call(_, _, _, ref args, _) => { - self.check_call(expr, None, expr.callee_id, expr.span, *args); + this.check_call(expr, None, expr.callee_id, expr.span, *args); } ast::expr_index(_, rval) | ast::expr_binary(_, _, rval) - if self.bccx.method_map.contains_key(&expr.id) => { - self.check_call(expr, + if this.bccx.method_map.contains_key(&expr.id) => { + this.check_call(expr, None, expr.callee_id, expr.span, ~[rval]); } ast::expr_unary(*) | ast::expr_index(*) - if self.bccx.method_map.contains_key(&expr.id) => { - self.check_call(expr, + if this.bccx.method_map.contains_key(&expr.id) => { + this.check_call(expr, None, expr.callee_id, expr.span, ~[]); } - ast::expr_match(*) => { - // Note: moves out of pattern bindings are not checked by - // the borrow checker, at least not directly. What happens - // is that if there are any moved bindings, the discriminant - // will be considered a move, and this will be checked as - // normal. Then, in `middle::check_match`, we will check - // that no move occurs in a binding that is underneath an - // `@` or `&`. Together these give the same guarantees as - // `check_move_out_from_expr()` without requiring us to - // rewalk the patterns and rebuild the pattern - // categorizations. - } _ => { } } - - visit::visit_expr(expr, self, vt); } -fn check_loans_in_block(blk: &ast::blk, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { - do save_and_restore_managed(self.declared_purity) { - self.check_for_conflicting_loans(blk.node.id); +fn check_loans_in_pat<'a>(pat: @ast::pat, + this: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) +{ + this.check_for_conflicting_loans(pat.id); + + // Note: moves out of pattern bindings are not checked by + // the borrow checker, at least not directly. What happens + // is that if there are any moved bindings, the discriminant + // will be considered a move, and this will be checked as + // normal. Then, in `middle::check_match`, we will check + // that no move occurs in a binding that is underneath an + // `@` or `&`. Together these give the same guarantees as + // `check_move_out_from_expr()` without requiring us to + // rewalk the patterns and rebuild the pattern + // categorizations. + + visit::visit_pat(pat, this, vt); +} - *self.declared_purity = self.declared_purity.recurse(blk); - visit::visit_block(blk, self, vt); - } +fn check_loans_in_block<'a>(blk: &ast::blk, + this: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) +{ + visit::visit_block(blk, this, vt); + this.check_for_conflicting_loans(blk.node.id); } diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs new file mode 100644 index 0000000000000..1e09fbe71843c --- /dev/null +++ b/src/librustc/middle/borrowck/doc.rs @@ -0,0 +1,750 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +# The Borrow Checker + +This pass has the job of enforcing memory safety. This is a subtle +topic. The only way I know how to explain it is terms of a formal +model, so that's what I'll do. + +# Formal model + +Let's consider a simple subset of Rust in which you can only borrow +from lvalues like so: + + LV = x | LV.f | *LV + +Here `x` represents some variable, `LV.f` is a field reference, +and `*LV` is a pointer dereference. There is no auto-deref or other +niceties. This means that if you have a type like: + + struct S { f: uint } + +and a variable `a: ~S`, then the rust expression `a.f` would correspond +to an `LV` of `(*a).f`. + +Here is the formal grammar for the types we'll consider: + + TY = () | S<'LT...> | ~TY | & 'LT MQ TY | @ MQ TY + MQ = mut | imm | const + +Most of these types should be pretty self explanatory. Here `S` is a +struct name and we assume structs are declared like so: + + SD = struct S<'LT...> { (f: TY)... } + +# An intuitive explanation + +## Issuing loans + +Now, imagine we had a program like this: + + struct Foo { f: uint, g: uint } + ... + 'a: { + let mut x: ~Foo = ...; + let y = &mut (*x).f; + x = ...; + } + +This is of course dangerous because mutating `x` will free the old +value and hence invalidate `y`. The borrow checker aims to prevent +this sort of thing. + +### Loans + +The way the borrow checker works is that it analyzes each borrow +expression (in our simple model, that's stuff like `&LV`, though in +real life there are a few other cases to consider). For each borrow +expression, it computes a vector of loans: + + LOAN = (LV, LT, PT, LK) + PT = Partial | Total + LK = MQ | RESERVE + +Each `LOAN` tuple indicates some sort of restriction on what can be +done to the lvalue `LV`; `LV` will always be a path owned by the +current stack frame. These restrictions are called "loans" because +they are always the result of a borrow expression. + +Every loan has a lifetime `LT` during which those restrictions are in +effect. The indicator `PT` distinguishes between *total* loans, in +which the LV itself was borrowed, and *partial* loans, which means +that some content ownwed by LV was borrowed. + +The final element in the loan tuple is the *loan kind* `LK`. There +are four kinds: mutable, immutable, const, and reserve: + +- A "mutable" loan means that LV may be written to through an alias, and + thus LV cannot be written to directly or immutably aliased (remember + that we preserve the invariant that any given value can only be + written to through one path at a time; hence if there is a mutable + alias to LV, then LV cannot be written directly until this alias is + out of scope). + +- An "immutable" loan means that LV must remain immutable. Hence it + cannot be written, but other immutable aliases are permitted. + +- A "const" loan means that an alias to LV exists. LV may still be + written or frozen. + +- A "reserve" loan is the strongest case. It prevents both mutation + and aliasing of any kind, including `&const` loans. Reserve loans + are a side-effect of borrowing an `&mut` loan. + +In addition to affecting mutability, a loan of any kind implies that +LV cannot be moved. + +### Example + +To give you a better feeling for what a loan is, let's look at three +loans that would be issued as a result of the borrow `&(*x).f` in the +example above: + + ((*x).f, Total, mut, 'a) + (*x, Partial, mut, 'a) + (x, Partial, mut, 'a) + +The first loan states that the expression `(*x).f` has been loaned +totally as mutable for the lifetime `'a`. This first loan would +prevent an assignment `(*x).f = ...` from occurring during the +lifetime `'a`. + +Now let's look at the second loan. You may have expected that each +borrow would result in only one loan. But this is not the case. +Instead, there will be loans for every path where mutation might +affect the validity of the borrowed pointer that is created (in some +cases, there can even be multiple loans per path, see the section on +"Borrowing in Calls" below for the gory details). The reason for this +is to prevent actions that would indirectly affect the borrowed path. +In this case, we wish to ensure that `(*x).f` is not mutated except +through the mutable alias `y`. Therefore, we must not only prevent an +assignment to `(*x).f` but also an assignment like `*x = Foo {...}`, +as this would also mutate the field `f`. To do so, we issue a +*partial* mutable loan for `*x` (the loan is partial because `*x` +itself was not borrowed). This partial loan will cause any attempt to +assign to `*x` to be flagged as an error. + +Because both partial and total loans prevent assignments, you may +wonder why we bother to distinguish between them. The reason for this +distinction has to do with preventing double borrows. In particular, +it is legal to borrow both `&mut x.f` and `&mut x.g` simultaneously, +but it is not legal to borrow `&mut x.f` twice. In the borrow checker, +the first case would result in two *partial* mutable loans of `x` +(along with one total mutable loan of `x.f` and one of `x.g) whereas +the second would result in two *total* mutable loans of `x.f` (along +with two partial mutable loans of `x`). Multiple *total mutable* loan +for the same path are not permitted, but multiple *partial* loans (of +any mutability) are permitted. + +Finally, we come to the third loan. This loan is a partial mutable +loan of `x`. This loan prevents us from reassigning `x`, which would +be bad for two reasons. First, it would change the value of `(*x).f` +but, even worse, it would cause the pointer `y` to become a dangling +pointer. Bad all around. + +## Checking for illegal assignments, moves, and reborrows + +Once we have computed the loans introduced by each borrow, the borrow +checker will determine the full set of loans in scope at each +expression and use that to decide whether that expression is legal. +Remember that the scope of loan is defined by its lifetime LT. We +sometimes say that a loan which is in-scope at a particular point is +an "outstanding loan". + +The kinds of expressions which in-scope loans can render illegal are +*assignments*, *moves*, and *borrows*. + +An assignments to an lvalue LV is illegal if there is in-scope mutable +or immutable loan for LV. Assignment with an outstanding mutable loan +is illegal because then the `&mut` pointer is supposed to be the only +way to mutate the value. Assignment with an outstanding immutable +loan is illegal because the value is supposed to be immutable at that +point. + +A move from an lvalue LV is illegal if there is any sort of +outstanding loan. + +A borrow expression may be illegal if any of the loans which it +produces conflict with other outstanding loans. Two loans are +considered compatible if one of the following conditions holds: + +- At least one loan is a const loan. +- Both loans are partial loans. +- Both loans are immutable. + +Any other combination of loans is illegal. + +# The set of loans that results from a borrow expression + +Here we'll define four functions---MUTATE, FREEZE, ALIAS, and +TAKE---which are all used to compute the set of LOANs that result +from a borrow expression. The first three functions each have +a similar type signature: + + MUTATE(LV, LT, PT) -> LOANS + FREEZE(LV, LT, PT) -> LOANS + ALIAS(LV, LT, PT) -> LOANS + +MUTATE, FREEZE, and ALIAS are used when computing the loans result +from mutable, immutable, and const loans respectively. For example, +the loans resulting from an expression like `&mut (*x).f` would be +computed by `MUTATE((*x).f, LT, Total)`, where `LT` is the lifetime of +the resulting pointer. Similarly the loans for `&(*x).f` and `&const +(*x).f` would be computed by `FREEZE((*x).f, LT, Total)` and +`ALIAS((*x).f, LT, Total)` respectively. (Actually this is a slight +simplification; see the section below on Borrows in Calls for the full +gory details) + +The names MUTATE, FREEZE, and ALIAS are intended to suggest the +semantics of `&mut`, `&`, and `&const` borrows respectively. `&mut`, +for example, creates a mutable alias of LV. `&` causes the borrowed +value to be frozen (immutable). `&const` does neither but does +introduce an alias to be the borrowed value. + +Each of these three functions is only defined for some inputs. That +is, it may occur that some particular borrow is not legal. For +example, it is illegal to make an `&mut` loan of immutable data. In +that case, the MUTATE() function is simply not defined (in the code, +it returns a Result<> condition to indicate when a loan would be +illegal). + +The final function, RESERVE, is used as part of borrowing an `&mut` +pointer. Due to the fact that it is used for one very particular +purpose, it has a rather simpler signature than the others: + + RESERVE(LV, LT) -> LOANS + +It is explained when we come to that case. + +## The function MUTATE() + +Here we use [inference rules][ir] to define the MUTATE() function. +We will go case by case for the various kinds of lvalues that +can be borrowed. + +[ir]: http://en.wikipedia.org/wiki/Rule_of_inference + +### Mutating local variables + +The rule for mutating local variables is as follows: + + Mutate-Variable: + LT <= Scope(x) + Mut(x) = Mut + -------------------------------------------------- + MUTATE(x, LT, PT) = (x, LT, PT, mut) + +Here `Scope(x)` is the lifetime of the block in which `x` was declared +and `Mut(x)` indicates the mutability with which `x` was declared. +This rule simply states that you can only create a mutable alias +to a variable if it is mutable, and that alias cannot outlive the +stack frame in which the variable is declared. + +### Mutating fields and owned pointers + +As it turns out, the rules for mutating fields and mutating owned +pointers turn out to be quite similar. The reason is that the +expressions `LV.f` and `*LV` are both owned by their base expression +`LV`. So basically the result of mutating `LV.f` or `*LV` is computed +by adding a loan for `LV.f` or `*LV` and then the loans for a partial +take of `LV`: + + Mutate-Field: + MUTATE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + MUTATE(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, mut) + + Mutate-Owned-Ptr: + Type(LV) = ~Ty + MUTATE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + MUTATE(*LV, LT, PT) = LOANS, (*LV, LT, PT, mut) + +Note that while our micro-language only has fields, the slight +variations on the `Mutate-Field` rule are used for any interior content +that appears in the full Rust language, such as the contents of a +tuple, fields in a struct, or elements of a fixed-length vector. + +### Mutating dereferenced borrowed pointers + +The rule for borrowed pointers is by far the most complicated: + + Mutate-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty // (1) + LT <= LT_P // (2) + RESERVE(LV, LT) = LOANS // (3) + ------------------------------------------------------------ + MUTATE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Mut) + +Condition (1) states that only a mutable borrowed pointer can be +taken. Condition (2) states that the lifetime of the alias must be +less than the lifetime of the borrowed pointer being taken. + +Conditions (3) and (4) are where things get interesting. The intended +semantics of the borrow is that the new `&mut` pointer is the only one +which has the right to modify the data; the original `&mut` pointer +must not be used for mutation. Because borrowed pointers do not own +their content nor inherit mutability, we must be particularly cautious +of aliases, which could permit the original borrowed pointer to be +reached from another path and thus circumvent our loans. + +Here is one example of what could go wrong if we ignore clause (4): + + let x: &mut T; + ... + let y = &mut *x; // Only *y should be able to mutate... + let z = &const x; + **z = ...; // ...but here **z is still able to mutate! + +Another possible error could occur with moves: + + let x: &mut T; + ... + let y = &mut *x; // Issues loan: (*x, LT, Total, Mut) + let z = x; // moves from x + *z = ...; // Mutates *y indirectly! Bad. + +In both of these cases, the problem is that when creating the alias +`y` we would only issue a loan preventing assignment through `*x`. +But this loan can be easily circumvented by moving from `x` or +aliasing it. Note that, in the first example, the alias of `x` was +created using `&const`, which is a particularly weak form of alias. + +The danger of aliases can also occur when the `&mut` pointer itself +is already located in an alias location, as here: + + let x: @mut &mut T; // or &mut &mut T, &&mut T, + ... // &const &mut T, @&mut T, etc + let y = &mut **x; // Only *y should be able to mutate... + let z = x; + **z = ...; // ...but here **z is still able to mutate! + +When we cover the rules for RESERVE, we will see that it would +disallow this case, because MUTATE can only be applied to canonical +lvalues which are owned by the current stack frame. + +It might be the case that if `&const` and `@const` pointers were +removed, we could do away with RESERVE and simply use MUTATE instead. +But we have to be careful about the final example in particular, since +dynamic freezing would not be sufficient to prevent this example. +Perhaps a combination of MUTATE with a predicate OWNED(LV). + +One final detail: unlike every other case, when we calculate the loans +using RESERVE we do not use the original lifetime `LT` but rather +`GLB(Scope(LV), LT)`. What this says is: + +### Mutating dereferenced managed pointers + +Because the correctness of managed pointer loans is checked dynamically, +the rule is quite simple: + + Mutate-Mut-Managed-Ptr: + Type(LV) = @mut Ty + Add ROOT-FREEZE annotation for *LV with lifetime LT + ------------------------------------------------------------ + MUTATE(*LV, LT, Total) = [] + +No loans are issued. Instead, we add a side annotation that causes +`*LV` to be rooted and frozen on entry to LV. You could rephrase +these rules as having multiple returns values, or rephrase this as a +kind of loan, but whatever. + +One interesting point is that *partial takes* of `@mut` are forbidden. +This is not for any soundness reason but just because it is clearer +for users when `@mut` values are either lent completely or not at all. + +## The function FREEZE + +The rules for FREEZE are pretty similar to MUTATE. The first four +cases I'll just present without discussion, as the reasoning is +quite analogous to the MUTATE case: + + Freeze-Variable: + LT <= Scope(x) + -------------------------------------------------- + FREEZE(x, LT, PT) = (x, LT, PT, imm) + + Freeze-Field: + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + FREEZE(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, imm) + + Freeze-Owned-Ptr: + Type(LV) = ~Ty + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, imm) + + Freeze-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty + LT <= LT_P + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Imm) + + Freeze-Mut-Managed-Ptr: + Type(LV) = @mut Ty + Add ROOT-FREEZE annotation for *LV with lifetime LT + ------------------------------------------------------------ + Freeze(*LV, LT, Total) = [] + +The rule to "freeze" an immutable borrowed pointer is quite +simple, since the content is already immutable: + + Freeze-Imm-Borrowed-Ptr: + Type(LV) = <_P Ty // (1) + LT <= LT_P // (2) + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Mut) + +The final two rules pertain to borrows of `@Ty`. There is a bit of +subtlety here. The main problem is that we must guarantee that the +managed box remains live for the entire borrow. We can either do this +dynamically, by rooting it, or (better) statically, and hence there +are two rules: + + Freeze-Imm-Managed-Ptr-1: + Type(LV) = @Ty + Add ROOT annotation for *LV + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = [] + + Freeze-Imm-Managed-Ptr-2: + Type(LV) = @Ty + LT <= Scope(LV) + Mut(LV) = imm + LV is not moved + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = [] + +The intention of the second rule is to avoid an extra root if LV +serves as a root. In that case, LV must (1) outlive the borrow; (2) +be immutable; and (3) not be moved. + +## The ALIAS function + +The function ALIAS is used for `&const` loans but also to handle one +corner case concerning function arguments (covered in the section +"Borrows in Calls" below). It computes the loans that result from +observing that there is a pointer to `LV` and thus that pointer must +remain valid. + +The first two rules are simple: + + Alias-Variable: + LT <= Scope(x) + -------------------------------------------------- + ALIAS(x, LT, PT) = (x, LT, PT, Const) + + Alias-Field: + ALIAS(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + ALIAS(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, Const) + +### Aliasing owned pointers + +The rule for owned pointers is somewhat interesting: + + Alias-Owned-Ptr: + Type(LV) = ~Ty + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = LOANS, (*LV, LT, PT, Const) + +Here we *freeze* the base `LV`. The reason is that if an owned +pointer is mutated it frees its content, which means that the alias to +`*LV` would become a dangling pointer. + +### Aliasing borrowed pointers + +The rule for borrowed pointers is quite simple, because borrowed +pointers do not own their content and thus do not play a role in +keeping it live: + + Alias-Borrowed-Ptr: + Type(LV) = <_P MQ Ty + LT <= LT_P + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + +Basically, the existence of a borrowed pointer to some memory with +lifetime LT_P is proof that the memory can safely be aliased for any +lifetime LT <= LT_P. + +### Aliasing managed pointers + +The rules for aliasing managed pointers are similar to those +used with FREEZE, except that they apply to all manager pointers +regardles of mutability: + + Alias-Managed-Ptr-1: + Type(LV) = @MQ Ty + Add ROOT annotation for *LV + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + + Alias-Managed-Ptr-2: + Type(LV) = @MQ Ty + LT <= Scope(LV) + Mut(LV) = imm + LV is not moved + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + +## The RESERVE function + +The final function, RESERVE, is used for loans of `&mut` pointers. As +discussed in the section on the function MUTATE, we must be quite +careful when "re-borrowing" an `&mut` pointer to ensure that the original +`&mut` pointer can no longer be used to mutate. + +There are a couple of dangers to be aware of: + +- `&mut` pointers do not inherit mutability. Therefore, if you have + an lvalue LV with type `&mut T` and you freeze `LV`, you do *not* + freeze `*LV`. This is quite different from an `LV` with type `~T`. + +- Also, because they do not inherit mutability, if the `&mut` pointer + lives in an aliased location, then *any alias* can be used to write! + +As a consequence of these two rules, RESERVE can only be successfully +invoked on an lvalue LV that is *owned by the current stack frame*. +This ensures that there are no aliases that are not visible from the +outside. Moreover, Reserve loans are incompatible with all other +loans, even Const loans. This prevents any aliases from being created +within the current function. + +### Reserving local variables + +The rule for reserving a variable is generally straightforward but +with one interesting twist: + + Reserve-Variable: + -------------------------------------------------- + RESERVE(x, LT) = (x, LT, Total, Reserve) + +The twist here is that the incoming lifetime is not required to +be a subset of the incoming variable, unlike every other case. To +see the reason for this, imagine the following function: + + struct Foo { count: uint } + fn count_field(x: &'a mut Foo) -> &'a mut count { + &mut (*x).count + } + +This function consumes one `&mut` pointer and returns another with the +same lifetime pointing at a particular field. The borrow for the +`&mut` expression will result in a call to `RESERVE(x, 'a)`, which is +intended to guarantee that `*x` is not later aliased or used to +mutate. But the lifetime of `x` is limited to the current function, +which is a sublifetime of the parameter `'a`, so the rules used for +MUTATE, FREEZE, and ALIAS (which require that the lifetime of the loan +not exceed the lifetime of the variable) would result in an error. + +Nonetheless this function is perfectly legitimate. After all, the +caller has moved in an `&mut` pointer with lifetime `'a`, and thus has +given up their right to mutate the value for the remainder of `'a`. +So it is fine for us to return a pointer with the same lifetime. + +The reason that RESERVE differs from the other functions is that +RESERVE is not responsible for guaranteeing that the pointed-to data +will outlive the borrowed pointer being created. After all, `&mut` +values do not own the data they point at. + +### Reserving owned content + +The rules for fields and owned pointers are very straightforward: + + Reserve-Field: + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(LV.f, LT) = LOANS, (LV.F, LT, Total, Reserve) + + Reserve-Owned-Ptr: + Type(LV) = ~Ty + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(*LV, LT) = LOANS, (*LV, LT, Total, Reserve) + +### Reserving `&mut` borrowed pointers + +Unlike other borrowed pointers, `&mut` pointers are unaliasable, +so we can reserve them like everything else: + + Reserve-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(*LV, LT) = LOANS, (*LV, LT, Total, Reserve) + +## Borrows in calls + +Earlier we said that the MUTATE, FREEZE, and ALIAS functions were used +to compute the loans resulting from a borrow expression. But this is +not strictly correct, there is a slight complication that occurs with +calls by which additional loans may be necessary. We will explain +that here and give the full details. + +Imagine a call expression `'a: E1(E2, E3)`, where `Ei` are some +expressions. If we break this down to something a bit lower-level, it +is kind of short for: + + 'a: { + 'a_arg1: let temp1: ... = E1; + 'a_arg2: let temp2: ... = E2; + 'a_arg3: let temp3: ... = E3; + 'a_call: temp1(temp2, temp3) + } + +Here the lifetime labels indicate the various lifetimes. As you can +see there are in fact four relevant lifetimes (only one of which was +named by the user): `'a` corresponds to the expression `E1(E2, E3)` as +a whole. `'a_arg1`, `'a_arg2`, and `'a_arg3` correspond to the +evaluations of `E1`, `E2`, and `E3` respectively. Finally, `'a_call` +corresponds to the *actual call*, which is the point where the values +of the parameters will be used. + +Now, let's look at a (contrived, but representative) example to see +why all this matters: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn inc(p: &mut uint) -> uint { + *p += 1; *p + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (*) + } + +The important part is the line marked `(*)` which contains a call to +`add()`. The first argument is a mutable borrow of the field `f`. +The second argument *always borrows* the field `f`. Now, if these two +borrows overlapped in time, this would be illegal, because there would +be two `&mut` pointers pointing at `f`. And, in a way, they *do* +overlap in time, since the first argument will be evaluated first, +meaning that the pointer will exist when the second argument executes. +But in another important way they do not overlap in time. Let's +expand out that final call to `add()` as we did before: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a_call mut uint = &'a_call mut (*x).f; + 'a_arg3_: let a_temp3: uint = { + let b_temp1: ... = inc; + let b_temp2: &'b_call = &'b_call mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) + } + +When it's written this way, we can see that although there are two +borrows, the first has lifetime `'a_call` and the second has lifetime +`'b_call` and in fact these lifetimes do not overlap. So everything +is fine. + +But this does not mean that there isn't reason for caution! Imagine a +devious program like *this* one: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn consume(x: ~Foo) -> uint { + x.f + x.g + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (*) + } + +In this case, there is only one borrow, but the second argument is +`consume(x)` instead of a second borrow. Because `consume()` is +declared to take a `~Foo`, it will in fact free the pointer `x` when +it has finished executing. If it is not obvious why this is +troublesome, consider this expanded version of that call: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a_call mut uint = &'a_call mut (*x).f; + 'a_arg3_: let a_temp3: uint = { + let b_temp1: ... = consume; + let b_temp2: ~Foo = x; + 'b_call: b_temp1(x) + }; + 'a_call: a_temp1(a_temp2, a_temp3) + } + +In this example, we will have borrowed the first argument before `x` +is freed and then free `x` during evaluation of the second +argument. This causes `a_temp2` to be invalidated. + +Of course the loans computed from the borrow expression are supposed +to prevent this situation. But if we just considered the loans from +`MUTATE((*x).f, 'a_call, Total)`, the resulting loans would be: + + ((*x).f, 'a_call, Total, Mut) + (*x, 'a_call, Partial, Mut) + (x, 'a_call, Partial, Mut) + +Because these loans are only in scope for `'a_call`, they do nothing +to prevent the move that occurs evaluating the second argument. + +The way that we solve this is to say that if you have a borrow +expression `&'LT_P mut LV` which itself occurs in the lifetime +`'LT_B`, then the resulting loans are: + + MUTATE(LV, LT_P, Total) + ALIAS(LV, LUB(LT_P, LT_B), Total) + +The call to MUTATE is what we've seen so far. The second part +expresses the idea that the expression LV will be evaluated starting +at LT_B until the end of LT_P. Now, in the normal case, LT_P >= LT_B, +and so the second set of loans that result from a ALIAS are basically +a no-op. However, in the case of an argument where the evaluation of +the borrow occurs before the interval where the resulting pointer will +be used, this ALIAS is important. + +In the case of our example, it would produce a set of loans like: + + ((*x).f, 'a, Total, Const) + (*x, 'a, Total, Const) + (x, 'a, Total, Imm) + +The scope of these loans is `'a = LUB('a_arg2, 'a_call)`, and so they +encompass all subsequent arguments. The first set of loans are Const +loans, which basically just prevent moves. However, when we cross +over the dereference of the owned pointer `x`, the rule for ALIAS +specifies that `x` must be frozen, and hence the final loan is an Imm +loan. In any case the troublesome second argument would be flagged +as an error. + +# Maps that are created + +Borrowck results in two maps. + +- `root_map`: identifies those expressions or patterns whose result + needs to be rooted. Conceptually the root_map maps from an + expression or pattern node to a `node_id` identifying the scope for + which the expression must be rooted (this `node_id` should identify + a block or call). The actual key to the map is not an expression id, + however, but a `root_map_key`, which combines an expression id with a + deref count and is used to cope with auto-deref. + +*/ diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs deleted file mode 100644 index e40d0e63eb38e..0000000000000 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ /dev/null @@ -1,643 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ---------------------------------------------------------------------- -// Gathering loans -// -// The borrow check proceeds in two phases. In phase one, we gather the full -// set of loans that are required at any point. These are sorted according to -// their associated scopes. In phase two, checking loans, we will then make -// sure that all of these loans are honored. - -use middle::borrowck::preserve::{PreserveCondition, PcOk, PcIfPure}; -use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl}; -use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze, - TotalTake, PartialTake, Immobile}; -use middle::borrowck::ReqMaps; -use middle::borrowck::loan; -use middle::mem_categorization::{cmt, mem_categorization_ctxt}; -use middle::pat_util; -use middle::ty::{ty_region}; -use middle::ty; -use util::common::indenter; -use util::ppaux::{Repr, region_to_str}; - -use core::hashmap::{HashSet, HashMap}; -use syntax::ast::{m_const, m_imm, m_mutbl}; -use syntax::ast; -use syntax::codemap::span; -use syntax::print::pprust; -use syntax::visit; - -/// Context used while gathering loans: -/// -/// - `bccx`: the the borrow check context -/// - `req_maps`: the maps computed by `gather_loans()`, see def'n of the -/// struct `ReqMaps` for more info -/// - `item_ub`: the id of the block for the enclosing fn/method item -/// - `root_ub`: the id of the outermost block for which we can root -/// an `@T`. This is the id of the innermost enclosing -/// loop or function body. -/// -/// The role of `root_ub` is to prevent us from having to accumulate -/// vectors of rooted items at runtime. Consider this case: -/// -/// fn foo(...) -> int { -/// let mut ptr: ∫ -/// while some_cond { -/// let x: @int = ...; -/// ptr = &*x; -/// } -/// *ptr -/// } -/// -/// If we are not careful here, we would infer the scope of the borrow `&*x` -/// to be the body of the function `foo()` as a whole. We would then -/// have root each `@int` that is produced, which is an unbounded number. -/// No good. Instead what will happen is that `root_ub` will be set to the -/// body of the while loop and we will refuse to root the pointer `&*x` -/// because it would have to be rooted for a region greater than `root_ub`. -struct GatherLoanCtxt { - bccx: @BorrowckCtxt, - req_maps: ReqMaps, - item_ub: ast::node_id, - root_ub: ast::node_id, - ignore_adjustments: HashSet -} - -pub fn gather_loans(bccx: @BorrowckCtxt, crate: @ast::crate) -> ReqMaps { - let glcx = @mut GatherLoanCtxt { - bccx: bccx, - req_maps: ReqMaps { req_loan_map: HashMap::new(), - pure_map: HashMap::new() }, - item_ub: 0, - root_ub: 0, - ignore_adjustments: HashSet::new() - }; - let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr, - visit_fn: req_loans_in_fn, - visit_stmt: add_stmt_to_map, - .. *visit::default_visitor()}); - visit::visit_crate(crate, glcx, v); - let @GatherLoanCtxt{req_maps, _} = glcx; - return req_maps; -} - -fn req_loans_in_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - sp: span, - id: ast::node_id, - self: @mut GatherLoanCtxt, - v: visit::vt<@mut GatherLoanCtxt>) { - // see explanation attached to the `root_ub` field: - let old_item_id = self.item_ub; - let old_root_ub = self.root_ub; - self.root_ub = body.node.id; - - match *fk { - visit::fk_anon(*) | visit::fk_fn_block(*) => {} - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { - self.item_ub = body.node.id; - } - } - - visit::visit_fn(fk, decl, body, sp, id, self, v); - self.root_ub = old_root_ub; - self.item_ub = old_item_id; -} - -fn req_loans_in_expr(ex: @ast::expr, - self: @mut GatherLoanCtxt, - vt: visit::vt<@mut GatherLoanCtxt>) { - let bccx = self.bccx; - let tcx = bccx.tcx; - let old_root_ub = self.root_ub; - - debug!("req_loans_in_expr(expr=%?/%s)", - ex.id, pprust::expr_to_str(ex, tcx.sess.intr())); - - // If this expression is borrowed, have to ensure it remains valid: - { - let mut this = &mut *self; - if !this.ignore_adjustments.contains(&ex.id) { - for tcx.adjustments.find(&ex.id).each |&adjustments| { - this.guarantee_adjustments(ex, *adjustments); - } - } - } - - // Special checks for various kinds of expressions: - match ex.node { - ast::expr_addr_of(mutbl, base) => { - let base_cmt = self.bccx.cat_expr(base); - - // make sure that the thing we are pointing out stays valid - // for the lifetime `scope_r` of the resulting ptr: - let scope_r = ty_region(tcx, ex.span, tcx.ty(ex)); - self.guarantee_valid(base_cmt, mutbl, scope_r); - visit::visit_expr(ex, self, vt); - } - - ast::expr_match(ex_v, ref arms) => { - let cmt = self.bccx.cat_expr(ex_v); - for (*arms).each |arm| { - for arm.pats.each |pat| { - self.gather_pat(cmt, *pat, arm.body.node.id, ex.id); - } - } - visit::visit_expr(ex, self, vt); - } - - ast::expr_index(rcvr, _) | - ast::expr_binary(_, rcvr, _) | - ast::expr_unary(_, rcvr) | - ast::expr_assign_op(_, rcvr, _) - if self.bccx.method_map.contains_key(&ex.id) => { - // Receivers in method calls are always passed by ref. - // - // Here, in an overloaded operator, the call is this expression, - // and hence the scope of the borrow is this call. - // - // FIX? / NOT REALLY---technically we should check the other - // argument and consider the argument mode. But how annoying. - // And this problem when goes away when argument modes are - // phased out. So I elect to leave this undone. - let scope_r = ty::re_scope(ex.id); - let rcvr_cmt = self.bccx.cat_expr(rcvr); - self.guarantee_valid(rcvr_cmt, m_imm, scope_r); - - // FIXME (#3387): Total hack: Ignore adjustments for the left-hand - // side. Their regions will be inferred to be too large. - self.ignore_adjustments.insert(rcvr.id); - - visit::visit_expr(ex, self, vt); - } - - // FIXME--#3387 - // ast::expr_binary(_, lhs, rhs) => { - // // Universal comparison operators like ==, >=, etc - // // take their arguments by reference. - // let lhs_ty = ty::expr_ty(self.tcx(), lhs); - // if !ty::type_is_scalar(lhs_ty) { - // let scope_r = ty::re_scope(ex.id); - // let lhs_cmt = self.bccx.cat_expr(lhs); - // self.guarantee_valid(lhs_cmt, m_imm, scope_r); - // let rhs_cmt = self.bccx.cat_expr(rhs); - // self.guarantee_valid(rhs_cmt, m_imm, scope_r); - // } - // visit::visit_expr(ex, self, vt); - // } - - ast::expr_field(rcvr, _, _) - if self.bccx.method_map.contains_key(&ex.id) => { - // Receivers in method calls are always passed by ref. - // - // Here, the field a.b is in fact a closure. Eventually, this - // should be an &fn, but for now it's an @fn. In any case, - // the enclosing scope is either the call where it is a rcvr - // (if used like `a.b(...)`), the call where it's an argument - // (if used like `x(a.b)`), or the block (if used like `let x - // = a.b`). - let scope_r = self.tcx().region_maps.encl_region(ex.id); - let rcvr_cmt = self.bccx.cat_expr(rcvr); - self.guarantee_valid(rcvr_cmt, m_imm, scope_r); - visit::visit_expr(ex, self, vt); - } - - // see explanation attached to the `root_ub` field: - ast::expr_while(cond, ref body) => { - // during the condition, can only root for the condition - self.root_ub = cond.id; - (vt.visit_expr)(cond, self, vt); - - // during body, can only root for the body - self.root_ub = body.node.id; - (vt.visit_block)(body, self, vt); - } - - // see explanation attached to the `root_ub` field: - ast::expr_loop(ref body, _) => { - self.root_ub = body.node.id; - visit::visit_expr(ex, self, vt); - } - - _ => { - visit::visit_expr(ex, self, vt); - } - } - - // Check any contained expressions: - - self.root_ub = old_root_ub; -} - -pub impl GatherLoanCtxt { - fn tcx(&mut self) -> ty::ctxt { self.bccx.tcx } - - fn guarantee_adjustments(&mut self, - expr: @ast::expr, - adjustment: &ty::AutoAdjustment) { - debug!("guarantee_adjustments(expr=%s, adjustment=%?)", - expr.repr(self.tcx()), adjustment); - let _i = indenter(); - - match *adjustment { - ty::AutoAddEnv(*) => { - debug!("autoaddenv -- no autoref"); - return; - } - - ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: None, _ }) => { - debug!("no autoref"); - return; - } - - ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: Some(ref autoref), - autoderefs: autoderefs}) => { - let mcx = &mem_categorization_ctxt { - tcx: self.tcx(), - method_map: self.bccx.method_map}; - let cmt = mcx.cat_expr_autoderefd(expr, autoderefs); - debug!("after autoderef, cmt=%s", self.bccx.cmt_to_repr(cmt)); - - match autoref.kind { - ty::AutoPtr => { - self.guarantee_valid(cmt, - autoref.mutbl, - autoref.region) - } - ty::AutoBorrowVec | ty::AutoBorrowVecRef => { - let cmt_index = mcx.cat_index(expr, cmt); - self.guarantee_valid(cmt_index, - autoref.mutbl, - autoref.region) - } - ty::AutoBorrowFn => { - let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0); - self.guarantee_valid(cmt_deref, - autoref.mutbl, - autoref.region) - } - } - } - } - } - - // guarantees that addr_of(cmt) will be valid for the duration of - // `static_scope_r`, or reports an error. This may entail taking - // out loans, which will be added to the `req_loan_map`. This can - // also entail "rooting" GC'd pointers, which means ensuring - // dynamically that they are not freed. - fn guarantee_valid(&mut self, - cmt: cmt, - req_mutbl: ast::mutability, - scope_r: ty::Region) - { - - let loan_kind = match req_mutbl { - m_mutbl => TotalTake, - m_imm => TotalFreeze, - m_const => Immobile - }; - - self.bccx.stats.guaranteed_paths += 1; - - debug!("guarantee_valid(cmt=%s, req_mutbl=%?, \ - loan_kind=%?, scope_r=%s)", - self.bccx.cmt_to_repr(cmt), - req_mutbl, - loan_kind, - region_to_str(self.tcx(), scope_r)); - let _i = indenter(); - - match cmt.lp { - // If this expression is a loanable path, we MUST take out a - // loan. This is somewhat non-obvious. You might think, - // for example, that if we have an immutable local variable - // `x` whose value is being borrowed, we could rely on `x` - // not to change. This is not so, however, because even - // immutable locals can be moved. So we take out a loan on - // `x`, guaranteeing that it remains immutable for the - // duration of the reference: if there is an attempt to move - // it within that scope, the loan will be detected and an - // error will be reported. - Some(_) => { - match loan::loan(self.bccx, cmt, scope_r, loan_kind) { - Err(ref e) => { self.bccx.report((*e)); } - Ok(loans) => { - self.add_loans(cmt, loan_kind, scope_r, loans); - } - } - } - - // The path is not loanable: in that case, we must try and - // preserve it dynamically (or see that it is preserved by - // virtue of being rooted in some immutable path). We must - // also check that the mutability of the desired pointer - // matches with the actual mutability (but if an immutable - // pointer is desired, that is ok as long as we are pure) - None => { - let result: bckres = { - do self.check_mutbl(loan_kind, cmt).chain |pc1| { - do self.bccx.preserve(cmt, scope_r, - self.item_ub, - self.root_ub).chain |pc2| { - Ok(pc1.combine(pc2)) - } - } - }; - - match result { - Ok(PcOk) => { - debug!("result of preserve: PcOk"); - - // we were able guarantee the validity of the ptr, - // perhaps by rooting or because it is immutably - // rooted. good. - self.bccx.stats.stable_paths += 1; - } - Ok(PcIfPure(ref e)) => { - debug!("result of preserve: %?", PcIfPure((*e))); - - // we are only able to guarantee the validity if - // the scope is pure - match scope_r { - ty::re_scope(pure_id) => { - // if the scope is some block/expr in the - // fn, then just require that this scope - // be pure - self.req_maps.pure_map.insert(pure_id, *e); - self.bccx.stats.req_pure_paths += 1; - - debug!("requiring purity for scope %?", - scope_r); - - if self.tcx().sess.borrowck_note_pure() { - self.bccx.span_note( - cmt.span, - fmt!("purity required")); - } - } - _ => { - // otherwise, we can't enforce purity for - // that scope, so give up and report an - // error - self.bccx.report((*e)); - } - } - } - Err(ref e) => { - // we cannot guarantee the validity of this pointer - debug!("result of preserve: error"); - self.bccx.report((*e)); - } - } - } - } - } - - // Check that the pat `cmt` is compatible with the required - // mutability, presuming that it can be preserved to stay alive - // long enough. - // - // For example, if you have an expression like `&x.f` where `x` - // has type `@mut{f:int}`, this check might fail because `&x.f` - // reqires an immutable pointer, but `f` lives in (aliased) - // mutable memory. - fn check_mutbl(&mut self, - loan_kind: LoanKind, - cmt: cmt) - -> bckres { - debug!("check_mutbl(loan_kind=%?, cmt.mutbl=%?)", - loan_kind, cmt.mutbl); - - match loan_kind { - Immobile => Ok(PcOk), - - TotalTake | PartialTake => { - if cmt.mutbl.is_mutable() { - Ok(PcOk) - } else { - Err(bckerr { cmt: cmt, code: err_mutbl(loan_kind) }) - } - } - - TotalFreeze | PartialFreeze => { - if cmt.mutbl.is_immutable() { - Ok(PcOk) - } else if cmt.cat.is_mutable_box() { - Ok(PcOk) - } else { - // Eventually: - let e = bckerr {cmt: cmt, - code: err_mutbl(loan_kind)}; - Ok(PcIfPure(e)) - } - } - } - } - - fn add_loans(&mut self, - cmt: cmt, - loan_kind: LoanKind, - scope_r: ty::Region, - loans: ~[Loan]) { - if loans.len() == 0 { - return; - } - - // Normally we wouldn't allow `re_free` here. However, in this case - // it should be sound. Below is nmatsakis' reasoning: - // - // Perhaps [this permits] a function kind of like this one here, which - // consumes one mut pointer and returns a narrower one: - // - // struct Foo { f: int } - // fn foo(p: &'v mut Foo) -> &'v mut int { &mut p.f } - // - // I think this should work fine but there is more subtlety to it than - // I at first imagined. Unfortunately it's a very important use case, - // I think, so it really ought to work. The changes you [pcwalton] - // made to permit re_free() do permit this case, I think, but I'm not - // sure what else they permit. I have to think that over a bit. - // - // Ordinarily, a loan with scope re_free wouldn't make sense, because - // you couldn't enforce it. But in this case, your function signature - // informs the caller that you demand exclusive access to p and its - // contents for the lifetime v. Since borrowed pointers are - // non-copyable, they must have (a) made a borrow which will enforce - // those conditions and then (b) given you the resulting pointer. - // Therefore, they should be respecting the loan. So it actually seems - // that it's ok in this case to have a loan with re_free, so long as - // the scope of the loan is no greater than the region pointer on - // which it is based. Neat but not something I had previously - // considered all the way through. (Note that we already rely on - // similar reasoning to permit you to return borrowed pointers into - // immutable structures, this is just the converse I suppose) - - let scope_id = match scope_r { - ty::re_scope(scope_id) | - ty::re_free(ty::FreeRegion {scope_id, _}) => { - scope_id - } - _ => { - self.bccx.tcx.sess.span_bug( - cmt.span, - fmt!("loans required but scope is scope_region is %s \ - (%?)", - region_to_str(self.tcx(), scope_r), - scope_r)); - } - }; - - self.add_loans_to_scope_id(scope_id, loans); - - if loan_kind.is_freeze() && !cmt.mutbl.is_immutable() { - self.bccx.stats.loaned_paths_imm += 1; - - if self.tcx().sess.borrowck_note_loan() { - self.bccx.span_note( - cmt.span, - fmt!("immutable loan required")); - } - } else { - self.bccx.stats.loaned_paths_same += 1; - } - } - - fn add_loans_to_scope_id(&mut self, - scope_id: ast::node_id, - loans: ~[Loan]) { - debug!("adding %u loans to scope_id %?: %s", - loans.len(), scope_id, - str::connect(loans.map(|l| self.bccx.loan_to_repr(l)), ", ")); - match self.req_maps.req_loan_map.find(&scope_id) { - Some(req_loans) => { - req_loans.push_all(loans); - return; - } - None => {} - } - self.req_maps.req_loan_map.insert(scope_id, @mut loans); - } - - fn gather_pat(@mut self, - discr_cmt: cmt, - root_pat: @ast::pat, - arm_id: ast::node_id, - match_id: ast::node_id) { - do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { - match pat.node { - ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { - match bm { - ast::bind_by_ref(mutbl) => { - // ref x or ref x @ p --- creates a ptr which must - // remain valid for the scope of the match - - // find the region of the resulting pointer (note that - // the type of such a pattern will *always* be a - // region pointer) - let scope_r = ty_region(self.tcx(), pat.span, - self.tcx().ty(pat)); - - // if the scope of the region ptr turns out to be - // specific to this arm, wrap the categorization with - // a cat_discr() node. There is a detailed discussion - // of the function of this node in method preserve(): - let arm_scope = ty::re_scope(arm_id); - if self.bccx.is_subregion_of(scope_r, arm_scope) { - let cmt_discr = self.bccx.cat_discr(cmt, match_id); - self.guarantee_valid(cmt_discr, mutbl, scope_r); - } else { - self.guarantee_valid(cmt, mutbl, scope_r); - } - } - ast::bind_by_copy | ast::bind_infer => { - // Nothing to do here; neither copies nor moves induce - // borrows. - } - } - } - - ast::pat_vec(_, Some(slice_pat), _) => { - // The `slice_pat` here creates a slice into the - // original vector. This is effectively a borrow of - // the elements of the vector being matched. - - let slice_ty = self.tcx().ty(slice_pat); - let (slice_mutbl, slice_r) = - self.vec_slice_info(slice_pat, slice_ty); - let mcx = self.bccx.mc_ctxt(); - let cmt_index = mcx.cat_index(slice_pat, cmt); - self.guarantee_valid(cmt_index, slice_mutbl, slice_r); - } - - _ => {} - } - } - } - - fn vec_slice_info(@mut self, - pat: @ast::pat, - slice_ty: ty::t) -> (ast::mutability, ty::Region) { - /*! - * - * In a pattern like [a, b, ..c], normally `c` has slice type, - * but if you have [a, b, ..ref c], then the type of `ref c` - * will be `&&[]`, so to extract the slice details we have - * to recurse through rptrs. - */ - - match ty::get(slice_ty).sty { - ty::ty_evec(slice_mt, ty::vstore_slice(slice_r)) => { - (slice_mt.mutbl, slice_r) - } - - ty::ty_rptr(_, ref mt) => { - self.vec_slice_info(pat, mt.ty) - } - - _ => { - self.tcx().sess.span_bug( - pat.span, - fmt!("Type of slice pattern is not a slice")); - } - } - } - - fn pat_is_variant_or_struct(@mut self, pat: @ast::pat) -> bool { - pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) - } - - fn pat_is_binding(@mut self, pat: @ast::pat) -> bool { - pat_util::pat_is_binding(self.bccx.tcx.def_map, pat) - } -} - -// Setting up info that preserve needs. -// This is just the most convenient place to do it. -fn add_stmt_to_map(stmt: @ast::stmt, - self: @mut GatherLoanCtxt, - vt: visit::vt<@mut GatherLoanCtxt>) { - match stmt.node { - ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => { - self.bccx.stmt_map.insert(id); - } - _ => () - } - visit::visit_stmt(stmt, self, vt); -} - diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs new file mode 100644 index 0000000000000..e01a26a1281b0 --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -0,0 +1,360 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module implements the check that the lifetime of a borrow +//! does not exceed the lifetime of the value being borrowed. + +use core::prelude::*; +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::ty; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; +use syntax::codemap::span; +use util::ppaux::{note_and_explain_region}; + +pub fn guarantee_lifetime(bccx: @BorrowckCtxt, + item_scope_id: ast::node_id, + root_scope_id: ast::node_id, + span: span, + cmt: mc::cmt, + loan_region: ty::Region, + loan_mutbl: ast::mutability) { + debug!("guarantee_lifetime(cmt=%s, loan_region=%s)", + cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx)); + let ctxt = GuaranteeLifetimeContext {bccx: bccx, + item_scope_id: item_scope_id, + span: span, + loan_region: loan_region, + loan_mutbl: loan_mutbl, + cmt_original: cmt, + root_scope_id: root_scope_id}; + ctxt.check(cmt, None); +} + +/////////////////////////////////////////////////////////////////////////// +// Private + +struct GuaranteeLifetimeContext { + bccx: @BorrowckCtxt, + + // the node id of the function body for the enclosing item + item_scope_id: ast::node_id, + + // the node id of the innermost loop / function body; this is the + // longest scope for which we can root managed boxes + root_scope_id: ast::node_id, + + span: span, + loan_region: ty::Region, + loan_mutbl: ast::mutability, + cmt_original: mc::cmt +} + +impl GuaranteeLifetimeContext { + fn tcx(&self) -> ty::ctxt { + self.bccx.tcx + } + + fn check(&self, cmt: mc::cmt, discr_scope: Option) { + //! Main routine. Walks down `cmt` until we find the "guarantor". + + match cmt.cat { + mc::cat_rvalue | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_local(*) | + mc::cat_arg(*) | + mc::cat_self(*) | + mc::cat_deref(_, _, mc::region_ptr(*)) | + mc::cat_deref(_, _, mc::unsafe_ptr) => { + let scope = self.scope(cmt); + self.check_scope(scope) + } + + mc::cat_stack_upvar(cmt) => { + self.check(cmt, discr_scope) + } + + mc::cat_static_item => { + } + + mc::cat_deref(base, derefs, mc::gc_ptr(ptr_mutbl)) => { + let base_scope = self.scope(base); + + // See rule Freeze-Imm-Managed-Ptr-2 in doc.rs + let omit_root = ( + ptr_mutbl == m_imm && + self.bccx.is_subregion_of(self.loan_region, base_scope) && + self.is_rvalue_or_immutable(base) && + !self.is_moved(base) + ); + + if !omit_root { + self.check_root(cmt, base, derefs, ptr_mutbl, discr_scope); + } else { + debug!("omitting root, base=%s, base_scope=%?", + base.repr(self.tcx()), base_scope); + } + } + + mc::cat_deref(base, _, mc::uniq_ptr(*)) | + mc::cat_interior(base, _) => { + self.check(base, discr_scope) + } + + mc::cat_discr(base, new_discr_scope) => { + // Subtle: in a match, we must ensure that each binding + // variable remains valid for the duration of the arm in + // which it appears, presuming that this arm is taken. + // But it is inconvenient in trans to root something just + // for one arm. Therefore, we insert a cat_discr(), + // basically a special kind of category that says "if this + // value must be dynamically rooted, root it for the scope + // `match_id`. + // + // As an example, consider this scenario: + // + // let mut x = @Some(3); + // match *x { Some(y) {...} None {...} } + // + // Technically, the value `x` need only be rooted + // in the `some` arm. However, we evaluate `x` in trans + // before we know what arm will be taken, so we just + // always root it for the duration of the match. + // + // As a second example, consider *this* scenario: + // + // let x = @mut @Some(3); + // match x { @@Some(y) {...} @@None {...} } + // + // Here again, `x` need only be rooted in the `some` arm. + // In this case, the value which needs to be rooted is + // found only when checking which pattern matches: but + // this check is done before entering the arm. Therefore, + // even in this case we just choose to keep the value + // rooted for the entire match. This means the value will be + // rooted even if the none arm is taken. Oh well. + // + // At first, I tried to optimize the second case to only + // root in one arm, but the result was suboptimal: first, + // it interfered with the construction of phi nodes in the + // arm, as we were adding code to root values before the + // phi nodes were added. This could have been addressed + // with a second basic block. However, the naive approach + // also yielded suboptimal results for patterns like: + // + // let x = @mut @...; + // match x { @@some_variant(y) | @@some_other_variant(y) => + // + // The reason is that we would root the value once for + // each pattern and not once per arm. This is also easily + // fixed, but it's yet more code for what is really quite + // the corner case. + // + // Nonetheless, if you decide to optimize this case in the + // future, you need only adjust where the cat_discr() + // node appears to draw the line between what will be rooted + // in the *arm* vs the *match*. + self.check(base, Some(new_discr_scope)) + } + } + } + + fn is_rvalue_or_immutable(&self, + cmt: mc::cmt) -> bool { + //! We can omit the root on an `@T` value if the location + //! that holds the box is either (1) an rvalue, in which case + //! is is in a non-user-accessible temporary, or (2) an immutable + //! lvalue. + + cmt.mutbl.is_immutable() || match cmt.guarantor().cat { + mc::cat_rvalue => true, + _ => false + } + } + + fn check_root(&self, + cmt_deref: mc::cmt, + cmt_base: mc::cmt, + derefs: uint, + ptr_mutbl: ast::mutability, + discr_scope: Option) { + debug!("check_root(cmt_deref=%s, cmt_base=%s, derefs=%?, ptr_mutbl=%?, \ + discr_scope=%?)", + cmt_deref.repr(self.tcx()), + cmt_base.repr(self.tcx()), + derefs, + ptr_mutbl, + discr_scope); + + // Make sure that the loan does not exceed the maximum time + // that we can root the value, dynamically. + let root_region = ty::re_scope(self.root_scope_id); + if !self.bccx.is_subregion_of(self.loan_region, root_region) { + self.report_error( + err_out_of_root_scope(root_region, self.loan_region)); + return; + } + + // Extract the scope id that indicates how long the rooting is required + let root_scope = match self.loan_region { + ty::re_scope(id) => id, + _ => { + // the check above should fail for anything is not re_scope + self.bccx.tcx.sess.span_bug( + cmt_base.span, + fmt!("Cannot issue root for scope region: %?", + self.loan_region)); + } + }; + + // If inside of a match arm, expand the rooting to the entire + // match. See the detailed discussion in `check()` above. + let mut root_scope = match discr_scope { + None => root_scope, + Some(id) => { + if self.bccx.is_subscope_of(root_scope, id) { + id + } else { + root_scope + } + } + }; + + // If we are borrowing the inside of an `@mut` box, + // we need to dynamically mark it to prevent incompatible + // borrows from happening later. + let opt_dyna = match ptr_mutbl { + m_imm | m_const => None, + m_mutbl => { + match self.loan_mutbl { + m_mutbl => Some(DynaMut), + m_imm | m_const => Some(DynaImm) + } + } + }; + + // FIXME(#3511) grow to the nearest cleanup scope---this can + // cause observable errors if freezing! + if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) { + debug!("%? is not a cleanup scope, adjusting", root_scope); + + let cleanup_scope = + self.bccx.tcx.region_maps.cleanup_scope(root_scope); + + if opt_dyna.is_some() { + self.tcx().sess.span_warn( + self.span, + fmt!("Dynamic freeze scope artifically extended \ + (see Issue #6248)")); + note_and_explain_region( + self.bccx.tcx, + "managed value only needs to be frozen for ", + ty::re_scope(root_scope), + "..."); + note_and_explain_region( + self.bccx.tcx, + "...but due to Issue #6248, it will be frozen for ", + ty::re_scope(cleanup_scope), + ""); + } + + root_scope = cleanup_scope; + } + + // Add a record of what is required + let rm_key = root_map_key {id: cmt_deref.id, derefs: derefs}; + let root_info = RootInfo {scope: root_scope, freeze: opt_dyna}; + self.bccx.root_map.insert(rm_key, root_info); + + debug!("root_key: %? root_info: %?", rm_key, root_info); + } + + fn check_scope(&self, max_scope: ty::Region) { + //! Reports an error if `loan_region` is larger than `valid_scope` + + if !self.bccx.is_subregion_of(self.loan_region, max_scope) { + self.report_error(err_out_of_scope(max_scope, self.loan_region)); + } + } + + fn is_moved(&self, cmt: mc::cmt) -> bool { + //! True if `cmt` is something that is potentially moved + //! out of the current stack frame. + + match cmt.guarantor().cat { + mc::cat_local(id) | + mc::cat_self(id) | + mc::cat_arg(id) => { + self.bccx.moved_variables_set.contains(&id) + } + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_deref(*) => { + false + } + r @ mc::cat_interior(*) | + r @ mc::cat_stack_upvar(*) | + r @ mc::cat_discr(*) => { + self.tcx().sess.span_bug( + cmt.span, + fmt!("illegal guarantor category: %?", r)); + } + } + } + + fn scope(&self, cmt: mc::cmt) -> ty::Region { + //! Returns the maximal region scope for the which the + //! lvalue `cmt` is guaranteed to be valid without any + //! rooting etc, and presuming `cmt` is not mutated. + + match cmt.cat { + mc::cat_rvalue => { + ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id)) + } + mc::cat_implicit_self | + mc::cat_copied_upvar(_) => { + ty::re_scope(self.item_scope_id) + } + mc::cat_static_item => { + ty::re_static + } + mc::cat_local(local_id) | + mc::cat_arg(local_id) | + mc::cat_self(local_id) => { + self.bccx.tcx.region_maps.encl_region(local_id) + } + mc::cat_deref(_, _, mc::unsafe_ptr(*)) => { + ty::re_static + } + mc::cat_deref(_, _, mc::region_ptr(_, r)) => { + r + } + mc::cat_deref(cmt, _, mc::uniq_ptr(*)) | + mc::cat_deref(cmt, _, mc::gc_ptr(*)) | + mc::cat_interior(cmt, _) | + mc::cat_stack_upvar(cmt) | + mc::cat_discr(cmt, _) => { + self.scope(cmt) + } + } + } + + fn report_error(&self, code: bckerr_code) { + self.bccx.report(BckError { + cmt: self.cmt_original, + span: self.span, + code: code + }); + } +} diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs new file mode 100644 index 0000000000000..64d32d713d0da --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -0,0 +1,637 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ---------------------------------------------------------------------- +// Gathering loans +// +// The borrow check proceeds in two phases. In phase one, we gather the full +// set of loans that are required at any point. These are sorted according to +// their associated scopes. In phase two, checking loans, we will then make +// sure that all of these loans are honored. + +use core::prelude::*; + +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::pat_util; +use middle::ty::{ty_region}; +use middle::ty; +use util::common::indenter; +use util::ppaux::{Repr}; + +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; +use syntax::ast_util::id_range; +use syntax::codemap::span; +use syntax::print::pprust; +use syntax::visit; + +mod lifetime; +mod restrictions; + +/// Context used while gathering loans: +/// +/// - `bccx`: the the borrow check context +/// - `item_ub`: the id of the block for the enclosing fn/method item +/// - `root_ub`: the id of the outermost block for which we can root +/// an `@T`. This is the id of the innermost enclosing +/// loop or function body. +/// +/// The role of `root_ub` is to prevent us from having to accumulate +/// vectors of rooted items at runtime. Consider this case: +/// +/// fn foo(...) -> int { +/// let mut ptr: ∫ +/// while some_cond { +/// let x: @int = ...; +/// ptr = &*x; +/// } +/// *ptr +/// } +/// +/// If we are not careful here, we would infer the scope of the borrow `&*x` +/// to be the body of the function `foo()` as a whole. We would then +/// have root each `@int` that is produced, which is an unbounded number. +/// No good. Instead what will happen is that `root_ub` will be set to the +/// body of the while loop and we will refuse to root the pointer `&*x` +/// because it would have to be rooted for a region greater than `root_ub`. +struct GatherLoanCtxt { + bccx: @BorrowckCtxt, + id_range: id_range, + all_loans: @mut ~[Loan], + item_ub: ast::node_id, + repeating_ids: ~[ast::node_id] +} + +pub fn gather_loans(bccx: @BorrowckCtxt, + body: &ast::blk) -> (id_range, @mut ~[Loan]) { + let glcx = @mut GatherLoanCtxt { + bccx: bccx, + id_range: id_range::max(), + all_loans: @mut ~[], + item_ub: body.node.id, + repeating_ids: ~[body.node.id] + }; + let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, + visit_block: gather_loans_in_block, + visit_fn: gather_loans_in_fn, + visit_stmt: add_stmt_to_map, + visit_pat: add_pat_to_id_range, + .. *visit::default_visitor()}); + (v.visit_block)(body, glcx, v); + return (glcx.id_range, glcx.all_loans); +} + +fn add_pat_to_id_range(p: @ast::pat, + this: @mut GatherLoanCtxt, + v: visit::vt<@mut GatherLoanCtxt>) { + // NB: This visitor function just adds the pat ids into the id + // range. We gather loans that occur in patterns using the + // `gather_pat()` method below. Eventually these two should be + // brought together. + this.id_range.add(p.id); + visit::visit_pat(p, this, v); +} + +fn gather_loans_in_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + this: @mut GatherLoanCtxt, + v: visit::vt<@mut GatherLoanCtxt>) { + match fk { + // Do not visit items here, the outer loop in borrowck/mod + // will visit them for us in turn. + &visit::fk_item_fn(*) | &visit::fk_method(*) => { + return; + } + + // Visit closures as part of the containing item. + &visit::fk_anon(*) | &visit::fk_fn_block(*) => { + this.push_repeating_id(body.node.id); + visit::visit_fn(fk, decl, body, sp, id, this, v); + this.pop_repeating_id(body.node.id); + } + } +} + +fn gather_loans_in_block(blk: &ast::blk, + this: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + this.id_range.add(blk.node.id); + visit::visit_block(blk, this, vt); +} + +fn gather_loans_in_expr(ex: @ast::expr, + this: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + let bccx = this.bccx; + let tcx = bccx.tcx; + + debug!("gather_loans_in_expr(expr=%?/%s)", + ex.id, pprust::expr_to_str(ex, tcx.sess.intr())); + + this.id_range.add(ex.id); + this.id_range.add(ex.callee_id); + + // If this expression is borrowed, have to ensure it remains valid: + for tcx.adjustments.find(&ex.id).each |&adjustments| { + this.guarantee_adjustments(ex, *adjustments); + } + + // Special checks for various kinds of expressions: + match ex.node { + ast::expr_addr_of(mutbl, base) => { + let base_cmt = this.bccx.cat_expr(base); + + // make sure that the thing we are pointing out stays valid + // for the lifetime `scope_r` of the resulting ptr: + let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex)); + this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r); + visit::visit_expr(ex, this, vt); + } + + ast::expr_match(ex_v, ref arms) => { + let cmt = this.bccx.cat_expr(ex_v); + for arms.each |arm| { + for arm.pats.each |pat| { + this.gather_pat(cmt, *pat, arm.body.node.id, ex.id); + } + } + visit::visit_expr(ex, this, vt); + } + + ast::expr_index(_, arg) | + ast::expr_binary(_, _, arg) + if this.bccx.method_map.contains_key(&ex.id) => { + // Arguments in method calls are always passed by ref. + // + // Currently these do not use adjustments, so we have to + // hardcode this check here (note that the receiver DOES use + // adjustments). + let scope_r = ty::re_scope(ex.id); + let arg_cmt = this.bccx.cat_expr(arg); + this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r); + visit::visit_expr(ex, this, vt); + } + + // see explanation attached to the `root_ub` field: + ast::expr_while(cond, ref body) => { + // during the condition, can only root for the condition + this.push_repeating_id(cond.id); + (vt.visit_expr)(cond, this, vt); + this.pop_repeating_id(cond.id); + + // during body, can only root for the body + this.push_repeating_id(body.node.id); + (vt.visit_block)(body, this, vt); + this.pop_repeating_id(body.node.id); + } + + // see explanation attached to the `root_ub` field: + ast::expr_loop(ref body, _) => { + this.push_repeating_id(body.node.id); + visit::visit_expr(ex, this, vt); + this.pop_repeating_id(body.node.id); + } + + _ => { + visit::visit_expr(ex, this, vt); + } + } +} + +pub impl GatherLoanCtxt { + fn tcx(&self) -> ty::ctxt { self.bccx.tcx } + + fn push_repeating_id(&mut self, id: ast::node_id) { + self.repeating_ids.push(id); + } + + fn pop_repeating_id(&mut self, id: ast::node_id) { + let popped = self.repeating_ids.pop(); + assert!(id == popped); + } + + fn guarantee_adjustments(&mut self, + expr: @ast::expr, + adjustment: &ty::AutoAdjustment) { + debug!("guarantee_adjustments(expr=%s, adjustment=%?)", + expr.repr(self.tcx()), adjustment); + let _i = indenter(); + + match *adjustment { + ty::AutoAddEnv(*) => { + debug!("autoaddenv -- no autoref"); + return; + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: None, _ }) => { + debug!("no autoref"); + return; + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(ref autoref), + autoderefs: autoderefs}) => { + let mcx = &mc::mem_categorization_ctxt { + tcx: self.tcx(), + method_map: self.bccx.method_map}; + let cmt = mcx.cat_expr_autoderefd(expr, autoderefs); + debug!("after autoderef, cmt=%s", cmt.repr(self.tcx())); + + match *autoref { + ty::AutoPtr(r, m) => { + self.guarantee_valid(expr.id, + expr.span, + cmt, + m, + r) + } + ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { + let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1); + self.guarantee_valid(expr.id, + expr.span, + cmt_index, + m, + r) + } + ty::AutoBorrowFn(r) => { + let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0); + self.guarantee_valid(expr.id, + expr.span, + cmt_deref, + m_imm, + r) + } + ty::AutoUnsafe(_) => {} + } + } + } + } + + // Guarantees that addr_of(cmt) will be valid for the duration of + // `static_scope_r`, or reports an error. This may entail taking + // out loans, which will be added to the `req_loan_map`. This can + // also entail "rooting" GC'd pointers, which means ensuring + // dynamically that they are not freed. + fn guarantee_valid(&mut self, + borrow_id: ast::node_id, + borrow_span: span, + cmt: mc::cmt, + req_mutbl: ast::mutability, + loan_region: ty::Region) + { + debug!("guarantee_valid(borrow_id=%?, cmt=%s, \ + req_mutbl=%?, loan_region=%?)", + borrow_id, + cmt.repr(self.tcx()), + req_mutbl, + loan_region); + + // a loan for the empty region can never be dereferenced, so + // it is always safe + if loan_region == ty::re_empty { + return; + } + + let root_ub = { *self.repeating_ids.last() }; // FIXME(#5074) + + // Check that the lifetime of the borrow does not exceed + // the lifetime of the data being borrowed. + lifetime::guarantee_lifetime(self.bccx, self.item_ub, root_ub, + borrow_span, cmt, loan_region, req_mutbl); + + // Check that we don't allow mutable borrows of non-mutable data. + check_mutability(self.bccx, borrow_span, cmt, req_mutbl); + + // Compute the restrictions that are required to enforce the + // loan is safe. + let restr = restrictions::compute_restrictions( + self.bccx, borrow_span, + cmt, self.restriction_set(req_mutbl)); + + // Create the loan record (if needed). + let loan = match restr { + restrictions::Safe => { + // No restrictions---no loan record necessary + return; + } + + restrictions::SafeIf(loan_path, restrictions) => { + let loan_scope = match loan_region { + ty::re_scope(id) => id, + ty::re_free(ref fr) => fr.scope_id, + + ty::re_static => { + // If we get here, an error must have been + // reported in + // `lifetime::guarantee_lifetime()`, because + // the only legal ways to have a borrow with a + // static lifetime should not require + // restrictions. To avoid reporting derived + // errors, we just return here without adding + // any loans. + return; + } + + ty::re_empty | + ty::re_bound(*) | + ty::re_infer(*) => { + self.tcx().sess.span_bug( + cmt.span, + fmt!("Invalid borrow lifetime: %?", loan_region)); + } + }; + debug!("loan_scope = %?", loan_scope); + + let gen_scope = self.compute_gen_scope(borrow_id, loan_scope); + debug!("gen_scope = %?", gen_scope); + + let kill_scope = self.compute_kill_scope(loan_scope, loan_path); + debug!("kill_scope = %?", kill_scope); + + if req_mutbl == m_mutbl { + self.mark_loan_path_as_mutated(loan_path); + } + + let all_loans = &mut *self.all_loans; // FIXME(#5074) + Loan { + index: all_loans.len(), + loan_path: loan_path, + cmt: cmt, + mutbl: req_mutbl, + gen_scope: gen_scope, + kill_scope: kill_scope, + span: borrow_span, + restrictions: restrictions + } + } + }; + + debug!("guarantee_valid(borrow_id=%?), loan=%s", + borrow_id, loan.repr(self.tcx())); + + // let loan_path = loan.loan_path; + // let loan_gen_scope = loan.gen_scope; + // let loan_kill_scope = loan.kill_scope; + self.all_loans.push(loan); + + // if loan_gen_scope != borrow_id { + // FIXME(#6268) Nested method calls + // + // Typically, the scope of the loan includes the point at + // which the loan is originated. This + // This is a subtle case. See the test case + // + // to see what we are guarding against. + + //let restr = restrictions::compute_restrictions( + // self.bccx, borrow_span, cmt, RESTR_EMPTY); + //let loan = { + // let all_loans = &mut *self.all_loans; // FIXME(#5074) + // Loan { + // index: all_loans.len(), + // loan_path: loan_path, + // cmt: cmt, + // mutbl: m_const, + // gen_scope: borrow_id, + // kill_scope: kill_scope, + // span: borrow_span, + // restrictions: restrictions + // } + // } + + fn check_mutability(bccx: @BorrowckCtxt, + borrow_span: span, + cmt: mc::cmt, + req_mutbl: ast::mutability) { + match req_mutbl { + m_const => { + // Data of any mutability can be lent as const. + } + + m_imm => { + match cmt.mutbl { + mc::McImmutable | mc::McDeclared | mc::McInherited => { + // both imm and mut data can be lent as imm; + // for mutable data, this is a freeze + } + mc::McReadOnly => { + bccx.report(BckError {span: borrow_span, + cmt: cmt, + code: err_mutbl(req_mutbl)}); + } + } + } + + m_mutbl => { + // Only mutable data can be lent as mutable. + if !cmt.mutbl.is_mutable() { + bccx.report(BckError {span: borrow_span, + cmt: cmt, + code: err_mutbl(req_mutbl)}); + } + } + } + } + } + + fn restriction_set(&self, req_mutbl: ast::mutability) -> RestrictionSet { + match req_mutbl { + m_const => RESTR_EMPTY, + m_imm => RESTR_EMPTY | RESTR_MUTATE, + m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_FREEZE + } + } + + fn mark_loan_path_as_mutated(&self, loan_path: @LoanPath) { + //! For mutable loans of content whose mutability derives + //! from a local variable, mark the mutability decl as necessary. + + match *loan_path { + LpVar(local_id) => { + self.tcx().used_mut_nodes.insert(local_id); + } + LpExtend(base, mc::McInherited, _) => { + self.mark_loan_path_as_mutated(base); + } + LpExtend(_, mc::McDeclared, _) | + LpExtend(_, mc::McImmutable, _) | + LpExtend(_, mc::McReadOnly, _) => { + } + } + } + + fn compute_gen_scope(&self, + borrow_id: ast::node_id, + loan_scope: ast::node_id) -> ast::node_id { + //! Determine when to introduce the loan. Typically the loan + //! is introduced at the point of the borrow, but in some cases, + //! notably method arguments, the loan may be introduced only + //! later, once it comes into scope. + + let rm = self.bccx.tcx.region_maps; + if rm.is_subscope_of(borrow_id, loan_scope) { + borrow_id + } else { + loan_scope + } + } + + fn compute_kill_scope(&self, + loan_scope: ast::node_id, + lp: @LoanPath) -> ast::node_id { + //! Determine when the loan restrictions go out of scope. + //! This is either when the lifetime expires or when the + //! local variable which roots the loan-path goes out of scope, + //! whichever happens faster. + //! + //! It may seem surprising that we might have a loan region + //! larger than the variable which roots the loan-path; this can + //! come about when variables of `&mut` type are re-borrowed, + //! as in this example: + //! + //! fn counter<'a>(v: &'a mut Foo) -> &'a mut uint { + //! &mut v.counter + //! } + //! + //! In this case, the borrowed pointer (`'a`) outlives the + //! variable `v` that hosts it. Note that this doesn't come up + //! with immutable `&` pointers, because borrows of such pointers + //! do not require restrictions and hence do not cause a loan. + + let rm = self.bccx.tcx.region_maps; + let lexical_scope = rm.encl_scope(lp.node_id()); + if rm.is_subscope_of(lexical_scope, loan_scope) { + lexical_scope + } else { + assert!(rm.is_subscope_of(loan_scope, lexical_scope)); + loan_scope + } + } + + fn gather_pat(&mut self, + discr_cmt: mc::cmt, + root_pat: @ast::pat, + arm_body_id: ast::node_id, + match_id: ast::node_id) { + do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { + match pat.node { + ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { + match bm { + ast::bind_by_ref(mutbl) => { + // ref x or ref x @ p --- creates a ptr which must + // remain valid for the scope of the match + + // find the region of the resulting pointer (note that + // the type of such a pattern will *always* be a + // region pointer) + let scope_r = + ty_region(self.tcx(), pat.span, + ty::node_id_to_type(self.tcx(), pat.id)); + + // if the scope of the region ptr turns out to be + // specific to this arm, wrap the categorization + // with a cat_discr() node. There is a detailed + // discussion of the function of this node in + // `lifetime.rs`: + let arm_scope = ty::re_scope(arm_body_id); + if self.bccx.is_subregion_of(scope_r, arm_scope) { + let cmt_discr = self.bccx.cat_discr(cmt, match_id); + self.guarantee_valid(pat.id, pat.span, + cmt_discr, mutbl, scope_r); + } else { + self.guarantee_valid(pat.id, pat.span, + cmt, mutbl, scope_r); + } + } + ast::bind_by_copy | ast::bind_infer => { + // Nothing to do here; neither copies nor moves induce + // borrows. + } + } + } + + ast::pat_vec(_, Some(slice_pat), _) => { + // The `slice_pat` here creates a slice into the + // original vector. This is effectively a borrow of + // the elements of the vector being matched. + + let slice_ty = ty::node_id_to_type(self.tcx(), + slice_pat.id); + let (slice_mutbl, slice_r) = + self.vec_slice_info(slice_pat, slice_ty); + let mcx = self.bccx.mc_ctxt(); + let cmt_index = mcx.cat_index(slice_pat, cmt, 0); + self.guarantee_valid(pat.id, pat.span, + cmt_index, slice_mutbl, slice_r); + } + + _ => {} + } + } + } + + fn vec_slice_info(&self, + pat: @ast::pat, + slice_ty: ty::t) -> (ast::mutability, ty::Region) { + /*! + * + * In a pattern like [a, b, ..c], normally `c` has slice type, + * but if you have [a, b, ..ref c], then the type of `ref c` + * will be `&&[]`, so to extract the slice details we have + * to recurse through rptrs. + */ + + match ty::get(slice_ty).sty { + ty::ty_evec(slice_mt, ty::vstore_slice(slice_r)) => { + (slice_mt.mutbl, slice_r) + } + + ty::ty_rptr(_, ref mt) => { + self.vec_slice_info(pat, mt.ty) + } + + _ => { + self.tcx().sess.span_bug( + pat.span, + fmt!("Type of slice pattern is not a slice")); + } + } + } + + fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool { + pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) + } + + fn pat_is_binding(&self, pat: @ast::pat) -> bool { + pat_util::pat_is_binding(self.bccx.tcx.def_map, pat) + } +} + +// Setting up info that preserve needs. +// This is just the most convenient place to do it. +fn add_stmt_to_map(stmt: @ast::stmt, + this: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + match stmt.node { + ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => { + this.bccx.stmt_map.insert(id); + } + _ => () + } + visit::visit_stmt(stmt, this, vt); +} + diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs new file mode 100644 index 0000000000000..0be4c67a9bc91 --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -0,0 +1,249 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Computes the restrictions that result from a borrow. + +use core::prelude::*; +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::ty; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::codemap::span; + +pub enum RestrictionResult { + Safe, + SafeIf(@LoanPath, ~[Restriction]) +} + +pub fn compute_restrictions(bccx: @BorrowckCtxt, + span: span, + cmt: mc::cmt, + restr: RestrictionSet) -> RestrictionResult { + let ctxt = RestrictionsContext { + bccx: bccx, + span: span, + cmt_original: cmt + }; + + ctxt.compute(cmt, restr) +} + +/////////////////////////////////////////////////////////////////////////// +// Private + +struct RestrictionsContext { + bccx: @BorrowckCtxt, + span: span, + cmt_original: mc::cmt +} + +impl RestrictionsContext { + fn tcx(&self) -> ty::ctxt { + self.bccx.tcx + } + + fn compute(&self, + cmt: mc::cmt, + restrictions: RestrictionSet) -> RestrictionResult { + + // Check for those cases where we cannot control the aliasing + // and make sure that we are not being asked to. + match cmt.freely_aliasable() { + None => {} + Some(cause) => { + self.check_aliasing_permitted(cause, restrictions); + } + } + + match cmt.cat { + mc::cat_rvalue => { + // Effectively, rvalues are stored into a + // non-aliasable temporary on the stack. Since they + // are inherently non-aliasable, they can only be + // accessed later through the borrow itself and hence + // must inherently comply with its terms. + Safe + } + + mc::cat_local(local_id) | + mc::cat_arg(local_id) | + mc::cat_self(local_id) => { + let lp = @LpVar(local_id); + SafeIf(lp, ~[Restriction {loan_path: lp, + set: restrictions}]) + } + + mc::cat_interior(cmt_base, i @ mc::interior_variant(_)) => { + // When we borrow the interior of an enum, we have to + // ensure the enum itself is not mutated, because that + // could cause the type of the memory to change. + let result = self.compute(cmt_base, restrictions | RESTR_MUTATE); + self.extend(result, cmt.mutbl, LpInterior(i), restrictions) + } + + mc::cat_interior(cmt_base, i @ mc::interior_tuple) | + mc::cat_interior(cmt_base, i @ mc::interior_anon_field) | + mc::cat_interior(cmt_base, i @ mc::interior_field(*)) | + mc::cat_interior(cmt_base, i @ mc::interior_index(*)) => { + // For all of these cases, overwriting the base would + // not change the type of the memory, so no additional + // restrictions are needed. + // + // FIXME(#5397) --- Mut fields are not treated soundly + // (hopefully they will just get phased out) + let result = self.compute(cmt_base, restrictions); + self.extend(result, cmt.mutbl, LpInterior(i), restrictions) + } + + mc::cat_deref(cmt_base, _, mc::uniq_ptr(*)) => { + // When we borrow the interior of an owned pointer, we + // cannot permit the base to be mutated, because that + // would cause the unique pointer to be freed. + let result = self.compute(cmt_base, restrictions | RESTR_MUTATE); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } + + mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars + mc::cat_static_item(*) | + mc::cat_implicit_self(*) | + mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) | + mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => { + Safe + } + + mc::cat_deref(_, _, mc::region_ptr(m_const, _)) | + mc::cat_deref(_, _, mc::gc_ptr(m_const)) => { + self.check_no_mutability_control(cmt, restrictions); + Safe + } + + mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => { + // Technically, no restrictions are *necessary* here. + // The validity of the borrow is guaranteed + // dynamically. However, nonetheless we add a + // restriction to make a "best effort" to report + // static errors. For example, if there is code like + // + // let v = @mut ~[1, 2, 3]; + // for v.each |e| { + // v.push(e + 1); + // } + // + // Then the code below would add restrictions on `*v`, + // which means that an error would be reported + // here. This of course is not perfect. For example, + // a function like the following would not report an error + // at compile-time but would fail dynamically: + // + // let v = @mut ~[1, 2, 3]; + // let w = v; + // for v.each |e| { + // w.push(e + 1); + // } + // + // In addition, we only add a restriction for those cases + // where we can construct a sensible loan path, so an + // example like the following will fail dynamically: + // + // impl V { + // fn get_list(&self) -> @mut ~[int]; + // } + // ... + // let v: &V = ...; + // for v.get_list().each |e| { + // v.get_list().push(e + 1); + // } + match opt_loan_path(cmt_base) { + None => Safe, + Some(lp_base) => { + let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref); + SafeIf(lp, ~[Restriction {loan_path: lp, + set: restrictions}]) + } + } + } + + mc::cat_deref(cmt_base, _, mc::region_ptr(m_mutbl, _)) => { + // Because an `&mut` pointer does not inherit its + // mutability, we can only prevent mutation or prevent + // freezing if it is not aliased. Therefore, in such + // cases we restrict aliasing on `cmt_base`. + if restrictions.intersects(RESTR_MUTATE | RESTR_FREEZE) { + let result = self.compute(cmt_base, restrictions | RESTR_ALIAS); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } else { + let result = self.compute(cmt_base, restrictions); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } + } + + mc::cat_deref(_, _, mc::unsafe_ptr) => { + // We are very trusting when working with unsafe pointers. + Safe + } + + mc::cat_stack_upvar(cmt_base) | + mc::cat_discr(cmt_base, _) => { + self.compute(cmt_base, restrictions) + } + } + } + + fn extend(&self, + result: RestrictionResult, + mc: mc::MutabilityCategory, + elem: LoanPathElem, + restrictions: RestrictionSet) -> RestrictionResult { + match result { + Safe => Safe, + SafeIf(base_lp, base_vec) => { + let lp = @LpExtend(base_lp, mc, elem); + SafeIf(lp, vec::append_one(base_vec, + Restriction {loan_path: lp, + set: restrictions})) + } + } + } + + fn check_aliasing_permitted(&self, + cause: mc::AliasableReason, + restrictions: RestrictionSet) { + //! This method is invoked when the current `cmt` is something + //! where aliasing cannot be controlled. It reports an error if + //! the restrictions required that it not be aliased; currently + //! this only occurs when re-borrowing an `&mut` pointer. + //! + //! NB: To be 100% consistent, we should report an error if + //! RESTR_FREEZE is found, because we cannot prevent freezing, + //! nor would we want to. However, we do not report such an + //! error, because this restriction only occurs when the user + //! is creating an `&mut` pointer to immutable or read-only + //! data, and there is already another piece of code that + //! checks for this condition. + + if restrictions.intersects(RESTR_ALIAS) { + self.bccx.report_aliasability_violation( + self.span, + BorrowViolation, + cause); + } + } + + fn check_no_mutability_control(&self, + cmt: mc::cmt, + restrictions: RestrictionSet) { + if restrictions.intersects(RESTR_MUTATE | RESTR_FREEZE) { + self.bccx.report(BckError {span: self.span, + cmt: cmt, + code: err_freeze_aliasable_const}); + } + } +} + diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs deleted file mode 100644 index 21de29b8f60ad..0000000000000 --- a/src/librustc/middle/borrowck/loan.rs +++ /dev/null @@ -1,312 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `Loan` module deals with borrows of *uniquely mutable* data. We -say that data is uniquely mutable if the current activation (stack -frame) controls the only mutable reference to the data. The most -common way that this can occur is if the current activation owns the -data being borrowed, but it can also occur with `&mut` pointers. The -primary characteristic of uniquely mutable data is that, at any given -time, there is at most one path that can be used to mutate it, and -that path is only accessible from the top stack frame. - -Given that some data found at a path P is being borrowed to a borrowed -pointer with mutability M and lifetime L, the job of the code in this -module is to compute the set of *loans* that are necessary to ensure -that (1) the data found at P outlives L and that (2) if M is mutable -then the path P will not be modified directly or indirectly except -through that pointer. A *loan* is the combination of a path P_L, a -mutability M_L, and a lifetime L_L where: - -- The path P_L indicates what data has been lent. -- The mutability M_L indicates the access rights on the data: - - const: the data cannot be moved - - immutable/mutable: the data cannot be moved or mutated -- The lifetime L_L indicates the *scope* of the loan. - -FIXME #4730 --- much more needed, don't have time to write this all up now - -*/ - -// ---------------------------------------------------------------------- -// Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety -// of the scope S, presuming that the returned set of loans `Ls` are honored. - -use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl}; -use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze, - TotalTake, PartialTake, Immobile}; -use middle::borrowck::{err_out_of_scope}; -use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp}; -use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self}; -use middle::mem_categorization::{cat_special, cat_stack_upvar, cmt}; -use middle::mem_categorization::{comp_field, comp_index, comp_variant}; -use middle::mem_categorization::{gc_ptr, region_ptr}; -use middle::ty; -use util::common::indenter; - -use syntax::ast::m_imm; -use syntax::ast; - -pub fn loan(bccx: @BorrowckCtxt, - cmt: cmt, - scope_region: ty::Region, - loan_kind: LoanKind) -> bckres<~[Loan]> -{ - let mut lc = LoanContext { - bccx: bccx, - scope_region: scope_region, - loans: ~[] - }; - match lc.loan(cmt, loan_kind, true) { - Err(ref e) => return Err((*e)), - Ok(()) => {} - } - // FIXME #4945: Workaround for borrow check bug. - Ok(copy lc.loans) -} - -struct LoanContext { - bccx: @BorrowckCtxt, - - // the region scope for which we must preserve the memory - scope_region: ty::Region, - - // accumulated list of loans that will be required - loans: ~[Loan] -} - -pub impl LoanContext { - fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - - fn loan(&mut self, - cmt: cmt, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> - { - /*! - * - * The main routine. - * - * # Parameters - * - * - `cmt`: the categorization of the data being borrowed - * - `req_mutbl`: the mutability of the borrowed pointer - * that was created - * - `owns_lent_data`: indicates whether `cmt` owns the - * data that is being lent. See - * discussion in `issue_loan()`. - */ - - debug!("loan(%s, %?)", - self.bccx.cmt_to_repr(cmt), - loan_kind); - let _i = indenter(); - - // see stable() above; should only be called when `cmt` is lendable - if cmt.lp.is_none() { - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"loan() called with non-lendable value"); - } - - match cmt.cat { - cat_binding(_) | cat_rvalue | cat_special(_) => { - // should never be loanable - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"rvalue with a non-none lp"); - } - cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { - // FIXME(#4903) - let local_region = self.bccx.tcx.region_maps.encl_region(local_id); - self.issue_loan(cmt, local_region, loan_kind, - owns_lent_data) - } - cat_stack_upvar(cmt) => { - self.loan(cmt, loan_kind, owns_lent_data) - } - cat_discr(base, _) => { - self.loan(base, loan_kind, owns_lent_data) - } - cat_comp(cmt_base, comp_field(_, m)) | - cat_comp(cmt_base, comp_index(_, m)) => { - // For most components, the type of the embedded data is - // stable. Therefore, the base structure need only be - // const---unless the component must be immutable. In - // that case, it must also be embedded in an immutable - // location, or else the whole structure could be - // overwritten and the component along with it. - self.loan_stable_comp(cmt, cmt_base, loan_kind, m, - owns_lent_data) - } - cat_comp(cmt_base, comp_tuple) | - cat_comp(cmt_base, comp_anon_field) => { - // As above. - self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm, - owns_lent_data) - } - cat_comp(cmt_base, comp_variant(enum_did)) => { - // For enums, the memory is unstable if there are multiple - // variants, because if the enum value is overwritten then - // the memory changes type. - if ty::enum_is_univariant(self.bccx.tcx, enum_did) { - self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm, - owns_lent_data) - } else { - self.loan_unstable_deref(cmt, cmt_base, loan_kind, - owns_lent_data) - } - } - cat_deref(cmt_base, _, uniq_ptr) => { - // For unique pointers, the memory being pointed out is - // unstable because if the unique pointer is overwritten - // then the memory is freed. - self.loan_unstable_deref(cmt, cmt_base, loan_kind, - owns_lent_data) - } - cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => { - // Mutable data can be loaned out as immutable or const. We must - // loan out the base as well as the main memory. For example, - // if someone borrows `*b`, we want to borrow `b` as immutable - // as well. - do self.loan(cmt_base, TotalFreeze, false).chain |_| { - self.issue_loan(cmt, region, loan_kind, owns_lent_data) - } - } - cat_deref(_, _, unsafe_ptr) | - cat_deref(_, _, gc_ptr(_)) | - cat_deref(_, _, region_ptr(_, _)) => { - // Aliased data is simply not lendable. - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"aliased ptr with a non-none lp"); - } - } - } - - // A "stable component" is one where assigning the base of the - // component cannot cause the component itself to change types. - // Example: record fields. - fn loan_stable_comp(&mut self, - cmt: cmt, - cmt_base: cmt, - loan_kind: LoanKind, - comp_mutbl: ast::mutability, - owns_lent_data: bool) -> bckres<()> - { - let base_kind = match (comp_mutbl, loan_kind) { - // Declared as "immutable" means: inherited mutability and - // hence mutable iff parent is mutable. So propagate - // mutability on up. - (m_imm, TotalFreeze) | (m_imm, PartialFreeze) => PartialFreeze, - (m_imm, TotalTake) | (m_imm, PartialTake) => PartialTake, - - // Declared as "mutable" means: always mutable no matter - // what the mutability of the base is. So that means we - // can weaken the condition on the base to PartialFreeze. - // This implies that the user could freeze the base, but - // that is ok since the even with an &T base, the mut - // field will still be considered mutable. - (_, TotalTake) | (_, PartialTake) | - (_, TotalFreeze) | (_, PartialFreeze) => { - PartialFreeze - } - - // If we just need to guarantee the value won't be moved, - // it doesn't matter what mutability the component was - // declared with. - (_, Immobile) => Immobile, - }; - - do self.loan(cmt_base, base_kind, owns_lent_data).chain |_ok| { - // can use static for the scope because the base - // determines the lifetime, ultimately - self.issue_loan(cmt, ty::re_static, loan_kind, - owns_lent_data) - } - } - - // An "unstable deref" means a deref of a ptr/comp where, if the - // base of the deref is assigned to, pointers into the result of the - // deref would be invalidated. Examples: interior of variants, uniques. - fn loan_unstable_deref(&mut self, - cmt: cmt, - cmt_base: cmt, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> { - // Variant components: the base must be immutable, because - // if it is overwritten, the types of the embedded data - // could change. - do self.loan(cmt_base, PartialFreeze, owns_lent_data).chain |_| { - // can use static, as in loan_stable_comp() - self.issue_loan(cmt, ty::re_static, loan_kind, - owns_lent_data) - } - } - - fn issue_loan(&mut self, - cmt: cmt, - scope_ub: ty::Region, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> { - // Subtle: the `scope_ub` is the maximal lifetime of `cmt`. - // Therefore, if `cmt` owns the data being lent, then the - // scope of the loan must be less than `scope_ub`, or else the - // data would be freed while the loan is active. - // - // However, if `cmt` does *not* own the data being lent, then - // it is ok if `cmt` goes out of scope during the loan. This - // can occur when you have an `&mut` parameter that is being - // reborrowed. - - if !owns_lent_data || - self.bccx.is_subregion_of(self.scope_region, scope_ub) - { - if cmt.mutbl.is_mutable() { - // If this loan is a mutable loan, then mark the loan path (if - // it exists) as being used. This is similar to the check - // performed in check_loans.rs in check_assignment(), but this - // is for a different purpose of having the 'mut' qualifier. - for cmt.lp.each |lp| { - for lp.node_id().each |&id| { - self.tcx().used_mut_nodes.insert(id); - } - } - } else if loan_kind.is_take() { - // We do not allow non-mutable data to be "taken" - // under any circumstances. - return Err(bckerr { - cmt:cmt, - code:err_mutbl(loan_kind) - }); - } - - self.loans.push(Loan { - // Note: cmt.lp must be Some(_) because otherwise this - // loan process does not apply at all. - lp: cmt.lp.get(), - cmt: cmt, - kind: loan_kind - }); - - return Ok(()); - } else { - // The loan being requested lives longer than the data - // being loaned out! - return Err(bckerr { - cmt:cmt, - code:err_out_of_scope(scope_ub, self.scope_region) - }); - } - } -} - diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3746f9c6e60b1..0f01b2b1e418e 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -8,254 +8,65 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -# Borrow check - -This pass is in job of enforcing *memory safety* and *purity*. As -memory safety is by far the more complex topic, I'll focus on that in -this description, but purity will be covered later on. In the context -of Rust, memory safety means three basic things: - -- no writes to immutable memory; -- all pointers point to non-freed memory; -- all pointers point to memory of the same type as the pointer. - -The last point might seem confusing: after all, for the most part, -this condition is guaranteed by the type check. However, there are -two cases where the type check effectively delegates to borrow check. - -The first case has to do with enums. If there is a pointer to the -interior of an enum, and the enum is in a mutable location (such as a -local variable or field declared to be mutable), it is possible that -the user will overwrite the enum with a new value of a different -variant, and thus effectively change the type of the memory that the -pointer is pointing at. +/*! See doc.rs for a thorough explanation of the borrow checker */ -The second case has to do with mutability. Basically, the type -checker has only a limited understanding of mutability. It will allow -(for example) the user to get an immutable pointer with the address of -a mutable local variable. It will also allow a `@mut T` or `~mut T` -pointer to be borrowed as a `&r.T` pointer. These seeming oversights -are in fact intentional; they allow the user to temporarily treat a -mutable value as immutable. It is up to the borrow check to guarantee -that the value in question is not in fact mutated during the lifetime -`r` of the reference. +use core::prelude::*; -# Definition of unstable memory - -The primary danger to safety arises due to *unstable memory*. -Unstable memory is memory whose validity or type may change as a -result of an assignment, move, or a variable going out of scope. -There are two cases in Rust where memory is unstable: the contents of -unique boxes and enums. - -Unique boxes are unstable because when the variable containing the -unique box is re-assigned, moves, or goes out of scope, the unique box -is freed or---in the case of a move---potentially given to another -task. In either case, if there is an extant and usable pointer into -the box, then safety guarantees would be compromised. - -Enum values are unstable because they are reassigned the types of -their contents may change if they are assigned with a different -variant than they had previously. - -# Safety criteria that must be enforced - -Whenever a piece of memory is borrowed for lifetime L, there are two -things which the borrow checker must guarantee. First, it must -guarantee that the memory address will remain allocated (and owned by -the current task) for the entirety of the lifetime L. Second, it must -guarantee that the type of the data will not change for the entirety -of the lifetime L. In exchange, the region-based type system will -guarantee that the pointer is not used outside the lifetime L. These -guarantees are to some extent independent but are also inter-related. - -In some cases, the type of a pointer cannot be invalidated but the -lifetime can. For example, imagine a pointer to the interior of -a shared box like: - - let mut x = @mut {f: 5, g: 6}; - let y = &mut x.f; - -Here, a pointer was created to the interior of a shared box which -contains a record. Even if `*x` were to be mutated like so: - - *x = {f: 6, g: 7}; - -This would cause `*y` to change from 5 to 6, but the pointer pointer -`y` remains valid. It still points at an integer even if that integer -has been overwritten. - -However, if we were to reassign `x` itself, like so: - - x = @{f: 6, g: 7}; - -This could potentially invalidate `y`, because if `x` were the final -reference to the shared box, then that memory would be released and -now `y` points at freed memory. (We will see that to prevent this -scenario we will *root* shared boxes that reside in mutable memory -whose contents are borrowed; rooting means that we create a temporary -to ensure that the box is not collected). - -In other cases, like an enum on the stack, the memory cannot be freed -but its type can change: - - let mut x = Some(5); - match x { - Some(ref y) => { ... } - None => { ... } - } - -Here as before, the pointer `y` would be invalidated if we were to -reassign `x` to `none`. (We will see that this case is prevented -because borrowck tracks data which resides on the stack and prevents -variables from reassigned if there may be pointers to their interior) - -Finally, in some cases, both dangers can arise. For example, something -like the following: - - let mut x = ~Some(5); - match x { - ~Some(ref y) => { ... } - ~None => { ... } - } - -In this case, if `x` to be reassigned or `*x` were to be mutated, then -the pointer `y` would be invalided. (This case is also prevented by -borrowck tracking data which is owned by the current stack frame) - -# Summary of the safety check - -In order to enforce mutability, the borrow check has a few tricks up -its sleeve: - -- When data is owned by the current stack frame, we can identify every - possible assignment to a local variable and simply prevent - potentially dangerous assignments directly. - -- If data is owned by a shared box, we can root the box to increase - its lifetime. - -- If data is found within a borrowed pointer, we can assume that the - data will remain live for the entirety of the borrowed pointer. - -- We can rely on the fact that pure actions (such as calling pure - functions) do not mutate data which is not owned by the current - stack frame. - -# Possible future directions - -There are numerous ways that the `borrowck` could be strengthened, but -these are the two most likely: - -- flow-sensitivity: we do not currently consider flow at all but only - block-scoping. This means that innocent code like the following is - rejected: - - let mut x: int; - ... - x = 5; - let y: &int = &x; // immutable ptr created - ... - - The reason is that the scope of the pointer `y` is the entire - enclosing block, and the assignment `x = 5` occurs within that - block. The analysis is not smart enough to see that `x = 5` always - happens before the immutable pointer is created. This is relatively - easy to fix and will surely be fixed at some point. - -- finer-grained purity checks: currently, our fallback for - guaranteeing random references into mutable, aliasable memory is to - require *total purity*. This is rather strong. We could use local - type-based alias analysis to distinguish writes that could not - possibly invalid the references which must be guaranteed. This - would only work within the function boundaries; function calls would - still require total purity. This seems less likely to be - implemented in the short term as it would make the code - significantly more complex; there is currently no code to analyze - the types and determine the possible impacts of a write. - -# How the code works - -The borrow check code is divided into several major modules, each of -which is documented in its own file. - -The `gather_loans` and `check_loans` are the two major passes of the -analysis. The `gather_loans` pass runs over the IR once to determine -what memory must remain valid and for how long. Its name is a bit of -a misnomer; it does in fact gather up the set of loans which are -granted, but it also determines when @T pointers must be rooted and -for which scopes purity must be required. - -The `check_loans` pass walks the IR and examines the loans and purity -requirements computed in `gather_loans`. It checks to ensure that (a) -the conditions of all loans are honored; (b) no contradictory loans -were granted (for example, loaning out the same memory as mutable and -immutable simultaneously); and (c) any purity requirements are -honored. - -The remaining modules are helper modules used by `gather_loans` and -`check_loans`: - -- `categorization` has the job of analyzing an expression to determine - what kind of memory is used in evaluating it (for example, where - dereferences occur and what kind of pointer is dereferenced; whether - the memory is mutable; etc) -- `loan` determines when data uniquely tied to the stack frame can be - loaned out. -- `preserve` determines what actions (if any) must be taken to preserve - aliasable data. This is the code which decides when to root - an @T pointer or to require purity. - -# Maps that are created - -Borrowck results in two maps. - -- `root_map`: identifies those expressions or patterns whose result - needs to be rooted. Conceptually the root_map maps from an - expression or pattern node to a `node_id` identifying the scope for - which the expression must be rooted (this `node_id` should identify - a block or call). The actual key to the map is not an expression id, - however, but a `root_map_key`, which combines an expression id with a - deref count and is used to cope with auto-deref. - -- `mutbl_map`: identifies those local variables which are modified or - moved. This is used by trans to guarantee that such variables are - given a memory location and not used as immediates. - */ - -use middle::mem_categorization::*; +use mc = middle::mem_categorization; use middle::ty; use middle::typeck; use middle::moves; +use middle::dataflow::DataFlowContext; +use middle::dataflow::DataFlowOperator; use util::common::stmt_set; -use util::ppaux::note_and_explain_region; +use util::ppaux::{note_and_explain_region, Repr}; +#[cfg(stage0)] +use core; // NOTE: this can be removed after the next snapshot use core::hashmap::{HashSet, HashMap}; -use core::to_bytes; -use syntax::ast::{mutability, m_imm}; +use core::io; +use core::result::{Result}; +use core::ops::{BitOr, BitAnd}; use syntax::ast; +use syntax::ast_map; +use syntax::visit; use syntax::codemap::span; +macro_rules! if_ok( + ($inp: expr) => ( + match $inp { + Ok(v) => { v } + Err(e) => { return Err(e); } + } + ) +) + +pub mod doc; + pub mod check_loans; + +#[path="gather_loans/mod.rs"] pub mod gather_loans; -pub mod loan; -pub mod preserve; + +pub struct LoanDataFlowOperator; +pub type LoanDataFlow = DataFlowContext; pub fn check_crate( tcx: ty::ctxt, method_map: typeck::method_map, moves_map: moves::MovesMap, + moved_variables_set: moves::MovedVariablesSet, capture_map: moves::CaptureMap, - crate: @ast::crate) -> (root_map, mutbl_map, write_guard_map) + crate: @ast::crate) -> (root_map, write_guard_map) { let bccx = @BorrowckCtxt { tcx: tcx, method_map: method_map, moves_map: moves_map, + moved_variables_set: moved_variables_set, capture_map: capture_map, root_map: root_map(), - mutbl_map: @mut HashSet::new(), + loan_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), stmt_map: @mut HashSet::new(), stats: @mut BorrowStats { @@ -267,8 +78,9 @@ pub fn check_crate( } }; - let req_maps = gather_loans::gather_loans(bccx, crate); - check_loans::check_loans(bccx, req_maps, crate); + let v = visit::mk_vt(@visit::Visitor {visit_fn: borrowck_fn, + ..*visit::default_visitor()}); + visit::visit_crate(crate, bccx, v); if tcx.sess.borrowck_stats() { io::println(~"--- borrowck stats ---"); @@ -284,7 +96,7 @@ pub fn check_crate( make_stat(bccx, bccx.stats.req_pure_paths))); } - return (bccx.root_map, bccx.mutbl_map, bccx.write_guard_map); + return (bccx.root_map, bccx.write_guard_map); fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> ~str { let stat_f = stat as float; @@ -293,6 +105,45 @@ pub fn check_crate( } } +fn borrowck_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + this: @BorrowckCtxt, + v: visit::vt<@BorrowckCtxt>) { + match fk { + &visit::fk_anon(*) | + &visit::fk_fn_block(*) => { + // Closures are checked as part of their containing fn item. + } + + &visit::fk_item_fn(*) | + &visit::fk_method(*) => { + debug!("borrowck_fn(id=%?)", id); + + // Check the body of fn items. + let (id_range, all_loans) = + gather_loans::gather_loans(this, body); + let all_loans: &~[Loan] = &*all_loans; // FIXME(#5074) + let mut dfcx = + DataFlowContext::new(this.tcx, + this.method_map, + LoanDataFlowOperator, + id_range, + all_loans.len()); + for all_loans.eachi |loan_idx, loan| { + dfcx.add_gen(loan.gen_scope, loan_idx); + dfcx.add_kill(loan.kill_scope, loan_idx); + } + dfcx.propagate(body); + check_loans::check_loans(this, &dfcx, *all_loans, body); + } + } + + visit::visit_fn(fk, decl, body, sp, id, this, v); +} + // ---------------------------------------------------------------------- // Type definitions @@ -300,9 +151,10 @@ pub struct BorrowckCtxt { tcx: ty::ctxt, method_map: typeck::method_map, moves_map: moves::MovesMap, + moved_variables_set: moves::MovedVariablesSet, capture_map: moves::CaptureMap, root_map: root_map, - mutbl_map: mutbl_map, + loan_map: LoanMap, write_guard_map: write_guard_map, stmt_map: stmt_set, @@ -318,137 +170,245 @@ pub struct BorrowStats { guaranteed_paths: uint } -pub struct RootInfo { - scope: ast::node_id, - // This will be true if we need to freeze this box at runtime. This will - // result in a call to `borrow_as_imm()` and `return_to_mut()`. - freezes: bool // True if we need to freeze this box at runtime. -} - -// a map mapping id's of expressions of gc'd type (@T, @[], etc) where -// the box needs to be kept live to the id of the scope for which they -// must stay live. -pub type root_map = @mut HashMap; +pub type LoanMap = @mut HashMap; -// the keys to the root map combine the `id` of the expression with -// the number of types that it is autodereferenced. So, for example, -// if you have an expression `x.f` and x has type ~@T, we could add an -// entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}` -// to refer to the deref of the unique pointer, and so on. -#[deriving(Eq)] +// The keys to the root map combine the `id` of the deref expression +// with the number of types that it is *autodereferenced*. So, for +// example, imagine I have a variable `x: @@@T` and an expression +// `(*x).f`. This will have 3 derefs, one explicit and then two +// autoderefs. These are the relevant `root_map_key` values that could +// appear: +// +// {id:*x, derefs:0} --> roots `x` (type: @@@T, due to explicit deref) +// {id:*x, derefs:1} --> roots `*x` (type: @@T, due to autoderef #1) +// {id:*x, derefs:2} --> roots `**x` (type: @T, due to autoderef #2) +// +// Note that there is no entry with derefs:3---the type of that expression +// is T, which is not a box. +// +// Note that implicit dereferences also occur with indexing of `@[]`, +// `@str`, etc. The same rules apply. So, for example, given a +// variable `x` of type `@[@[...]]`, if I have an instance of the +// expression `x[0]` which is then auto-slice'd, there would be two +// potential entries in the root map, both with the id of the `x[0]` +// expression. The entry with `derefs==0` refers to the deref of `x` +// used as part of evaluating `x[0]`. The entry with `derefs==1` +// refers to the deref of the `x[0]` that occurs as part of the +// auto-slice. +#[deriving(Eq, IterBytes)] pub struct root_map_key { id: ast::node_id, derefs: uint } -// set of ids of local vars / formal arguments that are modified / moved. -// this is used in trans for optimization purposes. -pub type mutbl_map = @mut HashSet; - // A set containing IDs of expressions of gc'd type that need to have a write // guard. pub type write_guard_map = @mut HashSet; -// Errors that can occur -#[deriving(Eq)] -pub enum bckerr_code { - err_mut_uniq, - err_mut_variant, - err_root_not_permitted, - err_mutbl(LoanKind), - err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope - err_out_of_scope(ty::Region, ty::Region) // superscope, subscope -} +pub type BckResult = Result; -// Combination of an error code and the categorization of the expression -// that caused it #[deriving(Eq)] -pub struct bckerr { - cmt: cmt, - code: bckerr_code +pub enum PartialTotal { + Partial, // Loan affects some portion + Total // Loan affects entire path } -pub enum MoveError { - MoveOk, - MoveFromIllegalCmt(cmt), - MoveWhileBorrowed(/*move*/ cmt, /*loan*/ cmt) +/////////////////////////////////////////////////////////////////////////// +// Loans and loan paths + +/// Record of a loan that was issued. +pub struct Loan { + index: uint, + loan_path: @LoanPath, + cmt: mc::cmt, + mutbl: ast::mutability, + restrictions: ~[Restriction], + gen_scope: ast::node_id, + kill_scope: ast::node_id, + span: span, } -// shorthand for something that fails with `bckerr` or succeeds with `T` -pub type bckres = Result; +#[deriving(Eq)] +pub enum LoanPath { + LpVar(ast::node_id), // `x` in doc.rs + LpExtend(@LoanPath, mc::MutabilityCategory, LoanPathElem) +} #[deriving(Eq)] -pub enum LoanKind { - TotalFreeze, // Entire path is frozen (borrowed as &T) - PartialFreeze, // Some subpath is frozen (borrowed as &T) - TotalTake, // Entire path is "taken" (borrowed as &mut T) - PartialTake, // Some subpath is "taken" (borrowed as &mut T) - Immobile // Path cannot be moved (borrowed as &const T) +pub enum LoanPathElem { + LpDeref, // `*LV` in doc.rs + LpInterior(mc::interior_kind) // `LV.f` in doc.rs } -/// a complete record of a loan that was granted -pub struct Loan { - lp: @loan_path, - cmt: cmt, - kind: LoanKind +pub impl LoanPath { + fn node_id(&self) -> ast::node_id { + match *self { + LpVar(local_id) => local_id, + LpExtend(base, _, _) => base.node_id() + } + } } -/// maps computed by `gather_loans` that are then used by `check_loans` -/// -/// - `req_loan_map`: map from each block/expr to the required loans needed -/// for the duration of that block/expr -/// - `pure_map`: map from block/expr that must be pure to the error message -/// that should be reported if they are not pure -pub struct ReqMaps { - req_loan_map: HashMap, - pure_map: HashMap +pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { + //! Computes the `LoanPath` (if any) for a `cmt`. + //! Note that this logic is somewhat duplicated in + //! the method `compute()` found in `gather_loans::restrictions`, + //! which allows it to share common loan path pieces as it + //! traverses the CMT. + + match cmt.cat { + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_copied_upvar(_) | + mc::cat_implicit_self => { + None + } + + mc::cat_local(id) | + mc::cat_arg(id) | + mc::cat_self(id) => { + Some(@LpVar(id)) + } + + mc::cat_deref(cmt_base, _, _) => { + opt_loan_path(cmt_base).map( + |&lp| @LpExtend(lp, cmt.mutbl, LpDeref)) + } + + mc::cat_interior(cmt_base, ik) => { + opt_loan_path(cmt_base).map( + |&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik))) + } + + mc::cat_stack_upvar(cmt_base) | + mc::cat_discr(cmt_base, _) => { + opt_loan_path(cmt_base) + } + } } -pub fn save_and_restore(save_and_restore_t: &mut T, - f: &fn() -> U) -> U { - let old_save_and_restore_t = *save_and_restore_t; - let u = f(); - *save_and_restore_t = old_save_and_restore_t; - u +/////////////////////////////////////////////////////////////////////////// +// Restrictions +// +// Borrowing an lvalue often results in *restrictions* that limit what +// can be done with this lvalue during the scope of the loan: +// +// - `RESTR_MUTATE`: The lvalue may not be modified and mutable pointers to +// the value cannot be created. +// - `RESTR_FREEZE`: Immutable pointers to the value cannot be created. +// - `RESTR_ALIAS`: The lvalue may not be aliased in any way. +// +// In addition, no value which is restricted may be moved. Therefore, +// restrictions are meaningful even if the RestrictionSet is empty, +// because the restriction against moves is implied. + +pub struct Restriction { + loan_path: @LoanPath, + set: RestrictionSet } -pub fn save_and_restore_managed(save_and_restore_t: @mut T, - f: &fn() -> U) -> U { - let old_save_and_restore_t = *save_and_restore_t; - let u = f(); - *save_and_restore_t = old_save_and_restore_t; - u +pub struct RestrictionSet { + bits: u32 } -pub impl LoanKind { - fn is_freeze(&self) -> bool { - match *self { - TotalFreeze | PartialFreeze => true, - _ => false - } +pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b000}; +pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b001}; +pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b010}; +pub static RESTR_ALIAS: RestrictionSet = RestrictionSet {bits: 0b100}; + +pub impl RestrictionSet { + fn intersects(&self, restr: RestrictionSet) -> bool { + (self.bits & restr.bits) != 0 } - fn is_take(&self) -> bool { - match *self { - TotalTake | PartialTake => true, - _ => false - } + fn contains_all(&self, restr: RestrictionSet) -> bool { + (self.bits & restr.bits) == restr.bits } } -/// Creates and returns a new root_map +impl BitOr for RestrictionSet { + fn bitor(&self, rhs: &RestrictionSet) -> RestrictionSet { + RestrictionSet {bits: self.bits | rhs.bits} + } +} -impl to_bytes::IterBytes for root_map_key { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f); +impl BitAnd for RestrictionSet { + fn bitand(&self, rhs: &RestrictionSet) -> RestrictionSet { + RestrictionSet {bits: self.bits & rhs.bits} } } +/////////////////////////////////////////////////////////////////////////// +// Rooting of managed boxes +// +// When we borrow the interior of a managed box, it is sometimes +// necessary to *root* the box, meaning to stash a copy of the box +// somewhere that the garbage collector will find it. This ensures +// that the box is not collected for the lifetime of the borrow. +// +// As part of this rooting, we sometimes also freeze the box at +// runtime, meaning that we dynamically detect when the box is +// borrowed in incompatible ways. +// +// Both of these actions are driven through the `root_map`, which maps +// from a node to the dynamic rooting action that should be taken when +// that node executes. The node is identified through a +// `root_map_key`, which pairs a node-id and a deref count---the +// problem is that sometimes the box that needs to be rooted is only +// uncovered after a certain number of auto-derefs. + +pub struct RootInfo { + scope: ast::node_id, + freeze: Option // Some() if we should freeze box at runtime +} + +pub type root_map = @mut HashMap; + pub fn root_map() -> root_map { return @mut HashMap::new(); } -// ___________________________________________________________________________ +pub enum DynaFreezeKind { + DynaImm, + DynaMut +} + +impl ToStr for DynaFreezeKind { + fn to_str(&self) -> ~str { + match *self { + DynaMut => ~"mutable", + DynaImm => ~"immutable" + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Errors + +// Errors that can occur +#[deriving(Eq)] +pub enum bckerr_code { + err_mutbl(ast::mutability), + err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope + err_out_of_scope(ty::Region, ty::Region), // superscope, subscope + err_freeze_aliasable_const +} + +// Combination of an error code and the categorization of the expression +// that caused it +#[deriving(Eq)] +pub struct BckError { + span: span, + cmt: mc::cmt, + code: bckerr_code +} + +pub enum AliasableViolationKind { + MutabilityViolation, + BorrowViolation +} + +/////////////////////////////////////////////////////////////////////////// // Misc pub impl BorrowckCtxt { @@ -456,27 +416,31 @@ pub impl BorrowckCtxt { self.tcx.region_maps.is_subregion_of(r_sub, r_sup) } - fn cat_expr(&self, expr: @ast::expr) -> cmt { - cat_expr(self.tcx, self.method_map, expr) + fn is_subscope_of(&self, r_sub: ast::node_id, r_sup: ast::node_id) -> bool { + self.tcx.region_maps.is_subscope_of(r_sub, r_sup) } - fn cat_expr_unadjusted(&self, expr: @ast::expr) -> cmt { - cat_expr_unadjusted(self.tcx, self.method_map, expr) + fn cat_expr(&self, expr: @ast::expr) -> mc::cmt { + mc::cat_expr(self.tcx, self.method_map, expr) + } + + fn cat_expr_unadjusted(&self, expr: @ast::expr) -> mc::cmt { + mc::cat_expr_unadjusted(self.tcx, self.method_map, expr) } fn cat_expr_autoderefd(&self, expr: @ast::expr, - adj: @ty::AutoAdjustment) -> cmt { + adj: @ty::AutoAdjustment) -> mc::cmt { match *adj { ty::AutoAddEnv(*) => { // no autoderefs - cat_expr_unadjusted(self.tcx, self.method_map, expr) + mc::cat_expr_unadjusted(self.tcx, self.method_map, expr) } ty::AutoDerefRef( ty::AutoDerefRef { autoderefs: autoderefs, _}) => { - cat_expr_autoderefd(self.tcx, self.method_map, expr, - autoderefs) + mc::cat_expr_autoderefd(self.tcx, self.method_map, expr, + autoderefs) } } } @@ -485,99 +449,113 @@ pub impl BorrowckCtxt { id: ast::node_id, span: span, ty: ty::t, - def: ast::def) -> cmt { - cat_def(self.tcx, self.method_map, id, span, ty, def) - } - - fn cat_variant(&self, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - cat_variant(self.tcx, self.method_map, arg, enum_did, cmt) + def: ast::def) -> mc::cmt { + mc::cat_def(self.tcx, self.method_map, id, span, ty, def) } - fn cat_discr(&self, cmt: cmt, match_id: ast::node_id) -> cmt { - return @cmt_ {cat:cat_discr(cmt, match_id),.. *cmt}; + fn cat_discr(&self, cmt: mc::cmt, match_id: ast::node_id) -> mc::cmt { + @mc::cmt_ {cat:mc::cat_discr(cmt, match_id), + mutbl:cmt.mutbl.inherit(), + ..*cmt} } - fn mc_ctxt(&self) -> mem_categorization_ctxt { - mem_categorization_ctxt {tcx: self.tcx, + fn mc_ctxt(&self) -> mc::mem_categorization_ctxt { + mc::mem_categorization_ctxt {tcx: self.tcx, method_map: self.method_map} } - fn cat_pattern(&self, cmt: cmt, pat: @ast::pat, op: &fn(cmt, @ast::pat)) { + fn cat_pattern(&self, + cmt: mc::cmt, + pat: @ast::pat, + op: &fn(mc::cmt, @ast::pat)) { let mc = self.mc_ctxt(); mc.cat_pattern(cmt, pat, op); } - fn report_if_err(&self, bres: bckres<()>) { - match bres { - Ok(()) => (), - Err(ref e) => self.report((*e)) - } - } - - fn report(&self, err: bckerr) { + fn report(&self, err: BckError) { self.span_err( - err.cmt.span, - fmt!("illegal borrow: %s", - self.bckerr_to_str(err))); + err.span, + self.bckerr_to_str(err)); self.note_and_explain_bckerr(err); } - fn span_err(&self, s: span, m: ~str) { + fn span_err(&self, s: span, m: &str) { self.tcx.sess.span_err(s, m); } - fn span_note(&self, s: span, m: ~str) { + fn span_note(&self, s: span, m: &str) { self.tcx.sess.span_note(s, m); } - fn add_to_mutbl_map(&self, cmt: cmt) { - match cmt.cat { - cat_local(id) | cat_arg(id) => { - self.mutbl_map.insert(id); - } - cat_stack_upvar(cmt) => { - self.add_to_mutbl_map(cmt); - } - _ => () - } - } - - fn bckerr_to_str(&self, err: bckerr) -> ~str { + fn bckerr_to_str(&self, err: BckError) -> ~str { match err.code { err_mutbl(lk) => { - fmt!("creating %s alias to %s", - self.loan_kind_to_str(lk), - self.cmt_to_str(err.cmt)) + fmt!("cannot borrow %s %s as %s", + err.cmt.mutbl.to_user_str(), + self.cmt_to_str(err.cmt), + self.mut_to_str(lk)) } - err_mut_uniq => { - ~"unique value in aliasable, mutable location" + err_out_of_root_scope(*) => { + fmt!("cannot root managed value long enough") } - err_mut_variant => { - ~"enum variant in aliasable, mutable location" + err_out_of_scope(*) => { + fmt!("borrowed value does not live long enough") } - err_root_not_permitted => { - // note: I don't expect users to ever see this error - // message, reasons are discussed in attempt_root() in - // preserve.rs. - ~"rooting is not permitted" + err_freeze_aliasable_const => { + // Means that the user borrowed a ~T or enum value + // residing in &const or @const pointer. Terrible + // error message, but then &const and @const are + // supposed to be going away. + fmt!("unsafe borrow of aliasable, const value") } - err_out_of_root_scope(*) => { - ~"cannot root managed value long enough" + } + } + + fn report_aliasability_violation(&self, + span: span, + kind: AliasableViolationKind, + cause: mc::AliasableReason) { + let prefix = match kind { + MutabilityViolation => "cannot assign to an `&mut`", + BorrowViolation => "cannot borrow an `&mut`" + }; + + match cause { + mc::AliasableOther => { + self.tcx.sess.span_err( + span, + fmt!("%s in an aliasable location", prefix)); } - err_out_of_scope(*) => { - ~"borrowed value does not live long enough" + mc::AliasableManaged(ast::m_mutbl) => { + // FIXME(#6269) reborrow @mut to &mut + self.tcx.sess.span_err( + span, + fmt!("%s in a `@mut` pointer; \ + try borrowing as `&mut` first", prefix)); + } + mc::AliasableManaged(m) => { + self.tcx.sess.span_err( + span, + fmt!("%s in a `@%s` pointer; \ + try an `@mut` instead", + prefix, + self.mut_to_keyword(m))); + } + mc::AliasableBorrowed(m) => { + self.tcx.sess.span_err( + span, + fmt!("%s in a `&%s` pointer; \ + try an `&mut` instead", + prefix, + self.mut_to_keyword(m))); } } } - fn note_and_explain_bckerr(&self, err: bckerr) { + fn note_and_explain_bckerr(&self, err: BckError) { let code = err.code; match code { - err_mutbl(*) | err_mut_uniq | err_mut_variant | - err_root_not_permitted => {} + err_mutbl(*) | err_freeze_aliasable_const(*) => {} err_out_of_root_scope(super_scope, sub_scope) => { note_and_explain_region( @@ -607,46 +585,140 @@ pub impl BorrowckCtxt { } } + fn append_loan_path_to_str_from_interior(&self, + loan_path: &LoanPath, + out: &mut ~str) { + match *loan_path { + LpExtend(_, _, LpDeref) => { + str::push_char(out, '('); + self.append_loan_path_to_str(loan_path, out); + str::push_char(out, ')'); + } + LpExtend(_, _, LpInterior(_)) | + LpVar(_) => { + self.append_loan_path_to_str(loan_path, out); + } + } + } - fn cmt_to_str(&self, cmt: cmt) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; - mc.cmt_to_str(cmt) + fn append_loan_path_to_str(&self, loan_path: &LoanPath, out: &mut ~str) { + match *loan_path { + LpVar(id) => { + match self.tcx.items.find(&id) { + Some(&ast_map::node_local(ident)) => { + str::push_str(out, *self.tcx.sess.intr().get(ident)); + } + r => { + self.tcx.sess.bug( + fmt!("Loan path LpVar(%?) maps to %?, not local", + id, r)); + } + } + } + + LpExtend(lp_base, _, LpInterior(mc::interior_field(fld))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_char(out, '.'); + str::push_str(out, *self.tcx.sess.intr().get(fld)); + } + + LpExtend(lp_base, _, LpInterior(mc::interior_index(*))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_str(out, "[]"); + } + + LpExtend(lp_base, _, LpInterior(mc::interior_tuple)) | + LpExtend(lp_base, _, LpInterior(mc::interior_anon_field)) | + LpExtend(lp_base, _, LpInterior(mc::interior_variant(_))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_str(out, ".(tuple)"); + } + + LpExtend(lp_base, _, LpDeref) => { + str::push_char(out, '*'); + self.append_loan_path_to_str(lp_base, out); + } + } } - fn cmt_to_repr(&self, cmt: cmt) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; - mc.cmt_to_repr(cmt) + fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str { + let mut result = ~""; + self.append_loan_path_to_str(loan_path, &mut result); + result + } + + fn cmt_to_str(&self, cmt: mc::cmt) -> ~str { + let mc = &mc::mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map}; + mc.cmt_to_str(cmt) } fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; + let mc = &mc::mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map}; mc.mut_to_str(mutbl) } - fn loan_kind_to_str(&self, lk: LoanKind) -> ~str { - match lk { - TotalFreeze | PartialFreeze => ~"immutable", - TotalTake | PartialTake => ~"mutable", - Immobile => ~"read-only" + fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str { + match mutbl { + ast::m_imm => "", + ast::m_const => "const", + ast::m_mutbl => "mut" } } +} + +impl DataFlowOperator for LoanDataFlowOperator { + #[inline(always)] + fn initial_value(&self) -> bool { + false // no loans in scope by default + } + + #[inline(always)] + fn join(&self, succ: uint, pred: uint) -> uint { + succ | pred // loans from both preds are in scope + } + + #[inline(always)] + fn walk_closures(&self) -> bool { + true + } +} - fn loan_to_repr(&self, loan: &Loan) -> ~str { - fmt!("Loan(lp=%?, cmt=%s, kind=%?)", - loan.lp, self.cmt_to_repr(loan.cmt), loan.kind) +impl Repr for Loan { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("Loan_%?(%s, %?, %?-%?, %s)", + self.index, + self.loan_path.repr(tcx), + self.mutbl, + self.gen_scope, + self.kill_scope, + self.restrictions.repr(tcx)) } } -// The inherent mutability of a component is its default mutability -// assuming it is embedded in an immutable context. In general, the -// mutability can be "overridden" if the component is embedded in a -// mutable structure. -pub fn inherent_mutability(ck: comp_kind) -> mutability { - match ck { - comp_tuple | comp_anon_field | comp_variant(_) => m_imm, - comp_field(_, m) | comp_index(_, m) => m +impl Repr for Restriction { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("Restriction(%s, %x)", + self.loan_path.repr(tcx), + self.set.bits as uint) + } +} + +impl Repr for LoanPath { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match self { + &LpVar(id) => { + fmt!("$(%?)", id) + } + + &LpExtend(lp, _, LpDeref) => { + fmt!("%s.*", lp.repr(tcx)) + } + + &LpExtend(lp, _, LpInterior(ref interior)) => { + fmt!("%s.%s", lp.repr(tcx), interior.repr(tcx)) + } + } } } diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs deleted file mode 100644 index c44920fffa568..0000000000000 --- a/src/librustc/middle/borrowck/preserve.rs +++ /dev/null @@ -1,409 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ---------------------------------------------------------------------- -// Preserve(Ex, S) holds if ToAddr(Ex) will remain valid for the entirety of -// the scope S. -// - -use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, BorrowckCtxt}; -use middle::borrowck::{err_mut_uniq, err_mut_variant}; -use middle::borrowck::{err_out_of_root_scope, err_out_of_scope}; -use middle::borrowck::{err_root_not_permitted, root_map_key}; -use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; -use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special}; -use middle::mem_categorization::{cat_stack_upvar, cmt, comp_field}; -use middle::mem_categorization::{comp_index, comp_variant, gc_ptr}; -use middle::mem_categorization::{region_ptr}; -use middle::ty; -use util::common::indenter; - -use syntax::ast; - -pub enum PreserveCondition { - PcOk, - PcIfPure(bckerr) -} - -pub impl PreserveCondition { - // combines two preservation conditions such that if either of - // them requires purity, the result requires purity - fn combine(&self, pc: PreserveCondition) -> PreserveCondition { - match *self { - PcOk => {pc} - PcIfPure(_) => {*self} - } - } -} - -pub impl BorrowckCtxt { - fn preserve(&self, - cmt: cmt, - scope_region: ty::Region, - item_ub: ast::node_id, - root_ub: ast::node_id) -> bckres - { - let ctxt = PreserveCtxt { - bccx: self, - scope_region: scope_region, - item_ub: item_ub, - root_ub: root_ub, - root_managed_data: true - }; - ctxt.preserve(cmt) - } -} - -struct PreserveCtxt<'self> { - bccx: &'self BorrowckCtxt, - - // the region scope for which we must preserve the memory - scope_region: ty::Region, - - // the scope for the body of the enclosing fn/method item - item_ub: ast::node_id, - - // the upper bound on how long we can root an @T pointer - root_ub: ast::node_id, - - // if false, do not attempt to root managed data - root_managed_data: bool -} - -pub impl<'self> PreserveCtxt<'self> { - fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - - fn preserve(&self, cmt: cmt) -> bckres { - debug!("preserve(cmt=%s, root_ub=%?, root_managed_data=%b)", - self.bccx.cmt_to_repr(cmt), self.root_ub, - self.root_managed_data); - let _i = indenter(); - - match cmt.cat { - cat_special(sk_implicit_self) | - cat_special(sk_heap_upvar) => { - self.compare_scope(cmt, ty::re_scope(self.item_ub)) - } - cat_special(sk_static_item) | cat_special(sk_method) => { - Ok(PcOk) - } - cat_rvalue => { - // when we borrow an rvalue, we can keep it rooted but only - // up to the root_ub point - - // When we're in a 'const &x = ...' context, self.root_ub is - // zero and the rvalue is static, not bound to a scope. - let scope_region = if self.root_ub == 0 { - ty::re_static - } else { - // Maybe if we pass in the parent instead here, - // we can prevent the "scope not found" error - debug!("scope_region thing: %? ", cmt.id); - self.tcx().region_maps.encl_region(cmt.id) - }; - - self.compare_scope(cmt, scope_region) - } - cat_stack_upvar(cmt) => { - self.preserve(cmt) - } - cat_local(local_id) => { - // Normally, local variables are lendable, and so this - // case should never trigger. However, if we are - // preserving an expression like a.b where the field `b` - // has @ type, then it will recurse to ensure that the `a` - // is stable to try and avoid rooting the value `a.b`. In - // this case, root_managed_data will be false. - if self.root_managed_data { - self.tcx().sess.span_bug( - cmt.span, - ~"preserve() called with local and !root_managed_data"); - } - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_binding(local_id) => { - // Bindings are these kind of weird implicit pointers (cc - // #2329). We require (in gather_loans) that they be - // rooted in an immutable location. - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_arg(local_id) => { - // This can happen as not all args are lendable (e.g., && - // modes). In that case, the caller guarantees stability - // for at least the scope of the fn. This is basically a - // deref of a region ptr. - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_self(local_id) => { - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_comp(cmt_base, comp_field(*)) | - cat_comp(cmt_base, comp_index(*)) | - cat_comp(cmt_base, comp_tuple) | - cat_comp(cmt_base, comp_anon_field) => { - // Most embedded components: if the base is stable, the - // type never changes. - self.preserve(cmt_base) - } - cat_comp(cmt_base, comp_variant(enum_did)) => { - if ty::enum_is_univariant(self.tcx(), enum_did) { - self.preserve(cmt_base) - } else { - // If there are multiple variants: overwriting the - // base could cause the type of this memory to change, - // so require imm. - self.require_imm(cmt, cmt_base, err_mut_variant) - } - } - cat_deref(cmt_base, _, uniq_ptr) => { - // Overwriting the base could cause this memory to be - // freed, so require imm. - self.require_imm(cmt, cmt_base, err_mut_uniq) - } - cat_deref(_, _, region_ptr(_, region)) => { - // References are always "stable" for lifetime `region` by - // induction (when the reference of type &MT was created, - // the memory must have been stable). - self.compare_scope(cmt, region) - } - cat_deref(_, _, unsafe_ptr) => { - // Unsafe pointers are the user's problem - Ok(PcOk) - } - cat_deref(base, derefs, gc_ptr(*)) => { - // GC'd pointers of type @MT: if this pointer lives in - // immutable, stable memory, then everything is fine. But - // otherwise we have no guarantee the pointer will stay - // live, so we must root the pointer (i.e., inc the ref - // count) for the duration of the loan. - debug!("base.mutbl = %?", base.mutbl); - if cmt.cat.derefs_through_mutable_box() { - self.attempt_root(cmt, base, derefs) - } else if base.mutbl.is_immutable() { - let non_rooting_ctxt = PreserveCtxt { - root_managed_data: false, - ..*self - }; - match non_rooting_ctxt.preserve(base) { - Ok(PcOk) => { - Ok(PcOk) - } - Ok(PcIfPure(_)) => { - debug!("must root @T, otherwise purity req'd"); - self.attempt_root(cmt, base, derefs) - } - Err(ref e) => { - debug!("must root @T, err: %s", - self.bccx.bckerr_to_str((*e))); - self.attempt_root(cmt, base, derefs) - } - } - } else { - self.attempt_root(cmt, base, derefs) - } - } - cat_discr(base, match_id) => { - // Subtle: in a match, we must ensure that each binding - // variable remains valid for the duration of the arm in - // which it appears, presuming that this arm is taken. - // But it is inconvenient in trans to root something just - // for one arm. Therefore, we insert a cat_discr(), - // basically a special kind of category that says "if this - // value must be dynamically rooted, root it for the scope - // `match_id`. - // - // As an example, consider this scenario: - // - // let mut x = @Some(3); - // match *x { Some(y) {...} None {...} } - // - // Technically, the value `x` need only be rooted - // in the `some` arm. However, we evaluate `x` in trans - // before we know what arm will be taken, so we just - // always root it for the duration of the match. - // - // As a second example, consider *this* scenario: - // - // let x = @mut @Some(3); - // match x { @@Some(y) {...} @@None {...} } - // - // Here again, `x` need only be rooted in the `some` arm. - // In this case, the value which needs to be rooted is - // found only when checking which pattern matches: but - // this check is done before entering the arm. Therefore, - // even in this case we just choose to keep the value - // rooted for the entire match. This means the value will be - // rooted even if the none arm is taken. Oh well. - // - // At first, I tried to optimize the second case to only - // root in one arm, but the result was suboptimal: first, - // it interfered with the construction of phi nodes in the - // arm, as we were adding code to root values before the - // phi nodes were added. This could have been addressed - // with a second basic block. However, the naive approach - // also yielded suboptimal results for patterns like: - // - // let x = @mut @...; - // match x { @@some_variant(y) | @@some_other_variant(y) => - // - // The reason is that we would root the value once for - // each pattern and not once per arm. This is also easily - // fixed, but it's yet more code for what is really quite - // the corner case. - // - // Nonetheless, if you decide to optimize this case in the - // future, you need only adjust where the cat_discr() - // node appears to draw the line between what will be rooted - // in the *arm* vs the *match*. - - let match_rooting_ctxt = PreserveCtxt { - scope_region: ty::re_scope(match_id), - ..*self - }; - match_rooting_ctxt.preserve(base) - } - } - } - - /// Reqiures that `cmt` (which is a deref or subcomponent of - /// `base`) be found in an immutable location (that is, `base` - /// must be immutable). Also requires that `base` itself is - /// preserved. - fn require_imm(&self, - cmt: cmt, - cmt_base: cmt, - code: bckerr_code) -> bckres { - // Variant contents and unique pointers: must be immutably - // rooted to a preserved address. - match self.preserve(cmt_base) { - // the base is preserved, but if we are not mutable then - // purity is required - Ok(PcOk) => { - if !cmt_base.mutbl.is_immutable() { - Ok(PcIfPure(bckerr {cmt:cmt, code:code})) - } else { - Ok(PcOk) - } - } - - // the base requires purity too, that's fine - Ok(PcIfPure(ref e)) => { - Ok(PcIfPure((*e))) - } - - // base is not stable, doesn't matter - Err(ref e) => { - Err((*e)) - } - } - } - - /// Checks that the scope for which the value must be preserved - /// is a subscope of `scope_ub`; if so, success. - fn compare_scope(&self, - cmt: cmt, - scope_ub: ty::Region) -> bckres { - if self.bccx.is_subregion_of(self.scope_region, scope_ub) { - Ok(PcOk) - } else { - Err(bckerr { - cmt:cmt, - code:err_out_of_scope(scope_ub, self.scope_region) - }) - } - } - - /// Here, `cmt=*base` is always a deref of managed data (if - /// `derefs` != 0, then an auto-deref). This routine determines - /// whether it is safe to MAKE cmt stable by rooting the pointer - /// `base`. We can only do the dynamic root if the desired - /// lifetime `self.scope_region` is a subset of `self.root_ub` - /// scope; otherwise, it would either require that we hold the - /// value live for longer than the current fn or else potentially - /// require that an statically unbounded number of values be - /// rooted (if a loop exists). - fn attempt_root(&self, cmt: cmt, base: cmt, - derefs: uint) -> bckres { - if !self.root_managed_data { - // normally, there is a root_ub; the only time that this - // is none is when a boxed value is stored in an immutable - // location. In that case, we will test to see if that - // immutable location itself can be preserved long enough - // in which case no rooting is necessary. But there it - // would be sort of pointless to avoid rooting the inner - // box by rooting an outer box, as it would just keep more - // memory live than necessary, so we set root_ub to none. - return Err(bckerr { cmt: cmt, code: err_root_not_permitted }); - } - - let root_region = ty::re_scope(self.root_ub); - match self.scope_region { - // we can only root values if the desired region is some concrete - // scope within the fn body - ty::re_scope(scope_id) => { - debug!("Considering root map entry for %s: \ - node %d:%u -> scope_id %?, root_ub %?", - self.bccx.cmt_to_repr(cmt), base.id, - derefs, scope_id, self.root_ub); - if self.bccx.is_subregion_of(self.scope_region, root_region) { - debug!("Elected to root"); - let rk = root_map_key { id: base.id, derefs: derefs }; - // This code could potentially lead cause boxes to be frozen - // for longer than necessarily at runtime. It prevents an - // ICE in trans; the fundamental problem is that it's hard - // to make sure trans and borrowck have the same notion of - // scope. The real fix is to clean up how trans handles - // cleanups, but that's hard. If this becomes an issue, it's - // an option to just change this to `let scope_to_use = - // scope_id;`. Though that would potentially re-introduce - // the ICE. See #3511 for more details. - let scope_to_use = if - self.bccx.stmt_map.contains(&scope_id) { - // Root it in its parent scope, b/c - // trans won't introduce a new scope for the - // stmt - self.root_ub - } - else { - // Use the more precise scope - scope_id - }; - // We freeze if and only if this is a *mutable* @ box that - // we're borrowing into a pointer. - self.bccx.root_map.insert(rk, RootInfo { - scope: scope_to_use, - freezes: cmt.cat.derefs_through_mutable_box() - }); - return Ok(PcOk); - } else { - debug!("Unable to root"); - return Err(bckerr { - cmt: cmt, - code: err_out_of_root_scope(root_region, - self.scope_region) - }); - } - } - - // we won't be able to root long enough - _ => { - return Err(bckerr { - cmt:cmt, - code:err_out_of_root_scope(root_region, self.scope_region) - }); - } - - } - } -} diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6a47eedcea8c3..9e6d90532373a 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -92,13 +92,13 @@ pub fn check_expr(sess: Session, expr_unary(deref, _) => { } expr_unary(box(_), _) | expr_unary(uniq(_), _) => { sess.span_err(e.span, - ~"disallowed operator in constant expression"); + "disallowed operator in constant expression"); return; } expr_lit(@codemap::spanned {node: lit_str(_), _}) => { } expr_binary(_, _, _) | expr_unary(_, _) => { if method_map.contains_key(&e.id) { - sess.span_err(e.span, ~"user-defined operators are not \ + sess.span_err(e.span, "user-defined operators are not \ allowed in constant expressions"); } } @@ -118,8 +118,8 @@ pub fn check_expr(sess: Session, // a path in trans::callee that only works in block contexts. if pth.types.len() != 0 { sess.span_err( - e.span, ~"paths in constants may only refer to \ - items without type parameters"); + e.span, "paths in constants may only refer to \ + items without type parameters"); } match def_map.find(&e.id) { Some(&def_const(_)) | @@ -131,11 +131,11 @@ pub fn check_expr(sess: Session, debug!("(checking const) found bad def: %?", def); sess.span_err( e.span, - fmt!("paths in constants may only refer to \ - constants or functions")); + "paths in constants may only refer to \ + constants or functions"); } None => { - sess.span_bug(e.span, ~"unbound path in const?!"); + sess.span_bug(e.span, "unbound path in const?!"); } } } @@ -146,8 +146,8 @@ pub fn check_expr(sess: Session, _ => { sess.span_err( e.span, - ~"function calls in constants are limited to \ - struct and enum constructors"); + "function calls in constants are limited to \ + struct and enum constructors"); } } } @@ -163,12 +163,12 @@ pub fn check_expr(sess: Session, expr_addr_of(*) => { sess.span_err( e.span, - ~"borrowed pointers in constants may only refer to \ - immutable values"); + "borrowed pointers in constants may only refer to \ + immutable values"); } _ => { sess.span_err(e.span, - ~"constant contains unimplemented expression type"); + "constant contains unimplemented expression type"); return; } } @@ -178,14 +178,14 @@ pub fn check_expr(sess: Session, if t != ty_char { if (v as u64) > ast_util::int_ty_max( if t == ty_i { sess.targ_cfg.int_type } else { t }) { - sess.span_err(e.span, ~"literal out of range for its type"); + sess.span_err(e.span, "literal out of range for its type"); } } } expr_lit(@codemap::spanned {node: lit_uint(v, t), _}) => { if v > ast_util::uint_ty_max( if t == ty_u { sess.targ_cfg.uint_type } else { t }) { - sess.span_err(e.span, ~"literal out of range for its type"); + sess.span_err(e.span, "literal out of range for its type"); } } _ => () @@ -224,7 +224,7 @@ pub fn check_item_recursion(sess: Session, fn visit_item(it: @item, env: env, v: visit::vt) { if env.idstack.contains(&(it.id)) { - env.sess.span_fatal(env.root_it.span, ~"recursive constant"); + env.sess.span_fatal(env.root_it.span, "recursive constant"); } env.idstack.push(it.id); visit::visit_item(it, env, v); @@ -237,7 +237,7 @@ pub fn check_item_recursion(sess: Session, match env.def_map.find(&e.id) { Some(&def_const(def_id)) => { if ast_util::is_local(def_id) { - match *env.ast_map.get(&def_id.node) { + match env.ast_map.get_copy(&def_id.node) { ast_map::node_item(it, _) => { (v.visit_item)(it, env, v); } @@ -253,11 +253,3 @@ pub fn check_item_recursion(sess: Session, visit::visit_expr(e, env, v); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 9f26f7f83724f..e3b816fceb8bb 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -54,17 +54,17 @@ pub fn check_crate(tcx: ty::ctxt, crate: @crate) { } expr_break(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, ~"`break` outside of loop"); + tcx.sess.span_err(e.span, "`break` outside of loop"); } } expr_again(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, ~"`again` outside of loop"); + tcx.sess.span_err(e.span, "`again` outside of loop"); } } expr_ret(oe) => { if !cx.can_ret { - tcx.sess.span_err(e.span, ~"`return` in block function"); + tcx.sess.span_err(e.span, "`return` in block function"); } visit::visit_expr_opt(oe, cx, v); } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 852eb1b50a499..330d30c17a80b 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -94,7 +94,7 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, s: (), v: visit::vt<()>) { } let arms = vec::concat(arms.filter_mapped(unguarded_pat)); if arms.is_empty() { - cx.tcx.sess.span_err(ex.span, ~"non-exhaustive patterns"); + cx.tcx.sess.span_err(ex.span, "non-exhaustive patterns"); } else { check_exhaustive(cx, ex.span, arms); } @@ -111,7 +111,7 @@ pub fn check_arms(cx: @MatchCheckCtxt, arms: &[arm]) { let v = ~[*pat]; match is_useful(cx, &seen, v) { not_useful => { - cx.tcx.sess.span_err(pat.span, ~"unreachable pattern"); + cx.tcx.sess.span_err(pat.span, "unreachable pattern"); } _ => () } @@ -366,7 +366,7 @@ pub fn missing_ctor(cx: @MatchCheckCtxt, } let variants = ty::enum_variants(cx.tcx, eid); if found.len() != (*variants).len() { - for vec::each(*variants) |v| { + for (*variants).each |v| { if !found.contains(&(variant(v.id))) { return Some(variant(v.id)); } @@ -488,7 +488,7 @@ pub fn specialize(cx: @MatchCheckCtxt, match cx.tcx.def_map.find(&pat_id) { Some(&def_variant(_, id)) => { if variant(id) == *ctor_id { - Some(vec::from_slice(r.tail())) + Some(vec::to_owned(r.tail())) } else { None } @@ -507,7 +507,7 @@ pub fn specialize(cx: @MatchCheckCtxt, _ => fail!(~"type error") }; if match_ { - Some(vec::from_slice(r.tail())) + Some(vec::to_owned(r.tail())) } else { None } @@ -523,7 +523,7 @@ pub fn specialize(cx: @MatchCheckCtxt, } } pat_enum(_, args) => { - match *cx.tcx.def_map.get(&pat_id) { + match cx.tcx.def_map.get_copy(&pat_id) { def_const(did) => { let const_expr = lookup_const_by_id(cx.tcx, did).get(); @@ -538,7 +538,7 @@ pub fn specialize(cx: @MatchCheckCtxt, _ => fail!(~"type error") }; if match_ { - Some(vec::from_slice(r.tail())) + Some(vec::to_owned(r.tail())) } else { None } @@ -548,7 +548,7 @@ pub fn specialize(cx: @MatchCheckCtxt, Some(args) => args, None => vec::from_elem(arity, wild()) }; - Some(vec::append(args, vec::from_slice(r.tail()))) + Some(vec::append(args, vec::to_owned(r.tail()))) } def_variant(_, _) => None, @@ -560,14 +560,14 @@ pub fn specialize(cx: @MatchCheckCtxt, Some(args) => new_args = args, None => new_args = vec::from_elem(arity, wild()) } - Some(vec::append(new_args, vec::from_slice(r.tail()))) + Some(vec::append(new_args, vec::to_owned(r.tail()))) } _ => None } } pat_struct(_, ref flds, _) => { // Is this a struct or an enum variant? - match *cx.tcx.def_map.get(&pat_id) { + match cx.tcx.def_map.get_copy(&pat_id) { def_variant(_, variant_id) => { if variant(variant_id) == *ctor_id { // FIXME #4731: Is this right? --pcw @@ -578,7 +578,7 @@ pub fn specialize(cx: @MatchCheckCtxt, _ => wild() } }); - Some(vec::append(args, vec::from_slice(r.tail()))) + Some(vec::append(args, vec::to_owned(r.tail()))) } else { None } @@ -608,7 +608,7 @@ pub fn specialize(cx: @MatchCheckCtxt, _ => wild() } }); - Some(vec::append(args, vec::from_slice(r.tail()))) + Some(vec::append(args, vec::to_owned(r.tail()))) } } } @@ -627,21 +627,21 @@ pub fn specialize(cx: @MatchCheckCtxt, single => true, _ => fail!(~"type error") }; - if match_ { Some(vec::from_slice(r.tail())) } else { None } + if match_ { Some(vec::to_owned(r.tail())) } else { None } } pat_range(lo, hi) => { let (c_lo, c_hi) = match *ctor_id { val(ref v) => ((/*bad*/copy *v), (/*bad*/copy *v)), range(ref lo, ref hi) => ((/*bad*/copy *lo), (/*bad*/copy *hi)), - single => return Some(vec::from_slice(r.tail())), + single => return Some(vec::to_owned(r.tail())), _ => fail!(~"type error") }; let v_lo = eval_const_expr(cx.tcx, lo), v_hi = eval_const_expr(cx.tcx, hi); let match_ = compare_const_vals(&c_lo, &v_lo) >= 0 && compare_const_vals(&c_hi, &v_hi) <= 0; - if match_ { Some(vec::from_slice(r.tail())) } else { None } + if match_ { Some(vec::to_owned(r.tail())) } else { None } } pat_vec(before, slice, after) => { match *ctor_id { @@ -674,7 +674,7 @@ pub fn specialize(cx: @MatchCheckCtxt, } pub fn default(cx: @MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { - if is_wild(cx, r[0]) { Some(vec::from_slice(r.tail())) } + if is_wild(cx, r[0]) { Some(vec::to_owned(r.tail())) } else { None } } @@ -685,7 +685,7 @@ pub fn check_local(cx: @MatchCheckCtxt, visit::visit_local(loc, s, v); if is_refutable(cx, loc.node.pat) { cx.tcx.sess.span_err(loc.node.pat.span, - ~"refutable pattern in local binding"); + "refutable pattern in local binding"); } // Check legality of move bindings. @@ -708,7 +708,7 @@ pub fn check_fn(cx: @MatchCheckCtxt, for decl.inputs.each |input| { if is_refutable(cx, input.pat) { cx.tcx.sess.span_err(input.pat.span, - ~"refutable pattern in function argument"); + "refutable pattern in function argument"); } } } @@ -780,24 +780,24 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, if sub.is_some() { tcx.sess.span_err( p.span, - ~"cannot bind by-move with sub-bindings"); + "cannot bind by-move with sub-bindings"); } else if has_guard { tcx.sess.span_err( p.span, - ~"cannot bind by-move into a pattern guard"); + "cannot bind by-move into a pattern guard"); } else if by_ref_span.is_some() { tcx.sess.span_err( p.span, - ~"cannot bind by-move and by-ref \ - in the same pattern"); + "cannot bind by-move and by-ref \ + in the same pattern"); tcx.sess.span_note( by_ref_span.get(), - ~"by-ref binding occurs here"); + "by-ref binding occurs here"); } else if is_lvalue { tcx.sess.span_err( p.span, - ~"cannot bind by-move when \ - matching an lvalue"); + "cannot bind by-move when \ + matching an lvalue"); } }; @@ -822,51 +822,65 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, } } - // Now check to ensure that any move binding is not behind an @ or &. - // This is always illegal. + // Now check to ensure that any move binding is not behind an + // @ or &, or within a struct with a destructor. This is + // always illegal. let vt = visit::mk_vt(@visit::Visitor { - visit_pat: |pat, behind_bad_pointer: bool, v| { + visit_pat: |pat, (behind_bad_pointer, behind_dtor_struct): (bool, bool), v| { match pat.node { pat_ident(_, _, sub) => { debug!("(check legality of move) checking pat \ - ident with behind_bad_pointer %?", - behind_bad_pointer); + ident with behind_bad_pointer %? and behind_dtor_struct %?", + behind_bad_pointer, behind_dtor_struct); - if behind_bad_pointer && + if behind_bad_pointer || behind_dtor_struct && cx.moves_map.contains(&pat.id) { - cx.tcx.sess.span_err( - pat.span, - ~"by-move pattern \ - bindings may not occur \ - behind @ or & bindings"); + let msg = if behind_bad_pointer { + "by-move pattern bindings may not occur behind @ or & bindings" + } else { + "cannot bind by-move within struct (it has a destructor)" + }; + cx.tcx.sess.span_err(pat.span, msg); } match sub { None => {} Some(subpat) => { - (v.visit_pat)(subpat, behind_bad_pointer, v); + (v.visit_pat)(subpat, + (behind_bad_pointer, behind_dtor_struct), + v); } } } pat_box(subpat) | pat_region(subpat) => { - (v.visit_pat)(subpat, true, v); + (v.visit_pat)(subpat, (true, behind_dtor_struct), v); } - _ => visit::visit_pat(pat, behind_bad_pointer, v) + pat_struct(_, ref fields, _) => { + let behind_dtor_struct = behind_dtor_struct || + (match cx.tcx.def_map.find(&pat.id) { + Some(&def_struct(id)) => { + ty::has_dtor(cx.tcx, id) + } + _ => false + }); + debug!("(check legality of move) checking pat \ + struct with behind_bad_pointer %? and behind_dtor_struct %?", + behind_bad_pointer, behind_dtor_struct); + + for fields.each |fld| { + (v.visit_pat)(fld.pat, (behind_bad_pointer, + behind_dtor_struct), v) + } + } + + _ => visit::visit_pat(pat, (behind_bad_pointer, behind_dtor_struct), v) } }, - .. *visit::default_visitor::() + .. *visit::default_visitor::<(bool, bool)>() }); - (vt.visit_pat)(*pat, false, vt); + (vt.visit_pat)(*pat, (false, false), vt); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bba4d35b56046..7c1933d67853a 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -185,9 +185,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, } } else { let maps = astencode::Maps { - mutbl_map: @mut HashSet::new(), root_map: @mut HashMap::new(), - last_use_map: @mut HashMap::new(), method_map: @mut HashMap::new(), vtable_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), @@ -279,7 +277,7 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_float(a + b)), subtract => Ok(const_float(a - b)), mul => Ok(const_float(a * b)), - quot => Ok(const_float(a / b)), + div => Ok(const_float(a / b)), rem => Ok(const_float(a % b)), eq => fromb(a == b), lt => fromb(a < b), @@ -295,8 +293,8 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_int(a + b)), subtract => Ok(const_int(a - b)), mul => Ok(const_int(a * b)), - quot if b == 0 => Err(~"attempted quotient with a divisor of zero"), - quot => Ok(const_int(a / b)), + div if b == 0 => Err(~"attempted to divide by zero"), + div => Ok(const_int(a / b)), rem if b == 0 => Err(~"attempted remainder with a divisor of zero"), rem => Ok(const_int(a % b)), and | bitand => Ok(const_int(a & b)), @@ -317,8 +315,8 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_uint(a + b)), subtract => Ok(const_uint(a - b)), mul => Ok(const_uint(a * b)), - quot if b == 0 => Err(~"attempted quotient with a divisor of zero"), - quot => Ok(const_uint(a / b)), + div if b == 0 => Err(~"attempted to divide by zero"), + div => Ok(const_uint(a / b)), rem if b == 0 => Err(~"attempted remainder with a divisor of zero"), rem => Ok(const_uint(a % b)), and | bitand => Ok(const_uint(a & b)), @@ -484,12 +482,3 @@ pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { pub fn lit_eq(a: @lit, b: @lit) -> bool { compare_const_vals(&lit_to_const(a), &lit_to_const(b)) == 0 } - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs new file mode 100644 index 0000000000000..31d22b76800c1 --- /dev/null +++ b/src/librustc/middle/dataflow.rs @@ -0,0 +1,1065 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +/*! + * A module for propagating forward dataflow information. The analysis + * assumes that the items to be propagated can be represented as bits + * and thus uses bitvectors. Your job is simply to specify the so-called + * GEN and KILL bits for each expression. + */ + +use core::prelude::*; +use core::cast; +use core::uint; +use syntax::ast; +use syntax::ast_util; +use syntax::ast_util::id_range; +use syntax::print::{pp, pprust}; +use middle::ty; +use middle::typeck; +use util::ppaux::Repr; + +pub struct DataFlowContext { + priv tcx: ty::ctxt, + priv method_map: typeck::method_map, + + /// the data flow operator + priv oper: O, + + /// range of ids that appear within the item in question + priv id_range: id_range, + + /// number of bits to propagate per id + priv bits_per_id: uint, + + /// number of words we will use to store bits_per_id. + /// equal to bits_per_id/uint::bits rounded up. + priv words_per_id: uint, + + // Bit sets per id. The following three fields (`gens`, `kills`, + // and `on_entry`) all have the same structure. For each id in + // `id_range`, there is a range of words equal to `words_per_id`. + // So, to access the bits for any given id, you take a slice of + // the full vector (see the method `compute_id_range()`). + + /// bits generated as we exit the scope `id`. Updated by `add_gen()`. + priv gens: ~[uint], + + /// bits killed as we exit the scope `id`. Updated by `add_kill()`. + priv kills: ~[uint], + + /// bits that are valid on entry to the scope `id`. Updated by + /// `propagate()`. + priv on_entry: ~[uint] +} + +/// Parameterization for the precise form of data flow that is used. +pub trait DataFlowOperator { + /// Specifies the initial value for each bit in the `on_entry` set + fn initial_value(&self) -> bool; + + /// Joins two predecessor bits together, typically either `|` or `&` + fn join(&self, succ: uint, pred: uint) -> uint; + + /// True if we should propagate through closures + fn walk_closures(&self) -> bool; +} + +struct PropagationContext<'self, O> { + dfcx: &'self mut DataFlowContext, + changed: bool +} + +#[deriving(Eq)] +enum LoopKind { + /// A `while` or `loop` loop + TrueLoop, + + /// A `for` "loop" (i.e., really a func call where `break`, `return`, + /// and `loop` all essentially perform an early return from the closure) + ForLoop +} + +struct LoopScope<'self> { + loop_id: ast::node_id, + loop_kind: LoopKind, + break_bits: ~[uint] +} + +impl DataFlowContext { + pub fn new(tcx: ty::ctxt, + method_map: typeck::method_map, + oper: O, + id_range: id_range, + bits_per_id: uint) -> DataFlowContext { + let words_per_id = (bits_per_id + uint::bits - 1) / uint::bits; + + debug!("DataFlowContext::new(id_range=%?, bits_per_id=%?, words_per_id=%?)", + id_range, bits_per_id, words_per_id); + + let len = (id_range.max - id_range.min) as uint * words_per_id; + let gens = vec::from_elem(len, 0); + let kills = vec::from_elem(len, 0); + let elem = if oper.initial_value() {uint::max_value} else {0}; + let on_entry = vec::from_elem(len, elem); + + DataFlowContext { + tcx: tcx, + method_map: method_map, + words_per_id: words_per_id, + bits_per_id: bits_per_id, + oper: oper, + id_range: id_range, + gens: gens, + kills: kills, + on_entry: on_entry + } + } + + pub fn add_gen(&mut self, id: ast::node_id, bit: uint) { + //! Indicates that `id` generates `bit` + + debug!("add_gen(id=%?, bit=%?)", id, bit); + let (start, end) = self.compute_id_range(id); + { + let gens = vec::mut_slice(self.gens, start, end); + set_bit(gens, bit); + } + } + + pub fn add_kill(&mut self, id: ast::node_id, bit: uint) { + //! Indicates that `id` kills `bit` + + debug!("add_kill(id=%?, bit=%?)", id, bit); + let (start, end) = self.compute_id_range(id); + { + let kills = vec::mut_slice(self.kills, start, end); + set_bit(kills, bit); + } + } + + fn apply_gen_kill(&self, id: ast::node_id, bits: &mut [uint]) { + //! Applies the gen and kill sets for `id` to `bits` + + debug!("apply_gen_kill(id=%?, bits=%s) [before]", + id, mut_bits_to_str(bits)); + let (start, end) = self.compute_id_range(id); + let gens = self.gens.slice(start, end); + bitwise(bits, gens, |a, b| a | b); + let kills = self.kills.slice(start, end); + bitwise(bits, kills, |a, b| a & !b); + + debug!("apply_gen_kill(id=%?, bits=%s) [after]", + id, mut_bits_to_str(bits)); + } + + fn apply_kill(&self, id: ast::node_id, bits: &mut [uint]) { + debug!("apply_kill(id=%?, bits=%s) [before]", + id, mut_bits_to_str(bits)); + let (start, end) = self.compute_id_range(id); + let kills = self.kills.slice(start, end); + bitwise(bits, kills, |a, b| a & !b); + debug!("apply_kill(id=%?, bits=%s) [after]", + id, mut_bits_to_str(bits)); + } + + fn compute_id_range(&self, absolute_id: ast::node_id) -> (uint, uint) { + assert!(absolute_id >= self.id_range.min); + assert!(absolute_id < self.id_range.max); + + let relative_id = absolute_id - self.id_range.min; + let start = (relative_id as uint) * self.words_per_id; + let end = start + self.words_per_id; + (start, end) + } + + + #[cfg(stage0)] + pub fn each_bit_on_entry(&self, + id: ast::node_id, + f: &fn(uint) -> bool) { + //! Iterates through each bit that is set on entry to `id`. + //! 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); + debug!("each_bit_on_entry(id=%?, on_entry=%s)", + id, bits_to_str(on_entry)); + self.each_bit(on_entry, f); + } + #[cfg(not(stage0))] + pub fn each_bit_on_entry(&self, + id: ast::node_id, + f: &fn(uint) -> bool) -> bool { + //! Iterates through each bit that is set on entry to `id`. + //! 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); + debug!("each_bit_on_entry(id=%?, on_entry=%s)", + id, bits_to_str(on_entry)); + self.each_bit(on_entry, f) + } + + #[cfg(stage0)] + pub fn each_gen_bit(&self, + id: ast::node_id, + f: &fn(uint) -> bool) { + //! 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); + debug!("each_gen_bit(id=%?, gens=%s)", + id, bits_to_str(gens)); + self.each_bit(gens, f) + } + #[cfg(not(stage0))] + pub fn each_gen_bit(&self, + id: ast::node_id, + f: &fn(uint) -> bool) -> bool { + //! 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); + debug!("each_gen_bit(id=%?, gens=%s)", + id, bits_to_str(gens)); + self.each_bit(gens, f) + } + + #[cfg(stage0)] + fn each_bit(&self, + words: &[uint], + f: &fn(uint) -> bool) { + //! Helper for iterating over the bits in a bit set. + + for words.eachi |word_index, &word| { + if word != 0 { + let base_index = word_index * uint::bits; + for uint::range(0, uint::bits) |offset| { + let bit = 1 << offset; + if (word & bit) != 0 { + // NB: we round up the total number of bits + // that we store in any given bit set so that + // it is an even multiple of uint::bits. This + // means that there may be some stray bits at + // the end that do not correspond to any + // actual value. So before we callback, check + // whether the bit_index is greater than the + // actual value the user specified and stop + // iterating if so. + let bit_index = base_index + offset; + if bit_index >= self.bits_per_id || !f(bit_index) { + return; + } + } + } + } + } + } + #[cfg(not(stage0))] + fn each_bit(&self, + words: &[uint], + f: &fn(uint) -> bool) -> bool { + //! Helper for iterating over the bits in a bit set. + + for words.eachi |word_index, &word| { + if word != 0 { + let base_index = word_index * uint::bits; + for uint::range(0, uint::bits) |offset| { + let bit = 1 << offset; + if (word & bit) != 0 { + // NB: we round up the total number of bits + // that we store in any given bit set so that + // it is an even multiple of uint::bits. This + // means that there may be some stray bits at + // the end that do not correspond to any + // actual value. So before we callback, check + // whether the bit_index is greater than the + // actual value the user specified and stop + // iterating if so. + let bit_index = base_index + offset; + if bit_index >= self.bits_per_id { + return true; + } else if !f(bit_index) { + return false; + } + } + } + } + } + return true; + } +} + +impl DataFlowContext { +// ^^^^^^^^^^^^ only needed for pretty printing + pub fn propagate(&mut self, blk: &ast::blk) { + //! Performs the data flow analysis. + + if self.bits_per_id == 0 { + // Optimize the surprisingly common degenerate case. + return; + } + + let mut propcx = PropagationContext { + dfcx: self, + changed: true + }; + + let mut temp = vec::from_elem(self.words_per_id, 0); + let mut loop_scopes = ~[]; + + while propcx.changed { + propcx.changed = false; + propcx.reset(temp); + propcx.walk_block(blk, temp, &mut loop_scopes); + } + + debug!("Dataflow result:"); + debug!("%s", { + let this = @copy *self; + this.pretty_print_to(io::stderr(), blk); + "" + }); + } + + fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::blk) { + let pre: @fn(pprust::ann_node) = |node| { + let (ps, id) = match node { + pprust::node_expr(ps, expr) => (ps, expr.id), + pprust::node_block(ps, blk) => (ps, blk.node.id), + pprust::node_item(ps, _) => (ps, 0), + pprust::node_pat(ps, pat) => (ps, pat.id) + }; + + if id >= self.id_range.min || id < self.id_range.max { + let (start, end) = self.compute_id_range(id); + let on_entry = vec::slice(self.on_entry, start, end); + let entry_str = bits_to_str(on_entry); + + let gens = vec::slice(self.gens, start, end); + let gens_str = if gens.any(|&u| u != 0) { + fmt!(" gen: %s", bits_to_str(gens)) + } else { + ~"" + }; + + let kills = vec::slice(self.kills, start, end); + let kills_str = if kills.any(|&u| u != 0) { + fmt!(" kill: %s", bits_to_str(kills)) + } else { + ~"" + }; + + let comment_str = fmt!("id %d: %s%s%s", + id, entry_str, gens_str, kills_str); + pprust::synth_comment(ps, comment_str); + pp::space(ps.s); + } + }; + + let post: @fn(pprust::ann_node) = |_| { + }; + + let ps = pprust::rust_printer_annotated( + wr, self.tcx.sess.intr(), + pprust::pp_ann {pre:pre, post:post}); + pprust::cbox(ps, pprust::indent_unit); + pprust::ibox(ps, 0u); + pprust::print_block(ps, blk); + pp::eof(ps.s); + } +} + +impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { + fn tcx(&self) -> ty::ctxt { + self.dfcx.tcx + } + + fn walk_block(&mut self, + blk: &ast::blk, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_block(blk.node.id=%?, in_out=%s)", + blk.node.id, bits_to_str(reslice(in_out))); + + self.merge_with_entry_set(blk.node.id, in_out); + + for blk.node.stmts.each |&stmt| { + self.walk_stmt(stmt, in_out, loop_scopes); + } + + self.walk_opt_expr(blk.node.expr, in_out, loop_scopes); + + self.dfcx.apply_gen_kill(blk.node.id, in_out); + } + + fn walk_stmt(&mut self, + stmt: @ast::stmt, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + match stmt.node { + ast::stmt_decl(decl, _) => { + self.walk_decl(decl, in_out, loop_scopes); + } + + ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => { + self.walk_expr(expr, in_out, loop_scopes); + } + + ast::stmt_mac(*) => { + self.tcx().sess.span_bug(stmt.span, ~"unexpanded macro"); + } + } + } + + fn walk_decl(&mut self, + decl: @ast::decl, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + match decl.node { + ast::decl_local(ref locals) => { + for locals.each |local| { + self.walk_pat(local.node.pat, in_out, loop_scopes); + self.walk_opt_expr(local.node.init, in_out, loop_scopes); + } + } + + ast::decl_item(_) => {} + } + } + + fn walk_expr(&mut self, + expr: @ast::expr, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_expr(expr=%s, in_out=%s)", + expr.repr(self.dfcx.tcx), bits_to_str(reslice(in_out))); + + self.merge_with_entry_set(expr.id, in_out); + + match expr.node { + ast::expr_fn_block(ref decl, ref body) => { + if self.dfcx.oper.walk_closures() { + // In the absence of once fns, we must assume that + // every function body will execute more than + // once. Thus we treat every function body like a + // loop. + // + // What is subtle and a bit tricky, also, is how + // to deal with the "output" bits---that is, what + // do we consider to be the successor of a + // function body, given that it could be called + // from any point within its lifetime? What we do + // is to add their effects immediately as of the + // point of creation. Of course we have to ensure + // that this is sound for the analyses which make + // use of dataflow. + // + // In the case of the initedness checker (which + // does not currently use dataflow, but I hope to + // convert at some point), we will simply not walk + // closures at all, so it's a moot point. + // + // In the case of the borrow checker, this means + // the loans which would be created by calling a + // function come into effect immediately when the + // function is created. This is guaranteed to be + // earlier than the point at which the loan + // actually comes into scope (which is the point + // at which the closure is *called*). Because + // loans persist until the scope of the loans is + // exited, it is always a safe approximation to + // have a loan begin earlier than it actually will + // at runtime, so this should be sound. + // + // We stil have to be careful in the region + // checker and borrow checker to treat function + // bodies like loops, which implies some + // limitations. For example, a closure cannot root + // a managed box for longer than its body. + // + // General control flow looks like this: + // + // +- (expr) <----------+ + // | | | + // | v | + // | (body) -----------+--> (exit) + // | | | + // | + (break/loop) -+ + // | | + // +--------------------+ + // + // This is a bit more conservative than a loop. + // Note that we must assume that even after a + // `break` occurs (e.g., in a `for` loop) that the + // closure may be reinvoked. + // + // One difference from other loops is that `loop` + // and `break` statements which target a closure + // both simply add to the `break_bits`. + + // func_bits represents the state when the function + // returns + let mut func_bits = reslice(in_out).to_vec(); + + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: ForLoop, + break_bits: reslice(in_out).to_vec() + }); + for decl.inputs.each |input| { + self.walk_pat(input.pat, func_bits, loop_scopes); + } + self.walk_block(body, func_bits, loop_scopes); + + // add the bits from any early return via `break`, + // `continue`, or `return` into `func_bits` + let loop_scope = loop_scopes.pop(); + join_bits(&self.dfcx.oper, loop_scope.break_bits, func_bits); + + // add `func_bits` to the entry bits for `expr`, + // since we must assume the function may be called + // more than once + self.add_to_entry_set(expr.id, reslice(func_bits)); + + // the final exit bits include whatever was present + // in the original, joined with the bits from the function + join_bits(&self.dfcx.oper, func_bits, in_out); + } + } + + ast::expr_if(cond, ref then, els) => { + // + // (cond) + // | + // v + // ( ) + // / \ + // | | + // v v + // (then)(els) + // | | + // v v + // ( succ ) + // + self.walk_expr(cond, in_out, loop_scopes); + + let mut then_bits = reslice(in_out).to_vec(); + self.walk_block(then, then_bits, loop_scopes); + + self.walk_opt_expr(els, in_out, loop_scopes); + join_bits(&self.dfcx.oper, then_bits, in_out); + } + + ast::expr_while(cond, ref blk) => { + // + // (expr) <--+ + // | | + // v | + // +--(cond) | + // | | | + // | v | + // v (blk) ----+ + // | + // <--+ (break) + // + + self.walk_expr(cond, in_out, loop_scopes); + + let mut body_bits = reslice(in_out).to_vec(); + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: TrueLoop, + break_bits: reslice(in_out).to_vec() + }); + self.walk_block(blk, body_bits, loop_scopes); + self.add_to_entry_set(expr.id, body_bits); + let new_loop_scope = loop_scopes.pop(); + copy_bits(new_loop_scope.break_bits, in_out); + } + + ast::expr_loop(ref blk, _) => { + // + // (expr) <--+ + // | | + // v | + // (blk) ----+ + // | + // <--+ (break) + // + + let mut body_bits = reslice(in_out).to_vec(); + self.reset(in_out); + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: TrueLoop, + break_bits: reslice(in_out).to_vec() + }); + self.walk_block(blk, body_bits, loop_scopes); + self.add_to_entry_set(expr.id, body_bits); + + let new_loop_scope = loop_scopes.pop(); + assert_eq!(new_loop_scope.loop_id, expr.id); + copy_bits(new_loop_scope.break_bits, in_out); + } + + ast::expr_match(discr, ref arms) => { + // + // (discr) + // / | \ + // | | | + // v v v + // (..arms..) + // | | | + // v v v + // ( succ ) + // + // + self.walk_expr(discr, in_out, loop_scopes); + + let mut guards = reslice(in_out).to_vec(); + + // We know that exactly one arm will be taken, so we + // can start out with a blank slate and just union + // together the bits from each arm: + self.reset(in_out); + + for arms.each |arm| { + // in_out reflects the discr and all guards to date + self.walk_opt_expr(arm.guard, guards, loop_scopes); + + // determine the bits for the body and then union + // them into `in_out`, which reflects all bodies to date + let mut body = reslice(guards).to_vec(); + self.walk_pat_alternatives(arm.pats, body, loop_scopes); + self.walk_block(&arm.body, body, loop_scopes); + join_bits(&self.dfcx.oper, body, in_out); + } + } + + ast::expr_ret(o_e) => { + self.walk_opt_expr(o_e, in_out, loop_scopes); + + // is this a return from a `for`-loop closure? + match loop_scopes.position(|s| s.loop_kind == ForLoop) { + Some(i) => { + // if so, add the in_out bits to the state + // upon exit. Remember that we cannot count + // upon the `for` loop function not to invoke + // the closure again etc. + self.break_from_to(expr, &mut loop_scopes[i], in_out); + } + + None => {} + } + + self.reset(in_out); + } + + ast::expr_break(label) => { + let scope = self.find_scope(expr, label, loop_scopes); + self.break_from_to(expr, scope, in_out); + self.reset(in_out); + } + + ast::expr_again(label) => { + let scope = self.find_scope(expr, label, loop_scopes); + + match scope.loop_kind { + TrueLoop => { + self.pop_scopes(expr, scope, in_out); + self.add_to_entry_set(scope.loop_id, reslice(in_out)); + } + + ForLoop => { + // If this `loop` construct is looping back to a `for` + // loop, then `loop` is really just a return from the + // closure. Therefore, we treat it the same as `break`. + // See case for `expr_fn_block` for more details. + self.break_from_to(expr, scope, in_out); + } + } + + self.reset(in_out); + } + + ast::expr_assign(l, r) | + ast::expr_assign_op(_, l, r) => { + self.walk_expr(r, in_out, loop_scopes); + self.walk_expr(l, in_out, loop_scopes); + } + + ast::expr_vec(ref exprs, _) => { + self.walk_exprs(*exprs, in_out, loop_scopes) + } + + ast::expr_repeat(l, r, _) => { + self.walk_expr(l, in_out, loop_scopes); + self.walk_expr(r, in_out, loop_scopes); + } + + ast::expr_struct(_, ref fields, with_expr) => { + self.walk_opt_expr(with_expr, in_out, loop_scopes); + for fields.each |field| { + self.walk_expr(field.node.expr, in_out, loop_scopes); + } + } + + ast::expr_call(f, ref args, _) => { + self.walk_call(expr.callee_id, expr.id, + f, *args, in_out, loop_scopes); + } + + ast::expr_method_call(rcvr, _, _, ref args, _) => { + self.walk_call(expr.callee_id, expr.id, + rcvr, *args, in_out, loop_scopes); + } + + ast::expr_index(l, r) | + ast::expr_binary(_, l, r) if self.is_method_call(expr) => { + self.walk_call(expr.callee_id, expr.id, + l, [r], in_out, loop_scopes); + } + + ast::expr_unary(_, e) if self.is_method_call(expr) => { + self.walk_call(expr.callee_id, expr.id, + e, [], in_out, loop_scopes); + } + + ast::expr_tup(ref exprs) => { + self.walk_exprs(*exprs, in_out, loop_scopes); + } + + ast::expr_binary(op, l, r) if ast_util::lazy_binop(op) => { + self.walk_expr(l, in_out, loop_scopes); + let temp = reslice(in_out).to_vec(); + self.walk_expr(r, in_out, loop_scopes); + join_bits(&self.dfcx.oper, temp, in_out); + } + + ast::expr_log(l, r) | + ast::expr_index(l, r) | + ast::expr_binary(_, l, r) => { + self.walk_exprs([l, r], in_out, loop_scopes); + } + + ast::expr_lit(*) | + ast::expr_path(*) | + ast::expr_self => { + } + + ast::expr_addr_of(_, e) | + ast::expr_copy(e) | + ast::expr_loop_body(e) | + ast::expr_do_body(e) | + ast::expr_cast(e, _) | + ast::expr_unary(_, e) | + ast::expr_paren(e) | + ast::expr_vstore(e, _) | + ast::expr_field(e, _, _) => { + self.walk_expr(e, in_out, loop_scopes); + } + + ast::expr_inline_asm(ref inline_asm) => { + for inline_asm.inputs.each |&(_, expr)| { + self.walk_expr(expr, in_out, loop_scopes); + } + for inline_asm.outputs.each |&(_, expr)| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + ast::expr_block(ref blk) => { + self.walk_block(blk, in_out, loop_scopes); + } + + ast::expr_mac(*) => { + self.tcx().sess.span_bug(expr.span, ~"unexpanded macro"); + } + } + + self.dfcx.apply_gen_kill(expr.id, in_out); + } + + fn pop_scopes(&mut self, + from_expr: @ast::expr, + to_scope: &mut LoopScope, + in_out: &mut [uint]) { + //! Whenever you have a `break` or a `loop` statement, flow + //! exits through any number of enclosing scopes on its + //! way to the new destination. This function applies the kill + //! sets of those enclosing scopes to `in_out` (those kill sets + //! concern items that are going out of scope). + + let tcx = self.tcx(); + let region_maps = tcx.region_maps; + + debug!("pop_scopes(from_expr=%s, to_scope=%?, in_out=%s)", + from_expr.repr(tcx), to_scope.loop_id, + bits_to_str(reslice(in_out))); + + let mut id = from_expr.id; + while id != to_scope.loop_id { + self.dfcx.apply_kill(id, in_out); + + match region_maps.opt_encl_scope(id) { + Some(i) => { id = i; } + None => { + tcx.sess.span_bug( + from_expr.span, + fmt!("pop_scopes(from_expr=%s, to_scope=%?) \ + to_scope does not enclose from_expr", + from_expr.repr(tcx), to_scope.loop_id)); + } + } + } + } + + fn break_from_to(&mut self, + from_expr: @ast::expr, + to_scope: &mut LoopScope, + in_out: &mut [uint]) { + self.pop_scopes(from_expr, to_scope, in_out); + self.dfcx.apply_kill(from_expr.id, in_out); + join_bits(&self.dfcx.oper, reslice(in_out), to_scope.break_bits); + debug!("break_from_to(from_expr=%s, to_scope=%?) final break_bits=%s", + from_expr.repr(self.tcx()), + to_scope.loop_id, + bits_to_str(reslice(in_out))); + } + + fn walk_exprs(&mut self, + exprs: &[@ast::expr], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + for exprs.each |&expr| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + fn walk_opt_expr(&mut self, + opt_expr: Option<@ast::expr>, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + for opt_expr.each |&expr| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + fn walk_call(&mut self, + _callee_id: ast::node_id, + call_id: ast::node_id, + arg0: @ast::expr, + args: &[@ast::expr], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + self.walk_expr(arg0, in_out, loop_scopes); + self.walk_exprs(args, in_out, loop_scopes); + + // FIXME(#6268) nested method calls + // self.merge_with_entry_set(callee_id, in_out); + // self.dfcx.apply_gen_kill(callee_id, in_out); + + let return_ty = ty::node_id_to_type(self.tcx(), call_id); + let fails = ty::type_is_bot(return_ty); + if fails { + self.reset(in_out); + } + } + + fn walk_pat(&mut self, + pat: @ast::pat, + in_out: &mut [uint], + _loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_pat(pat=%s, in_out=%s)", + pat.repr(self.dfcx.tcx), bits_to_str(reslice(in_out))); + + do ast_util::walk_pat(pat) |p| { + debug!(" p.id=%? in_out=%s", p.id, bits_to_str(reslice(in_out))); + self.merge_with_entry_set(p.id, in_out); + self.dfcx.apply_gen_kill(p.id, in_out); + } + } + + fn walk_pat_alternatives(&mut self, + pats: &[@ast::pat], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + if pats.len() == 1 { + // Common special case: + return self.walk_pat(pats[0], in_out, loop_scopes); + } + + // In the general case, the patterns in `pats` are + // alternatives, so we must treat this like an N-way select + // statement. + let initial_state = reslice(in_out).to_vec(); + for pats.each |&pat| { + let mut temp = copy initial_state; + self.walk_pat(pat, temp, loop_scopes); + join_bits(&self.dfcx.oper, temp, in_out); + } + } + + fn find_scope<'a>(&self, + expr: @ast::expr, + label: Option, + loop_scopes: &'a mut ~[LoopScope]) -> &'a mut LoopScope { + let index = match label { + None => { + let len = loop_scopes.len(); + len - 1 + } + + Some(_) => { + match self.tcx().def_map.find(&expr.id) { + Some(&ast::def_label(loop_id)) => { + match loop_scopes.position(|l| l.loop_id == loop_id) { + Some(i) => i, + None => { + self.tcx().sess.span_bug( + expr.span, + fmt!("No loop scope for id %?", loop_id)); + } + } + } + + r => { + self.tcx().sess.span_bug( + expr.span, + fmt!("Bad entry `%?` in def_map for label", r)); + } + } + } + }; + + &mut loop_scopes[index] + } + + fn is_method_call(&self, expr: @ast::expr) -> bool { + self.dfcx.method_map.contains_key(&expr.id) + } + + fn reset(&mut self, bits: &mut [uint]) { + let e = if self.dfcx.oper.initial_value() {uint::max_value} else {0}; + for vec::each_mut(bits) |b| { *b = e; } + } + + fn add_to_entry_set(&mut self, id: ast::node_id, pred_bits: &[uint]) { + debug!("add_to_entry_set(id=%?, pred_bits=%s)", + 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); + join_bits(&self.dfcx.oper, pred_bits, on_entry) + }; + if changed { + debug!("changed entry set for %? to %s", + id, bits_to_str(self.dfcx.on_entry.slice(start, end))); + self.changed = true; + } + } + + fn merge_with_entry_set(&mut self, + id: ast::node_id, + pred_bits: &mut [uint]) { + debug!("merge_with_entry_set(id=%?, pred_bits=%s)", + 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 changed = join_bits(&self.dfcx.oper, reslice(pred_bits), on_entry); + copy_bits(reslice(on_entry), pred_bits); + changed + }; + if changed { + debug!("changed entry set for %? to %s", + id, bits_to_str(self.dfcx.on_entry.slice(start, end))); + self.changed = true; + } + } +} + +fn mut_bits_to_str(words: &mut [uint]) -> ~str { + bits_to_str(reslice(words)) +} + +fn bits_to_str(words: &[uint]) -> ~str { + let mut result = ~""; + let mut sep = '['; + + // Note: this is a little endian printout of bytes. + + for words.each |&word| { + let mut v = word; + for uint::range(0, uint::bytes) |_| { + str::push_char(&mut result, sep); + str::push_str(&mut result, fmt!("%02x", v & 0xFF)); + v >>= 8; + sep = '-'; + } + } + str::push_char(&mut result, ']'); + return result; +} + +fn copy_bits(in_vec: &[uint], out_vec: &mut [uint]) -> bool { + bitwise(out_vec, in_vec, |_, b| b) +} + +fn join_bits(oper: &O, + in_vec: &[uint], + out_vec: &mut [uint]) -> bool { + bitwise(out_vec, in_vec, |a, b| oper.join(a, b)) +} + +#[inline(always)] +fn bitwise(out_vec: &mut [uint], + in_vec: &[uint], + op: &fn(uint, uint) -> uint) -> bool { + assert_eq!(out_vec.len(), in_vec.len()); + let mut changed = false; + for uint::range(0, out_vec.len()) |i| { + let old_val = out_vec[i]; + let new_val = op(old_val, in_vec[i]); + out_vec[i] = new_val; + changed |= (old_val != new_val); + } + return changed; +} + +fn set_bit(words: &mut [uint], bit: uint) -> bool { + debug!("set_bit: words=%s bit=%s", + mut_bits_to_str(words), bit_str(bit)); + let word = bit / uint::bits; + let bit_in_word = bit % uint::bits; + let bit_mask = 1 << bit_in_word; + debug!("word=%u bit_in_word=%u bit_mask=%u", word, bit_in_word, word); + let oldv = words[word]; + let newv = oldv | bit_mask; + words[word] = newv; + oldv != newv +} + +fn bit_str(bit: uint) -> ~str { + let byte = bit >> 8; + let lobits = 1 << (bit & 0xFF); + fmt!("[%u:%u-%02x]", bit, byte, lobits) +} + +fn reslice<'a>(v: &'a mut [uint]) -> &'a [uint] { + // bFIXME(#5074) this function should not be necessary at all + unsafe { + cast::transmute(v) + } +} + diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs new file mode 100644 index 0000000000000..9ffd0e6f22c3c --- /dev/null +++ b/src/librustc/middle/entry.rs @@ -0,0 +1,150 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use driver::session; +use driver::session::Session; +use syntax::parse::token::special_idents; +use syntax::ast::{crate, node_id, item, item_fn}; +use syntax::codemap::span; +use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item}; +use syntax::attr::{attrs_contains_name}; +use syntax::ast_map; +use core::util; + +struct EntryContext { + session: Session, + + ast_map: ast_map::map, + + // The top-level function called 'main' + main_fn: Option<(node_id, span)>, + + // The function that has attribute named 'main' + attr_main_fn: Option<(node_id, span)>, + + // The function that has the attribute 'start' on it + start_fn: Option<(node_id, span)>, + + // The functions that one might think are 'main' but aren't, e.g. + // main functions not defined at the top level. For diagnostics. + non_main_fns: ~[(node_id, span)], +} + +type EntryVisitor = vt<@mut EntryContext>; + +pub fn find_entry_point(session: Session, crate: @crate, ast_map: ast_map::map) { + + // FIXME #4404 android JNI hacks + if *session.building_library && + session.targ_cfg.os != session::os_android { + // No need to find a main function + return; + } + + let ctxt = @mut EntryContext { + session: session, + ast_map: ast_map, + main_fn: None, + attr_main_fn: None, + start_fn: None, + non_main_fns: ~[], + }; + + visit_crate(crate, ctxt, mk_vt(@Visitor { + visit_item: |item, ctxt, visitor| find_item(item, ctxt, visitor), + .. *default_visitor() + })); + + configure_main(ctxt); +} + +fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) { + match item.node { + item_fn(*) => { + if item.ident == special_idents::main { + match ctxt.ast_map.find(&item.id) { + Some(&ast_map::node_item(_, path)) => { + if path.len() == 0 { + // This is a top-level function so can be 'main' + if ctxt.main_fn.is_none() { + ctxt.main_fn = Some((item.id, item.span)); + } else { + ctxt.session.span_err( + item.span, + ~"multiple 'main' functions"); + } + } else { + // This isn't main + ctxt.non_main_fns.push((item.id, item.span)); + } + } + _ => util::unreachable() + } + } + + if attrs_contains_name(item.attrs, ~"main") { + if ctxt.attr_main_fn.is_none() { + ctxt.attr_main_fn = Some((item.id, item.span)); + } else { + ctxt.session.span_err( + item.span, + ~"multiple 'main' functions"); + } + } + + if attrs_contains_name(item.attrs, ~"start") { + if ctxt.start_fn.is_none() { + ctxt.start_fn = Some((item.id, item.span)); + } else { + ctxt.session.span_err( + item.span, + ~"multiple 'start' functions"); + } + } + } + _ => () + } + + visit_item(item, ctxt, visitor); +} + +fn configure_main(ctxt: @mut EntryContext) { + let this = &mut *ctxt; + if this.start_fn.is_some() { + *this.session.entry_fn = this.start_fn; + *this.session.entry_type = Some(session::EntryStart); + } else if this.attr_main_fn.is_some() { + *this.session.entry_fn = this.attr_main_fn; + *this.session.entry_type = Some(session::EntryMain); + } else if this.main_fn.is_some() { + *this.session.entry_fn = this.main_fn; + *this.session.entry_type = Some(session::EntryMain); + } else { + if !*this.session.building_library { + // No main function + this.session.err(~"main function not found"); + if !this.non_main_fns.is_empty() { + // There were some functions named 'main' though. Try to give the user a hint. + this.session.note(~"the main function must be defined at the crate level \ + but you have one or more functions named 'main' that are not \ + defined at the crate level. Either move the definition or \ + attach the `#[main]` attribute to override this behavior."); + for this.non_main_fns.each |&(_, span)| { + this.session.span_note(span, ~"here is a function named 'main'"); + } + } + this.session.abort_if_errors(); + } else { + // If we *are* building a library, then we're on android where we still might + // optionally want to translate main $4404 + assert!(this.session.targ_cfg.os == session::os_android); + } + } +} diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 4c8d36f93f4b2..98cc8cc014fb6 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -45,7 +45,7 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk) |expr, depth, v| { match expr.node { ast::expr_fn_block(*) => visit::visit_expr(expr, depth + 1, v), - ast::expr_path(*) => { + ast::expr_path(*) | ast::expr_self => { let mut i = 0; match def_map.find(&expr.id) { None => fail!(~"path not found"), @@ -119,11 +119,3 @@ pub fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info { pub fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool { return vec::len(*get_freevars(tcx, fid)) != 0u; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index cf488b0ac8939..f8f6dbd82595e 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -10,11 +10,11 @@ use middle::freevars::freevar_entry; use middle::freevars; -use middle::liveness; use middle::pat_util; use middle::ty; use middle::typeck; use util::ppaux::{Repr, ty_to_str}; +use util::ppaux::UserString; use syntax::ast::*; use syntax::attr::attrs_contains_name; @@ -56,19 +56,16 @@ pub static try_adding: &'static str = "Try adding a move"; pub struct Context { tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map, - current_item: node_id, + current_item: node_id } pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map, crate: @crate) { let ctx = Context { tcx: tcx, method_map: method_map, - last_use_map: last_use_map, - current_item: -1, + current_item: -1 }; let visit = visit::mk_vt(@visit::Visitor { visit_arm: check_arm, @@ -97,21 +94,21 @@ fn check_struct_safe_for_destructor(cx: Context, }); if !ty::type_is_owned(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 struct \ + that is not Owned"); cx.tcx.sess.span_note(span, - ~"use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + "use \"#[unsafe_destructor]\" on the \ + implementation to force the compiler to \ + allow this"); } } else { cx.tcx.sess.span_err(span, - ~"cannot implement a destructor on a struct \ - with type parameters"); + "cannot implement a destructor on a struct \ + with type parameters"); cx.tcx.sess.span_note(span, - ~"use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + "use \"#[unsafe_destructor]\" on the \ + implementation to force the compiler to \ + allow this"); } } @@ -132,7 +129,7 @@ fn check_item(item: @item, cx: Context, visitor: visit::vt) { // Yes, it's a destructor. match self_type.node { ty_path(_, path_node_id) => { - let struct_def = *cx.tcx.def_map.get( + let struct_def = cx.tcx.def_map.get_copy( &path_node_id); let struct_did = ast_util::def_id_of_def(struct_def); @@ -143,27 +140,16 @@ fn check_item(item: @item, cx: Context, visitor: visit::vt) { } _ => { cx.tcx.sess.span_bug(self_type.span, - ~"the self type for \ - the Drop trait \ - impl is not a \ - path"); + "the self type for \ + the Drop trait \ + impl is not a \ + path"); } } } } } } - item_struct(struct_def, _) => { - match struct_def.dtor { - None => {} - Some(ref dtor) => { - let struct_did = def_id { crate: 0, node: item.id }; - check_struct_safe_for_destructor(cx, - dtor.span, - struct_did); - } - } - } _ => {} } } @@ -204,7 +190,7 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) { fn check_for_bare(cx: Context, fv: @freevar_entry) { cx.tcx.sess.span_err( fv.span, - ~"attempted dynamic environment capture"); + "attempted dynamic environment capture"); } let fty = ty::node_id_to_type(cx.tcx, id); @@ -250,7 +236,7 @@ fn check_fn( } fn check_arm(a: &arm, cx: Context, v: visit::vt) { - for vec::each(a.pats) |p| { + for a.pats.each |p| { do pat_util::pat_bindings(cx.tcx.def_map, *p) |mode, id, span, _pth| { if mode == bind_by_copy { let t = ty::node_id_to_type(cx.tcx, id); @@ -272,11 +258,9 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { _ => e.id }; for cx.tcx.node_type_substs.find(&type_parameter_id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = /*bad*/ copy **ts; let type_param_defs = match e.node { expr_path(_) => { - let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&e.id)); + let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&e.id)); ty::lookup_item_type(cx.tcx, did).generics.type_param_defs } _ => { @@ -297,7 +281,7 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { ts.repr(cx.tcx), type_param_defs.repr(cx.tcx))); } - for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + for vec::each2(**ts, *type_param_defs) |&ty, type_param_def| { check_bounds(cx, type_parameter_id, e.span, ty, type_param_def) } } @@ -335,12 +319,10 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { match aty.node { ty_path(_, id) => { for cx.tcx.node_type_substs.find(&id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = /*bad*/ copy **ts; - let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&id)); + let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); let type_param_defs = ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; - for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + for vec::each2(**ts, *type_param_defs) |&ty, type_param_def| { check_bounds(cx, aty.id, aty.span, ty, type_param_def) } } @@ -357,53 +339,26 @@ pub fn check_bounds(cx: Context, type_param_def: &ty::TypeParameterDef) { let kind = ty::type_contents(cx.tcx, ty); - let mut missing = ~[]; - for type_param_def.bounds.each |bound| { - match *bound { - ty::bound_trait(_) => { - /* Not our job, checking in typeck */ - } - - ty::bound_copy => { - if !kind.is_copy(cx.tcx) { - missing.push("Copy"); - } - } - - ty::bound_durable => { - if !kind.is_durable(cx.tcx) { - missing.push("'static"); - } - } - - ty::bound_owned => { - if !kind.is_owned(cx.tcx) { - missing.push("Owned"); - } - } - - ty::bound_const => { - if !kind.is_const(cx.tcx) { - missing.push("Const"); - } - } + let mut missing = ty::EmptyBuiltinBounds(); + for type_param_def.bounds.builtin_bounds.each |bound| { + if !kind.meets_bound(cx.tcx, bound) { + missing.add(bound); } } - if !missing.is_empty() { cx.tcx.sess.span_err( sp, fmt!("instantiating a type parameter with an incompatible type \ `%s`, which does not fulfill `%s`", ty_to_str(cx.tcx, ty), - str::connect_slices(missing, " "))); + missing.user_string(cx.tcx))); } } fn is_nullary_variant(cx: Context, ex: @expr) -> bool { match ex.node { expr_path(_) => { - match *cx.tcx.def_map.get(&ex.id) { + match cx.tcx.def_map.get_copy(&ex.id) { def_variant(edid, vdid) => { vec::len(ty::enum_variant_with_id(cx.tcx, edid, vdid).args) == 0u } @@ -420,7 +375,7 @@ fn check_imm_free_var(cx: Context, def: def, sp: span) { if is_mutbl { cx.tcx.sess.span_err( sp, - ~"mutable variables cannot be implicitly captured"); + "mutable variables cannot be implicitly captured"); } } def_arg(*) => { /* ok */ } @@ -459,15 +414,15 @@ pub fn check_owned(cx: Context, ty: ty::t, sp: span) -> bool { // note: also used from middle::typeck::regionck! pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { - if !ty::type_is_durable(tcx, ty) { + if !ty::type_is_static(tcx, ty) { match ty::get(ty).sty { ty::ty_param(*) => { - tcx.sess.span_err(sp, ~"value may contain borrowed \ - pointers; use `'static` bound"); + tcx.sess.span_err(sp, "value may contain borrowed \ + pointers; use `'static` bound"); } _ => { - tcx.sess.span_err(sp, ~"value may contain borrowed \ - pointers"); + tcx.sess.span_err(sp, "value may contain borrowed \ + pointers"); } } false @@ -592,19 +547,9 @@ pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) { if !ty::type_is_owned(cx.tcx, source_ty) { cx.tcx.sess.span_err( target.span, - ~"uniquely-owned trait objects must be sendable"); + "uniquely-owned trait objects must be sendable"); } } _ => {} // Nothing to do. } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 2de12b9eb9746..e2b4684696a90 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -28,63 +28,65 @@ use syntax::ast_util::local_def; use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor}; use syntax::visit::visit_crate; -use core::cast::transmute; use core::hashmap::HashMap; pub enum LangItem { ConstTraitLangItem, // 0 CopyTraitLangItem, // 1 OwnedTraitLangItem, // 2 - DurableTraitLangItem, // 3 - - DropTraitLangItem, // 4 - - AddTraitLangItem, // 5 - SubTraitLangItem, // 6 - MulTraitLangItem, // 7 - QuotTraitLangItem, // 8 - RemTraitLangItem, // 9 - NegTraitLangItem, // 10 - NotTraitLangItem, // 11 - BitXorTraitLangItem, // 12 - BitAndTraitLangItem, // 13 - BitOrTraitLangItem, // 14 - ShlTraitLangItem, // 15 - ShrTraitLangItem, // 16 - IndexTraitLangItem, // 17 - - EqTraitLangItem, // 18 - OrdTraitLangItem, // 19 - - StrEqFnLangItem, // 20 - UniqStrEqFnLangItem, // 21 - AnnihilateFnLangItem, // 22 - LogTypeFnLangItem, // 23 - FailFnLangItem, // 24 - FailBoundsCheckFnLangItem, // 25 - ExchangeMallocFnLangItem, // 26 - ExchangeFreeFnLangItem, // 27 - MallocFnLangItem, // 28 - FreeFnLangItem, // 29 - BorrowAsImmFnLangItem, // 30 + + DropTraitLangItem, // 3 + + AddTraitLangItem, // 4 + SubTraitLangItem, // 5 + MulTraitLangItem, // 6 + DivTraitLangItem, // 7 + RemTraitLangItem, // 8 + NegTraitLangItem, // 9 + NotTraitLangItem, // 10 + BitXorTraitLangItem, // 11 + BitAndTraitLangItem, // 12 + BitOrTraitLangItem, // 13 + ShlTraitLangItem, // 14 + ShrTraitLangItem, // 15 + IndexTraitLangItem, // 16 + + EqTraitLangItem, // 17 + OrdTraitLangItem, // 18 + + StrEqFnLangItem, // 19 + UniqStrEqFnLangItem, // 20 + AnnihilateFnLangItem, // 21 + LogTypeFnLangItem, // 22 + FailFnLangItem, // 23 + FailBoundsCheckFnLangItem, // 24 + ExchangeMallocFnLangItem, // 25 + ExchangeFreeFnLangItem, // 26 + MallocFnLangItem, // 27 + FreeFnLangItem, // 28 + BorrowAsImmFnLangItem, // 29 + BorrowAsMutFnLangItem, // 30 ReturnToMutFnLangItem, // 31 CheckNotBorrowedFnLangItem, // 32 StrDupUniqFnLangItem, // 33 + RecordBorrowFnLangItem, // 34 + UnrecordBorrowFnLangItem, // 35 - StartFnLangItem, // 34 + StartFnLangItem, // 36 } pub struct LanguageItems { - items: [Option, ..35] + items: [Option, ..37] } pub impl LanguageItems { pub fn new() -> LanguageItems { LanguageItems { - items: [ None, ..35 ] + items: [ None, ..37 ] } } + #[cfg(stage0)] fn each_item(&self, f: &fn(def_id: def_id, i: uint) -> bool) { for self.items.eachi |i, &item| { if !f(item.get(), i) { @@ -92,48 +94,54 @@ pub impl LanguageItems { } } } + #[cfg(not(stage0))] + fn each_item(&self, f: &fn(def_id: def_id, i: uint) -> bool) -> bool { + self.items.eachi(|i, &item| f(item.get(), i)) + } pub fn item_name(index: uint) -> &'static str { match index { 0 => "const", 1 => "copy", 2 => "owned", - 3 => "durable", - - 4 => "drop", - - 5 => "add", - 6 => "sub", - 7 => "mul", - 8 => "quot", - 9 => "rem", - 10 => "neg", - 11 => "not", - 12 => "bitxor", - 13 => "bitand", - 14 => "bitor", - 15 => "shl", - 16 => "shr", - 17 => "index", - 18 => "eq", - 19 => "ord", - - 20 => "str_eq", - 21 => "uniq_str_eq", - 22 => "annihilate", - 23 => "log_type", - 24 => "fail_", - 25 => "fail_bounds_check", - 26 => "exchange_malloc", - 27 => "exchange_free", - 28 => "malloc", - 29 => "free", - 30 => "borrow_as_imm", + + 3 => "drop", + + 4 => "add", + 5 => "sub", + 6 => "mul", + 7 => "div", + 8 => "rem", + 9 => "neg", + 10 => "not", + 11 => "bitxor", + 12 => "bitand", + 13 => "bitor", + 14 => "shl", + 15 => "shr", + 16 => "index", + 17 => "eq", + 18 => "ord", + + 19 => "str_eq", + 20 => "uniq_str_eq", + 21 => "annihilate", + 22 => "log_type", + 23 => "fail_", + 24 => "fail_bounds_check", + 25 => "exchange_malloc", + 26 => "exchange_free", + 27 => "malloc", + 28 => "free", + 29 => "borrow_as_imm", + 30 => "borrow_as_mut", 31 => "return_to_mut", 32 => "check_not_borrowed", 33 => "strdup_uniq", + 34 => "record_borrow", + 35 => "unrecord_borrow", - 34 => "start", + 36 => "start", _ => "???" } @@ -150,9 +158,6 @@ pub impl LanguageItems { pub fn owned_trait(&const self) -> def_id { self.items[OwnedTraitLangItem as uint].get() } - pub fn durable_trait(&const self) -> def_id { - self.items[DurableTraitLangItem as uint].get() - } pub fn drop_trait(&const self) -> def_id { self.items[DropTraitLangItem as uint].get() @@ -167,8 +172,8 @@ pub impl LanguageItems { pub fn mul_trait(&const self) -> def_id { self.items[MulTraitLangItem as uint].get() } - pub fn quot_trait(&const self) -> def_id { - self.items[QuotTraitLangItem as uint].get() + pub fn div_trait(&const self) -> def_id { + self.items[DivTraitLangItem as uint].get() } pub fn rem_trait(&const self) -> def_id { self.items[RemTraitLangItem as uint].get() @@ -238,6 +243,9 @@ pub impl LanguageItems { pub fn borrow_as_imm_fn(&const self) -> def_id { self.items[BorrowAsImmFnLangItem as uint].get() } + pub fn borrow_as_mut_fn(&const self) -> def_id { + self.items[BorrowAsMutFnLangItem as uint].get() + } pub fn return_to_mut_fn(&const self) -> def_id { self.items[ReturnToMutFnLangItem as uint].get() } @@ -247,28 +255,32 @@ pub impl LanguageItems { pub fn strdup_uniq_fn(&const self) -> def_id { self.items[StrDupUniqFnLangItem as uint].get() } + pub fn record_borrow_fn(&const self) -> def_id { + self.items[RecordBorrowFnLangItem as uint].get() + } + pub fn unrecord_borrow_fn(&const self) -> def_id { + self.items[UnrecordBorrowFnLangItem as uint].get() + } pub fn start_fn(&const self) -> def_id { self.items[StartFnLangItem as uint].get() } } -fn LanguageItemCollector<'r>(crate: @crate, - session: Session, - items: &'r mut LanguageItems) - -> LanguageItemCollector<'r> { +fn LanguageItemCollector(crate: @crate, + session: Session) + -> LanguageItemCollector { let mut item_refs = HashMap::new(); item_refs.insert(@~"const", ConstTraitLangItem as uint); item_refs.insert(@~"copy", CopyTraitLangItem as uint); item_refs.insert(@~"owned", OwnedTraitLangItem as uint); - item_refs.insert(@~"durable", DurableTraitLangItem as uint); item_refs.insert(@~"drop", DropTraitLangItem as uint); item_refs.insert(@~"add", AddTraitLangItem as uint); item_refs.insert(@~"sub", SubTraitLangItem as uint); item_refs.insert(@~"mul", MulTraitLangItem as uint); - item_refs.insert(@~"quot", QuotTraitLangItem as uint); + item_refs.insert(@~"div", DivTraitLangItem as uint); item_refs.insert(@~"rem", RemTraitLangItem as uint); item_refs.insert(@~"neg", NegTraitLangItem as uint); item_refs.insert(@~"not", NotTraitLangItem as uint); @@ -294,22 +306,25 @@ fn LanguageItemCollector<'r>(crate: @crate, item_refs.insert(@~"malloc", MallocFnLangItem as uint); item_refs.insert(@~"free", FreeFnLangItem as uint); item_refs.insert(@~"borrow_as_imm", BorrowAsImmFnLangItem as uint); + item_refs.insert(@~"borrow_as_mut", BorrowAsMutFnLangItem as uint); item_refs.insert(@~"return_to_mut", ReturnToMutFnLangItem as uint); item_refs.insert(@~"check_not_borrowed", CheckNotBorrowedFnLangItem as uint); item_refs.insert(@~"strdup_uniq", StrDupUniqFnLangItem as uint); + item_refs.insert(@~"record_borrow", RecordBorrowFnLangItem as uint); + item_refs.insert(@~"unrecord_borrow", UnrecordBorrowFnLangItem as uint); item_refs.insert(@~"start", StartFnLangItem as uint); LanguageItemCollector { crate: crate, session: session, - items: items, + items: LanguageItems::new(), item_refs: item_refs } } -struct LanguageItemCollector<'self> { - items: &'self mut LanguageItems, +struct LanguageItemCollector { + items: LanguageItems, crate: @crate, session: Session, @@ -317,8 +332,8 @@ struct LanguageItemCollector<'self> { item_refs: HashMap<@~str, uint>, } -pub impl<'self> LanguageItemCollector<'self> { - fn match_and_collect_meta_item(&self, item_def_id: def_id, +pub impl LanguageItemCollector { + fn match_and_collect_meta_item(&mut self, item_def_id: def_id, meta_item: @meta_item) { match meta_item.node { meta_name_value(key, literal) => { @@ -333,7 +348,7 @@ pub impl<'self> LanguageItemCollector<'self> { } } - fn collect_item(&self, item_index: uint, item_def_id: def_id) { + fn collect_item(&mut self, item_index: uint, item_def_id: def_id) { // Check for duplicates. match self.items.items[item_index] { Some(original_def_id) if original_def_id != item_def_id => { @@ -349,42 +364,45 @@ pub impl<'self> LanguageItemCollector<'self> { self.items.items[item_index] = Some(item_def_id); } - fn match_and_collect_item(&self, + fn match_and_collect_item(&mut self, item_def_id: def_id, key: @~str, value: @~str) { if *key != ~"lang" { return; // Didn't match. } - match self.item_refs.find(&value) { + let item_index = self.item_refs.find(&value).map(|x| **x); + // prevent borrow checker from considering ^~~~~~~~~~~ + // self to be borrowed (annoying) + + match item_index { + Some(item_index) => { + self.collect_item(item_index, item_def_id); + } None => { // Didn't match. - } - Some(&item_index) => { - self.collect_item(item_index, item_def_id) + return; } } } - fn collect_local_language_items(&self) { - unsafe { - let this: *LanguageItemCollector<'self> = transmute(self); - visit_crate(self.crate, (), mk_simple_visitor(@SimpleVisitor { - visit_item: |item| { - for item.attrs.each |attribute| { - unsafe { - (*this).match_and_collect_meta_item( - local_def(item.id), - attribute.node.value - ); - } + fn collect_local_language_items(&mut self) { + let this: *mut LanguageItemCollector = &mut *self; + visit_crate(self.crate, (), mk_simple_visitor(@SimpleVisitor { + visit_item: |item| { + for item.attrs.each |attribute| { + unsafe { + (*this).match_and_collect_meta_item( + local_def(item.id), + attribute.node.value + ); } - }, - .. *default_simple_visitor() - })); - } + } + }, + .. *default_simple_visitor() + })); } - fn collect_external_language_items(&self) { + fn collect_external_language_items(&mut self) { let crate_store = self.session.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { for each_lang_item(crate_store, crate_number) @@ -408,7 +426,7 @@ pub impl<'self> LanguageItemCollector<'self> { } } - fn collect(&self) { + fn collect(&mut self) { self.collect_local_language_items(); self.collect_external_language_items(); self.check_completeness(); @@ -418,9 +436,8 @@ pub impl<'self> LanguageItemCollector<'self> { pub fn collect_language_items(crate: @crate, session: Session) -> LanguageItems { - let mut items = LanguageItems::new(); - let collector = LanguageItemCollector(crate, session, &mut items); + let mut collector = LanguageItemCollector(crate, session); collector.collect(); - copy items + let LanguageItemCollector { items, _ } = collector; + items } - diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index faf4b1c31061b..f7f5f0fe29c38 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -56,8 +56,6 @@ pub enum lint { non_camel_case_types, type_limits, default_methods, - deprecated_mutable_fields, - deprecated_drop, unused_unsafe, managed_heap_memory, @@ -91,167 +89,162 @@ struct LintSpec { pub type LintDict = @HashMap<~str, LintSpec>; +static lint_table: &'static [(&'static str, LintSpec)] = &[ + ("ctypes", + LintSpec { + lint: ctypes, + desc: "proper use of core::libc types in foreign modules", + default: warn + }), + + ("unused_imports", + LintSpec { + lint: unused_imports, + desc: "imports that are never used", + default: warn + }), + + ("while_true", + LintSpec { + lint: while_true, + desc: "suggest using loop { } instead of while(true) { }", + default: warn + }), + + ("path_statement", + LintSpec { + lint: path_statement, + desc: "path statements with no effect", + default: warn + }), + + ("unrecognized_lint", + LintSpec { + lint: unrecognized_lint, + desc: "unrecognized lint attribute", + default: warn + }), + + ("non_implicitly_copyable_typarams", + LintSpec { + lint: non_implicitly_copyable_typarams, + desc: "passing non implicitly copyable types as copy type params", + default: warn + }), + + ("vecs_implicitly_copyable", + LintSpec { + lint: vecs_implicitly_copyable, + desc: "make vecs and strs not implicitly copyable \ + (only checked at top level)", + default: warn + }), + + ("implicit_copies", + LintSpec { + lint: implicit_copies, + desc: "implicit copies of non implicitly copyable data", + default: warn + }), + + ("deprecated_pattern", + LintSpec { + lint: deprecated_pattern, + desc: "warn about deprecated uses of pattern bindings", + default: allow + }), + + ("non_camel_case_types", + LintSpec { + lint: non_camel_case_types, + desc: "types, variants and traits should have camel case names", + default: allow + }), + + ("managed_heap_memory", + LintSpec { + lint: managed_heap_memory, + desc: "use of managed (@ type) heap memory", + default: allow + }), + + ("owned_heap_memory", + LintSpec { + lint: owned_heap_memory, + desc: "use of owned (~ type) heap memory", + default: allow + }), + + ("heap_memory", + LintSpec { + lint: heap_memory, + desc: "use of any (~ type or @ type) heap memory", + default: allow + }), + + ("type_limits", + LintSpec { + lint: type_limits, + desc: "comparisons made useless by limits of the types involved", + default: warn + }), + + ("default_methods", + LintSpec { + lint: default_methods, + desc: "allow default methods", + default: deny + }), + + ("unused_unsafe", + LintSpec { + lint: unused_unsafe, + desc: "unnecessary use of an `unsafe` block", + default: warn + }), + + ("unused_variable", + LintSpec { + lint: unused_variable, + desc: "detect variables which are not used in any way", + default: warn + }), + + ("dead_assignment", + LintSpec { + lint: dead_assignment, + desc: "detect assignments that will never be read", + default: warn + }), + + ("unused_mut", + LintSpec { + lint: unused_mut, + desc: "detect mut variables which don't need to be mutable", + default: warn + }), +]; + /* Pass names should not contain a '-', as the compiler normalizes '-' to '_' in command-line flags */ pub fn get_lint_dict() -> LintDict { - let v = ~[ - (~"ctypes", - LintSpec { - lint: ctypes, - desc: "proper use of core::libc types in foreign modules", - default: warn - }), - - (~"unused_imports", - LintSpec { - lint: unused_imports, - desc: "imports that are never used", - default: warn - }), - - (~"while_true", - LintSpec { - lint: while_true, - desc: "suggest using loop { } instead of while(true) { }", - default: warn - }), - - (~"path_statement", - LintSpec { - lint: path_statement, - desc: "path statements with no effect", - default: warn - }), - - (~"unrecognized_lint", - LintSpec { - lint: unrecognized_lint, - desc: "unrecognized lint attribute", - default: warn - }), - - (~"non_implicitly_copyable_typarams", - LintSpec { - lint: non_implicitly_copyable_typarams, - desc: "passing non implicitly copyable types as copy type params", - default: warn - }), - - (~"vecs_implicitly_copyable", - LintSpec { - lint: vecs_implicitly_copyable, - desc: "make vecs and strs not implicitly copyable \ - (only checked at top level)", - default: warn - }), - - (~"implicit_copies", - LintSpec { - lint: implicit_copies, - desc: "implicit copies of non implicitly copyable data", - default: warn - }), - - (~"deprecated_pattern", - LintSpec { - lint: deprecated_pattern, - desc: "warn about deprecated uses of pattern bindings", - default: allow - }), - - (~"non_camel_case_types", - LintSpec { - lint: non_camel_case_types, - desc: "types, variants and traits should have camel case names", - default: allow - }), - - (~"managed_heap_memory", - LintSpec { - lint: managed_heap_memory, - desc: "use of managed (@ type) heap memory", - default: allow - }), - - (~"owned_heap_memory", - LintSpec { - lint: owned_heap_memory, - desc: "use of owned (~ type) heap memory", - default: allow - }), - - (~"heap_memory", - LintSpec { - lint: heap_memory, - desc: "use of any (~ type or @ type) heap memory", - default: allow - }), - - (~"type_limits", - LintSpec { - lint: type_limits, - desc: "comparisons made useless by limits of the types involved", - default: warn - }), - - (~"default_methods", - LintSpec { - lint: default_methods, - desc: "allow default methods", - default: deny - }), - - (~"deprecated_mutable_fields", - LintSpec { - lint: deprecated_mutable_fields, - desc: "deprecated mutable fields in structures", - default: deny - }), - - (~"deprecated_drop", - LintSpec { - lint: deprecated_drop, - desc: "deprecated \"drop\" notation for the destructor", - default: deny - }), - - (~"unused_unsafe", - LintSpec { - lint: unused_unsafe, - desc: "unnecessary use of an `unsafe` block", - default: warn - }), - - (~"unused_variable", - LintSpec { - lint: unused_variable, - desc: "detect variables which are not used in any way", - default: warn - }), - - (~"dead_assignment", - LintSpec { - lint: dead_assignment, - desc: "detect assignments that will never be read", - default: warn - }), - - (~"unused_mut", - LintSpec { - lint: unused_mut, - desc: "detect mut variables which don't need to be mutable", - default: warn - }), - ]; let mut map = HashMap::new(); - do vec::consume(v) |_, (k, v)| { - map.insert(k, v); + for lint_table.each|&(k, v)| { + map.insert(k.to_str(), v); } return @map; } +pub fn get_lint_name(lint_mode: lint) -> ~str { + for lint_table.each |&(name, spec)| { + if spec.lint == lint_mode { + return name.to_str(); + } + } + fail!(); +} // This is a highly not-optimal set of data structure decisions. type LintModes = @mut SmallIntMap; type LintModeMap = @mut HashMap; @@ -346,14 +339,14 @@ pub impl Context { _ => { self.sess.span_err( meta.span, - ~"malformed lint attribute"); + "malformed lint attribute"); } } } } _ => { self.sess.span_err(meta.span, - ~"malformed lint attribute"); + "malformed lint attribute"); } } } @@ -462,8 +455,6 @@ fn check_item(i: @ast::item, cx: ty::ctxt) { check_item_heap(cx, i); check_item_type_limits(cx, i); check_item_default_methods(cx, i); - check_item_deprecated_mutable_fields(cx, i); - check_item_deprecated_drop(cx, i); check_item_unused_unsafe(cx, i); check_item_unused_mut(cx, i); } @@ -494,8 +485,8 @@ fn check_item_while_true(cx: ty::ctxt, it: @ast::item) { cx.sess.span_lint( while_true, e.id, it.id, e.span, - ~"denote infinite loops \ - with loop { ... }"); + "denote infinite loops \ + with loop { ... }"); } _ => () } @@ -612,7 +603,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { && !check_limits(cx, *binop, l, r) { cx.sess.span_lint( type_limits, e.id, it.id, e.span, - ~"comparison is useless due to type limits"); + "comparison is useless due to type limits"); } } _ => () @@ -639,48 +630,8 @@ fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) { item.id, item.id, item.span, - ~"default methods are experimental"); - } - } - } - } - _ => {} - } -} - -fn check_item_deprecated_mutable_fields(cx: ty::ctxt, item: @ast::item) { - match item.node { - ast::item_struct(struct_def, _) => { - for struct_def.fields.each |field| { - match field.node.kind { - ast::named_field(_, ast::struct_mutable, _) => { - cx.sess.span_lint(deprecated_mutable_fields, - item.id, - item.id, - field.span, - ~"mutable fields are deprecated"); + "default methods are experimental"); } - ast::named_field(*) | ast::unnamed_field => {} - } - } - } - _ => {} - } -} - -fn check_item_deprecated_drop(cx: ty::ctxt, item: @ast::item) { - match item.node { - ast::item_struct(struct_def, _) => { - match struct_def.dtor { - None => {} - Some(ref dtor) => { - cx.sess.span_lint(deprecated_drop, - item.id, - item.id, - dtor.span, - ~"`drop` notation for destructors is \ - deprecated; implement the `Drop` \ - trait instead"); } } } @@ -689,26 +640,25 @@ fn check_item_deprecated_drop(cx: ty::ctxt, item: @ast::item) { } fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { - fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id, decl: &ast::fn_decl) { let tys = vec::map(decl.inputs, |a| a.ty ); for vec::each(vec::append_one(tys, decl.output)) |ty| { match ty.node { ast::ty_path(_, id) => { - match *cx.def_map.get(&id) { + match cx.def_map.get_copy(&id) { ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { cx.sess.span_lint( ctypes, id, fn_id, ty.span, - ~"found rust type `int` in foreign module, while \ + "found rust type `int` in foreign module, while \ libc::c_int or libc::c_long should be used"); } ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => { cx.sess.span_lint( ctypes, id, fn_id, ty.span, - ~"found rust type `uint` in foreign module, while \ + "found rust type `uint` in foreign module, while \ libc::c_uint or libc::c_ulong should be used"); } _ => () @@ -824,7 +774,7 @@ fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) { cx.sess.span_lint( path_statement, id, it.id, s.span, - ~"path statement with no effect"); + "path statement with no effect"); } _ => () } @@ -864,8 +814,8 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) { if !is_camel_case(cx, ident) { cx.sess.span_lint( non_camel_case_types, expr_id, item_id, span, - ~"type, variant, or trait should have \ - a camel case identifier"); + "type, variant, or trait should have \ + a camel case identifier"); } } @@ -892,7 +842,7 @@ fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) { if !cx.used_unsafe.contains(&blk.node.id) { cx.sess.span_lint(unused_unsafe, blk.node.id, it.id, blk.span, - ~"unnecessary `unsafe` block"); + "unnecessary `unsafe` block"); } } _ => () @@ -917,9 +867,9 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) { } if !used { let msg = if bindings == 1 { - ~"variable does not need to be mutable" + "variable does not need to be mutable" } else { - ~"variables do not need to be mutable" + "variables do not need to be mutable" }; tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg); } @@ -975,13 +925,3 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { tcx.sess.abort_if_errors(); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 94d82d0acb8e4..171048eac5575 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,25 +112,14 @@ use util::ppaux::ty_to_str; use core::cast::transmute; use core::hashmap::HashMap; -use core::util::with; use syntax::ast::*; use syntax::codemap::span; use syntax::parse::token::special_idents; use syntax::print::pprust::{expr_to_str, block_to_str}; -use syntax::visit::{fk_anon, fk_dtor, fk_fn_block, fk_item_fn, fk_method}; +use syntax::visit::{fk_anon, fk_fn_block, fk_item_fn, fk_method}; use syntax::visit::{vt}; use syntax::{visit, ast_util}; -// Maps from an expr id to a list of variable ids for which this expr -// is the last use. Typically, the expr is a path and the node id is -// the local/argument/etc that the path refers to. However, it also -// possible for the expr to be a closure, in which case the list is a -// list of closed over variables that can be moved into the closure. -// -// Very subtle (#2633): borrowck will remove entries from this table -// if it detects an outstanding loan (that is, the addr is taken). -pub type last_use_map = @mut HashMap; - #[deriving(Eq)] struct Variable(uint); #[deriving(Eq)] @@ -158,7 +147,7 @@ pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - crate: @crate) -> last_use_map { + crate: @crate) { let visitor = visit::mk_vt(@visit::Visitor { visit_fn: visit_fn, visit_local: visit_local, @@ -168,16 +157,13 @@ pub fn check_crate(tcx: ty::ctxt, .. *visit::default_visitor() }); - let last_use_map = @mut HashMap::new(); let initial_maps = @mut IrMaps(tcx, method_map, variable_moves_map, capture_map, - last_use_map, 0); visit::visit_crate(crate, initial_maps, visitor); tcx.sess.abort_if_errors(); - return last_use_map; } impl to_str::ToStr for LiveNode { @@ -241,23 +227,11 @@ enum VarKind { ImplicitRet } -fn relevant_def(def: def) -> Option { - match def { - def_binding(nid, _) | - def_arg(nid, _) | - def_local(nid, _) | - def_self(nid, _) => Some(nid), - - _ => None - } -} - struct IrMaps { tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - last_use_map: last_use_map, num_live_nodes: uint, num_vars: uint, @@ -274,7 +248,6 @@ fn IrMaps(tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - last_use_map: last_use_map, cur_item: node_id) -> IrMaps { IrMaps { @@ -282,7 +255,6 @@ fn IrMaps(tcx: ty::ctxt, method_map: method_map, variable_moves_map: variable_moves_map, capture_map: capture_map, - last_use_map: last_use_map, num_live_nodes: 0, num_vars: 0, live_node_map: HashMap::new(), @@ -359,7 +331,7 @@ pub impl IrMaps { match self.capture_info_map.find(&expr.id) { Some(&caps) => caps, None => { - self.tcx.sess.span_bug(expr.span, ~"no registered caps"); + self.tcx.sess.span_bug(expr.span, "no registered caps"); } } } @@ -367,35 +339,13 @@ pub impl IrMaps { fn lnk(&mut self, ln: LiveNode) -> LiveNodeKind { self.lnks[*ln] } - - fn add_last_use(&mut self, expr_id: node_id, var: Variable) { - let vk = self.var_kinds[*var]; - debug!("Node %d is a last use of variable %?", expr_id, vk); - match vk { - Arg(id, _) | - Local(LocalInfo { id: id, kind: FromLetNoInitializer, _ }) | - Local(LocalInfo { id: id, kind: FromLetWithInitializer, _ }) | - Local(LocalInfo { id: id, kind: FromMatch(_), _ }) => { - let v = match self.last_use_map.find(&expr_id) { - Some(&v) => v, - None => { - let v = @mut ~[]; - self.last_use_map.insert(expr_id, v); - v - } - }; - - v.push(id); - } - ImplicitRet => debug!("--but it is not owned"), - } - } } -fn visit_item(item: @item, self: @mut IrMaps, v: vt<@mut IrMaps>) { - do with(&mut self.cur_item, item.id) { - visit::visit_item(item, self, v) - } +fn visit_item(item: @item, this: @mut IrMaps, v: vt<@mut IrMaps>) { + let old_cur_item = this.cur_item; + this.cur_item = item.id; + visit::visit_item(item, this, v); + this.cur_item = old_cur_item; } fn visit_fn(fk: &visit::fn_kind, @@ -403,25 +353,24 @@ fn visit_fn(fk: &visit::fn_kind, body: &blk, sp: span, id: node_id, - self: @mut IrMaps, + this: @mut IrMaps, v: vt<@mut IrMaps>) { debug!("visit_fn: id=%d", id); let _i = ::util::common::indenter(); // swap in a new set of IR maps for this function body: - let fn_maps = @mut IrMaps(self.tcx, - self.method_map, - self.variable_moves_map, - self.capture_map, - self.last_use_map, - self.cur_item); + let fn_maps = @mut IrMaps(this.tcx, + this.method_map, + this.variable_moves_map, + this.capture_map, + this.cur_item); unsafe { debug!("creating fn_maps: %x", transmute(&*fn_maps)); } for decl.inputs.each |arg| { - do pat_util::pat_bindings(self.tcx.def_map, arg.pat) + do pat_util::pat_bindings(this.tcx.def_map, arg.pat) |_bm, arg_id, _x, path| { debug!("adding argument %d", arg_id); let ident = ast_util::path_to_ident(path); @@ -429,7 +378,7 @@ fn visit_fn(fk: &visit::fn_kind, } }; - // Add `self`, whether explicit or implicit. + // Add `this`, whether explicit or implicit. match *fk { fk_method(_, _, method) => { match method.self_ty.node { @@ -440,9 +389,6 @@ fn visit_fn(fk: &visit::fn_kind, sty_static => {} } } - fk_dtor(_, _, self_id, _) => { - fn_maps.add_variable(Arg(self_id, special_idents::self_)); - } fk_item_fn(*) | fk_anon(*) | fk_fn_block(*) => {} } @@ -477,35 +423,35 @@ fn visit_fn(fk: &visit::fn_kind, lsets.warn_about_unused_args(decl, entry_ln); } -fn visit_local(local: @local, self: @mut IrMaps, vt: vt<@mut IrMaps>) { - let def_map = self.tcx.def_map; +fn visit_local(local: @local, this: @mut IrMaps, vt: vt<@mut IrMaps>) { + let def_map = this.tcx.def_map; do pat_util::pat_bindings(def_map, local.node.pat) |_bm, p_id, sp, path| { debug!("adding local variable %d", p_id); let name = ast_util::path_to_ident(path); - self.add_live_node_for_node(p_id, VarDefNode(sp)); + this.add_live_node_for_node(p_id, VarDefNode(sp)); let kind = match local.node.init { Some(_) => FromLetWithInitializer, None => FromLetNoInitializer }; - self.add_variable(Local(LocalInfo { + this.add_variable(Local(LocalInfo { id: p_id, ident: name, is_mutbl: local.node.is_mutbl, kind: kind })); } - visit::visit_local(local, self, vt); + visit::visit_local(local, this, vt); } -fn visit_arm(arm: &arm, self: @mut IrMaps, vt: vt<@mut IrMaps>) { - let def_map = self.tcx.def_map; +fn visit_arm(arm: &arm, this: @mut IrMaps, vt: vt<@mut IrMaps>) { + let def_map = this.tcx.def_map; for arm.pats.each |pat| { do pat_util::pat_bindings(def_map, *pat) |bm, p_id, sp, path| { debug!("adding local variable %d from match with bm %?", p_id, bm); let name = ast_util::path_to_ident(path); - self.add_live_node_for_node(p_id, VarDefNode(sp)); - self.add_variable(Local(LocalInfo { + this.add_live_node_for_node(p_id, VarDefNode(sp)); + this.add_variable(Local(LocalInfo { id: p_id, ident: name, is_mutbl: false, @@ -513,35 +459,35 @@ fn visit_arm(arm: &arm, self: @mut IrMaps, vt: vt<@mut IrMaps>) { })); } } - visit::visit_arm(arm, self, vt); + visit::visit_arm(arm, this, vt); } -fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { +fn visit_expr(expr: @expr, this: @mut IrMaps, vt: vt<@mut IrMaps>) { match expr.node { // live nodes required for uses or definitions of variables: - expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); + expr_path(_) | expr_self => { + let def = this.tcx.def_map.get_copy(&expr.id); debug!("expr %d: path that leads to %?", expr.id, def); - if relevant_def(def).is_some() { - self.add_live_node_for_node(expr.id, ExprNode(expr.span)); + if moves::moved_variable_node_id_from_def(def).is_some() { + this.add_live_node_for_node(expr.id, ExprNode(expr.span)); } - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } expr_fn_block(*) => { // Interesting control flow (for loops can contain labeled // breaks or continues) - self.add_live_node_for_node(expr.id, ExprNode(expr.span)); + this.add_live_node_for_node(expr.id, ExprNode(expr.span)); // Make a live_node for each captured variable, with the span // being the location that the variable is used. This results // in better error messages than just pointing at the closure // construction site. - let cvs = self.capture_map.get(&expr.id); + let cvs = this.capture_map.get(&expr.id); let mut call_caps = ~[]; for cvs.each |cv| { - match relevant_def(cv.def) { + match moves::moved_variable_node_id_from_def(cv.def) { Some(rv) => { - let cv_ln = self.add_live_node(FreeVarNode(cv.span)); + let cv_ln = this.add_live_node(FreeVarNode(cv.span)); let is_move = match cv.mode { // var must be dead afterwards moves::CapMove => true, @@ -556,19 +502,19 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { None => {} } } - self.set_captures(expr.id, call_caps); + this.set_captures(expr.id, call_caps); - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } // live nodes required for interesting control flow: expr_if(*) | expr_match(*) | expr_while(*) | expr_loop(*) => { - self.add_live_node_for_node(expr.id, ExprNode(expr.span)); - visit::visit_expr(expr, self, vt); + this.add_live_node_for_node(expr.id, ExprNode(expr.span)); + visit::visit_expr(expr, this, vt); } expr_binary(op, _, _) if ast_util::lazy_binop(op) => { - self.add_live_node_for_node(expr.id, ExprNode(expr.span)); - visit::visit_expr(expr, self, vt); + this.add_live_node_for_node(expr.id, ExprNode(expr.span)); + visit::visit_expr(expr, this, vt); } // otherwise, live nodes are not required: @@ -577,10 +523,10 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { expr_binary(*) | expr_addr_of(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) | expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) | - expr_assign(*) | expr_swap(*) | expr_assign_op(*) | expr_mac(*) | + expr_assign(*) | expr_assign_op(*) | expr_mac(*) | expr_struct(*) | expr_repeat(*) | expr_paren(*) | expr_inline_asm(*) => { - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } } } @@ -667,8 +613,8 @@ pub impl Liveness { fn variable_from_path(&self, expr: @expr) -> Option { match expr.node { expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); - relevant_def(def).map( + let def = self.tcx.def_map.get_copy(&expr.id); + moves::moved_variable_node_id_from_def(def).map( |rdef| self.variable(*rdef, expr.span) ) } @@ -684,13 +630,13 @@ pub impl Liveness { span: span) -> Option { match self.tcx.def_map.find(&node_id) { Some(&def) => { - relevant_def(def).map( + moves::moved_variable_node_id_from_def(def).map( |rdef| self.variable(*rdef, span) ) } None => { self.tcx.sess.span_bug( - span, ~"Not present in def map") + span, "Not present in def map") } } } @@ -807,17 +753,19 @@ pub impl Liveness { // to find with one match self.tcx.def_map.find(&id) { Some(&def_label(loop_id)) => loop_id, - _ => self.tcx.sess.span_bug(sp, ~"Label on break/loop \ - doesn't refer to a loop") + _ => self.tcx.sess.span_bug(sp, "Label on break/loop \ + doesn't refer to a loop") }, None => { // Vanilla 'break' or 'loop', so use the enclosing // loop scope - let loop_scope = &mut *self.loop_scope; - if loop_scope.len() == 0 { + let len = { // FIXME(#5074) stage0 + let loop_scope = &mut *self.loop_scope; + loop_scope.len() + }; + if len == 0 { self.tcx.sess.span_bug(sp, ~"break outside loop"); - } - else { + } else { // FIXME(#5275): this shouldn't have to be a method... self.last_loop_scope() } @@ -997,7 +945,7 @@ pub impl Liveness { } stmt_mac(*) => { - self.tcx.sess.span_bug(stmt.span, ~"unexpanded macro"); + self.tcx.sess.span_bug(stmt.span, "unexpanded macro"); } } } @@ -1058,7 +1006,7 @@ pub impl Liveness { match expr.node { // Interesting cases with control flow or which gen/kill - expr_path(_) => { + expr_path(_) | expr_self => { self.access_path(expr, succ, ACC_READ | ACC_USE) } @@ -1167,7 +1115,7 @@ pub impl Liveness { match self.break_ln.find(&sc) { Some(&b) => b, None => self.tcx.sess.span_bug(expr.span, - ~"Break to unknown label") + "Break to unknown label") } } @@ -1181,7 +1129,7 @@ pub impl Liveness { match self.cont_ln.find(&sc) { Some(&b) => b, None => self.tcx.sess.span_bug(expr.span, - ~"Loop to unknown label") + "Loop to unknown label") } } @@ -1193,21 +1141,6 @@ pub impl Liveness { self.propagate_through_expr(r, succ) } - expr_swap(l, r) => { - // see comment on lvalues in - // propagate_through_lvalue_components() - - // I count swaps as `used` cause it might be something like: - // foo.bar <-> x - // and I am too lazy to distinguish this case from - // y <-> x - // (where both x, y are unused) just for a warning. - let succ = self.write_lvalue(r, succ, ACC_WRITE|ACC_READ|ACC_USE); - let succ = self.write_lvalue(l, succ, ACC_WRITE|ACC_READ|ACC_USE); - let succ = self.propagate_through_lvalue_components(r, succ); - self.propagate_through_lvalue_components(l, succ) - } - expr_assign_op(_, l, r) => { // see comment on lvalues in // propagate_through_lvalue_components() @@ -1307,7 +1240,7 @@ pub impl Liveness { } expr_mac(*) => { - self.tcx.sess.span_bug(expr.span, ~"unexpanded macro"); + self.tcx.sess.span_bug(expr.span, "unexpanded macro"); } } } @@ -1387,8 +1320,8 @@ pub impl Liveness { fn access_path(&self, expr: @expr, succ: LiveNode, acc: uint) -> LiveNode { - let def = *self.tcx.def_map.get(&expr.id); - match relevant_def(def) { + let def = self.tcx.def_map.get_copy(&expr.id); + match moves::moved_variable_node_id_from_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); if acc != 0u { @@ -1476,13 +1409,13 @@ pub impl Liveness { // _______________________________________________________________________ // Checking for error conditions -fn check_local(local: @local, self: @Liveness, vt: vt<@Liveness>) { +fn check_local(local: @local, this: @Liveness, vt: vt<@Liveness>) { match local.node.init { Some(_) => { // Initializer: - self.warn_about_unused_or_dead_vars_in_pat(local.node.pat); - self.check_for_reassignments_in_pat(local.node.pat, + this.warn_about_unused_or_dead_vars_in_pat(local.node.pat); + this.check_for_reassignments_in_pat(local.node.pat, local.node.is_mutbl); } None => { @@ -1491,12 +1424,12 @@ fn check_local(local: @local, self: @Liveness, vt: vt<@Liveness>) { // should not be live at this point. debug!("check_local() with no initializer"); - do self.pat_bindings(local.node.pat) |ln, var, sp, id| { - if !self.warn_about_unused(sp, id, ln, var) { - match self.live_on_exit(ln, var) { + do this.pat_bindings(local.node.pat) |ln, var, sp, id| { + if !this.warn_about_unused(sp, id, ln, var) { + match this.live_on_exit(ln, var) { None => { /* not live: good */ } Some(lnk) => { - self.report_illegal_read( + this.report_illegal_read( local.span, lnk, var, PossiblyUninitializedVariable); } @@ -1506,79 +1439,77 @@ fn check_local(local: @local, self: @Liveness, vt: vt<@Liveness>) { } } - visit::visit_local(local, self, vt); + visit::visit_local(local, this, vt); } -fn check_arm(arm: &arm, self: @Liveness, vt: vt<@Liveness>) { - do self.arm_pats_bindings(arm.pats) |ln, var, sp, id| { - self.warn_about_unused(sp, id, ln, var); +fn check_arm(arm: &arm, this: @Liveness, vt: vt<@Liveness>) { + do this.arm_pats_bindings(arm.pats) |ln, var, sp, id| { + this.warn_about_unused(sp, id, ln, var); } - visit::visit_arm(arm, self, vt); + visit::visit_arm(arm, this, vt); } -fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) { +fn check_expr(expr: @expr, this: @Liveness, vt: vt<@Liveness>) { match expr.node { - expr_path(_) => { - for self.variable_from_def_map(expr.id, expr.span).each |var| { - let ln = self.live_node(expr.id, expr.span); - self.consider_last_use(expr, ln, *var); + expr_path(_) | expr_self => { + for this.variable_from_def_map(expr.id, expr.span).each |var| { + let ln = this.live_node(expr.id, expr.span); - match self.ir.variable_moves_map.find(&expr.id) { + match this.ir.variable_moves_map.find(&expr.id) { None => {} Some(&entire_expr) => { debug!("(checking expr) is a move: `%s`", - expr_to_str(expr, self.tcx.sess.intr())); - self.check_move_from_var(ln, *var, entire_expr); + expr_to_str(expr, this.tcx.sess.intr())); + this.check_move_from_var(ln, *var, entire_expr); } } } - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } expr_fn_block(*) => { - let caps = self.ir.captures(expr); + let caps = this.ir.captures(expr); for caps.each |cap| { - let var = self.variable(cap.var_nid, expr.span); - self.consider_last_use(expr, cap.ln, var); + let var = this.variable(cap.var_nid, expr.span); if cap.is_move { - self.check_move_from_var(cap.ln, var, expr); + this.check_move_from_var(cap.ln, var, expr); } } - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } expr_assign(l, r) => { - self.check_lvalue(l, vt); - (vt.visit_expr)(r, self, vt); + this.check_lvalue(l, vt); + (vt.visit_expr)(r, this, vt); - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } expr_assign_op(_, l, _) => { - self.check_lvalue(l, vt); + this.check_lvalue(l, vt); - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } expr_inline_asm(ref ia) => { for ia.inputs.each |&(_, in)| { - (vt.visit_expr)(in, self, vt); + (vt.visit_expr)(in, this, vt); } // Output operands must be lvalues for ia.outputs.each |&(_, out)| { match out.node { expr_addr_of(_, inner) => { - self.check_lvalue(inner, vt); + this.check_lvalue(inner, vt); } _ => {} } - (vt.visit_expr)(out, self, vt); + (vt.visit_expr)(out, this, vt); } - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } // no correctness conditions related to liveness @@ -1587,10 +1518,10 @@ fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) { expr_vstore(*) | expr_vec(*) | expr_tup(*) | expr_log(*) | expr_binary(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) | - expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) | + expr_again(*) | expr_lit(_) | expr_block(*) | expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) | expr_paren(*) => { - visit::visit_expr(expr, self, vt); + visit::visit_expr(expr, this, vt); } } } @@ -1609,7 +1540,7 @@ enum ReadKind { } pub impl Liveness { - fn check_ret(@self, id: node_id, sp: span, _fk: &visit::fn_kind, + fn check_ret(&self, id: node_id, sp: span, _fk: &visit::fn_kind, entry_ln: LiveNode) { if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { // if no_ret_var is live, then we fall off the end of the @@ -1621,19 +1552,19 @@ pub impl Liveness { } else if ty::type_is_bot(t_ret) { // for bot return types, not ok. Function should fail. self.tcx.sess.span_err( - sp, ~"some control paths may return"); + sp, "some control paths may return"); } else { self.tcx.sess.span_err( - sp, ~"not all control paths return a value"); + sp, "not all control paths return a value"); } } } - fn check_move_from_var(@self, ln: LiveNode, + fn check_move_from_var(&self, + ln: LiveNode, var: Variable, move_expr: @expr) { /*! - * * Checks whether `var` is live on entry to any of the * successors of `ln`. If it is, report an error. * `move_expr` is the expression which caused the variable @@ -1653,20 +1584,10 @@ pub impl Liveness { } } - fn consider_last_use(@self, expr: @expr, ln: LiveNode, var: Variable) { - debug!("consider_last_use(expr.id=%?, ln=%s, var=%s)", - expr.id, ln.to_str(), var.to_str()); - - match self.live_on_exit(ln, var) { - Some(_) => {} - None => self.ir.add_last_use(expr.id, var) - } - } - fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) { match expr.node { expr_path(_) => { - match *self.tcx.def_map.get(&expr.id) { + match self.tcx.def_map.get_copy(&expr.id) { def_local(nid, mutbl) => { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually @@ -1679,7 +1600,7 @@ pub impl Liveness { self.warn_about_dead_assign(expr.span, expr.id, ln, var); } def => { - match relevant_def(def) { + match moves::moved_variable_node_id_from_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); @@ -1699,14 +1620,14 @@ pub impl Liveness { } } - fn check_for_reassignments_in_pat(@self, pat: @pat, mutbl: bool) { + fn check_for_reassignments_in_pat(&self, pat: @pat, mutbl: bool) { do self.pat_bindings(pat) |ln, var, sp, id| { self.check_for_reassignment(ln, var, sp, if mutbl {Some(id)} else {None}); } } - fn check_for_reassignment(@self, ln: LiveNode, var: Variable, + fn check_for_reassignment(&self, ln: LiveNode, var: Variable, orig_span: span, mutbl: Option) { match self.assigned_on_exit(ln, var) { Some(ExprNode(span)) => { @@ -1715,10 +1636,10 @@ pub impl Liveness { None => { self.tcx.sess.span_err( span, - ~"re-assignment of immutable variable"); + "re-assignment of immutable variable"); self.tcx.sess.span_note( orig_span, - ~"prior assignment occurs here"); + "prior assignment occurs here"); } } } @@ -1731,7 +1652,7 @@ pub impl Liveness { } } - fn report_illegal_move(@self, lnk: LiveNodeKind, + fn report_illegal_move(&self, lnk: LiveNodeKind, var: Variable, move_expr: @expr) { // the only time that it is possible to have a moved variable @@ -1796,7 +1717,8 @@ pub impl Liveness { }; } - fn report_move_location(@self, move_expr: @expr, + fn report_move_location(&self, + move_expr: @expr, var: Variable, expr_descr: &str, pronoun: &str) { @@ -1810,7 +1732,8 @@ pub impl Liveness { ty_to_str(self.tcx, move_expr_ty))); } - fn report_illegal_read(@self, chk_span: span, + fn report_illegal_read(&self, + chk_span: span, lnk: LiveNodeKind, var: Variable, rk: ReadKind) { @@ -1841,12 +1764,12 @@ pub impl Liveness { } } - fn should_warn(@self, var: Variable) -> Option<@~str> { + fn should_warn(&self, var: Variable) -> Option<@~str> { let name = self.ir.variable_name(var); if name[0] == ('_' as u8) { None } else { Some(name) } } - fn warn_about_unused_args(@self, decl: &fn_decl, entry_ln: LiveNode) { + fn warn_about_unused_args(&self, decl: &fn_decl, entry_ln: LiveNode) { for decl.inputs.each |arg| { do pat_util::pat_bindings(self.tcx.def_map, arg.pat) |_bm, p_id, sp, _n| { @@ -1856,7 +1779,7 @@ pub impl Liveness { } } - fn warn_about_unused_or_dead_vars_in_pat(@self, pat: @pat) { + fn warn_about_unused_or_dead_vars_in_pat(&self, pat: @pat) { do self.pat_bindings(pat) |ln, var, sp, id| { if !self.warn_about_unused(sp, id, ln, var) { self.warn_about_dead_assign(sp, id, ln, var); @@ -1864,7 +1787,7 @@ pub impl Liveness { } } - fn warn_about_unused(@self, sp: span, id: node_id, + fn warn_about_unused(&self, sp: span, id: node_id, ln: LiveNode, var: Variable) -> bool { if !self.used_on_entry(ln, var) { for self.should_warn(var).each |name| { @@ -1894,7 +1817,7 @@ pub impl Liveness { return false; } - fn warn_about_dead_assign(@self, sp: span, id: node_id, + fn warn_about_dead_assign(&self, sp: span, id: node_id, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { for self.should_warn(var).each |name| { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7fa198be1d47f..91c0b8e61cc7b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -48,7 +48,7 @@ use middle::ty; use middle::typeck; -use util::ppaux::{ty_to_str, region_to_str}; +use util::ppaux::{ty_to_str, region_to_str, Repr}; use util::common::indenter; use syntax::ast::{m_imm, m_const, m_mutbl}; @@ -58,48 +58,45 @@ use syntax::print::pprust; #[deriving(Eq)] pub enum categorization { - cat_rvalue, // result of eval'ing some misc expr - cat_special(special_kind), // - cat_local(ast::node_id), // local variable - cat_binding(ast::node_id), // pattern binding - cat_arg(ast::node_id), // formal argument - cat_stack_upvar(cmt), // upvar in stack closure - cat_deref(cmt, uint, ptr_kind), // deref of a ptr - cat_comp(cmt, comp_kind), // adjust to locate an internal component - cat_discr(cmt, ast::node_id), // match discriminant (see preserve()) - cat_self(ast::node_id), // explicit `self` + cat_rvalue, // result of eval'ing some misc expr + cat_static_item, + cat_implicit_self, + cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env + cat_stack_upvar(cmt), // by ref upvar from &fn + cat_local(ast::node_id), // local variable + cat_arg(ast::node_id), // formal argument + cat_deref(cmt, uint, ptr_kind), // deref of a ptr + cat_interior(cmt, interior_kind), // something interior + cat_discr(cmt, ast::node_id), // match discriminant (see preserve()) + cat_self(ast::node_id), // explicit `self` +} + +#[deriving(Eq)] +struct CopiedUpvar { + upvar_id: ast::node_id, + onceness: ast::Onceness, } // different kinds of pointers: #[deriving(Eq)] pub enum ptr_kind { - uniq_ptr, + uniq_ptr(ast::mutability), gc_ptr(ast::mutability), region_ptr(ast::mutability, ty::Region), unsafe_ptr } -// I am coining the term "components" to mean "pieces of a data -// structure accessible without a dereference": +// We use the term "interior" to mean "something reachable from the +// base without a pointer dereference", e.g. a field #[deriving(Eq)] -pub enum comp_kind { - comp_tuple, // elt in a tuple - comp_anon_field, // anonymous field (in e.g. - // struct Foo(int, int); - comp_variant(ast::def_id), // internals to a variant of given enum - comp_field(ast::ident, // name of field - ast::mutability), // declared mutability of field - comp_index(ty::t, // type of vec/str/etc being deref'd - ast::mutability) // mutability of vec content -} - -// different kinds of expressions we might evaluate -#[deriving(Eq)] -pub enum special_kind { - sk_method, - sk_static_item, - sk_implicit_self, // old by-reference `self` - sk_heap_upvar +pub enum interior_kind { + interior_tuple, // elt in a tuple + interior_anon_field, // anonymous field (in e.g. + // struct Foo(int, int); + interior_variant(ast::def_id), // internals to a variant of given enum + interior_field(ast::ident), // name of field + interior_index(ty::t, // type of vec/str/etc being deref'd + ast::mutability) // mutability of vec content } #[deriving(Eq)] @@ -110,49 +107,48 @@ pub enum MutabilityCategory { McInherited // Inherited from the fact that owner is mutable. } +// `cmt`: "Category, Mutability, and Type". +// // a complete categorization of a value indicating where it originated // and how it is located, as well as the mutability of the memory in // which the value is stored. // -// note: cmt stands for "categorized mutable type". +// *WARNING* The field `cmt.type` is NOT necessarily the same as the +// result of `node_id_to_type(cmt.id)`. This is because the `id` is +// always the `id` of the node producing the type; in an expression +// like `*x`, the type of this deref node is the deref'd type (`T`), +// but in a pattern like `@x`, the `@x` pattern is again a +// dereference, but its type is the type *before* the dereference +// (`@T`). So use `cmt.type` to find the type of the value in a consistent +// fashion. For more details, see the method `cat_pattern` #[deriving(Eq)] pub struct cmt_ { id: ast::node_id, // id of expr/pat producing this value span: span, // span of same expr/pat cat: categorization, // categorization of expr - lp: Option<@loan_path>, // loan path for expr, if any mutbl: MutabilityCategory, // mutability of expr as lvalue - ty: ty::t // type of the expr + ty: ty::t // type of the expr (*see WARNING above*) } pub type cmt = @cmt_; -// a loan path is like a category, but it exists only when the data is -// interior to the stack frame. loan paths are used as the key to a -// map indicating what is borrowed at any point in time. -#[deriving(Eq)] -pub enum loan_path { - lp_local(ast::node_id), - lp_arg(ast::node_id), - lp_self, - lp_deref(@loan_path, ptr_kind), - lp_comp(@loan_path, comp_kind) -} - // We pun on *T to mean both actual deref of a ptr as well // as accessing of components: -pub enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)} +pub enum deref_kind {deref_ptr(ptr_kind), deref_interior(interior_kind)} // Categorizes a derefable type. Note that we include vectors and strings as // derefable (we model an index as the combination of a deref and then a // pointer adjustment). pub fn opt_deref_kind(t: ty::t) -> Option { match ty::get(t).sty { - ty::ty_uniq(*) | + ty::ty_uniq(mt) => { + Some(deref_ptr(uniq_ptr(mt.mutbl))) + } + ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) | ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => { - Some(deref_ptr(uniq_ptr)) + Some(deref_ptr(uniq_ptr(m_imm))) } ty::ty_rptr(r, mt) | @@ -181,19 +177,19 @@ pub fn opt_deref_kind(t: ty::t) -> Option { } ty::ty_enum(did, _) => { - Some(deref_comp(comp_variant(did))) + Some(deref_interior(interior_variant(did))) } ty::ty_struct(_, _) => { - Some(deref_comp(comp_anon_field)) + Some(deref_interior(interior_anon_field)) } ty::ty_evec(mt, ty::vstore_fixed(_)) => { - Some(deref_comp(comp_index(t, mt.mutbl))) + Some(deref_interior(interior_index(t, mt.mutbl))) } ty::ty_estr(ty::vstore_fixed(_)) => { - Some(deref_comp(comp_index(t, m_imm))) + Some(deref_interior(interior_index(t, m_imm))) } _ => None @@ -257,19 +253,6 @@ pub fn cat_def( return mcx.cat_def(expr_id, expr_span, expr_ty, def); } -pub fn cat_variant( - tcx: ty::ctxt, - method_map: typeck::method_map, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - - let mcx = &mem_categorization_ctxt { - tcx: tcx, method_map: method_map - }; - return mcx.cat_variant(arg, enum_did, cmt); -} - pub trait ast_node { fn id(&self) -> ast::node_id; fn span(&self) -> span; @@ -285,16 +268,6 @@ impl ast_node for @ast::pat { fn span(&self) -> span { self.span } } -pub trait get_type_for_node { - fn ty(&self, node: N) -> ty::t; -} - -impl get_type_for_node for ty::ctxt { - fn ty(&self, node: N) -> ty::t { - ty::node_id_to_type(*self, node.id()) - } -} - pub struct mem_categorization_ctxt { tcx: ty::ctxt, method_map: typeck::method_map, @@ -338,26 +311,24 @@ pub impl MutabilityCategory { } } - fn to_user_str(&self) -> ~str { + fn to_user_str(&self) -> &'static str { match *self { - McDeclared | McInherited => ~"mutable", - McImmutable => ~"immutable", - McReadOnly => ~"const" + McDeclared | McInherited => "mutable", + McImmutable => "immutable", + McReadOnly => "const" } } } -pub impl loan_path { - fn node_id(&self) -> Option { - match *self { - lp_local(id) | lp_arg(id) => Some(id), - lp_deref(lp, _) | lp_comp(lp, _) => lp.node_id(), - lp_self => None - } +pub impl mem_categorization_ctxt { + fn expr_ty(&self, expr: @ast::expr) -> ty::t { + ty::expr_ty(self.tcx, expr) + } + + fn pat_ty(&self, pat: @ast::pat) -> ty::t { + ty::node_id_to_type(self.tcx, pat.id) } -} -pub impl mem_categorization_ctxt { fn cat_expr(&self, expr: @ast::expr) -> cmt { match self.tcx.adjustments.find(&expr.id) { None => { @@ -406,8 +377,7 @@ pub impl mem_categorization_ctxt { debug!("cat_expr: id=%d expr=%s", expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr())); - let tcx = self.tcx; - let expr_ty = tcx.ty(expr); + let expr_ty = self.expr_ty(expr); match expr.node { ast::expr_unary(ast::deref, e_base) => { if self.method_map.contains_key(&expr.id) { @@ -419,12 +389,12 @@ pub impl mem_categorization_ctxt { } ast::expr_field(base, f_name, _) => { - if self.method_map.contains_key(&expr.id) { - return self.cat_method_ref(expr, expr_ty); - } + // Method calls are now a special syntactic form, + // so `a.b` should always be a field. + assert!(!self.method_map.contains_key(&expr.id)); let base_cmt = self.cat_expr(base); - self.cat_field(expr, base_cmt, f_name, expr.id) + self.cat_field(expr, base_cmt, f_name, self.expr_ty(expr)) } ast::expr_index(base, _) => { @@ -433,17 +403,17 @@ pub impl mem_categorization_ctxt { } let base_cmt = self.cat_expr(base); - self.cat_index(expr, base_cmt) + self.cat_index(expr, base_cmt, 0) } - ast::expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); + ast::expr_path(_) | ast::expr_self => { + let def = self.tcx.def_map.get_copy(&expr.id); self.cat_def(expr.id, expr.span, expr_ty, def) } ast::expr_paren(e) => self.cat_expr_unadjusted(e), - ast::expr_addr_of(*) | ast::expr_call(*) | ast::expr_swap(*) | + ast::expr_addr_of(*) | ast::expr_call(*) | ast::expr_assign(*) | ast::expr_assign_op(*) | ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) | ast::expr_do_body(*) | ast::expr_unary(*) | @@ -475,8 +445,7 @@ pub impl mem_categorization_ctxt { @cmt_ { id:id, span:span, - cat:cat_special(sk_static_item), - lp:None, + cat:cat_static_item, mutbl: McImmutable, ty:expr_ty } @@ -487,66 +456,70 @@ pub impl mem_categorization_ctxt { // stuff as `&const` and `&mut`? // m: mutability of the argument - // lp: loan path, must be none for aliasable things let m = if mutbl {McDeclared} else {McImmutable}; - let lp = Some(@lp_arg(vid)); @cmt_ { - id:id, - span:span, - cat:cat_arg(vid), - lp:lp, + id: id, + span: span, + cat: cat_arg(vid), mutbl: m, ty:expr_ty } } ast::def_self(self_id, is_implicit) => { - let cat, loan_path; - if is_implicit { - cat = cat_special(sk_implicit_self); - loan_path = None; + let cat = if is_implicit { + cat_implicit_self } else { - cat = cat_self(self_id); - loan_path = Some(@lp_self); + cat_self(self_id) }; @cmt_ { id:id, span:span, cat:cat, - lp:loan_path, mutbl: McImmutable, ty:expr_ty } } - ast::def_upvar(_, inner, fn_node_id, _) => { - let ty = ty::node_id_to_type(self.tcx, fn_node_id); - let sigil = ty::ty_closure_sigil(ty); - match sigil { - ast::BorrowedSigil => { - let upcmt = self.cat_def(id, span, expr_ty, *inner); - @cmt_ { - id:id, - span:span, - cat:cat_stack_upvar(upcmt), - lp:upcmt.lp, - mutbl:upcmt.mutbl, - ty:upcmt.ty - } - } - ast::OwnedSigil | ast::ManagedSigil => { - // FIXME #2152 allow mutation of moved upvars - @cmt_ { - id:id, - span:span, - cat:cat_special(sk_heap_upvar), - lp:None, - mutbl:McImmutable, - ty:expr_ty - } - } - } + ast::def_upvar(upvar_id, inner, fn_node_id, _) => { + 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 + } + } + 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 + } + } + } + } + _ => { + self.tcx.sess.span_bug( + span, + fmt!("Upvar of non-closure %? - %s", + fn_node_id, ty.repr(self.tcx))); + } + } } ast::def_local(vid, mutbl) => { @@ -555,7 +528,6 @@ pub impl mem_categorization_ctxt { id:id, span:span, cat:cat_local(vid), - lp:Some(@lp_local(vid)), mutbl:m, ty:expr_ty } @@ -567,7 +539,6 @@ pub impl mem_categorization_ctxt { id:id, span:span, cat:cat_local(vid), - lp:Some(@lp_local(vid)), mutbl:McImmutable, ty:expr_ty } @@ -575,27 +546,12 @@ pub impl mem_categorization_ctxt { } } - fn cat_variant(&self, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - @cmt_ { - id: arg.id(), - span: arg.span(), - cat: cat_comp(cmt, comp_variant(enum_did)), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(arg) - } - } - fn cat_rvalue(&self, elt: N, expr_ty: ty::t) -> cmt { @cmt_ { id:elt.id(), span:elt.span(), cat:cat_rvalue, - lp:None, - mutbl:McImmutable, + mutbl:McDeclared, ty:expr_ty } } @@ -606,43 +562,26 @@ pub impl mem_categorization_ctxt { /// or if the container is mutable. fn inherited_mutability(&self, base_m: MutabilityCategory, - comp_m: ast::mutability) -> MutabilityCategory + interior_m: ast::mutability) -> MutabilityCategory { - match comp_m { + match interior_m { m_imm => base_m.inherit(), m_const => McReadOnly, m_mutbl => McDeclared } } - /// The `field_id` parameter is the ID of the enclosing expression or - /// pattern. It is used to determine which variant of an enum is in use. fn cat_field(&self, node: N, base_cmt: cmt, f_name: ast::ident, - field_id: ast::node_id) -> cmt { - let f_mutbl = match field_mutbl(self.tcx, base_cmt.ty, - f_name, field_id) { - Some(f_mutbl) => f_mutbl, - None => { - self.tcx.sess.span_bug( - node.span(), - fmt!("Cannot find field `%s` in type `%s`", - *self.tcx.sess.str_of(f_name), - ty_to_str(self.tcx, base_cmt.ty))); - } - }; - let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl); - let f_comp = comp_field(f_name, f_mutbl); - let lp = base_cmt.lp.map(|lp| @lp_comp(*lp, f_comp) ); + f_ty: ty::t) -> cmt { @cmt_ { id: node.id(), span: node.span(), - cat: cat_comp(base_cmt, f_comp), - lp:lp, - mutbl: m, - ty: self.tcx.ty(node) + cat: cat_interior(base_cmt, interior_field(f_name)), + mutbl: base_cmt.mutbl.inherit(), + ty: f_ty } } @@ -688,25 +627,10 @@ pub impl mem_categorization_ctxt { { match deref_kind(self.tcx, base_cmt.ty) { deref_ptr(ptr) => { - let lp = do base_cmt.lp.chain_ref |l| { - // Given that the ptr itself is loanable, we can - // loan out deref'd uniq ptrs or mut ptrs as the data - // they are the only way to mutably reach the data they - // point at. Other ptr types admit mutable aliases and - // are therefore not loanable. - match ptr { - uniq_ptr => Some(@lp_deref(*l, ptr)), - region_ptr(ast::m_mutbl, _) => { - Some(@lp_deref(*l, ptr)) - } - gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => None - } - }; - // for unique ptrs, we inherit mutability from the // owning reference. let m = match ptr { - uniq_ptr => { + uniq_ptr(*) => { self.inherited_mutability(base_cmt.mutbl, mt.mutbl) } gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => { @@ -718,20 +642,17 @@ pub impl mem_categorization_ctxt { id:node.id(), span:node.span(), cat:cat_deref(base_cmt, deref_cnt, ptr), - lp:lp, mutbl:m, ty:mt.ty } } - deref_comp(comp) => { - let lp = base_cmt.lp.map(|l| @lp_comp(*l, comp) ); + deref_interior(interior) => { let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); @cmt_ { id:node.id(), span:node.span(), - cat:cat_comp(base_cmt, comp), - lp:lp, + cat:cat_interior(base_cmt, interior), mutbl:m, ty:mt.ty } @@ -740,8 +661,40 @@ pub impl mem_categorization_ctxt { } fn cat_index(&self, - elt: N, - base_cmt: cmt) -> cmt { + elt: N, + base_cmt: cmt, + derefs: uint) -> cmt { + //! Creates a cmt for an indexing operation (`[]`); this + //! indexing operation may occurs as part of an + //! AutoBorrowVec, which when converting a `~[]` to an `&[]` + //! effectively takes the address of the 0th element. + //! + //! One subtle aspect of indexing that may not be + //! immediately obvious: for anything other than a fixed-length + //! vector, an operation like `x[y]` actually consists of two + //! disjoint (from the point of view of borrowck) operations. + //! The first is a deref of `x` to create a pointer `p` that points + //! at the first element in the array. The second operation is + //! an index which adds `y*sizeof(T)` to `p` to obtain the + //! pointer to `x[y]`. `cat_index` will produce a resulting + //! cmt containing both this deref and the indexing, + //! presuming that `base_cmt` is not of fixed-length type. + //! + //! In the event that a deref is needed, the "deref count" + //! is taken from the parameter `derefs`. See the comment + //! on the def'n of `root_map_key` in borrowck/mod.rs + //! for more details about deref counts; the summary is + //! that `derefs` should be 0 for an explicit indexing + //! operation and N+1 for an indexing that is part of + //! an auto-adjustment, where N is the number of autoderefs + //! in that adjustment. + //! + //! # Parameters + //! - `elt`: the AST node being indexed + //! - `base_cmt`: the cmt of `elt` + //! - `derefs`: the deref number to be used for + //! the implicit index deref, if any (see above) + let mt = match ty::index(base_cmt.ty) { Some(mt) => mt, None => { @@ -754,17 +707,10 @@ pub impl mem_categorization_ctxt { return match deref_kind(self.tcx, base_cmt.ty) { deref_ptr(ptr) => { - // (a) the contents are loanable if the base is loanable - // and this is a *unique* vector - let deref_lp = match ptr { - uniq_ptr => {base_cmt.lp.map(|lp| @lp_deref(*lp, uniq_ptr))} - _ => {None} - }; - - // (b) for unique ptrs, we inherit mutability from the + // for unique ptrs, we inherit mutability from the // owning reference. let m = match ptr { - uniq_ptr => { + uniq_ptr(*) => { self.inherited_mutability(base_cmt.mutbl, mt.mutbl) } gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => { @@ -772,79 +718,51 @@ pub impl mem_categorization_ctxt { } }; - // (c) the deref is explicit in the resulting cmt + // the deref is explicit in the resulting cmt let deref_cmt = @cmt_ { id:elt.id(), span:elt.span(), - cat:cat_deref(base_cmt, 0u, ptr), - lp:deref_lp, + cat:cat_deref(base_cmt, derefs, ptr), mutbl:m, ty:mt.ty }; - comp(elt, deref_cmt, base_cmt.ty, m, mt) + interior(elt, deref_cmt, base_cmt.ty, m, mt) } - deref_comp(_) => { + deref_interior(_) => { // fixed-length vectors have no deref let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - comp(elt, base_cmt, base_cmt.ty, m, mt) + interior(elt, base_cmt, base_cmt.ty, m, mt) } }; - fn comp(elt: N, of_cmt: cmt, - vect: ty::t, mutbl: MutabilityCategory, - mt: ty::mt) -> cmt + fn interior(elt: N, of_cmt: cmt, + vect: ty::t, mutbl: MutabilityCategory, + mt: ty::mt) -> cmt { - let comp = comp_index(vect, mt.mutbl); - let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) ); + let interior = interior_index(vect, mt.mutbl); @cmt_ { id:elt.id(), span:elt.span(), - cat:cat_comp(of_cmt, comp), - lp:index_lp, + cat:cat_interior(of_cmt, interior), mutbl:mutbl, ty:mt.ty } } } - fn cat_tuple_elt(&self, - elt: N, - cmt: cmt) -> cmt { - @cmt_ { - id: elt.id(), - span: elt.span(), - cat: cat_comp(cmt, comp_tuple), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(elt) - } - } - - fn cat_anon_struct_field(&self, - elt: N, - cmt: cmt) -> cmt { - @cmt_ { - id: elt.id(), - span: elt.span(), - cat: cat_comp(cmt, comp_anon_field), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(elt) - } - } - - fn cat_method_ref(&self, - expr: @ast::expr, - expr_ty: ty::t) -> cmt { + fn cat_imm_interior(&self, + node: N, + base_cmt: cmt, + interior_ty: ty::t, + interior: interior_kind) -> cmt { @cmt_ { - id:expr.id, - span:expr.span, - cat:cat_special(sk_method), - lp:None, - mutbl:McImmutable, - ty:expr_ty + id: node.id(), + span: node.span(), + cat: cat_interior(base_cmt, interior), + mutbl: base_cmt.mutbl.inherit(), + ty: interior_ty } } @@ -865,32 +783,42 @@ pub impl mem_categorization_ctxt { // we can be sure that the binding will remain valid for the // duration of the arm. // - // The correspondence between the id in the cmt and which - // pattern is being referred to is somewhat...subtle. In - // general, the id of the cmt is the id of the node that - // produces the value. For patterns, that's actually the - // *subpattern*, generally speaking. + // (*) There is subtlety concerning the correspondence between + // pattern ids and types as compared to *expression* ids and + // types. This is explained briefly. on the definition of the + // type `cmt`, so go off and read what it says there, then + // come back and I'll dive into a bit more detail here. :) OK, + // back? // - // To see what I mean about ids etc, consider: + // In general, the id of the cmt should be the node that + // "produces" the value---patterns aren't executable code + // exactly, but I consider them to "execute" when they match a + // value. So if you have something like: // // let x = @@3; // match x { // @@y { ... } // } // - // Here the cmt for `y` would be something like + // In this case, the cmt and the relevant ids would be: + // + // CMT Id Type of Id Type of cmt // // local(x)->@->@ + // ^~~~~~~^ `x` from discr @@int @@int + // ^~~~~~~~~~^ `@@y` pattern node @@int @int + // ^~~~~~~~~~~~~^ `@y` pattern node @int int // - // where the id of `local(x)` is the id of the `x` that appears - // in the match, the id of `local(x)->@` is the `@y` pattern, - // and the id of `local(x)->@->@` is the id of the `y` pattern. - + // You can see that the types of the id and the cmt are in + // sync in the first line, because that id is actually the id + // of an expression. But once we get to pattern ids, the types + // step out of sync again. So you'll see below that we always + // get the type of the *subpattern* and use that. let tcx = self.tcx; debug!("cat_pattern: id=%d pat=%s cmt=%s", pat.id, pprust::pat_to_str(pat, tcx.sess.intr()), - self.cmt_to_repr(cmt)); + cmt.repr(tcx)); let _i = indenter(); op(cmt, pat); @@ -907,28 +835,33 @@ pub impl mem_categorization_ctxt { match self.tcx.def_map.find(&pat.id) { Some(&ast::def_variant(enum_did, _)) => { // variant(x, y, z) - for subpats.each |subpat| { - let subcmt = self.cat_variant(*subpat, enum_did, cmt); - self.cat_pattern(subcmt, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let subcmt = + self.cat_imm_interior(pat, cmt, subpat_ty, + interior_variant(enum_did)); + self.cat_pattern(subcmt, subpat, op); } } Some(&ast::def_fn(*)) | Some(&ast::def_struct(*)) => { - for subpats.each |subpat| { - let cmt_field = self.cat_anon_struct_field(*subpat, - cmt); - self.cat_pattern(cmt_field, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let cmt_field = + self.cat_imm_interior(pat, cmt, subpat_ty, + interior_anon_field); + self.cat_pattern(cmt_field, subpat, op); } } Some(&ast::def_const(*)) => { - for subpats.each |subpat| { - self.cat_pattern(cmt, *subpat, op); + for subpats.each |&subpat| { + self.cat_pattern(cmt, subpat, op); } } _ => { self.tcx.sess.span_bug( pat.span, - ~"enum pattern didn't resolve to enum or struct"); + "enum pattern didn't resolve to enum or struct"); } } } @@ -944,39 +877,41 @@ pub impl mem_categorization_ctxt { ast::pat_struct(_, ref field_pats, _) => { // {f1: p1, ..., fN: pN} for field_pats.each |fp| { - let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); + 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); } } ast::pat_tup(ref subpats) => { // (p1, ..., pN) - for subpats.each |subpat| { - let subcmt = self.cat_tuple_elt(*subpat, cmt); - self.cat_pattern(subcmt, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let subcmt = self.cat_imm_interior(pat, cmt, subpat_ty, + interior_tuple); + self.cat_pattern(subcmt, subpat, op); } } ast::pat_box(subpat) | ast::pat_uniq(subpat) | ast::pat_region(subpat) => { // @p1, ~p1 - let subcmt = self.cat_deref(subpat, cmt, 0); + let subcmt = self.cat_deref(pat, cmt, 0); self.cat_pattern(subcmt, subpat, op); } ast::pat_vec(ref before, slice, ref after) => { - for before.each |pat| { - let elt_cmt = self.cat_index(*pat, cmt); - self.cat_pattern(elt_cmt, *pat, op); + let elt_cmt = self.cat_index(pat, cmt, 0); + for before.each |&before_pat| { + self.cat_pattern(elt_cmt, before_pat, op); } - for slice.each |slice_pat| { - let slice_ty = self.tcx.ty(*slice_pat); - let slice_cmt = self.cat_rvalue(*slice_pat, slice_ty); - self.cat_pattern(slice_cmt, *slice_pat, op); + for slice.each |&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); } - for after.each |pat| { - let elt_cmt = self.cat_index(*pat, cmt); - self.cat_pattern(elt_cmt, *pat, op); + for after.each |&after_pat| { + self.cat_pattern(elt_cmt, after_pat, op); } } @@ -986,29 +921,6 @@ pub impl mem_categorization_ctxt { } } - fn cat_to_repr(&self, cat: categorization) -> ~str { - match cat { - cat_special(sk_method) => ~"method", - cat_special(sk_static_item) => ~"static_item", - cat_special(sk_implicit_self) => ~"implicit-self", - cat_special(sk_heap_upvar) => ~"heap-upvar", - cat_stack_upvar(_) => ~"stack-upvar", - cat_rvalue => ~"rvalue", - cat_local(node_id) => fmt!("local(%d)", node_id), - cat_binding(node_id) => fmt!("binding(%d)", node_id), - cat_arg(node_id) => fmt!("arg(%d)", node_id), - cat_self(node_id) => fmt!("self(%d)", node_id), - cat_deref(cmt, derefs, ptr) => { - fmt!("%s->(%s, %u)", self.cat_to_repr(cmt.cat), - self.ptr_sigil(ptr), derefs) - } - cat_comp(cmt, comp) => { - fmt!("%s.%s", self.cat_to_repr(cmt.cat), *self.comp_to_repr(comp)) - } - cat_discr(cmt, _) => self.cat_to_repr(cmt.cat) - } - } - fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { match mutbl { m_mutbl => ~"mutable", @@ -1017,84 +929,33 @@ pub impl mem_categorization_ctxt { } } - fn ptr_sigil(&self, ptr: ptr_kind) -> ~str { - match ptr { - uniq_ptr => ~"~", - gc_ptr(_) => ~"@", - region_ptr(_, _) => ~"&", - unsafe_ptr => ~"*" - } - } - - fn comp_to_repr(&self, comp: comp_kind) -> @~str { - match comp { - comp_field(fld, _) => self.tcx.sess.str_of(fld), - comp_index(*) => @~"[]", - comp_tuple => @~"()", - comp_anon_field => @~"", - comp_variant(_) => @~"" - } - } - - fn lp_to_str(&self, lp: @loan_path) -> ~str { - match *lp { - lp_local(node_id) => { - fmt!("local(%d)", node_id) - } - lp_arg(node_id) => { - fmt!("arg(%d)", node_id) - } - lp_self => ~"self", - lp_deref(lp, ptr) => { - fmt!("%s->(%s)", self.lp_to_str(lp), - self.ptr_sigil(ptr)) - } - lp_comp(lp, comp) => { - fmt!("%s.%s", self.lp_to_str(lp), - *self.comp_to_repr(comp)) - } - } - } - - fn cmt_to_repr(&self, cmt: cmt) -> ~str { - fmt!("{%s id:%d m:%? lp:%s ty:%s}", - self.cat_to_repr(cmt.cat), - cmt.id, - cmt.mutbl, - cmt.lp.map_default(~"none", |p| self.lp_to_str(*p) ), - ty_to_str(self.tcx, cmt.ty)) - } - fn cmt_to_str(&self, cmt: cmt) -> ~str { - let mut_str = cmt.mutbl.to_user_str(); match cmt.cat { - cat_special(sk_method) => ~"method", - cat_special(sk_static_item) => ~"static item", - cat_special(sk_implicit_self) => ~"self reference", - cat_special(sk_heap_upvar) => { + cat_static_item => ~"static item", + cat_implicit_self => ~"self reference", + cat_copied_upvar(_) => { ~"captured outer variable in a heap closure" } cat_rvalue => ~"non-lvalue", - cat_local(_) => mut_str + ~" local variable", - cat_binding(_) => ~"pattern binding", + cat_local(_) => ~"local variable", cat_self(_) => ~"self value", - cat_arg(_) => ~"argument", - cat_deref(_, _, pk) => fmt!("dereference of %s %s pointer", - mut_str, self.ptr_sigil(pk)), - cat_stack_upvar(_) => { - ~"captured outer " + mut_str + ~" variable in a stack closure" - } - cat_comp(_, comp_field(*)) => mut_str + ~" field", - cat_comp(_, comp_tuple) => ~"tuple content", - cat_comp(_, comp_anon_field) => ~"anonymous field", - cat_comp(_, comp_variant(_)) => ~"enum content", - cat_comp(_, comp_index(t, _)) => { + cat_arg(*) => ~"argument", + cat_deref(_, _, pk) => fmt!("dereference of %s pointer", + ptr_sigil(pk)), + cat_interior(_, interior_field(*)) => ~"field", + cat_interior(_, interior_tuple) => ~"tuple content", + cat_interior(_, interior_anon_field) => ~"anonymous field", + cat_interior(_, interior_variant(_)) => ~"enum content", + cat_interior(_, interior_index(t, _)) => { match ty::get(t).sty { - ty::ty_evec(*) => mut_str + ~" vec content", - ty::ty_estr(*) => mut_str + ~" str content", - _ => mut_str + ~" indexed content" + ty::ty_evec(*) => ~"vec content", + ty::ty_estr(*) => ~"str content", + _ => ~"indexed content" } } + cat_stack_upvar(_) => { + ~"captured outer variable" + } cat_discr(cmt, _) => { self.cmt_to_str(cmt) } @@ -1119,24 +980,16 @@ pub fn field_mutbl(tcx: ty::ctxt, ty::ty_struct(did, _) => { for ty::lookup_struct_fields(tcx, did).each |fld| { if fld.ident == f_name { - let m = match fld.mutability { - ast::struct_mutable => ast::m_mutbl, - ast::struct_immutable => ast::m_imm - }; - return Some(m); + return Some(ast::m_imm); } } } ty::ty_enum(*) => { - match *tcx.def_map.get(&node_id) { + match tcx.def_map.get_copy(&node_id) { ast::def_variant(_, variant_id) => { for ty::lookup_struct_fields(tcx, variant_id).each |fld| { if fld.ident == f_name { - let m = match fld.mutability { - ast::struct_mutable => ast::m_mutbl, - ast::struct_immutable => ast::m_imm - }; - return Some(m); + return Some(ast::m_imm); } } } @@ -1149,34 +1002,141 @@ pub fn field_mutbl(tcx: ty::ctxt, return None; } -pub impl categorization { - fn derefs_through_mutable_box(&const self) -> bool { - match *self { - cat_deref(_, _, gc_ptr(ast::m_mutbl)) => { - true - } - cat_deref(subcmt, _, _) | - cat_comp(subcmt, _) | - cat_discr(subcmt, _) | - cat_stack_upvar(subcmt) => { - subcmt.cat.derefs_through_mutable_box() - } +pub enum AliasableReason { + AliasableManaged(ast::mutability), + AliasableBorrowed(ast::mutability), + AliasableOther +} + +pub impl cmt_ { + fn guarantor(@self) -> cmt { + //! Returns `self` after stripping away any owned pointer derefs or + //! interior content. The return value is basically the `cmt` which + //! determines how long the value in `self` remains live. + + match self.cat { cat_rvalue | - cat_special(*) | + cat_static_item | + cat_implicit_self | + cat_copied_upvar(*) | cat_local(*) | - cat_binding(*) | + cat_self(*) | cat_arg(*) | - cat_self(*) => { - false + cat_deref(_, _, unsafe_ptr(*)) | + cat_deref(_, _, gc_ptr(*)) | + cat_deref(_, _, region_ptr(*)) => { + self + } + cat_stack_upvar(b) | + cat_discr(b, _) | + cat_interior(b, _) | + cat_deref(b, _, uniq_ptr(*)) => { + b.guarantor() + } + } + } + + fn is_freely_aliasable(&self) -> bool { + self.freely_aliasable().is_some() + } + + fn freely_aliasable(&self) -> Option { + //! True if this lvalue resides in an area that is + //! freely aliasable, meaning that rustc cannot track + //! the alias//es with precision. + + // Maybe non-obvious: copied upvars can only be considered + // non-aliasable in once closures, since any other kind can be + // aliased and eventually recused. + + match self.cat { + cat_copied_upvar(CopiedUpvar {onceness: ast::Once, _}) | + cat_rvalue(*) | + cat_local(*) | + cat_arg(_) | + cat_self(*) | + cat_deref(_, _, unsafe_ptr(*)) | // of course it is aliasable, but... + cat_deref(_, _, region_ptr(m_mutbl, _)) => { + None + } + + cat_copied_upvar(CopiedUpvar {onceness: ast::Many, _}) | + cat_static_item(*) | + cat_implicit_self(*) => { + Some(AliasableOther) + } + + cat_deref(_, _, gc_ptr(m)) => { + Some(AliasableManaged(m)) + } + + cat_deref(_, _, region_ptr(m @ m_const, _)) | + cat_deref(_, _, region_ptr(m @ m_imm, _)) => { + Some(AliasableBorrowed(m)) + } + + cat_stack_upvar(b) | + cat_deref(b, _, uniq_ptr(*)) | + cat_interior(b, _) | + cat_discr(b, _) => { + b.freely_aliasable() } } } +} - fn is_mutable_box(&const self) -> bool { +impl Repr for cmt { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("{%s id:%d m:%? ty:%s}", + self.cat.repr(tcx), + self.id, + self.mutbl, + self.ty.repr(tcx)) + } +} + +impl Repr for categorization { + fn repr(&self, tcx: ty::ctxt) -> ~str { match *self { - cat_deref(_, _, gc_ptr(ast::m_mutbl)) => true, - _ => false + cat_static_item | + cat_implicit_self | + cat_rvalue | + cat_copied_upvar(*) | + cat_local(*) | + cat_self(*) | + cat_arg(*) => fmt!("%?", *self), + cat_deref(cmt, derefs, ptr) => { + fmt!("%s->(%s, %u)", cmt.cat.repr(tcx), + ptr_sigil(ptr), derefs) + } + cat_interior(cmt, interior) => { + fmt!("%s.%s", + cmt.cat.repr(tcx), + interior.repr(tcx)) + } + cat_stack_upvar(cmt) | + cat_discr(cmt, _) => cmt.cat.repr(tcx) } } } +pub fn ptr_sigil(ptr: ptr_kind) -> ~str { + match ptr { + uniq_ptr(_) => ~"~", + gc_ptr(_) => ~"@", + region_ptr(_, _) => ~"&", + unsafe_ptr => ~"*" + } +} + +impl Repr for interior_kind { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match *self { + interior_field(fld) => copy *tcx.sess.str_of(fld), + interior_index(*) => ~"[]", + interior_tuple => ~"()", + interior_anon_field => ~"", + interior_variant(_) => ~"" + } + } +} diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index fe1466bf808a3..3a2fb654006ec 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -246,10 +246,19 @@ pub type MovesMap = @mut HashSet; * expression */ pub type VariableMovesMap = @mut HashMap; +/** + * Set of variable node-ids that are moved. + * + * Note: The `VariableMovesMap` stores expression ids that + * are moves, whereas this set stores the ids of the variables + * that are moved at some point */ +pub type MovedVariablesSet = @mut HashSet; + /** See the section Output on the module comment for explanation. */ pub struct MoveMaps { moves_map: MovesMap, variable_moves_map: VariableMovesMap, + moved_variables_set: MovedVariablesSet, capture_map: CaptureMap } @@ -279,13 +288,25 @@ pub fn compute_moves(tcx: ty::ctxt, move_maps: MoveMaps { moves_map: @mut HashSet::new(), variable_moves_map: @mut HashMap::new(), - capture_map: @mut HashMap::new() + capture_map: @mut HashMap::new(), + moved_variables_set: @mut HashSet::new() } }; visit::visit_crate(crate, visit_cx, visitor); return visit_cx.move_maps; } +pub fn moved_variable_node_id_from_def(def: def) -> Option { + match def { + def_binding(nid, _) | + def_arg(nid, _) | + def_local(nid, _) | + def_self(nid, _) => Some(nid), + + _ => None + } +} + // ______________________________________________________________________ // Expressions @@ -414,17 +435,22 @@ pub impl VisitContext { debug!("comp_mode = %?", comp_mode); match expr.node { - expr_path(*) => { + expr_path(*) | expr_self => { match comp_mode { MoveInPart(entire_expr) => { self.move_maps.variable_moves_map.insert( expr.id, entire_expr); + + let def = self.tcx.def_map.get_copy(&expr.id); + for moved_variable_node_id_from_def(def).each |&id| { + self.move_maps.moved_variables_set.insert(id); + } } Read => {} MoveInWhole => { self.tcx.sess.span_bug( expr.span, - fmt!("Component mode can never be MoveInWhole")); + "Component mode can never be MoveInWhole"); } } } @@ -624,11 +650,6 @@ pub impl VisitContext { self.consume_expr(count, visitor); } - expr_swap(lhs, rhs) => { - self.use_expr(lhs, Read, visitor); - self.use_expr(rhs, Read, visitor); - } - expr_loop_body(base) | expr_do_body(base) => { self.use_expr(base, comp_mode, visitor); @@ -647,7 +668,7 @@ pub impl VisitContext { expr_mac(*) => { self.tcx.sess.span_bug( expr.span, - ~"macro expression remains after expansion"); + "macro expression remains after expansion"); } } } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 3ca79982b7b9a..b87adb75bc37a 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -86,4 +86,3 @@ pub fn pat_binding_ids(dm: resolve::DefMap, pat: @pat) -> ~[node_id] { pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| found.push(b_id) ); return found; } - diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index a37ebdcfaa263..ce0f124da74c9 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -99,8 +99,8 @@ pub fn check_crate(tcx: ty::ctxt, parental_privacy == Public) == Private { tcx.sess.span_err(span, - ~"can only dereference enums \ - with a single, public variant"); + "can only dereference enums \ + with a single, public variant"); } }; @@ -121,8 +121,8 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.parse_sess.interner))); } None => { - tcx.sess.span_bug(span, ~"method not found in \ - AST map?!"); + tcx.sess.span_bug(span, "method not found in \ + AST map?!"); } } }; @@ -140,8 +140,8 @@ pub fn check_crate(tcx: ty::ctxt, // Look up the enclosing impl. if container_id.crate != local_crate { tcx.sess.span_bug(span, - ~"local method isn't in local \ - impl?!"); + "local method isn't in local \ + impl?!"); } match tcx.items.find(&container_id.node) { @@ -155,10 +155,10 @@ pub fn check_crate(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, ~"impl wasn't an item?!"); + tcx.sess.span_bug(span, "impl wasn't an item?!"); } None => { - tcx.sess.span_bug(span, ~"impl wasn't in AST map?!"); + tcx.sess.span_bug(span, "impl wasn't in AST map?!"); } } } @@ -185,8 +185,8 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.parse_sess.interner))); } None => { - tcx.sess.span_bug(span, ~"method not found in \ - AST map?!"); + tcx.sess.span_bug(span, "method not found in \ + AST map?!"); } } }; @@ -219,7 +219,7 @@ pub fn check_crate(tcx: ty::ctxt, .interner))); } None => { - tcx.sess.span_bug(span, ~"item not found in AST map?!"); + tcx.sess.span_bug(span, "item not found in AST map?!"); } } }; @@ -333,10 +333,10 @@ pub fn check_crate(tcx: ty::ctxt, match item.node { item_trait(_, _, ref methods) => { if method_num >= (*methods).len() { - tcx.sess.span_bug(span, ~"method \ - number \ - out of \ - range?!"); + tcx.sess.span_bug(span, "method \ + number \ + out of \ + range?!"); } match (*methods)[method_num] { provided(method) @@ -363,20 +363,20 @@ pub fn check_crate(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(span, ~"trait wasn't \ - actually a \ - trait?!"); + tcx.sess.span_bug(span, "trait wasn't \ + actually a \ + trait?!"); } } } Some(_) => { - tcx.sess.span_bug(span, ~"trait wasn't an \ - item?!"); + tcx.sess.span_bug(span, "trait wasn't an \ + item?!"); } None => { - tcx.sess.span_bug(span, ~"trait item wasn't \ - found in the AST \ - map?!"); + tcx.sess.span_bug(span, "trait item wasn't \ + found in the AST \ + map?!"); } } } else { @@ -465,8 +465,8 @@ pub fn check_crate(tcx: ty::ctxt, match method_map.find(&expr.id) { None => { tcx.sess.span_bug(expr.span, - ~"method call not in \ - method map"); + "method call not in \ + method map"); } Some(ref entry) => { debug!("(privacy checking) checking \ @@ -481,7 +481,7 @@ pub fn check_crate(tcx: ty::ctxt, } } expr_path(path) => { - check_path(expr.span, *tcx.def_map.get(&expr.id), path); + check_path(expr.span, tcx.def_map.get_copy(&expr.id), path); } expr_struct(_, ref fields, _) => { match ty::get(ty::expr_ty(tcx, expr)).sty { @@ -499,7 +499,7 @@ pub fn check_crate(tcx: ty::ctxt, ty_enum(id, _) => { if id.crate != local_crate || !privileged_items.contains(&(id.node)) { - match *tcx.def_map.get(&expr.id) { + match tcx.def_map.get_copy(&expr.id) { def_variant(_, variant_id) => { for (*fields).each |field| { debug!("(privacy checking) \ @@ -512,18 +512,18 @@ pub fn check_crate(tcx: ty::ctxt, } _ => { tcx.sess.span_bug(expr.span, - ~"resolve didn't \ - map enum struct \ - constructor to a \ - variant def"); + "resolve didn't \ + map enum struct \ + constructor to a \ + variant def"); } } } } _ => { - tcx.sess.span_bug(expr.span, ~"struct expr \ - didn't have \ - struct type?!"); + tcx.sess.span_bug(expr.span, "struct expr \ + didn't have \ + struct type?!"); } } } @@ -579,18 +579,18 @@ pub fn check_crate(tcx: ty::ctxt, } _ => { tcx.sess.span_bug(pattern.span, - ~"resolve didn't \ - map enum struct \ - pattern to a \ - variant def"); + "resolve didn't \ + map enum struct \ + pattern to a \ + variant def"); } } } } _ => { tcx.sess.span_bug(pattern.span, - ~"struct pattern didn't have \ - struct type?!"); + "struct pattern didn't have \ + struct type?!"); } } } @@ -603,4 +603,3 @@ pub fn check_crate(tcx: ty::ctxt, }); visit::visit_crate(crate, method_map, visitor); } - diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f32998281711f..74082c02f6d04 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -47,59 +47,27 @@ The region maps encode information about region relationships. - the free region map is populated during type check as we check each function. See the function `relate_free_regions` for more information. +- `cleanup_scopes` includes scopes where trans cleanups occur + - this is intended to reflect the current state of trans, not + necessarily how I think things ought to work */ pub struct RegionMaps { priv scope_map: HashMap, priv free_region_map: HashMap, + priv cleanup_scopes: HashSet } -pub struct ctxt { +pub struct Context { sess: Session, def_map: resolve::DefMap, // Generated maps: region_maps: @mut RegionMaps, - // Generally speaking, expressions are parented to their innermost - // enclosing block. But some kinds of expressions serve as - // parents: calls, methods, etc. In addition, some expressions - // serve as parents by virtue of where they appear. For example, - // the condition in a while loop is always a parent. In those - // cases, we add the node id of such an expression to this set so - // that when we visit it we can view it as a parent. - root_exprs: @mut HashSet, - - // The parent scope is the innermost block, statement, call, or match - // expression during the execution of which the current expression - // will be evaluated. Generally speaking, the innermost parent - // scope is also the closest suitable ancestor in the AST tree. - // - // There is a subtle point concerning call arguments. Imagine - // you have a call: - // - // { // block a - // foo( // call b - // x, - // y); - // } - // - // In what lifetime are the expressions `x` and `y` evaluated? At - // first, I imagine the answer was the block `a`, as the arguments - // are evaluated before the call takes place. But this turns out - // to be wrong. The lifetime of the call must encompass the - // argument evaluation as well. - // - // The reason is that evaluation of an earlier argument could - // create a borrow which exists during the evaluation of later - // arguments. Consider this torture test, for example, - // - // fn test1(x: @mut ~int) { - // foo(&**x, *x = ~5); - // } - // - // Here, the first argument `&**x` will be a borrow of the `~int`, - // but the second argument overwrites that very value! Bad. - // (This test is borrowck-pure-scope-in-call.rs, btw) + // Scope where variables should be parented to + var_parent: parent, + + // Innermost enclosing expression parent: parent, } @@ -128,10 +96,22 @@ pub impl RegionMaps { sup: ast::node_id) { debug!("record_parent(sub=%?, sup=%?)", sub, sup); + assert!(sub != sup); self.scope_map.insert(sub, sup); } + pub fn record_cleanup_scope(&mut self, + scope_id: ast::node_id) + { + //! Records that a scope is a CLEANUP SCOPE. This is invoked + //! from within regionck. We wait until regionck because we do + //! not know which operators are overloaded until that point, + //! and only overloaded operators result in cleanup scopes. + + self.cleanup_scopes.insert(scope_id); + } + fn opt_encl_scope(&self, id: ast::node_id) -> Option { @@ -151,6 +131,22 @@ pub impl RegionMaps { } } + fn is_cleanup_scope(&self, scope_id: ast::node_id) -> bool { + self.cleanup_scopes.contains(&scope_id) + } + + fn cleanup_scope(&self, + expr_id: ast::node_id) -> ast::node_id + { + //! Returns the scope when temps in expr will be cleaned up + + let mut id = self.encl_scope(expr_id); + while !self.cleanup_scopes.contains(&id) { + id = self.encl_scope(id); + } + return id; + } + fn encl_region(&self, id: ast::node_id) -> ty::Region { @@ -159,22 +155,38 @@ pub impl RegionMaps { ty::re_scope(self.encl_scope(id)) } - fn is_sub_scope(&self, - sub_scope: ast::node_id, - superscope: ast::node_id) -> bool + pub fn scopes_intersect(&self, + scope1: ast::node_id, + scope2: ast::node_id) -> bool + { + self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1) + } + + fn is_subscope_of(&self, + subscope: ast::node_id, + superscope: ast::node_id) -> bool { /*! - * Returns true if `sub_scope` is equal to or is lexically + * Returns true if `subscope` is equal to or is lexically * nested inside `superscope` and false otherwise. */ - let mut sub_scope = sub_scope; - while superscope != sub_scope { - match self.scope_map.find(&sub_scope) { - None => return false, - Some(&scope) => sub_scope = scope + let mut s = subscope; + while superscope != s { + match self.scope_map.find(&s) { + None => { + debug!("is_subscope_of(%?, %?, s=%?)=false", + subscope, superscope, s); + + return false; + } + Some(&scope) => s = scope } } + + debug!("is_subscope_of(%?, %?)=true", + subscope, superscope); + return true; } @@ -239,11 +251,11 @@ pub impl RegionMaps { } (ty::re_scope(sub_scope), ty::re_scope(super_scope)) => { - self.is_sub_scope(sub_scope, super_scope) + self.is_subscope_of(sub_scope, super_scope) } (ty::re_scope(sub_scope), ty::re_free(ref fr)) => { - self.is_sub_scope(sub_scope, fr.scope_id) + self.is_subscope_of(sub_scope, fr.scope_id) } (ty::re_free(sub_fr), ty::re_free(super_fr)) => { @@ -298,29 +310,31 @@ pub impl RegionMaps { } } - fn ancestors_of(self: &RegionMaps, scope: ast::node_id) + fn ancestors_of(this: &RegionMaps, scope: ast::node_id) -> ~[ast::node_id] { + // debug!("ancestors_of(scope=%d)", scope); let mut result = ~[scope]; let mut scope = scope; loop { - match self.scope_map.find(&scope) { + match this.scope_map.find(&scope) { None => return result, Some(&superscope) => { result.push(superscope); scope = superscope; } } + // debug!("ancestors_of_loop(scope=%d)", scope); } } } } /// Extracts that current parent from cx, failing if there is none. -pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { +pub fn parent_id(cx: Context, span: span) -> ast::node_id { match cx.parent { None => { - cx.sess.span_bug(span, ~"crate should not be parent here"); + cx.sess.span_bug(span, "crate should not be parent here"); } Some(parent_id) => { parent_id @@ -329,144 +343,136 @@ pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { } /// Records the current parent (if any) as the parent of `child_id`. -pub fn record_parent(cx: ctxt, child_id: ast::node_id) { +pub fn parent_to_expr(cx: Context, child_id: ast::node_id) { for cx.parent.each |parent_id| { cx.region_maps.record_parent(child_id, *parent_id); } } -pub fn resolve_block(blk: &ast::blk, cx: ctxt, visitor: visit::vt) { +pub fn resolve_block(blk: &ast::blk, cx: Context, visitor: visit::vt) { // Record the parent of this block. - record_parent(cx, blk.node.id); + parent_to_expr(cx, blk.node.id); // Descend. - let new_cx: ctxt = ctxt {parent: Some(blk.node.id),.. cx}; + let new_cx = Context {var_parent: Some(blk.node.id), + parent: Some(blk.node.id), + ..cx}; visit::visit_block(blk, new_cx, visitor); } -pub fn resolve_arm(arm: &ast::arm, cx: ctxt, visitor: visit::vt) { +pub fn resolve_arm(arm: &ast::arm, cx: Context, visitor: visit::vt) { visit::visit_arm(arm, cx, visitor); } -pub fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt) { - match pat.node { - ast::pat_ident(*) => { - let defn_opt = cx.def_map.find(&pat.id); - match defn_opt { - Some(&ast::def_variant(_,_)) => { - /* Nothing to do; this names a variant. */ - } - _ => { - /* This names a local. Bind it to the containing scope. */ - record_parent(cx, pat.id); - } - } - } - _ => { /* no-op */ } - } - +pub fn resolve_pat(pat: @ast::pat, cx: Context, visitor: visit::vt) { + assert!(cx.var_parent == cx.parent); + parent_to_expr(cx, pat.id); visit::visit_pat(pat, cx, visitor); } -pub fn resolve_stmt(stmt: @ast::stmt, cx: ctxt, visitor: visit::vt) { +pub fn resolve_stmt(stmt: @ast::stmt, cx: Context, visitor: visit::vt) { match stmt.node { - ast::stmt_decl(*) => { - visit::visit_stmt(stmt, cx, visitor); - } - // This code has to be kept consistent with trans::base::trans_stmt - ast::stmt_expr(_, stmt_id) | - ast::stmt_semi(_, stmt_id) => { - record_parent(cx, stmt_id); - let mut expr_cx = cx; - expr_cx.parent = Some(stmt_id); - visit::visit_stmt(stmt, expr_cx, visitor); - } - ast::stmt_mac(*) => cx.sess.bug(~"unexpanded macro") + ast::stmt_decl(*) => { + visit::visit_stmt(stmt, cx, visitor); + } + ast::stmt_expr(_, stmt_id) | + ast::stmt_semi(_, stmt_id) => { + parent_to_expr(cx, stmt_id); + let expr_cx = Context {parent: Some(stmt_id), ..cx}; + visit::visit_stmt(stmt, expr_cx, visitor); + } + ast::stmt_mac(*) => cx.sess.bug(~"unexpanded macro") } } -pub fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt) { - record_parent(cx, expr.id); +pub fn resolve_expr(expr: @ast::expr, cx: Context, visitor: visit::vt) { + parent_to_expr(cx, expr.id); let mut new_cx = cx; + new_cx.parent = Some(expr.id); match expr.node { - // Calls or overloadable operators - // FIXME #3387 - // ast::expr_index(*) | ast::expr_binary(*) | - // ast::expr_unary(*) | - ast::expr_call(*) | ast::expr_method_call(*) => { - debug!("node %d: %s", expr.id, pprust::expr_to_str(expr, - cx.sess.intr())); - new_cx.parent = Some(expr.id); - } - ast::expr_match(*) => { - debug!("node %d: %s", expr.id, pprust::expr_to_str(expr, - cx.sess.intr())); - new_cx.parent = Some(expr.id); - } - ast::expr_while(cond, _) => { - new_cx.root_exprs.insert(cond.id); - } - _ => {} + ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) | + ast::expr_unary(*) | ast::expr_call(*) | ast::expr_method_call(*) => { + // FIXME(#6268) Nested method calls + // + // The lifetimes for a call or method call look as follows: + // + // call.id + // - arg0.id + // - ... + // - argN.id + // - call.callee_id + // + // The idea is that call.callee_id represents *the time when + // the invoked function is actually running* and call.id + // represents *the time to prepare the arguments and make the + // call*. See the section "Borrows in Calls" borrowck/doc.rs + // for an extended explanantion of why this distinction is + // important. + // + // parent_to_expr(new_cx, expr.callee_id); + } + + ast::expr_match(*) => { + new_cx.var_parent = Some(expr.id); + } + + _ => {} }; - if new_cx.root_exprs.contains(&expr.id) { - new_cx.parent = Some(expr.id); - } visit::visit_expr(expr, new_cx, visitor); } pub fn resolve_local(local: @ast::local, - cx: ctxt, - visitor: visit::vt) { - record_parent(cx, local.node.id); + cx: Context, + visitor: visit::vt) { + assert!(cx.var_parent == cx.parent); + parent_to_expr(cx, local.node.id); visit::visit_local(local, cx, visitor); } -pub fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt) { +pub fn resolve_item(item: @ast::item, cx: Context, visitor: visit::vt) { // Items create a new outer block scope as far as we're concerned. - let new_cx: ctxt = ctxt {parent: None,.. cx}; + let new_cx = Context {var_parent: None, parent: None, ..cx}; visit::visit_item(item, new_cx, visitor); } pub fn resolve_fn(fk: &visit::fn_kind, decl: &ast::fn_decl, body: &ast::blk, - sp: span, + _sp: span, id: ast::node_id, - cx: ctxt, - visitor: visit::vt) { - let fn_cx = match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { - // Top-level functions are a root scope. - ctxt {parent: Some(id),.. cx} - } - - visit::fk_anon(*) | visit::fk_fn_block(*) => { - // Closures continue with the inherited scope. - cx - } - }; - - // Record the ID of `self`. + cx: Context, + visitor: visit::vt) { + debug!("region::resolve_fn(id=%?, body.node.id=%?, cx.parent=%?)", + id, body.node.id, cx.parent); + + // The arguments and `self` are parented to the body of the fn. + let decl_cx = Context {parent: Some(body.node.id), + var_parent: Some(body.node.id), + ..cx}; match *fk { visit::fk_method(_, _, method) => { cx.region_maps.record_parent(method.self_id, body.node.id); } _ => {} } + visit::visit_fn_decl(decl, decl_cx, visitor); - debug!("visiting fn with body %d. cx.parent: %? \ - fn_cx.parent: %?", - body.node.id, cx.parent, fn_cx.parent); - - for decl.inputs.each |input| { - cx.region_maps.record_parent(input.id, body.node.id); - } - - visit::visit_fn(fk, decl, body, sp, id, fn_cx, visitor); + // The body of the fn itself is either a root scope (top-level fn) + // or it continues with the inherited scope (closures). + let body_cx = match *fk { + visit::fk_item_fn(*) | + visit::fk_method(*) => { + Context {parent: None, var_parent: None, ..cx} + } + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + cx + } + }; + (visitor.visit_block)(body, body_cx, visitor); } pub fn resolve_crate(sess: Session, @@ -475,13 +481,14 @@ pub fn resolve_crate(sess: Session, { let region_maps = @mut RegionMaps { scope_map: HashMap::new(), - free_region_map: HashMap::new() + free_region_map: HashMap::new(), + cleanup_scopes: HashSet::new(), }; - let cx: ctxt = ctxt {sess: sess, - def_map: def_map, - region_maps: region_maps, - root_exprs: @mut HashSet::new(), - parent: None}; + let cx = Context {sess: sess, + def_map: def_map, + region_maps: region_maps, + parent: None, + var_parent: None}; let visitor = visit::mk_vt(@visit::Visitor { visit_block: resolve_block, visit_item: resolve_item, @@ -678,7 +685,7 @@ pub impl DetermineRpCtxt { None => { self.anon_implies_rp } - Some(ref l) if l.ident == special_idents::static => { + Some(ref l) if l.ident == special_idents::statik => { false } Some(ref l) if l.ident == special_idents::self_ => { @@ -772,7 +779,8 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, pprust::ty_to_str(ty, sess.intr())); if cx.region_is_relevant(r) { - cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant)) + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } @@ -782,14 +790,14 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, match f.region { Some(_) => { if cx.region_is_relevant(f.region) { - cx.add_rp(cx.item_id, - cx.add_variance(rv_contravariant)) + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } None => { if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp { - cx.add_rp(cx.item_id, - cx.add_variance(rv_contravariant)); + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } } @@ -820,7 +828,8 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, debug!("reference to external, rp'd type %s", pprust::ty_to_str(ty, sess.intr())); if cx.region_is_relevant(path.rp) { - cx.add_rp(cx.item_id, cx.add_variance(variance)) + let rv = cx.add_variance(variance); + cx.add_rp(cx.item_id, rv) } } } @@ -885,17 +894,7 @@ pub fn determine_rp_in_struct_field( cm: @ast::struct_field, cx: @mut DetermineRpCtxt, visitor: visit::vt<@mut DetermineRpCtxt>) { - match cm.node.kind { - ast::named_field(_, ast::struct_mutable, _) => { - do cx.with_ambient_variance(rv_invariant) { - visit::visit_struct_field(cm, cx, visitor); - } - } - ast::named_field(_, ast::struct_immutable, _) | - ast::unnamed_field => { - visit::visit_struct_field(cm, cx, visitor); - } - } + visit::visit_struct_field(cm, cx, visitor); } pub fn determine_rp_in_crate(sess: Session, @@ -939,7 +938,7 @@ pub fn determine_rp_in_crate(sess: Session, let cx = &mut *cx; while cx.worklist.len() != 0 { let c_id = cx.worklist.pop(); - let c_variance = *cx.region_paramd_items.get(&c_id); + let c_variance = cx.region_paramd_items.get_copy(&c_id); debug!("popped %d from worklist", c_id); match cx.dep_map.find(&c_id) { None => {} @@ -969,4 +968,3 @@ pub fn determine_rp_in_crate(sess: Session, // return final set return cx.region_paramd_items; } - diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 294a21fac2c23..d2c8320d8baf5 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use driver::session; use driver::session::Session; use metadata::csearch::{each_path, get_trait_method_def_ids}; use metadata::csearch::get_method_name_and_self_ty; @@ -33,10 +32,10 @@ use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; use syntax::ast::{expr_binary, expr_break, expr_field}; use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; -use syntax::ast::{def_upvar, def_use, def_variant, quot, eq}; +use syntax::ast::{def_upvar, def_use, def_variant, div, eq}; use syntax::ast::{expr, expr_again, expr_assign_op}; use syntax::ast::{expr_index, expr_loop}; -use syntax::ast::{expr_path, expr_struct, expr_unary, fn_decl}; +use syntax::ast::{expr_path, expr_self, expr_struct, expr_unary, fn_decl}; use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge}; use syntax::ast::Generics; use syntax::ast::{gt, ident, inherited, item, item_struct}; @@ -47,7 +46,7 @@ use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident}; use syntax::ast::{Path, pat_lit, pat_range, pat_struct}; use syntax::ast::{prim_ty, private, provided}; use syntax::ast::{public, required, rem, self_ty_, shl, shr, stmt_decl}; -use syntax::ast::{struct_dtor, struct_field, struct_variant_kind}; +use syntax::ast::{struct_field, struct_variant_kind}; use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty}; use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path}; @@ -61,11 +60,11 @@ use syntax::ast_util::{def_id_of_def, local_def}; use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; use syntax::ast_util::{Privacy, Public, Private}; use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; -use syntax::attr::{attr_metas, contains_name, attrs_contains_name}; +use syntax::attr::{attr_metas, contains_name}; use syntax::parse::token::ident_interner; use syntax::parse::token::special_idents; use syntax::print::pprust::path_to_str; -use syntax::codemap::{span, dummy_sp}; +use syntax::codemap::{span, dummy_sp, BytePos}; use syntax::visit::{default_visitor, mk_vt, Visitor, visit_block}; use syntax::visit::{visit_crate, visit_expr, visit_expr_opt}; use syntax::visit::{visit_foreign_item, visit_item}; @@ -327,12 +326,14 @@ pub fn namespace_for_duplicate_checking_mode(mode: DuplicateCheckingMode) /// One local scope. pub struct Rib { bindings: @mut HashMap, + self_binding: @mut Option, kind: RibKind, } pub fn Rib(kind: RibKind) -> Rib { Rib { bindings: @mut HashMap::new(), + self_binding: @mut None, kind: kind } } @@ -709,7 +710,7 @@ pub struct PrimitiveTypeTable { } pub impl PrimitiveTypeTable { - fn intern(&mut self, intr: @ident_interner, string: @~str, + fn intern(&mut self, intr: @ident_interner, string: &str, primitive_type: prim_ty) { let ident = intr.intern(string); self.primitive_types.insert(ident, primitive_type); @@ -721,22 +722,22 @@ pub fn PrimitiveTypeTable(intr: @ident_interner) -> PrimitiveTypeTable { primitive_types: HashMap::new() }; - table.intern(intr, @~"bool", ty_bool); - table.intern(intr, @~"char", ty_int(ty_char)); - table.intern(intr, @~"float", ty_float(ty_f)); - table.intern(intr, @~"f32", ty_float(ty_f32)); - table.intern(intr, @~"f64", ty_float(ty_f64)); - table.intern(intr, @~"int", ty_int(ty_i)); - table.intern(intr, @~"i8", ty_int(ty_i8)); - table.intern(intr, @~"i16", ty_int(ty_i16)); - table.intern(intr, @~"i32", ty_int(ty_i32)); - table.intern(intr, @~"i64", ty_int(ty_i64)); - table.intern(intr, @~"str", ty_str); - table.intern(intr, @~"uint", ty_uint(ty_u)); - table.intern(intr, @~"u8", ty_uint(ty_u8)); - table.intern(intr, @~"u16", ty_uint(ty_u16)); - table.intern(intr, @~"u32", ty_uint(ty_u32)); - table.intern(intr, @~"u64", ty_uint(ty_u64)); + table.intern(intr, "bool", ty_bool); + table.intern(intr, "char", ty_int(ty_char)); + table.intern(intr, "float", ty_float(ty_f)); + table.intern(intr, "f32", ty_float(ty_f32)); + table.intern(intr, "f64", ty_float(ty_f64)); + table.intern(intr, "int", ty_int(ty_i)); + table.intern(intr, "i8", ty_int(ty_i8)); + table.intern(intr, "i16", ty_int(ty_i16)); + table.intern(intr, "i32", ty_int(ty_i32)); + table.intern(intr, "i64", ty_int(ty_i64)); + table.intern(intr, "str", ty_str); + table.intern(intr, "uint", ty_uint(ty_u)); + table.intern(intr, "u8", ty_uint(ty_u8)); + table.intern(intr, "u16", ty_uint(ty_u16)); + table.intern(intr, "u32", ty_uint(ty_u32)); + table.intern(intr, "u64", ty_uint(ty_u64)); return table; } @@ -763,7 +764,7 @@ pub fn Resolver(session: Session, let current_module = graph_root.get_module(); - let self = Resolver { + let this = Resolver { session: @session, lang_items: copy lang_items, crate: crate, @@ -779,9 +780,9 @@ pub fn Resolver(session: Session, unresolved_imports: 0, current_module: current_module, - value_ribs: ~[], - type_ribs: ~[], - label_ribs: ~[], + value_ribs: @mut ~[], + type_ribs: @mut ~[], + label_ribs: @mut ~[], xray_context: NoXray, current_trait_refs: None, @@ -794,11 +795,6 @@ pub fn Resolver(session: Session, namespaces: ~[ TypeNS, ValueNS ], - attr_main_fn: None, - main_fns: ~[], - - start_fn: None, - def_map: @mut HashMap::new(), export_map2: @mut HashMap::new(), trait_map: HashMap::new(), @@ -806,7 +802,7 @@ pub fn Resolver(session: Session, intr: session.intr() }; - self + this } /// The main resolver class. @@ -830,13 +826,13 @@ pub struct Resolver { // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. - value_ribs: ~[@Rib], + value_ribs: @mut ~[@Rib], // The current set of local scopes, for types. - type_ribs: ~[@Rib], + type_ribs: @mut ~[@Rib], // The current set of local scopes, for labels. - label_ribs: ~[@Rib], + label_ribs: @mut ~[@Rib], // Whether the current context is an X-ray context. An X-ray context is // allowed to access private names of any module. @@ -856,15 +852,6 @@ pub struct Resolver { // The four namespaces. namespaces: ~[Namespace], - // The function that has attribute named 'main' - attr_main_fn: Option<(node_id, span)>, - - // The functions that could be main functions - main_fns: ~[Option<(node_id, span)>], - - // The function that has the attribute 'start' on it - start_fn: Option<(node_id, span)>, - def_map: DefMap, export_map2: ExportMap2, trait_map: TraitMap, @@ -885,7 +872,6 @@ pub impl Resolver { self.resolve_crate(); self.session.abort_if_errors(); - self.check_duplicate_main(); self.check_for_unused_imports_if_necessary(); } @@ -971,7 +957,7 @@ pub impl Resolver { module_.children.insert(name, child); return (child, new_parent); } - Some(child) => { + Some(&child) => { // Enforce the duplicate checking mode: // // * If we're requesting duplicate module checking, check that @@ -1023,7 +1009,7 @@ pub impl Resolver { let ns = namespace_for_duplicate_checking_mode( duplicate_checking_mode); self.session.span_err(sp, - fmt!("duplicate definition of %s %s", + fmt!("duplicate definition of %s `%s`", namespace_to_str(ns), *self.session.str_of(name))); for child.span_for_namespace(ns).each |sp| { @@ -1033,7 +1019,7 @@ pub impl Resolver { *self.session.str_of(name))); } } - return (*child, new_parent); + return (child, new_parent); } } } @@ -1691,7 +1677,7 @@ pub impl Resolver { let mut current_module = root; for pieces.each |ident_str| { - let ident = self.session.ident_of(/*bad*/copy *ident_str); + let ident = self.session.ident_of(*ident_str); // Create or reuse a graph node for the child. let (child_name_bindings, new_parent) = self.add_child(ident, @@ -1864,7 +1850,7 @@ pub impl Resolver { *self.session.str_of(target)); match module_.import_resolutions.find(&target) { - Some(resolution) => { + Some(&resolution) => { debug!("(building import directive) bumping \ reference"); resolution.outstanding_references += 1; @@ -1925,7 +1911,6 @@ pub impl Resolver { } if self.unresolved_imports == prev_unresolved_imports { - self.session.err(~"failed to resolve imports"); self.report_unresolved_imports(module_root); break; } @@ -1975,7 +1960,7 @@ pub impl Resolver { match self.resolve_import_for_module(module, import_directive) { Failed => { // We presumably emitted an error. Continue. - let msg = fmt!("failed to resolve import: %s", + let msg = fmt!("failed to resolve import `%s`", *self.import_path_to_str( import_directive.module_path, *import_directive.subclass)); @@ -2299,17 +2284,19 @@ pub impl Resolver { } let i = import_resolution; + let mut resolve_fail = false; + let mut priv_fail = false; match (i.value_target, i.type_target) { // If this name wasn't found in either namespace, it's definitely // unresolved. - (None, None) => { return Failed; } + (None, None) => { resolve_fail = true; } // If it's private, it's also unresolved. (Some(t), None) | (None, Some(t)) => { let bindings = &mut *t.bindings; match bindings.type_def { Some(ref type_def) => { if type_def.privacy == Private { - return Failed; + priv_fail = true; } } _ => () @@ -2317,7 +2304,7 @@ pub impl Resolver { match bindings.value_def { Some(ref value_def) => { if value_def.privacy == Private { - return Failed; + priv_fail = true; } } _ => () @@ -2330,13 +2317,25 @@ pub impl Resolver { (Some(ref value_def), Some(ref type_def)) => if value_def.privacy == Private && type_def.privacy == Private { - return Failed; + priv_fail = true; }, _ => () } } } + if resolve_fail { + self.session.err(fmt!("unresolved import: there is no `%s` in `%s`", + *self.session.str_of(source), + self.module_to_str(containing_module))); + return Failed; + } else if priv_fail { + self.session.err(fmt!("unresolved import: found `%s` in `%s` but it is private", + *self.session.str_of(source), + self.module_to_str(containing_module))); + return Failed; + } + assert!(import_resolution.outstanding_references >= 1); import_resolution.outstanding_references -= 1; @@ -2395,7 +2394,7 @@ pub impl Resolver { (*ident, new_import_resolution); } None => { /* continue ... */ } - Some(dest_import_resolution) => { + Some(&dest_import_resolution) => { // Merge the two import resolutions at a finer-grained // level. @@ -2424,23 +2423,23 @@ pub impl Resolver { let merge_import_resolution = |ident, name_bindings: @mut NameBindings| { let dest_import_resolution; - match module_.import_resolutions.find(ident) { + match module_.import_resolutions.find(&ident) { None => { // Create a new import resolution from this child. dest_import_resolution = @mut ImportResolution(privacy, span, state); module_.import_resolutions.insert - (*ident, dest_import_resolution); + (ident, dest_import_resolution); } - Some(existing_import_resolution) => { - dest_import_resolution = *existing_import_resolution; + Some(&existing_import_resolution) => { + dest_import_resolution = existing_import_resolution; } } debug!("(resolving glob import) writing resolution `%s` in `%s` \ to `%s`, privacy=%?", - *self.session.str_of(*ident), + *self.session.str_of(ident), self.module_to_str(containing_module), self.module_to_str(module_), copy dest_import_resolution.privacy); @@ -2459,13 +2458,13 @@ pub impl Resolver { }; // Add all children from the containing module. - for containing_module.children.each |ident, name_bindings| { + for containing_module.children.each |&ident, name_bindings| { merge_import_resolution(ident, *name_bindings); } // Add external module children from the containing module. for containing_module.external_module_children.each - |ident, module| { + |&ident, module| { let name_bindings = @mut Resolver::create_name_bindings_from_module(*module); merge_import_resolution(ident, name_bindings); @@ -2498,7 +2497,18 @@ pub impl Resolver { TypeNS, name_search_type) { Failed => { - self.session.span_err(span, ~"unresolved name"); + let segment_name = self.session.str_of(name); + let module_name = self.module_to_str(search_module); + if module_name == ~"???" { + self.session.span_err(span {lo: span.lo, hi: span.lo + + BytePos(str::len(*segment_name)), expn_info: + span.expn_info}, fmt!("unresolved import. maybe \ + a missing `extern mod %s`?", + *segment_name)); + return Failed; + } + self.session.span_err(span, fmt!("unresolved import: could not find `%s` in \ + `%s`.", *segment_name, module_name)); return Failed; } Indeterminate => { @@ -2517,7 +2527,7 @@ pub impl Resolver { // Not a module. self.session.span_err(span, fmt!("not a \ - module: %s", + module `%s`", *self.session. str_of( name))); @@ -2531,7 +2541,7 @@ pub impl Resolver { None => { // There are no type bindings at all. self.session.span_err(span, - fmt!("not a module: %s", + fmt!("not a module `%s`", *self.session.str_of( name))); return Failed; @@ -2982,7 +2992,7 @@ pub impl Resolver { } // We're out of luck. - debug!("(resolving name in module) failed to resolve %s", + debug!("(resolving name in module) failed to resolve `%s`", *self.session.str_of(name)); return Failed; } @@ -3512,7 +3522,6 @@ pub impl Resolver { self.resolve_struct(item.id, generics, struct_def.fields, - &struct_def.dtor, visitor); } @@ -3545,40 +3554,6 @@ pub impl Resolver { } item_fn(ref fn_decl, _, _, ref generics, ref block) => { - // If this is the main function, we must record it in the - // session. - - // FIXME #4404 android JNI hacks - if !*self.session.building_library || - self.session.targ_cfg.os == session::os_android { - - if self.attr_main_fn.is_none() && - item.ident == special_idents::main { - - self.main_fns.push(Some((item.id, item.span))); - } - - if attrs_contains_name(item.attrs, ~"main") { - if self.attr_main_fn.is_none() { - self.attr_main_fn = Some((item.id, item.span)); - } else { - self.session.span_err( - item.span, - ~"multiple 'main' functions"); - } - } - - if attrs_contains_name(item.attrs, ~"start") { - if self.start_fn.is_none() { - self.start_fn = Some((item.id, item.span)); - } else { - self.session.span_err( - item.span, - ~"multiple 'start' functions"); - } - } - } - self.resolve_function(OpaqueFunctionRibKind, Some(fn_decl), HasTypeParameters @@ -3696,8 +3671,7 @@ pub impl Resolver { HasSelfBinding(self_node_id, is_implicit) => { let def_like = dl_def(def_self(self_node_id, is_implicit)); - (*function_value_rib).bindings.insert(self.self_ident, - def_like); + *function_value_rib.self_binding = Some(def_like); } } @@ -3770,7 +3744,6 @@ pub impl Resolver { id: node_id, generics: &Generics, fields: &[@struct_field], - optional_destructor: &Option, visitor: ResolveVisitor) { // If applicable, create a rib for the type parameters. do self.with_type_parameter_rib(HasTypeParameters @@ -3784,23 +3757,6 @@ pub impl Resolver { for fields.each |field| { self.resolve_type(field.node.ty, visitor); } - - // Resolve the destructor, if applicable. - match *optional_destructor { - None => { - // Nothing to do. - } - Some(ref destructor) => { - self.resolve_function(NormalRibKind, - None, - NoTypeParameters, - &destructor.node.body, - HasSelfBinding - ((*destructor).node.self_id, - true), - visitor); - } - } } } @@ -4217,7 +4173,7 @@ pub impl Resolver { // in the same disjunct, which is an // error self.session.span_err(pattern.span, - fmt!("Identifier %s is bound more \ + fmt!("Identifier `%s` is bound more \ than once in the same pattern", path_to_str(path, self.session .intr()))); @@ -4258,7 +4214,7 @@ pub impl Resolver { Some(_) => { self.session.span_err( path.span, - fmt!("not an enum variant or constant: %s", + fmt!("`%s` is not an enum variant or constant", *self.session.str_of( *path.idents.last()))); } @@ -4286,7 +4242,7 @@ pub impl Resolver { Some(_) => { self.session.span_err( path.span, - fmt!("not an enum variant, struct or const: %s", + fmt!("`%s` is not an enum variant, struct or const", *self.session.str_of( *path.idents.last()))); } @@ -4313,19 +4269,18 @@ pub impl Resolver { } pat_struct(path, _, _) => { - let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { let class_def = def_struct(class_id); self.record_def(pattern.id, class_def); } - Some(definition @ def_struct(class_id)) - if structs.contains(&class_id) => { + Some(definition @ def_struct(class_id)) => { + assert!(self.structs.contains(&class_id)); self.record_def(pattern.id, definition); } Some(definition @ def_variant(_, variant_id)) - if structs.contains(&variant_id) => { + if self.structs.contains(&variant_id) => { self.record_def(pattern.id, definition); } result => { @@ -4622,17 +4577,17 @@ pub impl Resolver { ident: ident, namespace: Namespace, span: span) - -> Option { + -> Option { // Check the local set of ribs. let search_result; match namespace { ValueNS => { - search_result = self.search_ribs(&mut self.value_ribs, ident, + search_result = self.search_ribs(self.value_ribs, ident, span, DontAllowCapturingSelf); } TypeNS => { - search_result = self.search_ribs(&mut self.type_ribs, ident, + search_result = self.search_ribs(self.type_ribs, ident, span, AllowCapturingSelf); } } @@ -4651,6 +4606,35 @@ pub impl Resolver { } } + fn resolve_self_value_in_local_ribs(@mut self, span: span) + -> Option { + // FIXME #4950: This should not use a while loop. + let ribs = &mut self.value_ribs; + let mut i = ribs.len(); + while i != 0 { + i -= 1; + match *ribs[i].self_binding { + Some(def_like) => { + match self.upvarify(*ribs, + i, + def_like, + span, + DontAllowCapturingSelf) { + Some(dl_def(def)) => return Some(def), + _ => { + self.session.span_bug(span, + ~"self wasn't mapped to a \ + def?!") + } + } + } + None => {} + } + } + + None + } + fn resolve_item_by_identifier_in_lexical_scope(@mut self, ident: ident, namespace: Namespace) @@ -4700,7 +4684,7 @@ pub impl Resolver { } let mut smallest = 0; - for vec::eachi(maybes) |i, &other| { + for maybes.eachi |i, &other| { values[i] = str::levdistance(name, other); @@ -4734,10 +4718,10 @@ pub impl Resolver { if item.id == node_id { match item.node { item_struct(class_def, _) => { - for vec::each(class_def.fields) |field| { + for class_def.fields.each |field| { match field.node.kind { unnamed_field => {}, - named_field(ident, _, _) => { + named_field(ident, _) => { if str::eq_slice(*this.session.str_of(ident), name) { return true @@ -4783,8 +4767,8 @@ pub impl Resolver { path.idents); if self.name_exists_in_scope_struct(wrong_name) { self.session.span_err(expr.span, - fmt!("unresolved name: `%s`. \ - Did you mean: `self.%s`?", + fmt!("unresolved name `%s`. \ + Did you mean `self.%s`?", wrong_name, wrong_name)); } @@ -4794,13 +4778,13 @@ pub impl Resolver { match self.find_best_match_for_name(wrong_name, 5) { Some(m) => { self.session.span_err(expr.span, - fmt!("unresolved name: `%s`. \ - Did you mean: `%s`?", + fmt!("unresolved name `%s`. \ + Did you mean `%s`?", wrong_name, m)); } None => { self.session.span_err(expr.span, - fmt!("unresolved name: `%s`.", + fmt!("unresolved name `%s`.", wrong_name)); } } @@ -4822,15 +4806,14 @@ pub impl Resolver { expr_struct(path, _, _) => { // Resolve the path to the structure it goes to. - let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) | Some(def_struct(class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { let class_def = def_struct(class_id); self.record_def(expr.id, class_def); } Some(definition @ def_variant(_, class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { self.record_def(expr.id, definition); } _ => { @@ -4846,17 +4829,19 @@ pub impl Resolver { expr_loop(_, Some(label)) => { do self.with_label_rib { - let this = &mut *self; - let def_like = dl_def(def_label(expr.id)); - let rib = this.label_ribs[this.label_ribs.len() - 1]; - rib.bindings.insert(label, def_like); + { + let this = &mut *self; + let def_like = dl_def(def_label(expr.id)); + let rib = this.label_ribs[this.label_ribs.len() - 1]; + rib.bindings.insert(label, def_like); + } visit_expr(expr, (), visitor); } } expr_break(Some(label)) | expr_again(Some(label)) => { - match self.search_ribs(&mut self.label_ribs, label, expr.span, + match self.search_ribs(self.label_ribs, label, expr.span, DontAllowCapturingSelf) { None => self.session.span_err(expr.span, @@ -4864,12 +4849,25 @@ pub impl Resolver { `%s`", *self.session.str_of( label))), - Some(dl_def(def @ def_label(_))) => - self.record_def(expr.id, def), - Some(_) => + Some(dl_def(def @ def_label(_))) => { + self.record_def(expr.id, def) + } + Some(_) => { self.session.span_bug(expr.span, ~"label wasn't mapped to a \ label def!") + } + } + } + + expr_self => { + match self.resolve_self_value_in_local_ribs(expr.span) { + None => { + self.session.span_err(expr.span, + ~"`self` is not allowed in \ + this context") + } + Some(def) => self.record_def(expr.id, def), } } @@ -4901,9 +4899,9 @@ pub impl Resolver { self.add_fixed_trait_for_expr(expr.id, self.lang_items.mul_trait()); } - expr_binary(quot, _, _) | expr_assign_op(quot, _, _) => { + expr_binary(div, _, _) | expr_assign_op(div, _, _) => { self.add_fixed_trait_for_expr(expr.id, - self.lang_items.quot_trait()); + self.lang_items.div_trait()); } expr_binary(rem, _, _) | expr_assign_op(rem, _, _) => { self.add_fixed_trait_for_expr(expr.id, @@ -5108,35 +5106,6 @@ pub impl Resolver { } } - // - // main function checking - // - // be sure that there is only one main function - // - fn check_duplicate_main(@mut self) { - let this = &mut *self; - if this.attr_main_fn.is_none() && this.start_fn.is_none() { - if this.main_fns.len() >= 1u { - let mut i = 1u; - while i < this.main_fns.len() { - let (_, dup_main_span) = this.main_fns[i].unwrap(); - this.session.span_err( - dup_main_span, - ~"multiple 'main' functions"); - i += 1; - } - *this.session.entry_fn = this.main_fns[0]; - *this.session.entry_type = Some(session::EntryMain); - } - } else if !this.start_fn.is_none() { - *this.session.entry_fn = this.start_fn; - *this.session.entry_type = Some(session::EntryStart); - } else { - *this.session.entry_fn = this.attr_main_fn; - *this.session.entry_type = Some(session::EntryMain); - } - } - // // Unused import checking // @@ -5267,7 +5236,7 @@ pub impl Resolver { debug!("Import resolutions:"); for module_.import_resolutions.each |name, import_resolution| { - let mut value_repr; + let value_repr; match import_resolution.target_for_namespace(ValueNS) { None => { value_repr = ~""; } Some(_) => { @@ -5276,7 +5245,7 @@ pub impl Resolver { } } - let mut type_repr; + let type_repr; match import_resolution.target_for_namespace(TypeNS) { None => { type_repr = ~""; } Some(_) => { diff --git a/src/librustc/middle/resolve_stage0.rs b/src/librustc/middle/resolve_stage0.rs new file mode 100644 index 0000000000000..de6a4452da1da --- /dev/null +++ b/src/librustc/middle/resolve_stage0.rs @@ -0,0 +1,5337 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use driver::session; +use driver::session::Session; +use metadata::csearch::{each_path, get_trait_method_def_ids}; +use metadata::csearch::get_method_name_and_self_ty; +use metadata::csearch::get_static_methods_if_impl; +use metadata::csearch::get_type_name_if_impl; +use metadata::cstore::find_extern_mod_stmt_cnum; +use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; +use middle::lang_items::LanguageItems; +use middle::lint::{allow, level, unused_imports}; +use middle::lint::{get_lint_level, get_lint_settings_level}; +use middle::pat_util::pat_bindings; + +use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; +use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk}; +use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy}; +use syntax::ast::{crate, decl_item, def, def_arg, def_binding}; +use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; +use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; +use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty}; +use syntax::ast::{def_ty_param, def_typaram_binder, def_trait}; +use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; +use syntax::ast::{expr_binary, expr_break, expr_field}; +use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; +use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; +use syntax::ast::{def_upvar, def_use, def_variant, div, eq}; +use syntax::ast::{expr, expr_again, expr_assign_op}; +use syntax::ast::{expr_index, expr_loop}; +use syntax::ast::{expr_path, expr_self, expr_struct, expr_unary, fn_decl}; +use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge}; +use syntax::ast::Generics; +use syntax::ast::{gt, ident, inherited, item, item_struct}; +use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod}; +use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le}; +use syntax::ast::{local, local_crate, lt, method, mul}; +use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident}; +use syntax::ast::{Path, pat_lit, pat_range, pat_struct}; +use syntax::ast::{prim_ty, private, provided}; +use syntax::ast::{public, required, rem, self_ty_, shl, shr, stmt_decl}; +use syntax::ast::{struct_field, struct_variant_kind}; +use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty}; +use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; +use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path}; +use syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint}; +use syntax::ast::unnamed_field; +use syntax::ast::{variant, view_item, view_item_extern_mod}; +use syntax::ast::{view_item_use, view_path_glob, view_path_list}; +use syntax::ast::{view_path_simple, anonymous, named, not}; +use syntax::ast::{unsafe_fn}; +use syntax::ast_util::{def_id_of_def, local_def}; +use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; +use syntax::ast_util::{Privacy, Public, Private}; +use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; +use syntax::attr::{attr_metas, contains_name, attrs_contains_name}; +use syntax::parse::token::ident_interner; +use syntax::parse::token::special_idents; +use syntax::print::pprust::path_to_str; +use syntax::codemap::{span, dummy_sp}; +use syntax::visit::{default_visitor, mk_vt, Visitor, visit_block}; +use syntax::visit::{visit_crate, visit_expr, visit_expr_opt}; +use syntax::visit::{visit_foreign_item, visit_item}; +use syntax::visit::{visit_mod, visit_ty, vt}; +use syntax::opt_vec::OptVec; + +use core::option::Some; +use core::str::each_split_str; +use core::hashmap::{HashMap, HashSet}; +use core::util; + +// Definition mapping +pub type DefMap = @mut HashMap; + +pub struct binding_info { + span: span, + binding_mode: binding_mode, +} + +// Map from the name in a pattern to its binding mode. +pub type BindingMap = HashMap; + +// Implementation resolution +// +// FIXME #4946: This kind of duplicates information kept in +// ty::method. Maybe it should go away. + +pub struct MethodInfo { + did: def_id, + n_tps: uint, + ident: ident, + self_type: self_ty_ +} + +pub struct Impl { + did: def_id, + ident: ident, + methods: ~[@MethodInfo] +} + +// Trait method resolution +pub type TraitMap = HashMap; + +// This is the replacement export map. It maps a module to all of the exports +// within. +pub type ExportMap2 = @mut HashMap; + +pub struct Export2 { + name: @~str, // The name of the target. + def_id: def_id, // The definition of the target. + reexport: bool, // Whether this is a reexport. +} + +#[deriving(Eq)] +pub enum PatternBindingMode { + RefutableMode, + LocalIrrefutableMode, + ArgumentIrrefutableMode, +} + +#[deriving(Eq)] +pub enum Namespace { + TypeNS, + ValueNS +} + +/// A NamespaceResult represents the result of resolving an import in +/// a particular namespace. The result is either definitely-resolved, +/// definitely- unresolved, or unknown. +pub enum NamespaceResult { + /// Means that resolve hasn't gathered enough information yet to determine + /// whether the name is bound in this namespace. (That is, it hasn't + /// resolved all `use` directives yet.) + UnknownResult, + /// Means that resolve has determined that the name is definitely + /// not bound in the namespace. + UnboundResult, + /// Means that resolve has determined that the name is bound in the Module + /// argument, and specified by the NameBindings argument. + BoundResult(@mut Module, @mut NameBindings) +} + +pub impl NamespaceResult { + fn is_unknown(&self) -> bool { + match *self { + UnknownResult => true, + _ => false + } + } +} + +pub enum NameDefinition { + NoNameDefinition, //< The name was unbound. + ChildNameDefinition(def), //< The name identifies an immediate child. + ImportNameDefinition(def) //< The name identifies an import. +} + +#[deriving(Eq)] +pub enum Mutability { + Mutable, + Immutable +} + +pub enum SelfBinding { + NoSelfBinding, + HasSelfBinding(node_id, bool /* is implicit */) +} + +pub type ResolveVisitor = vt<()>; + +/// Contains data for specific types of import directives. +pub enum ImportDirectiveSubclass { + SingleImport(ident /* target */, ident /* source */), + GlobImport +} + +/// The context that we thread through while building the reduced graph. +pub enum ReducedGraphParent { + ModuleReducedGraphParent(@mut Module) +} + +pub enum ResolveResult { + Failed, // Failed to resolve the name. + Indeterminate, // Couldn't determine due to unresolved globs. + Success(T) // Successfully resolved the import. +} + +pub impl ResolveResult { + fn failed(&self) -> bool { + match *self { Failed => true, _ => false } + } + fn indeterminate(&self) -> bool { + match *self { Indeterminate => true, _ => false } + } +} + +pub enum TypeParameters<'self> { + NoTypeParameters, //< No type parameters. + HasTypeParameters(&'self Generics, //< Type parameters. + node_id, //< ID of the enclosing item + + // The index to start numbering the type parameters at. + // This is zero if this is the outermost set of type + // parameters, or equal to the number of outer type + // parameters. For example, if we have: + // + // impl I { + // fn method() { ... } + // } + // + // The index at the method site will be 1, because the + // outer T had index 0. + uint, + + // The kind of the rib used for type parameters. + RibKind) +} + +// The rib kind controls the translation of argument or local definitions +// (`def_arg` or `def_local`) to upvars (`def_upvar`). + +pub enum RibKind { + // No translation needs to be applied. + NormalRibKind, + + // We passed through a function scope at the given node ID. Translate + // upvars as appropriate. + FunctionRibKind(node_id /* func id */, node_id /* body id */), + + // We passed through an impl or trait and are now in one of its + // methods. Allow references to ty params that that impl or trait + // binds. Disallow any other upvars (including other ty params that are + // upvars). + // parent; method itself + MethodRibKind(node_id, MethodSort), + + // We passed through a function *item* scope. Disallow upvars. + OpaqueFunctionRibKind, + + // We're in a constant item. Can't refer to dynamic stuff. + ConstantItemRibKind +} + +// Methods can be required or provided. Required methods only occur in traits. +pub enum MethodSort { + Required, + Provided(node_id) +} + +// The X-ray flag indicates that a context has the X-ray privilege, which +// allows it to reference private names. Currently, this is used for the test +// runner. +// +// FIXME #4947: The X-ray flag is kind of questionable in the first +// place. It might be better to introduce an expr_xray_path instead. + +#[deriving(Eq)] +pub enum XrayFlag { + NoXray, //< Private items cannot be accessed. + Xray //< Private items can be accessed. +} + +pub enum UseLexicalScopeFlag { + DontUseLexicalScope, + UseLexicalScope +} + +pub enum SearchThroughModulesFlag { + DontSearchThroughModules, + SearchThroughModules +} + +pub enum ModulePrefixResult { + NoPrefixFound, + PrefixFound(@mut Module, uint) +} + +#[deriving(Eq)] +pub enum AllowCapturingSelfFlag { + AllowCapturingSelf, //< The "self" definition can be captured. + DontAllowCapturingSelf, //< The "self" definition cannot be captured. +} + +#[deriving(Eq)] +enum NameSearchType { + SearchItemsAndPublicImports, //< Search items and public imports. + SearchItemsAndAllImports, //< Search items and all imports. +} + +pub enum BareIdentifierPatternResolution { + FoundStructOrEnumVariant(def), + FoundConst(def), + BareIdentifierPatternUnresolved +} + +// Specifies how duplicates should be handled when adding a child item if +// another item exists with the same name in some namespace. +#[deriving(Eq)] +pub enum DuplicateCheckingMode { + ForbidDuplicateModules, + ForbidDuplicateTypes, + ForbidDuplicateValues, + ForbidDuplicateTypesAndValues, + OverwriteDuplicates +} + +// Returns the namespace associated with the given duplicate checking mode, +// or fails for OverwriteDuplicates. This is used for error messages. +pub fn namespace_for_duplicate_checking_mode(mode: DuplicateCheckingMode) + -> Namespace { + match mode { + ForbidDuplicateModules | ForbidDuplicateTypes | + ForbidDuplicateTypesAndValues => TypeNS, + ForbidDuplicateValues => ValueNS, + OverwriteDuplicates => fail!(~"OverwriteDuplicates has no namespace") + } +} + +/// One local scope. +pub struct Rib { + bindings: @mut HashMap, + self_binding: @mut Option, + kind: RibKind, +} + +pub fn Rib(kind: RibKind) -> Rib { + Rib { + bindings: @mut HashMap::new(), + self_binding: @mut None, + kind: kind + } +} + + +/// One import directive. +pub struct ImportDirective { + privacy: Privacy, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span, +} + +pub fn ImportDirective(privacy: Privacy, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span) + -> ImportDirective { + ImportDirective { + privacy: privacy, + module_path: module_path, + subclass: subclass, + span: span + } +} + +/// The item that an import resolves to. +pub struct Target { + target_module: @mut Module, + bindings: @mut NameBindings, +} + +pub fn Target(target_module: @mut Module, + bindings: @mut NameBindings) + -> Target { + Target { + target_module: target_module, + bindings: bindings + } +} + +/// An ImportResolution represents a particular `use` directive. +pub struct ImportResolution { + /// The privacy of this `use` directive (whether it's `use` or + /// `pub use`. + privacy: Privacy, + span: span, + + // The number of outstanding references to this name. When this reaches + // zero, outside modules can count on the targets being correct. Before + // then, all bets are off; future imports could override this name. + + outstanding_references: uint, + + /// The value that this `use` directive names, if there is one. + value_target: Option, + /// The type that this `use` directive names, if there is one. + type_target: Option, + + /// There exists one state per import statement + state: @mut ImportState, +} + +pub fn ImportResolution(privacy: Privacy, + span: span, + state: @mut ImportState) -> ImportResolution { + ImportResolution { + privacy: privacy, + span: span, + outstanding_references: 0, + value_target: None, + type_target: None, + state: state, + } +} + +pub impl ImportResolution { + fn target_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => return copy self.type_target, + ValueNS => return copy self.value_target + } + } +} + +pub struct ImportState { + used: bool, + warned: bool +} + +pub fn ImportState() -> ImportState { + ImportState{ used: false, warned: false } +} + +/// The link from a module up to its nearest parent node. +pub enum ParentLink { + NoParentLink, + ModuleParentLink(@mut Module, ident), + BlockParentLink(@mut Module, node_id) +} + +/// The type of module this is. +pub enum ModuleKind { + NormalModuleKind, + ExternModuleKind, + TraitModuleKind, + AnonymousModuleKind, +} + +/// One node in the tree of modules. +pub struct Module { + parent_link: ParentLink, + def_id: Option, + kind: ModuleKind, + + children: @mut HashMap, + imports: @mut ~[@ImportDirective], + + // The external module children of this node that were declared with + // `extern mod`. + external_module_children: @mut HashMap, + + // The anonymous children of this node. Anonymous children are pseudo- + // modules that are implicitly created around items contained within + // blocks. + // + // For example, if we have this: + // + // fn f() { + // fn g() { + // ... + // } + // } + // + // There will be an anonymous module created around `g` with the ID of the + // entry block for `f`. + + anonymous_children: @mut HashMap, + + // The status of resolving each import in this module. + import_resolutions: @mut HashMap, + + // The number of unresolved globs that this module exports. + glob_count: uint, + + // The index of the import we're resolving. + resolved_import_count: uint, +} + +pub fn Module(parent_link: ParentLink, + def_id: Option, + kind: ModuleKind) + -> Module { + Module { + parent_link: parent_link, + def_id: def_id, + kind: kind, + children: @mut HashMap::new(), + imports: @mut ~[], + external_module_children: @mut HashMap::new(), + anonymous_children: @mut HashMap::new(), + import_resolutions: @mut HashMap::new(), + glob_count: 0, + resolved_import_count: 0 + } +} + +pub impl Module { + fn all_imports_resolved(&self) -> bool { + let imports = &mut *self.imports; + return imports.len() == self.resolved_import_count; + } +} + +// Records a possibly-private type definition. +pub struct TypeNsDef { + privacy: Privacy, + module_def: Option<@mut Module>, + type_def: Option +} + +// Records a possibly-private value definition. +pub struct ValueNsDef { + privacy: Privacy, + def: def, +} + +// Records the definitions (at most one for each namespace) that a name is +// bound to. +pub struct NameBindings { + type_def: Option, //< Meaning in type namespace. + value_def: Option, //< Meaning in value namespace. + + // For error reporting + // FIXME (#3783): Merge me into TypeNsDef and ValueNsDef. + type_span: Option, + value_span: Option, +} + +pub impl NameBindings { + /// Creates a new module in this set of name bindings. + fn define_module(@mut self, + privacy: Privacy, + parent_link: ParentLink, + def_id: Option, + kind: ModuleKind, + sp: span) { + // Merges the module with the existing type def or creates a new one. + let module_ = @mut Module(parent_link, def_id, kind); + match self.type_def { + None => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: Some(module_), + type_def: None + }); + } + Some(copy type_def) => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: Some(module_), + .. type_def + }); + } + } + self.type_span = Some(sp); + } + + /// Records a type definition. + fn define_type(@mut self, privacy: Privacy, def: def, sp: span) { + // Merges the type with the existing type def or creates a new one. + match self.type_def { + None => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: None, + type_def: Some(def) + }); + } + Some(copy type_def) => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + type_def: Some(def), + .. type_def + }); + } + } + self.type_span = Some(sp); + } + + /// Records a value definition. + fn define_value(@mut self, privacy: Privacy, def: def, sp: span) { + self.value_def = Some(ValueNsDef { privacy: privacy, def: def }); + self.value_span = Some(sp); + } + + /// Returns the module node if applicable. + fn get_module_if_available(&self) -> Option<@mut Module> { + match self.type_def { + Some(ref type_def) => (*type_def).module_def, + None => None + } + } + + /** + * Returns the module node. Fails if this node does not have a module + * definition. + */ + fn get_module(@mut self) -> @mut Module { + match self.get_module_if_available() { + None => { + fail!(~"get_module called on a node with no module \ + definition!") + } + Some(module_def) => module_def + } + } + + fn defined_in_namespace(&self, namespace: Namespace) -> bool { + match namespace { + TypeNS => return self.type_def.is_some(), + ValueNS => return self.value_def.is_some() + } + } + + fn defined_in_public_namespace(&self, namespace: Namespace) -> bool { + match namespace { + TypeNS => match self.type_def { + Some(def) => def.privacy != Private, + None => false + }, + ValueNS => match self.value_def { + Some(def) => def.privacy != Private, + None => false + } + } + } + + fn def_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => { + 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)) + } + None => None + } + } + } + } + } + } + ValueNS => { + match self.value_def { + None => None, + Some(value_def) => Some(value_def.def) + } + } + } + } + + fn privacy_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => { + match self.type_def { + None => None, + Some(ref type_def) => Some((*type_def).privacy) + } + } + ValueNS => { + match self.value_def { + None => None, + Some(value_def) => Some(value_def.privacy) + } + } + } + } + + fn span_for_namespace(&self, namespace: Namespace) -> Option { + if self.defined_in_namespace(namespace) { + match namespace { + TypeNS => self.type_span, + ValueNS => self.value_span, + } + } else { + None + } + } +} + +pub fn NameBindings() -> NameBindings { + NameBindings { + type_def: None, + value_def: None, + type_span: None, + value_span: None + } +} + +/// Interns the names of the primitive types. +pub struct PrimitiveTypeTable { + primitive_types: HashMap, +} + +pub impl PrimitiveTypeTable { + fn intern(&mut self, intr: @ident_interner, string: &str, + primitive_type: prim_ty) { + let ident = intr.intern(string); + self.primitive_types.insert(ident, primitive_type); + } +} + +pub fn PrimitiveTypeTable(intr: @ident_interner) -> PrimitiveTypeTable { + let mut table = PrimitiveTypeTable { + primitive_types: HashMap::new() + }; + + table.intern(intr, "bool", ty_bool); + table.intern(intr, "char", ty_int(ty_char)); + table.intern(intr, "float", ty_float(ty_f)); + table.intern(intr, "f32", ty_float(ty_f32)); + table.intern(intr, "f64", ty_float(ty_f64)); + table.intern(intr, "int", ty_int(ty_i)); + table.intern(intr, "i8", ty_int(ty_i8)); + table.intern(intr, "i16", ty_int(ty_i16)); + table.intern(intr, "i32", ty_int(ty_i32)); + table.intern(intr, "i64", ty_int(ty_i64)); + table.intern(intr, "str", ty_str); + table.intern(intr, "uint", ty_uint(ty_u)); + table.intern(intr, "u8", ty_uint(ty_u8)); + table.intern(intr, "u16", ty_uint(ty_u16)); + table.intern(intr, "u32", ty_uint(ty_u32)); + table.intern(intr, "u64", ty_uint(ty_u64)); + + return table; +} + + +pub fn namespace_to_str(ns: Namespace) -> ~str { + match ns { + TypeNS => ~"type", + ValueNS => ~"value", + } +} + +pub fn Resolver(session: Session, + lang_items: LanguageItems, + crate: @crate) + -> Resolver { + let graph_root = @mut NameBindings(); + + graph_root.define_module(Public, + NoParentLink, + Some(def_id { crate: 0, node: 0 }), + NormalModuleKind, + crate.span); + + let current_module = graph_root.get_module(); + + let this = Resolver { + session: @session, + lang_items: copy lang_items, + crate: crate, + + // The outermost module has def ID 0; this is not reflected in the + // AST. + + graph_root: graph_root, + + trait_info: HashMap::new(), + structs: HashSet::new(), + + unresolved_imports: 0, + + current_module: current_module, + value_ribs: ~[], + type_ribs: ~[], + label_ribs: ~[], + + xray_context: NoXray, + current_trait_refs: None, + + self_ident: special_idents::self_, + type_self_ident: special_idents::type_self, + + primitive_type_table: @PrimitiveTypeTable(session. + parse_sess.interner), + + namespaces: ~[ TypeNS, ValueNS ], + + attr_main_fn: None, + main_fns: ~[], + + start_fn: None, + + def_map: @mut HashMap::new(), + export_map2: @mut HashMap::new(), + trait_map: HashMap::new(), + + intr: session.intr() + }; + + this +} + +/// The main resolver class. +pub struct Resolver { + session: @Session, + lang_items: LanguageItems, + crate: @crate, + + intr: @ident_interner, + + graph_root: @mut NameBindings, + + trait_info: HashMap>, + structs: HashSet, + + // The number of imports that are currently unresolved. + unresolved_imports: uint, + + // The module that represents the current item scope. + current_module: @mut Module, + + // The current set of local scopes, for values. + // FIXME #4948: Reuse ribs to avoid allocation. + value_ribs: ~[@Rib], + + // The current set of local scopes, for types. + type_ribs: ~[@Rib], + + // The current set of local scopes, for labels. + label_ribs: ~[@Rib], + + // Whether the current context is an X-ray context. An X-ray context is + // allowed to access private names of any module. + xray_context: XrayFlag, + + // The trait that the current context can refer to. + current_trait_refs: Option<~[def_id]>, + + // The ident for the keyword "self". + self_ident: ident, + // The ident for the non-keyword "Self". + type_self_ident: ident, + + // The idents for the primitive types. + primitive_type_table: @PrimitiveTypeTable, + + // The four namespaces. + namespaces: ~[Namespace], + + // The function that has attribute named 'main' + attr_main_fn: Option<(node_id, span)>, + + // The functions that could be main functions + main_fns: ~[Option<(node_id, span)>], + + // The function that has the attribute 'start' on it + start_fn: Option<(node_id, span)>, + + def_map: DefMap, + export_map2: ExportMap2, + trait_map: TraitMap, +} + +pub impl Resolver { + /// The main name resolution procedure. + fn resolve(@mut self) { + self.build_reduced_graph(); + self.session.abort_if_errors(); + + self.resolve_imports(); + self.session.abort_if_errors(); + + self.record_exports(); + self.session.abort_if_errors(); + + self.resolve_crate(); + self.session.abort_if_errors(); + + self.check_duplicate_main(); + self.check_for_unused_imports_if_necessary(); + } + + // + // Reduced graph building + // + // Here we build the "reduced graph": the graph of the module tree without + // any imports resolved. + // + + /// Constructs the reduced graph for the entire crate. + fn build_reduced_graph(@mut self) { + let initial_parent = + ModuleReducedGraphParent(self.graph_root.get_module()); + visit_crate(self.crate, initial_parent, mk_vt(@Visitor { + visit_item: |item, context, visitor| + self.build_reduced_graph_for_item(item, context, visitor), + + visit_foreign_item: |foreign_item, context, visitor| + self.build_reduced_graph_for_foreign_item(foreign_item, + context, + visitor), + + visit_view_item: |view_item, context, visitor| + self.build_reduced_graph_for_view_item(view_item, + context, + visitor), + + visit_block: |block, context, visitor| + self.build_reduced_graph_for_block(block, + context, + visitor), + + .. *default_visitor() + })); + } + + /// Returns the current module tracked by the reduced graph parent. + fn get_module_from_parent(@mut self, + reduced_graph_parent: ReducedGraphParent) + -> @mut Module { + match reduced_graph_parent { + ModuleReducedGraphParent(module_) => { + return module_; + } + } + } + + /** + * Adds a new child item to the module definition of the parent node and + * returns its corresponding name bindings as well as the current parent. + * Or, if we're inside a block, creates (or reuses) an anonymous module + * corresponding to the innermost block ID and returns the name bindings + * as well as the newly-created parent. + * + * If this node does not have a module definition and we are not inside + * a block, fails. + */ + fn add_child(@mut self, + name: ident, + reduced_graph_parent: ReducedGraphParent, + duplicate_checking_mode: DuplicateCheckingMode, + // For printing errors + sp: span) + -> (@mut NameBindings, ReducedGraphParent) { + + // If this is the immediate descendant of a module, then we add the + // child name directly. Otherwise, we create or reuse an anonymous + // module and add the child to that. + + let module_; + match reduced_graph_parent { + ModuleReducedGraphParent(parent_module) => { + module_ = parent_module; + } + } + + // Add or reuse the child. + let new_parent = ModuleReducedGraphParent(module_); + match module_.children.find(&name) { + None => { + let child = @mut NameBindings(); + module_.children.insert(name, child); + return (child, new_parent); + } + Some(child) => { + // Enforce the duplicate checking mode: + // + // * If we're requesting duplicate module checking, check that + // there isn't a module in the module with the same name. + // + // * If we're requesting duplicate type checking, check that + // there isn't a type in the module with the same name. + // + // * If we're requesting duplicate value checking, check that + // there isn't a value in the module with the same name. + // + // * If we're requesting duplicate type checking and duplicate + // value checking, check that there isn't a duplicate type + // and a duplicate value with the same name. + // + // * If no duplicate checking was requested at all, do + // nothing. + + let mut is_duplicate = false; + match duplicate_checking_mode { + ForbidDuplicateModules => { + is_duplicate = + child.get_module_if_available().is_some(); + } + ForbidDuplicateTypes => { + match child.def_for_namespace(TypeNS) { + Some(def_mod(_)) | None => {} + Some(_) => is_duplicate = true + } + } + ForbidDuplicateValues => { + is_duplicate = child.defined_in_namespace(ValueNS); + } + ForbidDuplicateTypesAndValues => { + match child.def_for_namespace(TypeNS) { + Some(def_mod(_)) | None => {} + Some(_) => is_duplicate = true + }; + if child.defined_in_namespace(ValueNS) { + is_duplicate = true; + } + } + OverwriteDuplicates => {} + } + if duplicate_checking_mode != OverwriteDuplicates && + is_duplicate { + // Return an error here by looking up the namespace that + // had the duplicate. + let ns = namespace_for_duplicate_checking_mode( + duplicate_checking_mode); + self.session.span_err(sp, + fmt!("duplicate definition of %s %s", + namespace_to_str(ns), + *self.session.str_of(name))); + for child.span_for_namespace(ns).each |sp| { + self.session.span_note(*sp, + fmt!("first definition of %s %s here:", + namespace_to_str(ns), + *self.session.str_of(name))); + } + } + return (*child, new_parent); + } + } + } + + fn block_needs_anonymous_module(@mut self, block: &blk) -> bool { + // If the block has view items, we need an anonymous module. + if block.node.view_items.len() > 0 { + return true; + } + + // Check each statement. + for block.node.stmts.each |statement| { + match statement.node { + stmt_decl(declaration, _) => { + match declaration.node { + decl_item(_) => { + return true; + } + _ => { + // Keep searching. + } + } + } + _ => { + // Keep searching. + } + } + } + + // If we found neither view items nor items, we don't need to create + // an anonymous module. + + return false; + } + + fn get_parent_link(@mut self, + parent: ReducedGraphParent, + name: ident) + -> ParentLink { + match parent { + ModuleReducedGraphParent(module_) => { + return ModuleParentLink(module_, name); + } + } + } + + /// Constructs the reduced graph for one item. + fn build_reduced_graph_for_item(@mut self, + item: @item, + parent: ReducedGraphParent, + visitor: vt) { + let ident = item.ident; + let sp = item.span; + let privacy = visibility_to_privacy(item.vis); + + match item.node { + item_mod(ref module_) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateModules, sp); + + let parent_link = self.get_parent_link(new_parent, ident); + let def_id = def_id { crate: 0, node: item.id }; + name_bindings.define_module(privacy, + parent_link, + Some(def_id), + NormalModuleKind, + sp); + + let new_parent = + ModuleReducedGraphParent(name_bindings.get_module()); + + visit_mod(module_, sp, item.id, new_parent, visitor); + } + + item_foreign_mod(ref fm) => { + let new_parent = match fm.sort { + named => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, + ForbidDuplicateModules, sp); + + let parent_link = self.get_parent_link(new_parent, + ident); + let def_id = def_id { crate: 0, node: item.id }; + name_bindings.define_module(privacy, + parent_link, + Some(def_id), + ExternModuleKind, + sp); + + ModuleReducedGraphParent(name_bindings.get_module()) + } + + // For anon foreign mods, the contents just go in the + // current scope + anonymous => parent + }; + + visit_item(item, new_parent, visitor); + } + + // These items live in the value namespace. + item_const(*) => { + let (name_bindings, _) = + self.add_child(ident, parent, ForbidDuplicateValues, sp); + + name_bindings.define_value + (privacy, def_const(local_def(item.id)), sp); + } + item_fn(_, purity, _, _, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateValues, sp); + + let def = def_fn(local_def(item.id), purity); + name_bindings.define_value(privacy, def, sp); + visit_item(item, new_parent, visitor); + } + + // These items live in the type namespace. + item_ty(*) => { + let (name_bindings, _) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type + (privacy, def_ty(local_def(item.id)), sp); + } + + item_enum(ref enum_definition, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type + (privacy, def_ty(local_def(item.id)), sp); + + for (*enum_definition).variants.each |variant| { + self.build_reduced_graph_for_variant(variant, + local_def(item.id), + // inherited => privacy of the enum item + variant_visibility_to_privacy(variant.node.vis, + privacy == Public), + new_parent, + visitor); + } + } + + // These items live in both the type and value namespaces. + item_struct(struct_def, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type( + privacy, def_ty(local_def(item.id)), sp); + + // If this struct is tuple-like or enum-like, define a name + // in the value namespace. + match struct_def.ctor_id { + None => {} + Some(ctor_id) => { + name_bindings.define_value( + privacy, + def_struct(local_def(ctor_id)), + sp); + } + } + + // Record the def ID of this struct. + self.structs.insert(local_def(item.id)); + + 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. + // + // 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 has_static_methods = false; + for methods.each |method| { + match method.self_ty.node { + sty_static => has_static_methods = true, + _ => {} + } + } + + // 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. + let name = path_to_ident(path); + let (name_bindings, new_parent) = + self.add_child(name, + parent, + ForbidDuplicateModules, + sp); + + let parent_link = self.get_parent_link(new_parent, + ident); + let def_id = local_def(item.id); + name_bindings.define_module(Public, + parent_link, + Some(def_id), + TraitModuleKind, + sp); + + let new_parent = ModuleReducedGraphParent( + name_bindings.get_module()); + + // For each static method... + for methods.each |method| { + match method.self_ty.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); + } + _ => {} + } + } + } + _ => {} + } + + 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).each |method| { + let ty_m = trait_method_to_ty_method(method); + match ty_m.self_ty.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 the names of all the methods to the trait info. + let mut method_names = HashSet::new(); + for methods.each |method| { + 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.self_ty.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); + } + _ => { + method_names.insert(ident); + } + } + } + + let def_id = local_def(item.id); + self.trait_info.insert(def_id, method_names); + + name_bindings.define_type(privacy, def_trait(def_id), sp); + visit_item(item, new_parent, visitor); + } + + item_mac(*) => { + fail!(~"item macros unimplemented") + } + } + } + + // Constructs the reduced graph for one variant. Variants exist in the + // type and/or value namespaces. + fn build_reduced_graph_for_variant(@mut self, + variant: &variant, + item_id: def_id, + parent_privacy: Privacy, + parent: ReducedGraphParent, + _visitor: vt) { + let ident = variant.node.name; + let (child, _) = self.add_child(ident, parent, ForbidDuplicateValues, + variant.span); + + let privacy; + match variant.node.vis { + public => privacy = Public, + private => privacy = Private, + inherited => privacy = parent_privacy + } + + match variant.node.kind { + tuple_variant_kind(_) => { + child.define_value(privacy, + def_variant(item_id, + local_def(variant.node.id)), + variant.span); + } + struct_variant_kind(_) => { + child.define_type(privacy, + def_variant(item_id, + local_def(variant.node.id)), + variant.span); + self.structs.insert(local_def(variant.node.id)); + } + } + } + + /** + * Constructs the reduced graph for one 'view item'. View items consist + * of imports and use directives. + */ + fn build_reduced_graph_for_view_item(@mut self, + view_item: @view_item, + parent: ReducedGraphParent, + _visitor: vt) { + let privacy = visibility_to_privacy(view_item.vis); + match view_item.node { + view_item_use(ref view_paths) => { + for view_paths.each |view_path| { + // Extract and intern the module part of the path. For + // globs and lists, the path is found directly in the AST; + // for simple paths we have to munge the path a little. + + let mut module_path = ~[]; + match view_path.node { + view_path_simple(_, full_path, _) => { + let path_len = full_path.idents.len(); + assert!(path_len != 0); + + for full_path.idents.eachi |i, ident| { + if i != path_len - 1 { + module_path.push(*ident); + } + } + } + + view_path_glob(module_ident_path, _) | + view_path_list(module_ident_path, _, _) => { + for module_ident_path.idents.each |ident| { + module_path.push(*ident); + } + } + } + + // Build up the import directives. + let module_ = self.get_module_from_parent(parent); + match view_path.node { + view_path_simple(binding, full_path, _) => { + let source_ident = *full_path.idents.last(); + let subclass = @SingleImport(binding, + source_ident); + self.build_import_directive(privacy, + module_, + module_path, + subclass, + view_path.span); + } + view_path_list(_, ref source_idents, _) => { + for source_idents.each |source_ident| { + let name = source_ident.node.name; + let subclass = @SingleImport(name, name); + self.build_import_directive(privacy, + module_, + copy module_path, + subclass, + source_ident.span); + } + } + view_path_glob(_, _) => { + self.build_import_directive(privacy, + module_, + module_path, + @GlobImport, + view_path.span); + } + } + } + } + + view_item_extern_mod(name, _, node_id) => { + match find_extern_mod_stmt_cnum(self.session.cstore, + node_id) { + Some(crate_id) => { + let def_id = def_id { crate: crate_id, node: 0 }; + let parent_link = ModuleParentLink + (self.get_module_from_parent(parent), name); + let external_module = @mut Module(parent_link, + Some(def_id), + NormalModuleKind); + + parent.external_module_children.insert( + name, + external_module); + + self.build_reduced_graph_for_external_crate( + external_module); + } + None => {} // Ignore. + } + } + } + } + + /// Constructs the reduced graph for one foreign item. + fn build_reduced_graph_for_foreign_item(@mut self, + foreign_item: @foreign_item, + parent: ReducedGraphParent, + visitor: + vt) { + let name = foreign_item.ident; + let (name_bindings, new_parent) = + self.add_child(name, parent, ForbidDuplicateValues, + foreign_item.span); + + match foreign_item.node { + foreign_item_fn(_, _, ref generics) => { + let def = def_fn(local_def(foreign_item.id), unsafe_fn); + name_bindings.define_value(Public, def, foreign_item.span); + + do self.with_type_parameter_rib( + HasTypeParameters( + generics, foreign_item.id, 0, NormalRibKind)) + { + visit_foreign_item(foreign_item, new_parent, visitor); + } + } + foreign_item_const(*) => { + let def = def_const(local_def(foreign_item.id)); + name_bindings.define_value(Public, def, foreign_item.span); + + visit_foreign_item(foreign_item, new_parent, visitor); + } + } + } + + fn build_reduced_graph_for_block(@mut self, + block: &blk, + parent: ReducedGraphParent, + visitor: vt) { + let new_parent; + if self.block_needs_anonymous_module(block) { + let block_id = block.node.id; + + debug!("(building reduced graph for block) creating a new \ + anonymous module for block %d", + block_id); + + let parent_module = self.get_module_from_parent(parent); + let new_module = @mut Module( + BlockParentLink(parent_module, block_id), + None, + AnonymousModuleKind); + parent_module.anonymous_children.insert(block_id, new_module); + new_parent = ModuleReducedGraphParent(new_module); + } else { + new_parent = parent; + } + + visit_block(block, new_parent, visitor); + } + + fn handle_external_def(@mut self, + def: def, + modules: &mut HashMap, + child_name_bindings: @mut NameBindings, + final_ident: &str, + ident: ident, + new_parent: ReducedGraphParent) { + match def { + def_mod(def_id) | def_foreign_mod(def_id) => { + match child_name_bindings.type_def { + Some(TypeNsDef { module_def: Some(copy module_def), _ }) => { + debug!("(building reduced graph for external crate) \ + already created module"); + module_def.def_id = Some(def_id); + modules.insert(def_id, module_def); + } + Some(_) | None => { + debug!("(building reduced graph for \ + external crate) building module \ + %s", final_ident); + let parent_link = self.get_parent_link(new_parent, ident); + + // FIXME (#5074): this should be a match on find + if !modules.contains_key(&def_id) { + child_name_bindings.define_module(Public, + parent_link, + Some(def_id), + NormalModuleKind, + dummy_sp()); + modules.insert(def_id, + child_name_bindings.get_module()); + } else { + let existing_module = *modules.get(&def_id); + // Create an import resolution to + // avoid creating cycles in the + // module graph. + + let resolution = + @mut ImportResolution(Public, + dummy_sp(), + @mut ImportState()); + resolution.outstanding_references = 0; + + match existing_module.parent_link { + NoParentLink | + BlockParentLink(*) => { + fail!(~"can't happen"); + } + ModuleParentLink(parent_module, ident) => { + let name_bindings = parent_module.children.get( + &ident); + resolution.type_target = + Some(Target(parent_module, *name_bindings)); + } + } + + debug!("(building reduced graph for external crate) \ + ... creating import resolution"); + + new_parent.import_resolutions.insert(ident, resolution); + } + } + } + } + def_fn(*) | def_static_method(*) | def_const(*) | + def_variant(*) => { + debug!("(building reduced graph for external \ + crate) building value %s", final_ident); + child_name_bindings.define_value(Public, def, dummy_sp()); + } + def_trait(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + // If this is a trait, add all the method names + // to the trait info. + + let method_def_ids = get_trait_method_def_ids(self.session.cstore, + def_id); + let mut interned_method_names = HashSet::new(); + for method_def_ids.each |&method_def_id| { + let (method_name, self_ty) = + get_method_name_and_self_ty(self.session.cstore, + method_def_id); + + debug!("(building reduced graph for \ + external crate) ... adding \ + trait method '%s'", + *self.session.str_of(method_name)); + + // Add it to the trait info if not static. + if self_ty != sty_static { + interned_method_names.insert(method_name); + } + } + self.trait_info.insert(def_id, interned_method_names); + + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_ty(_) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_struct(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", + final_ident); + child_name_bindings.define_type(Public, def, dummy_sp()); + self.structs.insert(def_id); + } + def_self(*) | def_arg(*) | def_local(*) | + def_prim_ty(*) | def_ty_param(*) | def_binding(*) | + def_use(*) | def_upvar(*) | def_region(*) | + def_typaram_binder(*) | def_label(*) | def_self_ty(*) => { + fail!(fmt!("didn't expect `%?`", def)); + } + } + } + + /** + * Builds the reduced graph rooted at the 'use' directive for an external + * crate. + */ + fn build_reduced_graph_for_external_crate(@mut self, root: @mut Module) { + let mut modules = HashMap::new(); + + // Create all the items reachable by paths. + for each_path(self.session.cstore, root.def_id.get().crate) + |path_string, def_like| { + + debug!("(building reduced graph for external crate) found path \ + entry: %s (%?)", + path_string, def_like); + + let mut pieces = ~[]; + for each_split_str(path_string, "::") |s| { pieces.push(s.to_owned()) } + let final_ident_str = pieces.pop(); + let final_ident = self.session.ident_of(final_ident_str); + + // Find the module we need, creating modules along the way if we + // need to. + + let mut current_module = root; + for pieces.each |ident_str| { + let ident = self.session.ident_of(/*bad*/copy *ident_str); + // Create or reuse a graph node for the child. + let (child_name_bindings, new_parent) = + self.add_child(ident, + ModuleReducedGraphParent(current_module), + OverwriteDuplicates, + dummy_sp()); + + // Define or reuse the module node. + match child_name_bindings.type_def { + None => { + debug!("(building reduced graph for external crate) \ + autovivifying missing type def %s", + *ident_str); + let parent_link = self.get_parent_link(new_parent, + ident); + child_name_bindings.define_module(Public, + parent_link, + None, + NormalModuleKind, + dummy_sp()); + } + Some(copy type_ns_def) + if type_ns_def.module_def.is_none() => { + debug!("(building reduced graph for external crate) \ + autovivifying missing module def %s", + *ident_str); + let parent_link = self.get_parent_link(new_parent, + ident); + child_name_bindings.define_module(Public, + parent_link, + None, + NormalModuleKind, + dummy_sp()); + } + _ => {} // Fall through. + } + + current_module = child_name_bindings.get_module(); + } + + match def_like { + dl_def(def) => { + // Add the new child item. + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + + self.handle_external_def(def, + &mut modules, + child_name_bindings, + *self.session.str_of( + final_ident), + final_ident, + new_parent); + } + dl_impl(def) => { + // We only process static methods of impls here. + match get_type_name_if_impl(self.session.cstore, def) { + None => {} + Some(final_ident) => { + let static_methods_opt = + get_static_methods_if_impl( + self.session.cstore, def); + match static_methods_opt { + Some(ref static_methods) if + static_methods.len() >= 1 => { + debug!("(building reduced graph for \ + external crate) processing \ + static methods for type name %s", + *self.session.str_of( + final_ident)); + + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + + // Process the static methods. First, + // create the module. + let type_module; + match child_name_bindings.type_def { + Some(TypeNsDef { + module_def: Some(copy module_def), + _ + }) => { + // We already have a module. This + // is OK. + type_module = module_def; + } + Some(_) | None => { + let parent_link = + self.get_parent_link( + new_parent, final_ident); + child_name_bindings.define_module( + Public, + parent_link, + Some(def), + NormalModuleKind, + dummy_sp()); + type_module = + child_name_bindings. + get_module(); + } + } + + // Add each static method to the module. + let new_parent = ModuleReducedGraphParent( + type_module); + for static_methods.each + |static_method_info| { + let ident = static_method_info.ident; + debug!("(building reduced graph for \ + external crate) creating \ + static method '%s'", + *self.session.str_of(ident)); + + let (method_name_bindings, _) = + self.add_child( + ident, + new_parent, + OverwriteDuplicates, + dummy_sp()); + let def = def_fn( + static_method_info.def_id, + static_method_info.purity); + method_name_bindings.define_value( + Public, def, dummy_sp()); + } + } + + // Otherwise, do nothing. + Some(_) | None => {} + } + } + } + } + dl_field => { + debug!("(building reduced graph for external crate) \ + ignoring field"); + } + } + } + } + + /// Creates and adds an import directive to the given module. + fn build_import_directive(@mut self, + privacy: Privacy, + module_: @mut Module, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span) { + let directive = @ImportDirective(privacy, module_path, + subclass, span); + module_.imports.push(directive); + + // Bump the reference count on the name. Or, if this is a glob, set + // the appropriate flag. + + match *subclass { + SingleImport(target, _) => { + debug!("(building import directive) building import \ + directive: privacy %? %s::%s", + privacy, + self.idents_to_str(directive.module_path), + *self.session.str_of(target)); + + match module_.import_resolutions.find(&target) { + Some(resolution) => { + debug!("(building import directive) bumping \ + reference"); + resolution.outstanding_references += 1; + } + None => { + debug!("(building import directive) creating new"); + let state = @mut ImportState(); + let resolution = @mut ImportResolution(privacy, + span, + state); + let name = self.idents_to_str(directive.module_path); + // Don't warn about unused intrinsics because they're + // automatically appended to all files + if name == ~"intrinsic::rusti" { + resolution.state.warned = true; + } + resolution.outstanding_references = 1; + module_.import_resolutions.insert(target, resolution); + } + } + } + GlobImport => { + // Set the glob flag. This tells us that we don't know the + // module's exports ahead of time. + + module_.glob_count += 1; + } + } + + self.unresolved_imports += 1; + } + + // Import resolution + // + // This is a fixed-point algorithm. We resolve imports until our efforts + // are stymied by an unresolved import; then we bail out of the current + // module and continue. We terminate successfully once no more imports + // remain or unsuccessfully when no forward progress in resolving imports + // is made. + + /** + * Resolves all imports for the crate. This method performs the fixed- + * point iteration. + */ + fn resolve_imports(@mut self) { + let mut i = 0; + let mut prev_unresolved_imports = 0; + loop { + debug!("(resolving imports) iteration %u, %u imports left", + i, self.unresolved_imports); + + let module_root = self.graph_root.get_module(); + self.resolve_imports_for_module_subtree(module_root); + + if self.unresolved_imports == 0 { + debug!("(resolving imports) success"); + break; + } + + if self.unresolved_imports == prev_unresolved_imports { + self.session.err(~"failed to resolve imports"); + self.report_unresolved_imports(module_root); + break; + } + + i += 1; + prev_unresolved_imports = self.unresolved_imports; + } + } + + /// Attempts to resolve imports for the given module and all of its + /// submodules. + fn resolve_imports_for_module_subtree(@mut self, module_: @mut Module) { + debug!("(resolving imports for module subtree) resolving %s", + self.module_to_str(module_)); + self.resolve_imports_for_module(module_); + + for module_.children.each_value |&child_node| { + match child_node.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.resolve_imports_for_module_subtree(child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.resolve_imports_for_module_subtree(child_module); + } + } + + /// Attempts to resolve imports for the given module only. + fn resolve_imports_for_module(@mut self, module: @mut Module) { + if module.all_imports_resolved() { + debug!("(resolving imports for module) all imports resolved for \ + %s", + self.module_to_str(module)); + return; + } + + let imports = &mut *module.imports; + let import_count = imports.len(); + while module.resolved_import_count < import_count { + let import_index = module.resolved_import_count; + let import_directive = imports[import_index]; + match self.resolve_import_for_module(module, import_directive) { + Failed => { + // We presumably emitted an error. Continue. + let msg = fmt!("failed to resolve import: %s", + *self.import_path_to_str( + import_directive.module_path, + *import_directive.subclass)); + self.session.span_err(import_directive.span, msg); + } + Indeterminate => { + // Bail out. We'll come around next time. + break; + } + Success(()) => { + // Good. Continue. + } + } + + module.resolved_import_count += 1; + } + } + + fn idents_to_str(@mut self, idents: &[ident]) -> ~str { + let mut first = true; + let mut result = ~""; + for idents.each |ident| { + if first { first = false; } else { result += "::" }; + result += *self.session.str_of(*ident); + }; + return result; + } + + fn import_directive_subclass_to_str(@mut self, + subclass: ImportDirectiveSubclass) + -> @~str { + match subclass { + SingleImport(_target, source) => self.session.str_of(source), + GlobImport => @~"*" + } + } + + fn import_path_to_str(@mut self, + idents: &[ident], + subclass: ImportDirectiveSubclass) + -> @~str { + if idents.is_empty() { + self.import_directive_subclass_to_str(subclass) + } else { + @fmt!("%s::%s", + self.idents_to_str(idents), + *self.import_directive_subclass_to_str(subclass)) + } + } + + /// Attempts to resolve the given import. The return value indicates + /// failure if we're certain the name does not exist, indeterminate if we + /// don't know whether the name exists at the moment due to other + /// currently-unresolved imports, or success if we know the name exists. + /// If successful, the resolved bindings are written into the module. + fn resolve_import_for_module(@mut self, module_: @mut Module, + import_directive: @ImportDirective) + -> ResolveResult<()> { + let mut resolution_result = Failed; + let module_path = &import_directive.module_path; + + debug!("(resolving import for module) resolving import `%s::...` in \ + `%s`", + self.idents_to_str(*module_path), + self.module_to_str(module_)); + + // First, resolve the module path for the directive, if necessary. + let containing_module = if module_path.len() == 0 { + // Use the crate root. + Some(self.graph_root.get_module()) + } else { + match self.resolve_module_path_for_import(module_, + *module_path, + DontUseLexicalScope, + import_directive.span) { + + Failed => None, + Indeterminate => { + resolution_result = Indeterminate; + None + } + Success(containing_module) => Some(containing_module), + } + }; + + match containing_module { + None => {} + Some(containing_module) => { + // We found the module that the target is contained + // within. Attempt to resolve the import within it. + + match *import_directive.subclass { + SingleImport(target, source) => { + resolution_result = + self.resolve_single_import(module_, + containing_module, + target, + source); + } + GlobImport => { + let span = import_directive.span; + let privacy = import_directive.privacy; + resolution_result = + self.resolve_glob_import(privacy, + module_, + containing_module, + span); + } + } + } + } + + // Decrement the count of unresolved imports. + match resolution_result { + Success(()) => { + assert!(self.unresolved_imports >= 1); + self.unresolved_imports -= 1; + } + _ => { + // Nothing to do here; just return the error. + } + } + + // Decrement the count of unresolved globs if necessary. But only if + // the resolution result is indeterminate -- otherwise we'll stop + // processing imports here. (See the loop in + // resolve_imports_for_module.) + + if !resolution_result.indeterminate() { + match *import_directive.subclass { + GlobImport => { + assert!(module_.glob_count >= 1); + module_.glob_count -= 1; + } + SingleImport(*) => { + // Ignore. + } + } + } + + return resolution_result; + } + + fn create_name_bindings_from_module(module: @mut Module) -> NameBindings { + NameBindings { + type_def: Some(TypeNsDef { + privacy: Public, + module_def: Some(module), + type_def: None, + }), + value_def: None, + type_span: None, + value_span: None, + } + } + + fn resolve_single_import(@mut self, + module_: @mut Module, + containing_module: @mut Module, + target: ident, + source: ident) + -> ResolveResult<()> { + debug!("(resolving single import) resolving `%s` = `%s::%s` from \ + `%s`", + *self.session.str_of(target), + self.module_to_str(containing_module), + *self.session.str_of(source), + self.module_to_str(module_)); + + // We need to resolve both namespaces for this to succeed. + // + // FIXME #4949: See if there's some way of handling namespaces in + // a more generic way. We have two of them; it seems worth + // doing... + + let mut value_result = UnknownResult; + let mut type_result = UnknownResult; + + // Search for direct children of the containing module. + match containing_module.children.find(&source) { + None => { + // Continue. + } + Some(child_name_bindings) => { + if child_name_bindings.defined_in_namespace(ValueNS) { + value_result = BoundResult(containing_module, + *child_name_bindings); + } + if child_name_bindings.defined_in_namespace(TypeNS) { + type_result = BoundResult(containing_module, + *child_name_bindings); + } + } + } + + // Unless we managed to find a result in both namespaces (unlikely), + // search imports as well. + match (value_result, type_result) { + (BoundResult(*), BoundResult(*)) => { + // Continue. + } + _ => { + // If there is an unresolved glob at this point in the + // containing module, bail out. We don't know enough to be + // able to resolve this import. + + if containing_module.glob_count > 0 { + debug!("(resolving single import) unresolved glob; \ + bailing out"); + return Indeterminate; + } + + // Now search the exported imports within the containing + // module. + + match containing_module.import_resolutions.find(&source) { + None => { + // The containing module definitely doesn't have an + // exported import with the name in question. We can + // therefore accurately report that the names are + // unbound. + + if value_result.is_unknown() { + value_result = UnboundResult; + } + if type_result.is_unknown() { + type_result = UnboundResult; + } + } + Some(import_resolution) + if import_resolution.outstanding_references + == 0 => { + + fn get_binding(import_resolution: + @mut ImportResolution, + namespace: Namespace) + -> NamespaceResult { + + // Import resolutions must be declared with "pub" + // in order to be exported. + if import_resolution.privacy == Private { + return UnboundResult; + } + + match (*import_resolution). + target_for_namespace(namespace) { + None => { + return UnboundResult; + } + Some(target) => { + import_resolution.state.used = true; + return BoundResult(target.target_module, + target.bindings); + } + } + } + + // The name is an import which has been fully + // resolved. We can, therefore, just follow it. + if value_result.is_unknown() { + value_result = get_binding(*import_resolution, + ValueNS); + } + if type_result.is_unknown() { + type_result = get_binding(*import_resolution, + TypeNS); + } + } + Some(_) => { + // The import is unresolved. Bail out. + debug!("(resolving single import) unresolved import; \ + bailing out"); + return Indeterminate; + } + } + } + } + + // If we didn't find a result in the type namespace, search the + // external modules. + match type_result { + BoundResult(*) => {} + _ => { + match containing_module.external_module_children + .find(&source) { + None => {} // Continue. + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + type_result = BoundResult(containing_module, + name_bindings); + } + } + } + } + + // We've successfully resolved the import. Write the results in. + assert!(module_.import_resolutions.contains_key(&target)); + let import_resolution = module_.import_resolutions.get(&target); + + match value_result { + BoundResult(target_module, name_bindings) => { + import_resolution.value_target = + Some(Target(target_module, name_bindings)); + } + UnboundResult => { /* Continue. */ } + UnknownResult => { + fail!(~"value result should be known at this point"); + } + } + match type_result { + BoundResult(target_module, name_bindings) => { + import_resolution.type_target = + Some(Target(target_module, name_bindings)); + } + UnboundResult => { /* Continue. */ } + UnknownResult => { + fail!(~"type result should be known at this point"); + } + } + + let i = import_resolution; + match (i.value_target, i.type_target) { + // If this name wasn't found in either namespace, it's definitely + // unresolved. + (None, None) => { return Failed; } + // If it's private, it's also unresolved. + (Some(t), None) | (None, Some(t)) => { + let bindings = &mut *t.bindings; + match bindings.type_def { + Some(ref type_def) => { + if type_def.privacy == Private { + return Failed; + } + } + _ => () + } + match bindings.value_def { + Some(ref value_def) => { + if value_def.privacy == Private { + return Failed; + } + } + _ => () + } + } + // It's also an error if there's both a type and a value with this + // name, but both are private + (Some(val), Some(ty)) => { + match (val.bindings.value_def, ty.bindings.value_def) { + (Some(ref value_def), Some(ref type_def)) => + if value_def.privacy == Private + && type_def.privacy == Private { + return Failed; + }, + _ => () + } + } + } + + assert!(import_resolution.outstanding_references >= 1); + import_resolution.outstanding_references -= 1; + + debug!("(resolving single import) successfully resolved import"); + return Success(()); + } + + // Resolves a glob import. Note that this function cannot fail; it either + // succeeds or bails out (as importing * from an empty module or a module + // that exports nothing is valid). + fn resolve_glob_import(@mut self, + privacy: Privacy, + module_: @mut Module, + containing_module: @mut Module, + span: span) + -> ResolveResult<()> { + // This function works in a highly imperative manner; it eagerly adds + // everything it can to the list of import resolutions of the module + // node. + debug!("(resolving glob import) resolving %? glob import", privacy); + let state = @mut ImportState(); + + // We must bail out if the node has unresolved imports of any kind + // (including globs). + if !(*containing_module).all_imports_resolved() { + debug!("(resolving glob import) target module has unresolved \ + imports; bailing out"); + return Indeterminate; + } + + assert!(containing_module.glob_count == 0); + + // Add all resolved imports from the containing module. + for containing_module.import_resolutions.each + |ident, target_import_resolution| { + + debug!("(resolving glob import) writing module resolution \ + %? into `%s`", + target_import_resolution.type_target.is_none(), + self.module_to_str(module_)); + + // Here we merge two import resolutions. + match module_.import_resolutions.find(ident) { + None if target_import_resolution.privacy == Public => { + // Simple: just copy the old import resolution. + let new_import_resolution = + @mut ImportResolution(privacy, + target_import_resolution.span, + state); + new_import_resolution.value_target = + copy target_import_resolution.value_target; + new_import_resolution.type_target = + copy target_import_resolution.type_target; + + module_.import_resolutions.insert + (*ident, new_import_resolution); + } + None => { /* continue ... */ } + Some(dest_import_resolution) => { + // Merge the two import resolutions at a finer-grained + // level. + + match target_import_resolution.value_target { + None => { + // Continue. + } + Some(copy value_target) => { + dest_import_resolution.value_target = + Some(value_target); + } + } + match target_import_resolution.type_target { + None => { + // Continue. + } + Some(copy type_target) => { + dest_import_resolution.type_target = + Some(type_target); + } + } + } + } + } + + let merge_import_resolution = |ident, + name_bindings: @mut NameBindings| { + let dest_import_resolution; + match module_.import_resolutions.find(&ident) { + None => { + // Create a new import resolution from this child. + dest_import_resolution = @mut ImportResolution(privacy, + span, + state); + module_.import_resolutions.insert + (ident, dest_import_resolution); + } + Some(existing_import_resolution) => { + dest_import_resolution = *existing_import_resolution; + } + } + + debug!("(resolving glob import) writing resolution `%s` in `%s` \ + to `%s`, privacy=%?", + *self.session.str_of(ident), + self.module_to_str(containing_module), + self.module_to_str(module_), + copy dest_import_resolution.privacy); + + // Merge the child item into the import resolution. + if name_bindings.defined_in_public_namespace(ValueNS) { + debug!("(resolving glob import) ... for value target"); + dest_import_resolution.value_target = + Some(Target(containing_module, name_bindings)); + } + if name_bindings.defined_in_public_namespace(TypeNS) { + debug!("(resolving glob import) ... for type target"); + dest_import_resolution.type_target = + Some(Target(containing_module, name_bindings)); + } + }; + + // Add all children from the containing module. + for containing_module.children.each |&ident, name_bindings| { + merge_import_resolution(ident, *name_bindings); + } + + // Add external module children from the containing module. + for containing_module.external_module_children.each + |&ident, module| { + let name_bindings = + @mut Resolver::create_name_bindings_from_module(*module); + merge_import_resolution(ident, name_bindings); + } + + debug!("(resolving glob import) successfully resolved import"); + return Success(()); + } + + /// Resolves the given module path from the given root `module_`. + fn resolve_module_path_from_root(@mut self, + module_: @mut Module, + module_path: &[ident], + index: uint, + span: span, + mut name_search_type: NameSearchType) + -> ResolveResult<@mut Module> { + let mut search_module = module_; + let mut index = index; + let module_path_len = module_path.len(); + + // Resolve the module part of the path. This does not involve looking + // upward though scope chains; we simply resolve names directly in + // modules as we go. + + while index < module_path_len { + let name = module_path[index]; + match self.resolve_name_in_module(search_module, + name, + TypeNS, + name_search_type) { + Failed => { + self.session.span_err(span, ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) module \ + resolution is indeterminate: %s", + *self.session.str_of(name)); + return Indeterminate; + } + Success(target) => { + // Check to see whether there are type bindings, and, if + // so, whether there is a module within. + match target.bindings.type_def { + Some(copy type_def) => { + match type_def.module_def { + None => { + // Not a module. + self.session.span_err(span, + fmt!("not a \ + module: %s", + *self.session. + str_of( + name))); + return Failed; + } + Some(copy module_def) => { + search_module = module_def; + } + } + } + None => { + // There are no type bindings at all. + self.session.span_err(span, + fmt!("not a module: %s", + *self.session.str_of( + name))); + return Failed; + } + } + } + } + + index += 1; + + // After the first element of the path, allow searching through + // items and imports unconditionally. This allows things like: + // + // pub mod core { + // pub use vec; + // } + // + // pub mod something_else { + // use core::vec; + // } + + name_search_type = SearchItemsAndPublicImports; + } + + return Success(search_module); + } + + /// Attempts to resolve the module part of an import directive or path + /// rooted at the given module. + fn resolve_module_path_for_import(@mut self, + module_: @mut Module, + module_path: &[ident], + use_lexical_scope: UseLexicalScopeFlag, + span: span) + -> ResolveResult<@mut Module> { + let module_path_len = module_path.len(); + assert!(module_path_len > 0); + + debug!("(resolving module path for import) processing `%s` rooted at \ + `%s`", + self.idents_to_str(module_path), + self.module_to_str(module_)); + + // Resolve the module prefix, if any. + let module_prefix_result = self.resolve_module_prefix(module_, + module_path); + + let search_module; + let start_index; + match module_prefix_result { + Failed => { + self.session.span_err(span, ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) indeterminate; \ + bailing"); + return Indeterminate; + } + Success(NoPrefixFound) => { + // There was no prefix, so we're considering the first element + // of the path. How we handle this depends on whether we were + // instructed to use lexical scope or not. + match use_lexical_scope { + DontUseLexicalScope => { + // This is a crate-relative path. We will start the + // resolution process at index zero. + search_module = self.graph_root.get_module(); + start_index = 0; + } + UseLexicalScope => { + // This is not a crate-relative path. We resolve the + // first component of the path in the current lexical + // scope and then proceed to resolve below that. + let result = self.resolve_module_in_lexical_scope( + module_, + module_path[0]); + match result { + Failed => { + self.session.span_err(span, + ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) \ + indeterminate; bailing"); + return Indeterminate; + } + Success(containing_module) => { + search_module = containing_module; + start_index = 1; + } + } + } + } + } + Success(PrefixFound(containing_module, index)) => { + search_module = containing_module; + start_index = index; + } + } + + self.resolve_module_path_from_root(search_module, + module_path, + start_index, + span, + SearchItemsAndPublicImports) + } + + /// Invariant: This must only be called during main resolution, not during + /// import resolution. + fn resolve_item_in_lexical_scope(@mut self, + module_: @mut Module, + name: ident, + namespace: Namespace, + search_through_modules: + SearchThroughModulesFlag) + -> ResolveResult { + debug!("(resolving item in lexical scope) resolving `%s` in \ + namespace %? in `%s`", + *self.session.str_of(name), + namespace, + self.module_to_str(module_)); + + // The current module node is handled specially. First, check for + // its immediate children. + match module_.children.find(&name) { + Some(name_bindings) + if name_bindings.defined_in_namespace(namespace) => { + return Success(Target(module_, *name_bindings)); + } + Some(_) | None => { /* Not found; continue. */ } + } + + // Now check for its import directives. We don't have to have resolved + // all its imports in the usual way; this is because chains of + // adjacent import statements are processed as though they mutated the + // current scope. + match module_.import_resolutions.find(&name) { + None => { + // Not found; continue. + } + Some(import_resolution) => { + match (*import_resolution).target_for_namespace(namespace) { + None => { + // Not found; continue. + debug!("(resolving item in lexical scope) found \ + import resolution, but not in namespace %?", + namespace); + } + Some(target) => { + debug!("(resolving item in lexical scope) using \ + import resolution"); + import_resolution.state.used = true; + return Success(copy target); + } + } + } + } + + // Search for external modules. + if namespace == TypeNS { + match module_.external_module_children.find(&name) { + None => {} + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + return Success(Target(module_, name_bindings)); + } + } + } + + // Finally, proceed up the scope chain looking for parent modules. + let mut search_module = module_; + loop { + // Go to the next parent. + match search_module.parent_link { + NoParentLink => { + // No more parents. This module was unresolved. + debug!("(resolving item in lexical scope) unresolved \ + module"); + return Failed; + } + ModuleParentLink(parent_module_node, _) => { + match search_through_modules { + DontSearchThroughModules => { + match search_module.kind { + NormalModuleKind => { + // We stop the search here. + debug!("(resolving item in lexical \ + scope) unresolved module: not \ + searching through module \ + parents"); + return Failed; + } + ExternModuleKind | + TraitModuleKind | + AnonymousModuleKind => { + search_module = parent_module_node; + } + } + } + SearchThroughModules => { + search_module = parent_module_node; + } + } + } + BlockParentLink(parent_module_node, _) => { + search_module = parent_module_node; + } + } + + // Resolve the name in the parent module. + match self.resolve_name_in_module(search_module, + name, + namespace, + SearchItemsAndAllImports) { + Failed => { + // Continue up the search chain. + } + Indeterminate => { + // We couldn't see through the higher scope because of an + // unresolved import higher up. Bail. + + debug!("(resolving item in lexical scope) indeterminate \ + higher scope; bailing"); + return Indeterminate; + } + Success(target) => { + // We found the module. + return Success(copy target); + } + } + } + } + + /** Resolves a module name in the current lexical scope. */ + fn resolve_module_in_lexical_scope(@mut self, + module_: @mut Module, + name: ident) + -> ResolveResult<@mut Module> { + // If this module is an anonymous module, resolve the item in the + // lexical scope. Otherwise, resolve the item from the crate root. + let resolve_result = self.resolve_item_in_lexical_scope( + module_, name, TypeNS, DontSearchThroughModules); + match resolve_result { + Success(target) => { + let bindings = &mut *target.bindings; + match bindings.type_def { + Some(ref type_def) => { + match (*type_def).module_def { + None => { + error!("!!! (resolving module in lexical \ + scope) module wasn't actually a \ + module!"); + return Failed; + } + Some(module_def) => { + return Success(module_def); + } + } + } + None => { + error!("!!! (resolving module in lexical scope) module + wasn't actually a module!"); + return Failed; + } + } + } + Indeterminate => { + debug!("(resolving module in lexical scope) indeterminate; \ + bailing"); + return Indeterminate; + } + Failed => { + debug!("(resolving module in lexical scope) failed to \ + resolve"); + return Failed; + } + } + } + + /** + * Returns the nearest normal module parent of the given module. + */ + fn get_nearest_normal_module_parent(@mut self, module_: @mut Module) + -> Option<@mut Module> { + let mut module_ = module_; + loop { + match module_.parent_link { + NoParentLink => return None, + ModuleParentLink(new_module, _) | + BlockParentLink(new_module, _) => { + match new_module.kind { + NormalModuleKind => return Some(new_module), + ExternModuleKind | + TraitModuleKind | + AnonymousModuleKind => module_ = new_module, + } + } + } + } + } + + /** + * Returns the nearest normal module parent of the given module, or the + * module itself if it is a normal module. + */ + fn get_nearest_normal_module_parent_or_self(@mut self, + module_: @mut Module) + -> @mut Module { + match module_.kind { + NormalModuleKind => return module_, + ExternModuleKind | TraitModuleKind | AnonymousModuleKind => { + match self.get_nearest_normal_module_parent(module_) { + None => module_, + Some(new_module) => new_module + } + } + } + } + + /** + * Resolves a "module prefix". A module prefix is one of (a) `self::`; + * (b) some chain of `super::`. + */ + fn resolve_module_prefix(@mut self, + module_: @mut Module, + module_path: &[ident]) + -> ResolveResult { + let interner = self.session.parse_sess.interner; + + // Start at the current module if we see `self` or `super`, or at the + // top of the crate otherwise. + let mut containing_module; + let mut i; + if *interner.get(module_path[0]) == ~"self" { + containing_module = + self.get_nearest_normal_module_parent_or_self(module_); + i = 1; + } else if *interner.get(module_path[0]) == ~"super" { + containing_module = + self.get_nearest_normal_module_parent_or_self(module_); + i = 0; // We'll handle `super` below. + } else { + return Success(NoPrefixFound); + } + + // Now loop through all the `super`s we find. + while i < module_path.len() && + *interner.get(module_path[i]) == ~"super" { + debug!("(resolving module prefix) resolving `super` at %s", + self.module_to_str(containing_module)); + match self.get_nearest_normal_module_parent(containing_module) { + None => return Failed, + Some(new_module) => { + containing_module = new_module; + i += 1; + } + } + } + + debug!("(resolving module prefix) finished resolving prefix at %s", + self.module_to_str(containing_module)); + + return Success(PrefixFound(containing_module, i)); + } + + /// Attempts to resolve the supplied name in the given module for the + /// given namespace. If successful, returns the target corresponding to + /// the name. + fn resolve_name_in_module(@mut self, + module_: @mut Module, + name: ident, + namespace: Namespace, + name_search_type: NameSearchType) + -> ResolveResult { + debug!("(resolving name in module) resolving `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(module_)); + + // First, check the direct children of the module. + match module_.children.find(&name) { + Some(name_bindings) + if name_bindings.defined_in_namespace(namespace) => { + debug!("(resolving name in module) found node as child"); + return Success(Target(module_, *name_bindings)); + } + Some(_) | None => { + // Continue. + } + } + + // Next, check the module's imports if necessary. + + // If this is a search of all imports, we should be done with glob + // resolution at this point. + if name_search_type == SearchItemsAndAllImports { + assert!(module_.glob_count == 0); + } + + // Check the list of resolved imports. + match module_.import_resolutions.find(&name) { + Some(import_resolution) => { + if import_resolution.privacy == Public && + import_resolution.outstanding_references != 0 { + debug!("(resolving name in module) import \ + unresolved; bailing out"); + return Indeterminate; + } + + match import_resolution.target_for_namespace(namespace) { + None => { + debug!("(resolving name in module) name found, \ + but not in namespace %?", + namespace); + } + Some(target) + if name_search_type == + SearchItemsAndAllImports || + import_resolution.privacy == Public => { + debug!("(resolving name in module) resolved to \ + import"); + import_resolution.state.used = true; + return Success(copy target); + } + Some(_) => { + debug!("(resolving name in module) name found, \ + but not public"); + } + } + } + None => {} // Continue. + } + + // Finally, search through external children. + if namespace == TypeNS { + match module_.external_module_children.find(&name) { + None => {} + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + return Success(Target(module_, name_bindings)); + } + } + } + + // We're out of luck. + debug!("(resolving name in module) failed to resolve %s", + *self.session.str_of(name)); + return Failed; + } + + fn report_unresolved_imports(@mut self, module_: @mut Module) { + let index = module_.resolved_import_count; + let imports: &mut ~[@ImportDirective] = &mut *module_.imports; + let import_count = imports.len(); + if index != import_count { + let sn = self.session.codemap.span_to_snippet(imports[index].span); + if str::contains(sn, "::") { + self.session.span_err(imports[index].span, ~"unresolved import"); + } else { + let err = fmt!("unresolved import (maybe you meant `%s::*`?)", + sn.slice(0, sn.len() - 1)); // -1 to adjust for semicolon + self.session.span_err(imports[index].span, err); + } + } + + // Descend into children and anonymous children. + for module_.children.each_value |&child_node| { + match child_node.get_module_if_available() { + None => { + // Continue. + } + Some(child_module) => { + self.report_unresolved_imports(child_module); + } + } + } + + for module_.anonymous_children.each_value |&module_| { + self.report_unresolved_imports(module_); + } + } + + // Export recording + // + // This pass simply determines what all "export" keywords refer to and + // writes the results into the export map. + // + // FIXME #4953 This pass will be removed once exports change to per-item. + // Then this operation can simply be performed as part of item (or import) + // processing. + + fn record_exports(@mut self) { + let root_module = self.graph_root.get_module(); + self.record_exports_for_module_subtree(root_module); + } + + fn record_exports_for_module_subtree(@mut self, module_: @mut Module) { + // If this isn't a local crate, then bail out. We don't need to record + // exports for nonlocal crates. + + match module_.def_id { + Some(def_id) if def_id.crate == local_crate => { + // OK. Continue. + debug!("(recording exports for module subtree) recording \ + exports for local module"); + } + None => { + // Record exports for the root module. + debug!("(recording exports for module subtree) recording \ + exports for root module"); + } + Some(_) => { + // Bail out. + debug!("(recording exports for module subtree) not recording \ + exports for `%s`", + self.module_to_str(module_)); + return; + } + } + + self.record_exports_for_module(module_); + + for module_.children.each_value |&child_name_bindings| { + match child_name_bindings.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.record_exports_for_module_subtree(child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.record_exports_for_module_subtree(child_module); + } + } + + fn record_exports_for_module(@mut self, module_: @mut Module) { + let mut exports2 = ~[]; + + self.add_exports_for_module(&mut exports2, module_); + match /*bad*/copy module_.def_id { + Some(def_id) => { + self.export_map2.insert(def_id.node, exports2); + debug!("(computing exports) writing exports for %d (some)", + def_id.node); + } + None => {} + } + } + + fn add_exports_of_namebindings(@mut self, + exports2: &mut ~[Export2], + ident: ident, + namebindings: @mut NameBindings, + ns: Namespace, + reexport: bool) { + match (namebindings.def_for_namespace(ns), + namebindings.privacy_for_namespace(ns)) { + (Some(d), Some(Public)) => { + debug!("(computing exports) YES: %s '%s' => %?", + if reexport { ~"reexport" } else { ~"export"}, + *self.session.str_of(ident), + def_id_of_def(d)); + exports2.push(Export2 { + reexport: reexport, + name: self.session.str_of(ident), + def_id: def_id_of_def(d) + }); + } + (Some(_), Some(privacy)) => { + debug!("(computing reexports) NO: privacy %?", privacy); + } + (d_opt, p_opt) => { + debug!("(computing reexports) NO: %?, %?", d_opt, p_opt); + } + } + } + + fn add_exports_for_module(@mut self, + exports2: &mut ~[Export2], + module_: @mut Module) { + for module_.children.each |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.each |ident, importresolution| { + if importresolution.privacy != Public { + debug!("(computing exports) not reexporting private `%s`", + *self.session.str_of(*ident)); + loop; + } + for [ TypeNS, ValueNS ].each |ns| { + match importresolution.target_for_namespace(*ns) { + Some(target) => { + debug!("(computing exports) maybe reexport '%s'", + *self.session.str_of(*ident)); + self.add_exports_of_namebindings(&mut *exports2, + *ident, + target.bindings, + *ns, + true) + } + _ => () + } + } + } + } + + // AST resolution + // + // We maintain a list of value ribs and type ribs. + // + // Simultaneously, we keep track of the current position in the module + // graph in the `current_module` pointer. When we go to resolve a name in + // the value or type namespaces, we first look through all the ribs and + // then query the module graph. When we resolve a name in the module + // namespace, we can skip all the ribs (since nested modules are not + // allowed within blocks in Rust) and jump straight to the current module + // graph node. + // + // Named implementations are handled separately. When we find a method + // call, we consult the module node to find all of the implementations in + // scope. This information is lazily cached in the module node. We then + // generate a fake "implementation scope" containing all the + // implementations thus found, for compatibility with old resolve pass. + + fn with_scope(@mut self, name: Option, f: &fn()) { + let orig_module = self.current_module; + + // Move down in the graph. + match name { + None => { + // Nothing to do. + } + Some(name) => { + match orig_module.children.find(&name) { + None => { + debug!("!!! (with scope) didn't find `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(orig_module)); + } + Some(name_bindings) => { + match (*name_bindings).get_module_if_available() { + None => { + debug!("!!! (with scope) didn't find module \ + for `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(orig_module)); + } + Some(module_) => { + self.current_module = module_; + } + } + } + } + } + } + + f(); + + self.current_module = orig_module; + } + + // Wraps the given definition in the appropriate number of `def_upvar` + // wrappers. + + fn upvarify(@mut self, + ribs: &mut ~[@Rib], + rib_index: uint, + def_like: def_like, + span: span, + allow_capturing_self: AllowCapturingSelfFlag) + -> Option { + let mut def; + let is_ty_param; + + match def_like { + dl_def(d @ def_local(*)) | dl_def(d @ def_upvar(*)) | + dl_def(d @ def_arg(*)) | dl_def(d @ def_binding(*)) => { + def = d; + is_ty_param = false; + } + dl_def(d @ def_ty_param(*)) => { + def = d; + is_ty_param = true; + } + dl_def(d @ def_self(*)) + if allow_capturing_self == DontAllowCapturingSelf => { + def = d; + is_ty_param = false; + } + _ => { + return Some(def_like); + } + } + + let mut rib_index = rib_index + 1; + while rib_index < ribs.len() { + match ribs[rib_index].kind { + NormalRibKind => { + // Nothing to do. Continue. + } + FunctionRibKind(function_id, body_id) => { + if !is_ty_param { + def = def_upvar(def_id_of_def(def).node, + @def, + function_id, + body_id); + } + } + MethodRibKind(item_id, _) => { + // If the def is a ty param, and came from the parent + // item, it's ok + match def { + def_ty_param(did, _) + if self.def_map.find(&did.node).map_consume(|x| *x) + == Some(def_typaram_binder(item_id)) => { + // ok + } + _ => { + if !is_ty_param { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + + self.session.span_err( + span, + ~"attempted dynamic environment-capture"); + } else { + // This was an attempt to use a type parameter outside + // its scope. + + self.session.span_err(span, + ~"attempt to use a type \ + argument out of scope"); + } + + return None; + } + } + } + OpaqueFunctionRibKind => { + if !is_ty_param { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + + self.session.span_err( + span, + ~"attempted dynamic environment-capture"); + } else { + // This was an attempt to use a type parameter outside + // its scope. + + self.session.span_err(span, + ~"attempt to use a type \ + argument out of scope"); + } + + return None; + } + ConstantItemRibKind => { + // Still doesn't deal with upvars + self.session.span_err(span, + ~"attempt to use a non-constant \ + value in a constant"); + + } + } + + rib_index += 1; + } + + return Some(dl_def(def)); + } + + fn search_ribs(@mut self, + ribs: &mut ~[@Rib], + name: ident, + span: span, + allow_capturing_self: AllowCapturingSelfFlag) + -> Option { + // FIXME #4950: This should not use a while loop. + // FIXME #4950: Try caching? + + let mut i = ribs.len(); + while i != 0 { + i -= 1; + match ribs[i].bindings.find(&name) { + Some(&def_like) => { + return self.upvarify(ribs, i, def_like, span, + allow_capturing_self); + } + None => { + // Continue. + } + } + } + + return None; + } + + fn resolve_crate(@mut self) { + debug!("(resolving crate) starting"); + + visit_crate(self.crate, (), mk_vt(@Visitor { + visit_item: |item, _context, visitor| + self.resolve_item(item, visitor), + visit_arm: |arm, _context, visitor| + self.resolve_arm(arm, visitor), + visit_block: |block, _context, visitor| + self.resolve_block(block, visitor), + visit_expr: |expr, _context, visitor| + self.resolve_expr(expr, visitor), + visit_local: |local, _context, visitor| + self.resolve_local(local, visitor), + visit_ty: |ty, _context, visitor| + self.resolve_type(ty, visitor), + .. *default_visitor() + })); + } + + fn resolve_item(@mut self, item: @item, visitor: ResolveVisitor) { + debug!("(resolving item) resolving %s", + *self.session.str_of(item.ident)); + + // Items with the !resolve_unexported attribute are X-ray contexts. + // This is used to allow the test runner to run unexported tests. + let orig_xray_flag = self.xray_context; + if contains_name(attr_metas(item.attrs), + ~"!resolve_unexported") { + self.xray_context = Xray; + } + + match item.node { + + // enum item: resolve all the variants' discrs, + // then resolve the ty params + item_enum(ref enum_def, ref generics) => { + for (*enum_def).variants.each() |variant| { + for variant.node.disr_expr.each |dis_expr| { + // resolve the discriminator expr + // as a constant + self.with_constant_rib(|| { + self.resolve_expr(*dis_expr, visitor); + }); + } + } + + // n.b. the discr expr gets visted twice. + // but maybe it's okay since the first time will signal an + // error if there is one? -- tjc + do self.with_type_parameter_rib( + HasTypeParameters( + generics, item.id, 0, NormalRibKind)) { + visit_item(item, (), visitor); + } + } + + item_ty(_, ref generics) => { + do self.with_type_parameter_rib + (HasTypeParameters(generics, item.id, 0, + NormalRibKind)) + || { + + visit_item(item, (), visitor); + } + } + + item_impl(ref generics, + implemented_traits, + self_type, + ref methods) => { + self.resolve_implementation(item.id, + generics, + implemented_traits, + self_type, + *methods, + visitor); + } + + item_trait(ref generics, ref traits, ref methods) => { + // Create a new rib for the self type. + let self_type_rib = @Rib(NormalRibKind); + self.type_ribs.push(self_type_rib); + self_type_rib.bindings.insert(self.type_self_ident, + dl_def(def_self_ty(item.id))); + + // Create a new rib for the trait-wide type parameters. + do self.with_type_parameter_rib + (HasTypeParameters(generics, item.id, 0, + NormalRibKind)) { + + self.resolve_type_parameters(&generics.ty_params, + visitor); + + // Resolve derived traits. + for traits.each |trt| { + match self.resolve_path(trt.path, TypeNS, true, + visitor) { + None => + self.session.span_err(trt.path.span, + ~"attempt to derive a \ + nonexistent trait"), + Some(def) => { + // Write a mapping from the trait ID to the + // definition of the trait into the definition + // map. + + debug!("(resolving trait) found trait def: \ + %?", def); + + self.record_def(trt.ref_id, def); + } + } + } + + for (*methods).each |method| { + // Create a new rib for the method-specific type + // parameters. + // + // FIXME #4951: Do we need a node ID here? + + match *method { + required(ref ty_m) => { + do self.with_type_parameter_rib + (HasTypeParameters(&ty_m.generics, + item.id, + generics.ty_params.len(), + MethodRibKind(item.id, Required))) { + + // Resolve the method-specific type + // parameters. + self.resolve_type_parameters( + &ty_m.generics.ty_params, + visitor); + + for ty_m.decl.inputs.each |argument| { + self.resolve_type(argument.ty, visitor); + } + + self.resolve_type(ty_m.decl.output, visitor); + } + } + provided(m) => { + self.resolve_method(MethodRibKind(item.id, + Provided(m.id)), + m, + generics.ty_params.len(), + visitor) + } + } + } + } + + self.type_ribs.pop(); + } + + item_struct(ref struct_def, ref generics) => { + self.resolve_struct(item.id, + generics, + struct_def.fields, + visitor); + } + + item_mod(ref module_) => { + do self.with_scope(Some(item.ident)) { + self.resolve_module(module_, item.span, item.ident, + item.id, visitor); + } + } + + item_foreign_mod(ref foreign_module) => { + do self.with_scope(Some(item.ident)) { + for foreign_module.items.each |foreign_item| { + match foreign_item.node { + foreign_item_fn(_, _, ref generics) => { + self.with_type_parameter_rib( + HasTypeParameters( + generics, foreign_item.id, 0, + NormalRibKind), + || visit_foreign_item(*foreign_item, (), + visitor)); + } + foreign_item_const(_) => { + visit_foreign_item(*foreign_item, (), + visitor); + } + } + } + } + } + + item_fn(ref fn_decl, _, _, ref generics, ref block) => { + // If this is the main function, we must record it in the + // session. + + // FIXME #4404 android JNI hacks + if !*self.session.building_library || + self.session.targ_cfg.os == session::os_android { + + if self.attr_main_fn.is_none() && + item.ident == special_idents::main { + + self.main_fns.push(Some((item.id, item.span))); + } + + if attrs_contains_name(item.attrs, ~"main") { + if self.attr_main_fn.is_none() { + self.attr_main_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + ~"multiple 'main' functions"); + } + } + + if attrs_contains_name(item.attrs, ~"start") { + if self.start_fn.is_none() { + self.start_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + ~"multiple 'start' functions"); + } + } + } + + self.resolve_function(OpaqueFunctionRibKind, + Some(fn_decl), + HasTypeParameters + (generics, + item.id, + 0, + OpaqueFunctionRibKind), + block, + NoSelfBinding, + visitor); + } + + item_const(*) => { + self.with_constant_rib(|| { + visit_item(item, (), visitor); + }); + } + + item_mac(*) => { + fail!(~"item macros unimplemented") + } + } + + self.xray_context = orig_xray_flag; + } + + fn with_type_parameter_rib(@mut self, + type_parameters: TypeParameters, + f: &fn()) { + match type_parameters { + HasTypeParameters(generics, node_id, initial_index, + rib_kind) => { + + let function_type_rib = @Rib(rib_kind); + self.type_ribs.push(function_type_rib); + + for generics.ty_params.eachi |index, type_parameter| { + let name = type_parameter.ident; + debug!("with_type_parameter_rib: %d %d", node_id, + type_parameter.id); + let def_like = dl_def(def_ty_param + (local_def(type_parameter.id), + index + initial_index)); + // Associate this type parameter with + // the item that bound it + self.record_def(type_parameter.id, + def_typaram_binder(node_id)); + function_type_rib.bindings.insert(name, def_like); + } + } + + NoTypeParameters => { + // Nothing to do. + } + } + + f(); + + match type_parameters { + HasTypeParameters(*) => { + self.type_ribs.pop(); + } + + NoTypeParameters => { + // Nothing to do. + } + } + } + + fn with_label_rib(@mut self, f: &fn()) { + self.label_ribs.push(@Rib(NormalRibKind)); + f(); + self.label_ribs.pop(); + } + + fn with_constant_rib(@mut self, f: &fn()) { + self.value_ribs.push(@Rib(ConstantItemRibKind)); + f(); + self.value_ribs.pop(); + } + + fn resolve_function(@mut self, + rib_kind: RibKind, + optional_declaration: Option<&fn_decl>, + type_parameters: TypeParameters, + block: &blk, + self_binding: SelfBinding, + visitor: ResolveVisitor) { + // Create a value rib for the function. + let function_value_rib = @Rib(rib_kind); + self.value_ribs.push(function_value_rib); + + // Create a label rib for the function. + let function_label_rib = @Rib(rib_kind); + self.label_ribs.push(function_label_rib); + + // If this function has type parameters, add them now. + do self.with_type_parameter_rib(type_parameters) { + // Resolve the type parameters. + match type_parameters { + NoTypeParameters => { + // Continue. + } + HasTypeParameters(ref generics, _, _, _) => { + self.resolve_type_parameters(&generics.ty_params, + visitor); + } + } + + // Add self to the rib, if necessary. + match self_binding { + NoSelfBinding => { + // Nothing to do. + } + HasSelfBinding(self_node_id, is_implicit) => { + let def_like = dl_def(def_self(self_node_id, + is_implicit)); + *function_value_rib.self_binding = Some(def_like); + } + } + + // Add each argument to the rib. + match optional_declaration { + None => { + // Nothing to do. + } + Some(declaration) => { + for declaration.inputs.each |argument| { + let binding_mode = ArgumentIrrefutableMode; + let mutability = + if argument.is_mutbl {Mutable} else {Immutable}; + self.resolve_pattern(argument.pat, + binding_mode, + mutability, + None, + visitor); + + self.resolve_type(argument.ty, visitor); + + debug!("(resolving function) recorded argument"); + } + + self.resolve_type(declaration.output, visitor); + } + } + + // Resolve the function body. + self.resolve_block(block, visitor); + + debug!("(resolving function) leaving function"); + } + + self.label_ribs.pop(); + self.value_ribs.pop(); + } + + fn resolve_type_parameters(@mut self, + type_parameters: &OptVec, + visitor: ResolveVisitor) { + for type_parameters.each |type_parameter| { + for type_parameter.bounds.each |&bound| { + match bound { + TraitTyParamBound(tref) => { + self.resolve_trait_reference(tref, visitor) + } + RegionTyParamBound => {} + } + } + } + } + + fn resolve_trait_reference(@mut self, + trait_reference: &trait_ref, + visitor: ResolveVisitor) { + match self.resolve_path(trait_reference.path, TypeNS, true, visitor) { + None => { + self.session.span_err(trait_reference.path.span, + ~"attempt to implement an \ + unknown trait"); + } + Some(def) => { + self.record_def(trait_reference.ref_id, def); + } + } + } + + fn resolve_struct(@mut self, + id: node_id, + generics: &Generics, + fields: &[@struct_field], + visitor: ResolveVisitor) { + // If applicable, create a rib for the type parameters. + do self.with_type_parameter_rib(HasTypeParameters + (generics, id, 0, + OpaqueFunctionRibKind)) { + + // Resolve the type parameters. + self.resolve_type_parameters(&generics.ty_params, visitor); + + // Resolve fields. + for fields.each |field| { + self.resolve_type(field.node.ty, visitor); + } + } + } + + // Does this really need to take a RibKind or is it always going + // to be NormalRibKind? + fn resolve_method(@mut self, + rib_kind: RibKind, + method: @method, + outer_type_parameter_count: uint, + visitor: ResolveVisitor) { + let method_generics = &method.generics; + let type_parameters = + HasTypeParameters(method_generics, + method.id, + outer_type_parameter_count, + rib_kind); + // we only have self ty if it is a non static method + let self_binding = match method.self_ty.node { + sty_static => { NoSelfBinding } + _ => { HasSelfBinding(method.self_id, false) } + }; + + self.resolve_function(rib_kind, + Some(&method.decl), + type_parameters, + &method.body, + self_binding, + visitor); + } + + fn resolve_implementation(@mut self, + id: node_id, + generics: &Generics, + opt_trait_reference: Option<@trait_ref>, + self_type: @Ty, + methods: &[@method], + visitor: ResolveVisitor) { + // If applicable, create a rib for the type parameters. + let outer_type_parameter_count = generics.ty_params.len(); + do self.with_type_parameter_rib(HasTypeParameters + (generics, id, 0, + NormalRibKind)) { + // Resolve the type parameters. + self.resolve_type_parameters(&generics.ty_params, + visitor); + + // Resolve the trait reference, if necessary. + let original_trait_refs; + match opt_trait_reference { + Some(trait_reference) => { + self.resolve_trait_reference(trait_reference, visitor); + + // Record the current set of trait references. + let mut new_trait_refs = ~[]; + for self.def_map.find(&trait_reference.ref_id).each |&def| { + new_trait_refs.push(def_id_of_def(*def)); + } + original_trait_refs = Some(util::replace( + &mut self.current_trait_refs, + Some(new_trait_refs))); + } + None => { + original_trait_refs = None; + } + } + + // Resolve the self type. + self.resolve_type(self_type, visitor); + + for methods.each |method| { + // We also need a new scope for the method-specific + // type parameters. + self.resolve_method(MethodRibKind( + id, + Provided(method.id)), + *method, + outer_type_parameter_count, + visitor); +/* + let borrowed_type_parameters = &method.tps; + self.resolve_function(MethodRibKind( + id, + Provided(method.id)), + Some(@method.decl), + HasTypeParameters + (borrowed_type_parameters, + method.id, + outer_type_parameter_count, + NormalRibKind), + method.body, + HasSelfBinding(method.self_id), + visitor); +*/ + } + + // Restore the original trait references. + match original_trait_refs { + Some(r) => { self.current_trait_refs = r; } + None => () + } + } + } + + fn resolve_module(@mut self, + module_: &_mod, + span: span, + _name: ident, + id: node_id, + visitor: ResolveVisitor) { + // Write the implementations in scope into the module metadata. + debug!("(resolving module) resolving module ID %d", id); + visit_mod(module_, span, id, (), visitor); + } + + fn resolve_local(@mut self, local: @local, visitor: ResolveVisitor) { + let mutability = if local.node.is_mutbl {Mutable} else {Immutable}; + + // Resolve the type. + self.resolve_type(local.node.ty, visitor); + + // Resolve the initializer, if necessary. + match local.node.init { + None => { + // Nothing to do. + } + Some(initializer) => { + self.resolve_expr(initializer, visitor); + } + } + + // Resolve the pattern. + self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability, + None, visitor); + } + + fn binding_mode_map(@mut self, pat: @pat) -> BindingMap { + let mut result = HashMap::new(); + do pat_bindings(self.def_map, pat) |binding_mode, _id, sp, path| { + let ident = path_to_ident(path); + result.insert(ident, + binding_info {span: sp, + binding_mode: binding_mode}); + } + return result; + } + + fn check_consistent_bindings(@mut self, arm: &arm) { + if arm.pats.len() == 0 { return; } + let map_0 = self.binding_mode_map(arm.pats[0]); + for arm.pats.eachi() |i, p| { + let map_i = self.binding_mode_map(*p); + + for map_0.each |&key, &binding_0| { + match map_i.find(&key) { + None => { + self.session.span_err( + p.span, + fmt!("variable `%s` from pattern #1 is \ + not bound in pattern #%u", + *self.session.str_of(key), i + 1)); + } + Some(binding_i) => { + if binding_0.binding_mode != binding_i.binding_mode { + self.session.span_err( + binding_i.span, + fmt!("variable `%s` is bound with different \ + mode in pattern #%u than in pattern #1", + *self.session.str_of(key), i + 1)); + } + } + } + } + + for map_i.each |&key, &binding| { + if !map_0.contains_key(&key) { + self.session.span_err( + binding.span, + fmt!("variable `%s` from pattern #%u is \ + not bound in pattern #1", + *self.session.str_of(key), i + 1)); + } + } + } + } + + fn resolve_arm(@mut self, arm: &arm, visitor: ResolveVisitor) { + self.value_ribs.push(@Rib(NormalRibKind)); + + let bindings_list = @mut HashMap::new(); + for arm.pats.each |pattern| { + self.resolve_pattern(*pattern, RefutableMode, Immutable, + Some(bindings_list), visitor); + } + + // This has to happen *after* we determine which + // pat_idents are variants + self.check_consistent_bindings(arm); + + visit_expr_opt(arm.guard, (), visitor); + self.resolve_block(&arm.body, visitor); + + self.value_ribs.pop(); + } + + fn resolve_block(@mut self, block: &blk, visitor: ResolveVisitor) { + debug!("(resolving block) entering block"); + self.value_ribs.push(@Rib(NormalRibKind)); + + // Move down in the graph, if there's an anonymous module rooted here. + let orig_module = self.current_module; + match self.current_module.anonymous_children.find(&block.node.id) { + None => { /* Nothing to do. */ } + Some(&anonymous_module) => { + debug!("(resolving block) found anonymous module, moving \ + down"); + self.current_module = anonymous_module; + } + } + + // Descend into the block. + visit_block(block, (), visitor); + + // Move back up. + self.current_module = orig_module; + + self.value_ribs.pop(); + debug!("(resolving block) leaving block"); + } + + fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) { + match ty.node { + // Like path expressions, the interpretation of path types depends + // on whether the path has multiple elements in it or not. + + ty_path(path, path_id) => { + // This is a path in the type namespace. Walk through scopes + // scopes looking for it. + let mut result_def = None; + + // First, check to see whether the name is a primitive type. + if path.idents.len() == 1 { + let name = *path.idents.last(); + + match self.primitive_type_table + .primitive_types + .find(&name) { + + Some(&primitive_type) => { + result_def = + Some(def_prim_ty(primitive_type)); + } + None => { + // Continue. + } + } + } + + match result_def { + None => { + match self.resolve_path(path, TypeNS, true, visitor) { + Some(def) => { + debug!("(resolving type) resolved `%s` to \ + type %?", + *self.session.str_of( + *path.idents.last()), + def); + result_def = Some(def); + } + None => { + result_def = None; + } + } + } + Some(_) => { + // Continue. + } + } + + match result_def { + Some(def) => { + // Write the result into the def map. + debug!("(resolving type) writing resolution for `%s` \ + (id %d)", + self.idents_to_str(path.idents), + path_id); + self.record_def(path_id, def); + } + None => { + self.session.span_err + (ty.span, fmt!("use of undeclared type name `%s`", + self.idents_to_str(path.idents))); + } + } + } + + _ => { + // Just resolve embedded types. + visit_ty(ty, (), visitor); + } + } + } + + fn resolve_pattern(@mut self, + pattern: @pat, + mode: PatternBindingMode, + mutability: Mutability, + // Maps idents to the node ID for the (outermost) + // pattern that binds them + bindings_list: Option<@mut HashMap>, + visitor: ResolveVisitor) { + let pat_id = pattern.id; + do walk_pat(pattern) |pattern| { + match pattern.node { + pat_ident(binding_mode, path, _) + if !path.global && path.idents.len() == 1 => { + + // The meaning of pat_ident with no type parameters + // depends on whether an enum variant or unit-like struct + // with that name is in scope. The probing lookup has to + // be careful not to emit spurious errors. Only matching + // patterns (match) can match nullary variants or + // unit-like structs. For binding patterns (let), matching + // such a value is simply disallowed (since it's rarely + // what you want). + + let ident = path.idents[0]; + + match self.resolve_bare_identifier_pattern(ident) { + FoundStructOrEnumVariant(def) + if mode == RefutableMode => { + debug!("(resolving pattern) resolving `%s` to \ + struct or enum variant", + *self.session.str_of(ident)); + + self.enforce_default_binding_mode( + pattern, + binding_mode, + "an enum variant"); + self.record_def(pattern.id, def); + } + FoundStructOrEnumVariant(_) => { + self.session.span_err(pattern.span, + fmt!("declaration of `%s` \ + shadows an enum \ + variant or unit-like \ + struct in scope", + *self.session + .str_of(ident))); + } + FoundConst(def) if mode == RefutableMode => { + debug!("(resolving pattern) resolving `%s` to \ + constant", + *self.session.str_of(ident)); + + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); + self.record_def(pattern.id, def); + } + FoundConst(_) => { + self.session.span_err(pattern.span, + ~"only refutable patterns \ + allowed here"); + } + BareIdentifierPatternUnresolved => { + debug!("(resolving pattern) binding `%s`", + *self.session.str_of(ident)); + + let is_mutable = mutability == Mutable; + + let def = match mode { + RefutableMode => { + // For pattern arms, we must use + // `def_binding` definitions. + + def_binding(pattern.id, binding_mode) + } + LocalIrrefutableMode => { + // But for locals, we use `def_local`. + def_local(pattern.id, is_mutable) + } + ArgumentIrrefutableMode => { + // And for function arguments, `def_arg`. + def_arg(pattern.id, is_mutable) + } + }; + + // Record the definition so that later passes + // will be able to distinguish variants from + // locals in patterns. + + self.record_def(pattern.id, def); + + // Add the binding to the local ribs, if it + // doesn't already exist in the bindings list. (We + // must not add it if it's in the bindings list + // because that breaks the assumptions later + // passes make about or-patterns.) + + match bindings_list { + Some(bindings_list) + if !bindings_list.contains_key(&ident) => { + let this = &mut *self; + let last_rib = this.value_ribs[ + this.value_ribs.len() - 1]; + last_rib.bindings.insert(ident, + dl_def(def)); + bindings_list.insert(ident, pat_id); + } + Some(b) => { + if b.find(&ident) == Some(&pat_id) { + // Then this is a duplicate variable + // in the same disjunct, which is an + // error + self.session.span_err(pattern.span, + fmt!("Identifier %s is bound more \ + than once in the same pattern", + path_to_str(path, self.session + .intr()))); + } + // Not bound in the same pattern: do nothing + } + None => { + let this = &mut *self; + let last_rib = this.value_ribs[ + this.value_ribs.len() - 1]; + last_rib.bindings.insert(ident, + dl_def(def)); + } + } + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_ident(binding_mode, path, _) => { + // This must be an enum variant, struct, or constant. + match self.resolve_path(path, ValueNS, false, visitor) { + Some(def @ def_variant(*)) | + Some(def @ def_struct(*)) => { + self.record_def(pattern.id, def); + } + Some(def @ def_const(*)) => { + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); + self.record_def(pattern.id, def); + } + Some(_) => { + self.session.span_err( + path.span, + fmt!("not an enum variant or constant: %s", + *self.session.str_of( + *path.idents.last()))); + } + None => { + self.session.span_err(path.span, + ~"unresolved enum variant"); + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_enum(path, _) => { + // This must be an enum variant, struct or const. + match self.resolve_path(path, ValueNS, false, visitor) { + Some(def @ def_fn(*)) | + Some(def @ def_variant(*)) | + Some(def @ def_struct(*)) | + Some(def @ def_const(*)) => { + self.record_def(pattern.id, def); + } + Some(_) => { + self.session.span_err( + path.span, + fmt!("not an enum variant, struct or const: %s", + *self.session.str_of( + *path.idents.last()))); + } + None => { + self.session.span_err(path.span, + ~"unresolved enum variant, \ + struct or const"); + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_lit(expr) => { + self.resolve_expr(expr, visitor); + } + + pat_range(first_expr, last_expr) => { + self.resolve_expr(first_expr, visitor); + self.resolve_expr(last_expr, visitor); + } + + pat_struct(path, _, _) => { + let structs: &mut HashSet = &mut self.structs; + match self.resolve_path(path, TypeNS, false, visitor) { + Some(def_ty(class_id)) + if structs.contains(&class_id) => { + let class_def = def_struct(class_id); + self.record_def(pattern.id, class_def); + } + Some(definition @ def_struct(class_id)) + if structs.contains(&class_id) => { + self.record_def(pattern.id, definition); + } + Some(definition @ def_variant(_, variant_id)) + if structs.contains(&variant_id) => { + self.record_def(pattern.id, definition); + } + result => { + debug!("(resolving pattern) didn't find struct \ + def: %?", result); + self.session.span_err( + path.span, + fmt!("`%s` does not name a structure", + self.idents_to_str(path.idents))); + } + } + } + + _ => { + // Nothing to do. + } + } + } + } + + fn resolve_bare_identifier_pattern(@mut self, name: ident) + -> BareIdentifierPatternResolution { + match self.resolve_item_in_lexical_scope(self.current_module, + name, + ValueNS, + SearchThroughModules) { + Success(target) => { + match target.bindings.value_def { + None => { + fail!(~"resolved name in the value namespace to a \ + set of name bindings with no def?!"); + } + Some(def) => { + match def.def { + def @ def_variant(*) | def @ def_struct(*) => { + return FoundStructOrEnumVariant(def); + } + def @ def_const(*) => { + return FoundConst(def); + } + _ => { + return BareIdentifierPatternUnresolved; + } + } + } + } + } + + Indeterminate => { + fail!(~"unexpected indeterminate result"); + } + + Failed => { + return BareIdentifierPatternUnresolved; + } + } + } + + /// If `check_ribs` is true, checks the local definitions first; i.e. + /// doesn't skip straight to the containing module. + fn resolve_path(@mut self, + path: @Path, + namespace: Namespace, + check_ribs: bool, + visitor: ResolveVisitor) + -> Option { + // First, resolve the types. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + + if path.global { + return self.resolve_crate_relative_path(path, + self.xray_context, + namespace); + } + + if path.idents.len() > 1 { + return self.resolve_module_relative_path(path, + self.xray_context, + namespace); + } + + return self.resolve_identifier(*path.idents.last(), + namespace, + check_ribs, + path.span); + } + + fn resolve_identifier(@mut self, + identifier: ident, + namespace: Namespace, + check_ribs: bool, + span: span) + -> Option { + if check_ribs { + match self.resolve_identifier_in_local_ribs(identifier, + namespace, + span) { + Some(def) => { + return Some(def); + } + None => { + // Continue. + } + } + } + + return self.resolve_item_by_identifier_in_lexical_scope(identifier, + namespace); + } + + // FIXME #4952: Merge me with resolve_name_in_module? + fn resolve_definition_of_name_in_module(@mut self, + containing_module: @mut Module, + name: ident, + namespace: Namespace, + xray: XrayFlag) + -> NameDefinition { + // First, search children. + match containing_module.children.find(&name) { + Some(child_name_bindings) => { + match (child_name_bindings.def_for_namespace(namespace), + child_name_bindings.privacy_for_namespace(namespace)) { + (Some(def), Some(Public)) => { + // Found it. Stop the search here. + return ChildNameDefinition(def); + } + (Some(def), _) if xray == Xray => { + // Found it. Stop the search here. + return ChildNameDefinition(def); + } + (Some(_), _) | (None, _) => { + // Continue. + } + } + } + None => { + // Continue. + } + } + + // Next, search import resolutions. + match containing_module.import_resolutions.find(&name) { + Some(import_resolution) if import_resolution.privacy == Public || + xray == Xray => { + match (*import_resolution).target_for_namespace(namespace) { + Some(target) => { + match (target.bindings.def_for_namespace(namespace), + target.bindings.privacy_for_namespace( + namespace)) { + (Some(def), Some(Public)) => { + // Found it. + import_resolution.state.used = true; + return ImportNameDefinition(def); + } + (Some(_), _) | (None, _) => { + // This can happen with external impls, due to + // the imperfect way we read the metadata. + } + } + } + None => {} + } + } + Some(_) | None => {} // Continue. + } + + // Finally, search through external children. + if namespace == TypeNS { + match containing_module.external_module_children.find(&name) { + None => {} + Some(module) => { + match module.def_id { + None => {} // Continue. + Some(def_id) => { + return ChildNameDefinition(def_mod(def_id)); + } + } + } + } + } + + return NoNameDefinition; + } + + fn intern_module_part_of_path(@mut self, path: @Path) -> ~[ident] { + let mut module_path_idents = ~[]; + for path.idents.eachi |index, ident| { + if index == path.idents.len() - 1 { + break; + } + + module_path_idents.push(*ident); + } + + return module_path_idents; + } + + fn resolve_module_relative_path(@mut self, + path: @Path, + xray: XrayFlag, + namespace: Namespace) + -> Option { + let module_path_idents = self.intern_module_part_of_path(path); + + let containing_module; + match self.resolve_module_path_for_import(self.current_module, + module_path_idents, + UseLexicalScope, + path.span) { + Failed => { + self.session.span_err(path.span, + fmt!("use of undeclared module `%s`", + self.idents_to_str( + module_path_idents))); + return None; + } + + Indeterminate => { + fail!(~"indeterminate unexpected"); + } + + Success(resulting_module) => { + containing_module = resulting_module; + } + } + + let name = *path.idents.last(); + match self.resolve_definition_of_name_in_module(containing_module, + name, + namespace, + xray) { + NoNameDefinition => { + // We failed to resolve the name. Report an error. + return None; + } + ChildNameDefinition(def) | ImportNameDefinition(def) => { + return Some(def); + } + } + } + + /// Invariant: This must be called only during main resolution, not during + /// import resolution. + fn resolve_crate_relative_path(@mut self, + path: @Path, + xray: XrayFlag, + namespace: Namespace) + -> Option { + let module_path_idents = self.intern_module_part_of_path(path); + + let root_module = self.graph_root.get_module(); + + let containing_module; + match self.resolve_module_path_from_root(root_module, + module_path_idents, + 0, + path.span, + SearchItemsAndAllImports) { + Failed => { + self.session.span_err(path.span, + fmt!("use of undeclared module `::%s`", + self.idents_to_str( + module_path_idents))); + return None; + } + + Indeterminate => { + fail!(~"indeterminate unexpected"); + } + + Success(resulting_module) => { + containing_module = resulting_module; + } + } + + let name = *path.idents.last(); + match self.resolve_definition_of_name_in_module(containing_module, + name, + namespace, + xray) { + NoNameDefinition => { + // We failed to resolve the name. Report an error. + return None; + } + ChildNameDefinition(def) | ImportNameDefinition(def) => { + return Some(def); + } + } + } + + fn resolve_identifier_in_local_ribs(@mut self, + ident: ident, + namespace: Namespace, + span: span) + -> Option { + // Check the local set of ribs. + let search_result; + match namespace { + ValueNS => { + search_result = self.search_ribs(&mut self.value_ribs, ident, + span, + DontAllowCapturingSelf); + } + TypeNS => { + search_result = self.search_ribs(&mut self.type_ribs, ident, + span, AllowCapturingSelf); + } + } + + match search_result { + Some(dl_def(def)) => { + debug!("(resolving path in local ribs) resolved `%s` to \ + local: %?", + *self.session.str_of(ident), + def); + return Some(def); + } + Some(dl_field) | Some(dl_impl(_)) | None => { + return None; + } + } + } + + fn resolve_self_value_in_local_ribs(@mut self, span: span) + -> Option { + // FIXME #4950: This should not use a while loop. + let ribs = &mut self.value_ribs; + let mut i = ribs.len(); + while i != 0 { + i -= 1; + match *ribs[i].self_binding { + Some(def_like) => { + match self.upvarify(ribs, + i, + def_like, + span, + DontAllowCapturingSelf) { + Some(dl_def(def)) => return Some(def), + _ => { + self.session.span_bug(span, + ~"self wasn't mapped to a \ + def?!") + } + } + } + None => {} + } + } + + None + } + + fn resolve_item_by_identifier_in_lexical_scope(@mut self, + ident: ident, + namespace: Namespace) + -> Option { + // Check the items. + match self.resolve_item_in_lexical_scope(self.current_module, + ident, + namespace, + DontSearchThroughModules) { + Success(target) => { + match (*target.bindings).def_for_namespace(namespace) { + None => { + // This can happen if we were looking for a type and + // found a module instead. Modules don't have defs. + return None; + } + Some(def) => { + debug!("(resolving item path in lexical scope) \ + resolved `%s` to item", + *self.session.str_of(ident)); + return Some(def); + } + } + } + Indeterminate => { + fail!(~"unexpected indeterminate result"); + } + Failed => { + return None; + } + } + } + + fn find_best_match_for_name(@mut self, name: &str, max_distance: uint) -> Option<~str> { + let this = &mut *self; + + let mut maybes: ~[~str] = ~[]; + let mut values: ~[uint] = ~[]; + + let mut j = this.value_ribs.len(); + while j != 0 { + j -= 1; + for this.value_ribs[j].bindings.each_key |&k| { + vec::push(&mut maybes, copy *this.session.str_of(k)); + vec::push(&mut values, uint::max_value); + } + } + + let mut smallest = 0; + for maybes.eachi |i, &other| { + + values[i] = str::levdistance(name, other); + + if values[i] <= values[smallest] { + smallest = i; + } + } + + if vec::len(values) > 0 && + values[smallest] != uint::max_value && + values[smallest] < str::len(name) + 2 && + values[smallest] <= max_distance && + maybes[smallest] != name.to_owned() { + + Some(vec::swap_remove(&mut maybes, smallest)) + + } else { + None + } + } + + fn name_exists_in_scope_struct(@mut self, name: &str) -> bool { + let this = &mut *self; + + let mut i = this.type_ribs.len(); + while i != 0 { + i -= 1; + match this.type_ribs[i].kind { + MethodRibKind(node_id, _) => + for this.crate.node.module.items.each |item| { + if item.id == node_id { + match item.node { + item_struct(class_def, _) => { + for class_def.fields.each |field| { + match field.node.kind { + unnamed_field => {}, + named_field(ident, _) => { + if str::eq_slice(*this.session.str_of(ident), + name) { + return true + } + } + } + } + } + _ => {} + } + } + }, + _ => {} + } + } + return false; + } + + fn resolve_expr(@mut self, expr: @expr, visitor: ResolveVisitor) { + // First, record candidate traits for this expression if it could + // result in the invocation of a method call. + + self.record_candidate_traits_for_expr_if_necessary(expr); + + // Next, resolve the node. + match expr.node { + // The interpretation of paths depends on whether the path has + // multiple elements in it or not. + + expr_path(path) => { + // This is a local path in the value namespace. Walk through + // scopes looking for it. + + match self.resolve_path(path, ValueNS, true, visitor) { + Some(def) => { + // Write the result into the def map. + debug!("(resolving expr) resolved `%s`", + self.idents_to_str(path.idents)); + self.record_def(expr.id, def); + } + None => { + let wrong_name = self.idents_to_str( + path.idents); + if self.name_exists_in_scope_struct(wrong_name) { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`. \ + Did you mean: `self.%s`?", + wrong_name, + wrong_name)); + } + else { + // limit search to 5 to reduce the number + // of stupid suggestions + match self.find_best_match_for_name(wrong_name, 5) { + Some(m) => { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`. \ + Did you mean: `%s`?", + wrong_name, m)); + } + None => { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`.", + wrong_name)); + } + } + } + } + } + + visit_expr(expr, (), visitor); + } + + expr_fn_block(ref fn_decl, ref block) => { + self.resolve_function(FunctionRibKind(expr.id, block.node.id), + Some(fn_decl), + NoTypeParameters, + block, + NoSelfBinding, + visitor); + } + + expr_struct(path, _, _) => { + // Resolve the path to the structure it goes to. + let structs: &mut HashSet = &mut self.structs; + match self.resolve_path(path, TypeNS, false, visitor) { + Some(def_ty(class_id)) | Some(def_struct(class_id)) + if structs.contains(&class_id) => { + let class_def = def_struct(class_id); + self.record_def(expr.id, class_def); + } + Some(definition @ def_variant(_, class_id)) + if structs.contains(&class_id) => { + self.record_def(expr.id, definition); + } + _ => { + self.session.span_err( + path.span, + fmt!("`%s` does not name a structure", + self.idents_to_str(path.idents))); + } + } + + visit_expr(expr, (), visitor); + } + + expr_loop(_, Some(label)) => { + do self.with_label_rib { + let this = &mut *self; + let def_like = dl_def(def_label(expr.id)); + let rib = this.label_ribs[this.label_ribs.len() - 1]; + rib.bindings.insert(label, def_like); + + visit_expr(expr, (), visitor); + } + } + + expr_break(Some(label)) | expr_again(Some(label)) => { + match self.search_ribs(&mut self.label_ribs, label, expr.span, + DontAllowCapturingSelf) { + None => + self.session.span_err(expr.span, + fmt!("use of undeclared label \ + `%s`", + *self.session.str_of( + label))), + Some(dl_def(def @ def_label(_))) => { + self.record_def(expr.id, def) + } + Some(_) => { + self.session.span_bug(expr.span, + ~"label wasn't mapped to a \ + label def!") + } + } + } + + expr_self => { + match self.resolve_self_value_in_local_ribs(expr.span) { + None => { + self.session.span_err(expr.span, + ~"`self` is not allowed in \ + this context") + } + Some(def) => self.record_def(expr.id, def), + } + } + + _ => { + visit_expr(expr, (), visitor); + } + } + } + + fn record_candidate_traits_for_expr_if_necessary(@mut self, expr: @expr) { + match expr.node { + expr_field(_, ident, _) => { + let traits = self.search_for_traits_containing_method(ident); + self.trait_map.insert(expr.id, @mut traits); + } + expr_method_call(_, ident, _, _, _) => { + let traits = self.search_for_traits_containing_method(ident); + self.trait_map.insert(expr.id, @mut traits); + } + expr_binary(add, _, _) | expr_assign_op(add, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.add_trait()); + } + expr_binary(subtract, _, _) | expr_assign_op(subtract, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.sub_trait()); + } + expr_binary(mul, _, _) | expr_assign_op(mul, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.mul_trait()); + } + expr_binary(div, _, _) | expr_assign_op(div, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.div_trait()); + } + expr_binary(rem, _, _) | expr_assign_op(rem, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.rem_trait()); + } + expr_binary(bitxor, _, _) | expr_assign_op(bitxor, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitxor_trait()); + } + expr_binary(bitand, _, _) | expr_assign_op(bitand, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitand_trait()); + } + expr_binary(bitor, _, _) | expr_assign_op(bitor, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitor_trait()); + } + expr_binary(shl, _, _) | expr_assign_op(shl, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.shl_trait()); + } + expr_binary(shr, _, _) | expr_assign_op(shr, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.shr_trait()); + } + expr_binary(lt, _, _) | expr_binary(le, _, _) | + expr_binary(ge, _, _) | expr_binary(gt, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.ord_trait()); + } + expr_binary(eq, _, _) | expr_binary(ne, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.eq_trait()); + } + expr_unary(neg, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.neg_trait()); + } + expr_unary(not, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.not_trait()); + } + expr_index(*) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.index_trait()); + } + _ => { + // Nothing to do. + } + } + } + + fn search_for_traits_containing_method(@mut self, + name: ident) + -> ~[def_id] { + 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; + loop { + // Look for the current trait. + match /*bad*/copy self.current_trait_refs { + Some(trait_def_ids) => { + for trait_def_ids.each |trait_def_id| { + self.add_trait_info_if_containing_method( + &mut found_traits, *trait_def_id, name); + } + } + None => { + // Nothing to do. + } + } + + // Look for trait children. + for search_module.children.each_value |&child_name_bindings| { + match child_name_bindings.def_for_namespace(TypeNS) { + Some(def) => { + match def { + def_trait(trait_def_id) => { + self.add_trait_info_if_containing_method( + &mut found_traits, trait_def_id, name); + } + _ => { + // Continue. + } + } + } + None => { + // Continue. + } + } + } + + // Look for imports. + for search_module.import_resolutions.each_value + |&import_resolution| { + + match import_resolution.target_for_namespace(TypeNS) { + None => { + // Continue. + } + Some(target) => { + match target.bindings.def_for_namespace(TypeNS) { + Some(def) => { + match def { + def_trait(trait_def_id) => { + let added = self. + add_trait_info_if_containing_method( + &mut found_traits, + trait_def_id, name); + if added { + import_resolution.state.used = + true; + } + } + _ => { + // Continue. + } + } + } + None => { + // Continue. + } + } + } + } + } + + // Move to the next parent. + match search_module.parent_link { + NoParentLink => { + // Done. + break; + } + ModuleParentLink(parent_module, _) | + BlockParentLink(parent_module, _) => { + search_module = parent_module; + } + } + } + + return found_traits; + } + + fn add_trait_info_if_containing_method(&self, + found_traits: &mut ~[def_id], + trait_def_id: def_id, + name: ident) + -> bool { + debug!("(adding trait info if containing method) trying trait %d:%d \ + for method '%s'", + trait_def_id.crate, + trait_def_id.node, + *self.session.str_of(name)); + + match self.trait_info.find(&trait_def_id) { + Some(trait_info) if trait_info.contains(&name) => { + debug!("(adding trait info if containing method) found trait \ + %d:%d for method '%s'", + trait_def_id.crate, + trait_def_id.node, + *self.session.str_of(name)); + found_traits.push(trait_def_id); + true + } + Some(_) | None => { + false + } + } + } + + fn add_fixed_trait_for_expr(@mut self, + expr_id: node_id, + trait_id: def_id) { + self.trait_map.insert(expr_id, @mut ~[trait_id]); + } + + fn record_def(@mut self, node_id: node_id, def: def) { + debug!("(recording def) recording %? for %?", def, node_id); + self.def_map.insert(node_id, def); + } + + fn enforce_default_binding_mode(@mut self, + pat: @pat, + pat_binding_mode: binding_mode, + descr: &str) { + match pat_binding_mode { + bind_infer => {} + bind_by_copy => { + self.session.span_err( + pat.span, + fmt!("cannot use `copy` binding mode with %s", + descr)); + } + bind_by_ref(*) => { + self.session.span_err( + pat.span, + fmt!("cannot use `ref` binding mode with %s", + descr)); + } + } + } + + // + // main function checking + // + // be sure that there is only one main function + // + fn check_duplicate_main(@mut self) { + let this = &mut *self; + if this.attr_main_fn.is_none() && this.start_fn.is_none() { + if this.main_fns.len() >= 1u { + let mut i = 1u; + while i < this.main_fns.len() { + let (_, dup_main_span) = this.main_fns[i].unwrap(); + this.session.span_err( + dup_main_span, + ~"multiple 'main' functions"); + i += 1; + } + *this.session.entry_fn = this.main_fns[0]; + *this.session.entry_type = Some(session::EntryMain); + } + } else if !this.start_fn.is_none() { + *this.session.entry_fn = this.start_fn; + *this.session.entry_type = Some(session::EntryStart); + } else { + *this.session.entry_fn = this.attr_main_fn; + *this.session.entry_type = Some(session::EntryMain); + } + } + + // + // Unused import checking + // + // Although this is a lint pass, it lives in here because it depends on + // resolve data structures. + // + + fn unused_import_lint_level(@mut self, m: @mut Module) -> level { + let settings = self.session.lint_settings; + match m.def_id { + Some(def) => get_lint_settings_level(settings, unused_imports, + def.node, def.node), + None => get_lint_level(settings.default_settings, unused_imports) + } + } + + fn check_for_unused_imports_if_necessary(@mut self) { + if self.unused_import_lint_level(self.current_module) == allow { + return; + } + + let root_module = self.graph_root.get_module(); + self.check_for_unused_imports_in_module_subtree(root_module); + } + + fn check_for_unused_imports_in_module_subtree(@mut self, + module_: @mut Module) { + // If this isn't a local crate, then bail out. We don't need to check + // for unused imports in external crates. + + match module_.def_id { + Some(def_id) if def_id.crate == local_crate => { + // OK. Continue. + } + None => { + // Check for unused imports in the root module. + } + Some(_) => { + // Bail out. + debug!("(checking for unused imports in module subtree) not \ + checking for unused imports for `%s`", + self.module_to_str(module_)); + return; + } + } + + self.check_for_unused_imports_in_module(module_); + + for module_.children.each_value |&child_name_bindings| { + match (*child_name_bindings).get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.check_for_unused_imports_in_module_subtree + (child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.check_for_unused_imports_in_module_subtree(child_module); + } + } + + fn check_for_unused_imports_in_module(@mut self, module_: @mut Module) { + for module_.import_resolutions.each_value |&import_resolution| { + // Ignore dummy spans for things like automatically injected + // imports for the prelude, and also don't warn about the same + // import statement being unused more than once. Furthermore, if + // the import is public, then we can't be sure whether it's unused + // or not so don't warn about it. + if !import_resolution.state.used && + !import_resolution.state.warned && + import_resolution.span != dummy_sp() && + import_resolution.privacy != Public { + import_resolution.state.warned = true; + let span = import_resolution.span; + self.session.span_lint_level( + self.unused_import_lint_level(module_), + span, + ~"unused import"); + } + } + } + + + // + // Diagnostics + // + // Diagnostics are not particularly efficient, because they're rarely + // hit. + // + + /// A somewhat inefficient routine to obtain the name of a module. + fn module_to_str(@mut self, module_: @mut Module) -> ~str { + let mut idents = ~[]; + let mut current_module = module_; + loop { + match current_module.parent_link { + NoParentLink => { + break; + } + ModuleParentLink(module_, name) => { + idents.push(name); + current_module = module_; + } + BlockParentLink(module_, _) => { + idents.push(special_idents::opaque); + current_module = module_; + } + } + } + + if idents.len() == 0 { + return ~"???"; + } + return self.idents_to_str(vec::reversed(idents)); + } + + fn dump_module(@mut self, module_: @mut Module) { + debug!("Dump of module `%s`:", self.module_to_str(module_)); + + debug!("Children:"); + for module_.children.each_key |&name| { + debug!("* %s", *self.session.str_of(name)); + } + + debug!("Import resolutions:"); + for module_.import_resolutions.each |name, import_resolution| { + let mut value_repr; + match import_resolution.target_for_namespace(ValueNS) { + None => { value_repr = ~""; } + Some(_) => { + value_repr = ~" value:?"; + // FIXME #4954 + } + } + + let mut type_repr; + match import_resolution.target_for_namespace(TypeNS) { + None => { type_repr = ~""; } + Some(_) => { + type_repr = ~" type:?"; + // FIXME #4954 + } + } + + debug!("* %s:%s%s", *self.session.str_of(*name), + value_repr, type_repr); + } + } +} + +pub struct CrateMap { + def_map: DefMap, + exp_map2: ExportMap2, + trait_map: TraitMap +} + +/// Entry point to crate resolution. +pub fn resolve_crate(session: Session, + lang_items: LanguageItems, + crate: @crate) + -> CrateMap { + let resolver = @mut Resolver(session, lang_items, crate); + resolver.resolve(); + let @Resolver{def_map, export_map2, trait_map, _} = resolver; + CrateMap { + def_map: def_map, + exp_map2: export_map2, + trait_map: trait_map + } +} diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c3a79373931a2..5c7c33d35b238 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -78,9 +78,11 @@ impl Subst for ~[T] { } } -impl Subst for @~[T] { - fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @~[T] { - @(**self).subst(tcx, substs) +impl Subst for @T { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @T { + match self { + &@ref t => @t.subst(tcx, substs) + } } } @@ -115,19 +117,11 @@ impl Subst for ty::BareFnTy { } } -impl Subst for ty::param_bound { - fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::param_bound { - match self { - &ty::bound_copy | - &ty::bound_durable | - &ty::bound_owned | - &ty::bound_const => { - *self - } - - &ty::bound_trait(tref) => { - ty::bound_trait(@tref.subst(tcx, substs)) - } +impl Subst for ty::ParamBounds { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::ParamBounds { + ty::ParamBounds { + builtin_bounds: self.builtin_bounds, + trait_bounds: self.trait_bounds.subst(tcx, substs) } } } @@ -186,4 +180,3 @@ impl Subst for ty::ty_param_bounds_and_ty { } } } - diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 3755cca8c35e9..b24e88698af88 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -280,10 +280,10 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { pub fn variant_opt(bcx: block, pat_id: ast::node_id) -> Opt { let ccx = bcx.ccx(); - match *ccx.tcx.def_map.get(&pat_id) { + match ccx.tcx.def_map.get_copy(&pat_id) { ast::def_variant(enum_id, var_id) => { let variants = ty::enum_variants(ccx.tcx, enum_id); - for vec::each(*variants) |v| { + for (*variants).each |v| { if var_id == v.id { return var(v.disr_val, adt::represent_node(bcx, pat_id)) @@ -349,7 +349,7 @@ pub fn matches_to_str(bcx: block, m: &[@Match]) -> ~str { } pub fn has_nested_bindings(m: &[@Match], col: uint) -> bool { - for vec::each(m) |br| { + for m.each |br| { match br.pats[col].node { ast::pat_ident(_, _, Some(_)) => return true, _ => () @@ -418,7 +418,7 @@ pub fn enter_match<'r>(bcx: block, let _indenter = indenter(); let mut result = ~[]; - for vec::each(m) |br| { + for m.each |br| { match e(br.pats[col]) { Some(sub) => { let pats = @@ -426,10 +426,10 @@ pub fn enter_match<'r>(bcx: block, vec::append(sub, vec::slice(br.pats, 0u, col)), vec::slice(br.pats, col + 1u, br.pats.len())); - let self = br.pats[col]; - match self.node { + let this = br.pats[col]; + match this.node { ast::pat_ident(_, path, None) => { - if pat_is_binding(dm, self) { + if pat_is_binding(dm, this) { let binding_info = br.data.bindings_map.get( &path_to_ident(path)); @@ -516,7 +516,7 @@ pub fn enter_opt<'r>(bcx: block, match p.node { ast::pat_enum(*) | ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { - let const_def = *tcx.def_map.get(&p.id); + let const_def = tcx.def_map.get_copy(&p.id); let const_def_id = ast_util::def_id_of_def(const_def); if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) { Some(~[]) @@ -552,13 +552,12 @@ pub fn enter_opt<'r>(bcx: block, if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { // Look up the struct variant ID. let struct_id; - match *tcx.def_map.get(&p.id) { + match tcx.def_map.get_copy(&p.id) { ast::def_variant(_, found_struct_id) => { struct_id = found_struct_id; } _ => { - tcx.sess.span_bug(p.span, ~"expected enum \ - variant def"); + tcx.sess.span_bug(p.span, "expected enum variant def"); } } @@ -866,7 +865,18 @@ pub fn extract_variant_args(bcx: block, ExtractedBlock { vals: args, bcx: bcx } } +fn match_datum(bcx: block, val: ValueRef, pat_id: ast::node_id) -> Datum { + //! Helper for converting from the ValueRef that we pass around in + //! the match code, which is always by ref, into a Datum. Eventually + //! we should just pass around a Datum and be done with it. + + let ty = node_id_type(bcx, pat_id); + Datum {val: val, ty: ty, mode: datum::ByRef, source: RevokeClean} +} + + pub fn extract_vec_elems(bcx: block, + pat_span: span, pat_id: ast::node_id, elem_count: uint, slice: Option, @@ -874,9 +884,10 @@ pub fn extract_vec_elems(bcx: block, count: ValueRef) -> ExtractedBlock { let _icx = bcx.insn_ctxt("match::extract_vec_elems"); + let vec_datum = match_datum(bcx, val, pat_id); + let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, + pat_id, 0); let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); - let unboxed = load_if_immediate(bcx, val, vt.vec_ty); - let (base, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty); let mut elems = do vec::from_fn(elem_count) |i| { match slice { @@ -924,7 +935,7 @@ pub fn collect_record_or_struct_fields(bcx: block, col: uint) -> ~[ast::ident] { let mut fields: ~[ast::ident] = ~[]; - for vec::each(m) |br| { + for m.each |br| { match br.pats[col].node { ast::pat_struct(_, ref fs, _) => { match ty::get(node_id_type(bcx, br.pats[col].id)).sty { @@ -947,30 +958,28 @@ pub fn collect_record_or_struct_fields(bcx: block, } } -pub fn root_pats_as_necessary(bcx: block, +pub fn pats_require_rooting(bcx: block, + m: &[@Match], + col: uint) + -> bool { + vec::any(m, |br| { + let pat_id = br.pats[col].id; + let key = root_map_key {id: pat_id, derefs: 0u }; + bcx.ccx().maps.root_map.contains_key(&key) + }) +} + +pub fn root_pats_as_necessary(mut bcx: block, m: &[@Match], col: uint, val: ValueRef) -> block { - let mut bcx = bcx; - for vec::each(m) |br| { + for m.each |br| { let pat_id = br.pats[col].id; - - let key = root_map_key {id: pat_id, derefs: 0u }; - match bcx.ccx().maps.root_map.find(&key) { - None => (), - Some(&root_info) => { - // Note: the scope_id will always be the id of the match. See - // the extended comment in rustc::middle::borrowck::preserve() - // for details (look for the case covering cat_discr). - - let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), - mode: ByRef, source: ZeroMem}; - bcx = datum.root(bcx, root_info); - // If we kept going, we'd only re-root the same value, so - // return now. - return bcx; - } + if pat_id != 0 { + let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), + mode: ByRef, source: ZeroMem}; + bcx = datum.root_and_write_guard(bcx, br.pats[col].span, pat_id, 0); } } return bcx; @@ -1034,14 +1043,14 @@ pub fn pick_col(m: &[@Match]) -> uint { } } let mut scores = vec::from_elem(m[0].pats.len(), 0u); - for vec::each(m) |br| { + for m.each |br| { let mut i = 0u; - for vec::each(br.pats) |p| { scores[i] += score(*p); i += 1u; } + for br.pats.each |p| { scores[i] += score(*p); i += 1u; } } let mut max_score = 0u; let mut best_col = 0u; let mut i = 0u; - for vec::each(scores) |score| { + for scores.each |score| { let score = *score; // Irrefutable columns always go first, they'd only be duplicated in @@ -1114,7 +1123,8 @@ pub fn compare_values(cx: block, pub fn store_non_ref_bindings(bcx: block, data: &ArmData, opt_temp_cleanups: Option<&mut ~[ValueRef]>) - -> block { + -> block +{ /*! * * For each copy/move binding, copy the value from the value @@ -1125,6 +1135,7 @@ pub fn store_non_ref_bindings(bcx: block, */ let mut bcx = bcx; + let mut opt_temp_cleanups = opt_temp_cleanups; for data.bindings_map.each_value |&binding_info| { match binding_info.trmode { TrByValue(is_move, lldest) => { @@ -1139,9 +1150,10 @@ pub fn store_non_ref_bindings(bcx: block, } }; - for opt_temp_cleanups.each |temp_cleanups| { + do opt_temp_cleanups.mutate |temp_cleanups| { add_clean_temp_mem(bcx, lldest, binding_info.ty); temp_cleanups.push(lldest); + temp_cleanups } } TrByRef | TrByImplicitRef => {} @@ -1211,7 +1223,7 @@ pub fn compile_guard(bcx: block, let val = unpack_result!(bcx, { do with_scope_result(bcx, guard_expr.info(), - ~"guard") |bcx| { + "guard") |bcx| { expr::trans_to_datum(bcx, guard_expr).to_result() } }); @@ -1294,13 +1306,20 @@ pub fn compile_submatch(bcx: block, vec::slice(vals, col + 1u, vals.len())); let ccx = *bcx.fcx.ccx; let mut pat_id = 0; - for vec::each(m) |br| { + let mut pat_span = dummy_sp(); + for m.each |br| { // Find a real id (we're adding placeholder wildcard patterns, but // each column is guaranteed to have at least one real pattern) - if pat_id == 0 { pat_id = br.pats[col].id; } + if pat_id == 0 { + pat_id = br.pats[col].id; + pat_span = br.pats[col].span; + } } - bcx = root_pats_as_necessary(bcx, m, col, val); + // If we are not matching against an `@T`, we should not be + // required to root any values. + assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col)); + let rec_fields = collect_record_or_struct_fields(bcx, m, col); if rec_fields.len() > 0 { let pat_ty = node_id_type(bcx, pat_id); @@ -1361,6 +1380,7 @@ pub fn compile_submatch(bcx: block, // Unbox in case of a box field if any_box_pat(m, col) { + bcx = root_pats_as_necessary(bcx, m, col, val); let llbox = Load(bcx, val); let box_no_addrspace = non_gc_box_cast(bcx, llbox); let unboxed = @@ -1419,7 +1439,7 @@ pub fn compile_submatch(bcx: block, } } } - for vec::each(opts) |o| { + for opts.each |o| { match *o { range(_, _) => { kind = compare; break } _ => () @@ -1427,7 +1447,7 @@ pub fn compile_submatch(bcx: block, } let else_cx = match kind { no_branch | single => bcx, - _ => sub_block(bcx, ~"match_else") + _ => sub_block(bcx, "match_else") }; let sw = if kind == switch { Switch(bcx, test_val, else_cx.llbb, opts.len()) @@ -1441,11 +1461,11 @@ pub fn compile_submatch(bcx: block, let mut i = 0u; // Compile subtrees for each option - for vec::each(opts) |opt| { + for opts.each |opt| { i += 1u; let mut opt_cx = else_cx; if !exhaustive || i < len { - opt_cx = sub_block(bcx, ~"match_case"); + opt_cx = sub_block(bcx, "match_case"); match kind { single => Br(bcx, opt_cx.llbb), switch => { @@ -1467,7 +1487,7 @@ pub fn compile_submatch(bcx: block, let t = node_id_type(bcx, pat_id); let Result {bcx: after_cx, val: matches} = { do with_scope_result(bcx, None, - ~"compare_scope") |bcx| { + "compare_scope") |bcx| { match trans_opt(bcx, opt) { single_result( Result {bcx, val}) => { @@ -1495,13 +1515,13 @@ pub fn compile_submatch(bcx: block, } } }; - bcx = sub_block(after_cx, ~"compare_next"); + bcx = sub_block(after_cx, "compare_next"); CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); } compare_vec_len => { let Result {bcx: after_cx, val: matches} = { do with_scope_result(bcx, None, - ~"compare_vec_len_scope") |bcx| { + "compare_vec_len_scope") |bcx| { match trans_opt(bcx, opt) { single_result( Result {bcx, val}) => { @@ -1533,7 +1553,7 @@ pub fn compile_submatch(bcx: block, } } }; - bcx = sub_block(after_cx, ~"compare_vec_len_next"); + bcx = sub_block(after_cx, "compare_vec_len_next"); CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); } _ => () @@ -1561,8 +1581,8 @@ pub fn compile_submatch(bcx: block, vec_len_ge(_, i) => Some(i), _ => None }; - let args = extract_vec_elems(opt_cx, pat_id, n, slice, - val, test_val); + let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice, + val, test_val); size = args.vals.len(); unpacked = /*bad*/copy args.vals; opt_cx = args.bcx; @@ -1591,7 +1611,7 @@ pub fn trans_match(bcx: block, arms: ~[ast::arm], dest: Dest) -> block { let _icx = bcx.insn_ctxt("match::trans_match"); - do with_scope(bcx, match_expr.info(), ~"match") |bcx| { + do with_scope(bcx, match_expr.info(), "match") |bcx| { trans_match_inner(bcx, discr_expr, arms, dest) } } @@ -1612,8 +1632,8 @@ pub fn trans_match_inner(scope_cx: block, } let mut arm_datas = ~[], matches = ~[]; - for vec::each(arms) |arm| { - let body = scope_block(bcx, arm.body.info(), ~"case_body"); + for arms.each |arm| { + let body = scope_block(bcx, arm.body.info(), "case_body"); // Create the bindings map, which is a mapping from each binding name // to an alloca() that will be the value for that local variable. @@ -1651,7 +1671,7 @@ pub fn trans_match_inner(scope_cx: block, arm: arm, bindings_map: bindings_map}; arm_datas.push(arm_data); - for vec::each(arm.pats) |p| { + for arm.pats.each |p| { matches.push(@Match {pats: ~[*p], data: arm_data}); } } @@ -1697,7 +1717,7 @@ pub fn trans_match_inner(scope_cx: block, fn mk_fail(bcx: block, sp: span, msg: @~str, finished: @mut Option) -> BasicBlockRef { match *finished { Some(bb) => return bb, _ => () } - let fail_cx = sub_block(bcx, ~"case_fallthrough"); + let fail_cx = sub_block(bcx, "case_fallthrough"); controlflow::trans_fail(fail_cx, Some(sp), msg); *finished = Some(fail_cx.llbb); return fail_cx.llbb; @@ -1774,7 +1794,7 @@ pub fn bind_irrefutable_pat(bcx: block, vinfo.disr_val, val); for sub_pats.each |sub_pat| { - for vec::eachi(args.vals) |i, argval| { + for args.vals.eachi |i, argval| { bcx = bind_irrefutable_pat(bcx, sub_pat[i], *argval, @@ -1862,11 +1882,3 @@ pub fn bind_irrefutable_pat(bcx: block, } return bcx; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index b3e24fcc93951..21452a736fba8 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -217,7 +217,7 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t], packed: bool) -> Struct { size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, packed: packed, - fields: vec::from_slice(tys) + fields: vec::to_owned(tys) } } @@ -409,8 +409,8 @@ pub fn num_args(r: &Repr, discr: int) -> uint { st.fields.len() - (if dtor { 1 } else { 0 }) } General(ref cases) => cases[discr as uint].fields.len() - 1, - NullablePointer{ nonnull: ref nonnull, nndiscr, _ } => { - if discr == nndiscr { nonnull.fields.len() } else { 0 } + NullablePointer{ nonnull: ref nonnull, nndiscr, nullfields: ref nullfields, _ } => { + if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() } } } } @@ -574,7 +574,7 @@ fn padding(size: u64) -> ValueRef { } // XXX this utility routine should be somewhere more general -#[always_inline] +#[inline(always)] fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } /// Get the discriminant of a constant value. (Not currently used.) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index efa10dfc2aa34..3af58cfcadc3b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -34,7 +34,6 @@ use lib; use metadata::common::LinkMeta; use metadata::{csearch, cstore, encoder}; use middle::astencode; -use middle::borrowck::RootInfo; use middle::resolve; use middle::trans::_match; use middle::trans::adt; @@ -62,7 +61,6 @@ use middle::trans::type_of::*; use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; -use util::ppaux; use core::hash; use core::hashmap::{HashMap, HashSet}; @@ -106,7 +104,7 @@ impl get_insn_ctxt for @CrateContext { fn insn_ctxt(&self, s: &str) -> icx_popper { debug!("new insn_ctxt: %s", s); if self.sess.count_llvm_insns() { - self.stats.llvm_insn_ctxt.push(str::from_slice(s)); + self.stats.llvm_insn_ctxt.push(str::to_owned(s)); } icx_popper(*self) } @@ -391,14 +389,16 @@ pub fn get_tydesc_simple(ccx: @CrateContext, t: ty::t) -> ValueRef { pub fn get_tydesc(ccx: @CrateContext, t: ty::t) -> @mut tydesc_info { match ccx.tydescs.find(&t) { - Some(&inf) => inf, - _ => { - ccx.stats.n_static_tydescs += 1u; - let inf = glue::declare_tydesc(ccx, t); - ccx.tydescs.insert(t, inf); - inf - } + Some(&inf) => { + return inf; + } + _ => { } } + + ccx.stats.n_static_tydescs += 1u; + let inf = glue::declare_tydesc(ccx, t); + ccx.tydescs.insert(t, inf); + return inf; } pub fn set_optimize_for_size(f: ValueRef) { @@ -668,7 +668,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, ty::ty_struct(*) => { let repr = adt::represent_type(cx.ccx(), t); do expr::with_field_tys(cx.tcx(), t, None) |discr, field_tys| { - for vec::eachi(field_tys) |i, field_ty| { + for field_tys.eachi |i, field_ty| { let llfld_a = adt::trans_field_ptr(cx, repr, av, discr, i); cx = f(cx, llfld_a, field_ty.mt.ty); } @@ -703,13 +703,13 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, } (_match::switch, Some(lldiscrim_a)) => { cx = f(cx, lldiscrim_a, ty::mk_int()); - let unr_cx = sub_block(cx, ~"enum-iter-unr"); + let unr_cx = sub_block(cx, "enum-iter-unr"); Unreachable(unr_cx); let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants); - let next_cx = sub_block(cx, ~"enum-iter-next"); + let next_cx = sub_block(cx, "enum-iter-next"); - for vec::each(*variants) |variant| { + for (*variants).each |variant| { let variant_cx = sub_block(cx, ~"enum-iter-variant-" + int::to_str(variant.disr_val)); @@ -777,10 +777,10 @@ pub fn cast_shift_rhs(op: ast::binop, } } -pub fn fail_if_zero(cx: block, span: span, quotrem: ast::binop, +pub fn fail_if_zero(cx: block, span: span, divrem: ast::binop, rhs: ValueRef, rhs_t: ty::t) -> block { - let text = if quotrem == ast::quot { - @~"attempted quotient with a divisor of zero" + let text = if divrem == ast::div { + @~"attempted to divide by zero" } else { @~"attempted remainder with a divisor of zero" }; @@ -847,7 +847,7 @@ pub fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef]) debug!("arg: %x", ::core::cast::transmute(llarg)); } } - let normal_bcx = sub_block(bcx, ~"normal return"); + let normal_bcx = sub_block(bcx, "normal return"); let llresult = Invoke(bcx, llfn, llargs, @@ -885,23 +885,22 @@ pub fn need_invoke(bcx: block) -> bool { // Walk the scopes to look for cleanups let mut cur = bcx; loop { - let current = &mut *cur; - let kind = &mut *current.kind; - match *kind { - block_scope(ref mut inf) => { - for vec::each((*inf).cleanups) |cleanup| { - match *cleanup { - clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { - if cleanup_type == normal_exit_and_unwind { - return true; + match cur.kind { + block_scope(inf) => { + let inf = &mut *inf; // FIXME(#5074) workaround old borrowck + for inf.cleanups.each |cleanup| { + match *cleanup { + clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { + if cleanup_type == normal_exit_and_unwind { + return true; + } + } } - } } } - } - _ => () + _ => () } - cur = match current.parent { + cur = match cur.parent { Some(next) => next, None => return false } @@ -923,11 +922,13 @@ pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) { let mut bcx = bcx; loop { { - // FIXME #4280: Borrow check bug workaround. - let kind: &mut block_kind = &mut *bcx.kind; - match *kind { - block_scope(ref mut inf) => { - if inf.cleanups.len() > 0u || bcx.parent.is_none() { + match bcx.kind { + block_scope(inf) => { + let len = { // FIXME(#5074) workaround old borrowck + let inf = &mut *inf; + inf.cleanups.len() + }; + if len > 0u || bcx.parent.is_none() { f(inf); return; } @@ -948,7 +949,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { match inf.landing_pad { Some(target) => cached = Some(target), None => { - pad_bcx = lpad_block(bcx, ~"unwind"); + pad_bcx = lpad_block(bcx, "unwind"); inf.landing_pad = Some(pad_bcx.llbb); } } @@ -989,57 +990,30 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { return pad_bcx.llbb; } -// Arranges for the value found in `*root_loc` to be dropped once the scope -// associated with `scope_id` exits. This is used to keep boxes live when -// there are extant region pointers pointing at the interior. -// -// Note that `root_loc` is not the value itself but rather a pointer to the -// value. Generally it in alloca'd value. The reason for this is that the -// value is initialized in an inner block but may be freed in some outer -// block, so an SSA value that is valid in the inner block may not be valid in -// the outer block. In fact, the inner block may not even execute. Rather -// than generate the full SSA form, we just use an alloca'd value. -pub fn add_root_cleanup(bcx: block, - root_info: RootInfo, - root_loc: ValueRef, - ty: ty::t) { - - debug!("add_root_cleanup(bcx=%s, \ - scope=%d, \ - freezes=%?, \ - root_loc=%s, \ - ty=%s)", - bcx.to_str(), - root_info.scope, - root_info.freezes, - val_str(bcx.ccx().tn, root_loc), - ppaux::ty_to_str(bcx.ccx().tcx, ty)); - - let bcx_scope = find_bcx_for_scope(bcx, root_info.scope); - if root_info.freezes { - add_clean_frozen_root(bcx_scope, root_loc, ty); - } else { - add_clean_temp_mem(bcx_scope, root_loc, ty); - } - - fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { - let mut bcx_sid = bcx; - loop { - bcx_sid = match bcx_sid.node_info { - Some(NodeInfo { id, _ }) if id == scope_id => { +pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { + let mut bcx_sid = bcx; + loop { + bcx_sid = match bcx_sid.node_info { + Some(NodeInfo { id, _ }) if id == scope_id => { return bcx_sid } - _ => { - match bcx_sid.parent { - None => bcx.tcx().sess.bug( - fmt!("no enclosing scope with id %d", scope_id)), - Some(bcx_par) => bcx_par + + // FIXME(#6268, #6248) hacky cleanup for nested method calls + Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { + return bcx_sid + } + + _ => { + match bcx_sid.parent { + None => bcx.tcx().sess.bug( + fmt!("no enclosing scope with id %d", scope_id)), + Some(bcx_par) => bcx_par + } } - } } } } -} + pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { if ty::type_is_bot(t) { @@ -1125,10 +1099,11 @@ pub fn init_local(bcx: block, local: @ast::local) -> block { } let llptr = match bcx.fcx.lllocals.find(&local.node.id) { - Some(&local_mem(v)) => v, - _ => { bcx.tcx().sess.span_bug(local.span, - ~"init_local: Someone forgot to document why it's\ - safe to assume local.node.init must be local_mem!"); + Some(&local_mem(v)) => v, + _ => { + bcx.tcx().sess.span_bug(local.span, + "init_local: Someone forgot to document why it's\ + safe to assume local.node.init must be local_mem!"); } }; @@ -1159,7 +1134,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { let _icx = cx.insn_ctxt("trans_stmt"); debug!("trans_stmt(%s)", stmt_to_str(s, cx.tcx().sess.intr())); - if !cx.sess().no_asm_comments() { + if cx.sess().asm_comments() { add_span_comment(cx, s.span, stmt_to_str(s, cx.ccx().sess.intr())); } @@ -1193,7 +1168,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { // You probably don't want to use this one. See the // next three functions instead. pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, - is_lpad: bool, name: ~str, opt_node_info: Option) + is_lpad: bool, name: &str, opt_node_info: Option) -> block { let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo { @@ -1219,7 +1194,7 @@ pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, } pub fn simple_block_scope() -> block_kind { - block_scope(scope_info { + block_scope(@mut scope_info { loop_break: None, loop_label: None, cleanups: ~[], @@ -1232,12 +1207,12 @@ pub fn simple_block_scope() -> block_kind { pub fn top_scope_block(fcx: fn_ctxt, opt_node_info: Option) -> block { return new_block(fcx, None, simple_block_scope(), false, - ~"function top level", opt_node_info); + "function top level", opt_node_info); } pub fn scope_block(bcx: block, opt_node_info: Option, - n: ~str) -> block { + n: &str) -> block { return new_block(bcx.fcx, Some(bcx), simple_block_scope(), bcx.is_lpad, n, opt_node_info); } @@ -1245,9 +1220,9 @@ pub fn scope_block(bcx: block, pub fn loop_scope_block(bcx: block, loop_break: block, loop_label: Option, - n: ~str, + n: &str, opt_node_info: Option) -> block { - return new_block(bcx.fcx, Some(bcx), block_scope(scope_info { + return new_block(bcx.fcx, Some(bcx), block_scope(@mut scope_info { loop_break: Some(loop_break), loop_label: loop_label, cleanups: ~[], @@ -1257,12 +1232,12 @@ pub fn loop_scope_block(bcx: block, } // Use this when creating a block for the inside of a landing pad. -pub fn lpad_block(bcx: block, n: ~str) -> block { +pub fn lpad_block(bcx: block, n: &str) -> block { new_block(bcx.fcx, Some(bcx), block_non_scope, true, n, None) } // Use this when you're making a general CFG BB within a scope. -pub fn sub_block(bcx: block, n: ~str) -> block { +pub fn sub_block(bcx: block, n: &str) -> block { new_block(bcx.fcx, Some(bcx), block_non_scope, bcx.is_lpad, n, None) } @@ -1283,7 +1258,7 @@ pub fn trans_block_cleanups(bcx: block, cleanups: ~[cleanup]) -> block { } pub fn trans_block_cleanups_(bcx: block, - cleanups: ~[cleanup], + cleanups: &[cleanup], /* cleanup_cx: block, */ is_lpad: bool) -> block { let _icx = bcx.insn_ctxt("trans_block_cleanups"); @@ -1325,28 +1300,28 @@ pub fn cleanup_and_leave(bcx: block, @fmt!("cleanup_and_leave(%s)", cur.to_str())); } - { - // FIXME #4280: Borrow check bug workaround. - let kind: &mut block_kind = &mut *cur.kind; - match *kind { - block_scope(ref mut inf) if !inf.cleanups.is_empty() => { - for vec::find((*inf).cleanup_paths, - |cp| cp.target == leave).each |cp| { - Br(bcx, cp.dest); - return; - } - let sub_cx = sub_block(bcx, ~"cleanup"); - Br(bcx, sub_cx.llbb); - inf.cleanup_paths.push(cleanup_path { - target: leave, - dest: sub_cx.llbb - }); + match cur.kind { + block_scope(inf) if !inf.empty_cleanups() => { + let (sub_cx, inf_cleanups) = { + let inf = &mut *inf; // FIXME(#5074) workaround stage0 + for vec::find((*inf).cleanup_paths, + |cp| cp.target == leave).each |cp| { + Br(bcx, cp.dest); + return; + } + let sub_cx = sub_block(bcx, "cleanup"); + Br(bcx, sub_cx.llbb); + inf.cleanup_paths.push(cleanup_path { + target: leave, + dest: sub_cx.llbb + }); + (sub_cx, copy inf.cleanups) + }; bcx = trans_block_cleanups_(sub_cx, - block_cleanups(cur), + inf_cleanups, is_lpad); - } - _ => () } + _ => () } match upto { @@ -1371,7 +1346,7 @@ pub fn cleanup_and_Br(bcx: block, upto: block, target: BasicBlockRef) { pub fn leave_block(bcx: block, out_of: block) -> block { let _icx = bcx.insn_ctxt("leave_block"); - let next_cx = sub_block(block_parent(out_of), ~"next"); + let next_cx = sub_block(block_parent(out_of), "next"); if bcx.unreachable { Unreachable(next_cx); } cleanup_and_Br(bcx, out_of, next_cx.llbb); next_cx @@ -1379,7 +1354,7 @@ pub fn leave_block(bcx: block, out_of: block) -> block { pub fn with_scope(bcx: block, opt_node_info: Option, - name: ~str, + name: &str, f: &fn(block) -> block) -> block { let _icx = bcx.insn_ctxt("with_scope"); @@ -1394,7 +1369,7 @@ pub fn with_scope(bcx: block, pub fn with_scope_result(bcx: block, opt_node_info: Option, - name: ~str, + name: &str, f: &fn(block) -> Result) -> Result { let _icx = bcx.insn_ctxt("with_scope_result"); let scope_cx = scope_block(bcx, opt_node_info, name); @@ -1404,7 +1379,7 @@ pub fn with_scope_result(bcx: block, } pub fn with_scope_datumblock(bcx: block, opt_node_info: Option, - name: ~str, f: &fn(block) -> datum::DatumBlock) + name: &str, f: &fn(block) -> datum::DatumBlock) -> datum::DatumBlock { use middle::trans::datum::DatumBlock; @@ -1416,7 +1391,7 @@ pub fn with_scope_datumblock(bcx: block, opt_node_info: Option, } pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { - for vec::each(b.node.stmts) |s| { + for b.node.stmts.each |s| { match s.node { ast::stmt_decl(d, _) => { match d.node { @@ -1457,8 +1432,8 @@ pub fn alloc_local(cx: block, local: @ast::local) -> block { pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { let _icx = bcx.insn_ctxt("with_cond"); - let next_cx = base::sub_block(bcx, ~"next"); - let cond_cx = base::sub_block(bcx, ~"cond"); + let next_cx = base::sub_block(bcx, "next"); + let cond_cx = base::sub_block(bcx, "cond"); CondBr(bcx, val, cond_cx.llbb, next_cx.llbb); let after_cx = f(cond_cx); if !after_cx.terminated { Br(after_cx, next_cx.llbb); } @@ -1998,7 +1973,7 @@ pub fn trans_enum_variant(ccx: @CrateContext, repr, ty_to_str(ccx.tcx, enum_ty)); adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); - for vec::eachi(args) |i, va| { + for args.eachi |i, va| { let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr.get(), @@ -2071,6 +2046,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); let repr = adt::represent_type(ccx, tup_ty); + adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0); for fields.eachi |i, field| { let lldestptr = adt::trans_field_ptr(bcx, @@ -2078,7 +2054,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, fcx.llretptr.get(), 0, i); - let llarg = match *fcx.llargs.get(&field.node.id) { + let llarg = match fcx.llargs.get_copy(&field.node.id) { local_mem(x) => x, _ => { ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \ @@ -2093,58 +2069,10 @@ pub fn trans_tuple_struct(ccx: @CrateContext, finish_fn(fcx, lltop); } -pub fn trans_struct_dtor(ccx: @CrateContext, - path: path, - body: &ast::blk, - dtor_id: ast::node_id, - psubsts: Option<@param_substs>, - hash_id: Option, - parent_id: ast::def_id) - -> ValueRef { - let tcx = ccx.tcx; - /* Look up the parent class's def_id */ - let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty; - /* Substitute in the class type if necessary */ - for psubsts.each |ss| { - class_ty = ty::subst_tps(tcx, ss.tys, ss.self_ty, class_ty); - } - - /* The dtor takes a (null) output pointer, and a self argument, - and returns () */ - let lldty = type_of_dtor(ccx, class_ty); - - // XXX: Bad copies. - let s = get_dtor_symbol(ccx, copy path, dtor_id, psubsts); - - /* Register the dtor as a function. It has external linkage */ - let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty); - lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage); - - /* If we're monomorphizing, register the monomorphized decl - for the dtor */ - for hash_id.each |h_id| { - ccx.monomorphized.insert(*h_id, lldecl); - } - /* Translate the dtor body */ - let decl = ast_util::dtor_dec(); - trans_fn(ccx, - path, - &decl, - body, - lldecl, - impl_self(class_ty), - psubsts, - dtor_id, - None, - []); - lldecl -} - pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, - id: ast::node_id, - path: @ast_map::path, vi: @~[ty::VariantInfo], + id: ast::node_id, vi: @~[ty::VariantInfo], i: &mut uint) { - for vec::each(enum_definition.variants) |variant| { + for enum_definition.variants.each |variant| { let disr_val = vi[*i].disr_val; *i += 1; @@ -2158,8 +2086,7 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, // Nothing to do. } ast::struct_variant_kind(struct_def) => { - trans_struct_def(ccx, struct_def, path, - variant.node.id); + trans_struct_def(ccx, struct_def); } } } @@ -2167,7 +2094,7 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, pub fn trans_item(ccx: @CrateContext, item: &ast::item) { let _icx = ccx.insn_ctxt("trans_item"); - let path = match *ccx.tcx.items.get(&item.id) { + let path = match ccx.tcx.items.get_copy(&item.id) { ast_map::node_item(_, p) => p, // tjc: ? _ => fail!(~"trans_item"), @@ -2218,8 +2145,7 @@ pub fn trans_item(ccx: @CrateContext, item: &ast::item) { if !generics.is_type_parameterized() { let vi = ty::enum_variants(ccx.tcx, local_def(item.id)); let mut i = 0; - trans_enum_def(ccx, enum_definition, item.id, - path, vi, &mut i); + trans_enum_def(ccx, enum_definition, item.id, vi, &mut i); } } ast::item_const(_, expr) => consts::trans_const(ccx, expr, item.id), @@ -2228,22 +2154,14 @@ pub fn trans_item(ccx: @CrateContext, item: &ast::item) { } ast::item_struct(struct_def, ref generics) => { if !generics.is_type_parameterized() { - trans_struct_def(ccx, struct_def, path, item.id); + trans_struct_def(ccx, struct_def); } } _ => {/* fall through */ } } } -pub fn trans_struct_def(ccx: @CrateContext, struct_def: @ast::struct_def, - path: @ast_map::path, - id: ast::node_id) { - // Translate the destructor. - for struct_def.dtor.each |dtor| { - trans_struct_dtor(ccx, /*bad*/copy *path, &dtor.node.body, - dtor.node.id, None, None, local_def(id)); - }; - +pub fn trans_struct_def(ccx: @CrateContext, struct_def: @ast::struct_def) { // If this is a tuple-like struct, translate the constructor. match struct_def.ctor_id { // We only need to translate a constructor if there are fields; @@ -2358,7 +2276,7 @@ pub fn create_entry_wrapper(ccx: @CrateContext, // Call main. let lloutputarg = C_null(T_ptr(T_i8())); let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) }; - let mut args = ~[lloutputarg, llenvarg]; + let args = ~[lloutputarg, llenvarg]; let llresult = Call(bcx, main_llfn, args); Store(bcx, llresult, fcx.llretptr.get()); @@ -2469,7 +2387,7 @@ pub fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef, } pub fn item_path(ccx: @CrateContext, i: @ast::item) -> path { - let base = match *ccx.tcx.items.get(&i.id) { + let base = match ccx.tcx.items.get_copy(&i.id) { ast_map::node_item(_, p) => p, // separate map for paths? _ => fail!(~"item_path") @@ -2477,46 +2395,6 @@ pub fn item_path(ccx: @CrateContext, i: @ast::item) -> path { vec::append(/*bad*/copy *base, ~[path_name(i.ident)]) } -/* If there's already a symbol for the dtor with and substs , - return it; otherwise, create one and register it, returning it as well */ -pub fn get_dtor_symbol(ccx: @CrateContext, - path: path, - id: ast::node_id, - substs: Option<@param_substs>) - -> ~str { - let t = ty::node_id_to_type(ccx.tcx, id); - match ccx.item_symbols.find(&id) { - Some(s) => (/*bad*/copy *s), - None if substs.is_none() => { - let s = mangle_exported_name( - ccx, - vec::append(path, ~[path_name((ccx.names)(~"dtor"))]), - t); - // XXX: Bad copy, use `@str`? - ccx.item_symbols.insert(id, copy s); - s - } - None => { - // Monomorphizing, so just make a symbol, don't add - // this to item_symbols - match substs { - Some(ss) => { - let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, ss.self_ty, t); - mangle_exported_name( - ccx, - vec::append(path, - ~[path_name((ccx.names)(~"dtor"))]), - mono_ty) - } - None => { - ccx.sess.bug(fmt!("get_dtor_symbol: not monomorphizing and \ - couldn't find a symbol for dtor %?", path)); - } - } - } - } -} - pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { debug!("get_item_val(id=`%?`)", id); let tcx = ccx.tcx; @@ -2524,13 +2402,13 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { Some(&v) => v, None => { let mut exprt = false; - let val = match *ccx.tcx.items.get(&id) { + let val = match tcx.items.get_copy(&id) { ast_map::node_item(i, pth) => { let my_path = vec::append(/*bad*/copy *pth, ~[path_name(i.ident)]); match i.node { ast::item_const(_, expr) => { - let typ = ty::node_id_to_type(ccx.tcx, i.id); + let typ = ty::node_id_to_type(tcx, i.id); let s = mangle_exported_name(ccx, my_path, typ); // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. @@ -2589,7 +2467,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { ni.attrs) } ast::foreign_item_const(*) => { - let typ = ty::node_id_to_type(ccx.tcx, ni.id); + let typ = ty::node_id_to_type(tcx, ni.id); let ident = ccx.sess.parse_sess.interner.get(ni.ident); let g = do str::as_c_str(*ident) |buf| { unsafe { @@ -2602,28 +2480,6 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { } } } - ast_map::node_dtor(_, dt, parent_id, pt) => { - /* - Don't just call register_fn, since we don't want to add - the implicit self argument automatically (we want to make sure - it has the right type) - */ - // Want parent_id and not id, because id is the dtor's type - let class_ty = ty::lookup_item_type(tcx, parent_id).ty; - // This code shouldn't be reached if the class is generic - assert!(!ty::type_has_params(class_ty)); - let lldty = T_fn(~[ - T_ptr(T_i8()), - T_ptr(type_of(ccx, class_ty)) - ], - T_nil()); - let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None); - - /* Make the declaration for the dtor */ - let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty); - lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage); - llfn - } ast_map::node_variant(ref v, enm, pth) => { let llfn; @@ -2652,7 +2508,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { // Only register the constructor if this is a tuple-like struct. match struct_def.ctor_id { None => { - ccx.tcx.sess.bug(~"attempt to register a constructor of \ + tcx.sess.bug(~"attempt to register a constructor of \ a non-tuple-like struct") } Some(ctor_id) => { @@ -2686,7 +2542,7 @@ pub fn register_method(ccx: @CrateContext, pth: @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")), + 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); set_inline_hint_if_appr(m.attrs, llfn); @@ -2703,7 +2559,7 @@ pub fn trans_constant(ccx: @CrateContext, it: @ast::item) { node: it.id }); let mut i = 0; let path = item_path(ccx, it); - for vec::each((*enum_definition).variants) |variant| { + for (*enum_definition).variants.each |variant| { let p = vec::append(/*bad*/copy path, ~[ path_name(variant.node.name), path_name(special_idents::descrim) @@ -3131,9 +2987,8 @@ pub fn trans_crate(sess: session::Session, emap2: resolve::ExportMap2, maps: astencode::Maps) -> (ModuleRef, LinkMeta) { - let symbol_hasher = @hash::default_state(); - let link_meta = - link::build_link_meta(sess, crate, output, symbol_hasher); + let symbol_hasher = @mut hash::default_state(); + let link_meta = link::build_link_meta(sess, crate, output, symbol_hasher); let reachable = reachable::find_reachable( &crate.node.module, emap2, @@ -3290,12 +3145,3 @@ pub fn trans_crate(sess: session::Session, return (llmod, link_meta); } } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index f5c496484a037..b2af91887ecbf 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -537,6 +537,18 @@ pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef { } } +pub fn AtomicLoad(cx: block, PointerVal: ValueRef, order: AtomicOrdering) -> ValueRef { + unsafe { + let ccx = cx.fcx.ccx; + if cx.unreachable { + return llvm::LLVMGetUndef(ccx.int_type); + } + count_insn(cx, "load.atomic"); + return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, order); + } +} + + pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong, hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef { let value = Load(cx, PointerVal); @@ -567,6 +579,17 @@ pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) { } } +pub fn AtomicStore(cx: block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrdering) { + unsafe { + if cx.unreachable { return; } + debug!("Store %s -> %s", + val_str(cx.ccx().tn, Val), + val_str(cx.ccx().tn, Ptr)); + count_insn(cx, "store.atomic"); + llvm::LLVMBuildAtomicStore(B(cx), Val, Ptr, order); + } +} + pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { unsafe { if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); } @@ -846,7 +869,7 @@ pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef { pub fn add_span_comment(bcx: block, sp: span, text: &str) { let ccx = bcx.ccx(); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { let s = fmt!("%s (%s)", text, ccx.sess.codemap.span_to_str(sp)); debug!("%s", copy s); add_comment(bcx, s); @@ -856,7 +879,7 @@ pub fn add_span_comment(bcx: block, sp: span, text: &str) { pub fn add_comment(bcx: block, text: &str) { unsafe { let ccx = bcx.ccx(); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { let sanitized = str::replace(text, ~"$", ~""); let comment_text = ~"# " + str::replace(sanitized, ~"\n", ~"\n\t# "); @@ -963,20 +986,28 @@ pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> } pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef, - Index: ValueRef) { + Index: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return; } + if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } count_insn(cx, "insertelement"); - llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()); + llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()) } } pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef, - Mask: ValueRef) { + Mask: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return; } + if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } count_insn(cx, "shufflevector"); - llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()); + llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()) + } +} + +pub fn VectorSplat(cx: block, NumElts: uint, EltVal: ValueRef) -> ValueRef { + unsafe { + let Undef = llvm::LLVMGetUndef(T_vector(val_ty(EltVal), NumElts)); + let VecVal = InsertElement(cx, Undef, EltVal, C_i32(0)); + ShuffleVector(cx, VecVal, Undef, C_null(T_vector(T_i32(), NumElts))) } } @@ -1086,13 +1117,3 @@ pub fn AtomicRMW(cx: block, op: AtomicBinOp, llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order) } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index ed028d14bd65f..702d62f136348 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -71,8 +71,8 @@ pub impl FnType { let llretptr = GEPi(bcx, llargbundle, [0u, n]); let llretloc = Load(bcx, llretptr); llargvals = ~[llretloc]; - atys = vec::from_slice(atys.tail()); - attrs = vec::from_slice(attrs.tail()); + atys = vec::to_owned(atys.tail()); + attrs = vec::to_owned(attrs.tail()); } while i < n { @@ -137,8 +137,8 @@ pub impl FnType { let mut attrs = /*bad*/copy self.attrs; let mut j = 0u; let llretptr = if self.sret { - atys = vec::from_slice(atys.tail()); - attrs = vec::from_slice(attrs.tail()); + atys = vec::to_owned(atys.tail()); + attrs = vec::to_owned(attrs.tail()); j = 1u; get_param(llwrapfn, 0u) } else if self.ret_ty.cast { @@ -190,4 +190,3 @@ pub impl FnType { Store(bcx, llretval, llretptr); } } - diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index ecde50f347072..4da2199501f52 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -161,7 +161,7 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { cls: &mut [x86_64_reg_class], i: uint, off: uint) { let mut field_off = off; - for vec::each(tys) |ty| { + for tys.each |ty| { field_off = align(field_off, *ty); classify(*ty, cls, i, field_off); field_off += ty_size(*ty); @@ -283,7 +283,7 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { fn llvec_len(cls: &[x86_64_reg_class]) -> uint { let mut len = 1u; - for vec::each(cls) |c| { + for cls.each |c| { if *c != sseup_class { break; } @@ -370,7 +370,7 @@ fn x86_64_tys(atys: &[TypeRef], let mut arg_tys = ~[]; let mut attrs = ~[]; - for vec::each(atys) |t| { + for atys.each |t| { let (ty, attr) = x86_64_ty(*t, is_pass_byval, ByValAttribute); arg_tys.push(ty); attrs.push(attr); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ad0fea3b4b4af..70a0a7d06d351 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -39,7 +39,6 @@ use middle::trans::monomorphize; use middle::trans::type_of; use middle::ty; use middle::typeck; -use util::common::indenter; use util::ppaux::Repr; use syntax::ast; @@ -340,25 +339,19 @@ pub fn trans_method_call(in_cx: block, node_id_type(in_cx, call_ex.callee_id), expr_ty(in_cx, call_ex), |cx| { - match cx.ccx().maps.method_map.find(&call_ex.id) { + match cx.ccx().maps.method_map.find_copy(&call_ex.id) { Some(origin) => { debug!("origin for %s: %s", call_ex.repr(in_cx.tcx()), origin.repr(in_cx.tcx())); - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let origin = /*bad*/ copy *origin; - meth::trans_method_callee(cx, call_ex.callee_id, rcvr, origin) } None => { - cx.tcx().sess.span_bug(call_ex.span, - ~"method call expr wasn't in \ - method map") + cx.tcx().sess.span_bug(call_ex.span, "method call expr wasn't in method map") } } }, @@ -461,7 +454,7 @@ pub fn trans_call_inner(in_cx: block, dest: expr::Dest, autoref_arg: AutorefArg) -> block { - do base::with_scope(in_cx, call_info, ~"call") |cx| { + 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 { @@ -557,7 +550,14 @@ pub fn trans_call_inner(in_cx: block, // drop the value if it is not being saved. unsafe { if llvm::LLVMIsUndef(llretslot) != lib::llvm::True { - if ty::type_is_immediate(ret_ty) { + if ty::type_is_nil(ret_ty) { + // When implementing the for-loop sugar syntax, the + // type of the for-loop is nil, but the function + // it's invoking returns a bool. This is a special + // case to ignore instead of invoking the Store + // below into a scratch pointer of a mismatched + // type. + } else if ty::type_is_immediate(ret_ty) { let llscratchptr = alloc_ty(bcx, ret_ty); Store(bcx, llresult, llscratchptr); bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); @@ -638,7 +638,7 @@ pub fn trans_args(cx: block, match args { ArgExprs(arg_exprs) => { let last = arg_exprs.len() - 1u; - for vec::eachi(arg_exprs) |i, arg_expr| { + for arg_exprs.eachi |i, arg_expr| { let arg_val = unpack_result!(bcx, { trans_arg_expr(bcx, arg_tys[i], @@ -689,7 +689,6 @@ pub fn trans_arg_expr(bcx: block, self_mode, arg_expr.repr(bcx.tcx()), ret_flag.map(|v| bcx.val_str(*v))); - let _indenter = indenter(); // translate the arg expr to a datum let arg_datumblock = match ret_flag { @@ -724,7 +723,7 @@ pub fn trans_arg_expr(bcx: block, } } }; - let mut arg_datum = arg_datumblock.datum; + let arg_datum = arg_datumblock.datum; let bcx = arg_datumblock.bcx; debug!(" arg datum: %s", arg_datum.to_str(bcx.ccx())); @@ -801,4 +800,3 @@ pub fn trans_arg_expr(bcx: block, debug!("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val)); return rslt(bcx, val); } - diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index e35fef6b6f66a..0651d3443b56a 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -208,7 +208,6 @@ pub fn store_environment(bcx: block, // allocate closure in the heap let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, sigil, cdata_ty); - let mut temp_cleanups = ~[]; // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a // tuple. This could be a ptr in uniq or a box or on stack, @@ -224,7 +223,7 @@ pub fn store_environment(bcx: block, for vec::eachi(bound_values) |i, bv| { debug!("Copy %s into closure", bv.to_str(ccx)); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { add_comment(bcx, fmt!("Copy %s into closure", bv.to_str(ccx))); } @@ -244,9 +243,6 @@ pub fn store_environment(bcx: block, } } - for vec::each(temp_cleanups) |cleanup| { - revoke_clean(bcx, *cleanup); - } ClosureResult { llbox: llbox, cdata_ty: cdata_ty, bcx: bcx } } @@ -404,7 +400,7 @@ pub fn trans_expr_fn(bcx: block, // XXX: Bad copy. let s = mangle_internal_name_by_path_and_seq(ccx, copy sub_path, - ~"expr_fn"); + "expr_fn"); let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty); // Always mark inline if this is a loop body. This is important for @@ -424,7 +420,7 @@ pub fn trans_expr_fn(bcx: block, let Result {bcx: bcx, val: closure} = match sigil { ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => { - let cap_vars = *ccx.maps.capture_map.get(&user_id); + let cap_vars = ccx.maps.capture_map.get_copy(&user_id); let ret_handle = match is_loop_body {Some(x) => x, None => None}; let ClosureResult {llbox, cdata_ty, bcx} @@ -599,4 +595,3 @@ pub fn make_opaque_cbox_free_glue( } } } - diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f8fb0f4b7cf31..8000484c0550f 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -27,18 +27,18 @@ use middle::resolve; use middle::trans::adt; use middle::trans::base; use middle::trans::build; -use middle::trans::callee; use middle::trans::datum; use middle::trans::debuginfo; -use middle::trans::expr; use middle::trans::glue; use middle::trans::reachable; use middle::trans::shape; use middle::trans::type_of; use middle::trans::type_use; +use middle::trans::write_guard; use middle::ty::substs; use middle::ty; use middle::typeck; +use middle::borrowck::root_map_key; use util::ppaux::{Repr}; use core::cast::transmute; @@ -54,12 +54,12 @@ use syntax::parse::token::ident_interner; use syntax::{ast, ast_map}; use syntax::abi::{X86, X86_64, Arm, Mips}; -pub type namegen = @fn(s: ~str) -> ident; +pub type namegen = @fn(s: &str) -> ident; pub fn new_namegen(intr: @ident_interner) -> namegen { - let f: @fn(s: ~str) -> ident = |prefix| { - intr.gensym(@fmt!("%s_%u", + let f: @fn(s: &str) -> ident = |prefix| { + intr.gensym(fmt!("%s_%u", prefix, - intr.gensym(@prefix).repr)) + intr.gensym(prefix).repr)) }; f } @@ -207,7 +207,7 @@ pub struct CrateContext { adt_reprs: @mut HashMap, names: namegen, next_addrspace: addrspace_gen, - symbol_hasher: @hash::State, + symbol_hasher: @mut hash::State, type_hashcodes: @mut HashMap, type_short_names: @mut HashMap, all_llvm_symbols: @mut HashSet<@~str>, @@ -256,13 +256,11 @@ pub impl param_substs { } } -fn param_substs_to_str(self: ¶m_substs, - tcx: ty::ctxt) -> ~str -{ +fn param_substs_to_str(this: ¶m_substs, tcx: ty::ctxt) -> ~str { fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", - self.tys.repr(tcx), - self.vtables.repr(tcx), - self.type_param_defs.repr(tcx)) + this.tys.repr(tcx), + this.vtables.repr(tcx), + this.type_param_defs.repr(tcx)) } impl Repr for param_substs { @@ -467,28 +465,35 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { scope_clean_changed(scope_info); } } -pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) { - debug!("add_clean_frozen_root(%s, %s, %s)", - bcx.to_str(), val_str(bcx.ccx().tn, val), - t.repr(bcx.tcx())); - let (root, rooted) = root_for_cleanup(bcx, val, t); - let cleanup_type = cleanup_type(bcx.tcx(), t); +pub fn add_clean_return_to_mut(bcx: block, + root_key: root_map_key, + frozen_val_ref: ValueRef, + bits_val_ref: ValueRef, + filename_val: ValueRef, + line_val: ValueRef) { + //! When an `@mut` has been frozen, we have to + //! call the lang-item `return_to_mut` when the + //! freeze goes out of scope. We need to pass + //! in both the value which was frozen (`frozen_val`) and + //! the value (`bits_val_ref`) which was returned when the + //! box was frozen initially. Here, both `frozen_val_ref` and + //! `bits_val_ref` are in fact pointers to stack slots. + + debug!("add_clean_return_to_mut(%s, %s, %s)", + bcx.to_str(), + val_str(bcx.ccx().tn, frozen_val_ref), + val_str(bcx.ccx().tn, bits_val_ref)); do in_scope_cx(bcx) |scope_info| { scope_info.cleanups.push( - clean_temp(val, |bcx| { - let bcx = callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.return_to_mut_fn(), - ~[ - build::Load(bcx, - build::PointerCast(bcx, - root, - T_ptr(T_ptr(T_i8())))) - ], - expr::Ignore - ); - glue::drop_ty_root(bcx, root, rooted, t) - }, cleanup_type)); + clean_temp( + frozen_val_ref, + |bcx| write_guard::return_to_mut(bcx, + root_key, + frozen_val_ref, + bits_val_ref, + filename_val, + line_val), + normal_exit_only)); scope_clean_changed(scope_info); } } @@ -516,6 +521,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { // drop glue checks whether it is zero. pub fn revoke_clean(cx: block, val: ValueRef) { do in_scope_cx(cx) |scope_info| { + let scope_info = &mut *scope_info; // FIXME(#5074) workaround borrowck let cleanup_pos = vec::position( scope_info.cleanups, |cu| match *cu { @@ -534,9 +540,9 @@ pub fn revoke_clean(cx: block, val: ValueRef) { } pub fn block_cleanups(bcx: block) -> ~[cleanup] { - match *bcx.kind { + match bcx.kind { block_non_scope => ~[], - block_scope(ref mut inf) => /*bad*/copy inf.cleanups + block_scope(inf) => /*bad*/copy inf.cleanups } } @@ -545,7 +551,7 @@ pub enum block_kind { // cleaned up. May correspond to an actual block in the language, but also // to an implicit scope, for example, calls introduce an implicit scope in // which the arguments are evaluated and cleaned up. - block_scope(scope_info), + block_scope(@mut scope_info), // A non-scope block is a basic block created as a translation artifact // from translating code that expresses conditional logic rather than by @@ -568,19 +574,29 @@ pub struct scope_info { landing_pad: Option, } +pub impl scope_info { + fn empty_cleanups(&mut self) -> bool { + self.cleanups.is_empty() + } +} + pub trait get_node_info { fn info(&self) -> Option; } impl get_node_info for @ast::expr { fn info(&self) -> Option { - Some(NodeInfo { id: self.id, span: self.span }) + Some(NodeInfo {id: self.id, + callee_id: Some(self.callee_id), + span: self.span}) } } impl get_node_info for ast::blk { fn info(&self) -> Option { - Some(NodeInfo { id: self.node.id, span: self.span }) + Some(NodeInfo {id: self.node.id, + callee_id: None, + span: self.span}) } } @@ -592,6 +608,7 @@ impl get_node_info for Option<@ast::expr> { pub struct NodeInfo { id: ast::node_id, + callee_id: Option, span: span } @@ -611,7 +628,7 @@ pub struct block_ { unreachable: bool, parent: Option, // The 'kind' of basic block this is. - kind: @mut block_kind, + kind: block_kind, // Is this block part of a landing pad? is_lpad: bool, // info about the AST node this block originated from, if any @@ -630,7 +647,7 @@ pub fn block_(llbb: BasicBlockRef, parent: Option, kind: block_kind, terminated: false, unreachable: false, parent: parent, - kind: @mut kind, + kind: kind, is_lpad: is_lpad, node_info: node_info, fcx: fcx @@ -678,21 +695,17 @@ pub fn val_str(tn: @TypeNames, v: ValueRef) -> @str { return ty_str(tn, val_ty(v)); } -pub fn in_scope_cx(cx: block, f: &fn(si: &mut scope_info)) { +pub fn in_scope_cx(cx: block, f: &fn(si: @mut scope_info)) { let mut cur = cx; loop { - { - // XXX: Borrow check bug workaround. - let kind: &mut block_kind = &mut *cur.kind; - match *kind { - block_scope(ref mut inf) => { - debug!("in_scope_cx: selected cur=%s (cx=%s)", - cur.to_str(), cx.to_str()); - f(inf); - return; - } - _ => () + match cur.kind { + block_scope(inf) => { + debug!("in_scope_cx: selected cur=%s (cx=%s)", + cur.to_str(), cx.to_str()); + f(inf); + return; } + _ => () } cur = block_parent(cur); } @@ -969,6 +982,12 @@ pub fn T_array(t: TypeRef, n: uint) -> TypeRef { } } +pub fn T_vector(t: TypeRef, n: uint) -> TypeRef { + unsafe { + return llvm::LLVMVectorType(t, n as c_uint); + } +} + // Interior vector. pub fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef { return T_struct(~[T_int(targ_cfg), // fill @@ -1156,7 +1175,7 @@ pub fn C_cstr(cx: @CrateContext, s: @~str) -> ValueRef { llvm::LLVMConstString(buf, s.len() as c_uint, False) }; let g = - str::as_c_str(fmt!("str%u", (cx.names)(~"str").repr), + str::as_c_str(fmt!("str%u", (cx.names)("str").repr), |buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf)); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); @@ -1248,7 +1267,7 @@ pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef { pub fn C_shape(ccx: @CrateContext, bytes: ~[u8]) -> ValueRef { unsafe { let llshape = C_bytes_plus_null(bytes); - let name = fmt!("shape%u", (ccx.names)(~"shape").repr); + let name = fmt!("shape%u", (ccx.names)("shape").repr); let llglobal = str::as_c_str(name, |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape), buf) }); @@ -1348,6 +1367,7 @@ pub struct mono_id_ { pub type mono_id = @mono_id_; +#[cfg(stage0)] impl to_bytes::IterBytes for mono_param_id { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -1361,18 +1381,46 @@ impl to_bytes::IterBytes for mono_param_id { } } } +#[cfg(not(stage0))] +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) => + to_bytes::iter_bytes_3(&0u8, &ty::type_id(t), mids, lsb0, f), + + mono_any => 1u8.iter_bytes(lsb0, f), + + mono_repr(ref a, ref b, ref c, ref d) => + to_bytes::iter_bytes_5(&2u8, a, b, c, d, lsb0, f) + } + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for MonoDataClass { fn iter_bytes(&self, lsb0: bool, f:to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for MonoDataClass { + fn iter_bytes(&self, lsb0: bool, f:to_bytes::Cb) -> bool { + (*self as u8).iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for mono_id_ { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.def, &self.params, lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for mono_id_ { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.def, &self.params, lsb0, f) + } +} pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { let cond = build::ICmp(cx, lib::llvm::IntULT, a, b); @@ -1517,17 +1565,16 @@ pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { } } +pub fn filename_and_line_num_from_span(bcx: block, + span: span) -> (ValueRef, ValueRef) { + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = build::PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + let line = C_int(bcx.ccx(), loc.line as int); + (filename, line) +} + // Casts a Rust bool value to an i1. pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef { build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false)) } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 25f34b8eaa9d1..48c5a96c8e7b2 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -58,8 +58,7 @@ pub fn const_lit(cx: @CrateContext, e: @ast::expr, lit: ast::lit) } _ => { cx.sess.span_bug(lit.span, - ~"floating point literal doesn't have the right \ - type"); + "floating point literal doesn't have the right type"); } } } @@ -158,7 +157,7 @@ pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef { if !ast_util::is_local(def_id) { def_id = inline::maybe_instantiate_inline(cx, def_id, true); } - match *cx.tcx.items.get(&def_id.node) { + match cx.tcx.items.get_copy(&def_id.node) { ast_map::node_item(@ast::item { node: ast::item_const(_, subexpr), _ }, _) => { @@ -167,7 +166,7 @@ pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef { _ => cx.tcx.sess.bug(~"expected a const to be an item") } } - *cx.const_values.get(&def_id.node) + cx.const_values.get_copy(&def_id.node) } pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { @@ -195,18 +194,19 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { match adj.autoref { None => { } Some(ref autoref) => { - assert!(autoref.region == ty::re_static); - assert!(autoref.mutbl != ast::m_mutbl); // Don't copy data to do a deref+ref. let llptr = match maybe_ptr { Some(ptr) => ptr, None => const_addr_of(cx, llconst) }; - match autoref.kind { - ty::AutoPtr => { + match *autoref { + ty::AutoUnsafe(m) | + ty::AutoPtr(ty::re_static, m) => { + assert!(m != ast::m_mutbl); llconst = llptr; } - ty::AutoBorrowVec => { + ty::AutoBorrowVec(ty::re_static, m) => { + assert!(m != ast::m_mutbl); let size = machine::llsize_of(cx, val_ty(llconst)); assert!(abi::slice_elt_base == 0); @@ -270,7 +270,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { if is_float { llvm::LLVMConstFMul(te1, te2) } else { llvm::LLVMConstMul(te1, te2) } } - ast::quot => { + ast::div => { if is_float { llvm::LLVMConstFDiv(te1, te2) } else if signed { llvm::LLVMConstSDiv(te1, te2) } else { llvm::LLVMConstUDiv(te1, te2) } @@ -281,7 +281,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { else { llvm::LLVMConstURem(te1, te2) } } ast::and | - ast::or => cx.sess.span_unimpl(e.span, ~"binop logic"), + ast::or => cx.sess.span_unimpl(e.span, "binop logic"), ast::bitxor => llvm::LLVMConstXor(te1, te2), ast::bitand => llvm::LLVMConstAnd(te1, te2), ast::bitor => llvm::LLVMConstOr(te1, te2), @@ -295,7 +295,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { ast::le | ast::ne | ast::ge | - ast::gt => cx.sess.span_unimpl(e.span, ~"binop comparator") + ast::gt => cx.sess.span_unimpl(e.span, "binop comparator") } } ast::expr_unary(u, e) => { @@ -344,8 +344,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, _ => cx.sess.span_bug(index.span, - ~"index is not an integer-constant \ - expression") + "index is not an integer-constant expression") }; let (arr, len) = match ty::get(bt).sty { ty::ty_evec(_, vstore) | ty::ty_estr(vstore) => @@ -363,12 +362,10 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { unit_sz)) }, _ => cx.sess.span_bug(base.span, - ~"index-expr base must be \ - fixed-size or slice") + "index-expr base must be fixed-size or slice") }, _ => cx.sess.span_bug(base.span, - ~"index-expr base must be \ - a vector or string type") + "index-expr base must be a vector or string type") }; let len = llvm::LLVMConstIntGetZExtValue(len) as u64; @@ -380,7 +377,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { // FIXME #3170: report this earlier on in the const-eval // pass. Reporting here is a bit late. cx.sess.span_err(e.span, - ~"const index-expr is out of bounds"); + "const index-expr is out of bounds"); } const_get_elt(cx, arr, [iv as c_uint]) } @@ -454,8 +451,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { match fs.find(|f| field_ty.ident == f.node.ident) { Some(ref f) => const_expr(cx, (*f).node.expr), None => { - cx.tcx.sess.span_bug( - e.span, ~"missing struct field"); + cx.tcx.sess.span_bug(e.span, "missing struct field"); } } }); @@ -471,8 +467,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { ast::expr_lit(ref lit) => { match lit.node { ast::lit_str(*) => { const_expr(cx, sub) } - _ => { cx.sess.span_bug(e.span, - ~"bad const-slice lit") } + _ => { cx.sess.span_bug(e.span, "bad const-slice lit") } } } ast::expr_vec(ref es, ast::m_imm) => { @@ -487,8 +482,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { let p = const_ptrcast(cx, gv, llunitty); C_struct(~[p, sz]) } - _ => cx.sess.span_bug(e.span, - ~"bad const-slice expr") + _ => cx.sess.span_bug(e.span, "bad const-slice expr") } } ast::expr_path(pth) => { @@ -520,8 +514,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { C_null(llty) } _ => { - cx.sess.span_bug(e.span, ~"expected a const, fn, \ - struct, or variant def") + cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def") } } } @@ -542,13 +535,12 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { adt::trans_const(cx, repr, vinfo.disr_val, args.map(|a| const_expr(cx, *a))) } - _ => cx.sess.span_bug(e.span, ~"expected a struct or \ - variant def") + _ => cx.sess.span_bug(e.span, "expected a struct or variant def") } } ast::expr_paren(e) => { return const_expr(cx, e); } _ => cx.sess.span_bug(e.span, - ~"bad constant expression type in consts::const_expr") + "bad constant expression type in consts::const_expr") }; } } @@ -559,7 +551,7 @@ pub fn trans_const(ccx: @CrateContext, _e: @ast::expr, id: ast::node_id) { let g = base::get_item_val(ccx, id); // At this point, get_item_val has already translated the // constant's initializer to determine its LLVM type. - let v = *ccx.const_values.get(&id); + let v = ccx.const_values.get_copy(&id); llvm::LLVMSetInitializer(g, v); llvm::LLVMSetGlobalConstant(g, True); } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 113136fa58d13..ac512bc4bf95d 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -34,7 +34,7 @@ pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block { do block_locals(b) |local| { bcx = alloc_local(bcx, local); }; - for vec::each(b.node.stmts) |s| { + for b.node.stmts.each |s| { debuginfo::update_source_pos(bcx, b.span); bcx = trans_stmt(bcx, *s); } @@ -65,8 +65,8 @@ pub fn trans_if(bcx: block, let Result {bcx, val: cond_val} = expr::trans_to_datum(bcx, cond).to_result(); - let then_bcx_in = scope_block(bcx, thn.info(), ~"then"); - let else_bcx_in = scope_block(bcx, els.info(), ~"else"); + let then_bcx_in = scope_block(bcx, thn.info(), "then"); + let else_bcx_in = scope_block(bcx, els.info(), "else"); let cond_val = bool_to_i1(bcx, cond_val); CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb); @@ -105,9 +105,9 @@ pub fn trans_if(bcx: block, } pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block { - let out = sub_block(parent_bcx, ~"join"); + let out = sub_block(parent_bcx, "join"); let mut reachable = false; - for vec::each(in_cxs) |bcx| { + for in_cxs.each |bcx| { if !bcx.unreachable { Br(*bcx, out.llbb); reachable = true; @@ -121,7 +121,7 @@ pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block { pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block { let _icx = bcx.insn_ctxt("trans_while"); - let next_bcx = sub_block(bcx, ~"while next"); + let next_bcx = sub_block(bcx, "while next"); // bcx // | @@ -136,10 +136,10 @@ pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block { // | body_bcx_out --+ // next_bcx - let loop_bcx = loop_scope_block(bcx, next_bcx, None, ~"`while`", + let loop_bcx = loop_scope_block(bcx, next_bcx, None, "`while`", body.info()); - let cond_bcx_in = scope_block(loop_bcx, cond.info(), ~"while loop cond"); - let body_bcx_in = scope_block(loop_bcx, body.info(), ~"while loop body"); + let cond_bcx_in = scope_block(loop_bcx, cond.info(), "while loop cond"); + let body_bcx_in = scope_block(loop_bcx, body.info(), "while loop body"); Br(bcx, loop_bcx.llbb); Br(loop_bcx, cond_bcx_in.llbb); @@ -163,8 +163,8 @@ pub fn trans_loop(bcx:block, opt_label: Option) -> block { let _icx = bcx.insn_ctxt("trans_loop"); - let next_bcx = sub_block(bcx, ~"next"); - let body_bcx_in = loop_scope_block(bcx, next_bcx, opt_label, ~"`loop`", + let next_bcx = sub_block(bcx, "next"); + let body_bcx_in = loop_scope_block(bcx, next_bcx, opt_label, "`loop`", body.info()); Br(bcx, body_bcx_in.llbb); let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore); @@ -186,17 +186,17 @@ pub fn trans_log(log_ex: @ast::expr, let (modpath, modname) = { let path = &mut bcx.fcx.path; let modpath = vec::append( - ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name.to_owned()))], + ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name))], path.filtered(|e| match *e { path_mod(_) => true, _ => false })); let modname = path_str(ccx.sess, modpath); (modpath, modname) }; let global = if ccx.module_data.contains_key(&modname) { - *ccx.module_data.get(&modname) + ccx.module_data.get_copy(&modname) } else { let s = link::mangle_internal_name_by_path_and_seq( - ccx, modpath, ~"loglevel"); + ccx, modpath, "loglevel"); let global; unsafe { global = str::as_c_str(s, |buf| { @@ -211,14 +211,14 @@ pub fn trans_log(log_ex: @ast::expr, }; let current_level = Load(bcx, global); let level = unpack_result!(bcx, { - do with_scope_result(bcx, lvl.info(), ~"level") |bcx| { + do with_scope_result(bcx, lvl.info(), "level") |bcx| { expr::trans_to_datum(bcx, lvl).to_result() } }); let llenabled = ICmp(bcx, lib::llvm::IntUGE, current_level, level); do with_cond(bcx, llenabled) |bcx| { - do with_scope(bcx, log_ex.info(), ~"log") |bcx| { + do with_scope(bcx, log_ex.info(), "log") |bcx| { let mut bcx = bcx; // Translate the value to be logged @@ -243,8 +243,8 @@ pub fn trans_break_cont(bcx: block, let mut unwind = bcx; let mut target; loop { - match *unwind.kind { - block_scope(scope_info { + match unwind.kind { + block_scope(@scope_info { loop_break: Some(brk), loop_label: l, _ @@ -333,7 +333,7 @@ pub fn trans_fail_expr(bcx: block, bcx, expr::trans_to_datum(bcx, arg_expr)); if ty::type_is_str(arg_datum.ty) { - let (lldata, _lllen) = arg_datum.get_base_and_len(bcx); + let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx); return trans_fail_value(bcx, sp_opt, lldata); } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) { return bcx; @@ -385,17 +385,10 @@ fn trans_fail_value(bcx: block, pub fn trans_fail_bounds_check(bcx: block, sp: span, index: ValueRef, len: ValueRef) -> block { let _icx = bcx.insn_ctxt("trans_fail_bounds_check"); - let ccx = bcx.ccx(); - - let loc = bcx.sess().parse_sess.cm.lookup_char_pos(sp.lo); - let line = C_int(ccx, loc.line as int); - let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); - let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); - + let (filename, line) = filename_and_line_num_from_span(bcx, sp); let args = ~[filename, line, index, len]; let bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.fail_bounds_check_fn(), args, expr::Ignore); Unreachable(bcx); return bcx; } - diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index fa27f652ac880..374bb23f2cb57 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -87,17 +87,16 @@ use lib; use lib::llvm::ValueRef; -use middle::borrowck::{RootInfo, root_map_key}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; -use middle::trans::callee; use middle::trans::common::*; use middle::trans::common; use middle::trans::expr; use middle::trans::glue; use middle::trans::tvec; use middle::trans::type_of; +use middle::trans::write_guard; use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; @@ -105,6 +104,7 @@ use util::ppaux::ty_to_str; use core::container::Set; // XXX: this should not be necessary use core::to_bytes; use syntax::ast; +use syntax::codemap::span; use syntax::parse::token::special_idents; #[deriving(Eq)] @@ -155,11 +155,18 @@ pub impl DatumMode { } } +#[cfg(stage0)] impl to_bytes::IterBytes for DatumMode { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as uint).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for DatumMode { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} /// See `Datum cleanup styles` section at the head of this module. #[deriving(Eq)] @@ -516,59 +523,6 @@ pub impl Datum { } } - fn root(&self, bcx: block, root_info: RootInfo) -> block { - /*! - * - * In some cases, borrowck will decide that an @T/@[]/@str - * value must be rooted for the program to be safe. In that - * case, we will call this function, which will stash a copy - * away until we exit the scope `scope_id`. */ - - debug!("root(scope_id=%?, freezes=%?, self=%?)", - root_info.scope, root_info.freezes, self.to_str(bcx.ccx())); - - if bcx.sess().trace() { - trans_trace( - bcx, None, - @fmt!("preserving until end of scope %d", - root_info.scope)); - } - - let scratch = scratch_datum(bcx, self.ty, true); - self.copy_to_datum(bcx, INIT, scratch); - add_root_cleanup(bcx, root_info, scratch.val, scratch.ty); - - // If we need to freeze the box, do that now. - if root_info.freezes { - callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.borrow_as_imm_fn(), - ~[ - Load(bcx, - PointerCast(bcx, - scratch.val, - T_ptr(T_ptr(T_i8())))) - ], - expr::Ignore) - } else { - bcx - } - } - - fn perform_write_guard(&self, bcx: block) -> block { - // Create scratch space, but do not root it. - let llval = match self.mode { - ByValue => self.val, - ByRef => Load(bcx, self.val), - }; - - callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.check_not_borrowed_fn(), - ~[ PointerCast(bcx, llval, T_ptr(T_i8())) ], - expr::Ignore) - } - fn drop_val(&self, bcx: block) -> block { if !ty::type_needs_drop(bcx.tcx(), self.ty) { return bcx; @@ -601,11 +555,9 @@ pub impl Datum { } fn to_rptr(&self, bcx: block) -> Datum { - //! - // - // Returns a new datum of region-pointer type containing the - // the same ptr as this datum (after converting to by-ref - // using `to_ref_llval()`). + //! Returns a new datum of region-pointer type containing the + //! the same ptr as this datum (after converting to by-ref + //! using `to_ref_llval()`). // Convert to ref, yielding lltype *T. Then create a Rust // type &'static T (which translates to *T). Construct new @@ -620,32 +572,20 @@ pub impl Datum { fn try_deref(&self, bcx: block, // block wherein to generate insn's - expr_id: ast::node_id, // id of expr being deref'd + span: span, // location where deref occurs + expr_id: ast::node_id, // id of deref expr derefs: uint, // number of times deref'd already is_auto: bool) // if true, only deref if auto-derefable -> (Option, block) { let ccx = bcx.ccx(); - debug!("try_deref(expr_id=%d, derefs=%?, is_auto=%b, self=%?)", + debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)", expr_id, derefs, is_auto, self.to_str(bcx.ccx())); - let _indenter = indenter(); - // root the autoderef'd value, if necessary: - // - // (Note: root'd values are always boxes) - let key = root_map_key { id: expr_id, derefs: derefs }; - let bcx = match ccx.maps.root_map.find(&key) { - None => bcx, - Some(&root_info) => self.root(bcx, root_info) - }; - - // Perform the write guard, if necessary. - // - // (Note: write-guarded values are always boxes) - let bcx = if ccx.maps.write_guard_map.contains(&key) { - self.perform_write_guard(bcx) - } else { bcx }; + let bcx = + write_guard::root_and_write_guard( + self, bcx, span, expr_id, derefs); match ty::get(self.ty).sty { ty::ty_box(_) | ty::ty_uniq(_) => { @@ -755,19 +695,20 @@ pub impl Datum { } fn deref(&self, bcx: block, - expr: @ast::expr, // the expression whose value is being deref'd + expr: @ast::expr, // the deref expression derefs: uint) -> DatumBlock { - match self.try_deref(bcx, expr.id, derefs, false) { + match self.try_deref(bcx, expr.span, expr.id, derefs, false) { (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres }, (None, _) => { - bcx.ccx().sess.span_bug( - expr.span, ~"Cannot deref this expression"); + bcx.ccx().sess.span_bug(expr.span, + "Cannot deref this expression"); } } } fn autoderef(&self, bcx: block, + span: span, expr_id: ast::node_id, max: uint) -> DatumBlock { @@ -782,7 +723,7 @@ pub impl Datum { let mut bcx = bcx; while derefs < max { derefs += 1u; - match datum.try_deref(bcx, expr_id, derefs, true) { + match datum.try_deref(bcx, span, expr_id, derefs, true) { (None, new_bcx) => { bcx = new_bcx; break } (Some(datum_deref), new_bcx) => { datum = datum_deref; @@ -798,8 +739,35 @@ pub impl Datum { DatumBlock { bcx: bcx, datum: datum } } - fn get_base_and_len(&self, bcx: block) -> (ValueRef, ValueRef) { - tvec::get_base_and_len(bcx, self.to_appropriate_llval(bcx), self.ty) + fn get_vec_base_and_len(&self, + mut bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) + -> (block, ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Performs rooting + //! and write guards checks. + + // only imp't for @[] and @str, but harmless + bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs); + let (base, len) = self.get_vec_base_and_len_no_root(bcx); + (bcx, base, len) + } + + fn get_vec_base_and_len_no_root(&self, bcx: block) -> (ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Des not root + //! nor perform write guard checks. + + let llval = self.to_appropriate_llval(bcx); + tvec::get_base_and_len(bcx, llval, self.ty) + } + + fn root_and_write_guard(&self, + bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) -> block { + write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs) } fn to_result(&self, bcx: block) -> common::Result { @@ -855,4 +823,3 @@ pub impl DatumBlock { self.datum.to_str(self.ccx()) } } - diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 2a2bf7ba4ad68..f0fb33136ffbf 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -517,7 +517,7 @@ fn create_tuple(cx: @CrateContext, t: ty::t, elements: &[ty::t], span: span) let scx = create_structure(file_node, cx.sess.str_of( ((/*bad*/copy cx.dbg_cx).get().names) - (~"tuple")), + ("tuple")), line_from_span(cx.sess.codemap, span) as int); for elements.each |element| { let ty_md = create_ty(cx, *element, span); @@ -756,7 +756,7 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) } }, ty::ty_enum(_did, ref _substs) => { - cx.sess.span_bug(span, ~"debuginfo for enum NYI") + cx.sess.span_bug(span, "debuginfo for enum NYI") } ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => { let boxed = create_ty(cx, mt.ty, span); @@ -782,7 +782,7 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) create_pointer_type(cx, t, span, pointee) }, ty::ty_rptr(ref _region, ref _mt) => { - cx.sess.span_bug(span, ~"debuginfo for rptr NYI") + cx.sess.span_bug(span, "debuginfo for rptr NYI") }, ty::ty_bare_fn(ref barefnty) => { let inputs = do barefnty.sig.inputs.map |a| { a.ty }; @@ -790,10 +790,10 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) create_fn_ty(cx, t, inputs, output, span) }, ty::ty_closure(ref _closurety) => { - cx.sess.span_bug(span, ~"debuginfo for closure NYI") + cx.sess.span_bug(span, "debuginfo for closure NYI") }, ty::ty_trait(_did, ref _substs, ref _vstore, _) => { - cx.sess.span_bug(span, ~"debuginfo for trait NYI") + cx.sess.span_bug(span, "debuginfo for trait NYI") }, ty::ty_struct(did, ref substs) => { let fields = ty::struct_fields(cx.tcx, did, substs); @@ -860,14 +860,12 @@ pub fn create_local_var(bcx: block, local: @ast::local) let llptr = match bcx.fcx.lllocals.find(&local.node.id) { option::Some(&local_mem(v)) => v, option::Some(_) => { - bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird"); + bcx.tcx().sess.span_bug(local.span, "local is bound to something weird"); } option::None => { - match *bcx.fcx.lllocals.get(&local.node.pat.id) { + match bcx.fcx.lllocals.get_copy(&local.node.pat.id) { local_imm(v) => v, - _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird") + _ => bcx.tcx().sess.span_bug(local.span, "local is bound to something weird") } } }; @@ -917,7 +915,7 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) }; update_cache(cache, tg, argument_metadata(mdval)); - let llptr = match *fcx.llargs.get(&arg.id) { + let llptr = match fcx.llargs.get_copy(&arg.id) { local_mem(v) | local_imm(v) => v, }; let declargs = ~[llmdnode(~[llptr]), mdnode]; @@ -960,14 +958,13 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { let sp = fcx.span.get(); debug!("%s", cx.sess.codemap.span_to_str(sp)); - let (ident, ret_ty, id) = match *cx.tcx.items.get(&fcx.id) { + let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { ast_map::node_item(item, _) => { match item.node { ast::item_fn(ref decl, _, _, _, _) => { (item.ident, decl.output, item.id) } - _ => fcx.ccx.sess.span_bug(item.span, ~"create_function: item \ - bound to non-function") + _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function") } } ast_map::node_method(method, _, _) => { @@ -976,18 +973,13 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { ast_map::node_expr(expr) => { match expr.node { ast::expr_fn_block(ref decl, _) => { - ((dbg_cx.names)(~"fn"), decl.output, expr.id) + ((dbg_cx.names)("fn"), decl.output, expr.id) } _ => fcx.ccx.sess.span_bug(expr.span, - ~"create_function: \ - expected an expr_fn_block here") + "create_function: expected an expr_fn_block here") } } - ast_map::node_dtor(_, _, did, _) => { - ((dbg_cx.names)(~"dtor"), ast_util::dtor_ty(), did.node) - } - _ => fcx.ccx.sess.bug(~"create_function: unexpected \ - sort of node") + _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") }; debug!("%?", ident); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index f83562add3169..59526ffbe498d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -120,15 +120,14 @@ lvalues are *never* stored by value. */ use back::abi; -use lib; use lib::llvm::{ValueRef, TypeRef, llvm}; +use lib; use metadata::csearch; -use middle::borrowck::root_map_key; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; -use middle::trans::base; use middle::trans::base::*; +use middle::trans::base; use middle::trans::build::*; use middle::trans::callee::DoAutorefArg; use middle::trans::callee; @@ -143,12 +142,13 @@ use middle::trans::machine; use middle::trans::meth; use middle::trans::tvec; use middle::trans::type_of; -use middle::ty; -use middle::ty::struct_mutable_fields; +use middle::ty::struct_fields; +use middle::ty::{AutoDerefRef, AutoAddEnv}; use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn, - AutoDerefRef, AutoAddEnv}; + AutoDerefRef, AutoAddEnv, AutoUnsafe}; +use middle::ty; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use core::cast::transmute; use core::hashmap::HashMap; @@ -184,64 +184,73 @@ fn drop_and_cancel_clean(bcx: block, dat: Datum) -> block { pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr)); - return match bcx.tcx().adjustments.find(&expr.id) { - None => { - trans_to_datum_unadjusted(bcx, expr) - } - Some(&@AutoAddEnv(*)) => { - let mut bcx = bcx; - let datum = unpack_datum!(bcx, { - trans_to_datum_unadjusted(bcx, expr) - }); - add_env(bcx, expr, datum) - } - Some(&@AutoDerefRef(ref adj)) => { - let mut bcx = bcx; - let mut datum = unpack_datum!(bcx, { - trans_to_datum_unadjusted(bcx, expr) - }); + let mut bcx = bcx; + let mut datum = unpack_datum!(bcx, trans_to_datum_unadjusted(bcx, expr)); + let adjustment = match bcx.tcx().adjustments.find_copy(&expr.id) { + None => { return DatumBlock {bcx: bcx, datum: datum}; } + Some(adj) => { adj } + }; + debug!("unadjusted datum: %s", datum.to_str(bcx.ccx())); + match *adjustment { + AutoAddEnv(*) => { + datum = unpack_datum!(bcx, add_env(bcx, expr, datum)); + } + AutoDerefRef(ref adj) => { if adj.autoderefs > 0 { - let DatumBlock { bcx: new_bcx, datum: new_datum } = - datum.autoderef(bcx, expr.id, adj.autoderefs); - datum = new_datum; - bcx = new_bcx; + datum = + unpack_datum!( + bcx, + datum.autoderef(bcx, expr.span, + expr.id, adj.autoderefs)); } datum = match adj.autoref { - None => datum, - Some(ref autoref) => { - match autoref.kind { - AutoPtr => { - unpack_datum!(bcx, auto_ref(bcx, datum)) - } - AutoBorrowVec => { - unpack_datum!(bcx, auto_slice(bcx, datum)) - } - AutoBorrowVecRef => { - unpack_datum!(bcx, auto_slice_and_ref(bcx, datum)) - } - AutoBorrowFn => { - // currently, all closure types are - // represented precisely the same, so no - // runtime adjustment is required: - datum - } - } + None => { + datum + } + Some(AutoUnsafe(*)) | // region + unsafe ptrs have same repr + Some(AutoPtr(*)) => { + unpack_datum!(bcx, auto_ref(bcx, datum)) + } + Some(AutoBorrowVec(*)) => { + unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs, + expr, datum)) + } + Some(AutoBorrowVecRef(*)) => { + unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs, + expr, datum)) + } + Some(AutoBorrowFn(*)) => { + let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span, + datum.ty, Some(adjustment)); + unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum)) } }; - - debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx())); - - return DatumBlock {bcx: bcx, datum: datum}; } - }; + } + debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx())); + return DatumBlock {bcx: bcx, datum: datum}; fn auto_ref(bcx: block, datum: Datum) -> DatumBlock { DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)} } - fn auto_slice(bcx: block, datum: Datum) -> DatumBlock { + fn auto_borrow_fn(bcx: block, + adjusted_ty: ty::t, + datum: Datum) -> DatumBlock { + // Currently, all closure types are represented precisely the + // same, so no runtime adjustment is required, but we still + // must patchup the type. + DatumBlock {bcx: bcx, + datum: Datum {val: datum.val, ty: adjusted_ty, + mode: datum.mode, source: datum.source}} + } + + fn auto_slice(bcx: block, + autoderefs: uint, + expr: @ast::expr, + datum: Datum) -> DatumBlock { // This is not the most efficient thing possible; since slices // are two words it'd be better if this were compiled in // 'dest' mode, but I can't find a nice way to structure the @@ -250,7 +259,9 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let unit_ty = ty::sequence_element_type(tcx, datum.ty); - let (base, len) = datum.get_base_and_len(bcx); + + let (bcx, base, len) = + datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1); // this type may have a different region/mutability than the // real one, but it will have the same runtime representation @@ -273,7 +284,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let closure_ty = expr_ty_adjusted(bcx, expr); - debug!("add_env(closure_ty=%s)", ty_to_str(tcx, closure_ty)); + debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx)); let scratch = scratch_datum(bcx, closure_ty, false); let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); assert!(datum.appropriate_mode() == ByValue); @@ -283,8 +294,11 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { DatumBlock {bcx: bcx, datum: scratch} } - fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock { - let DatumBlock { bcx, datum } = auto_slice(bcx, datum); + fn auto_slice_and_ref(bcx: block, + autoderefs: uint, + expr: @ast::expr, + datum: Datum) -> DatumBlock { + let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum); auto_ref(bcx, datum) } } @@ -437,7 +451,7 @@ fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr))); match expr.node { - ast::expr_path(_) => { + ast::expr_path(_) | ast::expr_self => { return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id)); } ast::expr_vstore(contents, ast::expr_vstore_box) | @@ -514,33 +528,6 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { return src_datum.store_to_datum( bcx, src.id, DROP_EXISTING, dst_datum); } - ast::expr_swap(dst, src) => { - let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst)); - let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src)); - - // If the source and destination are the same, then don't swap. - // Avoids performing an overlapping memcpy - let dst_datum_ref = dst_datum.to_ref_llval(bcx); - let src_datum_ref = src_datum.to_ref_llval(bcx); - let cmp = ICmp(bcx, lib::llvm::IntEQ, - src_datum_ref, - dst_datum_ref); - - let swap_cx = base::sub_block(bcx, ~"swap"); - let next_cx = base::sub_block(bcx, ~"next"); - - CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb); - - let scratch = scratch_datum(swap_cx, dst_datum.ty, false); - - let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch); - let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum); - let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum); - - Br(swap_cx, next_cx.llbb); - - return next_cx; - } ast::expr_assign_op(op, dst, src) => { return trans_assign_op(bcx, expr, op, dst, src); } @@ -562,7 +549,6 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, dest: Dest) -> block { - let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_rvalue_dps_unadjusted"); let tcx = bcx.tcx(); @@ -572,7 +558,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, ast::expr_paren(e) => { return trans_rvalue_dps_unadjusted(bcx, e, dest); } - ast::expr_path(_) => { + ast::expr_path(_) | ast::expr_self => { return trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest); } @@ -585,7 +571,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_block(ref blk) => { return do base::with_scope(bcx, blk.info(), - ~"block-expr body") |bcx| { + "block-expr body") |bcx| { controlflow::trans_block(bcx, blk, dest) }; } @@ -612,7 +598,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, let sigil = ty::ty_closure_sigil(expr_ty); debug!("translating fn_block %s with type %s", expr_to_str(expr, tcx.sess.intr()), - ty_to_str(tcx, expr_ty)); + expr_ty.repr(tcx)); return closure::trans_expr_fn(bcx, sigil, decl, body, expr.id, expr.id, None, dest); @@ -690,7 +676,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } _ => { bcx.tcx().sess.span_bug(expr.span, - ~"expr_cast of non-trait"); + "expr_cast of non-trait"); } } } @@ -700,8 +686,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, _ => { bcx.tcx().sess.span_bug( expr.span, - fmt!("trans_rvalue_dps_unadjusted reached \ - fall-through case: %?", + fmt!("trans_rvalue_dps_unadjusted reached fall-through case: %?", expr.node)); } } @@ -821,67 +806,35 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr))); - let unrooted_datum = unpack_datum!(bcx, unrooted(bcx, expr)); - - // If the lvalue must remain rooted, create a scratch datum, copy - // the lvalue in there, and then arrange for it to be cleaned up - // at the end of the scope with id `scope_id`: - let root_key = root_map_key { id: expr.id, derefs: 0u }; - for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| { - bcx = unrooted_datum.root(bcx, *root_info); - } - - return DatumBlock {bcx: bcx, datum: unrooted_datum}; - - fn unrooted(bcx: block, expr: @ast::expr) -> DatumBlock { - /*! - * - * Translates `expr`. Note that this version generally - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - * - * One exception is if `expr` refers to a local variable, - * in which case the source may already be FromMovedLvalue - * if appropriate. - */ - - let mut bcx = bcx; - - match expr.node { - ast::expr_paren(e) => { - return unrooted(bcx, e); - } - ast::expr_path(_) => { - return trans_def_lvalue(bcx, expr, bcx.def(expr.id)); - } - ast::expr_field(base, ident, _) => { - return trans_rec_field(bcx, base, ident); - } - ast::expr_index(base, idx) => { - return trans_index(bcx, expr, base, idx); - } - ast::expr_unary(ast::deref, base) => { - let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base)); - return basedatum.deref(bcx, base, 0); - } - _ => { - bcx.tcx().sess.span_bug( - expr.span, - fmt!("trans_lvalue reached fall-through case: %?", - expr.node)); - } + return match expr.node { + ast::expr_paren(e) => { + trans_lvalue_unadjusted(bcx, e) } - } + ast::expr_path(_) | ast::expr_self => { + trans_def_lvalue(bcx, expr, bcx.def(expr.id)) + } + ast::expr_field(base, ident, _) => { + trans_rec_field(bcx, base, ident) + } + ast::expr_index(base, idx) => { + trans_index(bcx, expr, base, idx) + } + ast::expr_unary(ast::deref, base) => { + let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base)); + basedatum.deref(bcx, expr, 0) + } + _ => { + bcx.tcx().sess.span_bug( + expr.span, + fmt!("trans_lvalue reached fall-through case: %?", + expr.node)); + } + }; fn trans_rec_field(bcx: block, base: @ast::expr, field: ast::ident) -> DatumBlock { - /*! - * - * Translates `base.field`. Note that this version always - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - */ + //! Translates `base.field`. let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_rec_field"); @@ -905,12 +858,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { index_expr: @ast::expr, base: @ast::expr, idx: @ast::expr) -> DatumBlock { - /*! - * - * Translates `base[idx]`. Note that this version always - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - */ + //! Translates `base[idx]`. let _icx = bcx.insn_ctxt("trans_index"); let ccx = bcx.ccx(); @@ -941,7 +889,9 @@ 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 (base, len) = base_datum.get_base_and_len(bcx); + let mut (bcx, base, len) = + base_datum.get_vec_base_and_len(bcx, index_expr.span, + index_expr.id, 0); if ty::type_is_str(base_ty) { // acccount for null terminator in the case of string @@ -973,14 +923,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { def: ast::def) -> DatumBlock { - /*! - * - * Translates a reference to a path. Note that this version - * generally yields an unrooted, unmoved version. Rooting and - * possible moves are dealt with above in - * trans_lvalue_unadjusted(), with the caveat that local variables - * may already be in move mode. - */ + //! Translates a reference to a path. let _icx = bcx.insn_ctxt("trans_def_lvalue"); let ccx = bcx.ccx(); @@ -998,7 +941,10 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t) - -> ValueRef { + -> ValueRef { + // For external constants, we don't inline. + let extern_const_values = + &mut *bcx.ccx().extern_const_values; if did.crate == ast::local_crate { // The LLVM global has the type of its initializer, // which may not be equal to the enum's type for @@ -1007,25 +953,24 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { base::get_item_val(bcx.ccx(), did.node), T_ptr(type_of(bcx.ccx(), const_ty))) } else { - // For external constants, we don't inline. - match bcx.ccx().extern_const_values.find(&did) { - None => { - unsafe { - let llty = type_of(bcx.ccx(), const_ty); - let symbol = csearch::get_symbol( - bcx.ccx().sess.cstore, - did); - let llval = llvm::LLVMAddGlobal( - bcx.ccx().llmod, - llty, - transmute::<&u8,*i8>(&symbol[0])); - bcx.ccx().extern_const_values.insert( - did, - llval); - llval - } + match extern_const_values.find(&did) { + None => {} // Continue. + Some(llval) => { + return *llval; } - Some(llval) => *llval + } + + unsafe { + let llty = type_of(bcx.ccx(), const_ty); + let symbol = csearch::get_symbol( + bcx.ccx().sess.cstore, + did); + let llval = llvm::LLVMAddGlobal( + bcx.ccx().llmod, + llty, + transmute::<&u8,*i8>(&symbol[0])); + extern_const_values.insert(did, llval); + llval } } } @@ -1088,6 +1033,9 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { } }; + debug!("def_self() reference, self_info.t=%s", + self_info.t.repr(bcx.tcx())); + // This cast should not be necessary. We should cast self *once*, // but right now this conflicts with default methods. let real_self_ty = monomorphize_type(bcx, self_info.t); @@ -1141,7 +1089,7 @@ pub fn with_field_tys(tcx: ty::ctxt, op: &fn(int, (&[ty::field])) -> R) -> R { match ty::get(ty).sty { ty::ty_struct(did, ref substs) => { - op(0, struct_mutable_fields(tcx, did, substs)) + op(0, struct_fields(tcx, did, substs)) } ty::ty_enum(_, ref substs) => { @@ -1151,15 +1099,15 @@ pub fn with_field_tys(tcx: ty::ctxt, tcx.sess.bug(fmt!( "cannot get field types from the enum type %s \ without a node ID", - ty_to_str(tcx, ty))); + ty.repr(tcx))); } Some(node_id) => { - match *tcx.def_map.get(&node_id) { + match tcx.def_map.get_copy(&node_id) { ast::def_variant(enum_id, variant_id) => { let variant_info = ty::enum_variant_with_id( tcx, enum_id, variant_id); - op(variant_info.disr_val, struct_mutable_fields( - tcx, variant_id, substs)) + op(variant_info.disr_val, + struct_fields(tcx, variant_id, substs)) } _ => { tcx.sess.bug(~"resolve didn't map this expr to a \ @@ -1173,7 +1121,7 @@ pub fn with_field_tys(tcx: ty::ctxt, _ => { tcx.sess.bug(fmt!( "cannot get field types from the type %s", - ty_to_str(tcx, ty))); + ty.repr(tcx))); } } } @@ -1202,7 +1150,7 @@ fn trans_rec_or_struct(bcx: block, } None => { tcx.sess.span_bug(field.span, - ~"Couldn't find field in struct type") + "Couldn't find field in struct type") } } }; @@ -1296,7 +1244,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, } } - for vec::each(temp_cleanups) |cleanup| { + for temp_cleanups.each |cleanup| { revoke_clean(bcx, *cleanup); } return bcx; @@ -1404,7 +1352,6 @@ fn trans_eager_binop(bcx: block, lhs_datum: &Datum, rhs_datum: &Datum) -> DatumBlock { - let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_eager_binop"); let lhs = lhs_datum.to_appropriate_llval(bcx); @@ -1435,7 +1382,7 @@ fn trans_eager_binop(bcx: block, if is_float { FMul(bcx, lhs, rhs) } else { Mul(bcx, lhs, rhs) } } - ast::quot => { + ast::div => { if is_float { FDiv(bcx, lhs, rhs) } else { @@ -1478,7 +1425,7 @@ fn trans_eager_binop(bcx: block, } else { if !ty::type_is_scalar(rhs_t) { bcx.tcx().sess.span_bug(binop_expr.span, - ~"non-scalar comparison"); + "non-scalar comparison"); } let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op); bcx = cmpr.bcx; @@ -1486,7 +1433,7 @@ fn trans_eager_binop(bcx: block, } } _ => { - bcx.tcx().sess.span_bug(binop_expr.span, ~"unexpected binop"); + bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop"); } }; @@ -1506,7 +1453,7 @@ fn trans_lazy_binop(bcx: block, let bcx = bcx; let Result {bcx: past_lhs, val: lhs} = { - do base::with_scope_result(bcx, a.info(), ~"lhs") |bcx| { + do base::with_scope_result(bcx, a.info(), "lhs") |bcx| { trans_to_datum(bcx, a).to_result() } }; @@ -1515,8 +1462,8 @@ fn trans_lazy_binop(bcx: block, return immediate_rvalue_bcx(past_lhs, lhs, binop_ty); } - let join = base::sub_block(bcx, ~"join"); - let before_rhs = base::sub_block(bcx, ~"rhs"); + let join = base::sub_block(bcx, "join"); + let before_rhs = base::sub_block(bcx, "rhs"); let lhs_i1 = bool_to_i1(past_lhs, lhs); match op { @@ -1525,7 +1472,7 @@ fn trans_lazy_binop(bcx: block, } let Result {bcx: past_rhs, val: rhs} = { - do base::with_scope_result(before_rhs, b.info(), ~"rhs") |bcx| { + do base::with_scope_result(before_rhs, b.info(), "rhs") |bcx| { trans_to_datum(bcx, b).to_result() } }; @@ -1574,7 +1521,7 @@ fn trans_overloaded_op(bcx: block, ret_ty: ty::t, dest: Dest) -> block { - let origin = *bcx.ccx().maps.method_map.get(&expr.id); + let origin = bcx.ccx().maps.method_map.get_copy(&expr.id); let fty = node_id_type(bcx, expr.callee_id); callee::trans_call_inner(bcx, expr.info(), diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index c45ba64c58470..30db63e9c19da 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -294,7 +294,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext, Some(abi) => abi, }; - for vec::each(foreign_mod.items) |&foreign_item| { + for foreign_mod.items.each |&foreign_item| { match foreign_item.node { ast::foreign_item_fn(*) => { let id = foreign_item.id; @@ -592,6 +592,30 @@ pub fn trans_intrinsic(ccx: @CrateContext, Release); Store(bcx, old, fcx.llretptr.get()); } + ~"atomic_load" => { + let old = AtomicLoad(bcx, + get_param(decl, first_real_arg), + SequentiallyConsistent); + Store(bcx, old, fcx.llretptr.get()); + } + ~"atomic_load_acq" => { + let old = AtomicLoad(bcx, + get_param(decl, first_real_arg), + Acquire); + Store(bcx, old, fcx.llretptr.get()); + } + ~"atomic_store" => { + AtomicStore(bcx, + get_param(decl, first_real_arg + 1u), + get_param(decl, first_real_arg), + SequentiallyConsistent); + } + ~"atomic_store_rel" => { + AtomicStore(bcx, + get_param(decl, first_real_arg + 1u), + get_param(decl, first_real_arg), + Release); + } ~"atomic_xchg" => { let old = AtomicRMW(bcx, Xchg, get_param(decl, first_real_arg), @@ -715,6 +739,9 @@ pub fn trans_intrinsic(ccx: @CrateContext, Store(bcx, C_null(lltp_ty), fcx.llretptr.get()); } } + ~"uninit" => { + // Do nothing, this is effectively a no-op + } ~"forget" => {} ~"transmute" => { let (in_type, out_type) = (substs.tys[0], substs.tys[1]); @@ -724,7 +751,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, let in_type_size = machine::llbitsize_of_real(ccx, llintype); let out_type_size = machine::llbitsize_of_real(ccx, llouttype); if in_type_size != out_type_size { - let sp = match *ccx.tcx.items.get(&ref_id.get()) { + let sp = match ccx.tcx.items.get_copy(&ref_id.get()) { ast_map::node_expr(e) => e.span, _ => fail!(~"transmute has non-expr arg"), }; @@ -1080,7 +1107,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, _ => { // Could we make this an enum rather than a string? does it get // checked earlier? - ccx.sess.span_bug(item.span, ~"unknown intrinsic"); + ccx.sess.span_bug(item.span, "unknown intrinsic"); } } build_return(bcx); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 4c5a17056b2ea..585d9d8420cd7 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -394,10 +394,15 @@ pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint) pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { let _icx = bcx.insn_ctxt("make_visit_glue"); - let mut bcx = bcx; - let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); - let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); - bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); + let bcx = do with_scope(bcx, None, ~"visitor cleanup") |bcx| { + let mut bcx = bcx; + let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); + let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); + bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); + // The visitor is a boxed object and needs to be dropped + add_clean(bcx, v, object_ty); + bcx + }; build_return(bcx); } @@ -443,11 +448,8 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { // Call the dtor if there is one match ty::ty_dtor(bcx.tcx(), did) { ty::NoDtor => bcx, - ty::LegacyDtor(ref dt_id) => { - trans_struct_drop(bcx, t, v, *dt_id, did, substs, false) - } ty::TraitDtor(ref dt_id) => { - trans_struct_drop(bcx, t, v, *dt_id, did, substs, true) + trans_struct_drop(bcx, t, v, *dt_id, did, substs) } } } @@ -461,8 +463,7 @@ pub fn trans_struct_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id, class_did: ast::def_id, - substs: &ty::substs, - take_ref: bool) + substs: &ty::substs) -> block { let repr = adt::represent_type(bcx.ccx(), t); let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0); @@ -484,15 +485,10 @@ pub fn trans_struct_drop(bcx: block, // (self) assert!((params.len() == 2)); - // If we need to take a reference to the class (because it's using - // the Drop trait), do so now. - let llval; - if take_ref { - llval = alloca(bcx, val_ty(v0)); - Store(bcx, v0, llval); - } else { - llval = v0; - } + // Take a reference to the class (because it's using the Drop trait), + // do so now. + let llval = alloca(bcx, val_ty(v0)); + Store(bcx, v0, llval); let self_arg = PointerCast(bcx, llval, params[1]); let args = ~[C_null(T_ptr(T_i8())), self_arg]; @@ -500,9 +496,7 @@ pub fn trans_struct_drop(bcx: block, Call(bcx, dtor_addr, args); // Drop the fields - let field_tys = - ty::struct_mutable_fields(bcx.tcx(), class_did, - substs); + let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs); for vec::eachi(field_tys) |i, fld| { let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i); bcx = drop_ty(bcx, llfld_a, fld.mt.ty); @@ -534,10 +528,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { ty::TraitDtor(dtor) => { - trans_struct_drop(bcx, t, v0, dtor, did, substs, true) - } - ty::LegacyDtor(dtor) => { - trans_struct_drop(bcx, t, v0, dtor, did, substs, false) + trans_struct_drop(bcx, t, v0, dtor, did, substs) } ty::NoDtor => { // No dtor? Just the default case @@ -549,12 +540,12 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { closure::make_closure_glue(bcx, v0, t, drop_ty) } ty::ty_trait(_, _, ty::BoxTraitStore, _) => { - let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, v0, [0u, abi::trt_field_box])); decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let lluniquevalue = GEPi(bcx, v0, [0, 1]); - let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2])); + let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); + let lltydesc = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_tydesc])); call_tydesc_glue_full(bcx, lluniquevalue, lltydesc, abi::tydesc_field_free_glue, None); bcx @@ -613,13 +604,13 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { closure::make_closure_glue(bcx, v, t, take_ty) } ty::ty_trait(_, _, ty::BoxTraitStore, _) => { - let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box])); incr_refcnt_of_boxed(bcx, llbox); bcx } ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let llval = GEPi(bcx, v, [0, 1]); - let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2])); + let llval = GEPi(bcx, v, [0, abi::trt_field_box]); + let lltydesc = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_tydesc])); call_tydesc_glue_full(bcx, llval, lltydesc, abi::tydesc_field_take_glue, None); bcx @@ -680,9 +671,9 @@ pub fn declare_tydesc(ccx: @CrateContext, t: ty::t) -> @mut tydesc_info { let addrspace = declare_tydesc_addrspace(ccx, t); //XXX this triggers duplicate LLVM symbols let name = @(if false /*ccx.sess.opts.debuginfo*/ { - mangle_internal_name_by_type_only(ccx, t, ~"tydesc") + mangle_internal_name_by_type_only(ccx, t, "tydesc") } else { - mangle_internal_name_by_seq(ccx, ~"tydesc") + mangle_internal_name_by_seq(ccx, "tydesc") }); note_unique_llvm_symbol(ccx, name); debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), *name); diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 7a7f03c2273e1..e5c6244879d32 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -29,101 +29,101 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, -> ast::def_id { let _icx = ccx.insn_ctxt("maybe_instantiate_inline"); match ccx.external.find(&fn_id) { - Some(&Some(node_id)) => { - // Already inline - debug!("maybe_instantiate_inline(%s): already inline as node id %d", - ty::item_path_str(ccx.tcx, fn_id), node_id); - local_def(node_id) - } - Some(&None) => fn_id, // Not inlinable - None => { // Not seen yet - match csearch::maybe_get_item_ast( + Some(&Some(node_id)) => { + // Already inline + debug!("maybe_instantiate_inline(%s): already inline as node id %d", + ty::item_path_str(ccx.tcx, fn_id), node_id); + return local_def(node_id); + } + Some(&None) => { + return fn_id; // Not inlinable + } + None => { + // Not seen yet + } + } + + let csearch_result = + csearch::maybe_get_item_ast( ccx.tcx, fn_id, |a,b,c,d| { astencode::decode_inlined_item(a, b, ccx.maps, /*bad*/ copy c, d) - }) { - - csearch::not_found => { + }); + return match csearch_result { + csearch::not_found => { ccx.external.insert(fn_id, None); fn_id - } - csearch::found(ast::ii_item(item)) => { + } + csearch::found(ast::ii_item(item)) => { ccx.external.insert(fn_id, Some(item.id)); ccx.stats.n_inlines += 1; if translate { trans_item(ccx, item); } local_def(item.id) - } - csearch::found(ast::ii_foreign(item)) => { - ccx.external.insert(fn_id, Some(item.id)); - local_def(item.id) - } - csearch::found_parent(parent_id, ast::ii_item(item)) => { - ccx.external.insert(parent_id, Some(item.id)); - let mut my_id = 0; - match item.node { - ast::item_enum(_, _) => { - let vs_here = ty::enum_variants(ccx.tcx, local_def(item.id)); - let vs_there = ty::enum_variants(ccx.tcx, parent_id); - for vec::each2(*vs_here, *vs_there) |here, there| { - if there.id == fn_id { my_id = here.id.node; } - ccx.external.insert(there.id, Some(here.id.node)); - } + } + csearch::found(ast::ii_foreign(item)) => { + ccx.external.insert(fn_id, Some(item.id)); + local_def(item.id) + } + csearch::found_parent(parent_id, ast::ii_item(item)) => { + ccx.external.insert(parent_id, Some(item.id)); + let mut my_id = 0; + match item.node { + ast::item_enum(_, _) => { + let vs_here = ty::enum_variants(ccx.tcx, local_def(item.id)); + let vs_there = ty::enum_variants(ccx.tcx, parent_id); + for vec::each2(*vs_here, *vs_there) |here, there| { + if there.id == fn_id { my_id = here.id.node; } + ccx.external.insert(there.id, Some(here.id.node)); } - _ => ccx.sess.bug(~"maybe_instantiate_inline: item has a \ - non-enum parent") } - if translate { trans_item(ccx, item); } - local_def(my_id) + _ => ccx.sess.bug(~"maybe_instantiate_inline: item has a \ + non-enum parent") } - csearch::found_parent(_, _) => { - ccx.sess.bug(~"maybe_get_item_ast returned a found_parent \ - with a non-item parent"); - } - csearch::found(ast::ii_method(impl_did, mth)) => { - ccx.stats.n_inlines += 1; - ccx.external.insert(fn_id, Some(mth.id)); - let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did); - let num_type_params = - impl_tpt.generics.type_param_defs.len() + - mth.generics.ty_params.len(); - if translate && num_type_params == 0 { - let llfn = get_item_val(ccx, mth.id); - let path = vec::append( - ty::item_path(ccx.tcx, impl_did), - ~[path_name(mth.ident)]); - let self_kind = match mth.self_ty.node { - ast::sty_static => no_self, - _ => { - let self_ty = ty::node_id_to_type(ccx.tcx, - mth.self_id); - debug!("calling inline trans_fn with self_ty %s", - ty_to_str(ccx.tcx, self_ty)); - match mth.self_ty.node { - ast::sty_value => impl_owned_self(self_ty), - _ => impl_self(self_ty), - } - } - }; - trans_fn(ccx, - path, - &mth.decl, - &mth.body, - llfn, - self_kind, - None, - mth.id, - Some(impl_did), - []); - } - local_def(mth.id) - } - csearch::found(ast::ii_dtor(ref dtor, _, _, _)) => { - ccx.external.insert(fn_id, Some((*dtor).node.id)); - local_def((*dtor).node.id) + if translate { trans_item(ccx, item); } + local_def(my_id) + } + csearch::found_parent(_, _) => { + ccx.sess.bug(~"maybe_get_item_ast returned a found_parent \ + with a non-item parent"); + } + csearch::found(ast::ii_method(impl_did, mth)) => { + ccx.stats.n_inlines += 1; + ccx.external.insert(fn_id, Some(mth.id)); + let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did); + let num_type_params = + impl_tpt.generics.type_param_defs.len() + + mth.generics.ty_params.len(); + if translate && num_type_params == 0 { + let llfn = get_item_val(ccx, mth.id); + let path = vec::append( + ty::item_path(ccx.tcx, impl_did), + ~[path_name(mth.ident)]); + let self_kind = match mth.self_ty.node { + ast::sty_static => no_self, + _ => { + let self_ty = ty::node_id_to_type(ccx.tcx, + mth.self_id); + debug!("calling inline trans_fn with self_ty %s", + ty_to_str(ccx.tcx, self_ty)); + match mth.self_ty.node { + ast::sty_value => impl_owned_self(self_ty), + _ => impl_self(self_ty), + } + } + }; + trans_fn(ccx, + path, + &mth.decl, + &mth.body, + llfn, + self_kind, + None, + mth.id, + Some(impl_did), + []); } + local_def(mth.id) } - } - } + }; } - diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 3ae2421a55589..038c5e0369b8c 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -87,7 +87,7 @@ pub fn nonzero_llsize_of(cx: @CrateContext, t: TypeRef) -> ValueRef { } // Returns the preferred alignment of the given type for the current target. -// The preffered alignment may be larger than the alignment used when +// The preferred alignment may be larger than the alignment used when // packing the type into structs. This will be used for things like // allocations inside a stack frame, which LLVM has a free hand in. pub fn llalign_of_pref(cx: @CrateContext, t: TypeRef) -> uint { @@ -96,7 +96,7 @@ pub fn llalign_of_pref(cx: @CrateContext, t: TypeRef) -> uint { } } -// Returns the minimum alignment of a type required by the plattform. +// Returns the minimum alignment of a type required by the platform. // This is the alignment that will be used for struct fields, arrays, // and similar ABI-mandated things. pub fn llalign_of_min(cx: @CrateContext, t: TypeRef) -> uint { @@ -118,7 +118,7 @@ pub fn llalign_of(cx: @CrateContext, t: TypeRef) -> ValueRef { // Computes the size of the data part of an enum. pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint { if cx.enum_sizes.contains_key(&t) { - return *cx.enum_sizes.get(&t); + return cx.enum_sizes.get_copy(&t); } debug!("static_size_of_enum %s", ty_to_str(cx.tcx, t)); @@ -153,4 +153,3 @@ pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint { _ => cx.sess.bug(~"static_size_of_enum called on non-enum") } } - diff --git a/src/librustc/middle/trans/macros.rs b/src/librustc/middle/trans/macros.rs index 14ed7692661d4..43cc66c556867 100644 --- a/src/librustc/middle/trans/macros.rs +++ b/src/librustc/middle/trans/macros.rs @@ -51,4 +51,3 @@ macro_rules! trace( } ) ) - diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 90f9f93be2b48..02afbbdb11f7e 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -44,9 +44,14 @@ pub fn trans_impl(ccx: @CrateContext, path: path, name: ast::ident, methods: &[@ast::method], generics: &ast::Generics, self_ty: Option, id: ast::node_id) { let _icx = ccx.insn_ctxt("impl::trans_impl"); + let tcx = ccx.tcx; + + debug!("trans_impl(path=%s, name=%s, self_ty=%s, id=%?)", + path.repr(tcx), name.repr(tcx), self_ty.repr(tcx), id); + if !generics.ty_params.is_empty() { return; } let sub_path = vec::append_one(path, path_name(name)); - for vec::each(methods) |method| { + for methods.each |method| { if method.generics.ty_params.len() == 0u { let llfn = get_item_val(ccx, method.id); let path = vec::append_one(/*bad*/copy sub_path, @@ -169,14 +174,15 @@ pub fn trans_self_arg(bcx: block, pub fn trans_method_callee(bcx: block, callee_id: ast::node_id, - self: @ast::expr, + this: @ast::expr, mentry: typeck::method_map_entry) - -> Callee { + -> Callee { let _icx = bcx.insn_ctxt("impl::trans_method_callee"); let tcx = bcx.tcx(); - debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%s)", - callee_id, bcx.expr_to_str(self), + debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)", + callee_id, + bcx.expr_to_str(this), mentry.repr(bcx.tcx())); // Replace method_self with method_static here. @@ -197,7 +203,7 @@ pub fn trans_method_callee(bcx: block, } typeck::method_super(trait_id, method_index) => { // is the self type for this method call - let self_ty = node_id_type(bcx, self.id); + let self_ty = node_id_type(bcx, this.id); // is the ID of the implementation of // trait for type let impl_id = ty::get_impl_id(tcx, trait_id, self_ty); @@ -227,13 +233,13 @@ pub fn trans_method_callee(bcx: block, match origin { typeck::method_static(did) => { let callee_fn = callee::trans_fn_ref(bcx, did, callee_id); - let Result {bcx, val} = trans_self_arg(bcx, self, mentry); + let Result {bcx, val} = trans_self_arg(bcx, this, mentry); Callee { bcx: bcx, data: Method(MethodData { llfn: callee_fn.llfn, llself: val, - self_ty: node_id_type(bcx, self.id), + self_ty: node_id_type(bcx, this.id), self_mode: mentry.self_mode, }) } @@ -247,7 +253,7 @@ pub fn trans_method_callee(bcx: block, match bcx.fcx.param_substs { Some(substs) => { let vtbl = find_vtable(bcx.tcx(), substs, p, b); - trans_monomorphized_callee(bcx, callee_id, self, mentry, + trans_monomorphized_callee(bcx, callee_id, this, mentry, trait_id, off, vtbl) } // how to get rid of this? @@ -258,7 +264,7 @@ pub fn trans_method_callee(bcx: block, trans_trait_callee(bcx, callee_id, off, - self, + this, store, mentry.explicit_self) } @@ -307,7 +313,7 @@ pub fn trans_static_method_callee(bcx: block, }; let mname = if method_id.crate == ast::local_crate { - match *bcx.tcx().items.get(&method_id.node) { + match bcx.tcx().items.get_copy(&method_id.node) { ast_map::node_trait_method(trait_method, _, _) => { ast_util::trait_method_to_ty_method(trait_method).ident } @@ -324,7 +330,7 @@ pub fn trans_static_method_callee(bcx: block, name=%s", method_id, callee_id, *ccx.sess.str_of(mname)); let vtbls = resolve_vtables_in_fn_ctxt( - bcx.fcx, *ccx.maps.vtable_map.get(&callee_id)); + bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id)); match vtbls[bound_index] { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { @@ -362,7 +368,7 @@ pub fn method_from_methods(ms: &[@ast::method], name: ast::ident) pub fn method_with_name(ccx: @CrateContext, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { - match *ccx.tcx.items.get(&impl_id.node) { + match ccx.tcx.items.get_copy(&impl_id.node) { ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref ms), _ @@ -380,7 +386,7 @@ pub fn method_with_name_or_default(ccx: @CrateContext, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { - match *ccx.tcx.items.get(&impl_id.node) { + match ccx.tcx.items.get_copy(&impl_id.node) { ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref ms), _ }, _) => { @@ -637,14 +643,15 @@ pub fn trans_trait_callee_from_llval(bcx: block, val_str(bcx.ccx().tn, llpair)); let llvtable = Load(bcx, PointerCast(bcx, - GEPi(bcx, llpair, [0u, 0u]), + GEPi(bcx, llpair, + [0u, abi::trt_field_vtable]), T_ptr(T_ptr(T_vtable())))); // Load the box from the @Trait pair and GEP over the box header if // necessary: let mut llself; debug!("(translating trait callee) loading second index from pair"); - let llbox = Load(bcx, GEPi(bcx, llpair, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box])); // Munge `llself` appropriately for the type of `self` in the method. let self_mode; @@ -769,7 +776,7 @@ pub fn make_vtable(ccx: @CrateContext, ptrs: ~[ValueRef]) -> ValueRef { unsafe { let _icx = ccx.insn_ctxt("impl::make_vtable"); let tbl = C_struct(ptrs); - let vtable = ccx.sess.str_of((ccx.names)(~"vtable")); + let vtable = ccx.sess.str_of((ccx.names)("vtable")); let vt_gvar = do str::as_c_str(*vtable) |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf) }; @@ -845,27 +852,30 @@ pub fn trans_trait_cast(bcx: block, match store { ty::RegionTraitStore(_) | ty::BoxTraitStore => { - let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); - // Just store the pointer into the pair. + let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); + // Just store the pointer into the pair. (Region/borrowed + // and boxed trait objects are represented as pairs, and + // have no type descriptor field.) llboxdest = PointerCast(bcx, llboxdest, T_ptr(type_of(bcx.ccx(), v_ty))); bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); } ty::UniqTraitStore => { - // Translate the uniquely-owned value into the second element of - // the triple. (The first element is the vtable.) - let mut llvaldest = GEPi(bcx, lldest, [0, 1]); + // Translate the uniquely-owned value in the + // triple. (Unique trait objects are represented as + // triples.) + let mut llvaldest = GEPi(bcx, lldest, [0, abi::trt_field_box]); llvaldest = PointerCast(bcx, llvaldest, T_ptr(type_of(bcx.ccx(), v_ty))); bcx = expr::trans_into(bcx, val, SaveIn(llvaldest)); - // Get the type descriptor of the wrapped value and store it into - // the third element of the triple as well. + // Get the type descriptor of the wrapped value and store + // it in the triple as well. let tydesc = get_tydesc(bcx.ccx(), v_ty); glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc); - let lltydescdest = GEPi(bcx, lldest, [0, 2]); + let lltydescdest = GEPi(bcx, lldest, [0, abi::trt_field_tydesc]); Store(bcx, tydesc.tydesc, lltydescdest); } } @@ -875,7 +885,7 @@ pub fn trans_trait_cast(bcx: block, let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx.ccx(), orig); Store(bcx, vtable, PointerCast(bcx, - GEPi(bcx, lldest, [0u, 0u]), + GEPi(bcx, lldest, [0u, abi::trt_field_vtable]), T_ptr(val_ty(vtable)))); bcx diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 72ad6dde4f17d..3b0c03cdc991a 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -13,7 +13,7 @@ use driver::session; use lib::llvm::ValueRef; use middle::trans::base::{get_insn_ctxt}; use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint}; -use middle::trans::base::{trans_enum_variant, trans_struct_dtor}; +use middle::trans::base::{trans_enum_variant}; use middle::trans::base::{trans_fn, decl_internal_cdecl_fn}; use middle::trans::base::{get_item_val, no_self}; use middle::trans::base; @@ -35,7 +35,6 @@ use syntax::ast_map; use syntax::ast_map::path_name; use syntax::ast_util::local_def; use syntax::opt_vec; -use syntax::parse::token::special_idents; use syntax::abi::AbiSet; pub fn monomorphic_fn(ccx: @CrateContext, @@ -101,12 +100,14 @@ pub fn monomorphic_fn(ccx: @CrateContext, let tpt = ty::lookup_item_type(ccx.tcx, fn_id); let llitem_ty = tpt.ty; - let map_node = session::expect(ccx.sess, ccx.tcx.items.find(&fn_id.node), - || fmt!("While monomorphizing %?, couldn't find it in the item map \ - (may have attempted to monomorphize an item defined in a different \ - crate?)", fn_id)); + let map_node = session::expect( + ccx.sess, + ccx.tcx.items.find_copy(&fn_id.node), + || fmt!("While monomorphizing %?, couldn't find it in the item map \ + (may have attempted to monomorphize an item \ + defined in a different crate?)", fn_id)); // Get the path so that we can create a symbol - let (pt, name, span) = match *map_node { + let (pt, name, span) = match map_node { ast_map::node_item(i, pt) => (pt, i.ident, i.span), ast_map::node_variant(ref v, enm, pt) => (pt, (*v).node.name, enm.span), ast_map::node_method(m, _, pt) => (pt, m.ident, m.span), @@ -116,8 +117,6 @@ pub fn monomorphic_fn(ccx: @CrateContext, // Foreign externs don't have to be monomorphized. return (get_item_val(ccx, fn_id.node), true); } - ast_map::node_dtor(_, dtor, _, pt) => - (pt, special_idents::dtor, dtor.span), ast_map::node_trait_method(@ast::provided(m), _, pt) => { (pt, m.ident, m.span) } @@ -137,6 +136,9 @@ pub fn monomorphic_fn(ccx: @CrateContext, ast_map::node_local(*) => { ccx.tcx.sess.bug(~"Can't monomorphize a local") } + ast_map::node_callee_scope(*) => { + ccx.tcx.sess.bug(~"Can't monomorphize a callee-scope") + } ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span) }; @@ -163,13 +165,13 @@ pub fn monomorphic_fn(ccx: @CrateContext, // causing an infinite expansion. if depth > 30 { ccx.sess.span_fatal( - span, ~"overly deep expansion of inlined function"); + span, "overly deep expansion of inlined function"); } ccx.monomorphizing.insert(fn_id, depth + 1); let pt = vec::append(/*bad*/copy *pt, ~[path_name((ccx.names)( - copy *ccx.sess.str_of(name)))]); + *ccx.sess.str_of(name)))]); let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty); let mk_lldecl = || { @@ -185,7 +187,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, self_ty: impl_ty_opt }); - let lldecl = match *map_node { + let lldecl = match map_node { ast_map::node_item(i@@ast::item { node: ast::item_fn(ref decl, _, _, _, ref body), _ @@ -243,16 +245,6 @@ pub fn monomorphic_fn(ccx: @CrateContext, meth::trans_method(ccx, pt, mth, psubsts, None, d, impl_did); d } - ast_map::node_dtor(_, dtor, _, pt) => { - let parent_id = match ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx, - dtor.node.self_id)) { - Some(did) => did, - None => ccx.sess.span_bug(dtor.span, ~"Bad self ty in \ - dtor") - }; - trans_struct_dtor(ccx, /*bad*/copy *pt, &dtor.node.body, - dtor.node.id, psubsts, Some(hash_id), parent_id) - } ast_map::node_trait_method(@ast::provided(mth), _, pt) => { let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); @@ -279,6 +271,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, ast_map::node_trait_method(*) | ast_map::node_arg(*) | ast_map::node_block(*) | + ast_map::node_callee_scope(*) | ast_map::node_local(*) => { ccx.tcx.sess.bug(fmt!("Can't monomorphize a %?", map_node)) } @@ -355,14 +348,9 @@ pub fn make_mono_id(ccx: @CrateContext, 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.each |bound| { - match *bound { - ty::bound_trait(_) => { - v.push(meth::vtable_id(ccx, /*bad*/copy vts[i])); - i += 1; - } - _ => () - } + for type_param_def.bounds.trait_bounds.each |_bound| { + v.push(meth::vtable_id(ccx, /*bad*/copy vts[i])); + i += 1; } (*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 index 3ccef0dbc4aca..9bbf50397c35a 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -42,19 +42,19 @@ 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 = ctx { + 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); + traverse_public_mod(cx, ast::crate_node_id, crate_mod); + traverse_all_resources_and_impls(cx, crate_mod); } return @rmap; } -fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool { +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) => { @@ -68,23 +68,25 @@ fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool { return found_export; } -fn traverse_def_id(cx: &ctx, did: def_id) { +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: &ctx, mod_id: node_id, m: &_mod) { +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.each |item| { @@ -93,16 +95,21 @@ fn traverse_public_mod(cx: &ctx, mod_id: node_id, m: &_mod) { } } -fn traverse_public_item(cx: &ctx, item: @item) { - // FIXME #6021: naming rmap shouldn't be necessary - let rmap: &mut HashSet = cx.rmap; - if rmap.contains(&item.id) { return; } - rmap.insert(item.id); +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 = 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.each |item| { + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(item.id); } } @@ -119,23 +126,19 @@ fn traverse_public_item(cx: &ctx, item: @item) { m.generics.ty_params.len() > 0u || attr::find_inline_attr(m.attrs) != attr::ia_none { - cx.rmap.insert(m.id); + { + 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, ref generics) => { + item_struct(ref struct_def, _) => { for struct_def.ctor_id.each |&ctor_id| { + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(ctor_id); } - for struct_def.dtor.each |dtor| { - cx.rmap.insert(dtor.node.id); - if generics.ty_params.len() > 0u || - attr::find_inline_attr(dtor.node.attrs) != attr::ia_none - { - traverse_inline_body(cx, &dtor.node.body); - } - } } item_ty(t, _) => { traverse_ty(t, cx, @@ -148,11 +151,12 @@ fn traverse_public_item(cx: &ctx, item: @item) { } } -fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) { - // FIXME #6021: naming rmap shouldn't be necessary - let rmap: &mut HashSet = cx.rmap; - if rmap.contains(&ty.id) { return; } - rmap.insert(ty.id); +fn traverse_ty<'a>(ty: @Ty, cx: @mut ctx<'a>, v: 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, p_id) => { @@ -171,18 +175,20 @@ fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) { } } -fn traverse_inline_body(cx: &ctx, body: &blk) { - fn traverse_expr<'a, 'b>(e: @expr, cx: &'b ctx<'a>, - v: visit::vt<&'b ctx<'a>>) { +fn traverse_inline_body(cx: @mut ctx, body: &blk) { + fn traverse_expr<'a>(e: @expr, cx: @mut ctx<'a>, + v: 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)); + 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()))) + 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_field(_, _, _) => { @@ -218,7 +224,7 @@ fn traverse_inline_body(cx: &ctx, body: &blk) { // 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: &ctx, _v: visit::vt<&ctx>) { + fn traverse_item(i: @item, cx: @mut ctx, _v: visit::vt<@mut ctx>) { traverse_public_item(cx, i); } visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor { @@ -228,7 +234,7 @@ fn traverse_inline_body(cx: &ctx, body: &blk) { })); } -fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { +fn traverse_all_resources_and_impls(cx: @mut ctx, crate_mod: &_mod) { visit::visit_mod( crate_mod, codemap::dummy_sp(), @@ -239,9 +245,6 @@ fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { visit_item: |i, cx, v| { visit::visit_item(i, cx, v); match i.node { - item_struct(sdef, _) if sdef.dtor.is_some() => { - traverse_public_item(cx, i); - } item_impl(*) => { traverse_public_item(cx, i); } @@ -251,4 +254,3 @@ fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { ..*visit::default_visitor() })); } - diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 7e59f580a2c3c..2183472d59154 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -114,7 +114,7 @@ pub impl Reflector { ArgVals(args), SaveIn(scratch.val), DontAutorefArg); let result = scratch.to_value_llval(bcx); let result = bool_to_i1(bcx, result); - let next_bcx = sub_block(bcx, ~"next"); + let next_bcx = sub_block(bcx, "next"); CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb); self.bcx = next_bcx } @@ -274,15 +274,16 @@ pub impl Reflector { let repr = adt::represent_type(bcx.ccx(), t); let variants = ty::substd_enum_variants(ccx.tcx, did, substs); let llptrty = T_ptr(type_of(ccx, t)); - let (_, opaquety) = *(ccx.tcx.intrinsic_defs.find(&ccx.sess.ident_of(~"Opaque")) - .expect("Failed to resolve intrinsic::Opaque")); + let (_, opaquety) = + ccx.tcx.intrinsic_defs.find_copy(&ccx.sess.ident_of("Opaque")) + .expect("Failed to resolve intrinsic::Opaque"); let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm }); let make_get_disr = || { let sub_path = bcx.fcx.path + ~[path_name(special_idents::anon)]; let sym = mangle_internal_name_by_path_and_seq(ccx, sub_path, - ~"get_disr"); + "get_disr"); let args = [ ty::arg { ty: opaqueptrty @@ -372,9 +373,9 @@ pub fn emit_calls_to_trait_visit_ty(bcx: block, visitor_trait_id: def_id) -> block { use syntax::parse::token::special_idents::tydesc; - let final = sub_block(bcx, ~"final"); + let final = sub_block(bcx, "final"); assert!(bcx.ccx().tcx.intrinsic_defs.contains_key(&tydesc)); - let (_, tydesc_ty) = *bcx.ccx().tcx.intrinsic_defs.get(&tydesc); + let (_, tydesc_ty) = bcx.ccx().tcx.intrinsic_defs.get_copy(&tydesc); let tydesc_ty = type_of(bcx.ccx(), tydesc_ty); let mut r = Reflector { visitor_val: visitor_val, @@ -404,4 +405,3 @@ pub fn ast_purity_constant(purity: ast::purity) -> uint { ast::extern_fn => 3u } } - diff --git a/src/librustc/middle/trans/shape.rs b/src/librustc/middle/trans/shape.rs index 08337c918b0f5..6ff9e1cfc5717 100644 --- a/src/librustc/middle/trans/shape.rs +++ b/src/librustc/middle/trans/shape.rs @@ -74,4 +74,3 @@ pub fn add_substr(dest: &mut ~[u8], src: ~[u8]) { add_u16(&mut *dest, vec::len(src) as u16); *dest += src; } - diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 30a7648e7eafb..7a85e93584e25 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -28,7 +28,6 @@ use util::common::indenter; use util::ppaux::ty_to_str; use core::option::None; -use core::vec; use syntax::ast; use syntax::codemap; @@ -395,7 +394,7 @@ pub fn write_content(bcx: block, add_clean_temp_mem(bcx, lleltptr, vt.unit_ty); temp_cleanups.push(lleltptr); } - for vec::each(temp_cleanups) |cleanup| { + for temp_cleanups.each |cleanup| { revoke_clean(bcx, *cleanup); } } @@ -422,11 +421,11 @@ pub fn write_content(bcx: block, expr::trans_to_datum(bcx, element) }); - let next_bcx = sub_block(bcx, ~"expr_repeat: while next"); - let loop_bcx = loop_scope_block(bcx, next_bcx, None, ~"expr_repeat", None); - let cond_bcx = scope_block(loop_bcx, None, ~"expr_repeat: loop cond"); - let set_bcx = scope_block(loop_bcx, None, ~"expr_repeat: body: set"); - let inc_bcx = scope_block(loop_bcx, None, ~"expr_repeat: body: inc"); + let next_bcx = sub_block(bcx, "expr_repeat: while next"); + let loop_bcx = loop_scope_block(bcx, next_bcx, None, "expr_repeat", None); + let cond_bcx = scope_block(loop_bcx, None, "expr_repeat: loop cond"); + let set_bcx = scope_block(loop_bcx, None, "expr_repeat: body: set"); + let inc_bcx = scope_block(loop_bcx, None, "expr_repeat: body: inc"); Br(bcx, loop_bcx.llbb); let loop_counter = { @@ -469,7 +468,7 @@ pub fn write_content(bcx: block, } _ => { bcx.tcx().sess.span_bug(content_expr.span, - ~"Unexpected evec content"); + "Unexpected evec content"); } } } @@ -503,7 +502,7 @@ pub fn elements_required(bcx: block, content_expr: @ast::expr) -> uint { ty::eval_repeat_count(bcx.tcx(), count_expr) } _ => bcx.tcx().sess.span_bug(content_expr.span, - ~"Unexpected evec content") + "Unexpected evec content") } } @@ -562,14 +561,14 @@ pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t, let data_end_ptr = pointer_add(bcx, data_ptr, fill); // Now perform the iteration. - let header_bcx = base::sub_block(bcx, ~"iter_vec_loop_header"); + let header_bcx = base::sub_block(bcx, "iter_vec_loop_header"); Br(bcx, header_bcx.llbb); let data_ptr = Phi(header_bcx, val_ty(data_ptr), ~[data_ptr], ~[bcx.llbb]); let not_yet_at_end = ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr); - let body_bcx = base::sub_block(header_bcx, ~"iter_vec_loop_body"); - let next_bcx = base::sub_block(header_bcx, ~"iter_vec_next"); + let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body"); + let next_bcx = base::sub_block(header_bcx, "iter_vec_next"); CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb); let body_bcx = f(body_bcx, data_ptr, unit_ty); AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, @@ -594,13 +593,3 @@ pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t, let dataptr = get_dataptr(bcx, body_ptr); return iter_vec_raw(bcx, dataptr, vec_ty, fill, f); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index a842f91f0ed6e..b8e0b58f86634 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -110,8 +110,7 @@ pub fn type_of_non_gc_box(cx: @CrateContext, t: ty::t) -> TypeRef { pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { match cx.llsizingtypes.find(&t) { - // FIXME(#5562): removing this copy causes a segfault in stage1 core - Some(t) => return /*bad*/ copy *t, + Some(t) => return *t, None => () } @@ -156,9 +155,15 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { } ty::ty_struct(did, _) => { - let repr = adt::represent_type(cx, t); - let packed = ty::lookup_packed(cx.tcx, did); - T_struct(adt::sizing_fields_of(cx, repr), packed) + if ty::type_is_simd(cx.tcx, t) { + let et = ty::simd_type(cx.tcx, t); + let n = ty::simd_size(cx.tcx, t); + T_vector(type_of(cx, et), n) + } else { + let repr = adt::represent_type(cx, t); + let packed = ty::lookup_packed(cx.tcx, did); + T_struct(adt::sizing_fields_of(cx, repr), packed) + } } ty::ty_self(_) | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { @@ -178,8 +183,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { // Check the cache. match cx.lltypes.find(&t) { - // FIXME(#5562): removing this copy causes a segfault in stage1 core - Some(t) => return /*bad*/ copy *t, + Some(&t) => return t, None => () } @@ -265,14 +269,19 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { } ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx), ty::ty_struct(did, ref substs) => { - // Only create the named struct, but don't fill it in. We fill it - // in *after* placing it into the type cache. This prevents - // infinite recursion with recursive struct types. - - common::T_named_struct(llvm_type_name(cx, - a_struct, - did, - /*bad*/ copy substs.tps)) + if ty::type_is_simd(cx.tcx, t) { + let et = ty::simd_type(cx.tcx, t); + let n = ty::simd_size(cx.tcx, t); + T_vector(type_of(cx, et), n) + } else { + // Only create the named struct, but don't fill it in. We fill it + // in *after* placing it into the type cache. This prevents + // infinite recursion with recursive struct types. + T_named_struct(llvm_type_name(cx, + a_struct, + did, + /*bad*/ copy substs.tps)) + } } ty::ty_self(*) => cx.tcx.sess.unimpl(~"type_of: ty_self"), ty::ty_infer(*) => cx.tcx.sess.bug(~"type_of with ty_infer"), @@ -291,10 +300,12 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { } ty::ty_struct(did, _) => { - let repr = adt::represent_type(cx, t); - let packed = ty::lookup_packed(cx.tcx, did); - common::set_struct_body(llty, adt::fields_of(cx, repr), - packed); + if !ty::type_is_simd(cx.tcx, t) { + let repr = adt::represent_type(cx, t); + let packed = ty::lookup_packed(cx.tcx, did); + common::set_struct_body(llty, adt::fields_of(cx, repr), + packed); + } } _ => () } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 33145dd4334a5..0627272a1341c 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -77,7 +77,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint) match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty { ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) | ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => { - for vec::each(sig.inputs) |arg| { + for sig.inputs.each |arg| { type_needs(cx, use_repr, arg.ty); } } @@ -118,13 +118,15 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint) if abi.is_intrinsic() { let flags = match *cx.ccx.sess.str_of(i.ident) { ~"size_of" | ~"pref_align_of" | ~"min_align_of" | - ~"init" | ~"transmute" | ~"move_val" | + ~"uninit" | ~"init" | ~"transmute" | ~"move_val" | ~"move_val_init" => use_repr, ~"get_tydesc" | ~"needs_drop" => use_tydesc, ~"atomic_cxchg" | ~"atomic_cxchg_acq"| - ~"atomic_cxchg_rel"| ~"atomic_xchg" | + ~"atomic_cxchg_rel"| ~"atomic_load" | + ~"atomic_load_acq" | ~"atomic_store" | + ~"atomic_store_rel"| ~"atomic_xchg" | ~"atomic_xadd" | ~"atomic_xsub" | ~"atomic_xchg_acq" | ~"atomic_xadd_acq" | ~"atomic_xsub_acq" | ~"atomic_xchg_rel" | @@ -157,9 +159,6 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint) for uint::range(0u, n_tps) |n| { cx.uses[n] |= flags;} } } - ast_map::node_dtor(_, ref dtor, _, _) => { - handle_body(cx, &dtor.node.body); - } ast_map::node_struct_ctor(*) => { // Similarly to node_variant, this monomorphized function just uses // the representations of all of its type parameters. @@ -216,7 +215,7 @@ pub fn type_needs_inner(cx: Context, if list::find(enums_seen, |id| *id == did).is_none() { let seen = @Cons(did, enums_seen); for vec::each(*ty::enum_variants(cx.ccx.tcx, did)) |v| { - for vec::each(v.args) |aty| { + for v.args.each |aty| { let t = ty::subst(cx.ccx.tcx, &(*substs), *aty); type_needs_inner(cx, use_, t, seen); } @@ -239,18 +238,11 @@ pub fn node_type_needs(cx: Context, use_: uint, id: node_id) { } pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { + let mut opt_static_did = None; for cx.ccx.maps.method_map.find(&e_id).each |mth| { match mth.origin { typeck::method_static(did) => { - for cx.ccx.tcx.node_type_substs.find(&callee_id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let ts = /*bad*/ copy **ts; - let type_uses = type_uses_for(cx.ccx, did, ts.len()); - for vec::each2(*type_uses, ts) |uses, subst| { - type_needs(cx, *uses, *subst) - } - } + opt_static_did = Some(did); } typeck::method_param(typeck::method_param { param_num: param, @@ -262,6 +254,19 @@ pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { | typeck::method_super(*) => (), } } + + // Note: we do not execute this code from within the each() call + // above because the recursive call to `type_needs` can trigger + // inlining and hence can cause `method_map` and + // `node_type_substs` to be modified. + for opt_static_did.each |&did| { + for cx.ccx.tcx.node_type_substs.find_copy(&callee_id).each |ts| { + let type_uses = type_uses_for(cx.ccx, did, ts.len()); + for vec::each2(*type_uses, *ts) |uses, subst| { + type_needs(cx, *uses, *subst) + } + } + } } pub fn mark_for_expr(cx: Context, e: @expr) { @@ -290,13 +295,12 @@ pub fn mark_for_expr(cx: Context, e: @expr) { _ => () } } - expr_path(_) => { - for cx.ccx.tcx.node_type_substs.find(&e.id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = copy **ts; - let id = ast_util::def_id_of_def(*cx.ccx.tcx.def_map.get(&e.id)); + expr_path(_) | expr_self => { + let opt_ts = cx.ccx.tcx.node_type_substs.find_copy(&e.id); + for opt_ts.each |ts| { + let id = ast_util::def_id_of_def(cx.ccx.tcx.def_map.get_copy(&e.id)); let uses_for_ts = type_uses_for(cx.ccx, id, ts.len()); - for vec::each2(*uses_for_ts, ts) |uses, subst| { + for vec::each2(*uses_for_ts, *ts) |uses, subst| { type_needs(cx, *uses, *subst) } } @@ -312,7 +316,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) { } } } - expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) | + expr_assign(val, _) | expr_assign_op(_, val, _) | expr_ret(Some(val)) => { node_type_needs(cx, use_repr, val.id); } @@ -386,4 +390,3 @@ pub fn handle_body(cx: Context, body: &blk) { }); (v.visit_block)(body, cx, v); } - diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs new file mode 100644 index 0000000000000..18f21b489b0b8 --- /dev/null +++ b/src/librustc/middle/trans/write_guard.rs @@ -0,0 +1,201 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Logic relating to rooting and write guards for managed values +//! (`@` and `@mut`). This code is primarily for use by datum; +//! it exists in its own module both to keep datum.rs bite-sized +//! and for each in debugging (e.g., so you can use +//! `RUST_LOG=rustc::middle::trans::write_guard`). + +use lib::llvm::ValueRef; +use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut}; +use middle::trans::base::*; +use middle::trans::build::*; +use middle::trans::callee; +use middle::trans::common::*; +use middle::trans::datum::*; +use middle::trans::expr; +use middle::ty; +use driver::session; +use syntax::codemap::span; +use syntax::ast; + +pub fn root_and_write_guard(datum: &Datum, + mut bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) -> block { + let key = root_map_key { id: expr_id, derefs: derefs }; + debug!("write_guard::root_and_write_guard(key=%?)", key); + + // root the autoderef'd value, if necessary: + // + // (Note: root'd values are always boxes) + let ccx = bcx.ccx(); + bcx = match ccx.maps.root_map.find(&key) { + None => bcx, + Some(&root_info) => root(datum, bcx, span, key, root_info) + }; + + // Perform the write guard, if necessary. + // + // (Note: write-guarded values are always boxes) + if ccx.maps.write_guard_map.contains(&key) { + perform_write_guard(datum, bcx, span) + } else { + bcx + } +} + +pub fn return_to_mut(mut bcx: block, + root_key: root_map_key, + frozen_val_ref: ValueRef, + bits_val_ref: ValueRef, + filename_val: ValueRef, + line_val: ValueRef) -> block { + debug!("write_guard::return_to_mut(root_key=%?, %s, %s, %s)", + root_key, + bcx.to_str(), + val_str(bcx.ccx().tn, frozen_val_ref), + val_str(bcx.ccx().tn, bits_val_ref)); + + let box_ptr = + Load(bcx, PointerCast(bcx, + frozen_val_ref, + T_ptr(T_ptr(T_i8())))); + + let bits_val = + Load(bcx, bits_val_ref); + + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.unrecord_borrow_fn(), + ~[ + box_ptr, + bits_val, + filename_val, + line_val + ], + expr::Ignore); + } + + callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.return_to_mut_fn(), + ~[ + box_ptr, + bits_val, + filename_val, + line_val + ], + expr::Ignore + ) +} + +fn root(datum: &Datum, + mut bcx: block, + span: span, + root_key: root_map_key, + root_info: RootInfo) -> block { + //! In some cases, borrowck will decide that an @T/@[]/@str + //! value must be rooted for the program to be safe. In that + //! case, we will call this function, which will stash a copy + //! away until we exit the scope `scope_id`. + + debug!("write_guard::root(root_key=%?, root_info=%?, datum=%?)", + root_key, root_info, datum.to_str(bcx.ccx())); + + if bcx.sess().trace() { + trans_trace( + bcx, None, + @fmt!("preserving until end of scope %d", + root_info.scope)); + } + + // First, root the datum. Note that we must zero this value, + // because sometimes we root on one path but not another. + // See e.g. #4904. + let scratch = scratch_datum(bcx, datum.ty, true); + datum.copy_to_datum(bcx, INIT, scratch); + let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); + add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty); + + // Now, consider also freezing it. + match root_info.freeze { + None => {} + Some(freeze_kind) => { + let (filename, line) = filename_and_line_num_from_span(bcx, span); + + // in this case, we don't have to zero, because + // scratch.val will be NULL should the cleanup get + // called without the freezing actually occurring, and + // return_to_mut checks for this condition. + let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); + + let freeze_did = match freeze_kind { + DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), + DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), + }; + + let box_ptr = Load(bcx, + PointerCast(bcx, + scratch.val, + T_ptr(T_ptr(T_i8())))); + + bcx = callee::trans_lang_call( + bcx, + freeze_did, + ~[ + box_ptr, + filename, + line + ], + expr::SaveIn(scratch_bits.val)); + + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.record_borrow_fn(), + ~[ + box_ptr, + Load(bcx, scratch_bits.val), + filename, + line + ], + expr::Ignore); + } + + add_clean_return_to_mut( + cleanup_bcx, root_key, scratch.val, scratch_bits.val, + filename, line); + } + } + + bcx +} + +fn perform_write_guard(datum: &Datum, + bcx: block, + span: span) -> block { + debug!("perform_write_guard"); + + let llval = datum.to_value_llval(bcx); + let (filename, line) = filename_and_line_num_from_span(bcx, span); + + callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.check_not_borrowed_fn(), + ~[PointerCast(bcx, llval, T_ptr(T_i8())), + filename, + line], + expr::Ignore) +} + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c7fb1e94adf4c..5eaa6478ecfb6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -26,14 +26,16 @@ use util::ppaux::{note_and_explain_region, bound_region_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str}; use util::ppaux::Repr; use util::common::{indenter}; +use util::enum_set::{EnumSet, CLike}; -use core; +#[cfg(stage0)] +use core; // NOTE: this can be removed after the next snapshot use core::ptr::to_unsafe_ptr; use core::to_bytes; use core::hashmap::{HashMap, HashSet}; use std::smallintmap::SmallIntMap; use syntax::ast::*; -use syntax::ast_util::{is_local, local_def}; +use syntax::ast_util::is_local; use syntax::ast_util; use syntax::attr; use syntax::codemap::span; @@ -58,8 +60,6 @@ pub struct field { mt: mt } -pub type param_bounds = @~[param_bound]; - pub struct method { ident: ast::ident, generics: ty::Generics, @@ -106,10 +106,9 @@ pub enum SelfMode { } pub struct field_ty { - ident: ident, - id: def_id, - vis: ast::visibility, - mutability: ast::struct_mutability, + ident: ident, + id: def_id, + vis: ast::visibility, } // Contains information needed to resolve types and (in the future) look up @@ -123,11 +122,18 @@ pub struct creader_cache_key { type creader_cache = @mut HashMap; +#[cfg(stage0)] impl to_bytes::IterBytes for creader_cache_key { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for creader_cache_key { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f) + } +} struct intern_key { sty: *sty, @@ -147,6 +153,7 @@ impl cmp::Eq for intern_key { } } +#[cfg(stage0)] impl to_bytes::IterBytes for intern_key { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { unsafe { @@ -154,6 +161,14 @@ impl to_bytes::IterBytes for intern_key { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for intern_key { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + unsafe { + (*self.sty).iter_bytes(lsb0, f) + } + } +} pub enum ast_ty_to_ty_cache_entry { atttce_unresolved, /* not resolved yet */ @@ -183,26 +198,21 @@ pub struct AutoDerefRef { #[auto_encode] #[auto_decode] -pub struct AutoRef { - kind: AutoRefKind, - region: Region, - mutbl: ast::mutability -} - -#[auto_encode] -#[auto_decode] -pub enum AutoRefKind { +pub enum AutoRef { /// Convert from T to &T - AutoPtr, + AutoPtr(Region, ast::mutability), /// Convert from @[]/~[]/&[] to &[] (or str) - AutoBorrowVec, + AutoBorrowVec(Region, ast::mutability), /// Convert from @[]/~[]/&[] to &&[] (or str) - AutoBorrowVecRef, + AutoBorrowVecRef(Region, ast::mutability), /// Convert from @fn()/~fn()/&fn() to &fn() - AutoBorrowFn + AutoBorrowFn(Region), + + /// Convert from T to *T + AutoUnsafe(ast::mutability) } // Stores information about provided methods (a.k.a. default methods) in @@ -389,18 +399,33 @@ pub struct FnSig { output: t } +#[cfg(stage0)] impl to_bytes::IterBytes for BareFnTy { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.purity, &self.abis, &self.sig, lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for BareFnTy { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_3(&self.purity, &self.abis, &self.sig, lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for ClosureTy { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_5(&self.purity, &self.sigil, &self.onceness, &self.region, &self.sig, lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for ClosureTy { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_5(&self.purity, &self.sigil, &self.onceness, + &self.region, &self.sig, lsb0, f) + } +} #[deriving(Eq, IterBytes)] pub struct param_ty { @@ -432,11 +457,20 @@ pub enum Region { /// A concrete region naming some expression within the current function. re_scope(node_id), - /// Static data that has an "infinite" lifetime. + /// Static data that has an "infinite" lifetime. Top in the region lattice. re_static, /// A region variable. Should not exist after typeck. - re_infer(InferRegion) + re_infer(InferRegion), + + /// Empty lifetime is for data that is never accessed. + /// Bottom in the region lattice. We treat re_empty somewhat + /// specially; at least right now, we do not generate instances of + /// it during the GLB computations, but rather + /// generate an error instead. This is to improve error messages. + /// The only way to get an instance of re_empty is to have a region + /// variable with no constraints. + re_empty, } pub impl Region { @@ -652,12 +686,32 @@ pub enum type_err { } #[deriving(Eq, IterBytes)] -pub enum param_bound { - bound_copy, - bound_durable, - bound_owned, - bound_const, - bound_trait(@TraitRef), +pub struct ParamBounds { + builtin_bounds: BuiltinBounds, + trait_bounds: ~[@TraitRef] +} + +pub type BuiltinBounds = EnumSet; + +#[deriving(Eq, IterBytes)] +pub enum BuiltinBound { + BoundCopy, + BoundStatic, + BoundOwned, + BoundConst, +} + +pub fn EmptyBuiltinBounds() -> BuiltinBounds { + EnumSet::empty() +} + +impl CLike for BuiltinBound { + pub fn to_uint(&self) -> uint { + *self as uint + } + pub fn from_uint(v: uint) -> BuiltinBound { + unsafe { cast::transmute(v) } + } } #[deriving(Eq)] @@ -683,6 +737,7 @@ pub enum InferTy { FloatVar(FloatVid) } +#[cfg(stage0)] impl to_bytes::IterBytes for InferTy { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -692,6 +747,16 @@ impl to_bytes::IterBytes for InferTy { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for InferTy { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + match *self { + TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f), + IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f), + FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f), + } + } +} #[auto_encode] #[auto_decode] @@ -700,6 +765,7 @@ pub enum InferRegion { ReSkolemized(uint, bound_region) } +#[cfg(stage0)] impl to_bytes::IterBytes for InferRegion { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -708,6 +774,15 @@ impl to_bytes::IterBytes for InferRegion { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for InferRegion { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + match *self { + ReVar(ref rv) => to_bytes::iter_bytes_2(&0u8, rv, lsb0, f), + ReSkolemized(ref v, _) => to_bytes::iter_bytes_2(&1u8, v, lsb0, f) + } + } +} impl cmp::Eq for InferRegion { fn eq(&self, other: &InferRegion) -> bool { @@ -788,33 +863,61 @@ impl ToStr for IntVarValue { } } +#[cfg(stage0)] impl to_bytes::IterBytes for TyVid { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_uint().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for TyVid { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.to_uint().iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for IntVid { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_uint().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for IntVid { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.to_uint().iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for FloatVid { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_uint().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for FloatVid { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.to_uint().iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for RegionVid { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_uint().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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: param_bounds + bounds: @ParamBounds } /// Information about the type/lifetime parametesr associated with an item. @@ -1253,16 +1356,6 @@ pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t { pub fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) } -// Converts s to its machine type equivalent -pub fn mach_sty(cfg: @session::config, t: t) -> sty { - match get(t).sty { - ty_int(ast::ty_i) => ty_int(cfg.int_type), - ty_uint(ast::ty_u) => ty_uint(cfg.uint_type), - ty_float(ast::ty_f) => ty_float(cfg.float_type), - ref s => (/*bad*/copy *s) - } -} - pub fn walk_ty(ty: t, f: &fn(t)) { maybe_walk_ty(ty, |t| { f(t); true }); } @@ -1504,14 +1597,6 @@ pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str { substs.repr(cx) } -pub fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { - pb.repr(cx) -} - -pub fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str { - pbs.repr(cx) -} - pub fn subst(cx: ctxt, substs: &substs, typ: t) @@ -1549,6 +1634,13 @@ pub fn type_is_ty_var(ty: t) -> bool { pub fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool } +pub fn type_is_self(ty: t) -> bool { + match get(ty).sty { + ty_self(*) => true, + _ => false + } +} + pub fn type_is_structural(ty: t) -> bool { match get(ty).sty { ty_struct(*) | ty_tup(_) | ty_enum(*) | ty_closure(_) | ty_trait(*) | @@ -1566,6 +1658,13 @@ pub fn type_is_sequence(ty: t) -> bool { } } +pub fn type_is_simd(cx: ctxt, ty: t) -> bool { + match get(ty).sty { + ty_struct(did, _) => lookup_simd(cx, did), + _ => false + } +} + pub fn type_is_str(ty: t) -> bool { match get(ty).sty { ty_estr(_) => true, @@ -1582,6 +1681,26 @@ pub fn sequence_element_type(cx: ctxt, ty: t) -> t { } } +pub fn simd_type(cx: ctxt, ty: t) -> t { + match get(ty).sty { + ty_struct(did, ref substs) => { + let fields = lookup_struct_fields(cx, did); + lookup_field_type(cx, did, fields[0].id, substs) + } + _ => fail!(~"simd_type called on invalid type") + } +} + +pub fn simd_size(cx: ctxt, ty: t) -> uint { + match get(ty).sty { + ty_struct(did, _) => { + let fields = lookup_struct_fields(cx, did); + fields.len() + } + _ => fail!(~"simd_size called on invalid type") + } +} + pub fn get_element_type(ty: t, i: uint) -> t { match get(ty).sty { ty_tup(ref ts) => return ts[i], @@ -1713,7 +1832,7 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, true } ty_enum(did, ref substs) => { - for vec::each(*enum_variants(cx, did)) |v| { + for (*enum_variants(cx, did)).each |v| { for v.args.each |aty| { let t = subst(cx, substs, *aty); needs_unwind_cleanup |= @@ -1768,6 +1887,19 @@ pub struct TypeContents { } pub impl TypeContents { + fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool { + iter::all(|bb| self.meets_bound(cx, bb), |f| bbs.each(f)) + } + + fn meets_bound(&self, cx: ctxt, bb: BuiltinBound) -> bool { + match bb { + BoundCopy => self.is_copy(cx), + BoundStatic => self.is_static(cx), + BoundConst => self.is_const(cx), + BoundOwned => self.is_owned(cx) + } + } + fn intersects(&self, tc: TypeContents) -> bool { (self.bits & tc.bits) != 0 } @@ -1781,11 +1913,11 @@ pub impl TypeContents { TC_EMPTY_ENUM } - fn is_durable(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nondurable(cx)) + fn is_static(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonstatic(cx)) } - fn nondurable(_cx: ctxt) -> TypeContents { + fn nonstatic(_cx: ctxt) -> TypeContents { TC_BORROWED_POINTER } @@ -1794,7 +1926,7 @@ pub impl TypeContents { } fn nonowned(_cx: ctxt) -> TypeContents { - TC_MANAGED + TC_BORROWED_POINTER + TC_MANAGED + TC_BORROWED_POINTER + TC_NON_OWNED } fn contains_managed(&self) -> bool { @@ -1818,15 +1950,6 @@ pub impl TypeContents { if cx.vecs_implicitly_copyable {base} else {base + TC_OWNED_VEC} } - fn is_safe_for_default_mode(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nondefault_mode(cx)) - } - - fn nondefault_mode(cx: ctxt) -> TypeContents { - let tc = TypeContents::nonimplicitly_copyable(cx); - tc + TC_BIG + TC_OWNED_VEC // disregard cx.vecs_implicitly_copyable - } - fn needs_drop(&self, cx: ctxt) -> bool { let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx); self.intersects(tc) @@ -1857,50 +1980,50 @@ impl ToStr for TypeContents { } /// Constant for a type containing nothing of interest. -static TC_NONE: TypeContents = TypeContents{bits:0b0000_00000000}; +static TC_NONE: TypeContents = TypeContents{bits: 0b0000_0000_0000}; /// Contains a borrowed value with a lifetime other than static -static TC_BORROWED_POINTER: TypeContents = TypeContents{bits:0b0000_00000001}; +static TC_BORROWED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0001}; /// Contains an owned pointer (~T) but not slice of some kind -static TC_OWNED_POINTER: TypeContents = TypeContents{bits:0b000000000010}; +static TC_OWNED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0010}; /// Contains an owned vector ~[] or owned string ~str -static TC_OWNED_VEC: TypeContents = TypeContents{bits:0b000000000100}; +static TC_OWNED_VEC: TypeContents = TypeContents{bits: 0b0000_0000_0100}; /// Contains a ~fn() or a ~Trait, which is non-copyable. -static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits:0b000000001000}; +static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits: 0b0000_0000_1000}; /// Type with a destructor -static TC_DTOR: TypeContents = TypeContents{bits:0b000000010000}; +static TC_DTOR: TypeContents = TypeContents{bits: 0b0000_0001_0000}; /// Contains a managed value -static TC_MANAGED: TypeContents = TypeContents{bits:0b000000100000}; +static TC_MANAGED: TypeContents = TypeContents{bits: 0b0000_0010_0000}; /// &mut with any region -static TC_BORROWED_MUT: TypeContents = TypeContents{bits:0b000001000000}; +static TC_BORROWED_MUT: TypeContents = TypeContents{bits: 0b0000_0100_0000}; /// Mutable content, whether owned or by ref -static TC_MUTABLE: TypeContents = TypeContents{bits:0b000010000000}; +static TC_MUTABLE: TypeContents = TypeContents{bits: 0b0000_1000_0000}; -/// Mutable content, whether owned or by ref -static TC_ONCE_CLOSURE: TypeContents = TypeContents{bits:0b000100000000}; - -/// Something we estimate to be "big" -static TC_BIG: TypeContents = TypeContents{bits:0b001000000000}; +/// One-shot closure +static TC_ONCE_CLOSURE: TypeContents = TypeContents{bits: 0b0001_0000_0000}; /// An enum with no variants. -static TC_EMPTY_ENUM: TypeContents = TypeContents{bits:0b010000000000}; +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}; /// All possible contents. -static TC_ALL: TypeContents = TypeContents{bits:0b011111111111}; +static TC_ALL: TypeContents = TypeContents{bits: 0b0111_1111_1111}; pub fn type_is_copyable(cx: ctxt, t: ty::t) -> bool { type_contents(cx, t).is_copy(cx) } -pub fn type_is_durable(cx: ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_durable(cx) +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 { @@ -1961,7 +2084,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { let _i = indenter(); - let mut result = match get(ty).sty { + let result = match get(ty).sty { // Scalar and unique types are sendable, constant, and owned ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty_ptr(_) => { @@ -2035,14 +2158,13 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ty_struct(did, ref substs) => { let flds = struct_fields(cx, did, substs); - let flds_tc = flds.foldl( + let mut res = flds.foldl( TC_NONE, |tc, f| tc + tc_mt(cx, f.mt, cache)); if ty::has_dtor(cx, did) { - flds_tc + TC_DTOR - } else { - flds_tc + res += TC_DTOR; } + apply_tc_attr(cx, did, res) } ty_tup(ref tys) => { @@ -2051,7 +2173,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ty_enum(did, ref substs) => { let variants = substd_enum_variants(cx, did, substs); - if variants.is_empty() { + let res = if variants.is_empty() { // we somewhat arbitrary declare that empty enums // are non-copyable TC_EMPTY_ENUM @@ -2061,7 +2183,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { *tc, |tc, arg_ty| *tc + tc_ty(cx, *arg_ty, cache)) }) - } + }; + apply_tc_attr(cx, did, res) } ty_param(p) => { @@ -2109,10 +2232,6 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } }; - if type_size(cx, ty) > 4 { - result = result + TC_BIG; - } - cache.insert(ty_id, result); return result; } @@ -2125,6 +2244,16 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { mc + tc_ty(cx, mt.ty, cache) } + 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, "non_owned") { + tc += TC_NON_OWNED; + } + tc + } + fn borrowed_contents(region: ty::Region, mutbl: ast::mutability) -> TypeContents { @@ -2174,81 +2303,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx)); let _i = indenter(); - let r = type_param_def.bounds.foldl(TC_ALL, |tc, bound| { + let mut tc = TC_ALL; + for type_param_def.bounds.builtin_bounds.each |bound| { debug!("tc = %s, bound = %?", tc.to_str(), bound); - match *bound { - bound_copy => tc - TypeContents::nonimplicitly_copyable(cx), - bound_durable => tc - TypeContents::nondurable(cx), - bound_owned => tc - TypeContents::nonowned(cx), - bound_const => tc - TypeContents::nonconst(cx), - bound_trait(_) => *tc - } - }); - - debug!("result = %s", r.to_str()); - return r; - } - - /// gives a rough estimate of how much space it takes to represent - /// an instance of `ty`. Used for the mode transition. - fn type_size(cx: ctxt, ty: t) -> uint { - match get(ty).sty { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) | - ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) | - ty_evec(_, vstore_box) | ty_estr(vstore_box) => { - 1 - } - - ty_evec(_, vstore_slice(_)) | - ty_estr(vstore_slice(_)) | - ty_bare_fn(*) | - ty_closure(*) => { - 2 - } - - ty_evec(t, vstore_fixed(n)) => { - type_size(cx, t.ty) * n - } - - ty_estr(vstore_fixed(n)) => { - n - } - - ty_struct(did, ref substs) => { - let flds = struct_fields(cx, did, substs); - flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) - } - - ty_tup(ref tys) => { - tys.foldl(0, |s, t| *s + type_size(cx, *t)) - } - - ty_enum(did, ref substs) => { - let variants = substd_enum_variants(cx, did, substs); - variants.foldl( // find max size of any variant - 0, - |m, v| uint::max( - *m, - // find size of this variant: - v.args.foldl(0, |s, a| *s + type_size(cx, *a)))) - } - - ty_param(_) | ty_self(_) => { - 1 - } - - ty_infer(_) => { - cx.sess.bug(~"Asked to compute kind of a type variable"); - } - ty_type => 1, - ty_opaque_closure_ptr(_) => 1, - ty_opaque_box => 1, - ty_unboxed_vec(_) => 10, - ty_err => { - cx.sess.bug(~"Asked to compute kind of fictitious type"); - } + tc = tc - match bound { + BoundCopy => TypeContents::nonimplicitly_copyable(cx), + BoundStatic => TypeContents::nonstatic(cx), + BoundOwned => TypeContents::nonowned(cx), + BoundConst => TypeContents::nonconst(cx), + }; } + + debug!("result = %s", tc.to_str()); + return tc; } } @@ -2373,7 +2440,7 @@ pub fn type_structurally_contains(cx: ctxt, if test(sty) { return true; } match *sty { ty_enum(did, ref substs) => { - for vec::each(*enum_variants(cx, did)) |variant| { + for (*enum_variants(cx, did)).each |variant| { for variant.args.each |aty| { let sty = subst(cx, substs, *aty); if type_structurally_contains(cx, sty, test) { return true; } @@ -2445,6 +2512,14 @@ pub fn type_is_signed(ty: t) -> bool { } } +pub fn type_is_machine(ty: t) -> bool { + match get(ty).sty { + ty_int(ast::ty_i) | ty_uint(ast::ty_u) | ty_float(ast::ty_f) => false, + ty_int(*) | ty_uint(*) | ty_float(*) => true, + _ => false + } +} + // Whether a type is Plain Old Data -- meaning it does not contain pointers // that the cycle collector might care about. pub fn type_is_pod(cx: ctxt, ty: t) -> bool { @@ -2461,7 +2536,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool { // Structural types ty_enum(did, ref substs) => { let variants = enum_variants(cx, did); - for vec::each(*variants) |variant| { + for (*variants).each |variant| { let tup_ty = mk_tup(cx, /*bad*/copy variant.args); // Perform any type parameter substitutions. @@ -2509,12 +2584,15 @@ pub fn type_is_enum(ty: t) -> bool { // constructors pub fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { match get(ty).sty { - ty_enum(did, _) => { - let variants = enum_variants(cx, did); - let some_n_ary = vec::any(*variants, |v| vec::len(v.args) > 0u); - return !some_n_ary; - } - _ => return false + ty_enum(did, _) => { + let variants = enum_variants(cx, did); + if variants.len() == 0 { + false + } else { + variants.all(|v| v.args.len() == 0) + } + } + _ => false } } @@ -2640,6 +2718,7 @@ impl cmp::TotalEq for bound_region { } } +#[cfg(stage0)] impl to_bytes::IterBytes for vstore { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -2654,7 +2733,23 @@ impl to_bytes::IterBytes for vstore { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for vstore { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + match *self { + vstore_fixed(ref u) => + to_bytes::iter_bytes_2(&0u8, u, lsb0, f), + + vstore_uniq => 1u8.iter_bytes(lsb0, f), + vstore_box => 2u8.iter_bytes(lsb0, f), + vstore_slice(ref r) => + to_bytes::iter_bytes_2(&3u8, r, lsb0, f), + } + } +} + +#[cfg(stage0)] impl to_bytes::IterBytes for substs { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.self_r, @@ -2662,21 +2757,46 @@ impl to_bytes::IterBytes for substs { &self.tps, lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for substs { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_3(&self.self_r, + &self.self_ty, + &self.tps, lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for mt { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.ty, &self.mutbl, lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for mt { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.ty, + &self.mutbl, lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for field { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.ident, &self.mt, lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for field { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.ident, + &self.mt, lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for FnSig { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.inputs, @@ -2684,7 +2804,16 @@ impl to_bytes::IterBytes for FnSig { lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for FnSig { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.inputs, + &self.output, + lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for sty { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -2759,6 +2888,81 @@ impl to_bytes::IterBytes for sty { } } } +#[cfg(not(stage0))] +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) => + to_bytes::iter_bytes_2(&2u8, t, lsb0, f), + + ty_uint(ref t) => + to_bytes::iter_bytes_2(&3u8, t, lsb0, f), + + ty_float(ref t) => + to_bytes::iter_bytes_2(&4u8, t, lsb0, f), + + ty_estr(ref v) => + to_bytes::iter_bytes_2(&5u8, v, lsb0, f), + + ty_enum(ref did, ref substs) => + to_bytes::iter_bytes_3(&6u8, did, substs, lsb0, f), + + ty_box(ref mt) => + to_bytes::iter_bytes_2(&7u8, mt, lsb0, f), + + ty_evec(ref mt, ref v) => + to_bytes::iter_bytes_3(&8u8, mt, v, lsb0, f), + + ty_unboxed_vec(ref mt) => + to_bytes::iter_bytes_2(&9u8, mt, lsb0, f), + + ty_tup(ref ts) => + to_bytes::iter_bytes_2(&10u8, ts, lsb0, f), + + ty_bare_fn(ref ft) => + to_bytes::iter_bytes_2(&12u8, ft, lsb0, f), + + ty_self(ref did) => to_bytes::iter_bytes_2(&13u8, did, lsb0, f), + + ty_infer(ref v) => + to_bytes::iter_bytes_2(&14u8, v, lsb0, f), + + ty_param(ref p) => + to_bytes::iter_bytes_2(&15u8, p, lsb0, f), + + ty_type => 16u8.iter_bytes(lsb0, f), + ty_bot => 17u8.iter_bytes(lsb0, f), + + ty_ptr(ref mt) => + to_bytes::iter_bytes_2(&18u8, mt, lsb0, f), + + ty_uniq(ref mt) => + to_bytes::iter_bytes_2(&19u8, mt, lsb0, f), + + ty_trait(ref did, ref substs, ref v, ref mutbl) => + to_bytes::iter_bytes_5(&20u8, did, substs, v, mutbl, lsb0, f), + + ty_opaque_closure_ptr(ref ck) => + to_bytes::iter_bytes_2(&21u8, ck, lsb0, f), + + ty_opaque_box => 22u8.iter_bytes(lsb0, f), + + ty_struct(ref did, ref substs) => + to_bytes::iter_bytes_3(&23u8, did, substs, lsb0, f), + + ty_rptr(ref r, ref mt) => + to_bytes::iter_bytes_3(&24u8, r, mt, lsb0, f), + + ty_err => 25u8.iter_bytes(lsb0, f), + + ty_closure(ref ct) => + to_bytes::iter_bytes_2(&26u8, ct, lsb0, f), + } + } +} pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef { match cx.trait_refs.find(&id) { @@ -2874,6 +3078,17 @@ pub fn ty_region(tcx: ctxt, } } +pub fn replace_fn_sig(cx: ctxt, fsty: &sty, new_sig: FnSig) -> t { + match *fsty { + ty_bare_fn(ref f) => mk_bare_fn(cx, BareFnTy {sig: new_sig, ..*f}), + ty_closure(ref f) => mk_closure(cx, ClosureTy {sig: new_sig, ..*f}), + ref s => { + cx.sess.bug( + fmt!("ty_fn_sig() called on non-fn type: %?", s)); + } + } +} + pub fn replace_closure_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t { /*! * @@ -2943,20 +3158,20 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { */ let unadjusted_ty = expr_ty(cx, expr); - adjust_ty(cx, expr.span, unadjusted_ty, cx.adjustments.find(&expr.id)) + adjust_ty(cx, expr.span, unadjusted_ty, cx.adjustments.find_copy(&expr.id)) } pub fn adjust_ty(cx: ctxt, span: span, unadjusted_ty: ty::t, - adjustment: Option<&@AutoAdjustment>) -> ty::t + adjustment: Option<@AutoAdjustment>) -> ty::t { /*! See `expr_ty_adjusted` */ return match adjustment { None => unadjusted_ty, - Some(&@AutoAddEnv(r, s)) => { + Some(@AutoAddEnv(r, s)) => { match ty::get(unadjusted_ty).sty { ty::ty_bare_fn(ref b) => { ty::mk_closure( @@ -2974,7 +3189,7 @@ pub fn adjust_ty(cx: ctxt, } } - Some(&@AutoDerefRef(ref adj)) => { + Some(@AutoDerefRef(ref adj)) => { let mut adjusted_ty = unadjusted_ty; for uint::range(0, adj.autoderefs) |i| { @@ -2993,26 +3208,26 @@ pub fn adjust_ty(cx: ctxt, match adj.autoref { None => adjusted_ty, Some(ref autoref) => { - match autoref.kind { - AutoPtr => { - mk_rptr(cx, autoref.region, - mt {ty: adjusted_ty, - mutbl: autoref.mutbl}) + match *autoref { + AutoPtr(r, m) => { + mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: m}) } - AutoBorrowVec => { - borrow_vec(cx, span, autoref, adjusted_ty) + AutoBorrowVec(r, m) => { + borrow_vec(cx, span, r, m, adjusted_ty) } - AutoBorrowVecRef => { - adjusted_ty = borrow_vec(cx, span, autoref, - adjusted_ty); - mk_rptr(cx, autoref.region, - mt {ty: adjusted_ty, mutbl: ast::m_imm}) + AutoBorrowVecRef(r, m) => { + adjusted_ty = borrow_vec(cx, span, r, m, adjusted_ty); + mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: ast::m_imm}) } - AutoBorrowFn => { - borrow_fn(cx, span, autoref, adjusted_ty) + AutoBorrowFn(r) => { + borrow_fn(cx, span, r, adjusted_ty) + } + + AutoUnsafe(m) => { + mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) } } } @@ -3021,15 +3236,15 @@ pub fn adjust_ty(cx: ctxt, }; fn borrow_vec(cx: ctxt, span: span, - autoref: &AutoRef, ty: ty::t) -> ty::t { + r: Region, m: ast::mutability, + ty: ty::t) -> ty::t { match get(ty).sty { ty_evec(mt, _) => { - ty::mk_evec(cx, mt {ty: mt.ty, mutbl: autoref.mutbl}, - vstore_slice(autoref.region)) + ty::mk_evec(cx, mt {ty: mt.ty, mutbl: m}, vstore_slice(r)) } ty_estr(_) => { - ty::mk_estr(cx, vstore_slice(autoref.region)) + ty::mk_estr(cx, vstore_slice(r)) } ref s => { @@ -3041,13 +3256,12 @@ pub fn adjust_ty(cx: ctxt, } } - fn borrow_fn(cx: ctxt, span: span, - autoref: &AutoRef, ty: ty::t) -> ty::t { + fn borrow_fn(cx: ctxt, span: span, r: Region, ty: ty::t) -> ty::t { match get(ty).sty { ty_closure(ref fty) => { ty::mk_closure(cx, ClosureTy { sigil: BorrowedSigil, - region: autoref.region, + region: r, ..copy *fty }) } @@ -3062,6 +3276,18 @@ pub fn adjust_ty(cx: ctxt, } } +pub impl AutoRef { + fn map_region(&self, f: &fn(Region) -> Region) -> AutoRef { + match *self { + ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m), + ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m), + ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m), + ty::AutoBorrowFn(r) => ty::AutoBorrowFn(f(r)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m), + } + } +} + pub struct ParamsTy { params: ~[t], ty: t @@ -3157,7 +3383,7 @@ pub fn expr_kind(tcx: ctxt, } match expr.node { - ast::expr_path(*) => { + ast::expr_path(*) | ast::expr_self => { match resolve_expr(tcx, expr) { ast::def_variant(*) | ast::def_struct(*) => RvalueDpsExpr, @@ -3240,7 +3466,6 @@ pub fn expr_kind(tcx: ctxt, ast::expr_while(*) | ast::expr_loop(*) | ast::expr_assign(*) | - ast::expr_swap(*) | ast::expr_inline_asm(*) | ast::expr_assign_op(*) => { RvalueStmtExpr @@ -3261,7 +3486,7 @@ pub fn expr_kind(tcx: ctxt, ast::expr_mac(*) => { tcx.sess.span_bug( expr.span, - ~"macro expression remains after expansion"); + "macro expression remains after expansion"); } } } @@ -3582,7 +3807,7 @@ pub fn trait_supertraits(cx: ctxt, pub fn trait_ref_supertraits(cx: ctxt, trait_ref: &ty::TraitRef) -> ~[@TraitRef] { let supertrait_refs = trait_supertraits(cx, trait_ref.def_id); supertrait_refs.map( - |supertrait_ref| @supertrait_ref.subst(cx, &trait_ref.substs)) + |supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs)) } fn lookup_locally_or_in_crate_store( @@ -3728,7 +3953,6 @@ pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { pub enum DtorKind { NoDtor, - LegacyDtor(def_id), TraitDtor(def_id) } @@ -3748,28 +3972,8 @@ pub impl DtorKind { Otherwise return none. */ pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind { match cx.destructor_for_type.find(&struct_id) { - Some(&method_def_id) => return TraitDtor(method_def_id), - None => {} // Continue. - } - - if is_local(struct_id) { - match cx.items.find(&struct_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_struct(@ast::struct_def { dtor: Some(ref dtor), - _ }, - _), - _ - }, _)) => - LegacyDtor(local_def((*dtor).node.id)), - _ => - NoDtor - } - } - else { - match csearch::struct_dtor(cx.sess.cstore, struct_id) { + Some(&method_def_id) => TraitDtor(method_def_id), None => NoDtor, - Some(did) => LegacyDtor(did), - } } } @@ -3815,15 +4019,10 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { } ast_map::node_variant(ref variant, _, path) => { - vec::append_one(vec::from_slice(vec::init(*path)), + vec::append_one(vec::to_owned(vec::init(*path)), ast_map::path_name((*variant).node.name)) } - ast_map::node_dtor(_, _, _, path) => { - vec::append_one(/*bad*/copy *path, ast_map::path_name( - syntax::parse::token::special_idents::literally_dtor)) - } - ast_map::node_struct_ctor(_, item, path) => { vec::append_one(/*bad*/copy *path, ast_map::path_name(item.ident)) } @@ -3860,7 +4059,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { call eval_const_expr, it should never get called twice for the same expr, since check_enum_variants also updates the enum_var_cache */ - match *cx.items.get(&id.node) { + match cx.items.get_copy(&id.node) { ast_map::node_item(@ast::item { node: ast::item_enum(ref enum_definition, _), _ @@ -3952,28 +4151,37 @@ pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { } } -// Determine whether an item is annotated with #[packed] or not -pub fn lookup_packed(tcx: ctxt, - did: def_id) -> bool { +/// Determine whether an item is annotated with an attribute +pub fn has_attr(tcx: ctxt, did: def_id, attr: &str) -> bool { if is_local(did) { match tcx.items.find(&did.node) { Some( &ast_map::node_item(@ast::item { attrs: ref attrs, _ - }, _)) => attr::attrs_contains_name(*attrs, "packed"), - _ => tcx.sess.bug(fmt!("lookup_packed: %? is not an item", + }, _)) => attr::attrs_contains_name(*attrs, attr), + _ => tcx.sess.bug(fmt!("has_attr: %? is not an item", did)) } } else { let mut ret = false; do csearch::get_item_attrs(tcx.cstore, did) |meta_items| { - ret = attr::contains_name(meta_items, "packed"); + ret = attr::contains_name(meta_items, attr); } ret } } +/// Determine whether an item is annotated with `#[packed]` +pub fn lookup_packed(tcx: ctxt, did: def_id) -> bool { + has_attr(tcx, did, "packed") +} + +/// Determine whether an item is annotated with `#[simd]` +pub fn lookup_simd(tcx: ctxt, did: def_id) -> bool { + has_attr(tcx, did, "simd") +} + // Look up a field ID, whether or not it's local // Takes a list of type substs in case the struct is generic pub fn lookup_field_type(tcx: ctxt, @@ -3986,7 +4194,7 @@ pub fn lookup_field_type(tcx: ctxt, } else { match tcx.tcache.find(&id) { - Some(tpt) => tpt.ty, + Some(&ty_param_bounds_and_ty {ty, _}) => ty, None => { let tpt = csearch::get_field_type(tcx, struct_id, id); tcx.tcache.insert(id, tpt); @@ -4048,12 +4256,11 @@ pub fn lookup_struct_field(cx: ctxt, fn struct_field_tys(fields: &[@struct_field]) -> ~[field_ty] { do fields.map |field| { match field.node.kind { - named_field(ident, mutability, visibility) => { + named_field(ident, visibility) => { field_ty { ident: ident, id: ast_util::local_def(field.node.id), vis: visibility, - mutability: mutability, } } unnamed_field => { @@ -4062,51 +4269,22 @@ fn struct_field_tys(fields: &[@struct_field]) -> ~[field_ty] { syntax::parse::token::special_idents::unnamed_field, id: ast_util::local_def(field.node.id), vis: ast::public, - mutability: ast::struct_immutable, } } } } } -// Return a list of fields corresponding to the struct's items -// (as if the struct was a record). trans uses this -// Takes a list of substs with which to instantiate field types -// Keep in mind that this function reports that all fields are -// mutable, regardless of how they were declared. It's meant to -// be used in trans. -pub fn struct_mutable_fields(cx: ctxt, - did: ast::def_id, - substs: &substs) - -> ~[field] { - struct_item_fields(cx, did, substs, |_mt| m_mutbl) -} - -// Same as struct_mutable_fields, but doesn't change -// mutability. -pub fn struct_fields(cx: ctxt, - did: ast::def_id, - substs: &substs) - -> ~[field] { - struct_item_fields(cx, did, substs, |mt| match mt { - struct_mutable => m_mutbl, - struct_immutable => m_imm }) -} - - -fn struct_item_fields(cx:ctxt, - did: ast::def_id, - substs: &substs, - frob_mutability: &fn(struct_mutability) -> mutability) - -> ~[field] { +// Returns a list of fields corresponding to the struct's items. trans uses +// this. Takes a list of substs with which to instantiate field types. +pub fn struct_fields(cx: ctxt, did: ast::def_id, substs: &substs) + -> ~[field] { do lookup_struct_fields(cx, did).map |f| { - // consider all instance vars mut, because the - // constructor may mutate all vars field { - ident: f.ident, + ident: f.ident, mt: mt { ty: lookup_field_type(cx, did, f.id, substs), - mutbl: frob_mutability(f.mutability) + mutbl: m_imm } } } @@ -4134,7 +4312,7 @@ pub fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { ast::add => opcat_add, ast::subtract => opcat_sub, ast::mul => opcat_mult, - ast::quot => opcat_mult, + ast::div => opcat_mult, ast::rem => opcat_mult, ast::and => opcat_logic, ast::or => opcat_logic, @@ -4267,27 +4445,27 @@ pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint { const_eval::const_uint(count) => return count as uint, const_eval::const_float(count) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found float"); + "expected signed or unsigned integer for \ + repeat count but found float"); return count as uint; } const_eval::const_str(_) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found string"); + "expected signed or unsigned integer for \ + repeat count but found string"); return 0; } const_eval::const_bool(_) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found boolean"); + "expected signed or unsigned integer for \ + repeat count but found boolean"); return 0; } }, Err(*) => { tcx.sess.span_err(count_expr.span, - ~"expected constant integer for repeat count \ - but found variable"); + "expected constant integer for repeat count \ + but found variable"); return 0; } } @@ -4312,19 +4490,56 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), // Here, the supertraits are the transitive closure of the supertrait // relation on the supertraits from each bounded trait's constraint // list. +#[cfg(stage0)] pub fn each_bound_trait_and_supertraits(tcx: ctxt, - bounds: param_bounds, - f: &fn(&TraitRef) -> bool) { - for bounds.each |bound| { - let bound_trait_ref = match *bound { - ty::bound_trait(bound_t) => bound_t, - - ty::bound_copy | ty::bound_owned | - ty::bound_const | ty::bound_durable => { - loop; // skip non-trait bounds + bounds: &ParamBounds, + f: &fn(@TraitRef) -> bool) { + for bounds.trait_bounds.each |&bound_trait_ref| { + let mut supertrait_set = HashMap::new(); + let mut trait_refs = ~[]; + let mut i = 0; + + // Seed the worklist with the trait from the bound + supertrait_set.insert(bound_trait_ref.def_id, ()); + trait_refs.push(bound_trait_ref); + + // Add the given trait ty to the hash map + while i < trait_refs.len() { + debug!("each_bound_trait_and_supertraits(i=%?, trait_ref=%s)", + i, trait_refs[i].repr(tcx)); + + if !f(trait_refs[i]) { + return; } - }; + // Add supertraits to supertrait_set + let supertrait_refs = trait_ref_supertraits(tcx, trait_refs[i]); + for supertrait_refs.each |&supertrait_ref| { + debug!("each_bound_trait_and_supertraits(supertrait_ref=%s)", + supertrait_ref.repr(tcx)); + + let d_id = supertrait_ref.def_id; + if !supertrait_set.contains_key(&d_id) { + // FIXME(#5527) Could have same trait multiple times + supertrait_set.insert(d_id, ()); + trait_refs.push(supertrait_ref); + } + } + + i += 1; + } + } +} +// Iterate over a type parameter's bounded traits and any supertraits +// of those traits, ignoring kinds. +// Here, the supertraits are the transitive closure of the supertrait +// relation on the supertraits from each bounded trait's constraint +// list. +#[cfg(not(stage0))] +pub fn each_bound_trait_and_supertraits(tcx: ctxt, + bounds: &ParamBounds, + f: &fn(@TraitRef) -> bool) -> bool { + for bounds.trait_bounds.each |&bound_trait_ref| { let mut supertrait_set = HashMap::new(); let mut trait_refs = ~[]; let mut i = 0; @@ -4339,7 +4554,7 @@ pub fn each_bound_trait_and_supertraits(tcx: ctxt, i, trait_refs[i].repr(tcx)); if !f(trait_refs[i]) { - return; + return false; } // Add supertraits to supertrait_set @@ -4359,6 +4574,7 @@ pub fn each_bound_trait_and_supertraits(tcx: ctxt, i += 1; } } + return true; } pub fn count_traits_and_supertraits(tcx: ctxt, @@ -4391,15 +4607,7 @@ pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id { pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { let ty_visitor_name = special_idents::ty_visitor; assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); - let trait_ref = *tcx.intrinsic_traits.get(&ty_visitor_name); + let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name); (trait_ref, mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm)) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ffaa6d46d3379..469e31d0c49cc 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -101,8 +101,8 @@ pub fn get_region_reporting_err( } } -pub fn ast_region_to_region( - self: &AC, +pub fn ast_region_to_region( + this: &AC, rscope: &RS, default_span: span, opt_lifetime: Option<@ast::Lifetime>) -> ty::Region @@ -111,7 +111,7 @@ pub fn ast_region_to_region( None => { (default_span, rscope.anon_region(default_span)) } - Some(ref lifetime) if lifetime.ident == special_idents::static => { + Some(ref lifetime) if lifetime.ident == special_idents::statik => { (lifetime.span, Ok(ty::re_static)) } Some(ref lifetime) if lifetime.ident == special_idents::self_ => { @@ -123,11 +123,11 @@ pub fn ast_region_to_region( } }; - get_region_reporting_err(self.tcx(), span, opt_lifetime, res) + get_region_reporting_err(this.tcx(), span, opt_lifetime, res) } -fn ast_path_substs( - self: &AC, +fn ast_path_substs( + this: &AC, rscope: &RS, def_id: ast::def_id, decl_generics: &ty::Generics, @@ -141,9 +141,9 @@ fn ast_path_substs( * set of substitutions for this particular reference to `I`. */ - let tcx = self.tcx(); + let tcx = this.tcx(); - // If the type is parameterized by the self region, then replace self + // If the type is parameterized by the this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). let self_r = match (&decl_generics.region_param, &path.rp) { @@ -160,55 +160,55 @@ fn ast_path_substs( } (&Some(_), &None) => { let res = rscope.anon_region(path.span); - let r = get_region_reporting_err(self.tcx(), path.span, None, res); + let r = get_region_reporting_err(this.tcx(), path.span, None, res); Some(r) } (&Some(_), &Some(_)) => { - Some(ast_region_to_region(self, rscope, path.span, path.rp)) + Some(ast_region_to_region(this, rscope, path.span, path.rp)) } }; // Convert the type parameters supplied by the user. if !vec::same_length(*decl_generics.type_param_defs, path.types) { - self.tcx().sess.span_fatal( + this.tcx().sess.span_fatal( path.span, fmt!("wrong number of type arguments: expected %u but found %u", decl_generics.type_param_defs.len(), path.types.len())); } - let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); + let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, *a_t)); substs {self_r:self_r, self_ty:self_ty, tps:tps} } -pub fn ast_path_to_substs_and_ty( - self: &AC, +pub fn ast_path_to_substs_and_ty( + this: &AC, rscope: &RS, did: ast::def_id, path: @ast::Path) -> ty_param_substs_and_ty { - let tcx = self.tcx(); + let tcx = this.tcx(); let ty::ty_param_bounds_and_ty { generics: generics, ty: decl_ty - } = self.get_item_ty(did); + } = this.get_item_ty(did); - let substs = ast_path_substs(self, rscope, did, &generics, None, path); + let substs = ast_path_substs(this, rscope, did, &generics, None, path); let ty = ty::subst(tcx, &substs, decl_ty); ty_param_substs_and_ty { substs: substs, ty: ty } } -pub fn ast_path_to_trait_ref( - self: &AC, +pub fn ast_path_to_trait_ref( + this: &AC, rscope: &RS, trait_def_id: ast::def_id, self_ty: Option, path: @ast::Path) -> @ty::TraitRef { let trait_def = - self.get_trait_def(trait_def_id); + this.get_trait_def(trait_def_id); let substs = ast_path_substs( - self, + this, rscope, trait_def.trait_ref.def_id, &trait_def.generics, @@ -221,8 +221,8 @@ pub fn ast_path_to_trait_ref( } -pub fn ast_path_to_ty( - self: &AC, +pub fn ast_path_to_ty( + this: &AC, rscope: &RS, did: ast::def_id, path: @ast::Path) @@ -233,7 +233,7 @@ pub fn ast_path_to_ty( let ty::ty_param_substs_and_ty { substs: substs, ty: ty - } = ast_path_to_substs_and_ty(self, rscope, did, path); + } = ast_path_to_substs_and_ty(this, rscope, did, path); ty_param_substs_and_ty { substs: substs, ty: ty } } @@ -243,30 +243,30 @@ pub static NO_TPS: uint = 2; // Parses the programmer's textual representation of a type into our // internal notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: -pub fn ast_ty_to_ty( - self: &AC, rscope: &RS, ast_ty: @ast::Ty) -> ty::t { +pub fn ast_ty_to_ty( + this: &AC, rscope: &RS, ast_ty: @ast::Ty) -> ty::t { - fn ast_mt_to_mt( - self: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt { + fn ast_mt_to_mt( + this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt { - ty::mt {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl} + ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl} } // Handle @, ~, and & being able to mean estrs and evecs. // If a_seq_ty is a str or a vec, make it an estr/evec. // Also handle first-class trait types. - fn mk_pointer( - self: &AC, + fn mk_pointer( + this: &AC, rscope: &RS, a_seq_ty: &ast::mt, vst: ty::vstore, constr: &fn(ty::mt) -> ty::t) -> ty::t { - let tcx = self.tcx(); + let tcx = this.tcx(); match a_seq_ty.ty.node { ast::ty_vec(ref mt) => { - let mut mt = ast_mt_to_mt(self, rscope, mt); + let mut mt = ast_mt_to_mt(this, rscope, mt); if a_seq_ty.mutbl == ast::m_mutbl || a_seq_ty.mutbl == ast::m_const { mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl }; @@ -281,7 +281,7 @@ pub fn ast_ty_to_ty( } Some(&ast::def_trait(trait_def_id)) => { let result = ast_path_to_trait_ref( - self, rscope, trait_def_id, None, path); + this, rscope, trait_def_id, None, path); let trait_store = match vst { ty::vstore_box => ty::BoxTraitStore, ty::vstore_uniq => ty::UniqTraitStore, @@ -291,10 +291,8 @@ pub fn ast_ty_to_ty( ty::vstore_fixed(*) => { tcx.sess.span_err( path.span, - ~"@trait, ~trait or &trait \ - are the only supported \ - forms of casting-to-\ - trait"); + "@trait, ~trait or &trait are the only supported \ + forms of casting-to-trait"); ty::BoxTraitStore } }; @@ -310,7 +308,7 @@ pub fn ast_ty_to_ty( _ => {} } - let seq_ty = ast_mt_to_mt(self, rscope, a_seq_ty); + let seq_ty = ast_mt_to_mt(this, rscope, a_seq_ty); return constr(seq_ty); } @@ -321,7 +319,7 @@ pub fn ast_ty_to_ty( if path.types.len() > 0u { tcx.sess.span_err( path.span, - ~"type parameters are not allowed on this type"); + "type parameters are not allowed on this type"); } } @@ -329,19 +327,18 @@ pub fn ast_ty_to_ty( if path.rp.is_some() { tcx.sess.span_err( path.span, - ~"region parameters are not allowed on this type"); + "region parameters are not allowed on this type"); } } } - let tcx = self.tcx(); + let tcx = this.tcx(); match tcx.ast_ty_to_ty_cache.find(&ast_ty.id) { Some(&ty::atttce_resolved(ty)) => return ty, Some(&ty::atttce_unresolved) => { - tcx.sess.span_fatal(ast_ty.span, ~"illegal recursive type; \ - insert an enum in the cycle, \ - if this is desired"); + tcx.sess.span_fatal(ast_ty.span, "illegal recursive type; \ + insert an enum in the cycle, if this is desired"); } None => { /* go on */ } } @@ -351,38 +348,36 @@ pub fn ast_ty_to_ty( ast::ty_nil => ty::mk_nil(), ast::ty_bot => ty::mk_bot(), ast::ty_box(ref mt) => { - mk_pointer(self, rscope, mt, ty::vstore_box, + mk_pointer(this, rscope, mt, ty::vstore_box, |tmt| ty::mk_box(tcx, tmt)) } ast::ty_uniq(ref mt) => { - mk_pointer(self, rscope, mt, ty::vstore_uniq, + mk_pointer(this, rscope, mt, ty::vstore_uniq, |tmt| ty::mk_uniq(tcx, tmt)) } ast::ty_vec(ref mt) => { - tcx.sess.span_err(ast_ty.span, - ~"bare `[]` is not a type"); + tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type"); // return /something/ so they can at least get more errors - ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, mt), - ty::vstore_uniq) + ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, mt), ty::vstore_uniq) } ast::ty_ptr(ref mt) => { - ty::mk_ptr(tcx, ast_mt_to_mt(self, rscope, mt)) + ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt)) } ast::ty_rptr(region, ref mt) => { - let r = ast_region_to_region(self, rscope, ast_ty.span, region); - mk_pointer(self, rscope, mt, ty::vstore_slice(r), + let r = ast_region_to_region(this, rscope, ast_ty.span, region); + mk_pointer(this, rscope, mt, ty::vstore_slice(r), |tmt| ty::mk_rptr(tcx, r, tmt)) } ast::ty_tup(ref fields) => { - let flds = fields.map(|t| ast_ty_to_ty(self, rscope, *t)); + let flds = fields.map(|t| ast_ty_to_ty(this, rscope, *t)); ty::mk_tup(tcx, flds) } ast::ty_bare_fn(ref bf) => { - ty::mk_bare_fn(tcx, ty_of_bare_fn(self, rscope, bf.purity, + ty::mk_bare_fn(tcx, ty_of_bare_fn(this, rscope, bf.purity, bf.abis, &bf.lifetimes, &bf.decl)) } ast::ty_closure(ref f) => { - let fn_decl = ty_of_closure(self, + let fn_decl = ty_of_closure(this, rscope, f.sigil, f.purity, @@ -412,7 +407,7 @@ pub fn ast_ty_to_ty( ty::mk_err() } ast::def_ty(did) | ast::def_struct(did) => { - ast_path_to_ty(self, rscope, did, path).ty + ast_path_to_ty(this, rscope, did, path).ty } ast::def_prim_ty(nty) => { match nty { @@ -434,7 +429,7 @@ pub fn ast_ty_to_ty( } ast::ty_str => { tcx.sess.span_err(ast_ty.span, - ~"bare `str` is not a type"); + "bare `str` is not a type"); // return /something/ so they can at least get more errors ty::mk_estr(tcx, ty::vstore_uniq) } @@ -445,7 +440,7 @@ pub fn ast_ty_to_ty( ty::mk_param(tcx, n, id) } ast::def_self_ty(id) => { - // n.b.: resolve guarantees that the self type only appears in a + // n.b.: resolve guarantees that the this type only appears in a // trait, which we rely upon in various places when creating // substs check_path_args(tcx, path, NO_TPS | NO_REGIONS); @@ -454,7 +449,7 @@ pub fn ast_ty_to_ty( } _ => { tcx.sess.span_fatal(ast_ty.span, - ~"found type name used as a variable"); + "found type name used as a variable"); } } } @@ -463,14 +458,14 @@ pub fn ast_ty_to_ty( Ok(ref r) => { match *r { const_eval::const_int(i) => - ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, a_mt), + ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, a_mt), ty::vstore_fixed(i as uint)), const_eval::const_uint(i) => - ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, a_mt), + ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, a_mt), ty::vstore_fixed(i as uint)), _ => { tcx.sess.span_fatal( - ast_ty.span, ~"expected constant expr for vector length"); + ast_ty.span, "expected constant expr for vector length"); } } } @@ -487,13 +482,13 @@ pub fn ast_ty_to_ty( // values in a fn_expr, or as the type of local variables. Both of // these cases are handled specially and should not descend into this // routine. - self.tcx().sess.span_bug( + this.tcx().sess.span_bug( ast_ty.span, - ~"found `ty_infer` in unexpected place"); + "found `ty_infer` in unexpected place"); } ast::ty_mac(_) => { tcx.sess.span_bug(ast_ty.span, - ~"found `ty_mac` in unexpected place"); + "found `ty_mac` in unexpected place"); } }; @@ -502,16 +497,16 @@ pub fn ast_ty_to_ty( } pub fn ty_of_arg( - self: &AC, + RS:region_scope + Copy + 'static>( + this: &AC, rscope: &RS, a: ast::arg, expected_ty: Option) -> ty::arg { let ty = match a.ty.node { ast::ty_infer if expected_ty.is_some() => expected_ty.get().ty, - ast::ty_infer => self.ty_infer(a.ty.span), - _ => ast_ty_to_ty(self, rscope, a.ty), + ast::ty_infer => this.ty_infer(a.ty.span), + _ => ast_ty_to_ty(this, rscope, a.ty), }; arg { @@ -520,28 +515,28 @@ pub fn ty_of_arg( - self: &AC, + this: &AC, ast_lifetimes: &OptVec) -> OptVec { /*! * * Converts a list of lifetimes into a list of bound identifier - * names. Does not permit special names like 'static or 'self to + * names. Does not permit special names like 'static or 'this to * be bound. Note that this function is for use in closures, - * methods, and fn definitions. It is legal to bind 'self in a + * methods, and fn definitions. It is legal to bind 'this in a * type. Eventually this distinction should go away and the same - * rules should apply everywhere ('self would not be a special name + * rules should apply everywhere ('this would not be a special name * at that point). */ - let special_idents = [special_idents::static, special_idents::self_]; + let special_idents = [special_idents::statik, special_idents::self_]; let mut bound_lifetime_names = opt_vec::Empty; ast_lifetimes.map_to_vec(|ast_lifetime| { if special_idents.any(|&i| i == ast_lifetime.ident) { - self.tcx().sess.span_err( + this.tcx().sess.span_err( ast_lifetime.span, fmt!("illegal lifetime parameter name: `%s`", - lifetime_to_str(ast_lifetime, self.tcx().sess.intr()))); + lifetime_to_str(ast_lifetime, this.tcx().sess.intr()))); } else { bound_lifetime_names.push(ast_lifetime.ident); } @@ -554,8 +549,8 @@ struct SelfInfo { self_transform: ast::self_ty } -pub fn ty_of_method( - self: &AC, +pub fn ty_of_method( + this: &AC, rscope: &RS, purity: ast::purity, lifetimes: &OptVec, @@ -568,12 +563,12 @@ pub fn ty_of_method( self_transform: self_transform }; let (a, b) = ty_of_method_or_bare_fn( - self, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); + this, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); (a.get(), b) } -pub fn ty_of_bare_fn( - self: &AC, +pub fn ty_of_bare_fn( + this: &AC, rscope: &RS, purity: ast::purity, abi: AbiSet, @@ -581,12 +576,12 @@ pub fn ty_of_bare_fn( decl: &ast::fn_decl) -> ty::BareFnTy { let (_, b) = ty_of_method_or_bare_fn( - self, rscope, purity, abi, lifetimes, None, decl); + this, rscope, purity, abi, lifetimes, None, decl); b } -fn ty_of_method_or_bare_fn( - self: &AC, +fn ty_of_method_or_bare_fn( + this: &AC, rscope: &RS, purity: ast::purity, abi: AbiSet, @@ -598,18 +593,18 @@ fn ty_of_method_or_bare_fn( // new region names that appear inside of the fn decl are bound to // that function type - let bound_lifetime_names = bound_lifetimes(self, lifetimes); + let bound_lifetime_names = bound_lifetimes(this, lifetimes); let rb = in_binding_rscope(rscope, RegionParamNames(copy bound_lifetime_names)); let opt_transformed_self_ty = opt_self_info.map(|&self_info| { - transform_self_ty(self, &rb, self_info) + transform_self_ty(this, &rb, self_info) }); - let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None)); + let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, *a, None)); let output_ty = match decl.output.node { - ast::ty_infer => self.ty_infer(decl.output.span), - _ => ast_ty_to_ty(self, &rb, decl.output) + ast::ty_infer => this.ty_infer(decl.output.span), + _ => ast_ty_to_ty(this, &rb, decl.output) }; return (opt_transformed_self_ty, @@ -621,8 +616,8 @@ fn ty_of_method_or_bare_fn( output: output_ty} }); - fn transform_self_ty( - self: &AC, + fn transform_self_ty( + this: &AC, rscope: &RS, self_info: &SelfInfo) -> Option { @@ -633,20 +628,20 @@ fn ty_of_method_or_bare_fn( } ast::sty_region(lifetime, mutability) => { let region = - ast_region_to_region(self, rscope, + ast_region_to_region(this, rscope, self_info.self_transform.span, lifetime); - Some(ty::mk_rptr(self.tcx(), region, + Some(ty::mk_rptr(this.tcx(), region, ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } ast::sty_box(mutability) => { - Some(ty::mk_box(self.tcx(), + Some(ty::mk_box(this.tcx(), ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } ast::sty_uniq(mutability) => { - Some(ty::mk_uniq(self.tcx(), + Some(ty::mk_uniq(this.tcx(), ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } @@ -654,8 +649,8 @@ fn ty_of_method_or_bare_fn( } } -pub fn ty_of_closure( - self: &AC, +pub fn ty_of_closure( + this: &AC, rscope: &RS, sigil: ast::Sigil, purity: ast::purity, @@ -679,7 +674,7 @@ pub fn ty_of_closure( // scope `rscope`, not the scope of the function parameters let bound_region = match opt_lifetime { Some(_) => { - ast_region_to_region(self, rscope, span, opt_lifetime) + ast_region_to_region(this, rscope, span, opt_lifetime) } None => { match sigil { @@ -690,7 +685,7 @@ pub fn ty_of_closure( } ast::BorrowedSigil => { // &fn() defaults as normal for an omitted lifetime: - ast_region_to_region(self, rscope, span, opt_lifetime) + ast_region_to_region(this, rscope, span, opt_lifetime) } } } @@ -698,7 +693,7 @@ pub fn ty_of_closure( // new region names that appear inside of the fn decl are bound to // that function type - let bound_lifetime_names = bound_lifetimes(self, lifetimes); + let bound_lifetime_names = bound_lifetimes(this, lifetimes); let rb = in_binding_rscope(rscope, RegionParamNames(copy bound_lifetime_names)); let input_tys = do decl.inputs.mapi |i, a| { @@ -707,14 +702,14 @@ pub fn ty_of_closure( // were supplied if i < e.inputs.len() {Some(e.inputs[i])} else {None} }; - ty_of_arg(self, &rb, *a, expected_arg_ty) + ty_of_arg(this, &rb, *a, expected_arg_ty) }; let expected_ret_ty = expected_sig.map(|e| e.output); let output_ty = match decl.output.node { ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(), - ast::ty_infer => self.ty_infer(decl.output.span), - _ => ast_ty_to_ty(self, &rb, decl.output) + ast::ty_infer => this.ty_infer(decl.output.span), + _ => ast_ty_to_ty(this, &rb, decl.output) }; ty::ClosureTy { diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7f0066a1aa272..07083459020b1 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -114,37 +114,51 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, ty::ty_enum(_, ref expected_substs) => { // Lookup the enum and variant def ids: let v_def = lookup_def(pcx.fcx, pat.span, pat.id); - let (enm, var) = ast_util::variant_def_ids(v_def); - - // Assign the pattern the type of the *enum*, not the variant. - let enum_tpt = ty::lookup_item_type(tcx, enm); - instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, - pcx.block_region); - - // check that the type of the value being matched is a subtype - // of the type of the pattern: - let pat_ty = fcx.node_ty(pat.id); - demand::subtype(fcx, pat.span, expected, pat_ty); - - // Get the expected types of the arguments. - arg_types = { - let vinfo = - ty::enum_variant_with_id(tcx, enm, var); - let var_tpt = ty::lookup_item_type(tcx, var); - vinfo.args.map(|t| { - if var_tpt.generics.type_param_defs.len() == - expected_substs.tps.len() - { - ty::subst(tcx, expected_substs, *t) - } - else { - *t // In this case, an error was already signaled - // anyway - } - }) - }; - - kind_name = "variant"; + match ast_util::variant_def_ids(v_def) { + Some((enm, var)) => { + // Assign the pattern the type of the *enum*, not the variant. + let enum_tpt = ty::lookup_item_type(tcx, enm); + instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id); + + // check that the type of the value being matched is a subtype + // of the type of the pattern: + let pat_ty = fcx.node_ty(pat.id); + demand::subtype(fcx, pat.span, expected, pat_ty); + + // Get the expected types of the arguments. + arg_types = { + let vinfo = + ty::enum_variant_with_id(tcx, enm, var); + let var_tpt = ty::lookup_item_type(tcx, var); + vinfo.args.map(|t| { + if var_tpt.generics.type_param_defs.len() == + expected_substs.tps.len() + { + ty::subst(tcx, expected_substs, *t) + } + else { + *t // In this case, an error was already signaled + // anyway + } + }) + }; + + kind_name = "variant"; + } + None => { + fcx.infcx().type_error_message_str_with_expected(pat.span, + |expected, actual| { + expected.map_default(~"", |&e| { + fmt!("mismatched types: expected `%s` but found %s", + e, actual)})}, + Some(expected), ~"a structure pattern", + None); + fcx.write_error(pat.id); + kind_name = "[error]"; + arg_types = (copy subpats).get_or_default(~[]).map(|_| + ty::mk_err()); + } + } } ty::ty_struct(struct_def_id, ref expected_substs) => { // Lookup the struct ctor def id @@ -159,8 +173,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, } else { ctor_tpt }; - instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id, - pcx.block_region); + instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id); // Check that the type of the value being matched is a subtype of // the type of the pattern. @@ -175,11 +188,17 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, kind_name = "structure"; } _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched types: expected `%s` but found enum or \ - structure", - fcx.infcx().ty_to_str(expected))); + fcx.infcx().type_error_message_str_with_expected(pat.span, + |expected, actual| { + expected.map_default(~"", |&e| { + fmt!("mismatched types: expected `%s` but found %s", + e, actual)})}, + Some(expected), ~"an enum or structure pattern", + None); + fcx.write_error(pat.id); + kind_name = "[error]"; + arg_types = (copy subpats).get_or_default(~[]).map(|_| + ty::mk_err()); } } @@ -197,8 +216,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, if arg_len > 0 { // N-ary variant. if arg_len != subpats_len { - let s = fmt!("this pattern has %u field%s, but the corresponding \ - %s has %u field%s", + let s = fmt!("this pattern has %u field%s, but the corresponding %s has %u field%s", subpats_len, if subpats_len == 1u { ~"" } else { ~"s" }, kind_name, @@ -216,13 +234,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, } } } else if subpats_len > 0 { - tcx.sess.span_err - (pat.span, fmt!("this pattern has %u field%s, but the \ - corresponding %s has no fields", - subpats_len, - if subpats_len == 1u { ~"" } - else { ~"s" }, - kind_name)); + tcx.sess.span_err(pat.span, + fmt!("this pattern has %u field%s, but the corresponding %s has no \ + fields", + subpats_len, + if subpats_len == 1u { "" } else { "s" }, + kind_name)); error_happened = true; } @@ -312,22 +329,15 @@ pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::node_id, span: span, Some(&ast::def_struct(*)) | Some(&ast::def_variant(*)) => { let name = pprust::path_to_str(path, tcx.sess.intr()); tcx.sess.span_err(span, - fmt!("mismatched types: expected `%s` but \ - found `%s`", + fmt!("mismatched types: expected `%s` but found `%s`", fcx.infcx().ty_to_str(expected), name)); } _ => { - tcx.sess.span_bug(span, ~"resolve didn't write in class"); + tcx.sess.span_bug(span, "resolve didn't write in class"); } } - // Forbid pattern-matching structs with destructors. - if ty::has_dtor(tcx, class_id) { - tcx.sess.span_err(span, ~"deconstructing struct not allowed in \ - pattern (it has a destructor)"); - } - check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id, substitutions, etc); } @@ -363,7 +373,7 @@ pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt, name)); } _ => { - tcx.sess.span_bug(span, ~"resolve didn't write in variant"); + tcx.sess.span_bug(span, "resolve didn't write in variant"); } } } @@ -397,16 +407,15 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { { // no-op } else if !ty::type_is_numeric(b_ty) { - tcx.sess.span_err(pat.span, ~"non-numeric type used in range"); + tcx.sess.span_err(pat.span, "non-numeric type used in range"); } else if !valid_range_bounds(fcx.ccx, begin, end) { - tcx.sess.span_err(begin.span, ~"lower range bound must be less \ - than upper"); + tcx.sess.span_err(begin.span, "lower range bound must be less than upper"); } fcx.write_ty(pat.id, b_ty); } ast::pat_enum(*) | ast::pat_ident(*) if pat_is_const(tcx.def_map, pat) => { - let const_did = ast_util::def_id_of_def(*tcx.def_map.get(&pat.id)); + let const_did = ast_util::def_id_of_def(tcx.def_map.get_copy(&pat.id)); let const_tpt = ty::lookup_item_type(tcx, const_did); demand::suptype(fcx, pat.span, expected, const_tpt.ty); fcx.write_ty(pat.id, const_tpt.ty); @@ -469,9 +478,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } _ => { tcx.sess.span_err(pat.span, - fmt!("mismatched types: expected `%s` \ - but found struct", - fcx.infcx().ty_to_str(expected))); + fmt!("mismatched types: expected `%s` but found struct", + fcx.infcx().ty_to_str(expected))); error_happened = true; } } @@ -486,74 +494,41 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } ast::pat_tup(ref elts) => { let s = structure_of(fcx, pat.span, expected); - let ex_elts = match s { - ty::ty_tup(ref elts) => elts, - _ => { - tcx.sess.span_fatal - (pat.span, - fmt!("mismatched types: expected `%s`, found tuple", - fcx.infcx().ty_to_str(expected))); - } - }; let e_count = elts.len(); - if e_count != ex_elts.len() { - tcx.sess.span_fatal - (pat.span, fmt!("mismatched types: expected a tuple \ - with %u fields, found one with %u \ - fields", ex_elts.len(), e_count)); - } - let mut i = 0u; - for elts.each |elt| { - check_pat(pcx, *elt, ex_elts[i]); - i += 1u; + match s { + ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => { + for elts.eachi |i, elt| { + check_pat(pcx, *elt, ex_elts[i]); + } + fcx.write_ty(pat.id, expected); + } + _ => { + for elts.each |elt| { + check_pat(pcx, *elt, ty::mk_err()); + } + // use terr_tuple_size if both types are tuples + let type_error = match s { + ty::ty_tup(ref ex_elts) => + ty::terr_tuple_size(ty::expected_found{expected: ex_elts.len(), + found: e_count}), + _ => ty::terr_mismatch + }; + fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { + expected.map_default(~"", |&e| { + fmt!("mismatched types: expected `%s` but found %s", + e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + fcx.write_error(pat.id); + } } - - fcx.write_ty(pat.id, expected); } ast::pat_box(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_box(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found box"); - } - } + check_pointer_pat(pcx, Managed, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_uniq(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found uniq"); - } - } + check_pointer_pat(pcx, Owned, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_rptr(_, e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found borrowed pointer"); - } - } + check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); } ast::pat_vec(ref before, slice, ref after) => { let default_region_var = @@ -577,11 +552,26 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { (mt, default_region_var) }, _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched type: expected `%s` but found vector", - fcx.infcx().ty_to_str(expected)) - ); + for before.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for slice.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for after.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + fcx.infcx().type_error_message_str_with_expected( + pat.span, + |expected, actual| { + expected.map_default(~"", |&e| { + fmt!("mismatched types: expected `%s` but found %s", + e, actual)})}, + Some(expected), + ~"a vector pattern", + None); + fcx.write_error(pat.id); + return; } }; for before.each |elt| { @@ -605,3 +595,47 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } } +// Helper function to check @, ~ and & patterns +pub fn check_pointer_pat(pcx: &pat_ctxt, + pointer_kind: PointerKind, + inner: @ast::pat, + pat_id: ast::node_id, + span: span, + expected: ty::t) { + let fcx = pcx.fcx; + let check_inner: &fn(ty::mt) = |e_inner| { + check_pat(pcx, inner, e_inner.ty); + fcx.write_ty(pat_id, expected); + }; + match structure_of(fcx, span, expected) { + ty::ty_box(e_inner) if pointer_kind == Managed => { + check_inner(e_inner); + } + ty::ty_uniq(e_inner) if pointer_kind == Owned => { + check_inner(e_inner); + } + ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { + check_inner(e_inner); + } + _ => { + check_pat(pcx, inner, ty::mk_err()); + fcx.infcx().type_error_message_str_with_expected( + span, + |expected, actual| { + expected.map_default(~"", |&e| { + fmt!("mismatched types: expected `%s` but found %s", + e, actual)})}, + Some(expected), + fmt!("%s pattern", match pointer_kind { + Managed => "an @-box", + Owned => "a ~-box", + Borrowed => "an &-pointer" + }), + None); + fcx.write_error(pat_id); + } + } +} + +#[deriving(Eq)] +enum PointerKind { Managed, Owned, Borrowed } diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 1bb71c156c3dc..3fa551e4b057a 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -66,5 +66,3 @@ pub fn coerce(fcx: @mut FnCtxt, } } } - - diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index fb5b53d9400fb..08398f9880a40 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -119,7 +119,8 @@ pub fn lookup( // In a call `a.b::(...)`: expr: @ast::expr, // The expression `a.b(...)`. self_expr: @ast::expr, // The expression `a`. - callee_id: node_id, // Where to store `a.b`'s type + callee_id: node_id, /* Where to store `a.b`'s type, + * also the scope of the call */ m_name: ast::ident, // The ident `b`. self_ty: ty::t, // The type of `a`. supplied_tps: &[ty::t], // The list of types X, Y, ... . @@ -127,7 +128,7 @@ pub fn lookup( check_traits: CheckTraitsFlag, // Whether we check traits only. autoderef_receiver: AutoderefReceiverFlag) -> Option { - let mut impl_dups = HashSet::new(); + let impl_dups = @mut HashSet::new(); let lcx = LookupContext { fcx: fcx, expr: expr, @@ -135,7 +136,7 @@ pub fn lookup( callee_id: callee_id, m_name: m_name, supplied_tps: supplied_tps, - impl_dups: &mut impl_dups, + impl_dups: impl_dups, inherent_candidates: @mut ~[], extension_candidates: @mut ~[], deref_args: deref_args, @@ -154,7 +155,7 @@ pub struct LookupContext<'self> { callee_id: node_id, m_name: ast::ident, supplied_tps: &'self [ty::t], - impl_dups: &'self mut HashSet, + impl_dups: @mut HashSet, inherent_candidates: @mut ~[Candidate], extension_candidates: @mut ~[Candidate], deref_args: check::DerefArgs, @@ -640,7 +641,7 @@ pub impl<'self> LookupContext<'self> { /*! * * In the event that we are invoking a method with a receiver - * of a linear borrowed type like `&mut T` or `&mut [T]`, + * of a borrowed type like `&T`, `&mut T`, or `&mut [T]`, * we will "reborrow" the receiver implicitly. For example, if * you have a call `r.inc()` and where `r` has type `&mut T`, * then we treat that like `(&mut *r).inc()`. This avoids @@ -657,26 +658,25 @@ pub impl<'self> LookupContext<'self> { let tcx = self.tcx(); return match ty::get(self_ty).sty { - ty::ty_rptr(_, self_mt) if self_mt.mutbl == m_mutbl => { - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => { + (self_ty, + ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None})) + } + ty::ty_rptr(_, self_mt) => { + let region = self.infcx().next_region_var_nb(self.expr.span); (ty::mk_rptr(tcx, region, self_mt), ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs+1, - autoref: Some(ty::AutoRef {kind: AutoPtr, - region: region, - mutbl: self_mt.mutbl})})) + autoref: Some(ty::AutoPtr(region, self_mt.mutbl))})) } - ty::ty_evec(self_mt, vstore_slice(_)) - if self_mt.mutbl == m_mutbl => { - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + ty::ty_evec(self_mt, vstore_slice(_)) => { + let region = self.infcx().next_region_var_nb(self.expr.span); (ty::mk_evec(tcx, self_mt, vstore_slice(region)), ty::AutoDerefRef(ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoRef {kind: AutoBorrowVec, - region: region, - mutbl: self_mt.mutbl})})) + autoderefs: autoderefs, + autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))})) } _ => { (self_ty, @@ -685,6 +685,16 @@ pub impl<'self> LookupContext<'self> { autoref: None})) } }; + + fn default_method_hack(self_mt: ty::mt) -> bool { + // FIXME(#6129). Default methods can't deal with autoref. + // + // I am a horrible monster and I pray for death. Currently + // the default method code fails when you try to reborrow + // because it is not handling types correctly. In lieu of + // fixing that, I am introducing this horrible hack. - ndm + self_mt.mutbl == m_imm && ty::type_is_self(self_mt.ty) + } } fn search_for_autosliced_method( @@ -793,7 +803,7 @@ pub impl<'self> LookupContext<'self> { fn search_for_some_kind_of_autorefd_method( &self, - kind: AutoRefKind, + kind: &fn(Region, ast::mutability) -> ty::AutoRef, autoderefs: uint, mutbls: &[ast::mutability], mk_autoref_ty: &fn(ast::mutability, ty::Region) -> ty::t) @@ -801,8 +811,7 @@ pub impl<'self> LookupContext<'self> { { // This is hokey. We should have mutability inference as a // variable. But for now, try &const, then &, then &mut: - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + let region = self.infcx().next_region_var_nb(self.expr.span); for mutbls.each |mutbl| { let autoref_ty = mk_autoref_ty(*mutbl, region); match self.search_for_method(autoref_ty) { @@ -812,12 +821,7 @@ pub impl<'self> LookupContext<'self> { self.self_expr.id, @ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoRef { - kind: kind, - region: region, - mutbl: *mutbl, - }), - })); + autoref: Some(kind(region, *mutbl))})); return Some(mme); } } @@ -872,7 +876,7 @@ pub impl<'self> LookupContext<'self> { if relevant_candidates.len() > 1 { self.tcx().sess.span_err( self.expr.span, - ~"multiple applicable methods in scope"); + "multiple applicable methods in scope"); for uint::range(0, relevant_candidates.len()) |idx| { self.report_candidate(idx, &relevant_candidates[idx].origin); } @@ -983,12 +987,12 @@ pub impl<'self> LookupContext<'self> { } else if num_method_tps == 0u { tcx.sess.span_err( self.expr.span, - ~"this method does not take type parameters"); + "this method does not take type parameters"); self.fcx.infcx().next_ty_vars(num_method_tps) } else if num_supplied_tps != num_method_tps { tcx.sess.span_err( self.expr.span, - ~"incorrect number of type \ + "incorrect number of type \ parameters given for this method"); self.fcx.infcx().next_ty_vars(num_method_tps) } else { @@ -1024,8 +1028,7 @@ pub impl<'self> LookupContext<'self> { let (_, opt_transformed_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, - |_br| self.fcx.infcx().next_region_var( - self.expr.span, self.expr.id)); + |_br| self.fcx.infcx().next_region_var_nb(self.expr.span)); let transformed_self_ty = opt_transformed_self_ty.get(); 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)); @@ -1082,14 +1085,14 @@ pub impl<'self> LookupContext<'self> { if ty::type_has_self(method_fty) { self.tcx().sess.span_err( self.expr.span, - ~"cannot call a method whose type contains a \ - self-type through a boxed trait"); + "cannot call a method whose type contains a \ + self-type through a boxed trait"); } if candidate.method_ty.generics.has_type_params() { self.tcx().sess.span_err( self.expr.span, - ~"cannot call a generic method through a boxed trait"); + "cannot call a generic method through a boxed trait"); } } @@ -1109,7 +1112,7 @@ pub impl<'self> LookupContext<'self> { if bad { self.tcx().sess.span_err(self.expr.span, - ~"explicit call to destructor"); + "explicit call to destructor"); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b9f3de873cf07..2096299f2cff5 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -207,9 +207,11 @@ pub impl PurityState { } pub struct FnCtxt { - // var_bindings, locals and next_var_id are shared - // with any nested functions that capture the environment - // (and with any functions whose environment is being captured). + // Number of errors that had been reported when we started + // checking this function. On exit, if we find that *more* errors + // have been reported, we will skip regionck and other work that + // expects the types within the function to be consistent. + err_count_on_creation: uint, ret_ty: ty::t, // Used by loop bodies that return from the outer function @@ -263,6 +265,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, // It's kind of a kludge to manufacture a fake function context // and statement context, but we might as well do write the code only once @mut FnCtxt { + err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, indirect_ret_ty: None, ps: PurityState::function(ast::pure_fn, 0), @@ -328,6 +331,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, */ let tcx = ccx.tcx; + let err_count_on_creation = tcx.sess.err_count(); // ______________________________________________________________________ // First, we have to replace any bound regions in the fn and self @@ -368,6 +372,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, }; @mut FnCtxt { + err_count_on_creation: err_count_on_creation, ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, ps: PurityState::function(purity, id), @@ -433,7 +438,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, assign(self_info.self_id, Some(self_info.self_ty)); debug!("self is assigned to %s", fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&self_info.self_id))); + fcx.inh.locals.get_copy(&self_info.self_id))); } // Add formal parameters. @@ -466,7 +471,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, debug!("Local variable %s is assigned type %s", fcx.pat_to_str(local.node.pat), fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&local.node.id))); + fcx.inh.locals.get_copy(&local.node.id))); visit::visit_local(local, e, v); }; @@ -479,7 +484,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, debug!("Pattern binding %s is assigned to %s", *tcx.sess.str_of(path.idents[0]), fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&p.id))); + fcx.inh.locals.get_copy(&p.id))); } _ => {} } @@ -542,47 +547,28 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, let (id, sp) = *p; let orig_sp = field_names.find(&id).map_consume(|x| *x); match orig_sp { - Some(orig_sp) => { - tcx.sess.span_err(sp, fmt!("Duplicate field \ - name %s in record type declaration", - *tcx.sess.str_of(id))); - tcx.sess.span_note(orig_sp, ~"First declaration of \ - this field occurred here"); - break; - } - None => { - field_names.insert(id, sp); - } + Some(orig_sp) => { + tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration", + *tcx.sess.str_of(id))); + tcx.sess.span_note(orig_sp, "First declaration of this field occurred here"); + break; + } + None => { + field_names.insert(id, sp); + } } } } -pub fn check_struct(ccx: @mut CrateCtxt, - struct_def: @ast::struct_def, - id: ast::node_id, - span: span) { +pub fn check_struct(ccx: @mut CrateCtxt, id: ast::node_id, span: span) { let tcx = ccx.tcx; - let self_ty = ty::node_id_to_type(tcx, id); - - for struct_def.dtor.each |dtor| { - let class_t = SelfInfo { - self_ty: self_ty, - self_id: dtor.node.self_id, - span: dtor.span, - }; - // typecheck the dtor - let dtor_dec = ast_util::dtor_dec(); - check_bare_fn( - ccx, - &dtor_dec, - &dtor.node.body, - dtor.node.id, - Some(class_t) - ); - }; // Check that the class is instantiable - check_instantiable(ccx.tcx, span, id); + check_instantiable(tcx, span, id); + + if ty::lookup_simd(tcx, local_def(id)) { + check_simd(tcx, span, id); + } } pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { @@ -623,8 +609,8 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } } } - ast::item_struct(struct_def, _) => { - check_struct(ccx, struct_def, it.id, it.span); + ast::item_struct(*) => { + check_struct(ccx, it.id, it.span); } ast::item_ty(t, ref generics) => { let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id); @@ -667,7 +653,12 @@ impl AstConv for FnCtxt { } pub impl FnCtxt { - fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx } + fn infcx(&self) -> @mut infer::InferCtxt { + self.inh.infcx + } + fn err_count_since_creation(&self) -> uint { + self.ccx.tcx.sess.err_count() - self.err_count_on_creation + } fn search_in_scope_regions( &self, span: span, @@ -837,6 +828,7 @@ pub impl FnCtxt { } } + #[cfg(stage0)] fn opt_node_ty_substs(&self, id: ast::node_id, f: &fn(&ty::substs) -> bool) { match self.inh.node_type_substs.find(&id) { @@ -844,6 +836,14 @@ pub impl FnCtxt { None => () } } + #[cfg(not(stage0))] + fn opt_node_ty_substs(&self, id: ast::node_id, + f: &fn(&ty::substs) -> bool) -> bool { + match self.inh.node_type_substs.find(&id) { + Some(s) => f(s), + None => true + } + } fn mk_subty(&self, a_is_expected: bool, @@ -923,11 +923,9 @@ pub impl FnCtxt { fn region_var_if_parameterized(&self, rp: Option, - span: span, - lower_bound: ty::Region) + span: span) -> Option { - rp.map( - |_rp| self.infcx().next_region_var_with_lb(span, lower_bound)) + rp.map(|_rp| self.infcx().next_region_var_nb(span)) } fn type_error_message(&self, @@ -1108,8 +1106,7 @@ pub fn impl_self_ty(vcx: &VtableContext, }; let self_r = if region_param.is_some() { - Some(vcx.infcx.next_region_var(location_info.span, - location_info.id)) + Some(vcx.infcx.next_region_var_nb(location_info.span)) } else { None }; @@ -1275,8 +1272,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::ty_rptr(_, mt) => formal_ty = mt.ty, ty::ty_err => (), _ => { - fcx.ccx.tcx.sess.span_bug(arg.span, - ~"no ref"); + fcx.ccx.tcx.sess.span_bug(arg.span, "no ref"); } } } @@ -1307,6 +1303,26 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // The callee checks for bot / err, we don't need to } + fn write_call(fcx: @mut FnCtxt, + call_expr: @ast::expr, + output: ty::t, + sugar: ast::CallSugar) { + let ret_ty = match sugar { + ast::ForSugar => { + match ty::get(output).sty { + ty::ty_bool => {} + _ => fcx.type_error_message(call_expr.span, |actual| { + fmt!("expected `for` closure to return `bool`, \ + but found `%s`", actual) }, + output, None) + } + ty::mk_nil() + } + _ => output + }; + fcx.write_ty(call_expr.id, ret_ty); + } + // A generic function for doing all of the checking for call expressions fn check_call(fcx: @mut FnCtxt, call_expr: @ast::expr, @@ -1317,24 +1333,19 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // that they appear in call position. check_expr(fcx, f); + // Store the type of `f` as the type of the callee + let fn_ty = fcx.expr_ty(f); + + // FIXME(#6273) should write callee type AFTER regions have + // been subst'd. However, it is awkward to deal with this + // now. Best thing would I think be to just have a separate + // "callee table" that contains the FnSig and not a general + // purpose ty::t + fcx.write_ty(call_expr.callee_id, fn_ty); // Extract the function signature from `in_fty`. - let fn_ty = fcx.expr_ty(f); let fn_sty = structure_of(fcx, f.span, fn_ty); - // FIXME(#3678) For now, do not permit calls to C abi functions. - match fn_sty { - ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { - if !abis.is_rust() { - fcx.tcx().sess.span_err( - call_expr.span, - fmt!("Calls to C ABI functions are not (yet) \ - supported; be patient, dear user")); - } - } - _ => {} - } - let fn_sig = match fn_sty { ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) | ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig, @@ -1356,14 +1367,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let (_, _, fn_sig) = replace_bound_regions_in_fn_sig( fcx.tcx(), @Nil, None, &fn_sig, - |_br| fcx.infcx().next_region_var(call_expr.span, call_expr.id)); + |_br| fcx.infcx().next_region_var_nb(call_expr.span)); // Call the generic checker. check_argument_types(fcx, call_expr.span, fn_sig.inputs, f, args, sugar, DontDerefArgs); - // Pull the return type out of the type of the function. - fcx.write_ty(call_expr.id, fn_sig.output); + write_call(fcx, call_expr, fn_sig.output, sugar); } // Checks a method call. @@ -1419,8 +1429,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fn_ty, expr, args, sugar, DontDerefArgs); - // Pull the return type out of the type of the function. - fcx.write_ty(expr.id, ret_ty); + write_call(fcx, expr, ret_ty, sugar); } // A generic function for checking the then and else in an if @@ -1568,7 +1577,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, lhs_resolved_t, None) }; return lookup_op_method(fcx, ex, lhs_expr, lhs_resolved_t, - fcx.tcx().sess.ident_of(copy *name), + fcx.tcx().sess.ident_of(*name), ~[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound, expected_result); } @@ -1582,8 +1591,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, match ty::get(lhs_resolved_t).sty { ty::ty_bare_fn(_) | ty::ty_closure(_) => { tcx.sess.span_note( - ex.span, ~"did you forget the `do` keyword \ - for the call?"); + ex.span, "did you forget the `do` keyword for the call?"); } _ => () } @@ -1593,8 +1601,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } fn check_user_unop(fcx: @mut FnCtxt, - op_str: ~str, - mname: ~str, + op_str: &str, + mname: &str, ex: @ast::expr, rhs_expr: @ast::expr, rhs_t: ty::t, @@ -1678,7 +1686,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, }; // construct the function type - let mut fn_ty = astconv::ty_of_closure(fcx, + let fn_ty = astconv::ty_of_closure(fcx, fcx, sigil, purity, @@ -1689,7 +1697,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, &opt_vec::Empty, expr.span); - let mut fty_sig; + let fty_sig; let fty = if error_happened { fty_sig = FnSig { bound_lifetime_names: opt_vec::Empty, @@ -1874,9 +1882,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, tcx.sess.span_err(span, fmt!("missing field%s: %s", if missing_fields.len() == 1 { - ~"" + "" } else { - ~"s" + "s" }, str::connect(missing_fields, ~", "))); } @@ -1924,7 +1932,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } _ => { tcx.sess.span_bug(span, - ~"resolve didn't map this to a class"); + "resolve didn't map this to a class"); } } } else { @@ -1936,9 +1944,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Generate the struct type. let self_region = - fcx.region_var_if_parameterized(region_parameterized, - span, - ty::re_scope(id)); + fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { self_r: self_region, @@ -2012,7 +2018,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } _ => { tcx.sess.span_bug(span, - ~"resolve didn't map this to an enum"); + "resolve didn't map this to an enum"); } } } else { @@ -2024,9 +2030,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Generate the enum type. let self_region = - fcx.region_var_if_parameterized(region_parameterized, - span, - ty::re_scope(id)); + fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { self_r: self_region, @@ -2224,7 +2228,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } _ => - tcx.sess.span_bug(expr.span, ~"vstore modifier on non-sequence") + tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence") }; fcx.write_ty(ev.id, typ); fcx.write_ty(id, typ); @@ -2307,21 +2311,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::ty_enum(*) => { tcx.sess.span_err( expr.span, - ~"can only dereference enums \ - with a single variant which has a \ - single argument"); + "can only dereference enums with a single variant which \ + has a single argument"); } ty::ty_struct(*) => { tcx.sess.span_err( expr.span, - ~"can only dereference structs with \ - one anonymous field"); + "can only dereference structs with one anonymous field"); } _ => { fcx.type_error_message(expr.span, |actual| { - fmt!("type %s cannot be \ - dereferenced", actual) + fmt!("type %s cannot be dereferenced", actual) }, oprnd_t, None); } } @@ -2334,7 +2335,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, if !(ty::type_is_integral(oprnd_t) || ty::get(oprnd_t).sty == ty::ty_bool) { oprnd_t = check_user_unop(fcx, - ~"!", ~"not", expr, oprnd, oprnd_t, + "!", "not", expr, oprnd, oprnd_t, expected); } } @@ -2344,7 +2345,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, if !(ty::type_is_integral(oprnd_t) || ty::type_is_fp(oprnd_t)) { oprnd_t = check_user_unop(fcx, - ~"-", ~"neg", expr, oprnd, oprnd_t, expected); + "-", "neg", expr, oprnd, oprnd_t, expected); } } } @@ -2366,13 +2367,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // (and how long it is valid), which we don't know yet until type // inference is complete. // - // Therefore, here we simply generate a region variable with - // the current expression as a lower bound. The region - // inferencer will then select the ultimate value. Finally, - // borrowck is charged with guaranteeing that the value whose - // address was taken can actually be made to live as long as - // it needs to live. - let region = fcx.infcx().next_region_var(expr.span, expr.id); + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + let region = fcx.infcx().next_region_var_nb(expr.span); let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { @@ -2389,8 +2389,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let defn = lookup_def(fcx, pth.span, id); let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); - let region_lb = ty::re_scope(expr.id); - instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb); + instantiate_path(fcx, pth, tpt, expr.span, expr.id); + } + ast::expr_self => { + let definition = lookup_def(fcx, expr.span, id); + let ty_param_bounds_and_ty = + ty_param_bounds_and_ty_for_def(fcx, expr.span, definition); + fcx.write_ty(id, ty_param_bounds_and_ty.ty); } ast::expr_inline_asm(ref ia) => { fcx.require_unsafe(expr.span, ~"use of inline assembly"); @@ -2417,7 +2422,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, result::Err(_) => { tcx.sess.span_err( expr.span, - ~"`return;` in function returning non-nil"); + "`return;` in function returning non-nil"); } }, Some(e) => { @@ -2461,20 +2466,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_nil(id); } } - ast::expr_swap(lhs, rhs) => { - check_assignment(fcx, lhs, rhs, id); - let lhs_ty = fcx.expr_ty(lhs); - let rhs_ty = fcx.expr_ty(rhs); - if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) { - fcx.write_error(id); - } - else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) { - fcx.write_bot(id); - } - else { - fcx.write_nil(id); - } - } ast::expr_if(cond, ref thn, elsopt) => { check_expr_has_type(fcx, cond, ty::mk_bool()); check_then_else(fcx, thn, elsopt, id, expr.span); @@ -2781,8 +2772,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, variant_id, *fields); } _ => { - tcx.sess.span_bug(path.span, ~"structure constructor does \ - not name a structure type"); + tcx.sess.span_bug(path.span, + "structure constructor does not name a structure type"); } } } @@ -2811,7 +2802,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let resolved = structurally_resolved_type(fcx, expr.span, raw_base_t); - let index_ident = tcx.sess.ident_of(~"index"); + let index_ident = tcx.sess.ident_of("index"); let error_message = || { fcx.type_error_message(expr.span, |actual| { @@ -2966,7 +2957,8 @@ pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::blk) { pub fn check_block_with_expected(fcx: @mut FnCtxt, blk: &ast::blk, expected: Option) { - let prev = replace(&mut fcx.ps, fcx.ps.recurse(blk)); + let purity_state = fcx.ps.recurse(blk); + let prev = replace(&mut fcx.ps, purity_state); do fcx.with_region_lb(blk.node.id) { let mut warned = false; @@ -2984,7 +2976,7 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, } _ => false } { - fcx.ccx.tcx.sess.span_warn(s.span, ~"unreachable statement"); + fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement"); warned = true; } if ty::type_is_bot(s_ty) { @@ -3005,7 +2997,7 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, }, Some(e) => { if any_bot && !warned { - fcx.ccx.tcx.sess.span_warn(e.span, ~"unreachable expression"); + fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); } check_expr_with_opt_hint(fcx, e, expected); let ety = fcx.expr_ty(e); @@ -3067,6 +3059,35 @@ pub fn check_instantiable(tcx: ty::ctxt, } } +pub fn check_simd(tcx: ty::ctxt, sp: span, id: ast::node_id) { + let t = ty::node_id_to_type(tcx, id); + if ty::type_needs_subst(t) { + tcx.sess.span_err(sp, "SIMD vector cannot be generic"); + return; + } + match ty::get(t).sty { + ty::ty_struct(did, ref substs) => { + let fields = ty::lookup_struct_fields(tcx, did); + if fields.is_empty() { + tcx.sess.span_err(sp, "SIMD vector cannot be empty"); + return; + } + let e = ty::lookup_field_type(tcx, did, fields[0].id, substs); + if !vec::all(fields, + |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) { + tcx.sess.span_err(sp, "SIMD vector should be homogeneous"); + return; + } + if !ty::type_is_machine(e) { + tcx.sess.span_err(sp, "SIMD vector element type should be \ + machine type"); + return; + } + } + _ => () + } +} + pub fn check_enum_variants(ccx: @mut CrateCtxt, sp: span, vs: &[ast::variant], @@ -3096,8 +3117,8 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, *disr_val = val as int; } Ok(_) => { - ccx.tcx.sess.span_err(e.span, ~"expected signed integer \ - constant"); + ccx.tcx.sess.span_err(e.span, "expected signed integer \ + constant"); } Err(ref err) => { ccx.tcx.sess.span_err(e.span, @@ -3108,7 +3129,7 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, } if vec::contains(*disr_vals, &*disr_val) { ccx.tcx.sess.span_err(v.span, - ~"discriminator value already exists"); + "discriminator value already exists"); } disr_vals.push(*disr_val); let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id); @@ -3165,9 +3186,9 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, _ => false } }) { - ccx.tcx.sess.span_err(sp, ~"illegal recursive enum type; \ - wrap the inner value in a box to \ - make it representable"); + ccx.tcx.sess.span_err(sp, + "illegal recursive enum type; \ + wrap the inner value in a box to make it representable"); } // Check that it is possible to instantiate this enum: @@ -3228,26 +3249,25 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*)=> { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type"); } ast::def_mod(*) | ast::def_foreign_mod(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found module"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module"); } ast::def_use(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found use"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use"); } ast::def_region(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found region"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region"); } ast::def_typaram_binder(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type \ - parameter"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter"); } ast::def_label(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found label"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label"); } ast::def_self_ty(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found self ty"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty"); } } } @@ -3258,8 +3278,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, pth: @ast::Path, tpt: ty_param_bounds_and_ty, span: span, - node_id: ast::node_id, - region_lb: ty::Region) { + node_id: ast::node_id) { debug!(">>> instantiate_path"); let ty_param_count = tpt.generics.type_param_defs.len(); @@ -3276,7 +3295,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, match tpt.generics.region_param { None => { // ...but the type is not lifetime parameterized! fcx.ccx.tcx.sess.span_err - (span, ~"this item is not region-parameterized"); + (span, "this item is not region-parameterized"); None } Some(_) => { // ...and the type is lifetime parameterized, ok. @@ -3285,8 +3304,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } } None => { // no lifetime parameter supplied, insert default - fcx.region_var_if_parameterized( - tpt.generics.region_param, span, region_lb) + fcx.region_var_if_parameterized(tpt.generics.region_param, span) } }; @@ -3296,15 +3314,15 @@ pub fn instantiate_path(fcx: @mut FnCtxt, fcx.infcx().next_ty_vars(ty_param_count) } else if ty_param_count == 0 { fcx.ccx.tcx.sess.span_err - (span, ~"this item does not take type parameters"); + (span, "this item does not take type parameters"); fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len > ty_param_count { fcx.ccx.tcx.sess.span_err - (span, ~"too many type parameters provided for this item"); + (span, "too many type parameters provided for this item"); fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len < ty_param_count { fcx.ccx.tcx.sess.span_err - (span, ~"not enough type parameters provided for this item"); + (span, "not enough type parameters provided for this item"); fcx.infcx().next_ty_vars(ty_param_count) } else { pth.types.map(|aty| fcx.to_ty(*aty)) @@ -3370,7 +3388,7 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt, ast::expr_vstore_uniq => ty::vstore_uniq, ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box, ast::expr_vstore_slice | ast::expr_vstore_mut_slice => { - let r = fcx.infcx().next_region_var(e.span, e.id); + let r = fcx.infcx().next_region_var_nb(e.span); ty::vstore_slice(r) } } @@ -3448,6 +3466,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ~"size_of" | ~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint()), ~"init" => (1u, ~[], param(ccx, 0u)), + ~"uninit" => (1u, ~[], param(ccx, 0u)), ~"forget" => (1u, ~[arg(param(ccx, 0u))], ty::mk_nil()), ~"transmute" => (2, ~[ arg(param(ccx, 0)) ], param(ccx, 1)), ~"move_val" | ~"move_val_init" => { @@ -3473,6 +3492,25 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ], ty::mk_int()) } + ~"atomic_load" | ~"atomic_load_acq" => { + (0, + ~[ + arg(ty::mk_imm_rptr(tcx, + ty::re_bound(ty::br_anon(0)), + ty::mk_int())) + ], + ty::mk_int()) + } + ~"atomic_store" | ~"atomic_store_rel" => { + (0, + ~[ + arg(ty::mk_mut_rptr(tcx, + ty::re_bound(ty::br_anon(0)), + ty::mk_int())), + arg(ty::mk_int()) + ], + ty::mk_nil()) + } ~"atomic_xchg" | ~"atomic_xadd" | ~"atomic_xsub" | ~"atomic_xchg_acq" | ~"atomic_xadd_acq" | ~"atomic_xsub_acq" | ~"atomic_xchg_rel" | ~"atomic_xadd_rel" | ~"atomic_xsub_rel" => { @@ -3493,7 +3531,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ~"visit_tydesc" => { let tydesc_name = special_idents::tydesc; assert!(tcx.intrinsic_defs.contains_key(&tydesc_name)); - let (_, tydesc_ty) = *tcx.intrinsic_defs.get(&tydesc_name); + let (_, tydesc_ty) = tcx.intrinsic_defs.get_copy(&tydesc_name); let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { ty: tydesc_ty, @@ -3630,7 +3668,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { }; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { purity: ast::unsafe_fn, - abis: AbiSet::Rust(), + abis: AbiSet::Intrinsic(), sig: FnSig {bound_lifetime_names: opt_vec::Empty, inputs: inputs, output: output} diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index cb2b854276d6f..ecec07ec51287 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -28,16 +28,15 @@ this point a bit better. */ use middle::freevars::get_freevars; -use middle::pat_util::pat_bindings; use middle::ty::{re_scope}; use middle::ty; use middle::typeck::check::FnCtxt; -use middle::typeck::check::lookup_def; use middle::typeck::check::regionmanip::relate_nested_regions; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; use util::ppaux::{note_and_explain_region, ty_to_str, region_to_str}; +use middle::pat_util; use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil}; use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar}; @@ -73,7 +72,11 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region { } pub impl Rcx { - fn resolve_type(@mut self, unresolved_ty: ty::t) -> ty::t { + fn tcx(&self) -> ty::ctxt { + self.fcx.ccx.tcx + } + + fn resolve_type(&mut self, unresolved_ty: ty::t) -> ty::t { /*! * Try to resolve the type for the given node, returning * t_err if an error results. Note that we never care @@ -115,6 +118,7 @@ pub impl Rcx { } /// Try to resolve the type for the given node. + #[config(stage0)] fn resolve_expr_type_adjusted(@mut self, expr: @ast::expr) -> ty::t { let ty_unadjusted = self.resolve_node_type(expr.id); if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) { @@ -122,37 +126,67 @@ pub impl Rcx { } else { let tcx = self.fcx.tcx(); let adjustments = self.fcx.inh.adjustments; - match adjustments.find(&expr.id) { + match adjustments.find_copy(&expr.id) { None => ty_unadjusted, - Some(&adjustment) => { - // FIXME(#3850) --- avoid region scoping errors - ty::adjust_ty(tcx, expr.span, ty_unadjusted, Some(&adjustment)) + Some(adjustment) => { + ty::adjust_ty(tcx, expr.span, ty_unadjusted, + Some(adjustment)) } } } } + + /// Try to resolve the type for the given node. + #[config(not(stage0))] + fn resolve_expr_type_adjusted(@mut self, expr: @ast::expr) -> ty::t { + let ty_unadjusted = self.resolve_node_type(expr.id); + if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) { + ty_unadjusted + } else { + let tcx = self.fcx.tcx(); + let adjustments = self.fcx.inh.adjustments; + ty::adjust_ty(tcx, expr.span, ty_unadjusted, + adjustments.find_copy(&expr.id)) + } + } } pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - let v = regionck_visitor(); - (v.visit_expr)(e, rcx, v); + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + let v = regionck_visitor(); + (v.visit_expr)(e, rcx, v); + } fcx.infcx().resolve_regions(); } pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - let v = regionck_visitor(); - (v.visit_block)(blk, rcx, v); + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + let v = regionck_visitor(); + (v.visit_block)(blk, rcx, v); + } fcx.infcx().resolve_regions(); } fn regionck_visitor() -> rvt { + // (*) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, + // However, right now we run into an issue whereby some free + // regions are not properly related if they appear within the + // types of arguments that must be inferred. This could be + // addressed by deferring the construction of the region + // hierarchy, and in particular the relationships between free + // regions, until regionck, as described in #3238. visit::mk_vt(@visit::Visitor {visit_item: visit_item, - visit_stmt: visit_stmt, visit_expr: visit_expr, - visit_block: visit_block, + + //visit_pat: visit_pat, // (*) see above + visit_arm: visit_arm, visit_local: visit_local, + + visit_block: visit_block, .. *visit::default_visitor()}) } @@ -160,44 +194,110 @@ fn visit_item(_item: @ast::item, _rcx: @mut Rcx, _v: rvt) { // Ignore items } -fn visit_local(l: @ast::local, rcx: @mut Rcx, v: rvt) { - // Check to make sure that the regions in all local variables are - // within scope. - // - // Note: we do this here rather than in visit_pat because we do - // not wish to constrain the regions in *patterns* in quite the - // same way. `visit_node()` guarantees that the region encloses - // the node in question, which ultimately constrains the regions - // in patterns to enclose the match expression as a whole. But we - // want them to enclose the *arm*. However, regions in patterns - // must either derive from the discriminant or a ref pattern: in - // the case of the discriminant, the regions will be constrained - // when the type of the discriminant is checked. In the case of a - // ref pattern, the variable is created with a suitable lower - // bound. - let e = rcx.errors_reported; - (v.visit_pat)(l.node.pat, rcx, v); - let def_map = rcx.fcx.ccx.tcx.def_map; - do pat_bindings(def_map, l.node.pat) |_bm, id, sp, _path| { - visit_node(id, sp, rcx); - } - if e != rcx.errors_reported { - return; // if decl has errors, skip initializer expr - } +fn visit_block(b: &ast::blk, rcx: @mut Rcx, v: rvt) { + rcx.fcx.tcx().region_maps.record_cleanup_scope(b.node.id); + visit::visit_block(b, rcx, v); +} - (v.visit_ty)(l.node.ty, rcx, v); - for l.node.init.each |i| { - (v.visit_expr)(*i, rcx, v); +fn visit_arm(arm: &ast::arm, rcx: @mut Rcx, v: rvt) { + // see above + for arm.pats.each |&p| { + constrain_bindings_in_pat(p, rcx); } + + visit::visit_arm(arm, rcx, v); } -fn visit_block(b: &ast::blk, rcx: @mut Rcx, v: rvt) { - visit::visit_block(b, rcx, v); +fn visit_local(l: @ast::local, rcx: @mut Rcx, v: rvt) { + // see above + constrain_bindings_in_pat(l.node.pat, rcx); + visit::visit_local(l, rcx, v); +} + +fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) { + let tcx = rcx.fcx.tcx(); + debug!("regionck::visit_pat(pat=%s)", pat.repr(tcx)); + do pat_util::pat_bindings(tcx.def_map, pat) |_, id, span, _| { + // If we have a variable that contains region'd data, that + // data will be accessible from anywhere that the variable is + // accessed. We must be wary of loops like this: + // + // // from src/test/compile-fail/borrowck-lend-flow.rs + // let mut v = ~3, w = ~4; + // let mut x = &mut w; + // loop { + // **x += 1; // (2) + // borrow(v); //~ ERROR cannot borrow + // x = &mut v; // (1) + // } + // + // Typically, we try to determine the region of a borrow from + // those points where it is dereferenced. In this case, one + // might imagine that the lifetime of `x` need only be the + // body of the loop. But of course this is incorrect because + // the pointer that is created at point (1) is consumed at + // point (2), meaning that it must be live across the loop + // iteration. The easiest way to guarantee this is to require + // that the lifetime of any regions that appear in a + // variable's type enclose at least the variable's scope. + + let encl_region = tcx.region_maps.encl_region(id); + constrain_regions_in_type_of_node(rcx, id, encl_region, span); + } } fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { debug!("regionck::visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + let has_method_map = rcx.fcx.inh.method_map.contains_key(&expr.id); + + // Record cleanup scopes, which are used by borrowck to decide the + // maximum lifetime of a temporary rvalue. These were derived by + // examining where trans creates block scopes, not because this + // reflects some principled decision around temporary lifetimes. + // Ordinarily this would seem like something that should be setup + // in region, but we need to know which uses of operators are + // overloaded. See #3511. + let tcx = rcx.fcx.tcx(); + match expr.node { + // You'd think that x += y where `+=` is overloaded would be a + // cleanup scope. You'd be... kind of right. In fact the + // handling of `+=` and friends in trans for overloaded + // operators is a hopeless mess and I can't figure out how to + // represent it. - ndm + // + // ast::expr_assign_op(*) | + + ast::expr_index(*) | + ast::expr_binary(*) | + ast::expr_unary(*) if has_method_map => { + tcx.region_maps.record_cleanup_scope(expr.id); + } + ast::expr_binary(ast::and, lhs, rhs) | + ast::expr_binary(ast::or, lhs, rhs) => { + tcx.region_maps.record_cleanup_scope(lhs.id); + tcx.region_maps.record_cleanup_scope(rhs.id); + } + ast::expr_call(*) | + ast::expr_method_call(*) => { + tcx.region_maps.record_cleanup_scope(expr.id); + } + ast::expr_match(_, ref arms) => { + tcx.region_maps.record_cleanup_scope(expr.id); + for arms.each |arm| { + for arm.guard.each |guard| { + tcx.region_maps.record_cleanup_scope(guard.id); + } + } + } + ast::expr_while(cond, ref body) => { + tcx.region_maps.record_cleanup_scope(cond.id); + tcx.region_maps.record_cleanup_scope(body.node.id); + } + _ => {} + } + + // Check any autoderefs or autorefs that appear. for rcx.fcx.inh.adjustments.find(&expr.id).each |&adjustment| { debug!("adjustment=%?", adjustment); match *adjustment { @@ -208,6 +308,13 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { constrain_derefs(rcx, expr, autoderefs, expr_ty); for opt_autoref.each |autoref| { guarantor::for_autoref(rcx, expr, autoderefs, autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + constrain_regions_in_type_of_node( + rcx, expr.id, ty::re_scope(expr.id), expr.span); } } _ => {} @@ -215,58 +322,40 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } match expr.node { - ast::expr_path(*) => { - // Avoid checking the use of local variables, as we - // already check their definitions. The def'n always - // encloses the use. So if the def'n is enclosed by the - // region, then the uses will also be enclosed (and - // otherwise, an error will have been reported at the - // def'n site). - match lookup_def(rcx.fcx, expr.span, expr.id) { - ast::def_local(*) | ast::def_arg(*) | - ast::def_upvar(*) => return, - _ => () - } + ast::expr_call(callee, ref args, _) => { + constrain_callee(rcx, expr, callee); + constrain_call(rcx, expr, None, *args, false); } - ast::expr_call(callee, ref args, _) => { - // Check for a.b() where b is a method. Ensure that - // any types in the callee are valid for the entire - // method call. - - // FIXME(#3387)--we should really invoke - // `constrain_auto_ref()` on all exprs. But that causes a - // lot of spurious errors because of how the region - // hierarchy is setup. - if rcx.fcx.inh.method_map.contains_key(&callee.id) { - match callee.node { - ast::expr_field(base, _, _) => { - constrain_auto_ref(rcx, base); - } - _ => { - // This can happen if you have code like - // (x[0])() where `x[0]` is overloaded. Just - // ignore it. - } - } - } else { - constrain_auto_ref(rcx, callee); - } + ast::expr_method_call(arg0, _, _, ref args, _) => { + constrain_call(rcx, expr, Some(arg0), *args, false); + } - for args.each |arg| { - constrain_auto_ref(rcx, *arg); - } + ast::expr_index(lhs, rhs) | + ast::expr_assign_op(_, lhs, rhs) | + ast::expr_binary(_, lhs, rhs) if has_method_map => { + // As `expr_method_call`, but the call is via an + // overloaded op. Note that we (sadly) currently use an + // implicit "by ref" sort of passing style here. This + // should be converted to an adjustment! + constrain_call(rcx, expr, Some(lhs), [rhs], true); } - ast::expr_method_call(rcvr, _, _, ref args, _) => { - // Check for a.b() where b is a method. Ensure that - // any types in the callee are valid for the entire - // method call. + ast::expr_unary(_, lhs) if has_method_map => { + // As above. + constrain_call(rcx, expr, Some(lhs), [], true); + } - constrain_auto_ref(rcx, rcvr); - for args.each |arg| { - constrain_auto_ref(rcx, *arg); - } + ast::expr_unary(ast::deref, base) => { + // For *a, the lifetime of a must enclose the deref + let base_ty = rcx.resolve_node_type(base.id); + constrain_derefs(rcx, expr, 1, base_ty); + } + + ast::expr_index(vec_expr, _) => { + // For a[b], the lifetime of a must enclose the deref + let vec_type = rcx.resolve_expr_type_adjusted(vec_expr); + constrain_index(rcx, expr, vec_type); } ast::expr_cast(source, _) => { @@ -294,18 +383,18 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } } - ast::expr_index(vec_expr, _) => { - let vec_type = rcx.resolve_expr_type_adjusted(vec_expr); - constrain_index(rcx, expr, vec_type); - } - - ast::expr_unary(ast::deref, base) => { - let base_ty = rcx.resolve_node_type(base.id); - constrain_derefs(rcx, expr, 1, base_ty); - } - ast::expr_addr_of(_, base) => { guarantor::for_addr_of(rcx, expr, base); + + // Require that when you write a `&expr` expression, the + // resulting pointer has a lifetime that encompasses the + // `&expr` expression itself. Note that we constraining + // the type of the node expr.id here *before applying + // adjustments*. + // + // FIXME(#6268) nested method calls requires that this rule change + let ty0 = rcx.resolve_node_type(expr.id); + constrain_regions_in_type(rcx, ty::re_scope(expr.id), expr.span, ty0); } ast::expr_match(discr, ref arms) => { @@ -313,6 +402,8 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } ast::expr_fn_block(*) => { + // The lifetime of a block fn must not outlive the variables + // it closes over let function_type = rcx.resolve_node_type(expr.id); match ty::get(function_type).sty { ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil, @@ -326,46 +417,101 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { _ => () } - if !visit_node(expr.id, expr.span, rcx) { return; } visit::visit_expr(expr, rcx, v); } -fn visit_stmt(s: @ast::stmt, rcx: @mut Rcx, v: rvt) { - visit::visit_stmt(s, rcx, v); -} +fn constrain_callee(rcx: @mut Rcx, + call_expr: @ast::expr, + callee_expr: @ast::expr) +{ + let tcx = rcx.fcx.tcx(); -fn visit_node(id: ast::node_id, span: span, rcx: @mut Rcx) -> bool { - /*! - * - * checks the type of the node `id` and reports an error if it - * references a region that is not in scope for that node. - * Returns false if an error is reported; this is used to cause us - * to cut off region checking for that subtree to avoid reporting - * tons of errors. */ - - let fcx = rcx.fcx; - - // find the region where this expr evaluation is taking place - let tcx = fcx.ccx.tcx; - let encl_region = match tcx.region_maps.opt_encl_scope(id) { - None => ty::re_static, - Some(r) => ty::re_scope(r) - }; - - // Otherwise, look at the type and see if it is a region pointer. - constrain_regions_in_type_of_node(rcx, id, encl_region, span) + let call_region = ty::re_scope(call_expr.id); + + let callee_ty = rcx.resolve_node_type(call_expr.callee_id); + match ty::get(callee_ty).sty { + ty::ty_bare_fn(*) => { } + ty::ty_closure(ref closure_ty) => { + match rcx.fcx.mk_subr(true, callee_expr.span, + call_region, closure_ty.region) { + result::Err(_) => { + tcx.sess.span_err( + callee_expr.span, + fmt!("cannot invoke closure outside of its lifetime")); + note_and_explain_region( + tcx, + "the closure is only valid for ", + closure_ty.region, + ""); + } + result::Ok(_) => {} + } + } + _ => { + // this should not happen, but it does if the program is + // erroneous + // + // tcx.sess.span_bug( + // callee_expr.span, + // fmt!("Calling non-function: %s", callee_ty.repr(tcx))); + } + } } -fn encl_region_or_static(rcx: @mut Rcx, expr: @ast::expr) -> ty::Region { - // FIXME(#3850) --- interactions with modes compel overly large granularity - // that is, we would probably prefer to just return re_scope(expr.id) - // here but we cannot just yet. +fn constrain_call(rcx: @mut Rcx, + // might be expr_call, expr_method_call, or an overloaded + // operator + call_expr: @ast::expr, + receiver: Option<@ast::expr>, + arg_exprs: &[@ast::expr], + implicitly_ref_args: bool) +{ + //! Invoked on every call site (i.e., normal calls, method calls, + //! and overloaded operators). Constrains the regions which appear + //! in the type of the function. Also constrains the regions that + //! appear in the arguments appropriately. let tcx = rcx.fcx.tcx(); - match tcx.region_maps.opt_encl_scope(expr.id) { - Some(s) => ty::re_scope(s), - None => ty::re_static // occurs in constants + debug!("constrain_call(call_expr=%s, implicitly_ref_args=%?)", + call_expr.repr(tcx), implicitly_ref_args); + let callee_ty = rcx.resolve_node_type(call_expr.callee_id); + let fn_sig = ty::ty_fn_sig(callee_ty); + + // `callee_region` is the scope representing the time in which the + // call occurs. + // + // FIXME(#6268) to support nested method calls, should be callee_id + let callee_scope = call_expr.id; + let callee_region = ty::re_scope(callee_scope); + + for arg_exprs.each |&arg_expr| { + // ensure that any regions appearing in the argument type are + // valid for at least the lifetime of the function: + constrain_regions_in_type_of_node( + rcx, arg_expr.id, callee_region, arg_expr.span); + + // unfortunately, there are two means of taking implicit + // references, and we need to propagate constraints as a + // result. modes are going away and the "DerefArgs" code + // should be ported to use adjustments + if implicitly_ref_args { + guarantor::for_by_ref(rcx, arg_expr, callee_scope); + } + } + + // as loop above, but for receiver + for receiver.each |&r| { + constrain_regions_in_type_of_node( + rcx, r.id, callee_region, r.span); + if implicitly_ref_args { + guarantor::for_by_ref(rcx, r, callee_scope); + } } + + // constrain regions that may appear in the return type to be + // valid for the function call: + constrain_regions_in_type( + rcx, callee_region, call_expr.span, fn_sig.output); } fn constrain_derefs(rcx: @mut Rcx, @@ -379,9 +525,8 @@ fn constrain_derefs(rcx: @mut Rcx, * pointer being derefenced, the lifetime of the pointer includes * the deref expr. */ - let tcx = rcx.fcx.tcx(); - let r_deref_expr = encl_region_or_static(rcx, deref_expr); + 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), @@ -390,19 +535,8 @@ fn constrain_derefs(rcx: @mut Rcx, match ty::get(derefd_ty).sty { ty::ty_rptr(r_ptr, _) => { - match rcx.fcx.mk_subr(true, deref_expr.span, r_deref_expr, r_ptr) { - result::Ok(*) => {} - result::Err(*) => { - tcx.sess.span_err( - deref_expr.span, - fmt!("dereference of reference outside its lifetime")); - note_and_explain_region( - tcx, - "the reference is only valid for ", - r_ptr, - ""); - } - } + mk_subregion_due_to_derefence(rcx, deref_expr.span, + r_deref_expr, r_ptr); } _ => {} @@ -417,6 +551,27 @@ fn constrain_derefs(rcx: @mut Rcx, } } +pub fn mk_subregion_due_to_derefence(rcx: @mut Rcx, + deref_span: span, + minimum_lifetime: ty::Region, + maximum_lifetime: ty::Region) { + match rcx.fcx.mk_subr(true, deref_span, + minimum_lifetime, maximum_lifetime) { + result::Ok(*) => {} + result::Err(*) => { + rcx.tcx().sess.span_err( + deref_span, + fmt!("dereference of reference outside its lifetime")); + note_and_explain_region( + rcx.tcx(), + "the reference is only valid for ", + maximum_lifetime, + ""); + } + } +} + + fn constrain_index(rcx: @mut Rcx, index_expr: @ast::expr, indexed_ty: ty::t) @@ -433,7 +588,7 @@ fn constrain_index(rcx: @mut Rcx, rcx.fcx.expr_to_str(index_expr), rcx.fcx.infcx().ty_to_str(indexed_ty)); - let r_index_expr = encl_region_or_static(rcx, index_expr); + let r_index_expr = ty::re_scope(index_expr.id); match ty::get(indexed_ty).sty { ty::ty_estr(ty::vstore_slice(r_ptr)) | ty::ty_evec(_, ty::vstore_slice(r_ptr)) => { @@ -456,83 +611,39 @@ fn constrain_index(rcx: @mut Rcx, } } -fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { - /*! - * - * If `expr` is auto-ref'd (e.g., as part of a borrow), then this - * function ensures that the lifetime of the resulting borrowed - * ptr includes at least the expression `expr`. */ - - debug!("constrain_auto_ref(expr=%s)", rcx.fcx.expr_to_str(expr)); - - let adjustment = rcx.fcx.inh.adjustments.find(&expr.id); - let region = match adjustment { - Some(&@ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: Some(ref auto_ref), _})) => { - auto_ref.region - } - _ => { return; } - }; - - let tcx = rcx.fcx.tcx(); - let encl_region = tcx.region_maps.encl_region(expr.id); - match rcx.fcx.mk_subr(true, expr.span, encl_region, region) { - result::Ok(()) => {} - result::Err(_) => { - // In practice, this cannot happen: `region` is always a - // region variable, and constraints on region variables - // are collected and then resolved later. However, I - // included the span_err() here (rather than, say, - // span_bug()) because it seemed more future-proof: if, - // for some reason, the code were to change so that in - // some cases `region` is not a region variable, then - // reporting an error would be the correct path. - tcx.sess.span_err( - expr.span, - ~"lifetime of borrowed pointer does not include \ - the expression being borrowed"); - note_and_explain_region( - tcx, - ~"lifetime of the borrowed pointer is", - region, - ~""); - rcx.errors_reported += 1; - } - } -} - -fn constrain_free_variables( - rcx: @mut Rcx, - region: ty::Region, - expr: @ast::expr) { +fn constrain_free_variables(rcx: @mut Rcx, + region: ty::Region, + expr: @ast::expr) { /*! - * * Make sure that all free variables referenced inside the closure - * outlive the closure itself. */ + * outlive the closure itself. + */ let tcx = rcx.fcx.ccx.tcx; + debug!("constrain_free_variables(%s, %s)", + region.repr(tcx), expr.repr(tcx)); for get_freevars(tcx, expr.id).each |freevar| { debug!("freevar def is %?", freevar.def); let def = freevar.def; let en_region = encl_region_of_def(rcx.fcx, def); + debug!("en_region = %s", en_region.repr(tcx)); match rcx.fcx.mk_subr(true, freevar.span, region, en_region) { result::Ok(()) => {} result::Err(_) => { tcx.sess.span_err( freevar.span, - ~"captured variable does not outlive the enclosing closure"); + "captured variable does not outlive the enclosing closure"); note_and_explain_region( tcx, - ~"captured variable is valid for ", + "captured variable is valid for ", en_region, - ~""); + ""); note_and_explain_region( tcx, - ~"closure is valid for ", + "closure is valid for ", region, - ~""); + ""); } } } @@ -541,34 +652,37 @@ fn constrain_free_variables( fn constrain_regions_in_type_of_node( rcx: @mut Rcx, id: ast::node_id, - encl_region: ty::Region, + minimum_lifetime: ty::Region, span: span) -> bool { + //! Guarantees that any lifetimes which appear in the type of + //! the node `id` (after applying adjustments) are valid for at + //! least `minimum_lifetime` + let tcx = rcx.fcx.tcx(); // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = rcx.resolve_node_type(id); - let adjustment = rcx.fcx.inh.adjustments.find(&id); + let adjustment = rcx.fcx.inh.adjustments.find_copy(&id); let ty = ty::adjust_ty(tcx, span, ty0, adjustment); debug!("constrain_regions_in_type_of_node(\ - ty=%s, ty0=%s, id=%d, encl_region=%?, adjustment=%?)", + ty=%s, ty0=%s, id=%d, minimum_lifetime=%?, adjustment=%?)", ty_to_str(tcx, ty), ty_to_str(tcx, ty0), - id, encl_region, adjustment); - constrain_regions_in_type(rcx, encl_region, span, ty) + id, minimum_lifetime, adjustment); + constrain_regions_in_type(rcx, minimum_lifetime, span, ty) } fn constrain_regions_in_type( rcx: @mut Rcx, - encl_region: ty::Region, + minimum_lifetime: ty::Region, span: span, ty: ty::t) -> bool { /*! - * * Requires that any regions which appear in `ty` must be - * superregions of `encl_region`. Also enforces the constraint + * superregions of `minimum_lifetime`. Also enforces the constraint * that given a pointer type `&'r T`, T must not contain regions * that outlive 'r, as well as analogous constraints for other * lifetime'd types. @@ -583,11 +697,11 @@ fn constrain_regions_in_type( let e = rcx.errors_reported; let tcx = rcx.fcx.ccx.tcx; - debug!("constrain_regions_in_type(encl_region=%s, ty=%s)", - region_to_str(tcx, encl_region), + debug!("constrain_regions_in_type(minimum_lifetime=%s, ty=%s)", + region_to_str(tcx, minimum_lifetime), ty_to_str(tcx, ty)); - do relate_nested_regions(tcx, Some(encl_region), ty) |r_sub, r_sup| { + do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { debug!("relate(r_sub=%s, r_sup=%s)", region_to_str(tcx, r_sub), region_to_str(tcx, r_sup)); @@ -595,12 +709,12 @@ fn constrain_regions_in_type( if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. // (e.g., the `&` in `fn(&T)`). Such regions need not be - // constrained by `encl_region` as they are placeholders + // constrained by `minimum_lifetime` as they are placeholders // for regions that are as-yet-unknown. } else { match rcx.fcx.mk_subr(true, span, r_sub, r_sup) { result::Err(_) => { - if r_sub == encl_region { + if r_sub == minimum_lifetime { tcx.sess.span_err( span, fmt!("reference is not valid outside of its lifetime")); @@ -639,7 +753,6 @@ fn constrain_regions_in_type( pub mod guarantor { /*! - * * The routines in this module are aiming to deal with the case * where a the contents of a borrowed pointer are re-borrowed. * Imagine you have a borrowed pointer `b` with lifetime L1 and @@ -686,6 +799,7 @@ pub mod guarantor { */ use middle::typeck::check::regionck::{Rcx, infallibly_mk_subr}; + use middle::typeck::check::regionck::mk_subregion_due_to_derefence; use middle::ty; use syntax::ast; use syntax::codemap::span; @@ -693,14 +807,12 @@ pub mod guarantor { pub fn for_addr_of(rcx: @mut Rcx, expr: @ast::expr, base: @ast::expr) { /*! - * * Computes the guarantor for an expression `&base` and then * ensures that the lifetime of the resulting pointer is linked * to the lifetime of its guarantor (if any). */ debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); - let _i = ::util::common::indenter(); let guarantor = guarantor(rcx, base); link(rcx, expr.span, expr.id, guarantor); @@ -708,13 +820,14 @@ pub mod guarantor { pub fn for_match(rcx: @mut Rcx, discr: @ast::expr, arms: &[ast::arm]) { /*! - * * Computes the guarantors for any ref bindings in a match and * then ensures that the lifetime of the resulting pointer is * linked to the lifetime of its guarantor (if any). */ + debug!("regionck::for_match()"); let discr_guarantor = guarantor(rcx, discr); + debug!("discr_guarantor=%s", discr_guarantor.repr(rcx.tcx())); for arms.each |arm| { for arm.pats.each |pat| { link_ref_bindings_in_pat(rcx, *pat, discr_guarantor); @@ -727,7 +840,6 @@ pub mod guarantor { autoderefs: uint, autoref: &ty::AutoRef) { /*! - * * Computes the guarantor for an expression that has an * autoref adjustment and links it to the lifetime of the * autoref. This is only important when auto re-borrowing @@ -736,30 +848,30 @@ pub mod guarantor { debug!("guarantor::for_autoref(expr=%s, autoref=%?)", rcx.fcx.expr_to_str(expr), autoref); - let _i = ::util::common::indenter(); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!(" unadjusted cat=%?", expr_ct.cat); expr_ct = apply_autoderefs( rcx, expr, autoderefs, expr_ct); - match autoref.kind { - ty::AutoPtr => { + match *autoref { + ty::AutoPtr(r, _) => { // In this case, we are implicitly adding an `&`. - maybe_make_subregion(rcx, expr, autoref.region, - expr_ct.cat.guarantor); + maybe_make_subregion(rcx, expr, r, expr_ct.cat.guarantor); } - ty::AutoBorrowVec | - ty::AutoBorrowVecRef | - ty::AutoBorrowFn => { + ty::AutoBorrowVec(r, _) | + ty::AutoBorrowVecRef(r, _) | + ty::AutoBorrowFn(r) => { // In each of these cases, what is being borrowed is // not the (autoderef'd) expr itself but rather the // contents of the autoderef'd expression (i.e., what // the pointer points at). - maybe_make_subregion(rcx, expr, autoref.region, + maybe_make_subregion(rcx, expr, r, guarantor_of_deref(&expr_ct.cat)); } + + ty::AutoUnsafe(_) => {} } fn maybe_make_subregion( @@ -774,6 +886,28 @@ pub mod guarantor { } } + pub fn for_by_ref(rcx: @mut Rcx, + expr: @ast::expr, + callee_scope: ast::node_id) { + /*! + * Computes the guarantor for cases where the `expr` is + * being passed by implicit reference and must outlive + * `callee_scope`. + */ + + let tcx = rcx.tcx(); + debug!("guarantor::for_by_ref(expr=%s, callee_scope=%?)", + expr.repr(tcx), callee_scope); + let expr_cat = categorize(rcx, expr); + debug!("guarantor::for_by_ref(expr=%?, callee_scope=%?) category=%?", + expr.id, callee_scope, expr_cat); + let minimum_lifetime = ty::re_scope(callee_scope); + for expr_cat.guarantor.each |guarantor| { + mk_subregion_due_to_derefence(rcx, expr.span, + minimum_lifetime, *guarantor); + } + } + fn link( rcx: @mut Rcx, span: span, @@ -801,7 +935,7 @@ pub mod guarantor { // expressions, both of which always yield a region variable, so // mk_subr should never fail. let rptr_ty = rcx.resolve_node_type(id); - if !ty::type_is_error(rptr_ty) && !ty::type_is_bot(rptr_ty) { + if !ty::type_is_bot(rptr_ty) { let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty=%s", ty_to_str(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); @@ -859,7 +993,7 @@ pub mod guarantor { guarantor(rcx, e) } - ast::expr_path(*) => { + ast::expr_path(*) | ast::expr_self => { // Either a variable or constant and hence resides // in constant memory or on the stack frame. Either way, // not guaranteed by a region pointer. @@ -882,7 +1016,6 @@ pub mod guarantor { ast::expr_while(*) | ast::expr_loop(*) | ast::expr_assign(*) | - ast::expr_swap(*) | ast::expr_assign_op(*) | ast::expr_cast(*) | ast::expr_call(*) | @@ -907,7 +1040,6 @@ pub mod guarantor { fn categorize(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorization { debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); - let _i = ::util::common::indenter(); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!("before adjustments, cat=%?", expr_ct.cat); @@ -928,12 +1060,24 @@ pub mod guarantor { expr_ct = apply_autoderefs( rcx, expr, adjustment.autoderefs, expr_ct); - for adjustment.autoref.each |autoref| { - // If there is an autoref, then the result of this - // expression will be some sort of borrowed pointer. - expr_ct.cat.guarantor = None; - expr_ct.cat.pointer = BorrowedPointer(autoref.region); - debug!("autoref, cat=%?", expr_ct.cat); + match adjustment.autoref { + None => { + } + Some(ty::AutoUnsafe(_)) => { + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = OtherPointer; + debug!("autoref, cat=%?", expr_ct.cat); + } + Some(ty::AutoPtr(r, _)) | + Some(ty::AutoBorrowVec(r, _)) | + Some(ty::AutoBorrowVecRef(r, _)) | + Some(ty::AutoBorrowFn(r)) => { + // If there is an autoref, then the result of this + // expression will be some sort of borrowed pointer. + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = BorrowedPointer(r); + debug!("autoref, cat=%?", expr_ct.cat); + } } } @@ -948,7 +1092,6 @@ pub mod guarantor { expr: @ast::expr) -> ExprCategorizationType { debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); - let _i = ::util::common::indenter(); let guarantor = { if rcx.fcx.inh.method_map.contains_key(&expr.id) { @@ -1053,7 +1196,6 @@ pub mod guarantor { debug!("link_ref_bindings_in_pat(pat=%s, guarantor=%?)", rcx.fcx.pat_to_str(pat), guarantor); - let _i = ::util::common::indenter(); match pat.node { ast::pat_wild => {} @@ -1069,7 +1211,10 @@ pub mod guarantor { link_ref_bindings_in_pat(rcx, *p, guarantor); } } - ast::pat_enum(*) => {} + ast::pat_enum(_, None) => {} + ast::pat_enum(_, Some(ref pats)) => { + link_ref_bindings_in_pats(rcx, pats, guarantor); + } ast::pat_struct(_, ref fpats, _) => { for fpats.each |fpat| { link_ref_bindings_in_pat(rcx, fpat.pat, guarantor); @@ -1086,29 +1231,25 @@ pub mod guarantor { } ast::pat_region(p) => { let rptr_ty = rcx.resolve_node_type(pat.id); - if !ty::type_is_error(rptr_ty) { - let r = ty::ty_region(rcx.fcx.tcx(), pat.span, rptr_ty); - link_ref_bindings_in_pat(rcx, p, Some(r)); - } + let r = ty::ty_region(rcx.fcx.tcx(), pat.span, rptr_ty); + link_ref_bindings_in_pat(rcx, p, Some(r)); } ast::pat_lit(*) => {} ast::pat_range(*) => {} ast::pat_vec(ref before, ref slice, ref after) => { let vec_ty = rcx.resolve_node_type(pat.id); - if !ty::type_is_error(vec_ty) { - let vstore = ty::ty_vstore(vec_ty); - let guarantor1 = match vstore { - ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, - ty::vstore_slice(r) => Some(r), - ty::vstore_box => None - }; - - link_ref_bindings_in_pats(rcx, before, guarantor1); - for slice.each |&p| { - link_ref_bindings_in_pat(rcx, p, guarantor); - } - link_ref_bindings_in_pats(rcx, after, guarantor1); + let vstore = ty::ty_vstore(vec_ty); + let guarantor1 = match vstore { + ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, + ty::vstore_slice(r) => Some(r), + ty::vstore_box => None + }; + + link_ref_bindings_in_pats(rcx, before, guarantor1); + for slice.each |&p| { + link_ref_bindings_in_pat(rcx, p, guarantor); } + link_ref_bindings_in_pats(rcx, after, guarantor1); } } } diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index f293893bc131f..cfbd012b7b7cd 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -87,7 +87,7 @@ pub fn replace_bound_regions_in_fn_sig( to_r: &fn(ty::bound_region) -> ty::Region, r: ty::Region) -> isr_alist { match r { - ty::re_free(*) | ty::re_static | ty::re_scope(_) | + ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) | ty::re_infer(_) => { isr } @@ -153,6 +153,7 @@ pub fn replace_bound_regions_in_fn_sig( } // Free regions like these just stay the same: + ty::re_empty | ty::re_static | ty::re_scope(_) | ty::re_free(*) | diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 44b6212261246..1277715982158 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -31,7 +31,7 @@ use syntax::print::pprust::expr_to_str; use syntax::visit; // vtable resolution looks for places where trait bounds are -// subsituted in and figures out which vtable is used. There is some +// substituted in and figures out which vtable is used. There is some // extra complication thrown in to support early "opportunistic" // vtable resolution. This is a hacky mechanism that is invoked while // typechecking function calls (after typechecking non-closure @@ -67,8 +67,7 @@ pub impl VtableContext { fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { type_param_defs.any( - |type_param_def| type_param_def.bounds.any( - |bound| match bound { &ty::bound_trait(*) => true, _ => false })) + |type_param_def| !type_param_def.bounds.trait_bounds.is_empty()) } fn lookup_vtables(vcx: &VtableContext, @@ -99,7 +98,7 @@ fn lookup_vtables(vcx: &VtableContext, // Substitute the values of the type parameters that may // appear in the bound. - let trait_ref = trait_ref.subst(tcx, substs); + let trait_ref = (*trait_ref).subst(tcx, substs); debug!("after subst: %s", trait_ref.repr(tcx)); @@ -244,11 +243,14 @@ fn lookup_vtable(vcx: &VtableContext, // Nothing found. Continue. } Some(implementations) => { - let implementations: &mut ~[@Impl] = *implementations; + let len = { // FIXME(#5074): stage0 requires it + let implementations: &mut ~[@Impl] = *implementations; + implementations.len() + }; // implementations is the list of all impls in scope for // trait_ref. (Usually, there's just one.) - for uint::range(0, implementations.len()) |i| { + for uint::range(0, len) |i| { let im = implementations[i]; // im is one specific impl of trait_ref. @@ -336,7 +338,8 @@ fn lookup_vtable(vcx: &VtableContext, vcx.infcx.trait_ref_to_str(trait_ref), vcx.infcx.trait_ref_to_str(of_trait_ref)); - let of_trait_ref = of_trait_ref.subst(tcx, &substs); + let of_trait_ref = + (*of_trait_ref).subst(tcx, &substs); relate_trait_refs( vcx, location_info, &of_trait_ref, trait_ref); @@ -414,7 +417,7 @@ fn lookup_vtable(vcx: &VtableContext, if !is_early { vcx.tcx().sess.span_err( location_info.span, - ~"multiple applicable methods in scope"); + "multiple applicable methods in scope"); } return Some(/*bad*/copy found[0]); } @@ -455,7 +458,7 @@ fn connect_trait_tps(vcx: &VtableContext, // XXX: This should work for multiple traits. let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0]; - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs); relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref); } @@ -487,7 +490,7 @@ pub fn early_resolve_expr(ex: @ast::expr, for fcx.opt_node_ty_substs(ex.id) |substs| { debug!("vtable resolution on parameter bounds for expr %s", ex.repr(fcx.tcx())); - let def = *cx.tcx.def_map.get(&ex.id); + let def = cx.tcx.def_map.get_copy(&ex.id); let did = ast_util::def_id_of_def(def); let item_ty = ty::lookup_item_type(cx.tcx, did); debug!("early resolve expr: def %? %?, %?, %s", ex.id, did, def, @@ -666,5 +669,3 @@ pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) { .. *visit::default_visitor() })); } - - diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index d6b09d1e7f453..2869c3737c937 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -134,23 +134,22 @@ fn resolve_type_vars_for_node(wbcx: @mut WbCtxt, sp: span, id: ast::node_id) } Some(&@ty::AutoDerefRef(adj)) => { - let resolved_autoref = match adj.autoref { - Some(ref autoref) => { - match resolve_region(fcx.infcx(), autoref.region, - resolve_all | force_all) { - Err(e) => { - // This should not, I think, happen. - fcx.ccx.tcx.sess.span_err( - sp, fmt!("cannot resolve scope of borrow: %s", - infer::fixup_err_to_str(e))); - Some(*autoref) - } - Ok(r) => { - Some(ty::AutoRef {region: r, ..*autoref}) - } + let fixup_region = |r| { + match resolve_region(fcx.infcx(), r, resolve_all | force_all) { + Ok(r1) => r1, + Err(e) => { + // This should not, I think, happen. + fcx.ccx.tcx.sess.span_err( + sp, fmt!("cannot resolve scope of borrow: %s", + infer::fixup_err_to_str(e))); + r } } - None => None + }; + + let resolved_autoref = match adj.autoref { + None => None, + Some(ref r) => Some(r.map_region(fixup_region)) }; let resolved_adj = @ty::AutoDerefRef(ty::AutoDerefRef { @@ -229,7 +228,7 @@ fn visit_expr(e: @ast::expr, wbcx: @mut WbCtxt, v: wb_vt) { match e.node { ast::expr_fn_block(ref decl, _) => { - for vec::each(decl.inputs) |input| { + for decl.inputs.each |input| { let _ = resolve_type_vars_for_node(wbcx, e.span, input.id); } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 05b2f6f577b82..260d3f440f9cf 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -22,7 +22,7 @@ use metadata::csearch; use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; -use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get}; +use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, get}; use middle::ty::{lookup_item_type, subst}; use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil}; @@ -76,10 +76,8 @@ pub fn get_base_type(inference_context: @mut InferCtxt, } _ => { inference_context.tcx.sess.span_fatal(span, - ~"the type of this value \ - must be known in order \ - to determine the base \ - type"); + "the type of this value must be known in order \ + to determine the base type"); } } @@ -240,8 +238,8 @@ pub impl CoherenceChecker { fn check_implementation(&self, item: @item, associated_traits: ~[@trait_ref]) { - let self_type = self.crate_context.tcx.tcache.get( - &local_def(item.id)); + let tcx = self.crate_context.tcx; + let self_type = ty::lookup_item_type(tcx, local_def(item.id)); // If there are no traits, then this implementation must have a // base type. @@ -257,9 +255,8 @@ pub impl CoherenceChecker { None => { let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"no base type found for inherent \ - implementation; implement a \ - trait or new type instead"); + "no base type found for inherent implementation; \ + implement a trait or new type instead"); } Some(_) => { // Nothing to do. @@ -393,7 +390,7 @@ pub impl CoherenceChecker { let pmm = self.crate_context.tcx.provided_methods; match pmm.find(&local_def(impl_id)) { - Some(mis) => { + Some(&mis) => { // If the trait already has an entry in the // provided_methods_map, we just need to add this // method to that entry. @@ -426,8 +423,8 @@ pub impl CoherenceChecker { self.crate_context.coherence_info.inherent_methods .insert(base_def_id, implementation_list); } - Some(existing_implementation_list) => { - implementation_list = *existing_implementation_list; + Some(&existing_implementation_list) => { + implementation_list = existing_implementation_list; } } @@ -443,8 +440,8 @@ pub impl CoherenceChecker { self.crate_context.coherence_info.extension_methods .insert(trait_id, implementation_list); } - Some(existing_implementation_list) => { - implementation_list = *existing_implementation_list; + Some(&existing_implementation_list) => { + implementation_list = existing_implementation_list; } } @@ -452,10 +449,8 @@ pub impl CoherenceChecker { } fn check_implementation_coherence(&self) { - let coherence_info = &mut self.crate_context.coherence_info; - let extension_methods = &coherence_info.extension_methods; - - for extension_methods.each_key |&trait_id| { + let coherence_info = self.crate_context.coherence_info; + for coherence_info.extension_methods.each_key |&trait_id| { self.check_implementation_coherence_of(trait_id); } } @@ -483,11 +478,9 @@ pub impl CoherenceChecker { if self.polytypes_unify(polytype_a, polytype_b) { let session = self.crate_context.tcx.sess; session.span_err(self.span_of_impl(implementation_b), - ~"conflicting implementations for a \ - trait"); + "conflicting implementations for a trait"); session.span_note(self.span_of_impl(implementation_a), - ~"note conflicting implementation \ - here"); + "note conflicting implementation here"); } } } @@ -507,20 +500,23 @@ pub impl CoherenceChecker { m.insert(self_t, the_impl); self.crate_context.tcx.trait_impls.insert(trait_t, m); } - Some(m) => { + Some(&m) => { m.insert(self_t, the_impl); } } } fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) { - let coherence_info = &mut self.crate_context.coherence_info; - let extension_methods = &coherence_info.extension_methods; + let coherence_info = self.crate_context.coherence_info; + let extension_methods = &*coherence_info.extension_methods; match extension_methods.find(&trait_def_id) { Some(impls) => { - let impls: &mut ~[@Impl] = *impls; - for uint::range(0, impls.len()) |i| { + let len = { // FIXME(#5074) stage0 requires this + let impls: &mut ~[@Impl] = *impls; + impls.len() + }; + for uint::range(0, len) |i| { f(impls[i]); } } @@ -528,6 +524,7 @@ pub impl CoherenceChecker { } } + #[cfg(stage0)] fn each_provided_trait_method(&self, trait_did: ast::def_id, f: &fn(x: @ty::method) -> bool) { @@ -547,6 +544,27 @@ pub impl CoherenceChecker { } } } + #[cfg(not(stage0))] + fn each_provided_trait_method(&self, + trait_did: ast::def_id, + f: &fn(x: @ty::method) -> bool) -> bool { + // Make a list of all the names of the provided methods. + // XXX: This is horrible. + let mut provided_method_idents = HashSet::new(); + let tcx = self.crate_context.tcx; + for ty::provided_trait_methods(tcx, trait_did).each |ident| { + provided_method_idents.insert(*ident); + } + + for ty::trait_methods(tcx, trait_did).each |&method| { + if provided_method_idents.contains(&method.ident) { + if !f(method) { + return false; + } + } + } + return true; + } fn polytypes_unify(&self, polytype_a: ty_param_bounds_and_ty, polytype_b: ty_param_bounds_and_ty) @@ -607,34 +625,28 @@ pub impl CoherenceChecker { // Check to ensure that each parameter binding respected its // kind bounds. for [ a, b ].each |result| { - for vec::each2(result.type_variables, *result.type_param_defs) - |ty_var, type_param_def| { - match resolve_type(self.inference_context, - *ty_var, - resolve_nested_tvar) { - Ok(resolved_ty) => { - for type_param_def.bounds.each |bound| { - match *bound { - bound_copy => { - if !ty::type_is_copyable( - self.inference_context.tcx, - resolved_ty) - { - might_unify = false; - break; - } - } - - // XXX: We could be smarter here. - // Check to see whether owned, send, - // const, trait param bounds could - // possibly unify. - _ => {} + for vec::each2(result.type_variables, + *result.type_param_defs) + |ty_var, type_param_def| + { + if type_param_def.bounds.builtin_bounds.contains_elem( + ty::BoundCopy) + { + match resolve_type(self.inference_context, + *ty_var, + resolve_nested_tvar) { + Ok(resolved_ty) => { + if !ty::type_is_copyable( + self.inference_context.tcx, + resolved_ty) + { + might_unify = false; + break; } } - } - Err(*) => { - // Conservatively assume it might unify. + Err(*) => { + // Conservatively assume it might unify. + } } } } @@ -650,7 +662,7 @@ pub impl CoherenceChecker { fn get_self_type_for_implementation(&self, implementation: @Impl) -> ty_param_bounds_and_ty { - return *self.crate_context.tcx.tcache.get(&implementation.did); + return self.crate_context.tcx.tcache.get_copy(&implementation.did); } // Privileged scope checking @@ -667,11 +679,9 @@ pub impl CoherenceChecker { // This is an error. let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"cannot associate methods with \ - a type outside the crate the \ - type is defined in; define \ - and implement a trait or new \ - type instead"); + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); } } item_impl(_, Some(trait_ref), _, _) => { @@ -690,10 +700,8 @@ pub impl CoherenceChecker { if trait_def_id.crate != local_crate { let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"cannot provide an \ - extension implementation \ - for a trait not defined \ - in this crate"); + "cannot provide an extension implementation \ + for a trait not defined in this crate"); } } @@ -710,7 +718,7 @@ pub impl CoherenceChecker { fn trait_ref_to_trait_def_id(&self, trait_ref: @trait_ref) -> def_id { let def_map = self.crate_context.tcx.def_map; - let trait_def = *def_map.get(&trait_ref.ref_id); + let trait_def = def_map.get_copy(&trait_ref.ref_id); let trait_id = def_id_of_def(trait_def); return trait_id; } @@ -750,7 +758,7 @@ pub impl CoherenceChecker { -> bool { match original_type.node { ty_path(_, path_id) => { - match *self.crate_context.tcx.def_map.get(&path_id) { + match self.crate_context.tcx.def_map.get_copy(&path_id) { def_ty(def_id) | def_struct(def_id) => { if def_id.crate != local_crate { return false; @@ -765,7 +773,7 @@ pub impl CoherenceChecker { None => { self.crate_context.tcx.sess.span_bug( original_type.span, - ~"resolve didn't resolve this type?!"); + "resolve didn't resolve this type?!"); } Some(&node_item(item, _)) => { match item.node { @@ -849,8 +857,7 @@ pub impl CoherenceChecker { } _ => { self.crate_context.tcx.sess.span_bug(item.span, - ~"can't convert a \ - non-impl to an impl"); + "can't convert a non-impl to an impl"); } } } @@ -862,9 +869,8 @@ pub impl CoherenceChecker { return item.span; } _ => { - self.crate_context.tcx.sess.bug(~"span_of_impl() called on \ - something that wasn't an \ - impl!"); + self.crate_context.tcx.sess.bug("span_of_impl() called on something that \ + wasn't an impl!"); } } } @@ -1014,7 +1020,7 @@ pub impl CoherenceChecker { // fn populate_destructor_table(&self) { - let coherence_info = &mut self.crate_context.coherence_info; + let coherence_info = self.crate_context.coherence_info; let tcx = self.crate_context.tcx; let drop_trait = tcx.lang_items.drop_trait(); let impls_opt = coherence_info.extension_methods.find(&drop_trait); @@ -1045,17 +1051,16 @@ pub impl CoherenceChecker { match tcx.items.find(&impl_info.did.node) { Some(&ast_map::node_item(@ref item, _)) => { tcx.sess.span_err((*item).span, - ~"the Drop trait may only \ - be implemented on \ - structures"); + "the Drop trait may only be implemented on \ + structures"); } _ => { - tcx.sess.bug(~"didn't find impl in ast map"); + tcx.sess.bug("didn't find impl in ast map"); } } } else { - tcx.sess.bug(~"found external impl of Drop trait on \ - something other than a struct"); + tcx.sess.bug("found external impl of Drop trait on \ + something other than a struct"); } } } @@ -1131,4 +1136,3 @@ pub fn check_coherence(crate_context: @mut CrateCtxt, crate: @crate) { let coherence_checker = @CoherenceChecker(crate_context); coherence_checker.check_coherence(crate); } - diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0ffd398d03c19..03601a716c020 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -41,15 +41,15 @@ use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::rscope; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; -use util::common::{indenter, pluralize}; +use util::common::pluralize; use util::ppaux; +use util::ppaux::UserString; use syntax::abi::AbiSet; use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; -use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; use syntax::print::pprust::{path_to_str, self_ty_to_str}; @@ -117,7 +117,7 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { } impl CrateCtxt { - fn to_ty( + fn to_ty( &self, rs: &RS, ast_ty: @ast::Ty) -> ty::t { ast_ty_to_ty(self, rs, ast_ty) @@ -135,8 +135,8 @@ impl AstConv for CrateCtxt { Some(&ast_map::node_item(item, _)) => { ty_of_item(self, item) } - Some(&ast_map::node_foreign_item(foreign_item, _, _, _)) => { - ty_of_foreign_item(self, foreign_item) + Some(&ast_map::node_foreign_item(foreign_item, abis, _, _)) => { + ty_of_foreign_item(self, foreign_item, abis) } ref x => { self.tcx.sess.bug(fmt!("unexpected sort of item \ @@ -152,7 +152,7 @@ impl AstConv for CrateCtxt { fn ty_infer(&self, span: span) -> ty::t { self.tcx.sess.span_bug(span, - ~"found `ty_infer` in unexpected place"); + "found `ty_infer` in unexpected place"); } } @@ -220,7 +220,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, { let tcx = ccx.tcx; let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); - match *tcx.items.get(&trait_id) { + match tcx.items.get_copy(&trait_id) { ast_map::node_item(@ast::item { node: ast::item_trait(ref generics, _, ref ms), _ @@ -342,10 +342,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // add in the "self" type parameter let self_trait_def = get_trait_def(ccx, local_def(trait_id)); - let self_trait_ref = @self_trait_def.trait_ref.subst(tcx, &substs); + let self_trait_ref = self_trait_def.trait_ref.subst(tcx, &substs); new_type_param_defs.push(ty::TypeParameterDef { def_id: dummy_defid, - bounds: @~[ty::bound_trait(self_trait_ref)] + bounds: @ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[self_trait_ref] + } }); // add in the type parameters from the method @@ -367,7 +370,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, }); } - fn ty_method_of_trait_method(self: &CrateCtxt, + fn ty_method_of_trait_method(this: &CrateCtxt, trait_id: ast::node_id, trait_rp: Option, trait_generics: &ast::Generics, @@ -378,15 +381,15 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m_purity: &ast::purity, m_decl: &ast::fn_decl) -> ty::method { - let trait_self_ty = ty::mk_self(self.tcx, local_def(trait_id)); + let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id)); let rscope = MethodRscope::new(m_self_ty.node, trait_rp, trait_generics); let (transformed_self_ty, fty) = - astconv::ty_of_method(self, &rscope, *m_purity, &m_generics.lifetimes, + astconv::ty_of_method(this, &rscope, *m_purity, &m_generics.lifetimes, trait_self_ty, *m_self_ty, m_decl); let num_trait_type_params = trait_generics.ty_params.len(); ty::method { ident: *m_ident, - generics: ty_generics(self, None, m_generics, num_trait_type_params), + generics: ty_generics(this, None, m_generics, num_trait_type_params), transformed_self_ty: transformed_self_ty, fty: fty, self_ty: m_self_ty.node, @@ -417,8 +420,7 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { // This means a trait inherited from the same supertrait more // than once. - tcx.sess.span_err(sp, ~"Duplicate supertrait in trait \ - declaration"); + tcx.sess.span_err(sp, "Duplicate supertrait in trait declaration"); break; } else { ty_trait_refs.push(trait_ref); @@ -446,7 +448,7 @@ pub fn compare_impl_method(tcx: ty::ctxt, trait_substs: &ty::substs, self_ty: ty::t) { debug!("compare_impl_method()"); - let _indenter = indenter(); + let infcx = infer::new_infer_ctxt(tcx); let impl_m = &cm.mty; @@ -509,28 +511,50 @@ pub fn compare_impl_method(tcx: ty::ctxt, return; } - // FIXME(#2687)---we should be checking that the bounds of the - // trait imply the bounds of the subtype, but it appears - // we are...not checking this. for trait_m.generics.type_param_defs.eachi |i, trait_param_def| { // For each of the corresponding impl ty param's bounds... let impl_param_def = &impl_m.generics.type_param_defs[i]; - // Make sure the bounds lists have the same length - // Would be nice to use the ty param names in the error message, - // but we don't have easy access to them here - if impl_param_def.bounds.len() != trait_param_def.bounds.len() { + + // Check that the impl does not require any builtin-bounds + // that the trait does not guarantee: + let extra_bounds = + impl_param_def.bounds.builtin_bounds - + trait_param_def.bounds.builtin_bounds; + if !extra_bounds.is_empty() { tcx.sess.span_err( cm.span, fmt!("in method `%s`, \ - type parameter %u has %u %s, but the same type \ - parameter in its trait declaration has %u %s", + type parameter %u requires `%s`, \ + which is not required by \ + the corresponding type parameter \ + in the trait declaration", *tcx.sess.str_of(trait_m.ident), - i, impl_param_def.bounds.len(), - pluralize(impl_param_def.bounds.len(), ~"bound"), - trait_param_def.bounds.len(), - pluralize(trait_param_def.bounds.len(), ~"bound"))); + i, + extra_bounds.user_string(tcx))); return; } + + // FIXME(#2687)---we should be checking that the bounds of the + // trait imply the bounds of the subtype, but it appears we + // are...not checking this. + if impl_param_def.bounds.trait_bounds.len() != + trait_param_def.bounds.trait_bounds.len() + { + tcx.sess.span_err( + cm.span, + fmt!("in method `%s`, \ + type parameter %u has %u trait %s, but the \ + corresponding type parameter in \ + the trait declaration has %u trait %s", + *tcx.sess.str_of(trait_m.ident), + i, impl_param_def.bounds.trait_bounds.len(), + pluralize(impl_param_def.bounds.trait_bounds.len(), + ~"bound"), + trait_param_def.bounds.trait_bounds.len(), + pluralize(trait_param_def.bounds.trait_bounds.len(), + ~"bound"))); + return; + } } // Replace any references to the self region in the self type with @@ -621,7 +645,6 @@ pub fn compare_impl_method(tcx: ty::ctxt, }; debug!("trait_fty (post-subst): %s", trait_fty.repr(tcx)); - let infcx = infer::new_infer_ctxt(tcx); match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) { result::Ok(()) => {} result::Err(ref terr) => { @@ -897,30 +920,6 @@ pub fn convert_struct(ccx: &CrateCtxt, id: ast::node_id) { let tcx = ccx.tcx; - for struct_def.dtor.each |dtor| { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - - // Write the dtor type - let t_dtor = ty::mk_bare_fn( - tcx, - astconv::ty_of_bare_fn( - ccx, - &type_rscope(region_parameterization), - ast::impure_fn, - AbiSet::Rust(), - &opt_vec::Empty, - &ast_util::dtor_dec())); - write_ty_to_tcx(tcx, dtor.node.id, t_dtor); - tcx.tcache.insert(local_def(dtor.node.id), - ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: tpt.generics.type_param_defs, - region_param: rp - }, - ty: t_dtor}); - }; - // Write the type of each of the members for struct_def.fields.each |f| { convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); @@ -958,7 +957,20 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { // As above, this call populates the type table with the converted // type of the foreign item. We simply write it into the node type // table. - let tpt = ty_of_foreign_item(ccx, i); + + // For reasons I cannot fully articulate, I do so hate the AST + // map, and I regard each time that I use it as a personal and + // moral failing, but at the moment it seems like the only + // convenient way to extract the ABI. - ndm + let abis = match ccx.tcx.items.find(&i.id) { + Some(&ast_map::node_foreign_item(_, abis, _, _)) => abis, + ref x => { + ccx.tcx.sess.bug(fmt!("unexpected sort of item \ + in get_item_ty(): %?", (*x))); + } + }; + + let tpt = ty_of_foreign_item(ccx, i, abis); write_ty_to_tcx(ccx.tcx, i.id, tpt.ty); ccx.tcx.tcache.insert(local_def(i.id), tpt); } @@ -1129,14 +1141,17 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } } -pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item) - -> ty::ty_param_bounds_and_ty { +pub fn ty_of_foreign_item(ccx: &CrateCtxt, + it: @ast::foreign_item, + abis: AbiSet) -> ty::ty_param_bounds_and_ty +{ match it.node { ast::foreign_item_fn(ref fn_decl, _, ref generics) => { ty_of_foreign_fn_decl(ccx, fn_decl, local_def(it.id), - generics) + generics, + abis) } ast::foreign_item_const(t) => { ty::ty_param_bounds_and_ty { @@ -1162,8 +1177,8 @@ pub fn ty_generics(ccx: &CrateCtxt, None => { let param_ty = ty::param_ty {idx: base_index + offset, def_id: local_def(param.id)}; - let bounds = compute_bounds(ccx, rp, generics, - param_ty, param.bounds); + let bounds = @compute_bounds(ccx, rp, generics, + param_ty, param.bounds); let def = ty::TypeParameterDef { def_id: local_def(param.id), bounds: bounds @@ -1181,7 +1196,7 @@ pub fn ty_generics(ccx: &CrateCtxt, rp: Option, generics: &ast::Generics, param_ty: ty::param_ty, - ast_bounds: @OptVec) -> ty::param_bounds + ast_bounds: @OptVec) -> ty::ParamBounds { /*! * @@ -1189,41 +1204,46 @@ 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, Durable, and Send. + * as kinds): Const, Copy, and Send. */ - @ast_bounds.flat_map_to_vec(|b| { + let mut param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[] + }; + for ast_bounds.each |b| { match b { &TraitTyParamBound(b) => { let li = &ccx.tcx.lang_items; let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty); if trait_ref.def_id == li.owned_trait() { - ~[ty::bound_owned] + param_bounds.builtin_bounds.add(ty::BoundOwned); } else if trait_ref.def_id == li.copy_trait() { - ~[ty::bound_copy] + param_bounds.builtin_bounds.add(ty::BoundCopy); } else if trait_ref.def_id == li.const_trait() { - ~[ty::bound_const] - } else if trait_ref.def_id == li.durable_trait() { - ~[ty::bound_durable] + param_bounds.builtin_bounds.add(ty::BoundConst); } else { // Must be a user-defined trait - ~[ty::bound_trait(trait_ref)] + param_bounds.trait_bounds.push(trait_ref); } } &RegionTyParamBound => { - ~[ty::bound_durable] + param_bounds.builtin_bounds.add(ty::BoundStatic); } } - }) + } + + param_bounds } } pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, decl: &ast::fn_decl, def_id: ast::def_id, - ast_generics: &ast::Generics) + ast_generics: &ast::Generics, + abis: AbiSet) -> ty::ty_param_bounds_and_ty { let ty_generics = ty_generics(ccx, None, ast_generics, 0); let region_param_names = RegionParamNames::from_generics(ast_generics); @@ -1234,7 +1254,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, let t_fn = ty::mk_bare_fn( ccx.tcx, ty::BareFnTy { - abis: AbiSet::Rust(), + abis: abis, purity: ast::unsafe_fn, sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty, inputs: input_tys, diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index dcd1c861540f4..3620b609edf3b 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur. */ use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn}; -use middle::ty::{AutoDerefRef, AutoRef}; +use middle::ty::{AutoDerefRef}; use middle::ty::{vstore_slice, vstore_box, vstore_uniq}; use middle::ty::{mt}; use middle::ty; @@ -120,9 +120,9 @@ pub impl Coerce { }; } - ty::ty_ptr(_) => { + ty::ty_ptr(mt_b) => { return do self.unpack_actual_value(a) |sty_a| { - self.coerce_unsafe_ptr(a, sty_a, b) + self.coerce_unsafe_ptr(a, sty_a, b, mt_b) }; } @@ -205,11 +205,7 @@ pub impl Coerce { if_ok!(sub.tys(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(AutoRef { - kind: AutoPtr, - region: r_borrow, - mutbl: mt_b.mutbl - }) + autoref: Some(AutoPtr(r_borrow, mt_b.mutbl)) }))) } @@ -235,11 +231,7 @@ pub impl Coerce { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowVec, - region: r_a, - mutbl: m_imm - }) + autoref: Some(AutoBorrowVec(r_a, m_imm)) }))) } @@ -268,11 +260,7 @@ pub impl Coerce { if_ok!(sub.tys(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowVec, - region: r_borrow, - mutbl: mt_b.mutbl - }) + autoref: Some(AutoBorrowVec(r_borrow, mt_b.mutbl)) }))) } @@ -308,11 +296,7 @@ pub impl Coerce { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowFn, - region: r_borrow, - mutbl: m_imm - }) + autoref: Some(AutoBorrowFn(r_borrow)) }))) } @@ -363,7 +347,8 @@ pub impl Coerce { fn coerce_unsafe_ptr(&self, a: ty::t, sty_a: &ty::sty, - b: ty::t) -> CoerceResult + b: ty::t, + mt_b: ty::mt) -> CoerceResult { debug!("coerce_unsafe_ptr(a=%s, sty_a=%?, b=%s)", a.inf_str(self.infcx), sty_a, @@ -376,10 +361,17 @@ pub impl Coerce { } }; - // borrowed pointers and unsafe pointers have the same - // representation, so just check that the types which they - // point at are compatible: + // check that the types which they point at are compatible let a_unsafe = ty::mk_ptr(self.infcx.tcx, mt_a); - self.subtype(a_unsafe, b) + if_ok!(self.subtype(a_unsafe, b)); + + // although borrowed ptrs and unsafe ptrs have the same + // representation, we still register an AutoDerefRef so that + // regionck knows that that the region for `a` must be valid + // here + Ok(Some(@AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) + }))) } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index e4db423c2e35c..a845d6fe9d0fd 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -120,31 +120,31 @@ pub struct CombineFields { } pub fn expected_found( - self: &C, a: T, b: T) -> ty::expected_found { - if self.a_is_expected() { + this: &C, a: T, b: T) -> ty::expected_found { + if this.a_is_expected() { ty::expected_found {expected: a, found: b} } else { ty::expected_found {expected: b, found: a} } } -pub fn eq_tys(self: &C, a: ty::t, b: ty::t) -> ures { - let suber = self.sub(); - do self.infcx().try { +pub fn eq_tys(this: &C, a: ty::t, b: ty::t) -> ures { + let suber = this.sub(); + do this.infcx().try { do suber.tys(a, b).chain |_ok| { suber.contratys(a, b) }.to_ures() } } -pub fn eq_regions(self: &C, a: ty::Region, b: ty::Region) +pub fn eq_regions(this: &C, a: ty::Region, b: ty::Region) -> ures { debug!("eq_regions(%s, %s)", - a.inf_str(self.infcx()), - b.inf_str(self.infcx())); - let sub = self.sub(); + a.inf_str(this.infcx()), + b.inf_str(this.infcx())); + let sub = this.sub(); do indent { - self.infcx().try(|| { + this.infcx().try(|| { do sub.regions(a, b).chain |_r| { sub.contraregions(a, b) } @@ -161,7 +161,7 @@ pub fn eq_regions(self: &C, a: ty::Region, b: ty::Region) } pub fn eq_opt_regions( - self: &C, + this: &C, a: Option, b: Option) -> cres> { @@ -170,7 +170,7 @@ pub fn eq_opt_regions( Ok(None) } (Some(a), Some(b)) => { - do eq_regions(self, a, b).then { + do eq_regions(this, a, b).then { Ok(Some(a)) } } @@ -179,21 +179,21 @@ pub fn eq_opt_regions( // they should be), then the type should either // consistently have a region parameter or not have a // region parameter. - self.infcx().tcx.sess.bug( + this.infcx().tcx.sess.bug( fmt!("substitution a had opt_region %s and \ b had opt_region %s", - a.inf_str(self.infcx()), - b.inf_str(self.infcx()))); + a.inf_str(this.infcx()), + b.inf_str(this.infcx()))); } } } pub fn super_substs( - self: &C, generics: &ty::Generics, + this: &C, generics: &ty::Generics, a: &ty::substs, b: &ty::substs) -> cres { fn relate_region_param( - self: &C, + this: &C, generics: &ty::Generics, a: Option, b: Option) @@ -204,17 +204,17 @@ pub fn super_substs( Ok(None) } (&Some(ty::rv_invariant), &Some(a), &Some(b)) => { - do eq_regions(self, a, b).then { + do eq_regions(this, a, b).then { Ok(Some(a)) } } (&Some(ty::rv_covariant), &Some(a), &Some(b)) => { - do self.regions(a, b).chain |r| { + do this.regions(a, b).chain |r| { Ok(Some(r)) } } (&Some(ty::rv_contravariant), &Some(a), &Some(b)) => { - do self.contraregions(a, b).chain |r| { + do this.contraregions(a, b).chain |r| { Ok(Some(r)) } } @@ -224,19 +224,19 @@ pub fn super_substs( // consistently have a region parameter or not have a // region parameter, and that should match with the // polytype. - self.infcx().tcx.sess.bug( + this.infcx().tcx.sess.bug( fmt!("substitution a had opt_region %s and \ b had opt_region %s with variance %?", - a.inf_str(self.infcx()), - b.inf_str(self.infcx()), + a.inf_str(this.infcx()), + b.inf_str(this.infcx()), generics.region_param)); } } } - do self.tps(a.tps, b.tps).chain |tps| { - do self.self_tys(a.self_ty, b.self_ty).chain |self_ty| { - do relate_region_param(self, generics, + do this.tps(a.tps, b.tps).chain |tps| { + do this.self_tys(a.self_ty, b.self_ty).chain |self_ty| { + do relate_region_param(this, generics, a.self_r, b.self_r).chain |self_r| { Ok(substs { @@ -250,7 +250,7 @@ pub fn super_substs( } pub fn super_tps( - self: &C, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { + this: &C, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { // Note: type parameters are always treated as *invariant* // (otherwise the type system would be unsound). In the @@ -259,16 +259,16 @@ pub fn super_tps( if vec::same_length(as_, bs) { iter_vec2(as_, bs, |a, b| { - eq_tys(self, *a, *b) + eq_tys(this, *a, *b) }).then(|| Ok(as_.to_vec()) ) } else { Err(ty::terr_ty_param_size( - expected_found(self, as_.len(), bs.len()))) + expected_found(this, as_.len(), bs.len()))) } } pub fn super_self_tys( - self: &C, a: Option, b: Option) -> cres> { + this: &C, a: Option, b: Option) -> cres> { match (a, b) { (None, None) => { @@ -276,8 +276,8 @@ pub fn super_self_tys( } (Some(a), Some(b)) => { // FIXME(#5781) this should be eq_tys - // eq_tys(self, a, b).then(|| Ok(Some(a)) ) - self.contratys(a, b).chain(|t| Ok(Some(t))) + // eq_tys(this, a, b).then(|| Ok(Some(a)) ) + this.contratys(a, b).chain(|t| Ok(Some(t))) } (None, Some(_)) | (Some(_), None) => { @@ -290,46 +290,46 @@ pub fn super_self_tys( } pub fn super_sigils( - self: &C, p1: ast::Sigil, p2: ast::Sigil) -> cres { + this: &C, p1: ast::Sigil, p2: ast::Sigil) -> cres { if p1 == p2 { Ok(p1) } else { - Err(ty::terr_sigil_mismatch(expected_found(self, p1, p2))) + Err(ty::terr_sigil_mismatch(expected_found(this, p1, p2))) } } pub fn super_flds( - self: &C, a: ty::field, b: ty::field) -> cres { + this: &C, a: ty::field, b: ty::field) -> cres { if a.ident == b.ident { - self.mts(&a.mt, &b.mt) + this.mts(&a.mt, &b.mt) .chain(|mt| Ok(ty::field {ident: a.ident, mt: mt}) ) .chain_err(|e| Err(ty::terr_in_field(@e, a.ident)) ) } else { Err(ty::terr_record_fields( - expected_found(self, a.ident, b.ident))) + expected_found(this, a.ident, b.ident))) } } -pub fn super_args(self: &C, a: ty::arg, b: ty::arg) +pub fn super_args(this: &C, a: ty::arg, b: ty::arg) -> cres { - do self.contratys(a.ty, b.ty).chain |t| { + do this.contratys(a.ty, b.ty).chain |t| { Ok(arg { ty: t }) } } -pub fn super_vstores(self: &C, +pub fn super_vstores(this: &C, vk: ty::terr_vstore_kind, a: ty::vstore, b: ty::vstore) -> cres { - debug!("%s.super_vstores(a=%?, b=%?)", self.tag(), a, b); + debug!("%s.super_vstores(a=%?, b=%?)", this.tag(), a, b); match (a, b) { (ty::vstore_slice(a_r), ty::vstore_slice(b_r)) => { - do self.contraregions(a_r, b_r).chain |r| { + do this.contraregions(a_r, b_r).chain |r| { Ok(ty::vstore_slice(r)) } } @@ -339,21 +339,21 @@ pub fn super_vstores(self: &C, } _ => { - Err(ty::terr_vstores_differ(vk, expected_found(self, a, b))) + Err(ty::terr_vstores_differ(vk, expected_found(this, a, b))) } } } -pub fn super_trait_stores(self: &C, +pub fn super_trait_stores(this: &C, vk: ty::terr_vstore_kind, a: ty::TraitStore, b: ty::TraitStore) -> cres { - debug!("%s.super_vstores(a=%?, b=%?)", self.tag(), a, b); + debug!("%s.super_vstores(a=%?, b=%?)", this.tag(), a, b); match (a, b) { (ty::RegionTraitStore(a_r), ty::RegionTraitStore(b_r)) => { - do self.contraregions(a_r, b_r).chain |r| { + do this.contraregions(a_r, b_r).chain |r| { Ok(ty::RegionTraitStore(r)) } } @@ -363,19 +363,19 @@ pub fn super_trait_stores(self: &C, } _ => { - Err(ty::terr_trait_stores_differ(vk, expected_found(self, a, b))) + Err(ty::terr_trait_stores_differ(vk, expected_found(this, a, b))) } } } pub fn super_closure_tys( - self: &C, a_f: &ty::ClosureTy, b_f: &ty::ClosureTy) -> cres + this: &C, a_f: &ty::ClosureTy, b_f: &ty::ClosureTy) -> cres { - let p = if_ok!(self.sigils(a_f.sigil, b_f.sigil)); - let r = if_ok!(self.contraregions(a_f.region, b_f.region)); - let purity = if_ok!(self.purities(a_f.purity, b_f.purity)); - let onceness = if_ok!(self.oncenesses(a_f.onceness, b_f.onceness)); - let sig = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig)); + let p = if_ok!(this.sigils(a_f.sigil, b_f.sigil)); + let r = if_ok!(this.contraregions(a_f.region, b_f.region)); + let purity = if_ok!(this.purities(a_f.purity, b_f.purity)); + let onceness = if_ok!(this.oncenesses(a_f.onceness, b_f.onceness)); + let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig)); Ok(ty::ClosureTy {purity: purity, sigil: p, onceness: onceness, @@ -384,43 +384,43 @@ pub fn super_closure_tys( } pub fn super_abis( - self: &C, a: AbiSet, b: AbiSet) -> cres + this: &C, a: AbiSet, b: AbiSet) -> cres { if a == b { Ok(a) } else { - Err(ty::terr_abi_mismatch(expected_found(self, a, b))) + Err(ty::terr_abi_mismatch(expected_found(this, a, b))) } } pub fn super_bare_fn_tys( - self: &C, a_f: &ty::BareFnTy, b_f: &ty::BareFnTy) -> cres + this: &C, a_f: &ty::BareFnTy, b_f: &ty::BareFnTy) -> cres { - let purity = if_ok!(self.purities(a_f.purity, b_f.purity)); - let abi = if_ok!(self.abis(a_f.abis, b_f.abis)); - let sig = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig)); + let purity = if_ok!(this.purities(a_f.purity, b_f.purity)); + let abi = if_ok!(this.abis(a_f.abis, b_f.abis)); + let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig)); Ok(ty::BareFnTy {purity: purity, abis: abi, sig: sig}) } pub fn super_fn_sigs( - self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres + this: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres { - fn argvecs(self: &C, + fn argvecs(this: &C, a_args: &[ty::arg], b_args: &[ty::arg]) -> cres<~[ty::arg]> { if vec::same_length(a_args, b_args) { - map_vec2(a_args, b_args, |a, b| self.args(*a, *b)) + map_vec2(a_args, b_args, |a, b| this.args(*a, *b)) } else { Err(ty::terr_arg_count) } } - do argvecs(self, a_f.inputs, b_f.inputs) + do argvecs(this, a_f.inputs, b_f.inputs) .chain |inputs| { - do self.tys(a_f.output, b_f.output).chain |output| { + do this.tys(a_f.output, b_f.output).chain |output| { Ok(FnSig {bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) inputs: /*bad*/copy inputs, output: output}) @@ -429,8 +429,8 @@ pub fn super_fn_sigs( } pub fn super_tys( - self: &C, a: ty::t, b: ty::t) -> cres { - let tcx = self.infcx().tcx; + this: &C, a: ty::t, b: ty::t) -> cres { + let tcx = this.infcx().tcx; return match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) { // The "subtype" ought to be handling cases involving bot or var: (ty::ty_bot, _) | @@ -439,64 +439,56 @@ pub fn super_tys( (_, ty::ty_infer(TyVar(_))) => { tcx.sess.bug( fmt!("%s: bot and var types should have been handled (%s,%s)", - self.tag(), - a.inf_str(self.infcx()), - b.inf_str(self.infcx()))); + this.tag(), + a.inf_str(this.infcx()), + b.inf_str(this.infcx()))); } // Relate integral variables to other types (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => { - if_ok!(self.infcx().simple_vars(self.a_is_expected(), + if_ok!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); Ok(a) } (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) => { - unify_integral_variable(self, self.a_is_expected(), + unify_integral_variable(this, this.a_is_expected(), v_id, IntType(v)) } (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(self, !self.a_is_expected(), + unify_integral_variable(this, !this.a_is_expected(), v_id, IntType(v)) } (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) => { - unify_integral_variable(self, self.a_is_expected(), + unify_integral_variable(this, this.a_is_expected(), v_id, UintType(v)) } (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(self, !self.a_is_expected(), + unify_integral_variable(this, !this.a_is_expected(), v_id, UintType(v)) } // Relate floating-point variables to other types (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { - if_ok!(self.infcx().simple_vars(self.a_is_expected(), + if_ok!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); Ok(a) } (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) => { - unify_float_variable(self, self.a_is_expected(), v_id, v) + unify_float_variable(this, this.a_is_expected(), v_id, v) } (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => { - unify_float_variable(self, !self.a_is_expected(), v_id, v) + unify_float_variable(this, !this.a_is_expected(), v_id, v) } + (ty::ty_nil, _) | + (ty::ty_bool, _) | (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) => { if ty::get(a).sty == ty::get(b).sty { Ok(a) } else { - Err(ty::terr_sorts(expected_found(self, a, b))) - } - } - - (ty::ty_nil, _) | - (ty::ty_bool, _) => { - let cfg = tcx.sess.targ_cfg; - if ty::mach_sty(cfg, a) == ty::mach_sty(cfg, b) { - Ok(a) - } else { - Err(ty::terr_sorts(expected_found(self, a, b))) + Err(ty::terr_sorts(expected_found(this, a, b))) } } @@ -508,7 +500,7 @@ pub fn super_tys( ty::ty_enum(b_id, ref b_substs)) if a_id == b_id => { let type_def = ty::lookup_item_type(tcx, a_id); - do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| { Ok(ty::mk_enum(tcx, a_id, substs)) } } @@ -517,8 +509,8 @@ pub fn super_tys( ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl)) if a_id == b_id && a_mutbl == b_mutbl => { let trait_def = ty::lookup_trait_def(tcx, a_id); - do self.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { - do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { + do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { + do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl)) } } @@ -527,76 +519,76 @@ pub fn super_tys( (ty::ty_struct(a_id, ref a_substs), ty::ty_struct(b_id, ref b_substs)) if a_id == b_id => { let type_def = ty::lookup_item_type(tcx, a_id); - do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| { Ok(ty::mk_struct(tcx, a_id, substs)) } } (ty::ty_box(ref a_mt), ty::ty_box(ref b_mt)) => { - do self.mts(a_mt, b_mt).chain |mt| { + do this.mts(a_mt, b_mt).chain |mt| { Ok(ty::mk_box(tcx, mt)) } } (ty::ty_uniq(ref a_mt), ty::ty_uniq(ref b_mt)) => { - do self.mts(a_mt, b_mt).chain |mt| { + do this.mts(a_mt, b_mt).chain |mt| { Ok(ty::mk_uniq(tcx, mt)) } } (ty::ty_ptr(ref a_mt), ty::ty_ptr(ref b_mt)) => { - do self.mts(a_mt, b_mt).chain |mt| { + do this.mts(a_mt, b_mt).chain |mt| { Ok(ty::mk_ptr(tcx, mt)) } } (ty::ty_rptr(a_r, ref a_mt), ty::ty_rptr(b_r, ref b_mt)) => { - let r = if_ok!(self.contraregions(a_r, b_r)); - let mt = if_ok!(self.mts(a_mt, b_mt)); + let r = if_ok!(this.contraregions(a_r, b_r)); + let mt = if_ok!(this.mts(a_mt, b_mt)); Ok(ty::mk_rptr(tcx, r, mt)) } (ty::ty_evec(ref a_mt, vs_a), ty::ty_evec(ref b_mt, vs_b)) => { - do self.mts(a_mt, b_mt).chain |mt| { - do self.vstores(ty::terr_vec, vs_a, vs_b).chain |vs| { + do this.mts(a_mt, b_mt).chain |mt| { + do this.vstores(ty::terr_vec, vs_a, vs_b).chain |vs| { Ok(ty::mk_evec(tcx, mt, vs)) } } } (ty::ty_estr(vs_a), ty::ty_estr(vs_b)) => { - do self.vstores(ty::terr_str, vs_a, vs_b).chain |vs| { + do this.vstores(ty::terr_str, vs_a, vs_b).chain |vs| { Ok(ty::mk_estr(tcx,vs)) } } (ty::ty_tup(ref as_), ty::ty_tup(ref bs)) => { if as_.len() == bs.len() { - map_vec2(*as_, *bs, |a, b| self.tys(*a, *b) ) + map_vec2(*as_, *bs, |a, b| this.tys(*a, *b) ) .chain(|ts| Ok(ty::mk_tup(tcx, ts)) ) } else { Err(ty::terr_tuple_size( - expected_found(self, as_.len(), bs.len()))) + expected_found(this, as_.len(), bs.len()))) } } (ty::ty_bare_fn(ref a_fty), ty::ty_bare_fn(ref b_fty)) => { - do self.bare_fn_tys(a_fty, b_fty).chain |fty| { + do this.bare_fn_tys(a_fty, b_fty).chain |fty| { Ok(ty::mk_bare_fn(tcx, fty)) } } (ty::ty_closure(ref a_fty), ty::ty_closure(ref b_fty)) => { - do self.closure_tys(a_fty, b_fty).chain |fty| { + do this.closure_tys(a_fty, b_fty).chain |fty| { Ok(ty::mk_closure(tcx, fty)) } } - _ => Err(ty::terr_sorts(expected_found(self, a, b))) + _ => Err(ty::terr_sorts(expected_found(this, a, b))) }; fn unify_integral_variable( - self: &C, + this: &C, vid_is_expected: bool, vid: ty::IntVid, val: ty::IntVarValue) -> cres @@ -604,7 +596,7 @@ pub fn super_tys( if val == IntType(ast::ty_char) { Err(ty::terr_integer_as_char) } else { - if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + if_ok!(this.infcx().simple_var_t(vid_is_expected, vid, val)); match val { IntType(v) => Ok(ty::mk_mach_int(v)), UintType(v) => Ok(ty::mk_mach_uint(v)) @@ -613,18 +605,18 @@ pub fn super_tys( } fn unify_float_variable( - self: &C, + this: &C, vid_is_expected: bool, vid: ty::FloatVid, val: ast::float_ty) -> cres { - if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + if_ok!(this.infcx().simple_var_t(vid_is_expected, vid, val)); Ok(ty::mk_mach_float(val)) } } pub fn super_trait_refs( - self: &C, a: &ty::TraitRef, b: &ty::TraitRef) -> cres + this: &C, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { // Different traits cannot be related @@ -632,15 +624,14 @@ pub fn super_trait_refs( if a.def_id != b.def_id { Err(ty::terr_traits( - expected_found(self, a.def_id, b.def_id))) + expected_found(this, a.def_id, b.def_id))) } else { - let tcx = self.infcx().tcx; + let tcx = this.infcx().tcx; let trait_def = ty::lookup_trait_def(tcx, a.def_id); - let substs = if_ok!(self.substs(&trait_def.generics, &a.substs, &b.substs)); + let substs = if_ok!(this.substs(&trait_def.generics, &a.substs, &b.substs)); Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) } } - diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 2bbcd24595cba..462d7a003f405 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -16,6 +16,7 @@ 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}; +use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use syntax::ast; use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl}; @@ -188,7 +189,8 @@ impl Combine for Glb { let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); let sig1 = - self.infcx.fold_regions_in_sig( + fold_regions_in_sig( + self.infcx.tcx, &sig0, |r, _in_fn| generalize_region(self, snapshot, new_vars, a_isr, a_vars, b_vars, @@ -196,7 +198,7 @@ impl Combine for Glb { debug!("sig1 = %s", sig1.inf_str(self.infcx)); return Ok(sig1); - fn generalize_region(self: &Glb, + fn generalize_region(this: &Glb, snapshot: uint, new_vars: &[RegionVid], a_isr: isr_alist, @@ -207,19 +209,19 @@ impl Combine for Glb { return r0; } - let tainted = self.infcx.region_vars.tainted(snapshot, r0); + let tainted = this.infcx.region_vars.tainted(snapshot, r0); let mut a_r = None, b_r = None, only_new_vars = true; for tainted.each |r| { if is_var_in_set(a_vars, *r) { if a_r.is_some() { - return fresh_bound_variable(self); + return fresh_bound_variable(this); } else { a_r = Some(*r); } } else if is_var_in_set(b_vars, *r) { if b_r.is_some() { - return fresh_bound_variable(self); + return fresh_bound_variable(this); } else { b_r = Some(*r); } @@ -244,17 +246,17 @@ impl Combine for Glb { if a_r.is_some() && b_r.is_some() && only_new_vars { // Related to exactly one bound variable from each fn: - return rev_lookup(self, a_isr, a_r.get()); + return rev_lookup(this, a_isr, a_r.get()); } else if a_r.is_none() && b_r.is_none() { // Not related to bound variables from either fn: return r0; } else { // Other: - return fresh_bound_variable(self); + return fresh_bound_variable(this); } } - fn rev_lookup(self: &Glb, + fn rev_lookup(this: &Glb, a_isr: isr_alist, r: ty::Region) -> ty::Region { @@ -265,13 +267,13 @@ impl Combine for Glb { } } - self.infcx.tcx.sess.span_bug( - self.span, + this.infcx.tcx.sess.span_bug( + this.span, fmt!("could not find original bound region for %?", r)); } - fn fresh_bound_variable(self: &Glb) -> ty::Region { - self.infcx.region_vars.new_bound() + fn fresh_bound_variable(this: &Glb) -> ty::Region { + this.infcx.region_vars.new_bound() } } @@ -313,4 +315,3 @@ impl Combine for Glb { super_trait_refs(self, a, b) } } - diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index b9344724f60e5..3c48e09c05747 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -330,27 +330,27 @@ impl TyLatticeDir for Glb { } pub fn super_lattice_tys( - self: &L, + this: &L, a: ty::t, b: ty::t) -> cres { - debug!("%s.lattice_tys(%s, %s)", self.tag(), - a.inf_str(self.infcx()), - b.inf_str(self.infcx())); + debug!("%s.lattice_tys(%s, %s)", this.tag(), + a.inf_str(this.infcx()), + b.inf_str(this.infcx())); let _r = indenter(); if a == b { return Ok(a); } - let tcx = self.infcx().tcx; + let tcx = this.infcx().tcx; match (&ty::get(a).sty, &ty::get(b).sty) { - (&ty::ty_bot, _) => { return self.ty_bot(b); } - (_, &ty::ty_bot) => { return self.ty_bot(a); } + (&ty::ty_bot, _) => { return this.ty_bot(b); } + (_, &ty::ty_bot) => { return this.ty_bot(a); } (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => { - let r = if_ok!(lattice_vars(self, a_id, b_id, - |x, y| self.tys(*x, *y))); + let r = if_ok!(lattice_vars(this, a_id, b_id, + |x, y| this.tys(*x, *y))); return match r { VarResult(v) => Ok(ty::mk_var(tcx, v)), ValueResult(t) => Ok(t) @@ -358,17 +358,17 @@ pub fn super_lattice_tys( } (&ty::ty_infer(TyVar(a_id)), _) => { - return lattice_var_and_t(self, a_id, &b, - |x, y| self.tys(*x, *y)); + return lattice_var_and_t(this, a_id, &b, + |x, y| this.tys(*x, *y)); } (_, &ty::ty_infer(TyVar(b_id))) => { - return lattice_var_and_t(self, b_id, &a, - |x, y| self.tys(*x, *y)); + return lattice_var_and_t(this, b_id, &a, + |x, y| this.tys(*x, *y)); } _ => { - return super_tys(self, a, b); + return super_tys(this, a, b); } } } @@ -398,22 +398,22 @@ pub enum LatticeVarResult { pub fn lattice_vars>>( - self: &L, // defines whether we want LUB or GLB + this: &L, // defines whether we want LUB or GLB a_vid: V, // first variable b_vid: V, // second variable lattice_dir_op: LatticeDirOp) // LUB or GLB operation on types -> cres> { - let nde_a = self.infcx().get(a_vid); - let nde_b = self.infcx().get(b_vid); + let nde_a = this.infcx().get(a_vid); + let nde_b = this.infcx().get(b_vid); let a_vid = nde_a.root; let b_vid = nde_b.root; let a_bounds = &nde_a.possible_types; let b_bounds = &nde_b.possible_types; debug!("%s.lattice_vars(%s=%s <: %s=%s)", - self.tag(), - a_vid.to_str(), a_bounds.inf_str(self.infcx()), - b_vid.to_str(), b_bounds.inf_str(self.infcx())); + this.tag(), + a_vid.to_str(), a_bounds.inf_str(this.infcx()), + b_vid.to_str(), b_bounds.inf_str(this.infcx())); // Same variable: the easy case. if a_vid == b_vid { @@ -422,10 +422,10 @@ pub fn lattice_vars { - match self.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) { + match this.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) { Ok(t) => return Ok(ValueResult(t)), Err(_) => { /*fallthrough */ } } @@ -435,7 +435,7 @@ pub fn lattice_vars>>( - self: &L, + this: &L, a_id: V, b: &T, lattice_dir_op: LatticeDirOp) -> cres { - let nde_a = self.infcx().get(a_id); + let nde_a = this.infcx().get(a_id); let a_id = nde_a.root; let a_bounds = &nde_a.possible_types; @@ -457,24 +457,24 @@ pub fn lattice_var_and_t { // If a has an upper bound, return the LUB(a.ub, b) - debug!("bnd=Some(%s)", a_bnd.inf_str(self.infcx())); + debug!("bnd=Some(%s)", a_bnd.inf_str(this.infcx())); lattice_dir_op(a_bnd, b) } None => { // If a does not have an upper bound, make b the upper bound of a // and then return b. debug!("bnd=None"); - let a_bounds = self.with_bnd(a_bounds, *b); - do self.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then { - self.infcx().set(a_id, Root(a_bounds, nde_a.rank)); + let a_bounds = this.with_bnd(a_bounds, *b); + do this.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then { + this.infcx().set(a_id, Root(a_bounds, nde_a.rank)); Ok(*b) } } @@ -485,14 +485,14 @@ pub fn lattice_var_and_t(self: &T, isr: isr_alist) -> ~[RegionVid] { +pub fn var_ids(this: &T, isr: isr_alist) -> ~[RegionVid] { let mut result = ~[]; for list::each(isr) |pair| { match pair.second() { ty::re_infer(ty::ReVar(r)) => { result.push(r); } r => { - self.infcx().tcx.sess.span_bug( - self.span(), + this.infcx().tcx.sess.span_bug( + this.span(), fmt!("Found non-region-vid: %?", r)); } } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 8591433801796..bd5821873d2cb 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -16,6 +16,7 @@ use middle::typeck::infer::lattice::*; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; +use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use util::common::indent; use util::ppaux::mt_to_str; @@ -141,13 +142,14 @@ impl Combine for Lub { let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); let sig1 = - self.infcx.fold_regions_in_sig( + fold_regions_in_sig( + self.infcx.tcx, &sig0, |r, _in_fn| generalize_region(self, snapshot, new_vars, a_isr, r)); return Ok(sig1); - fn generalize_region(self: &Lub, + fn generalize_region(this: &Lub, snapshot: uint, new_vars: &[RegionVid], a_isr: isr_alist, @@ -158,7 +160,7 @@ impl Combine for Lub { return r0; } - let tainted = self.infcx.region_vars.tainted(snapshot, r0); + let tainted = this.infcx.region_vars.tainted(snapshot, r0); // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation @@ -185,8 +187,8 @@ impl Combine for Lub { } } - self.infcx.tcx.sess.span_bug( - self.span, + this.infcx.tcx.sess.span_bug( + this.span, fmt!("Region %? is not associated with \ any bound region from A!", r0)); } diff --git a/src/librustc/middle/typeck/infer/macros.rs b/src/librustc/middle/typeck/infer/macros.rs index e02772d951c55..306f124be3c8f 100644 --- a/src/librustc/middle/typeck/infer/macros.rs +++ b/src/librustc/middle/typeck/infer/macros.rs @@ -18,4 +18,3 @@ macro_rules! if_ok( } ) ) - diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 7b5a93d4cad88..2c42914f4b551 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -339,7 +339,7 @@ pub fn fixup_err_to_str(f: fixup_err) -> ~str { fn new_ValsAndBindings() -> ValsAndBindings { ValsAndBindings { - vals: @mut SmallIntMap::new(), + vals: SmallIntMap::new(), bindings: ~[] } } @@ -469,28 +469,6 @@ pub fn resolve_region(cx: @mut InferCtxt, r: ty::Region, modes: uint) resolver.resolve_region_chk(r) } -/* -fn resolve_borrowings(cx: @mut InferCtxt) { - for cx.borrowings.each |item| { - match resolve_region(cx, item.scope, resolve_all|force_all) { - Ok(region) => { - debug!("borrowing for expr %d resolved to region %?, mutbl %?", - item.expr_id, region, item.mutbl); - cx.tcx.borrowings.insert( - item.expr_id, {region: region, mutbl: item.mutbl}); - } - - Err(e) => { - let str = fixup_err_to_str(e); - cx.tcx.sess.span_err( - item.span, - fmt!("could not resolve lifetime for borrow: %s", str)); - } - } - } -} -*/ - trait then { fn then(&self, f: &fn() -> Result) -> Result; @@ -554,7 +532,8 @@ struct Snapshot { } pub impl InferCtxt { - fn combine_fields(@mut self, a_is_expected: bool, + fn combine_fields(@mut self, + a_is_expected: bool, span: span) -> CombineFields { CombineFields {infcx: self, a_is_expected: a_is_expected, @@ -565,25 +544,24 @@ pub impl InferCtxt { Sub(self.combine_fields(a_is_expected, span)) } - fn in_snapshot(@mut self) -> bool { + fn in_snapshot(&self) -> bool { self.region_vars.in_snapshot() } - fn start_snapshot(@mut self) -> Snapshot { - let this = &mut *self; + fn start_snapshot(&mut self) -> Snapshot { Snapshot { ty_var_bindings_len: - this.ty_var_bindings.bindings.len(), + self.ty_var_bindings.bindings.len(), int_var_bindings_len: - this.int_var_bindings.bindings.len(), + self.int_var_bindings.bindings.len(), float_var_bindings_len: - this.float_var_bindings.bindings.len(), + self.float_var_bindings.bindings.len(), region_vars_snapshot: - this.region_vars.start_snapshot(), + self.region_vars.start_snapshot(), } } - fn rollback_to(@mut self, snapshot: &Snapshot) { + fn rollback_to(&mut self, snapshot: &Snapshot) { debug!("rollback!"); rollback_to(&mut self.ty_var_bindings, snapshot.ty_var_bindings_len); @@ -647,45 +625,47 @@ fn next_simple_var( } pub impl InferCtxt { - fn next_ty_var_id(@mut self) -> TyVid { + fn next_ty_var_id(&mut self) -> TyVid { let id = self.ty_var_counter; self.ty_var_counter += 1; - let vals = self.ty_var_bindings.vals; - vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); + { + let vals = &mut self.ty_var_bindings.vals; + vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); + } return TyVid(id); } - fn next_ty_var(@mut self) -> ty::t { + fn next_ty_var(&mut self) -> ty::t { ty::mk_var(self.tcx, self.next_ty_var_id()) } - fn next_ty_vars(@mut self, n: uint) -> ~[ty::t] { + fn next_ty_vars(&mut self, n: uint) -> ~[ty::t] { vec::from_fn(n, |_i| self.next_ty_var()) } - fn next_int_var_id(@mut self) -> IntVid { + fn next_int_var_id(&mut self) -> IntVid { IntVid(next_simple_var(&mut self.int_var_counter, &mut self.int_var_bindings)) } - fn next_int_var(@mut self) -> ty::t { + fn next_int_var(&mut self) -> ty::t { ty::mk_int_var(self.tcx, self.next_int_var_id()) } - fn next_float_var_id(@mut self) -> FloatVid { + fn next_float_var_id(&mut self) -> FloatVid { FloatVid(next_simple_var(&mut self.float_var_counter, &mut self.float_var_bindings)) } - fn next_float_var(@mut self) -> ty::t { + fn next_float_var(&mut self) -> ty::t { ty::mk_float_var(self.tcx, self.next_float_var_id()) } - fn next_region_var_nb(@mut self, span: span) -> ty::Region { + fn next_region_var_nb(&mut self, span: span) -> ty::Region { ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span))) } - fn next_region_var_with_lb(@mut self, span: span, + fn next_region_var_with_lb(&mut self, span: span, lb_region: ty::Region) -> ty::Region { let region_var = self.next_region_var_nb(span); @@ -697,12 +677,12 @@ pub impl InferCtxt { return region_var; } - fn next_region_var(@mut self, span: span, scope_id: ast::node_id) + fn next_region_var(&mut self, span: span, scope_id: ast::node_id) -> ty::Region { self.next_region_var_with_lb(span, ty::re_scope(scope_id)) } - fn resolve_regions(@mut self) { + fn resolve_regions(&mut self) { self.region_vars.resolve_regions(); } @@ -722,7 +702,6 @@ pub impl InferCtxt { result::Err(_) => typ } } - fn resolve_type_vars_in_trait_ref_if_possible(@mut self, trait_ref: &ty::TraitRef) -> ty::TraitRef @@ -749,23 +728,53 @@ pub impl InferCtxt { } } - fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, - actual_ty: ty::t, err: Option<&ty::type_err>) { + fn type_error_message_str(@mut self, + sp: span, + mk_msg: &fn(Option<~str>, ~str) -> ~str, + actual_ty: ~str, err: Option<&ty::type_err>) { + self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) + } + + fn type_error_message_str_with_expected(@mut self, + sp: span, + mk_msg: &fn(Option<~str>, ~str) -> ~str, + expected_ty: Option, actual_ty: ~str, + err: Option<&ty::type_err>) { + debug!("hi! expected_ty = %?, actual_ty = %s", expected_ty, actual_ty); + + let error_str = err.map_default(~"", |t_err| + fmt!(" (%s)", + ty::type_err_to_str(self.tcx, *t_err))); + let resolved_expected = expected_ty.map(|&e_ty| + { self.resolve_type_vars_if_possible(e_ty) }); + if !resolved_expected.map_default(false, |&e| { ty::type_is_error(e) }) { + match resolved_expected { + None => self.tcx.sess.span_err(sp, + fmt!("%s%s", mk_msg(None, actual_ty), error_str)), + Some(e) => { + self.tcx.sess.span_err(sp, + fmt!("%s%s", mk_msg(Some(self.ty_to_str(e)), actual_ty), error_str)); + } + } + for err.each |err| { + ty::note_and_explain_type_err(self.tcx, *err) + } + } + } + + fn type_error_message(@mut self, + sp: span, + mk_msg: &fn(~str) -> ~str, + actual_ty: ty::t, + err: Option<&ty::type_err>) { let actual_ty = self.resolve_type_vars_if_possible(actual_ty); // Don't report an error if actual type is ty_err. if ty::type_is_error(actual_ty) { return; } - let error_str = err.map_default(~"", |t_err| - fmt!(" (%s)", - ty::type_err_to_str(self.tcx, *t_err))); - self.tcx.sess.span_err(sp, - fmt!("%s%s", mk_msg(self.ty_to_str(actual_ty)), - error_str)); - for err.each |err| { - ty::note_and_explain_type_err(self.tcx, *err) - } + + self.type_error_message_str(sp, |_e, a| { mk_msg(a) }, self.ty_to_str(actual_ty), err); } fn report_mismatched_types(@mut self, sp: span, e: ty::t, a: ty::t, @@ -786,7 +795,7 @@ pub impl InferCtxt { self.type_error_message(sp, mk_msg, a, Some(err)); } - fn replace_bound_regions_with_fresh_regions(@mut self, + fn replace_bound_regions_with_fresh_regions(&mut self, span: span, fsig: &ty::FnSig) -> (ty::FnSig, isr_alist) { @@ -804,15 +813,14 @@ pub impl InferCtxt { }); (fn_sig, isr) } +} - fn fold_regions_in_sig( - @mut self, - fn_sig: &ty::FnSig, - fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig - { - do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(self.tcx, t, fldr) - } +pub fn fold_regions_in_sig( + tcx: ty::ctxt, + fn_sig: &ty::FnSig, + 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) } - } diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index e12a3f2e97522..a5e8b42dee5ac 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -24,7 +24,7 @@ it's worth spending more time on a more involved analysis. Moreover, regions are a simpler case than types: they don't have aggregate structure, for example. -Unlike normal type inference, which is similar in spirit H-M and thus +Unlike normal type inference, which is similar in spirit to H-M and thus works progressively, the region type inference works by accumulating constraints over the course of a function. Finally, at the end of processing a function, we process and solve the constraints all at @@ -130,7 +130,7 @@ of these variables can effectively be unified into a single variable. Once SCCs are removed, we are left with a DAG. At this point, we can walk the DAG in toplogical order once to compute the expanding nodes, and again in reverse topological order to compute the contracting -nodes.The main reason I did not write it this way is that I did not +nodes. The main reason I did not write it this way is that I did not feel like implementing the SCC and toplogical sort algorithms at the moment. @@ -538,15 +538,19 @@ more convincing in the future. use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; -use middle::ty::{re_static, re_infer, re_free, re_bound}; +use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; use util::common::indenter; use util::ppaux::note_and_explain_region; +#[cfg(stage0)] +use core; // NOTE: this can be removed after next snapshot use core::cell::{Cell, empty_cell}; use core::hashmap::{HashMap, HashSet}; use core::to_bytes; +use core::uint; +use core::vec; use syntax::codemap::span; use syntax::ast; @@ -557,6 +561,7 @@ enum Constraint { ConstrainVarSubReg(RegionVid, Region) } +#[cfg(stage0)] impl to_bytes::IterBytes for Constraint { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -571,19 +576,28 @@ impl to_bytes::IterBytes for Constraint { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for Constraint { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + match *self { + ConstrainVarSubVar(ref v0, ref v1) => + to_bytes::iter_bytes_3(&0u8, v0, v1, lsb0, f), -#[deriving(Eq)] + ConstrainRegSubVar(ref ra, ref va) => + to_bytes::iter_bytes_3(&1u8, ra, va, lsb0, f), + + ConstrainVarSubReg(ref va, ref ra) => + to_bytes::iter_bytes_3(&2u8, va, ra, lsb0, f) + } + } +} + +#[deriving(Eq, IterBytes)] struct TwoRegions { a: Region, b: Region, } -impl to_bytes::IterBytes for TwoRegions { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.a, &self.b, lsb0, f) - } -} - enum UndoLogEntry { Snapshot, AddVar(RegionVid), @@ -637,7 +651,7 @@ pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings { } pub impl RegionVarBindings { - fn in_snapshot(&mut self) -> bool { + fn in_snapshot(&self) -> bool { self.undo_log.len() > 0 } @@ -832,7 +846,6 @@ pub impl RegionVarBindings { } fn resolve_var(&mut self, rid: RegionVid) -> ty::Region { - debug!("RegionVarBindings: resolve_var(%?=%u)", rid, rid.to_uint()); if self.values.is_empty() { self.tcx.sess.span_bug( self.var_spans[rid.to_uint()], @@ -841,29 +854,14 @@ pub impl RegionVarBindings { } let v = self.values.with_ref(|values| values[rid.to_uint()]); + debug!("RegionVarBindings: resolve_var(%?=%u)=%?", + rid, rid.to_uint(), v); match v { Value(r) => r, NoValue => { - // No constraints, report an error. It is plausible - // that we could select an arbitrary region here - // instead. At the moment I am not doing this because - // this generally masks bugs in the inference - // algorithm, and given our syntax one cannot create - // generally create a lifetime variable that isn't - // used in some type, and hence all lifetime variables - // should ultimately have some bounds. - - self.tcx.sess.span_err( - self.var_spans[rid.to_uint()], - fmt!("Unconstrained region variable #%u", rid.to_uint())); - - // Touch of a hack: to suppress duplicate messages, - // replace the NoValue entry with ErrorValue. - let mut values = self.values.take(); - values[rid.to_uint()] = ErrorValue; - self.values.put_back(values); - re_static + // No constraints, return ty::re_empty + re_empty } ErrorValue => { @@ -878,7 +876,7 @@ pub impl RegionVarBindings { a: Region, b: Region, span: span, - relate: &fn(self: &mut RegionVarBindings, + relate: &fn(this: &mut RegionVarBindings, old_r: Region, new_r: Region) -> cres<()>) -> cres { @@ -1031,6 +1029,10 @@ priv impl RegionVarBindings { re_static // nothing lives longer than static } + (re_empty, r) | (r, re_empty) => { + r // everything lives longer than empty + } + (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_spans[v_id.to_uint()], @@ -1101,11 +1103,11 @@ priv impl RegionVarBindings { Equal => ty::re_free(*a) }; - fn helper(self: &RegionVarBindings, + fn helper(this: &RegionVarBindings, a: &FreeRegion, b: &FreeRegion) -> ty::Region { - let rm = self.tcx.region_maps; + let rm = this.tcx.region_maps; if rm.sub_free_region(*a, *b) { ty::re_free(*b) } else if rm.sub_free_region(*b, *a) { @@ -1127,6 +1129,11 @@ priv impl RegionVarBindings { Ok(r) } + (re_empty, _) | (_, re_empty) => { + // nothing lives shorter than everything else + Ok(re_empty) + } + (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( @@ -1191,17 +1198,17 @@ priv impl RegionVarBindings { Equal => Ok(ty::re_free(*a)) }; - fn helper(self: &RegionVarBindings, + fn helper(this: &RegionVarBindings, a: &FreeRegion, b: &FreeRegion) -> cres { - let rm = self.tcx.region_maps; + let rm = this.tcx.region_maps; if rm.sub_free_region(*a, *b) { Ok(ty::re_free(*a)) } else if rm.sub_free_region(*b, *a) { Ok(ty::re_free(*b)) } else { - self.intersect_scopes(ty::re_free(*a), ty::re_free(*b), + this.intersect_scopes(ty::re_free(*a), ty::re_free(*b), a.scope_id, b.scope_id) } } @@ -1266,8 +1273,6 @@ struct SpannedRegion { span: span, } -type TwoRegionsMap = HashSet; - pub impl RegionVarBindings { fn infer_variable_values(&mut self) -> ~[GraphNodeValue] { let mut graph = self.construct_graph(); @@ -1329,11 +1334,15 @@ pub impl RegionVarBindings { node_id: RegionVid, edge_dir: Direction, edge_idx: uint) { + //! Insert edge `edge_idx` on the link list of edges in direction + //! `edge_dir` for the node `node_id` let edge_dir = edge_dir as uint; - graph.edges[edge_idx].next_edge[edge_dir] = - graph.nodes[node_id.to_uint()].head_edge[edge_dir]; - graph.nodes[node_id.to_uint()].head_edge[edge_dir] = - edge_idx; + assert_eq!(graph.edges[edge_idx].next_edge[edge_dir], + uint::max_value); + let n = node_id.to_uint(); + let prev_head = graph.nodes[n].head_edge[edge_dir]; + graph.edges[edge_idx].next_edge[edge_dir] = prev_head; + graph.nodes[n].head_edge[edge_dir] = edge_idx; } } @@ -1452,13 +1461,13 @@ pub impl RegionVarBindings { } }; - fn check_node(self: &mut RegionVarBindings, + fn check_node(this: &mut RegionVarBindings, a_vid: RegionVid, a_node: &mut GraphNode, a_region: Region, b_region: Region) -> bool { - if !self.is_subregion_of(a_region, b_region) { + if !this.is_subregion_of(a_region, b_region) { debug!("Setting %? to ErrorValue: %? not subregion of %?", a_vid, a_region, b_region); a_node.value = ErrorValue; @@ -1466,13 +1475,13 @@ pub impl RegionVarBindings { false } - fn adjust_node(self: &mut RegionVarBindings, + fn adjust_node(this: &mut RegionVarBindings, a_vid: RegionVid, a_node: &mut GraphNode, a_region: Region, b_region: Region) -> bool { - match self.glb_concrete_regions(a_region, b_region) { + match this.glb_concrete_regions(a_region, b_region) { Ok(glb) => { if glb == a_region { false @@ -1484,6 +1493,8 @@ pub impl RegionVarBindings { } } Err(_) => { + debug!("Setting %? to ErrorValue: no glb of %?, %?", + a_vid, a_region, b_region); a_node.value = ErrorValue; false } @@ -1495,7 +1506,21 @@ pub impl RegionVarBindings { &mut self, graph: &Graph) -> ~[GraphNodeValue] { - let mut dup_map = HashSet::new(); + debug!("extract_values_and_report_conflicts()"); + + // This is the best way that I have found to suppress + // duplicate and related errors. Basically we keep a set of + // flags for every node. Whenever an error occurs, we will + // walk some portion of the graph looking to find pairs of + // conflicting regions to report to the user. As we walk, we + // trip the flags from false to true, and if we find that + // we've already reported an error involving any particular + // node we just stop and don't report the current error. The + // idea is to report errors that derive from independent + // regions of the graph, but not those that derive from + // overlapping locations. + let mut dup_vec = graph.nodes.map(|_| uint::max_value); + graph.nodes.mapi(|idx, node| { match node.value { Value(_) => { @@ -1530,15 +1555,16 @@ pub impl RegionVarBindings { that is not used is not a problem, so if this rule starts to create problems we'll have to revisit this portion of the code and think hard about it. =) */ + let node_vid = RegionVid { id: idx }; match node.classification { Expanding => { self.report_error_for_expanding_node( - graph, &mut dup_map, node_vid); + graph, dup_vec, node_vid); } Contracting => { self.report_error_for_contracting_node( - graph, &mut dup_map, node_vid); + graph, dup_vec, node_vid); } } } @@ -1548,38 +1574,26 @@ pub impl RegionVarBindings { }) } - // Used to suppress reporting the same basic error over and over - fn is_reported(&mut self, - dup_map: &mut TwoRegionsMap, - r_a: Region, - r_b: Region) - -> bool { - let key = TwoRegions { a: r_a, b: r_b }; - !dup_map.insert(key) - } - fn report_error_for_expanding_node(&mut self, graph: &Graph, - dup_map: &mut TwoRegionsMap, + dup_vec: &mut [uint], node_idx: RegionVid) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. - let lower_bounds = - self.collect_concrete_regions(graph, node_idx, Incoming); - let upper_bounds = - self.collect_concrete_regions(graph, node_idx, Outgoing); + let (lower_bounds, lower_dup) = + self.collect_concrete_regions(graph, node_idx, Incoming, dup_vec); + let (upper_bounds, upper_dup) = + self.collect_concrete_regions(graph, node_idx, Outgoing, dup_vec); + + if lower_dup || upper_dup { + return; + } - for vec::each(lower_bounds) |lower_bound| { - for vec::each(upper_bounds) |upper_bound| { + for lower_bounds.each |lower_bound| { + for upper_bounds.each |upper_bound| { if !self.is_subregion_of(lower_bound.region, upper_bound.region) { - if self.is_reported(dup_map, - lower_bound.region, - upper_bound.region) { - return; - } - self.tcx.sess.span_err( self.var_spans[node_idx.to_uint()], fmt!("cannot infer an appropriate lifetime \ @@ -1587,9 +1601,9 @@ pub impl RegionVarBindings { note_and_explain_region( self.tcx, - ~"first, the lifetime cannot outlive ", + "first, the lifetime cannot outlive ", upper_bound.region, - ~"..."); + "..."); self.tcx.sess.span_note( upper_bound.span, @@ -1597,9 +1611,9 @@ pub impl RegionVarBindings { note_and_explain_region( self.tcx, - ~"but, the lifetime must be valid for ", + "but, the lifetime must be valid for ", lower_bound.region, - ~"..."); + "..."); self.tcx.sess.span_note( lower_bound.span, @@ -1609,30 +1623,36 @@ pub impl RegionVarBindings { } } } + + self.tcx.sess.span_bug( + self.var_spans[node_idx.to_uint()], + fmt!("report_error_for_expanding_node() could not find error \ + for var %?, lower_bounds=%s, upper_bounds=%s", + node_idx, + lower_bounds.map(|x| x.region).repr(self.tcx), + upper_bounds.map(|x| x.region).repr(self.tcx))); } fn report_error_for_contracting_node(&mut self, graph: &Graph, - dup_map: &mut TwoRegionsMap, + dup_vec: &mut [uint], node_idx: RegionVid) { // Errors in contracting nodes result from two upper-bounds // that have no intersection. - let upper_bounds = self.collect_concrete_regions(graph, node_idx, - Outgoing); + let (upper_bounds, dup_found) = + self.collect_concrete_regions(graph, node_idx, Outgoing, dup_vec); + + if dup_found { + return; + } - for vec::each(upper_bounds) |upper_bound_1| { - for vec::each(upper_bounds) |upper_bound_2| { + for upper_bounds.each |upper_bound_1| { + for upper_bounds.each |upper_bound_2| { match self.glb_concrete_regions(upper_bound_1.region, upper_bound_2.region) { Ok(_) => {} Err(_) => { - if self.is_reported(dup_map, - upper_bound_1.region, - upper_bound_2.region) { - return; - } - self.tcx.sess.span_err( self.var_spans[node_idx.to_uint()], fmt!("cannot infer an appropriate lifetime \ @@ -1663,52 +1683,97 @@ pub impl RegionVarBindings { } } } + + self.tcx.sess.span_bug( + self.var_spans[node_idx.to_uint()], + fmt!("report_error_for_contracting_node() could not find error \ + for var %?, upper_bounds=%s", + node_idx, + upper_bounds.map(|x| x.region).repr(self.tcx))); } fn collect_concrete_regions(&mut self, graph: &Graph, orig_node_idx: RegionVid, - dir: Direction) - -> ~[SpannedRegion] { - let mut set = HashSet::new(); - let mut stack = ~[orig_node_idx]; - set.insert(orig_node_idx.to_uint()); - let mut result = ~[]; - while !vec::is_empty(stack) { - let node_idx = stack.pop(); - for self.each_edge(graph, node_idx, dir) |edge| { + dir: Direction, + dup_vec: &mut [uint]) + -> (~[SpannedRegion], bool) { + struct WalkState { + set: HashSet, + stack: ~[RegionVid], + result: ~[SpannedRegion], + dup_found: bool + } + let mut state = WalkState { + set: HashSet::new(), + stack: ~[orig_node_idx], + result: ~[], + dup_found: false + }; + state.set.insert(orig_node_idx); + + // to start off the process, walk the source node in the + // direction specified + process_edges(self, &mut state, graph, orig_node_idx, dir); + + while !state.stack.is_empty() { + let node_idx = state.stack.pop(); + let classification = graph.nodes[node_idx.to_uint()].classification; + + // check whether we've visited this node on some previous walk + if dup_vec[node_idx.to_uint()] == uint::max_value { + dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint(); + } else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() { + state.dup_found = true; + } + + debug!("collect_concrete_regions(orig_node_idx=%?, node_idx=%?, \ + classification=%?)", + orig_node_idx, node_idx, classification); + + // figure out the direction from which this node takes its + // values, and search for concrete regions etc in that direction + let dir = match classification { + Expanding => Incoming, + Contracting => Outgoing + }; + + process_edges(self, &mut state, graph, node_idx, dir); + } + + let WalkState {result, dup_found, _} = state; + return (result, dup_found); + + fn process_edges(this: &mut RegionVarBindings, + state: &mut WalkState, + graph: &Graph, + source_vid: RegionVid, + dir: Direction) { + debug!("process_edges(source_vid=%?, dir=%?)", source_vid, dir); + + for this.each_edge(graph, source_vid, dir) |edge| { match edge.constraint { - ConstrainVarSubVar(from_vid, to_vid) => { - let vid = match dir { - Incoming => from_vid, - Outgoing => to_vid - }; - if set.insert(vid.to_uint()) { - stack.push(vid); + ConstrainVarSubVar(from_vid, to_vid) => { + let opp_vid = + if from_vid == source_vid {to_vid} else {from_vid}; + if state.set.insert(opp_vid) { + state.stack.push(opp_vid); + } } - } - ConstrainRegSubVar(region, _) => { - assert!(dir == Incoming); - result.push(SpannedRegion { - region: region, - span: edge.span - }); - } - - ConstrainVarSubReg(_, region) => { - assert!(dir == Outgoing); - result.push(SpannedRegion { - region: region, - span: edge.span - }); - } + ConstrainRegSubVar(region, _) | + ConstrainVarSubReg(_, region) => { + state.result.push(SpannedRegion { + region: region, + span: edge.span + }); + } } } } - return result; } + #[cfg(stage0)] fn each_edge(&mut self, graph: &Graph, node_idx: RegionVid, @@ -1724,6 +1789,23 @@ pub impl RegionVarBindings { edge_idx = edge_ptr.next_edge[dir as uint]; } } + #[cfg(not(stage0))] + fn each_edge(&mut self, + graph: &Graph, + node_idx: RegionVid, + dir: Direction, + op: &fn(edge: &GraphEdge) -> bool) -> bool { + let mut edge_idx = + graph.nodes[node_idx.to_uint()].head_edge[dir as uint]; + while edge_idx != uint::max_value { + let edge_ptr = &graph.edges[edge_idx]; + if !op(edge_ptr) { + return false; + } + edge_idx = edge_ptr.next_edge[dir as uint]; + } + return true; + } } fn iterate_until_fixed_point( @@ -1746,4 +1828,3 @@ fn iterate_until_fixed_point( } debug!("---- %s Complete after %u iteration(s)", tag, iteration); } - diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 9b648f6a05341..2b88825c49a69 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -278,4 +278,3 @@ pub impl ResolveState { } } } - diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 266d157c4d040..48d7765f88ec9 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -269,4 +269,3 @@ impl Combine for Sub { super_trait_refs(self, a, b) } } - diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index bc13074422450..3bcff92346566 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -23,7 +23,7 @@ pub enum VarValue { } pub struct ValsAndBindings { - vals: @mut SmallIntMap>, + vals: SmallIntMap>, bindings: ~[(V, VarValue)], } @@ -60,26 +60,25 @@ pub impl InferCtxt { vid: V) -> Node { let vid_u = vid.to_uint(); - match vb.vals.find(&vid_u) { + let var_val = match vb.vals.find(&vid_u) { + Some(&var_val) => var_val, None => { tcx.sess.bug(fmt!( "failed lookup of vid `%u`", vid_u)); } - Some(var_val) => { - match *var_val { - Redirect(vid) => { - let node: Node = helper(tcx, vb, vid); - if node.root != vid { - // Path compression - vb.vals.insert(vid.to_uint(), - Redirect(node.root)); - } - node - } - Root(ref pt, rk) => { - Node {root: vid, possible_types: *pt, rank: rk} - } + }; + match var_val { + Redirect(vid) => { + let node: Node = helper(tcx, vb, vid); + if node.root != vid { + // Path compression + vb.vals.insert(vid.to_uint(), + Redirect(node.root)); } + node + } + Root(pt, rk) => { + Node {root: vid, possible_types: pt, rank: rk} } } } @@ -99,8 +98,8 @@ pub impl InferCtxt { { // FIXME(#4903)---borrow checker is not flow sensitive let vb = UnifyVid::appropriate_vals_and_bindings(self); - let old_v = vb.vals.get(&vid.to_uint()); - vb.bindings.push((vid, *old_v)); + let old_v = { *vb.vals.get(&vid.to_uint()) }; // FIXME(#4903) + vb.bindings.push((vid, old_v)); vb.vals.insert(vid.to_uint(), new_v); } } @@ -265,5 +264,3 @@ impl SimplyUnifiable for ast::float_ty { return ty::terr_float_mismatch(err); } } - - diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 646b6412f5507..5da14d9917173 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -214,7 +214,7 @@ pub fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def { match tcx.def_map.find(&id) { Some(&x) => x, _ => { - tcx.sess.span_fatal(sp, ~"internal error looking up a definition") + tcx.sess.span_fatal(sp, "internal error looking up a definition") } } } @@ -301,8 +301,7 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt, if ps.is_parameterized() => { tcx.sess.span_err( main_span, - ~"main function is not allowed \ - to have type parameters"); + "main function is not allowed to have type parameters"); return; } _ => () @@ -343,8 +342,7 @@ fn check_start_fn_ty(ccx: @mut CrateCtxt, if ps.is_parameterized() => { tcx.sess.span_err( start_span, - ~"start function is not allowed to have type \ - parameters"); + "start function is not allowed to have type parameters"); return; } _ => () @@ -395,7 +393,7 @@ fn check_for_entry_fn(ccx: @mut CrateCtxt) { Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp), None => tcx.sess.bug(~"entry function without a type") }, - None => tcx.sess.err(~"entry function not found") + None => tcx.sess.bug(~"type checking without entry function") } } } @@ -416,7 +414,11 @@ pub fn check_crate(tcx: ty::ctxt, time(time_passes, ~"type collecting", || collect::collect_item_types(ccx, crate)); - time(time_passes, ~"method resolution", || + // this ensures that later parts of type checking can assume that items + // have valid types and not error + tcx.sess.abort_if_errors(); + + time(time_passes, ~"coherence checking", || coherence::check_coherence(ccx, crate)); time(time_passes, ~"type checking", || @@ -426,12 +428,3 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); (ccx.method_map, ccx.vtable_map) } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 65f5b910f3772..e5ed2efa4c263 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -266,11 +266,11 @@ pub struct binding_rscope { region_param_names: RegionParamNames, } -pub fn in_binding_rscope( - self: &RS, +pub fn in_binding_rscope( + this: &RS, region_param_names: RegionParamNames) -> binding_rscope { - let base = @copy *self; + let base = @copy *this; let base = base as @region_scope; binding_rscope { base: base, diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 54c51cf2e487a..6027a04454180 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -20,7 +20,6 @@ #[allow(non_implicitly_copyable_typarams)]; #[allow(non_camel_case_types)]; #[deny(deprecated_pattern)]; -#[deny(deprecated_mode)]; extern mod std(vers = "0.7-pre"); extern mod syntax(vers = "0.7-pre"); @@ -47,6 +46,7 @@ pub mod middle { pub mod controlflow; pub mod glue; pub mod datum; + pub mod write_guard; pub mod callee; pub mod expr; pub mod common; @@ -76,6 +76,9 @@ pub mod middle { } pub mod ty; pub mod subst; + #[cfg(stage0)] #[path = "resolve_stage0.rs"] + pub mod resolve; + #[cfg(not(stage0))] pub mod resolve; #[path = "typeck/mod.rs"] pub mod typeck; @@ -85,6 +88,7 @@ pub mod middle { pub mod lint; #[path = "borrowck/mod.rs"] pub mod borrowck; + pub mod dataflow; pub mod mem_categorization; pub mod liveness; pub mod kind; @@ -96,6 +100,7 @@ pub mod middle { pub mod lang_items; pub mod privacy; pub mod moves; + pub mod entry; } pub mod front { @@ -126,6 +131,7 @@ pub mod driver; pub mod util { pub mod common; pub mod ppaux; + pub mod enum_set; } pub mod lib { @@ -357,11 +363,3 @@ pub fn main() { run_compiler(&args, demitter); } } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 38f55b2b6e423..b4a479fc5970f 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -112,13 +112,3 @@ pub fn pluralize(n: uint, s: ~str) -> ~str { // A set of node IDs (used to keep track of which node IDs are for statements) pub type stmt_set = @mut HashSet; - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/util/enum_set.rs b/src/librustc/util/enum_set.rs new file mode 100644 index 0000000000000..8c4cbd0bce586 --- /dev/null +++ b/src/librustc/util/enum_set.rs @@ -0,0 +1,250 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core; + +#[deriving(Eq, IterBytes)] +pub struct EnumSet { + bits: uint +} + +pub trait CLike { + pub fn to_uint(&self) -> uint; + pub fn from_uint(uint) -> Self; +} + +fn bit(e: E) -> uint { + 1 << e.to_uint() +} + +pub impl EnumSet { + fn empty() -> EnumSet { + EnumSet {bits: 0} + } + + fn is_empty(&self) -> bool { + self.bits == 0 + } + + fn intersects(&self, e: EnumSet) -> bool { + (self.bits & e.bits) != 0 + } + + fn contains(&self, e: EnumSet) -> bool { + (self.bits & e.bits) == e.bits + } + + fn add(&mut self, e: E) { + self.bits |= bit(e); + } + + fn contains_elem(&self, e: E) -> bool { + (self.bits & bit(e)) != 0 + } + + #[cfg(stage0)] + fn each(&self, f: &fn(E) -> bool) { + let mut bits = self.bits; + let mut index = 0; + while bits != 0 { + if (bits & 1) != 0 { + let e = CLike::from_uint(index); + if !f(e) { + return; + } + } + index += 1; + bits >>= 1; + } + } + #[cfg(not(stage0))] + fn each(&self, f: &fn(E) -> bool) -> bool { + let mut bits = self.bits; + let mut index = 0; + while bits != 0 { + if (bits & 1) != 0 { + let e = CLike::from_uint(index); + if !f(e) { + return false; + } + } + index += 1; + bits >>= 1; + } + return true; + } +} + +impl Sub, EnumSet> for EnumSet { + fn sub(&self, e: &EnumSet) -> EnumSet { + EnumSet {bits: self.bits & !e.bits} + } +} + +impl BitOr, EnumSet> for EnumSet { + fn bitor(&self, e: &EnumSet) -> EnumSet { + EnumSet {bits: self.bits | e.bits} + } +} + +impl BitAnd, EnumSet> for EnumSet { + fn bitand(&self, e: &EnumSet) -> EnumSet { + EnumSet {bits: self.bits & e.bits} + } +} + +#[cfg(test)] +mod test { + use core; + use core::iter; + use util::enum_set::*; + + #[deriving(Eq)] + enum Foo { + A, B, C + } + + impl CLike for Foo { + pub fn to_uint(&self) -> uint { + *self as uint + } + + pub fn from_uint(v: uint) -> Foo { + unsafe { cast::transmute(v) } + } + } + + #[test] + fn test_empty() { + let e: EnumSet = EnumSet::empty(); + assert!(e.is_empty()); + } + + /////////////////////////////////////////////////////////////////////////// + // intersect + + #[test] + fn test_two_empties_do_not_intersect() { + let e1: EnumSet = EnumSet::empty(); + let e2: EnumSet = EnumSet::empty(); + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1: EnumSet = EnumSet::empty(); + + let mut e2: EnumSet = EnumSet::empty(); + e2.add(A); + e2.add(B); + e2.add(C); + + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let mut e1: EnumSet = EnumSet::empty(); + e1.add(A); + + let mut e2: EnumSet = EnumSet::empty(); + e2.add(B); + + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let mut e1: EnumSet = EnumSet::empty(); + e1.add(A); + + let mut e2: EnumSet = EnumSet::empty(); + e2.add(A); + e2.add(B); + + assert!(e1.intersects(e2)); + } + + /////////////////////////////////////////////////////////////////////////// + // contains and contains_elem + + #[test] + fn test_contains() { + let mut e1: EnumSet = EnumSet::empty(); + e1.add(A); + + let mut e2: EnumSet = EnumSet::empty(); + e2.add(A); + e2.add(B); + + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + } + + #[test] + fn test_contains_elem() { + let mut e1: EnumSet = EnumSet::empty(); + e1.add(A); + assert!(e1.contains_elem(A)); + assert!(!e1.contains_elem(B)); + assert!(!e1.contains_elem(C)); + + e1.add(A); + e1.add(B); + assert!(e1.contains_elem(A)); + assert!(e1.contains_elem(B)); + assert!(!e1.contains_elem(C)); + } + + /////////////////////////////////////////////////////////////////////////// + // each + + #[test] + fn test_each() { + let mut e1: EnumSet = EnumSet::empty(); + + assert_eq!(~[], iter::to_vec(|f| e1.each(f))) + + e1.add(A); + assert_eq!(~[A], iter::to_vec(|f| e1.each(f))) + + e1.add(C); + assert_eq!(~[A,C], iter::to_vec(|f| e1.each(f))) + + e1.add(C); + assert_eq!(~[A,C], iter::to_vec(|f| e1.each(f))) + + e1.add(B); + assert_eq!(~[A,B,C], iter::to_vec(|f| e1.each(f))) + } + + /////////////////////////////////////////////////////////////////////////// + // operators + + #[test] + fn test_operators() { + let mut e1: EnumSet = EnumSet::empty(); + e1.add(A); + e1.add(C); + + let mut e2: EnumSet = EnumSet::empty(); + e2.add(B); + e2.add(C); + + let e_union = e1 | e2; + assert_eq!(~[A,B,C], iter::to_vec(|f| e_union.each(f))) + + let e_intersection = e1 & e2; + assert_eq!(~[C], iter::to_vec(|f| e_intersection.each(f))) + + let e_subtract = e1 - e2; + assert_eq!(~[A], iter::to_vec(|f| e_subtract.each(f))) + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aa8c3f8fd1b7e..804b23025f09e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -12,8 +12,9 @@ use metadata::encoder; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid}; use middle::ty::{br_fresh, ctxt, field, method}; -use middle::ty::{mt, t, param_bound, param_ty}; -use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region}; +use middle::ty::{mt, t, param_ty}; +use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region, + re_empty}; use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; @@ -28,10 +29,16 @@ use syntax::codemap::span; use syntax::print::pprust; use syntax::{ast, ast_util}; +/// Produces a string suitable for debugging output. pub trait Repr { fn repr(&self, tcx: ctxt) -> ~str; } +/// Produces a string suitable for showing to the user. +pub trait UserString { + fn user_string(&self, tcx: ctxt) -> ~str; +} + pub fn note_and_explain_region(cx: ctxt, prefix: &str, region: ty::Region, @@ -65,6 +72,9 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) Some(&ast_map::node_block(ref blk)) => { explain_span(cx, "block", blk.span) } + Some(&ast_map::node_callee_scope(expr)) => { + explain_span(cx, "callee", expr.span) + } Some(&ast_map::node_expr(expr)) => { match expr.node { ast::expr_call(*) => explain_span(cx, "call", expr.span), @@ -113,6 +123,8 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) re_static => { (~"the static lifetime", None) } + re_empty => { (~"the empty lifetime", None) } + // I believe these cases should not occur (except when debugging, // perhaps) re_infer(_) | re_bound(_) => { @@ -212,7 +224,8 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { bound_region_to_str_space(cx, prefix, br) } re_infer(ReVar(_)) => prefix.to_str(), - re_static => fmt!("%s'static ", prefix) + re_static => fmt!("%s'static ", prefix), + re_empty => fmt!("%s' ", prefix) } } @@ -266,10 +279,6 @@ pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { fmt!("(%s)", str::connect(tstrs, ", ")) } -pub fn bound_to_str(cx: ctxt, b: param_bound) -> ~str { - ty::param_bound_to_str(cx, &b) -} - pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { fmt!("fn%s -> %s", tys_to_str(cx, typ.inputs.map(|a| a.ty)), @@ -277,15 +286,7 @@ pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { } pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { - let path = ty::item_path(cx, trait_ref.def_id); - let base = ast_map::path_to_str(path, cx.sess.intr()); - if cx.sess.verbose() && trait_ref.substs.self_ty.is_some() { - let mut all_tps = copy trait_ref.substs.tps; - for trait_ref.substs.self_ty.each |&t| { all_tps.push(t); } - parameterized(cx, base, trait_ref.substs.self_r, all_tps) - } else { - parameterized(cx, base, trait_ref.substs.self_r, trait_ref.substs.tps) - } + trait_ref.user_string(cx) } pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { @@ -548,15 +549,21 @@ impl Repr for ty::substs { } } -impl Repr for ty::param_bound { +impl Repr for ty::ParamBounds { fn repr(&self, tcx: ctxt) -> ~str { - match *self { - ty::bound_copy => ~"copy", - ty::bound_durable => ~"'static", - ty::bound_owned => ~"owned", - ty::bound_const => ~"const", - ty::bound_trait(ref t) => t.repr(tcx) + let mut res = ~[]; + for self.builtin_bounds.each |b| { + res.push(match b { + ty::BoundCopy => ~"Copy", + ty::BoundStatic => ~"'static", + ty::BoundOwned => ~"Owned", + ty::BoundConst => ~"Const", + }); + } + for self.trait_bounds.each |t| { + res.push(t.repr(tcx)); } + str::connect(res, "+") } } @@ -740,10 +747,61 @@ impl Repr for ty::vstore { } } -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End +impl Repr for ast_map::path_elt { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + ast_map::path_mod(id) => id.repr(tcx), + ast_map::path_name(id) => id.repr(tcx) + } + } +} + +impl Repr for ty::BuiltinBound { + fn repr(&self, _tcx: ctxt) -> ~str { + fmt!("%?", *self) + } +} + +impl UserString for ty::BuiltinBound { + fn user_string(&self, _tcx: ctxt) -> ~str { + match *self { + ty::BoundCopy => ~"Copy", + ty::BoundStatic => ~"'static", + ty::BoundOwned => ~"Owned", + ty::BoundConst => ~"Const" + } + } +} + +impl Repr for ty::BuiltinBounds { + fn repr(&self, tcx: ctxt) -> ~str { + self.user_string(tcx) + } +} + +impl UserString for ty::BuiltinBounds { + fn user_string(&self, tcx: ctxt) -> ~str { + if self.is_empty() { ~"" } else { + let mut result = ~[]; + for self.each |bb| { + result.push(bb.user_string(tcx)); + } + str::connect(result, "+") + } + } +} + +impl UserString for ty::TraitRef { + fn user_string(&self, tcx: ctxt) -> ~str { + let path = ty::item_path(tcx, self.def_id); + let base = ast_map::path_to_str(path, tcx.sess.intr()); + if tcx.sess.verbose() && self.substs.self_ty.is_some() { + let mut all_tps = copy self.substs.tps; + for self.substs.self_ty.each |&t| { all_tps.push(t); } + parameterized(tcx, base, self.substs.self_r, all_tps) + } else { + parameterized(tcx, base, self.substs.self_r, + self.substs.tps) + } + } +} diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index 40ff9b2182964..278f77135f9f5 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -129,13 +129,13 @@ fn first_sentence_(s: &str) -> ~str { }; match idx { Some(idx) if idx > 2u => { - str::from_slice(str::slice(s, 0, idx - 1)) + str::to_owned(str::slice(s, 0, idx - 1)) } _ => { if str::ends_with(s, ~".") { - str::from_slice(s) + str::to_owned(s) } else { - str::from_slice(s) + str::to_owned(s) } } } diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index ce120f477a523..0c49d457ad809 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -14,7 +14,7 @@ use astsrv; use doc::ItemUtils; use doc; -use core::task::local_data::local_data_get; +use core::local_data::local_data_get; use syntax::ast; use syntax; @@ -22,7 +22,7 @@ use syntax; * there. */ macro_rules! interner_key ( () => (cast::transmute::<(uint, uint), - &fn(+v: @@syntax::parse::token::ident_interner)>((-3 as uint, 0u))) + &fn(v: @@syntax::parse::token::ident_interner)>((-3 as uint, 0u))) ) // Hack; rather than thread an interner through everywhere, rely on @@ -274,7 +274,7 @@ fn structdoc_from_struct( item: itemdoc, fields: do struct_def.fields.map |field| { match field.node.kind { - ast::named_field(ident, _, _) => to_str(ident), + ast::named_field(ident, _) => to_str(ident), ast::unnamed_field => ~"(unnamed)", } }, diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs index d9e24453652a7..24bfa62305a94 100644 --- a/src/librustdoc/markdown_index_pass.rs +++ b/src/librustdoc/markdown_index_pass.rs @@ -252,20 +252,6 @@ mod test { }); } - #[test] - fn should_index_foreign_mod_pages() { - let doc = mk_doc( - config::DocPerMod, - ~"extern mod a { }" - ); - assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { - kind: ~"Foreign module", - name: ~"a", - brief: None, - link: ~"a.html" - }); - } - #[test] fn should_add_brief_desc_to_index() { let doc = mk_doc( @@ -280,7 +266,7 @@ mod test { fn should_index_foreign_mod_contents() { let doc = mk_doc( config::DocPerCrate, - ~"extern mod a { fn b(); }" + ~"extern { fn b(); }" ); assert!((&doc.cratemod().nmods()[0].index).get().entries[0] == doc::IndexEntry { diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 16b84190ee391..65171c30a523d 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -276,7 +276,7 @@ fn write_desc( } fn write_sections(ctxt: &Ctxt, sections: &[doc::Section]) { - for vec::each(sections) |section| { + for sections.each |section| { write_section(ctxt, copy *section); } } @@ -439,7 +439,7 @@ fn write_variants( write_header_(ctxt, H4, ~"Variants"); - for vec::each(docs) |variant| { + for docs.each |variant| { write_variant(ctxt, copy *variant); } @@ -465,7 +465,7 @@ fn write_trait(ctxt: &Ctxt, doc: doc::TraitDoc) { } fn write_methods(ctxt: &Ctxt, docs: &[doc::MethodDoc]) { - for vec::each(docs) |doc| { + for docs.each |doc| { write_method(ctxt, copy *doc); } } @@ -702,31 +702,24 @@ mod test { #[test] fn should_write_index_for_foreign_mods() { - let markdown = render(~"extern mod a { fn a(); }"); + let markdown = render(~"extern { fn a(); }"); assert!(str::contains( markdown, ~"\n\n* [Function `a`](#function-a)\n\n" )); } - #[test] - fn should_write_foreign_mods() { - let markdown = render(~"#[doc = \"test\"] extern mod a { }"); - assert!(str::contains(markdown, ~"Foreign module `a`")); - assert!(str::contains(markdown, ~"test")); - } - #[test] fn should_write_foreign_fns() { let markdown = render( - ~"extern mod a { #[doc = \"test\"] fn a(); }"); + ~"extern { #[doc = \"test\"] fn a(); }"); assert!(str::contains(markdown, ~"test")); } #[test] fn should_write_foreign_fn_headers() { let markdown = render( - ~"extern mod a { #[doc = \"test\"] fn a(); }"); + ~"extern { #[doc = \"test\"] fn a(); }"); assert!(str::contains(markdown, ~"## Function `a`")); } diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs index b9a2ee7ccb7c9..e56b0fb60cd12 100644 --- a/src/librustdoc/markdown_writer.rs +++ b/src/librustdoc/markdown_writer.rs @@ -26,8 +26,8 @@ pub type Writer = ~fn(v: WriteInstr); pub type WriterFactory = ~fn(page: doc::Page) -> Writer; pub trait WriterUtils { - fn put_str(&self, +str: ~str); - fn put_line(&self, +str: ~str); + fn put_str(&self, str: ~str); + fn put_line(&self, str: ~str); fn put_done(&self); } @@ -230,6 +230,7 @@ pub fn future_writer_factory( let markdown_ch = markdown_ch.clone(); do task::spawn || { let (writer, future) = future_writer(); + let mut future = future; writer_ch.send(writer); let s = future.get(); markdown_ch.send((copy page, s)); diff --git a/src/librustdoc/pass.rs b/src/librustdoc/pass.rs index 94db038bdec4b..b80f43a7bbd06 100644 --- a/src/librustdoc/pass.rs +++ b/src/librustdoc/pass.rs @@ -17,7 +17,7 @@ use time; /// A single operation on the document model pub struct Pass { name: ~str, - f: @fn(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc + f: @fn(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc } pub fn run_passes( diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs index 629c6955566f5..5560f21af61db 100644 --- a/src/librustdoc/path_pass.rs +++ b/src/librustdoc/path_pass.rs @@ -112,4 +112,3 @@ fn should_record_fn_paths() { assert!(doc.cratemod().mods()[0].fns()[0].path() == ~[~"a"]); } } - diff --git a/src/librustdoc/sort_item_type_pass.rs b/src/librustdoc/sort_item_type_pass.rs index d75565d4ec824..158d407fff64f 100644 --- a/src/librustdoc/sort_item_type_pass.rs +++ b/src/librustdoc/sort_item_type_pass.rs @@ -43,8 +43,6 @@ fn test() { let source = ~"mod imod { } \ - extern mod inmod { - } \ static iconst: int = 0; \ fn ifn() { } \ enum ienum { ivar } \ @@ -63,6 +61,5 @@ fn test() { assert!(doc.cratemod().items[5].name() == ~"__extensions__"); assert!(doc.cratemod().items[6].name() == ~"ifn"); assert!(doc.cratemod().items[7].name() == ~"imod"); - assert!(doc.cratemod().items[8].name() == ~"inmod"); } } diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 303bdc53b6982..9006543a4dee4 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -332,13 +332,7 @@ fn fold_struct( /// what I actually want fn strip_struct_extra_stuff(item: @ast::item) -> @ast::item { let node = match copy item.node { - ast::item_struct(def, tys) => { - let def = @ast::struct_def { - dtor: None, // Remove the drop { } block - .. copy *def - }; - ast::item_struct(def, tys) - } + ast::item_struct(def, tys) => ast::item_struct(def, tys), _ => fail!(~"not a struct") }; @@ -371,7 +365,7 @@ mod test { #[test] fn should_add_foreign_fn_sig() { - let doc = mk_doc(~"extern mod a { fn a() -> int; }"); + let doc = mk_doc(~"extern { fn a() -> int; }"); assert!(doc.cratemod().nmods()[0].fns[0].sig == Some(~"fn a() -> int")); } @@ -440,13 +434,6 @@ mod test { "struct S {")); } - #[test] - fn should_not_serialize_struct_drop_blocks() { - // All we care about are the fields - let doc = mk_doc(~"struct S { field: (), drop { } }"); - assert!(!(&doc.cratemod().structs()[0].sig).get().contains("drop")); - } - #[test] fn should_not_serialize_struct_attrs() { // All we care about are the fields diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc index 0749f20156f1c..836ca1cfa45b5 100644 --- a/src/librusti/rusti.rc +++ b/src/librusti/rusti.rc @@ -96,10 +96,6 @@ fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl { match expr.node { ast::expr_assign(*) | ast::expr_assign_op(*) | - ast::expr_swap(*) => { - pprust::print_stmt(pp, *stmt); - writer.write_line(~""); - } _ => {} } } @@ -156,7 +152,7 @@ fn run(repl: Repl, input: ~str) -> Repl { for crate.node.module.items.each |item| { match item.node { ast::item_fn(_, _, _, _, blk) => { - if item.ident == sess.ident_of(~"main") { + if item.ident == sess.ident_of("main") { opt = blk.node.expr; } } diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 35e70af7914c1..5b19a3bd66042 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -18,5 +18,13 @@ condition! { } condition! { - nonexistent_package: (super::PkgId, ~str) -> super::Path; + nonexistent_package: (super::PkgId, ~str) -> (); +} + +condition! { + copy_failed: (super::Path, super::Path) -> (); +} + +condition! { + missing_pkg_files: (super::PkgId) -> (); } diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index db036f44a185b..348d828bded2f 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -13,6 +13,9 @@ use core::hashmap::HashMap; pub struct Ctx { + // Sysroot -- if this is None, uses rustc filesearch's + // idea of the default + sysroot_opt: Option<@Path>, // I'm not sure what this is for json: bool, // Cache of hashes of things already installed diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 0490f066f0bea..d21fdcda7f76f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -12,6 +12,7 @@ use util::PkgId; use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; +use core::os::mkdir_recursive; #[deriving(Eq)] pub enum OutputType { Main, Lib, Bench, Test } @@ -23,16 +24,12 @@ pub fn rust_path() -> ~[Path] { ~[Path(".")] } -static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; +pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// Creates a directory that is readable, writeable, /// and executable by the user. Returns true iff creation /// succeeded. -pub fn make_dir_rwx(p: &Path) -> bool { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - - os::make_dir(p, u_rwx) -} +pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } /// Replace all occurrences of '-' in the stem part of path with '_' /// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux @@ -70,34 +67,137 @@ pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { result.push(pkgid.path.to_str()) } +/// Figure out what the executable name for in 's build +/// directory is, and if the file exists, return it. +pub fn built_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + let mut result = workspace.push("build"); + result = result.push_rel(&pkgid.path); + // should use a target-specific subdirectory + result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()), + result); + debug!("built_executable_in_workspace: checking whether %s exists", + result.to_str()); + if os::path_exists(&result) { + Some(result) + } + else { + None + } +} + +/// Figure out what the library name for in 's build +/// directory is, and if the file exists, return it. +pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + let mut result = workspace.push("build"); + result = result.push_rel(&pkgid.path); + // should use a target-specific subdirectory + result = mk_output_path(Lib, pkgid.path.to_str(), result); + debug!("built_library_in_workspace: checking whether %s exists", + result.to_str()); + + // We don't know what the hash is, so we have to search through the directory + // contents + let dir_contents = os::list_dir(&result.pop()); + debug!("dir has %? entries", dir_contents.len()); + + // n.b. This code assumes the pkgid's path only has one element + let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str()); + let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX); + + debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); + + let mut result_filename = None; + for dir_contents.each |&p| { + let mut which = 0; + let mut hash = None; + // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix) + // and remember what the hash was + for p.each_split_char('-') |piece| { + debug!("a piece = %s", piece); + if which == 0 && piece != lib_prefix { + break; + } + else if which == 0 { + which += 1; + } + else if which == 1 { + hash = Some(piece.to_owned()); + which += 1; + } + else if which == 2 && piece != lib_filetype { + hash = None; + break; + } + else if which == 2 { + break; + } + else { + // something went wrong + hash = None; + break; + } + } + if hash.is_some() { + result_filename = Some(p); + break; + } + } + + // Return the filename that matches, which we now know exists + // (if result_filename != None) + debug!("result_filename = %?", result_filename); + match result_filename { + None => None, + Some(result_filename) => { + let result_filename = result.with_filename(result_filename); + debug!("result_filename = %s", result_filename.to_str()); + Some(result_filename) + } + } +} + /// Returns the executable that would be installed for /// in +/// As a side effect, creates the bin-dir if it doesn't exist pub fn target_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("bin"); - // should use a target-specific subdirectory - mk_output_path(Main, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Main) } /// Returns the executable that would be installed for /// in +/// As a side effect, creates the bin-dir if it doesn't exist pub fn target_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("lib"); - mk_output_path(Lib, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Lib) } /// Returns the test executable that would be installed for /// in pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("build"); - mk_output_path(Test, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Test) } /// Returns the bench executable that would be installed for /// in pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("build"); - mk_output_path(Bench, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Bench) +} + +fn target_file_in_workspace(pkgid: PkgId, workspace: &Path, + what: OutputType) -> Path { + use conditions::bad_path::cond; + + let (subdir, create_dir) = match what { + Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false) + }; + let result = workspace.push(subdir); + if create_dir { + if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { + cond.raise((result, fmt!("I couldn't create the %s dir", subdir))); + } + } + mk_output_path(what, pkgid.path.to_str(), result) + } /// Return the directory for 's build artifacts in . @@ -123,7 +223,11 @@ pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path { match what { Lib => dir.push(os::dll_filename(short_name)), _ => dir.push(fmt!("%s%s%s", short_name, - if what == Test { ~"test" } else { ~"" }, + match what { + Test => "test", + Bench => "bench", + _ => "" + } os::EXE_SUFFIX)) } } diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index a296f0ca32a48..502f34a4d9e47 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -34,18 +34,21 @@ use syntax::{ast, diagnostic}; use util::*; use path_util::normalize; use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace}; +use path_util::{built_executable_in_workspace, built_library_in_workspace}; +use path_util::{target_executable_in_workspace, target_library_in_workspace}; use workspace::pkg_parent_workspaces; use rustc::driver::session::{lib_crate, bin_crate, crate_type}; use context::Ctx; mod conditions; mod context; -mod usage; mod path_util; mod tests; mod util; mod workspace; +pub mod usage; + /// A PkgScript represents user-supplied custom logic for /// special build hooks. This only exists for packages with /// an explicit package script. @@ -188,49 +191,7 @@ impl Ctx { // argument let pkgid = PkgId::new(args[0]); for pkg_parent_workspaces(pkgid) |workspace| { - let src_dir = pkgid_src_in_workspace(pkgid, workspace); - let build_dir = build_pkg_id_in_workspace(pkgid, workspace); - debug!("Destination dir = %s", build_dir.to_str()); - - // Create the package source - let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid); - debug!("Package src = %?", src); - - // Is there custom build logic? If so, use it - let pkg_src_dir = src_dir; - let mut custom = false; - debug!("Package source directory = %s", pkg_src_dir.to_str()); - let cfgs = match src.package_script_option(&pkg_src_dir) { - Some(package_script_path) => { - let pscript = PkgScript::parse(package_script_path, - workspace, - pkgid); - // Limited right now -- we're only running the post_build - // hook and probably fail otherwise - // also post_build should be called pre_build - let (cfgs, hook_result) = pscript.run_custom(~"post_build"); - debug!("Command return code = %?", hook_result); - if hook_result != 0 { - fail!(fmt!("Error running custom build command")) - } - custom = true; - // otherwise, the package script succeeded - cfgs - } - None => { - debug!("No package script, continuing"); - ~[] - } - }; - - // If there was a package script, it should have finished - // the build already. Otherwise... - if !custom { - // Find crates inside the workspace - src.find_crates(); - // Build it! - src.build(&build_dir, cfgs); - } + self.build(workspace, pkgid); } } ~"clean" => { @@ -304,6 +265,53 @@ impl Ctx { fail!(~"`do` not yet implemented"); } + fn build(&self, workspace: &Path, pkgid: PkgId) { + let src_dir = pkgid_src_in_workspace(pkgid, workspace); + let build_dir = build_pkg_id_in_workspace(pkgid, workspace); + debug!("Destination dir = %s", build_dir.to_str()); + + // Create the package source + let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid); + debug!("Package src = %?", src); + + // Is there custom build logic? If so, use it + let pkg_src_dir = src_dir; + let mut custom = false; + debug!("Package source directory = %s", pkg_src_dir.to_str()); + let cfgs = match src.package_script_option(&pkg_src_dir) { + Some(package_script_path) => { + let pscript = PkgScript::parse(package_script_path, + workspace, + pkgid); + // Limited right now -- we're only running the post_build + // hook and probably fail otherwise + // also post_build should be called pre_build + let (cfgs, hook_result) = pscript.run_custom(~"post_build"); + debug!("Command return code = %?", hook_result); + if hook_result != 0 { + fail!(fmt!("Error running custom build command")) + } + custom = true; + // otherwise, the package script succeeded + cfgs + } + None => { + debug!("No package script, continuing"); + ~[] + } + }; + + // If there was a package script, it should have finished + // the build already. Otherwise... + if !custom { + // Find crates inside the workspace + src.find_crates(); + // Build it! + src.build(&build_dir, cfgs, self.sysroot_opt); + } + + } + fn clean(&self, workspace: &Path, id: PkgId) { // Could also support a custom build hook in the pkg // script for cleaning files rustpkg doesn't know about. @@ -325,9 +333,31 @@ impl Ctx { fail!(~"info not yet implemented"); } - fn install(&self, _workspace: &Path, _id: PkgId) { - // stub - fail!(~"install not yet implemented"); + fn install(&self, workspace: &Path, id: PkgId) { + use conditions::copy_failed::cond; + + // Should use RUST_PATH in the future. + // Also should use workcache to not build if not necessary. + self.build(workspace, id); + + // Now copy stuff into the install dirs + let maybe_executable = built_executable_in_workspace(id, workspace); + let maybe_library = built_library_in_workspace(id, workspace); + let target_exec = target_executable_in_workspace(id, workspace); + let target_lib = target_library_in_workspace(id, workspace); + + for maybe_executable.each |exec| { + debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str()); + if !os::copy_file(exec, &target_exec) { + cond.raise((*exec, target_exec)); + } + } + for maybe_library.each |lib| { + debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); + if !os::copy_file(lib, &target_lib) { + cond.raise((*lib, target_lib)); + } + } } fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>) { @@ -477,6 +507,7 @@ pub fn main() { } Ctx { + sysroot_opt: None, // Currently, only tests override this json: json, dep_cache: @mut HashMap::new() }.run(cmd, args); @@ -610,7 +641,7 @@ impl PkgSrc { fn check_dir(&self) -> Path { - use conditions::bad_path::cond; + use conditions::nonexistent_package::cond; debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str()); @@ -619,13 +650,15 @@ impl PkgSrc { debug!("Checking dir: %s", dir.to_str()); + // tjc: Rather than erroring out, need to try downloading the + // contents of the path to a local directory (#5679) if !os::path_exists(&dir) { - return cond.raise((dir, ~"missing package dir")); + cond.raise((self.id, ~"missing package dir")); } if !os::path_is_dir(&dir) { - return cond.raise((dir, ~"supplied path for package dir is a \ - non-directory")); + cond.raise((self.id, ~"supplied path for package dir is a \ + non-directory")); } dir @@ -680,6 +713,7 @@ impl PkgSrc { /// is no custom build logic fn find_crates(&mut self) { use PkgSrc::push_crate; + use conditions::missing_pkg_files::cond; let dir = self.check_dir(); let prefix = dir.components.len(); @@ -704,7 +738,7 @@ impl PkgSrc { util::note(~"Couldn't infer any crates to build.\n\ Try naming a crate `main.rs`, `lib.rs`, \ `test.rs`, or `bench.rs`."); - fail!(~"Failed to infer crates to build"); + cond.raise(self.id); } debug!("found %u libs, %u mains, %u tests, %u benchs", @@ -714,18 +748,20 @@ impl PkgSrc { self.benchs.len()) } - fn build_crates(&self, dst_dir: &Path, - src_dir: &Path, - crates: &[Crate], - cfgs: ~[~str], - test: bool, crate_type: crate_type) { + fn build_crates(&self, + maybe_sysroot: Option<@Path>, + dst_dir: &Path, + src_dir: &Path, + crates: &[Crate], + cfgs: ~[~str], + test: bool, crate_type: crate_type) { for crates.each |&crate| { let path = &src_dir.push_rel(&crate.file).normalize(); util::note(fmt!("build_crates: compiling %s", path.to_str())); util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); - let result = util::compile_crate(None, self.id, path, + let result = util::compile_crate(maybe_sysroot, self.id, path, dst_dir, crate.flags, crate.cfgs + cfgs, @@ -739,15 +775,15 @@ impl PkgSrc { } } - fn build(&self, dst_dir: &Path, cfgs: ~[~str]) { + fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) { let dir = self.check_dir(); debug!("Building libs"); - self.build_crates(dst_dir, &dir, self.libs, cfgs, false, lib_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, false, lib_crate); debug!("Building mains"); - self.build_crates(dst_dir, &dir, self.mains, cfgs, false, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, false, bin_crate); debug!("Building tests"); - self.build_crates(dst_dir, &dir, self.tests, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, true, bin_crate); debug!("Building benches"); - self.build_crates(dst_dir, &dir, self.benchs, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, true, bin_crate); } } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index bcee2992e5ab9..486e2959e9ed7 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -17,10 +17,12 @@ use std::tempfile::mkdtemp; use util::{PkgId, default_version}; use path_util::{target_executable_in_workspace, target_library_in_workspace, target_test_in_workspace, target_bench_in_workspace, - make_dir_rwx}; + make_dir_rwx, u_rwx}; +use core::os::mkdir_recursive; -fn fake_ctxt() -> Ctx { +fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { Ctx { + sysroot_opt: sysroot_opt, json: false, dep_cache: @mut HashMap::new() } @@ -33,8 +35,34 @@ fn fake_pkg() -> PkgId { } } -fn mk_temp_workspace() -> Path { - mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir") +fn remote_pkg() -> PkgId { + PkgId { + path: Path(~"github.com/catamorphism/test-pkg"), + version: default_version() + } +} + +fn writeFile(file_path: &Path, contents: ~str) { + let out: @io::Writer = + result::get(&io::file_writer(file_path, + ~[io::Create, io::Truncate])); + out.write_line(contents); +} + +fn mk_temp_workspace(short_name: &Path) -> Path { + let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); + let package_dir = workspace.push(~"src").push_rel(short_name); + assert!(mkdir_recursive(&package_dir, u_rwx)); + // Create main, lib, test, and bench files + writeFile(&package_dir.push(~"main.rs"), + ~"fn main() { let _x = (); }"); + writeFile(&package_dir.push(~"lib.rs"), + ~"pub fn f() { let _x = (); }"); + writeFile(&package_dir.push(~"test.rs"), + ~"#[test] pub fn f() { (); }"); + writeFile(&package_dir.push(~"bench.rs"), + ~"#[bench] pub fn f() { (); }"); + workspace } fn is_rwx(p: &Path) -> bool { @@ -42,60 +70,104 @@ fn is_rwx(p: &Path) -> bool { match p.get_mode() { None => return false, - Some(m) => { + Some(m) => ((m & S_IRUSR as uint) == S_IRUSR as uint && (m & S_IWUSR as uint) == S_IWUSR as uint && (m & S_IXUSR as uint) == S_IXUSR as uint) - } } } +#[cfg(test)] +fn test_sysroot() -> Path { + // Totally gross hack but it's just for test cases. + // Infer the sysroot from the exe name and tack "stage2" + // onto it. (Did I mention it was a gross hack?) + let self_path = os::self_exe_path().expect("Couldn't get self_exe path"); + self_path.pop().push("stage2") +} + #[test] fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.push(~"quux"); - let _ = os::remove_dir(&dir); + assert!(!os::path_exists(&dir) || + os::remove_dir_recursive(&dir)); + debug!("Trying to make %s", dir.to_str()); assert!(make_dir_rwx(&dir)); assert!(os::path_is_dir(&dir)); assert!(is_rwx(&dir)); - assert!(os::remove_dir(&dir)); + assert!(os::remove_dir_recursive(&dir)); } #[test] -#[ignore(reason = "install not yet implemented")] fn test_install_valid() { - let ctxt = fake_ctxt(); + let sysroot = test_sysroot(); + debug!("sysroot = %s", sysroot.to_str()); + let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); // should have test, bench, lib, and main ctxt.install(&temp_workspace, temp_pkg_id); // Check that all files exist let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace); + debug!("exec = %s", exec.to_str()); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace); + debug!("lib = %s", lib.to_str()); assert!(os::path_exists(&lib)); assert!(is_rwx(&lib)); // And that the test and bench executables aren't installed assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace))); - assert!(!os::path_exists(&target_bench_in_workspace(temp_pkg_id, &temp_workspace))); + let bench = target_bench_in_workspace(temp_pkg_id, &temp_workspace); + debug!("bench = %s", bench.to_str()); + assert!(!os::path_exists(&bench)); } #[test] -#[ignore(reason = "install not yet implemented")] fn test_install_invalid() { use conditions::nonexistent_package::cond; + use cond1 = conditions::missing_pkg_files::cond; - let ctxt = fake_ctxt(); + let ctxt = fake_ctxt(None); let pkgid = fake_pkg(); - let temp_workspace = mk_temp_workspace(); - let expected_path = Path(~"quux"); - let substituted: Path = do cond.trap(|_| { - expected_path + let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); + let mut error_occurred = false; + let mut error1_occurred = false; + do cond1.trap(|_| { + error1_occurred = true; }).in { - ctxt.install(&temp_workspace, pkgid); - // ok - fail!(~"test_install_invalid failed, should have raised a condition"); - }; - assert!(substituted == expected_path); + do cond.trap(|_| { + error_occurred = true; + }).in { + ctxt.install(&temp_workspace, pkgid); + } + } + assert!(error_occurred && error1_occurred); } + +#[test] +#[ignore(reason = "install from URL-fragment not yet implemented")] +fn test_install_url() { + let sysroot = test_sysroot(); + debug!("sysroot = %s", sysroot.to_str()); + let ctxt = fake_ctxt(Some(@sysroot)); + let temp_pkg_id = remote_pkg(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); + // should have test, bench, lib, and main + ctxt.install(&temp_workspace, temp_pkg_id); + // Check that all files exist + let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace); + debug!("exec = %s", exec.to_str()); + assert!(os::path_exists(&exec)); + assert!(is_rwx(&exec)); + let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace); + debug!("lib = %s", lib.to_str()); + assert!(os::path_exists(&lib)); + assert!(is_rwx(&lib)); + // And that the test and bench executables aren't installed + assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace))); + let bench = target_bench_in_workspace(temp_pkg_id, &temp_workspace); + debug!("bench = %s", bench.to_str()); + assert!(!os::path_exists(&bench)); +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/commands.txt b/src/librustpkg/testsuite/pass/commands.txt index e1a1b2462b253..baeaef1e3c791 100644 --- a/src/librustpkg/testsuite/pass/commands.txt +++ b/src/librustpkg/testsuite/pass/commands.txt @@ -32,4 +32,3 @@ Commands that should succeed: 15. `rustpkg test foo` runs tests and prints their output, if foo contains #[test]s. 16. If foo is installed, `rustpkg uninstall foo; rustpkg list` doesn't include foo in the list - diff --git a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs index 41041ccb50912..62785c06db31a 100644 --- a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs +++ b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs @@ -15,4 +15,3 @@ The test runner should check that, after `rustpkg install deeply/nested/path/foo */ fn main() {} - diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 28198e59f86d4..5e43cb4396075 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -11,6 +11,7 @@ use core::*; use core::cmp::Ord; use core::hash::Streaming; +use core::rt::io::Writer; use rustc::driver::{driver, session}; use rustc::driver::session::{lib_crate, unknown_crate}; use rustc::metadata::filesearch; @@ -367,9 +368,9 @@ pub fn error(msg: ~str) { } pub fn hash(data: ~str) -> ~str { - let hasher = &hash::default_state(); - - hasher.write_str(data); + let mut hasher = hash::default_state(); + let buffer = str::as_bytes_slice(data); + hasher.write(buffer); hasher.result_str() } @@ -435,7 +436,7 @@ pub fn add_pkg(pkg: &Pkg) -> bool { } // FIXME (#4432): Use workcache to only compile when needed -pub fn compile_input(sysroot: Option, +pub fn compile_input(sysroot: Option<@Path>, pkg_id: PkgId, in_file: &Path, out_dir: &Path, @@ -474,9 +475,12 @@ pub fn compile_input(sysroot: Option, out_file.to_str()); debug!("flags: %s", str::connect(flags, ~" ")); debug!("cfgs: %s", str::connect(cfgs, ~" ")); + debug!("compile_input's sysroot = %?", sysroot); let matches = getopts(~[~"-Z", ~"time-passes"] + if building_library { ~[~"--lib"] } + else if test { ~[~"--test"] } + // bench? else { ~[] } + flags + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), @@ -540,9 +544,13 @@ pub fn compile_crate_from_input(input: driver::input, let (crate, _) = driver::compile_upto(sess, cfg, &input, driver::cu_parse, Some(outputs)); + debug!("About to inject link_meta info..."); // Inject the inferred link_meta info if it's not already there // (assumes that name and vers are the only linkage metas) let mut crate_to_use = crate; + + debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len()); + if attr::find_linkage_metas(crate.node.attrs).is_empty() { crate_to_use = add_attrs(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link", // change PkgId to have a field? @@ -552,7 +560,6 @@ pub fn compile_crate_from_input(input: driver::input, mk_string_lit(@pkg_id.version.to_str())))])))]); } - driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use)); crate_to_use } @@ -582,7 +589,7 @@ fn add_attrs(c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate { // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed -pub fn compile_crate(sysroot: Option, pkg_id: PkgId, +pub fn compile_crate(sysroot: Option<@Path>, pkg_id: PkgId, crate: &Path, dir: &Path, flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool, crate_type: crate_type) -> bool { diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 15e2166b24abe..94b94d373e6b6 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -14,7 +14,7 @@ use path_util::{rust_path, workspace_contains_package_id}; use util::PkgId; use core::path::Path; -pub fn pkg_parent_workspaces(pkgid: PkgId, action: &fn(&Path) -> bool) { +pub fn pkg_parent_workspaces(pkgid: PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain // this package ID let workspaces = rust_path().filtered(|ws| @@ -31,4 +31,5 @@ pub fn pkg_parent_workspaces(pkgid: PkgId, action: &fn(&Path) -> bool) { break; } } -} \ No newline at end of file + return true; +} diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index f45fb4e765833..d3f774a1cd51f 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -17,9 +17,7 @@ use sync; use sync::{Mutex, mutex_with_condvars, RWlock, rwlock_with_condvars}; use core::cast; -use core::unstable::{SharedMutableState, shared_mutable_state}; -use core::unstable::{clone_shared_mutable_state}; -use core::unstable::{get_shared_mutable_state, get_shared_immutable_state}; +use core::unstable::sync::UnsafeAtomicRcBox; use core::ptr; use core::task; @@ -83,11 +81,11 @@ pub impl<'self> Condvar<'self> { ****************************************************************************/ /// An atomically reference counted wrapper for shared immutable state. -struct ARC { x: SharedMutableState } +struct ARC { x: UnsafeAtomicRcBox } /// Create an atomically reference counted wrapper. pub fn ARC(data: T) -> ARC { - ARC { x: unsafe { shared_mutable_state(data) } } + ARC { x: UnsafeAtomicRcBox::new(data) } } /** @@ -95,7 +93,7 @@ pub fn ARC(data: T) -> ARC { * wrapper. */ pub fn get<'a, T:Const + Owned>(rc: &'a ARC) -> &'a T { - unsafe { get_shared_immutable_state(&rc.x) } + unsafe { &*rc.x.get_immut() } } /** @@ -106,7 +104,7 @@ pub fn get<'a, T:Const + Owned>(rc: &'a ARC) -> &'a T { * allowing them to share the underlying data. */ pub fn clone(rc: &ARC) -> ARC { - ARC { x: unsafe { clone_shared_mutable_state(&rc.x) } } + ARC { x: rc.x.clone() } } impl Clone for ARC { @@ -122,7 +120,7 @@ impl Clone for ARC { #[doc(hidden)] struct MutexARCInner { lock: Mutex, failed: bool, data: T } /// An ARC with mutable data protected by a blocking mutex. -struct MutexARC { x: SharedMutableState> } +struct MutexARC { x: UnsafeAtomicRcBox> } /// Create a mutex-protected ARC with the supplied data. pub fn MutexARC(user_data: T) -> MutexARC { @@ -137,7 +135,7 @@ pub fn mutex_arc_with_condvars(user_data: T, let data = MutexARCInner { lock: mutex_with_condvars(num_condvars), failed: false, data: user_data }; - MutexARC { x: unsafe { shared_mutable_state(data) } } + MutexARC { x: UnsafeAtomicRcBox::new(data) } } impl Clone for MutexARC { @@ -145,7 +143,7 @@ impl Clone for MutexARC { fn clone(&self) -> MutexARC { // NB: Cloning the underlying mutex is not necessary. Its reference // count would be exactly the same as the shared state's. - MutexARC { x: unsafe { clone_shared_mutable_state(&self.x) } } + MutexARC { x: self.x.clone() } } } @@ -176,7 +174,7 @@ pub impl MutexARC { */ #[inline(always)] unsafe fn access(&self, blk: &fn(x: &mut T) -> U) -> U { - let state = get_shared_mutable_state(&self.x); + let state = self.x.get(); // Borrowck would complain about this if the function were // not already unsafe. See borrow_rwlock, far below. do (&(*state).lock).lock { @@ -192,7 +190,7 @@ pub impl MutexARC { &self, blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) -> U { - let state = get_shared_mutable_state(&self.x); + let state = self.x.get(); do (&(*state).lock).lock_cond |cond| { check_poison(true, (*state).failed); let _z = PoisonOnFail(&mut (*state).failed); @@ -252,8 +250,9 @@ struct RWARCInner { lock: RWlock, failed: bool, data: T } * * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ +#[mutable] struct RWARC { - x: SharedMutableState>, + x: UnsafeAtomicRcBox>, cant_nest: () } @@ -272,13 +271,13 @@ pub fn rw_arc_with_condvars( let data = RWARCInner { lock: rwlock_with_condvars(num_condvars), failed: false, data: user_data }; - RWARC { x: unsafe { shared_mutable_state(data) }, cant_nest: () } + RWARC { x: UnsafeAtomicRcBox::new(data), cant_nest: () } } pub impl RWARC { /// Duplicate a rwlock-protected ARC, as arc::clone. fn clone(&self) -> RWARC { - RWARC { x: unsafe { clone_shared_mutable_state(&self.x) }, + RWARC { x: self.x.clone(), cant_nest: () } } @@ -298,7 +297,7 @@ pub impl RWARC { #[inline(always)] fn write(&self, blk: &fn(x: &mut T) -> U) -> U { unsafe { - let state = get_shared_mutable_state(&self.x); + let state = self.x.get(); do (*borrow_rwlock(state)).write { check_poison(false, (*state).failed); let _z = PoisonOnFail(&mut (*state).failed); @@ -312,7 +311,7 @@ pub impl RWARC { blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) -> U { unsafe { - let state = get_shared_mutable_state(&self.x); + let state = self.x.get(); do (*borrow_rwlock(state)).write_cond |cond| { check_poison(false, (*state).failed); let _z = PoisonOnFail(&mut (*state).failed); @@ -333,10 +332,12 @@ pub impl RWARC { * access modes, this will not poison the ARC. */ fn read(&self, blk: &fn(x: &T) -> U) -> U { - let state = unsafe { get_shared_immutable_state(&self.x) }; - do (&state.lock).read { - check_poison(false, state.failed); - blk(&state.data) + let state = self.x.get(); + unsafe { + do (*state).lock.read { + check_poison(false, (*state).failed); + blk(&(*state).data) + } } } @@ -359,7 +360,7 @@ pub impl RWARC { */ fn write_downgrade(&self, blk: &fn(v: RWWriteMode) -> U) -> U { unsafe { - let state = get_shared_mutable_state(&self.x); + let state = self.x.get(); do (*borrow_rwlock(state)).write_downgrade |write_mode| { check_poison(false, (*state).failed); blk(RWWriteMode { @@ -373,25 +374,27 @@ pub impl RWARC { /// To be called inside of the write_downgrade block. fn downgrade<'a>(&self, token: RWWriteMode<'a, T>) -> RWReadMode<'a, T> { - // The rwlock should assert that the token belongs to us for us. - let state = unsafe { get_shared_immutable_state(&self.x) }; - let RWWriteMode { - data: data, - token: t, - poison: _poison - } = token; - // Let readers in - let new_token = (&state.lock).downgrade(t); - // Whatever region the input reference had, it will be safe to use - // the same region for the output reference. (The only 'unsafe' part - // of this cast is removing the mutability.) - let new_data = unsafe { cast::transmute_immut(data) }; - // Downgrade ensured the token belonged to us. Just a sanity check. - assert!(ptr::ref_eq(&state.data, new_data)); - // Produce new token - RWReadMode { - data: new_data, - token: new_token, + unsafe { + // The rwlock should assert that the token belongs to us for us. + let state = self.x.get(); + let RWWriteMode { + data: data, + token: t, + poison: _poison + } = token; + // Let readers in + let new_token = (*state).lock.downgrade(t); + // Whatever region the input reference had, it will be safe to use + // the same region for the output reference. (The only 'unsafe' part + // of this cast is removing the mutability.) + let new_data = cast::transmute_immut(data); + // Downgrade ensured the token belonged to us. Just a sanity check. + assert!(ptr::ref_eq(&(*state).data, new_data)); + // Produce new token + RWReadMode { + data: new_data, + token: new_token, + } } } } @@ -419,26 +422,26 @@ pub struct RWReadMode<'self, T> { pub impl<'self, T:Const + Owned> RWWriteMode<'self, T> { /// Access the pre-downgrade RWARC in write mode. - fn write(&self, blk: &fn(x: &mut T) -> U) -> U { + fn write(&mut self, blk: &fn(x: &mut T) -> U) -> U { match *self { RWWriteMode { - data: ref data, + data: &ref mut data, token: ref token, poison: _ } => { do token.write { - blk(&mut **data) + blk(data) } } } } /// Access the pre-downgrade RWARC in write mode with a condvar. - fn write_cond<'x, 'c, U>(&self, + fn write_cond<'x, 'c, U>(&mut self, blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) -> U { match *self { RWWriteMode { - data: ref data, + data: &ref mut data, token: ref token, poison: ref poison } => { @@ -449,7 +452,7 @@ pub impl<'self, T:Const + Owned> RWWriteMode<'self, T> { failed: &mut *poison.failed, cond: cond }; - blk(&mut **data, &cvar) + blk(data, &cvar) } } } @@ -483,7 +486,6 @@ mod tests { use core::cell::Cell; use core::task; - use core::vec; #[test] fn manually_share_arc() { @@ -498,7 +500,7 @@ mod tests { let arc_v = p.recv(); - let v = *arc::get::<~[int]>(&arc_v); + let v = copy *arc::get::<~[int]>(&arc_v); assert!(v[3] == 4); }; @@ -598,8 +600,8 @@ mod tests { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { - do arc2.write_downgrade |write_mode| { - do (&write_mode).write |one| { + do arc2.write_downgrade |mut write_mode| { + do write_mode.write |one| { assert!(*one == 2); } } @@ -672,8 +674,9 @@ mod tests { let mut children = ~[]; for 5.times { let arc3 = (*arc).clone(); - do task::task().future_result(|+r| children.push(r)).spawn - || { + let mut builder = task::task(); + builder.future_result(|r| children.push(r)); + do builder.spawn { do arc3.read |num| { assert!(*num >= 0); } @@ -681,11 +684,15 @@ mod tests { } // Wait for children to pass their asserts - for vec::each(children) |r| { r.recv(); } + for children.each |r| { + r.recv(); + } // Wait for writer to finish p.recv(); - do arc.read |num| { assert!(*num == 10); } + do arc.read |num| { + assert!(*num == 10); + } } #[test] fn test_rw_downgrade() { @@ -733,8 +740,8 @@ mod tests { } // Downgrader (us) - do arc.write_downgrade |write_mode| { - do (&write_mode).write_cond |state, cond| { + do arc.write_downgrade |mut write_mode| { + do write_mode.write_cond |state, cond| { wc1.send(()); // send to another writer who will wake us up while *state == 0 { cond.wait(); @@ -742,7 +749,7 @@ mod tests { assert!(*state == 42); *state = 31337; // send to other readers - for vec::each(reader_convos) |x| { + for reader_convos.each |x| { match *x { (ref rc, _) => rc.send(()), } @@ -751,7 +758,7 @@ mod tests { let read_mode = arc.downgrade(write_mode); do (&read_mode).read |state| { // complete handshake with other readers - for vec::each(reader_convos) |x| { + for reader_convos.each |x| { match *x { (_, ref rp) => rp.recv(), } diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 8e2c734504512..fd9fba8c1d753 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -20,7 +20,7 @@ // calling the destructors on them. // One subtle point that needs to be addressed is how to handle // failures while running the user provided initializer function. It -// is important to not run the destructor on uninitalized objects, but +// is important to not run the destructor on uninitialized objects, but // how to detect them is somewhat subtle. Since alloc() can be invoked // recursively, it is not sufficient to simply exclude the most recent // object. To solve this without requiring extra space, we use the low @@ -32,11 +32,10 @@ // overhead when initializing plain-old-data and means we don't need // to waste time running the destructors of POD. -use list; -use list::{List, Cons, Nil}; +use list::{MutList, MutCons, MutNil}; use core::at_vec; -use core::cast::transmute; +use core::cast::{transmute, transmute_mut_region}; use core::cast; use core::libc::size_t; use core::ptr; @@ -48,7 +47,7 @@ use core::vec; pub mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { - fn move_val_init(dst: &mut T, +src: T); + fn move_val_init(dst: &mut T, src: T); fn needs_drop() -> bool; } } @@ -74,17 +73,17 @@ static tydesc_drop_glue_index: size_t = 3 as size_t; // will always stay at 0. struct Chunk { data: @[u8], - mut fill: uint, + fill: uint, is_pod: bool, } pub struct Arena { - // The head is seperated out from the list as a unbenchmarked + // The head is separated out from the list as a unbenchmarked // microoptimization, to avoid needing to case on the list to // access the head. - priv mut head: Chunk, - priv mut pod_head: Chunk, - priv mut chunks: @List, + priv head: Chunk, + priv pod_head: Chunk, + priv chunks: @mut MutList, } #[unsafe_destructor] @@ -92,8 +91,10 @@ impl Drop for Arena { fn finalize(&self) { unsafe { destroy_chunk(&self.head); - for list::each(self.chunks) |chunk| { - if !chunk.is_pod { destroy_chunk(chunk); } + for self.chunks.each |chunk| { + if !chunk.is_pod { + destroy_chunk(chunk); + } } } } @@ -113,7 +114,7 @@ pub fn arena_with_size(initial_size: uint) -> Arena { Arena { head: chunk(initial_size, false), pod_head: chunk(initial_size, true), - chunks: @Nil, + chunks: @mut MutNil, } } @@ -170,11 +171,11 @@ unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) { pub impl Arena { // Functions for the POD part of the arena - priv fn alloc_pod_grow(&self, n_bytes: uint, align: uint) -> *u8 { + priv fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.pod_head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); - self.chunks = @Cons(copy self.pod_head, self.chunks); + self.chunks = @mut MutCons(copy self.pod_head, self.chunks); self.pod_head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true); @@ -182,41 +183,27 @@ pub impl Arena { } #[inline(always)] - priv fn alloc_pod_inner(&self, n_bytes: uint, align: uint) -> *u8 { - let head = &mut self.pod_head; + priv 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 end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_pod_grow(n_bytes, align); - } - head.fill = end; + let start = round_up_to(head.fill, align); + let end = start + n_bytes; + if end > at_vec::capacity(head.data) { + return self.alloc_pod_grow(n_bytes, align); + } + head.fill = end; - //debug!("idx = %u, size = %u, align = %u, fill = %u", - // start, n_bytes, align, head.fill); + //debug!("idx = %u, size = %u, align = %u, fill = %u", + // start, n_bytes, align, head.fill); - unsafe { ptr::offset(vec::raw::to_ptr(head.data), start) } } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_pod(&self, op: &fn() -> T) -> &'self T { - unsafe { - let tydesc = sys::get_type_desc::(); - let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); - let ptr: *mut T = transmute(ptr); - rusti::move_val_init(&mut (*ptr), op()); - return transmute(ptr); - } - } - - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - priv fn alloc_pod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + priv fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); @@ -227,11 +214,12 @@ pub impl Arena { } // Functions for the non-POD part of the arena - priv fn alloc_nonpod_grow(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { + priv fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint) + -> (*u8, *u8) { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); - self.chunks = @Cons(copy self.head, self.chunks); + self.chunks = @mut MutCons(copy self.head, self.chunks); self.head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false); @@ -239,30 +227,30 @@ pub impl Arena { } #[inline(always)] - priv fn alloc_nonpod_inner(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { - let head = &mut self.head; - - let tydesc_start = head.fill; - let after_tydesc = head.fill + sys::size_of::<*TypeDesc>(); - let start = round_up_to(after_tydesc, align); - let end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_nonpod_grow(n_bytes, align); - } - head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>()); + priv fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint) + -> (*u8, *u8) { + unsafe { + let head = transmute_mut_region(&mut self.head); + + let tydesc_start = head.fill; + let after_tydesc = head.fill + sys::size_of::<*TypeDesc>(); + let start = round_up_to(after_tydesc, align); + let end = start + n_bytes; + if end > at_vec::capacity(head.data) { + return self.alloc_nonpod_grow(n_bytes, align); + } + head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>()); - //debug!("idx = %u, size = %u, align = %u, fill = %u", - // start, n_bytes, align, head.fill); + //debug!("idx = %u, size = %u, align = %u, fill = %u", + // start, n_bytes, align, head.fill); - unsafe { let buf = vec::raw::to_ptr(head.data); return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start)); } } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_nonpod(&self, op: &fn() -> T) -> &'self T { + priv fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let (ty_ptr, ptr) = @@ -282,62 +270,25 @@ pub impl Arena { } } - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - priv fn alloc_nonpod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { - unsafe { - let tydesc = sys::get_type_desc::(); - let (ty_ptr, ptr) = - self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); - let ty_ptr: *mut uint = transmute(ty_ptr); - let ptr: *mut T = transmute(ptr); - // Write in our tydesc along with a bit indicating that it - // has *not* been initialized yet. - *ty_ptr = transmute(tydesc); - // Actually initialize it - rusti::move_val_init(&mut(*ptr), op()); - // Now that we are done, update the tydesc to indicate that - // the object is there. - *ty_ptr = bitpack_tydesc_ptr(tydesc, true); - - return transmute(ptr); - } - } - - // The external interface - #[inline(always)] - #[cfg(stage0)] - fn alloc(&self, op: &fn() -> T) -> &'self T { - unsafe { - if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { - self.alloc_nonpod(op) - } - } - } - // The external interface #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + fn alloc<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { + // XXX: Borrow check + let this = transmute_mut_region(self); if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { - self.alloc_nonpod(op) + return this.alloc_pod(op); } + // XXX: Borrow check + let this = transmute_mut_region(self); + this.alloc_nonpod(op) } } } #[test] fn test_arena_destructors() { - let arena = Arena(); + let mut arena = Arena(); for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it // doesn't leak. @@ -348,9 +299,11 @@ fn test_arena_destructors() { } } -#[test] #[should_fail] #[ignore(cfg(windows))] +#[test] +#[should_fail] +#[ignore(cfg(windows))] fn test_arena_destructors_fail() { - let arena = Arena(); + let mut arena = Arena(); // Put some stuff in the arena. for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it @@ -362,9 +315,6 @@ fn test_arena_destructors_fail() { } // Now, fail while allocating do arena.alloc::<@int> { - // First, recursively allocate something else; that needs to - // get freed too. - do arena.alloc { @20 }; // Now fail. fail!(); }; diff --git a/src/libstd/base64.rs b/src/libstd/base64.rs index b26296c9acae4..85ba2707863dc 100644 --- a/src/libstd/base64.rs +++ b/src/libstd/base64.rs @@ -156,31 +156,27 @@ impl FromBase64 for ~[u8] { let ch = self[i] as char; n <<= 6u; - if ch >= 'A' && ch <= 'Z' { - n |= (ch as uint) - 0x41u; - } else if ch >= 'a' && ch <= 'z' { - n |= (ch as uint) - 0x47u; - } else if ch >= '0' && ch <= '9' { - n |= (ch as uint) + 0x04u; - } else if ch == '+' { - n |= 0x3Eu; - } else if ch == '/' { - n |= 0x3Fu; - } else if ch == '=' { - match len - i { - 1u => { - r.push(((n >> 16u) & 0xFFu) as u8); - r.push(((n >> 8u ) & 0xFFu) as u8); - return copy r; - } - 2u => { - r.push(((n >> 10u) & 0xFFu) as u8); - return copy r; - } - _ => fail!(~"invalid base64 padding") + match ch { + 'A'..'Z' => n |= (ch as uint) - 0x41, + 'a'..'z' => n |= (ch as uint) - 0x47, + '0'..'9' => n |= (ch as uint) + 0x04, + '+' => n |= 0x3E, + '/' => n |= 0x3F, + '=' => { + match len - i { + 1u => { + r.push(((n >> 16u) & 0xFFu) as u8); + r.push(((n >> 8u ) & 0xFFu) as u8); + return copy r; + } + 2u => { + r.push(((n >> 10u) & 0xFFu) as u8); + return copy r; + } + _ => fail!(~"invalid base64 padding") + } } - } else { - fail!(~"invalid base64 character"); + _ => fail!(~"invalid base64 character") } i += 1u; diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 5314c35419cc5..09f86f30d320f 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -143,6 +143,7 @@ pub impl BigBitv { } #[inline(always)] + #[cfg(stage0)] fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) { for uint::range(0, self.storage.len()) |i| { let mut w = self.storage[i]; @@ -150,7 +151,12 @@ pub impl BigBitv { self.storage[i] = w; if !b { break; } } - } + } + #[inline(always)] + #[cfg(not(stage0))] + fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) -> bool { + uint::range(0, self.storage.len(), |i| op(&mut self.storage[i])) + } #[inline(always)] fn invert(&mut self) { for self.each_storage |w| { *w = !*w } } @@ -193,6 +199,7 @@ pub impl BigBitv { } #[inline(always)] + #[cfg(stage0)] fn equals(&self, b: &BigBitv, nbits: uint) -> bool { let len = b.storage.len(); for uint::iterate(0, len) |i| { @@ -203,6 +210,19 @@ pub impl BigBitv { } } + #[inline(always)] + #[cfg(not(stage0))] + fn equals(&self, b: &BigBitv, nbits: uint) -> bool { + let len = b.storage.len(); + for uint::iterate(0, len) |i| { + let mask = big_mask(nbits, i); + if mask & self.storage[i] != mask & b.storage[i] { + return false; + } + } + return true; + } + } enum BitvVariant { Big(~BigBitv), Small(~SmallBitv) } @@ -215,16 +235,16 @@ pub struct Bitv { nbits: uint } -priv impl Bitv { +fn die() -> ! { + fail!(~"Tried to do operation on bit vectors with different sizes"); +} - fn die(&self) -> ! { - fail!(~"Tried to do operation on bit vectors with different sizes"); - } +priv impl Bitv { #[inline(always)] fn do_op(&mut self, op: Op, other: &Bitv) -> bool { if self.nbits != other.nbits { - self.die(); + die(); } match self.rep { Small(ref mut s) => match other.rep { @@ -234,10 +254,10 @@ priv impl Bitv { Assign => s.become(*s1, self.nbits), Difference => s.difference(*s1, self.nbits) }, - Big(_) => self.die() + Big(_) => die() }, Big(ref mut s) => match other.rep { - Small(_) => self.die(), + Small(_) => die(), Big(ref s1) => match op { Union => s.union(*s1, self.nbits), Intersect => s.intersect(*s1, self.nbits), @@ -387,6 +407,7 @@ pub impl Bitv { } #[inline(always)] + #[cfg(stage0)] fn each(&self, f: &fn(bool) -> bool) { let mut i = 0; while i < self.nbits { @@ -394,6 +415,16 @@ pub impl Bitv { i += 1; } } + #[inline(always)] + #[cfg(not(stage0))] + fn each(&self, f: &fn(bool) -> bool) -> bool { + let mut i = 0; + while i < self.nbits { + if !f(self.get(i)) { return false; } + i += 1; + } + return true; + } /// Returns true if all bits are 0 fn is_false(&self) -> bool { @@ -488,6 +519,7 @@ pub impl Bitv { true } + #[cfg(stage0)] fn ones(&self, f: &fn(uint) -> bool) { for uint::range(0, self.nbits) |i| { if self.get(i) { @@ -495,6 +527,10 @@ pub impl Bitv { } } } + #[cfg(not(stage0))] + fn ones(&self, f: &fn(uint) -> bool) -> bool { + uint::range(0, self.nbits, |i| !self.get(i) || f(i)) + } } @@ -661,18 +697,21 @@ pub impl BitvSet { } } +#[cfg(not(stage0))] impl BaseIter for BitvSet { fn size_hint(&self) -> Option { Some(self.len()) } - fn each(&self, blk: &fn(v: &uint) -> bool) { + fn each(&self, blk: &fn(v: &uint) -> bool) -> bool { for self.bitv.storage.eachi |i, &w| { if !iterate_bits(i * uint::bits, w, |b| blk(&b)) { - return; + return false; } } + return true; } } +#[cfg(not(stage0))] impl cmp::Eq for BitvSet { fn eq(&self, other: &BitvSet) -> bool { if self.size != other.size { @@ -706,6 +745,7 @@ impl Mutable for BitvSet { } } +#[cfg(not(stage0))] impl Set for BitvSet { fn contains(&self, value: &uint) -> bool { *value < self.bitv.storage.len() * uint::bits && self.bitv.get(*value) @@ -773,64 +813,55 @@ impl Set for BitvSet { other.is_subset(self) } - fn difference(&self, other: &BitvSet, f: &fn(&uint) -> bool) { + fn difference(&self, other: &BitvSet, f: &fn(&uint) -> bool) -> bool { for self.each_common(other) |i, w1, w2| { if !iterate_bits(i, w1 & !w2, |b| f(&b)) { - return; + return false; } } /* everything we have that they don't also shows up */ self.each_outlier(other, |mine, i, w| !mine || iterate_bits(i, w, |b| f(&b)) - ); + ) } fn symmetric_difference(&self, other: &BitvSet, - f: &fn(&uint) -> bool) { + f: &fn(&uint) -> bool) -> bool { for self.each_common(other) |i, w1, w2| { if !iterate_bits(i, w1 ^ w2, |b| f(&b)) { - return; + return false; } } - self.each_outlier(other, |_, i, w| - iterate_bits(i, w, |b| f(&b)) - ); + self.each_outlier(other, |_, i, w| iterate_bits(i, w, |b| f(&b))) } - fn intersection(&self, other: &BitvSet, f: &fn(&uint) -> bool) { - for self.each_common(other) |i, w1, w2| { - if !iterate_bits(i, w1 & w2, |b| f(&b)) { - return; - } - } + fn intersection(&self, other: &BitvSet, f: &fn(&uint) -> bool) -> bool { + self.each_common(other, |i, w1, w2| iterate_bits(i, w1 & w2, |b| f(&b))) } - fn union(&self, other: &BitvSet, f: &fn(&uint) -> bool) { + fn union(&self, other: &BitvSet, f: &fn(&uint) -> bool) -> bool { for self.each_common(other) |i, w1, w2| { if !iterate_bits(i, w1 | w2, |b| f(&b)) { - return; + return false; } } - self.each_outlier(other, |_, i, w| - iterate_bits(i, w, |b| f(&b)) - ); + self.each_outlier(other, |_, i, w| iterate_bits(i, w, |b| f(&b))) } } +#[cfg(not(stage0))] priv impl BitvSet { /// Visits each of the words that the two bit vectors (self and other) /// both have in common. The three yielded arguments are (bit location, /// w1, w2) where the bit location is the number of bits offset so far, /// and w1/w2 are the words coming from the two vectors self, other. fn each_common(&self, other: &BitvSet, - f: &fn(uint, uint, uint) -> bool) { + f: &fn(uint, uint, uint) -> bool) -> bool { let min = uint::min(self.bitv.storage.len(), other.bitv.storage.len()); - for self.bitv.storage.slice(0, min).eachi |i, &w| { - if !f(i * uint::bits, w, other.bitv.storage[i]) { - return; - } - } + self.bitv.storage.slice(0, min).eachi(|i, &w| { + f(i * uint::bits, w, other.bitv.storage[i]) + }) } /// Visits each word in self or other that extends beyond the other. This @@ -841,7 +872,7 @@ priv impl BitvSet { /// is true if the word comes from 'self', and false if it comes from /// 'other'. fn each_outlier(&self, other: &BitvSet, - f: &fn(bool, uint, uint) -> bool) { + f: &fn(bool, uint, uint) -> bool) -> bool { let len1 = self.bitv.storage.len(); let len2 = other.bitv.storage.len(); let min = uint::min(len1, len2); @@ -849,14 +880,15 @@ priv impl BitvSet { /* only one of these loops will execute and that's the point */ for self.bitv.storage.slice(min, len1).eachi |i, &w| { if !f(true, (i + min) * uint::bits, w) { - return; + return false; } } for other.bitv.storage.slice(min, len2).eachi |i, &w| { if !f(false, (i + min) * uint::bits, w) { - return; + return false; } } + return true; } } @@ -1426,7 +1458,7 @@ mod tests { #[bench] fn bench_uint_small(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = 0 as uint; do b.iter { bitv |= (1 << ((r.next() as uint) % uint::bits)); @@ -1435,7 +1467,7 @@ mod tests { #[bench] fn bench_small_bitv_small(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = SmallBitv::new(uint::bits); do b.iter { bitv.set((r.next() as uint) % uint::bits, true); @@ -1444,7 +1476,7 @@ mod tests { #[bench] fn bench_big_bitv_small(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = BigBitv::new(~[0]); do b.iter { bitv.set((r.next() as uint) % uint::bits, true); @@ -1453,7 +1485,7 @@ mod tests { #[bench] fn bench_big_bitv_big(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut storage = ~[]; storage.grow(bench_bits / uint::bits, &0); let mut bitv = BigBitv::new(storage); @@ -1464,7 +1496,7 @@ mod tests { #[bench] fn bench_bitv_big(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = Bitv::new(bench_bits, false); do b.iter { bitv.set((r.next() as uint) % bench_bits, true); @@ -1473,7 +1505,7 @@ mod tests { #[bench] fn bench_bitv_small(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = Bitv::new(uint::bits, false); do b.iter { bitv.set((r.next() as uint) % uint::bits, true); @@ -1482,7 +1514,7 @@ mod tests { #[bench] fn bench_bitv_set_small(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = BitvSet::new(); do b.iter { bitv.insert((r.next() as uint) % uint::bits); @@ -1491,7 +1523,7 @@ mod tests { #[bench] fn bench_bitv_set_big(b: &mut BenchHarness) { - let r = rng(); + let mut r = rng(); let mut bitv = BitvSet::new(); do b.iter { bitv.insert((r.next() as uint) % bench_bits); @@ -1507,13 +1539,3 @@ mod tests { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index b4b4e2bf1a2cb..17b7bae6de5df 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -78,7 +78,7 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes { * * base - A foreign pointer to a buffer * * len - The number of elements in the buffer */ -pub fn CVec(base: *mut T, len: uint) -> CVec { +pub unsafe fn CVec(base: *mut T, len: uint) -> CVec { return CVec{ base: base, len: len, @@ -97,7 +97,7 @@ pub fn CVec(base: *mut T, len: uint) -> CVec { * * dtor - A function to run when the value is destructed, useful * for freeing the buffer, etc. */ -pub fn c_vec_with_dtor(base: *mut T, len: uint, dtor: @fn()) +pub unsafe fn c_vec_with_dtor(base: *mut T, len: uint, dtor: @fn()) -> CVec { return CVec{ base: base, @@ -138,7 +138,7 @@ pub fn set(t: CVec, ofs: uint, v: T) { pub fn len(t: CVec) -> uint { t.len } /// Returns a pointer to the first element of the vector -pub fn ptr(t: CVec) -> *mut T { t.base } +pub unsafe fn ptr(t: CVec) -> *mut T { t.base } #[cfg(test)] mod tests { @@ -191,7 +191,7 @@ mod tests { #[test] fn test_and_I_mean_it() { let cv = malloc(16u as size_t); - let p = ptr(cv); + let p = unsafe { ptr(cv) }; set(cv, 0u, 32u8); set(cv, 1u, 33u8); diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs deleted file mode 100644 index 5d7f64a7c8fa0..0000000000000 --- a/src/libstd/cmp.rs +++ /dev/null @@ -1,102 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Additional general-purpose comparison functionality. - -use core::f32; -use core::f64; -use core::float; - -pub static FUZZY_EPSILON: float = 1.0e-6; - -pub trait FuzzyEq { - fn fuzzy_eq(&self, other: &Self) -> bool; - fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Eps) -> bool; -} - -impl FuzzyEq for float { - fn fuzzy_eq(&self, other: &float) -> bool { - self.fuzzy_eq_eps(other, &FUZZY_EPSILON) - } - - fn fuzzy_eq_eps(&self, other: &float, epsilon: &float) -> bool { - float::abs(*self - *other) < *epsilon - } -} - -impl FuzzyEq for f32 { - fn fuzzy_eq(&self, other: &f32) -> bool { - self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f32)) - } - - fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool { - f32::abs(*self - *other) < *epsilon - } -} - -impl FuzzyEq for f64 { - fn fuzzy_eq(&self, other: &f64) -> bool { - self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f64)) - } - - fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool { - f64::abs(*self - *other) < *epsilon - } -} - -#[test] -fn test_fuzzy_equals() { - assert!((&1.0f).fuzzy_eq(&1.0)); - assert!((&1.0f32).fuzzy_eq(&1.0f32)); - assert!((&1.0f64).fuzzy_eq(&1.0f64)); -} - -#[test] -fn test_fuzzy_eq_eps() { - assert!((&1.2f).fuzzy_eq_eps(&0.9, &0.5)); - assert!(!(&1.5f).fuzzy_eq_eps(&0.9, &0.5)); -} - -#[test] -mod test_complex{ - use cmp::*; - - struct Complex { r: float, i: float } - - impl FuzzyEq for Complex { - fn fuzzy_eq(&self, other: &Complex) -> bool { - self.fuzzy_eq_eps(other, &FUZZY_EPSILON) - } - - fn fuzzy_eq_eps(&self, other: &Complex, - epsilon: &float) -> bool { - self.r.fuzzy_eq_eps(&other.r, epsilon) && - self.i.fuzzy_eq_eps(&other.i, epsilon) - } - } - - #[test] - fn test_fuzzy_equals() { - let a = Complex {r: 0.9, i: 0.9}; - let b = Complex {r: 0.9, i: 0.9}; - - assert!((a.fuzzy_eq(&b))); - } - - #[test] - fn test_fuzzy_eq_eps() { - let other = Complex {r: 0.9, i: 0.9}; - - assert!((&Complex {r: 0.9, i: 1.2}).fuzzy_eq_eps(&other, &0.5)); - assert!((&Complex {r: 1.2, i: 0.9}).fuzzy_eq_eps(&other, &0.5)); - assert!(!(&Complex {r: 0.9, i: 1.5}).fuzzy_eq_eps(&other, &0.5)); - assert!(!(&Complex {r: 1.5, i: 0.9}).fuzzy_eq_eps(&other, &0.5)); - } -} diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index d866ee6cedbdd..20ab2d61ecc07 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -72,7 +72,7 @@ impl Peekable for DuplexStream { } impl Selectable for DuplexStream { - fn header(&self) -> *pipes::PacketHeader { + fn header(&mut self) -> *mut pipes::PacketHeader { self.port.header() } } diff --git a/src/libstd/dbg.rs b/src/libstd/dbg.rs index 34dd6390ecc12..4b2d2a60a68ef 100644 --- a/src/libstd/dbg.rs +++ b/src/libstd/dbg.rs @@ -76,11 +76,3 @@ fn test_breakpoint_should_not_abort_process_when_not_under_gdb() { // the process under normal circumstances breakpoint(); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index 5d52bb7c0810b..c94acaa1f70db 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -10,6 +10,8 @@ //! A double-ended queue implemented as a circular buffer +use core::util::replace; + static initial_capacity: uint = 32u; // 2^5 pub struct Deque { @@ -37,7 +39,6 @@ impl Mutable for Deque { } } -#[cfg(stage0)] pub impl Deque { /// Create an empty Deque fn new() -> Deque { @@ -48,152 +49,41 @@ pub impl Deque { /// Return a reference to the first element in the deque /// /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_front(&self) -> &'self T { get(self.elts, self.lo) } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } /// Return a reference to the last element in the deque /// /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_back(&self) -> &'self T { get(self.elts, self.hi - 1u) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } /// Retrieve an element in the deque by index /// /// Fails if there is no element with the given index - #[cfg(stage0)] - fn get(&self, i: int) -> &'self T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, i: int) -> &'a T { let idx = (self.lo + (i as uint)) % self.elts.len(); get(self.elts, idx) } /// Iterate over the elements in the deque + #[cfg(stage0)] fn each(&self, f: &fn(&T) -> bool) { self.eachi(|_i, e| f(e)) } - - /// Iterate over the elements in the deque by index - fn eachi(&self, f: &fn(uint, &T) -> bool) { - for uint::range(0, self.nelts) |i| { - if !f(i, self.get(i as int)) { return; } - } - } - - /// Remove and return the first element in the deque - /// - /// Fails if the deque is empty - fn pop_front(&mut self) -> T { - let result = self.elts[self.lo].swap_unwrap(); - self.lo = (self.lo + 1u) % self.elts.len(); - self.nelts -= 1u; - result - } - - /// Remove and return the last element in the deque - /// - /// Fails if the deque is empty - fn pop_back(&mut self) -> T { - if self.hi == 0u { - self.hi = self.elts.len() - 1u; - } else { self.hi -= 1u; } - let result = self.elts[self.hi].swap_unwrap(); - self.elts[self.hi] = None; - self.nelts -= 1u; - result - } - - /// Prepend an element to the deque - fn add_front(&mut self, t: T) { - let oldlo = self.lo; - if self.lo == 0u { - self.lo = self.elts.len() - 1u; - } else { self.lo -= 1u; } - if self.lo == self.hi { - self.elts = grow(self.nelts, oldlo, self.elts); - self.lo = self.elts.len() - 1u; - self.hi = self.nelts; - } - self.elts[self.lo] = Some(t); - self.nelts += 1u; - } - - /// Append an element to the deque - fn add_back(&mut self, t: T) { - if self.lo == self.hi && self.nelts != 0u { - self.elts = grow(self.nelts, self.lo, self.elts); - self.lo = 0u; - self.hi = self.nelts; - } - self.elts[self.hi] = Some(t); - self.hi = (self.hi + 1u) % self.elts.len(); - self.nelts += 1u; - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] -pub impl Deque { - /// Create an empty Deque - fn new() -> Deque { - Deque{nelts: 0, lo: 0, hi: 0, - elts: vec::from_fn(initial_capacity, |_| None)} - } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - fn get<'a>(&'a self, i: int) -> &'a T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - /// Iterate over the elements in the deque - fn each(&self, f: &fn(&T) -> bool) { + #[cfg(not(stage0))] + fn each(&self, f: &fn(&T) -> bool) -> bool { self.eachi(|_i, e| f(e)) } /// Iterate over the elements in the deque by index + #[cfg(stage0)] fn eachi(&self, f: &fn(uint, &T) -> bool) { - for uint::range(0, self.nelts) |i| { - if !f(i, self.get(i as int)) { return; } - } + uint::range(0, self.nelts, |i| f(i, self.get(i as int))) + } + /// Iterate over the elements in the deque by index + #[cfg(not(stage0))] + fn eachi(&self, f: &fn(uint, &T) -> bool) -> bool { + uint::range(0, self.nelts, |i| f(i, self.get(i as int))) } /// Remove and return the first element in the deque @@ -254,9 +144,7 @@ fn grow(nelts: uint, lo: uint, elts: &mut [Option]) -> ~[Option] { let mut rv = ~[]; do rv.grow_fn(nelts + 1) |i| { - let mut element = None; - element <-> elts[(lo + i) % nelts]; - element + replace(&mut elts[(lo + i) % nelts], None) } rv @@ -270,7 +158,7 @@ fn get<'r, T>(elts: &'r [Option], i: uint) -> &'r T { mod tests { use super::*; use core::cmp::Eq; - use core::kinds::{Durable, Copy}; + use core::kinds::Copy; #[test] fn test_simple() { @@ -353,8 +241,8 @@ mod tests { assert!(*deq.get(3) == d); } - #[test] - fn test_parameterized(a: T, b: T, c: T, d: T) { + #[cfg(test)] + fn test_parameterized(a: T, b: T, c: T, d: T) { let mut deq = Deque::new(); assert!(deq.len() == 0); deq.add_front(a); diff --git a/src/libstd/dlist.rs b/src/libstd/dlist.rs index 1257d55453205..741bd62968018 100644 --- a/src/libstd/dlist.rs +++ b/src/libstd/dlist.rs @@ -393,6 +393,7 @@ pub impl DList { } /// Iterate over nodes. + #[cfg(stage0)] fn each_node(@mut self, f: &fn(@mut DListNode) -> bool) { let mut link = self.peek_n(); while link.is_some() { @@ -401,6 +402,17 @@ pub impl DList { link = nobe.next_link(); } } + /// Iterate over nodes. + #[cfg(not(stage0))] + fn each_node(@mut self, f: &fn(@mut DListNode) -> bool) -> bool { + let mut link = self.peek_n(); + while link.is_some() { + let nobe = link.get(); + if !f(nobe) { return false; } + link = nobe.next_link(); + } + return true; + } /// Check data structure integrity. O(n). fn assert_consistent(@mut self) { @@ -492,12 +504,13 @@ pub impl DList { impl BaseIter for @mut DList { /** - * Iterates through the current contents. - * - * Attempts to access this dlist during iteration are allowed (to - * allow for e.g. breadth-first search with in-place enqueues), but - * removing the current node is forbidden. - */ + * Iterates through the current contents. + * + * Attempts to access this dlist during iteration are allowed (to + * allow for e.g. breadth-first search with in-place enqueues), but + * removing the current node is forbidden. + */ + #[cfg(stage0)] fn each(&self, f: &fn(v: &T) -> bool) { let mut link = self.peek_n(); while link.is_some() { @@ -525,6 +538,42 @@ impl BaseIter for @mut DList { link = nobe.next_link(); } } + /** + * Iterates through the current contents. + * + * Attempts to access this dlist during iteration are allowed (to + * allow for e.g. breadth-first search with in-place enqueues), but + * removing the current node is forbidden. + */ + #[cfg(not(stage0))] + fn each(&self, f: &fn(v: &T) -> bool) -> bool { + let mut link = self.peek_n(); + while link.is_some() { + let nobe = link.get(); + assert!(nobe.linked); + + { + let frozen_nobe = &*nobe; + if !f(&frozen_nobe.data) { return false; } + } + + // Check (weakly) that the user didn't do a remove. + if self.size == 0 { + fail!("The dlist became empty during iteration??") + } + if !nobe.linked || + (!((nobe.prev.is_some() + || managed::mut_ptr_eq(self.hd.expect(~"headless dlist?"), + nobe)) + && (nobe.next.is_some() + || managed::mut_ptr_eq(self.tl.expect(~"tailless dlist?"), + nobe)))) { + fail!("Removing a dlist node during iteration is forbidden!") + } + link = nobe.next_link(); + } + return true; + } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 2598e96a141e2..98618e4928b0d 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -36,13 +36,27 @@ pub struct TaggedDoc { } pub enum EbmlEncoderTag { - EsUint, EsU64, EsU32, EsU16, EsU8, - EsInt, EsI64, EsI32, EsI16, EsI8, - EsBool, - EsStr, - EsF64, EsF32, EsFloat, - EsEnum, EsEnumVid, EsEnumBody, - EsVec, EsVecLen, EsVecElt, + EsUint, // 0 + EsU64, // 1 + EsU32, // 2 + EsU16, // 3 + EsU8, // 4 + EsInt, // 5 + EsI64, // 6 + EsI32, // 7 + EsI16, // 8 + EsI8, // 9 + EsBool, // 10 + EsStr, // 11 + EsF64, // 12 + EsF32, // 13 + EsFloat, // 14 + EsEnum, // 15 + EsEnumVid, // 16 + EsEnumBody, // 17 + EsVec, // 18 + EsVecLen, // 19 + EsVecElt, // 20 EsOpaque, @@ -143,6 +157,7 @@ pub mod reader { } #[cfg(target_arch = "arm")] + #[cfg(target_arch = "mips")] pub fn vuint_at(data: &[u8], start: uint) -> Res { vuint_at_slow(data, start) } @@ -185,6 +200,7 @@ pub mod reader { } } + #[cfg(stage0)] pub fn docs(d: Doc, it: &fn(uint, Doc) -> bool) { let mut pos = d.start; while pos < d.end { @@ -197,7 +213,22 @@ pub mod reader { } } } + #[cfg(not(stage0))] + pub fn docs(d: Doc, it: &fn(uint, Doc) -> bool) -> bool { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(*d.data, pos); + let elt_size = vuint_at(*d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + let doc = Doc { data: d.data, start: elt_size.next, end: pos }; + if !it(elt_tag.val, doc) { + return false; + } + } + return true; + } + #[cfg(stage0)] pub fn tagged_docs(d: Doc, tg: uint, it: &fn(Doc) -> bool) { let mut pos = d.start; while pos < d.end { @@ -213,6 +244,23 @@ pub mod reader { } } } + #[cfg(not(stage0))] + pub fn tagged_docs(d: Doc, tg: uint, it: &fn(Doc) -> bool) -> bool { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(*d.data, pos); + let elt_size = vuint_at(*d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + let doc = Doc { data: d.data, start: elt_size.next, + end: pos }; + if !it(doc) { + return false; + } + } + } + return true; + } pub fn doc_data(d: Doc) -> ~[u8] { vec::slice::(*d.data, d.start, d.end).to_vec() @@ -249,18 +297,20 @@ pub mod reader { pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } - pub struct Decoder { - priv mut parent: Doc, - priv mut pos: uint, + priv parent: Doc, + priv pos: uint, } pub fn Decoder(d: Doc) -> Decoder { - Decoder { parent: d, pos: d.start } + Decoder { + parent: d, + pos: d.start + } } priv impl Decoder { - fn _check_label(&self, lbl: &str) { + fn _check_label(&mut self, lbl: &str) { if self.pos < self.parent.end { let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos); @@ -269,14 +319,15 @@ pub mod reader { self.pos = r_doc.end; let str = doc_as_str(r_doc); if lbl != str { - fail!(fmt!("Expected label %s but found %s", lbl, - str)); + fail!(fmt!("Expected label %s but found %s", + lbl, + str)); } } } } - fn next_doc(&self, exp_tag: EbmlEncoderTag) -> Doc { + fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> Doc { debug!(". next_doc(exp_tag=%?)", exp_tag); if self.pos >= self.parent.end { fail!(~"no more documents in current node!"); @@ -298,7 +349,7 @@ pub mod reader { r_doc } - fn push_doc(&self, d: Doc, f: &fn() -> T) -> T { + fn push_doc(&mut self, d: Doc, f: &fn() -> T) -> T { let old_parent = self.parent; let old_pos = self.pos; self.parent = d; @@ -309,7 +360,7 @@ pub mod reader { r } - fn _next_uint(&self, exp_tag: EbmlEncoderTag) -> uint { + fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> uint { let r = doc_as_u32(self.next_doc(exp_tag)); debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); r as uint @@ -317,21 +368,29 @@ pub mod reader { } pub impl Decoder { - fn read_opaque(&self, op: &fn(Doc) -> R) -> R { - do self.push_doc(self.next_doc(EsOpaque)) { - op(copy self.parent) - } + fn read_opaque(&mut self, op: &fn(&mut Decoder, Doc) -> R) -> R { + let doc = self.next_doc(EsOpaque); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = doc.start; + + let result = op(self, doc); + + self.parent = old_parent; + self.pos = old_pos; + result } } impl serialize::Decoder for Decoder { - fn read_nil(&self) -> () { () } + fn read_nil(&mut self) -> () { () } - fn read_u64(&self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } - fn read_u32(&self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } - fn read_u16(&self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } - fn read_u8 (&self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } - fn read_uint(&self) -> uint { + fn read_u64(&mut self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } + fn read_u32(&mut self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } + fn read_u16(&mut self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } + fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } + fn read_uint(&mut self) -> uint { let v = doc_as_u64(self.next_doc(EsUint)); if v > (::core::uint::max_value as u64) { fail!(fmt!("uint %? too large for this architecture", v)); @@ -339,141 +398,225 @@ pub mod reader { v as uint } - fn read_i64(&self) -> i64 { doc_as_u64(self.next_doc(EsI64)) as i64 } - fn read_i32(&self) -> i32 { doc_as_u32(self.next_doc(EsI32)) as i32 } - fn read_i16(&self) -> i16 { doc_as_u16(self.next_doc(EsI16)) as i16 } - fn read_i8 (&self) -> i8 { doc_as_u8 (self.next_doc(EsI8 )) as i8 } - fn read_int(&self) -> int { + fn read_i64(&mut self) -> i64 { + doc_as_u64(self.next_doc(EsI64)) as i64 + } + fn read_i32(&mut self) -> i32 { + doc_as_u32(self.next_doc(EsI32)) as i32 + } + fn read_i16(&mut self) -> i16 { + doc_as_u16(self.next_doc(EsI16)) as i16 + } + fn read_i8 (&mut self) -> i8 { + doc_as_u8(self.next_doc(EsI8 )) as i8 + } + fn read_int(&mut self) -> int { let v = doc_as_u64(self.next_doc(EsInt)) as i64; if v > (int::max_value as i64) || v < (int::min_value as i64) { + debug!("FIXME #6122: Removing this makes this function miscompile"); fail!(fmt!("int %? out of range for this architecture", v)); } v as int } - fn read_bool(&self) -> bool { doc_as_u8(self.next_doc(EsBool)) - as bool } + fn read_bool(&mut self) -> bool { + doc_as_u8(self.next_doc(EsBool)) as bool + } - fn read_f64(&self) -> f64 { fail!(~"read_f64()"); } - fn read_f32(&self) -> f32 { fail!(~"read_f32()"); } - fn read_float(&self) -> float { fail!(~"read_float()"); } - fn read_char(&self) -> char { fail!(~"read_char()"); } - fn read_str(&self) -> ~str { doc_as_str(self.next_doc(EsStr)) } + fn read_f64(&mut self) -> f64 { fail!(~"read_f64()"); } + fn read_f32(&mut self) -> f32 { fail!(~"read_f32()"); } + fn read_float(&mut self) -> float { fail!(~"read_float()"); } + fn read_char(&mut self) -> char { fail!(~"read_char()"); } + fn read_str(&mut self) -> ~str { doc_as_str(self.next_doc(EsStr)) } // Compound types: - fn read_enum(&self, name: &str, f: &fn() -> T) -> T { + fn read_enum(&mut self, + name: &str, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_enum(%s)", name); self._check_label(name); - self.push_doc(self.next_doc(EsEnum), f) + + let doc = self.next_doc(EsEnum); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self); + + self.parent = old_parent; + self.pos = old_pos; + result } - fn read_enum_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_variant(&mut self, + _: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_enum_variant()"); let idx = self._next_uint(EsEnumVid); debug!(" idx=%u", idx); - do self.push_doc(self.next_doc(EsEnumBody)) { - f(idx) - } + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result } - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) -> T { debug!("read_enum_variant_arg(idx=%u)", idx); - f() + f(self) } - fn read_enum_struct_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_struct_variant(&mut self, + _: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_enum_struct_variant()"); let idx = self._next_uint(EsEnumVid); debug!(" idx=%u", idx); - do self.push_doc(self.next_doc(EsEnumBody)) { - f(idx) - } + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result } - fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); - f() + f(self) } - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T { + fn read_struct(&mut self, + name: &str, + _: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_struct(name=%s)", name); - f() + f(self) } - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - self._check_label(name); - f() - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_struct_field(name=%?, idx=%u)", name, idx); self._check_label(name); - f() + f(self) } - fn read_tuple(&self, f: &fn(uint) -> T) -> T { + fn read_tuple(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_tuple()"); self.read_seq(f) } - fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_tuple_arg(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { debug!("read_tuple_arg(idx=%u)", idx); self.read_seq_elt(idx, f) } - fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + fn read_tuple_struct(&mut self, + name: &str, + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_tuple_struct(name=%?)", name); self.read_tuple(f) } - fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_tuple_struct_arg(idx=%u)", idx); self.read_tuple_arg(idx, f) } - fn read_option(&self, f: &fn(bool) -> T) -> T { + fn read_option(&mut self, f: &fn(&mut Decoder, bool) -> T) -> T { debug!("read_option()"); - do self.read_enum("Option") || { - do self.read_enum_variant(["None", "Some"]) |idx| { + do self.read_enum("Option") |this| { + do this.read_enum_variant(["None", "Some"]) |this, idx| { match idx { - 0 => f(false), - 1 => f(true), + 0 => f(this, false), + 1 => f(this, true), _ => fail!(), } } } } - fn read_seq(&self, f: &fn(uint) -> T) -> T { + fn read_seq(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_seq()"); - do self.push_doc(self.next_doc(EsVec)) { - let len = self._next_uint(EsVecLen); - debug!(" len=%u", len); - f(len) - } + let doc = self.next_doc(EsVec); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let len = self._next_uint(EsVecLen); + debug!(" len=%u", len); + let result = f(self, len); + + self.parent = old_parent; + self.pos = old_pos; + result } - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { debug!("read_seq_elt(idx=%u)", idx); - self.push_doc(self.next_doc(EsVecElt), f) + let doc = self.next_doc(EsVecElt); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self); + + self.parent = old_parent; + self.pos = old_pos; + result } - fn read_map(&self, _f: &fn(uint) -> T) -> T { + fn read_map(&mut self, _: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_map()"); fail!(~"read_map is unimplemented"); } - fn read_map_elt_key(&self, idx: uint, _f: &fn() -> T) -> T { + fn read_map_elt_key(&mut self, + idx: uint, + _: &fn(&mut Decoder) -> T) + -> T { debug!("read_map_elt_key(idx=%u)", idx); fail!(~"read_map_elt_val is unimplemented"); } - fn read_map_elt_val(&self, idx: uint, _f: &fn() -> T) -> T { + fn read_map_elt_val(&mut self, + idx: uint, + _: &fn(&mut Decoder) -> T) + -> T { debug!("read_map_elt_val(idx=%u)", idx); fail!(~"read_map_elt_val is unimplemented"); } @@ -493,7 +636,7 @@ pub mod writer { // ebml writing pub struct Encoder { writer: @io::Writer, - priv mut size_positions: ~[uint], + priv size_positions: ~[uint], } fn write_sized_vuint(w: @io::Writer, n: uint, size: uint) { @@ -516,14 +659,27 @@ pub mod writer { fail!(fmt!("vint to write too big: %?", n)); } + #[cfg(stage0)] pub fn Encoder(w: @io::Writer) -> Encoder { let size_positions: ~[uint] = ~[]; - Encoder { writer: w, mut size_positions: size_positions } + Encoder { + writer: w, + mut size_positions: size_positions + } + } + + #[cfg(not(stage0))] + pub fn Encoder(w: @io::Writer) -> Encoder { + let size_positions: ~[uint] = ~[]; + Encoder { + writer: w, + size_positions: size_positions + } } // FIXME (#2741): Provide a function to write the standard ebml header. pub impl Encoder { - fn start_tag(&self, tag_id: uint) { + fn start_tag(&mut self, tag_id: uint) { debug!("Start tag %u", tag_id); // Write the enum ID: @@ -535,7 +691,7 @@ pub mod writer { self.writer.write(zeroes); } - fn end_tag(&self) { + fn end_tag(&mut self) { let last_size_pos = self.size_positions.pop(); let cur_pos = self.writer.tell(); self.writer.seek(last_size_pos as int, io::SeekSet); @@ -546,72 +702,72 @@ pub mod writer { debug!("End tag (size = %u)", size); } - fn wr_tag(&self, tag_id: uint, blk: &fn()) { + fn wr_tag(&mut self, tag_id: uint, blk: &fn()) { self.start_tag(tag_id); blk(); self.end_tag(); } - fn wr_tagged_bytes(&self, tag_id: uint, b: &[u8]) { + fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) { write_vuint(self.writer, tag_id); write_vuint(self.writer, vec::len(b)); self.writer.write(b); } - fn wr_tagged_u64(&self, tag_id: uint, v: u64) { + fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { do io::u64_to_be_bytes(v, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_u32(&self, tag_id: uint, v: u32) { + fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { do io::u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_u16(&self, tag_id: uint, v: u16) { + fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { do io::u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_u8(&self, tag_id: uint, v: u8) { + fn wr_tagged_u8(&mut self, tag_id: uint, v: u8) { self.wr_tagged_bytes(tag_id, &[v]); } - fn wr_tagged_i64(&self, tag_id: uint, v: i64) { + fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { do io::u64_to_be_bytes(v as u64, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_i32(&self, tag_id: uint, v: i32) { + fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { do io::u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_i16(&self, tag_id: uint, v: i16) { + fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { do io::u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } - fn wr_tagged_i8(&self, tag_id: uint, v: i8) { + fn wr_tagged_i8(&mut self, tag_id: uint, v: i8) { self.wr_tagged_bytes(tag_id, &[v as u8]); } - fn wr_tagged_str(&self, tag_id: uint, v: &str) { + fn wr_tagged_str(&mut self, tag_id: uint, v: &str) { str::byte_slice(v, |b| self.wr_tagged_bytes(tag_id, b)); } - fn wr_bytes(&self, b: &[u8]) { + fn wr_bytes(&mut self, b: &[u8]) { debug!("Write %u bytes", vec::len(b)); self.writer.write(b); } - fn wr_str(&self, s: &str) { + fn wr_str(&mut self, s: &str) { debug!("Write str: %?", s); self.writer.write(str::to_bytes(s)); } @@ -622,16 +778,16 @@ pub mod writer { // Set to true to generate more debugging in EBML code. // Totally lame approach. - static debug: bool = false; + static debug: bool = true; priv impl Encoder { // used internally to emit things like the vector length and so on - fn _emit_tagged_uint(&self, t: EbmlEncoderTag, v: uint) { - assert!(v <= 0xFFFF_FFFF_u); + fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { + assert!(v <= 0xFFFF_FFFF_u); // FIXME(#6130) assert warns on 32-bit self.wr_tagged_u32(t as uint, v as u32); } - fn _emit_label(&self, label: &str) { + fn _emit_label(&mut self, label: &str) { // There are various strings that we have access to, such as // the name of a record field, which do not actually appear in // the encoded EBML (normally). This is just for @@ -643,126 +799,169 @@ pub mod writer { } pub impl Encoder { - fn emit_opaque(&self, f: &fn()) { - do self.wr_tag(EsOpaque as uint) { - f() - } + fn emit_opaque(&mut self, f: &fn(&mut Encoder)) { + self.start_tag(EsOpaque as uint); + f(self); + self.end_tag(); } } impl ::serialize::Encoder for Encoder { - fn emit_nil(&self) {} + fn emit_nil(&mut self) {} - fn emit_uint(&self, v: uint) { + fn emit_uint(&mut self, v: uint) { self.wr_tagged_u64(EsUint as uint, v as u64); } - fn emit_u64(&self, v: u64) { self.wr_tagged_u64(EsU64 as uint, v); } - fn emit_u32(&self, v: u32) { self.wr_tagged_u32(EsU32 as uint, v); } - fn emit_u16(&self, v: u16) { self.wr_tagged_u16(EsU16 as uint, v); } - fn emit_u8(&self, v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); } + fn emit_u64(&mut self, v: u64) { + self.wr_tagged_u64(EsU64 as uint, v); + } + fn emit_u32(&mut self, v: u32) { + self.wr_tagged_u32(EsU32 as uint, v); + } + fn emit_u16(&mut self, v: u16) { + self.wr_tagged_u16(EsU16 as uint, v); + } + fn emit_u8(&mut self, v: u8) { + self.wr_tagged_u8(EsU8 as uint, v); + } - fn emit_int(&self, v: int) { + fn emit_int(&mut self, v: int) { self.wr_tagged_i64(EsInt as uint, v as i64); } - fn emit_i64(&self, v: i64) { self.wr_tagged_i64(EsI64 as uint, v); } - fn emit_i32(&self, v: i32) { self.wr_tagged_i32(EsI32 as uint, v); } - fn emit_i16(&self, v: i16) { self.wr_tagged_i16(EsI16 as uint, v); } - fn emit_i8(&self, v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); } + fn emit_i64(&mut self, v: i64) { + self.wr_tagged_i64(EsI64 as uint, v); + } + fn emit_i32(&mut self, v: i32) { + self.wr_tagged_i32(EsI32 as uint, v); + } + fn emit_i16(&mut self, v: i16) { + self.wr_tagged_i16(EsI16 as uint, v); + } + fn emit_i8(&mut self, v: i8) { + self.wr_tagged_i8(EsI8 as uint, v); + } - fn emit_bool(&self, v: bool) { + fn emit_bool(&mut self, v: bool) { self.wr_tagged_u8(EsBool as uint, v as u8) } // FIXME (#2742): implement these - fn emit_f64(&self, _v: f64) { + fn emit_f64(&mut self, _v: f64) { fail!(~"Unimplemented: serializing an f64"); } - fn emit_f32(&self, _v: f32) { + fn emit_f32(&mut self, _v: f32) { fail!(~"Unimplemented: serializing an f32"); } - fn emit_float(&self, _v: float) { + fn emit_float(&mut self, _v: float) { fail!(~"Unimplemented: serializing a float"); } - fn emit_char(&self, _v: char) { + fn emit_char(&mut self, _v: char) { fail!(~"Unimplemented: serializing a char"); } - fn emit_str(&self, v: &str) { + fn emit_str(&mut self, v: &str) { self.wr_tagged_str(EsStr as uint, v) } - fn emit_enum(&self, name: &str, f: &fn()) { + fn emit_enum(&mut self, name: &str, f: &fn(&mut Encoder)) { self._emit_label(name); - self.wr_tag(EsEnum as uint, f) + self.start_tag(EsEnum as uint); + f(self); + self.end_tag(); } - fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint, - f: &fn()) { + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: &fn(&mut Encoder)) { self._emit_tagged_uint(EsEnumVid, v_id); - self.wr_tag(EsEnumBody as uint, f) + self.start_tag(EsEnumBody as uint); + f(self); + self.end_tag(); } - fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } + fn emit_enum_variant_arg(&mut self, _: uint, f: &fn(&mut Encoder)) { + f(self) + } - fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { self.emit_enum_variant(v_name, v_id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _f_name: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut Encoder)) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } - #[cfg(stage0)] - fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { - self._emit_label(name); - f() + fn emit_struct(&mut self, _: &str, _len: uint, f: &fn(&mut Encoder)) { + f(self) } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, _idx: uint, f: &fn()) { + + fn emit_struct_field(&mut self, + name: &str, + _: uint, + f: &fn(&mut Encoder)) { self._emit_label(name); - f() + f(self) } - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_option(&self, f: &fn()) { + fn emit_option(&mut self, f: &fn(&mut Encoder)) { self.emit_enum("Option", f); } - fn emit_option_none(&self) { - self.emit_enum_variant("None", 0, 0, || ()) + fn emit_option_none(&mut self) { + self.emit_enum_variant("None", 0, 0, |_| ()) } - fn emit_option_some(&self, f: &fn()) { + fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { self.emit_enum_variant("Some", 1, 1, f) } - fn emit_seq(&self, len: uint, f: &fn()) { - do self.wr_tag(EsVec as uint) { - self._emit_tagged_uint(EsVecLen, len); - f() - } + fn emit_seq(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.start_tag(EsVec as uint); + self._emit_tagged_uint(EsVecLen, len); + f(self); + self.end_tag(); } - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.wr_tag(EsVecElt as uint, f) + fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut Encoder)) { + self.start_tag(EsVecElt as uint); + f(self); + self.end_tag(); } - fn emit_map(&self, _len: uint, _f: &fn()) { + fn emit_map(&mut self, _len: uint, _f: &fn(&mut Encoder)) { fail!(~"emit_map is unimplemented"); } - fn emit_map_elt_key(&self, _idx: uint, _f: &fn()) { + fn emit_map_elt_key(&mut self, _idx: uint, _f: &fn(&mut Encoder)) { fail!(~"emit_map_elt_key is unimplemented"); } - fn emit_map_elt_val(&self, _idx: uint, _f: &fn()) { + fn emit_map_elt_val(&mut self, _idx: uint, _f: &fn(&mut Encoder)) { fail!(~"emit_map_elt_val is unimplemented"); } } @@ -786,12 +985,12 @@ mod tests { fn test_v(v: Option) { debug!("v == %?", v); let bytes = do io::with_bytes_writer |wr| { - let ebml_w = writer::Encoder(wr); - v.encode(&ebml_w) + let mut ebml_w = writer::Encoder(wr); + v.encode(&mut ebml_w) }; let ebml_doc = reader::Doc(@bytes); - let deser = reader::Decoder(ebml_doc); - let v1 = serialize::Decodable::decode(&deser); + let mut deser = reader::Decoder(ebml_doc); + let v1 = serialize::Decodable::decode(&mut deser); debug!("v1 == %?", v1); assert!(v == v1); } diff --git a/src/libstd/fileinput.rs b/src/libstd/fileinput.rs index a24b11d71c68d..c3622fad53bac 100644 --- a/src/libstd/fileinput.rs +++ b/src/libstd/fileinput.rs @@ -94,8 +94,6 @@ total line count). } */ -#[allow(deprecated_mutable_fields)]; - use core::io::ReaderUtil; /** @@ -145,7 +143,7 @@ struct FileInput_ { // "self.fi." -> "self." and renaming FileInput_. Documentation above // will likely have to be updated to use `let mut in = ...`. pub struct FileInput { - priv mut fi: FileInput_ + priv fi: @mut FileInput_ } impl FileInput { @@ -170,7 +168,7 @@ impl FileInput { pub fn from_vec_raw(files: ~[Option]) -> FileInput { FileInput{ - fi: FileInput_ { + fi: @mut FileInput_ { files: files, current_reader: None, state: FileInputState { @@ -212,8 +210,8 @@ impl FileInput { pub fn next_file(&self) -> bool { // No more files - // Compiler whines about "illegal borrow unless pure" for - // files.is_empty() + // unsafe block can be removed after the next snapshot + // (next one after 2013-05-03) if unsafe { self.fi.files.is_empty() } { self.fi.current_reader = None; return false; @@ -256,10 +254,21 @@ impl FileInput { (line numbers and file names, see documentation for `FileInputState`). Otherwise identical to `lines_each`. */ + #[cfg(stage0)] pub fn each_line_state(&self, f: &fn(&str, FileInputState) -> bool) { self.each_line(|line| f(line, copy self.fi.state)); } + /** + Apply `f` to each line successively, along with some state + (line numbers and file names, see documentation for + `FileInputState`). Otherwise identical to `lines_each`. + */ + #[cfg(not(stage0))] + pub fn each_line_state(&self, + f: &fn(&str, FileInputState) -> bool) -> bool { + self.each_line(|line| f(line, copy self.fi.state)) + } /** @@ -326,7 +335,8 @@ impl io::Reader for FileInput { fn eof(&self) -> bool { // we've run out of files, and current_reader is either None or eof. - // compiler whines about illegal borrows for files.is_empty() + // unsafe block can be removed after the next snapshot + // (next one after 2013-05-03) (unsafe { self.fi.files.is_empty() }) && match self.fi.current_reader { None => true, Some(r) => r.eof() } @@ -367,9 +377,20 @@ reading from `stdin`). Fails when attempting to read from a file that can't be opened. */ +#[cfg(stage0)] pub fn input(f: &fn(&str) -> bool) { - let mut i = FileInput::from_args(); - i.each_line(f); + FileInput::from_args().each_line(f); +} +/** +Iterate directly over the command line arguments (no arguments implies +reading from `stdin`). + +Fails when attempting to read from a file that can't be opened. +*/ +#[cfg(not(stage0))] +pub fn input(f: &fn(&str) -> bool) -> bool { + let i = FileInput::from_args(); + i.each_line(f) } /** @@ -379,9 +400,21 @@ provided at each call. Fails when attempting to read from a file that can't be opened. */ +#[cfg(stage0)] pub fn input_state(f: &fn(&str, FileInputState) -> bool) { - let mut i = FileInput::from_args(); - i.each_line_state(f); + FileInput::from_args().each_line_state(f); +} +/** +Iterate directly over the command line arguments (no arguments +implies reading from `stdin`) with the current state of the iteration +provided at each call. + +Fails when attempting to read from a file that can't be opened. +*/ +#[cfg(not(stage0))] +pub fn input_state(f: &fn(&str, FileInputState) -> bool) -> bool { + let i = FileInput::from_args(); + i.each_line_state(f) } /** @@ -389,9 +422,19 @@ Iterate over a vector of files (an empty vector implies just `stdin`). Fails when attempting to read from a file that can't be opened. */ +#[cfg(stage0)] pub fn input_vec(files: ~[Option], f: &fn(&str) -> bool) { - let mut i = FileInput::from_vec(files); - i.each_line(f); + FileInput::from_vec(files).each_line(f); +} +/** +Iterate over a vector of files (an empty vector implies just `stdin`). + +Fails when attempting to read from a file that can't be opened. +*/ +#[cfg(not(stage0))] +pub fn input_vec(files: ~[Option], f: &fn(&str) -> bool) -> bool { + let i = FileInput::from_vec(files); + i.each_line(f) } /** @@ -400,10 +443,22 @@ with the current state of the iteration provided at each call. Fails when attempting to read from a file that can't be opened. */ +#[cfg(stage0)] pub fn input_vec_state(files: ~[Option], f: &fn(&str, FileInputState) -> bool) { - let mut i = FileInput::from_vec(files); - i.each_line_state(f); + FileInput::from_vec(files).each_line_state(f); +} +/** +Iterate over a vector of files (an empty vector implies just `stdin`) +with the current state of the iteration provided at each call. + +Fails when attempting to read from a file that can't be opened. +*/ +#[cfg(not(stage0))] +pub fn input_vec_state(files: ~[Option], + f: &fn(&str, FileInputState) -> bool) -> bool { + let i = FileInput::from_vec(files); + i.each_line_state(f) } #[cfg(test)] diff --git a/src/libcore/flate.rs b/src/libstd/flate.rs similarity index 82% rename from src/libcore/flate.rs rename to src/libstd/flate.rs index c3518cc8b6ee2..7485f2645bdf2 100644 --- a/src/libcore/flate.rs +++ b/src/libstd/flate.rs @@ -15,27 +15,26 @@ Simple compression */ use libc; -use libc::{c_void, size_t, c_int}; -use ptr; +use core::libc::{c_void, size_t, c_int}; use vec; -#[cfg(test)] use rand; -#[cfg(test)] use rand::RngUtil; +#[cfg(test)] use core::rand; +#[cfg(test)] use core::rand::RngUtil; pub mod rustrt { - use libc::{c_int, c_void, size_t}; + use core::libc::{c_int, c_void, size_t}; #[link_name = "rustrt"] pub extern { unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void, src_buf_len: size_t, - pout_len: *size_t, + pout_len: *mut size_t, flags: c_int) -> *c_void; unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, src_buf_len: size_t, - pout_len: *size_t, + pout_len: *mut size_t, flags: c_int) -> *c_void; } @@ -53,11 +52,11 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { let res = rustrt::tdefl_compress_mem_to_heap(b as *c_void, len as size_t, - &outsz, + &mut outsz, lz_norm); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, - outsz as uint); + outsz as uint); libc::free(res); out } @@ -67,11 +66,11 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { do vec::as_const_buf(bytes) |b, len| { unsafe { - let outsz : size_t = 0; + let mut outsz : size_t = 0; let res = rustrt::tinfl_decompress_mem_to_heap(b as *c_void, len as size_t, - &outsz, + &mut outsz, 0); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, @@ -85,10 +84,11 @@ pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { #[test] #[allow(non_implicitly_copyable_typarams)] fn test_flate_round_trip() { - let r = rand::rng(); + let mut r = rand::rng(); let mut words = ~[]; for 20.times { - words.push(r.gen_bytes(r.gen_uint_range(1, 10))); + let range = r.gen_uint_range(1, 10); + words.push(r.gen_bytes(range)); } for 20.times { let mut in = ~[]; diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index bd0acb849fcac..6547ff8eefbb9 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -15,7 +15,7 @@ or transformed to and from, byte vectors. The `FlatPort` and `FlatChan` types implement the generic channel and port interface for arbitrary types and transport strategies. It can -particularly be used to send and recieve serializable types over I/O +particularly be used to send and receive serializable types over I/O streams. `FlatPort` and `FlatChan` implement the same comm traits as pipe-based @@ -55,7 +55,7 @@ use core::sys::size_of; use core::vec; /** -A FlatPort, consisting of a `BytePort` that recieves byte vectors, +A FlatPort, consisting of a `BytePort` that receives byte vectors, and an `Unflattener` that converts the bytes to a value. Create using the constructors in the `serial` and `pod` modules. @@ -439,19 +439,23 @@ pub mod flatteners { */ pub fn deserialize_buffer>(buf: &[u8]) -> T { - let buf = vec::from_slice(buf); + T: Decodable>( + buf: &[u8]) + -> T { + let buf = vec::to_owned(buf); let buf_reader = @BufReader::new(buf); let reader = buf_reader as @Reader; - let deser: D = FromReader::from_reader(reader); - Decodable::decode(&deser) + let mut deser: D = FromReader::from_reader(reader); + Decodable::decode(&mut deser) } pub fn serialize_value>(val: &T) -> ~[u8] { + T: Encodable>( + val: &T) + -> ~[u8] { do io::with_bytes_writer |writer| { - let ser = FromWriter::from_writer(writer); - val.encode(&ser); + let mut ser = FromWriter::from_writer(writer); + val.encode(&mut ser); } } @@ -554,9 +558,11 @@ pub mod bytepipes { } } + // XXX: Remove `@mut` when this module is ported to the new I/O traits, + // which use `&mut self` properly. pub struct PipeBytePort { port: comm::Port<~[u8]>, - mut buf: ~[u8] + buf: @mut ~[u8] } pub struct PipeByteChan { @@ -565,13 +571,13 @@ pub mod bytepipes { impl BytePort for PipeBytePort { fn try_recv(&self, count: uint) -> Option<~[u8]> { - if vec::uniq_len(&const self.buf) >= count { - let mut bytes = ::core::util::replace(&mut self.buf, ~[]); - self.buf = bytes.slice(count, bytes.len()).to_owned(); + if vec::uniq_len(&const *self.buf) >= count { + let mut bytes = ::core::util::replace(&mut *self.buf, ~[]); + *self.buf = bytes.slice(count, bytes.len()).to_owned(); bytes.truncate(count); return Some(bytes); - } else if vec::uniq_len(&const self.buf) > 0 { - let mut bytes = ::core::util::replace(&mut self.buf, ~[]); + } else if vec::uniq_len(&const *self.buf) > 0 { + let mut bytes = ::core::util::replace(&mut *self.buf, ~[]); assert!(count > bytes.len()); match self.try_recv(count - bytes.len()) { Some(rest) => { @@ -580,11 +586,11 @@ pub mod bytepipes { } None => return None } - } else if vec::uniq_len(&const self.buf) == 0 { + } else if vec::uniq_len(&const *self.buf) == 0 { match self.port.try_recv() { Some(buf) => { assert!(!buf.is_empty()); - self.buf = buf; + *self.buf = buf; return self.try_recv(count); } None => return None @@ -605,7 +611,7 @@ pub mod bytepipes { fn new(p: Port<~[u8]>) -> PipeBytePort { PipeBytePort { port: p, - buf: ~[] + buf: @mut ~[] } } } @@ -639,7 +645,7 @@ mod test { chan.send(10); - let bytes = copy chan.byte_chan.writer.bytes; + let bytes = copy *chan.byte_chan.writer.bytes; let reader = BufReader::new(bytes); let port = serial::reader_port(reader); @@ -649,6 +655,7 @@ mod test { } #[test] + #[ignore(reason = "FIXME #6211 failing on linux snapshot machine")] fn test_serializing_pipes() { let (port, chan) = serial::pipe_stream(); @@ -685,7 +692,7 @@ mod test { chan.send(10); - let bytes = copy chan.byte_chan.writer.bytes; + let bytes = copy *chan.byte_chan.writer.bytes; let reader = BufReader::new(bytes); let port = pod::reader_port(reader); @@ -814,7 +821,7 @@ mod test { } } - // Reciever task + // Receiver task do task::spawn || { // Wait for a connection let (conn, res_chan) = accept_port.recv(); @@ -833,7 +840,7 @@ mod test { for int::range(0, 10) |i| { let j = port.recv(); - debug!("receieved %?", j); + debug!("received %?", j); assert!(i == j); } @@ -921,7 +928,7 @@ mod test { test_try_recv_none3(pipe_port_loader); } - fn test_try_recv_none4(+loader: PortLoader

) { + fn test_try_recv_none4(loader: PortLoader

) { assert!(do task::try || { static CONTINUE: [u8, ..4] = [0xAA, 0xBB, 0xCC, 0xDD]; // The control word is followed by a valid length, diff --git a/src/libstd/future.rs b/src/libstd/future.rs index f59abfa81ca10..9906be13cb9e5 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -23,15 +23,18 @@ use core::cast; use core::cell::Cell; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::pipes::recv; use core::task; +use core::util::replace; #[doc = "The future type"] pub struct Future { - priv mut state: FutureState, + priv state: FutureState, } +// n.b. It should be possible to get rid of this. +// Add a test, though -- tjc // FIXME(#2829) -- futures should not be copyable, because they close // over ~fn's that have pipes and so forth within! #[unsafe_destructor] @@ -47,62 +50,35 @@ priv enum FutureState { /// Methods on the `future` type pub impl Future { - fn get(&self) -> A { + fn get(&mut self) -> A { //! Get the value of the future *(self.get_ref()) } } pub impl Future { - #[cfg(stage0)] - fn get_ref(&self) -> &'self A { + fn get_ref<'a>(&'a mut self) -> &'a A { /*! * Executes the future's closure and then returns a borrowed * pointer to the result. The borrowed pointer lasts as long as * the future. */ unsafe { - match self.state { - Forced(ref mut v) => { return cast::transmute(v); } - Evaluating => fail!(~"Recursive forcing of future!"), - Pending(_) => {} - } - - let mut state = Evaluating; - self.state <-> state; - match state { - Forced(_) | Evaluating => fail!(~"Logic error."), - Pending(f) => { - self.state = Forced(f()); - self.get_ref() + { + match self.state { + Forced(ref mut v) => { return cast::transmute(v); } + Evaluating => fail!(~"Recursive forcing of future!"), + Pending(_) => {} } } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn get_ref<'a>(&'a self) -> &'a A { - /*! - * Executes the future's closure and then returns a borrowed - * pointer to the result. The borrowed pointer lasts as long as - * the future. - */ - unsafe { - match self.state { - Forced(ref mut v) => { return cast::transmute(v); } - Evaluating => fail!(~"Recursive forcing of future!"), - Pending(_) => {} - } - - let mut state = Evaluating; - self.state <-> state; - match state { - Forced(_) | Evaluating => fail!(~"Logic error."), - Pending(f) => { - self.state = Forced(f()); - self.get_ref() + { + let state = replace(&mut self.state, Evaluating); + match state { + Forced(_) | Evaluating => fail!(~"Logic error."), + Pending(f) => { + self.state = Forced(f()); + cast::transmute(self.get_ref()) + } } } } @@ -171,15 +147,15 @@ pub fn spawn(blk: ~fn() -> A) -> Future { #[allow(non_implicitly_copyable_typarams)] #[cfg(test)] mod test { - use future::*; + use core::cell::Cell; use core::comm::{oneshot, send_one}; use core::task; #[test] fn test_from_value() { - let f = from_value(~"snail"); + let mut f = from_value(~"snail"); assert!(f.get() == ~"snail"); } @@ -187,31 +163,31 @@ mod test { fn test_from_port() { let (po, ch) = oneshot(); send_one(ch, ~"whale"); - let f = from_port(po); + let mut f = from_port(po); assert!(f.get() == ~"whale"); } #[test] fn test_from_fn() { - let f = from_fn(|| ~"brail"); + let mut f = from_fn(|| ~"brail"); assert!(f.get() == ~"brail"); } #[test] fn test_interface_get() { - let f = from_value(~"fail"); + let mut f = from_value(~"fail"); assert!(f.get() == ~"fail"); } #[test] fn test_get_ref_method() { - let f = from_value(22); + let mut f = from_value(22); assert!(*f.get_ref() == 22); } #[test] fn test_spawn() { - let f = spawn(|| ~"bale"); + let mut f = spawn(|| ~"bale"); assert!(f.get() == ~"bale"); } @@ -219,15 +195,16 @@ mod test { #[should_fail] #[ignore(cfg(target_os = "win32"))] fn test_futurefail() { - let f = spawn(|| fail!()); + let mut f = spawn(|| fail!()); let _x: ~str = f.get(); } #[test] fn test_sendable_future() { - let expected = ~"schlorf"; - let f = do spawn { copy expected }; - do task::spawn || { + let expected = "schlorf"; + let f = Cell(do spawn { expected }); + do task::spawn { + let mut f = f.take(); let actual = f.get(); assert!(actual == expected); } diff --git a/src/libstd/getopts.rs b/src/libstd/getopts.rs index fda5c105da5f7..f66b56381f0f4 100644 --- a/src/libstd/getopts.rs +++ b/src/libstd/getopts.rs @@ -106,7 +106,7 @@ pub struct Opt { } fn mkname(nm: &str) -> Name { - let unm = str::from_slice(nm); + let unm = str::to_owned(nm); return if nm.len() == 1u { Short(str::char_at(unm, 0u)) } else { Long(unm) }; @@ -229,13 +229,13 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { let l = args.len(); let mut i = 0; while i < l { - let cur = args[i]; + let cur = copy args[i]; let curlen = cur.len(); if !is_arg(cur) { free.push(cur); } else if cur == ~"--" { let mut j = i + 1; - while j < l { free.push(args[j]); j += 1; } + while j < l { free.push(copy args[j]); j += 1; } break; } else { let mut names; @@ -248,8 +248,8 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { names = ~[Long(tail)]; } else { names = - ~[Long(tail_eq[0])]; - i_arg = Some(tail_eq[1]); + ~[Long(copy tail_eq[0])]; + i_arg = Some(copy tail_eq[1]); } } else { let mut j = 1; @@ -266,7 +266,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { interpreted correctly */ - match find_opt(opts, opt) { + match find_opt(opts, copy opt) { Some(id) => last_valid_opt_id = Some(id), None => { let arg_follows = @@ -292,7 +292,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { let mut name_pos = 0; for names.each() |nm| { name_pos += 1; - let optid = match find_opt(opts, *nm) { + let optid = match find_opt(opts, copy *nm) { Some(id) => id, None => return Err(UnrecognizedOption(name_str(nm))) }; @@ -305,18 +305,18 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { } Maybe => { if !i_arg.is_none() { - vals[optid].push(Val(i_arg.get())); + vals[optid].push(Val((copy i_arg).get())); } else if name_pos < names.len() || i + 1 == l || is_arg(args[i + 1]) { vals[optid].push(Given); - } else { i += 1; vals[optid].push(Val(args[i])); } + } else { i += 1; vals[optid].push(Val(copy args[i])); } } Yes => { if !i_arg.is_none() { - vals[optid].push(Val(i_arg.get())); + vals[optid].push(Val((copy i_arg).get())); } else if i + 1 == l { return Err(ArgumentMissing(name_str(nm))); - } else { i += 1; vals[optid].push(Val(args[i])); } + } else { i += 1; vals[optid].push(Val(copy args[i])); } } } } @@ -339,14 +339,14 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { } i += 1; } - return Ok(Matches {opts: vec::from_slice(opts), + return Ok(Matches {opts: vec::to_owned(opts), vals: vals, free: free}); } fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] { return match find_opt(mm.opts, mkname(nm)) { - Some(id) => mm.vals[id], + Some(id) => copy mm.vals[id], None => { error!("No option '%s' defined", nm); fail!() @@ -354,7 +354,7 @@ fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] { }; } -fn opt_val(mm: &Matches, nm: &str) -> Optval { return opt_vals(mm, nm)[0]; } +fn opt_val(mm: &Matches, nm: &str) -> Optval { copy opt_vals(mm, nm)[0] } /// Returns true if an option was matched pub fn opt_present(mm: &Matches, nm: &str) -> bool { @@ -368,7 +368,7 @@ pub fn opt_count(mm: &Matches, nm: &str) -> uint { /// Returns true if any of several options were matched pub fn opts_present(mm: &Matches, names: &[~str]) -> bool { - for vec::each(names) |nm| { + for names.each |nm| { match find_opt(mm.opts, mkname(*nm)) { Some(id) if !mm.vals[id].is_empty() => return true, _ => (), @@ -395,7 +395,7 @@ pub fn opt_str(mm: &Matches, nm: &str) -> ~str { * option took an argument */ pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str { - for vec::each(names) |nm| { + for names.each |nm| { match opt_val(mm, *nm) { Val(copy s) => return s, _ => () @@ -441,7 +441,7 @@ pub fn opt_default(mm: &Matches, nm: &str, def: &str) -> Option<~str> { let vals = opt_vals(mm, nm); if vec::len::(vals) == 0u { return None::<~str>; } return match vals[0] { Val(copy s) => Some::<~str>(s), - _ => Some::<~str>(str::from_slice(def)) } + _ => Some::<~str>(str::to_owned(def)) } } #[deriving(Eq)] @@ -481,10 +481,10 @@ pub mod groups { desc: &str, hint: &str) -> OptGroup { let len = short_name.len(); assert!(len == 1 || len == 0); - return OptGroup { short_name: str::from_slice(short_name), - long_name: str::from_slice(long_name), - hint: str::from_slice(hint), - desc: str::from_slice(desc), + return OptGroup { short_name: str::to_owned(short_name), + long_name: str::to_owned(long_name), + hint: str::to_owned(hint), + desc: str::to_owned(desc), hasarg: Yes, occur: Req}; } @@ -494,10 +494,10 @@ pub mod groups { desc: &str, hint: &str) -> OptGroup { let len = short_name.len(); assert!(len == 1 || len == 0); - return OptGroup {short_name: str::from_slice(short_name), - long_name: str::from_slice(long_name), - hint: str::from_slice(hint), - desc: str::from_slice(desc), + return OptGroup {short_name: str::to_owned(short_name), + long_name: str::to_owned(long_name), + hint: str::to_owned(hint), + desc: str::to_owned(desc), hasarg: Yes, occur: Optional}; } @@ -507,10 +507,10 @@ pub mod groups { desc: &str) -> OptGroup { let len = short_name.len(); assert!(len == 1 || len == 0); - return OptGroup {short_name: str::from_slice(short_name), - long_name: str::from_slice(long_name), + return OptGroup {short_name: str::to_owned(short_name), + long_name: str::to_owned(long_name), hint: ~"", - desc: str::from_slice(desc), + desc: str::to_owned(desc), hasarg: No, occur: Optional}; } @@ -520,10 +520,10 @@ pub mod groups { desc: &str, hint: &str) -> OptGroup { let len = short_name.len(); assert!(len == 1 || len == 0); - return OptGroup {short_name: str::from_slice(short_name), - long_name: str::from_slice(long_name), - hint: str::from_slice(hint), - desc: str::from_slice(desc), + return OptGroup {short_name: str::to_owned(short_name), + long_name: str::to_owned(long_name), + hint: str::to_owned(hint), + desc: str::to_owned(desc), hasarg: Maybe, occur: Optional}; } @@ -536,10 +536,10 @@ pub mod groups { desc: &str, hint: &str) -> OptGroup { let len = short_name.len(); assert!(len == 1 || len == 0); - return OptGroup {short_name: str::from_slice(short_name), - long_name: str::from_slice(long_name), - hint: str::from_slice(hint), - desc: str::from_slice(desc), + return OptGroup {short_name: str::to_owned(short_name), + long_name: str::to_owned(long_name), + hint: str::to_owned(hint), + desc: str::to_owned(desc), hasarg: Yes, occur: Multi}; } @@ -547,25 +547,29 @@ pub mod groups { // translate OptGroup into Opt // (both short and long names correspond to different Opts) pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { - match ((*lopt).short_name.len(), - (*lopt).long_name.len()) { + let OptGroup{short_name: short_name, + long_name: long_name, + hasarg: hasarg, + occur: occur, + _} = copy *lopt; + match (short_name.len(), long_name.len()) { (0,0) => fail!(~"this long-format option was given no name"), - (0,_) => ~[Opt {name: Long(((*lopt).long_name)), - hasarg: (*lopt).hasarg, - occur: (*lopt).occur}], + (0,_) => ~[Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur}], - (1,0) => ~[Opt {name: Short(str::char_at((*lopt).short_name, 0)), - hasarg: (*lopt).hasarg, - occur: (*lopt).occur}], + (1,0) => ~[Opt {name: Short(str::char_at(short_name, 0)), + hasarg: hasarg, + occur: occur}], - (1,_) => ~[Opt {name: Short(str::char_at((*lopt).short_name, 0)), - hasarg: (*lopt).hasarg, - occur: (*lopt).occur}, - Opt {name: Long(((*lopt).long_name)), - hasarg: (*lopt).hasarg, - occur: (*lopt).occur}], + (1,_) => ~[Opt {name: Short(str::char_at(short_name, 0)), + hasarg: hasarg, + occur: occur}, + Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur}], (_,_) => fail!(~"something is wrong with the long-form opt") } @@ -586,11 +590,12 @@ pub mod groups { let desc_sep = ~"\n" + str::repeat(~" ", 24); let rows = vec::map(opts, |optref| { - let short_name = (*optref).short_name; - let long_name = (*optref).long_name; - let hint = (*optref).hint; - let desc = (*optref).desc; - let hasarg = (*optref).hasarg; + let OptGroup{short_name: short_name, + long_name: long_name, + hint: hint, + desc: desc, + hasarg: hasarg, + _} = copy *optref; let mut row = str::repeat(~" ", 4); @@ -620,10 +625,10 @@ pub mod groups { row += if rowlen < 24 { str::repeat(~" ", 24 - rowlen) } else { - desc_sep + copy desc_sep }; - // Normalize desc to contain words seperated by one space character + // Normalize desc to contain words separated by one space character let mut desc_normalized_whitespace = ~""; for str::each_word(desc) |word| { desc_normalized_whitespace.push_str(word); @@ -643,7 +648,7 @@ pub mod groups { row }); - return str::from_slice(brief) + + return str::to_owned(brief) + ~"\n\nOptions:\n" + str::connect(rows, ~"\n") + ~"\n\n"; @@ -892,7 +897,7 @@ mod tests { let rs = getopts(args, opts); match rs { Err(copy f) => { - error!(fail_str(f)); + error!(fail_str(copy f)); check_fail_type(f, UnexpectedArgument_); } _ => fail!() @@ -1374,11 +1379,3 @@ Options: assert!(usage == expected) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/io_util.rs b/src/libstd/io_util.rs index 50d2eb6a78521..7d43663cc808b 100644 --- a/src/libstd/io_util.rs +++ b/src/libstd/io_util.rs @@ -13,14 +13,14 @@ use core::io; pub struct BufReader { buf: ~[u8], - mut pos: uint + pos: @mut uint } pub impl BufReader { pub fn new(v: ~[u8]) -> BufReader { BufReader { buf: v, - pos: 0 + pos: @mut 0 } } @@ -29,13 +29,13 @@ pub impl BufReader { // I can't get the borrowing to work correctly let bytes_reader = BytesReader { bytes: ::core::util::id::<&[u8]>(self.buf), - pos: self.pos + pos: @mut *self.pos }; let res = f(&bytes_reader); // FIXME #4429: This isn't correct if f fails - self.pos = bytes_reader.pos; + *self.pos = *bytes_reader.pos; return res; } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 7353bec7333c5..2acbcf5c7ec08 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -72,25 +72,27 @@ pub struct Encoder { } pub fn Encoder(wr: @io::Writer) -> Encoder { - Encoder { wr: wr } + Encoder { + wr: wr + } } impl serialize::Encoder for Encoder { - fn emit_nil(&self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { self.wr.write_str("null") } - fn emit_uint(&self, v: uint) { self.emit_float(v as float); } - fn emit_u64(&self, v: u64) { self.emit_float(v as float); } - fn emit_u32(&self, v: u32) { self.emit_float(v as float); } - fn emit_u16(&self, v: u16) { self.emit_float(v as float); } - fn emit_u8(&self, v: u8) { self.emit_float(v as float); } + fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } - fn emit_int(&self, v: int) { self.emit_float(v as float); } - fn emit_i64(&self, v: i64) { self.emit_float(v as float); } - fn emit_i32(&self, v: i32) { self.emit_float(v as float); } - fn emit_i16(&self, v: i16) { self.emit_float(v as float); } - fn emit_i8(&self, v: i8) { self.emit_float(v as float); } + fn emit_int(&mut self, v: int) { self.emit_float(v as float); } + fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } - fn emit_bool(&self, v: bool) { + fn emit_bool(&mut self, v: bool) { if v { self.wr.write_str("true"); } else { @@ -98,18 +100,22 @@ impl serialize::Encoder for Encoder { } } - fn emit_f64(&self, v: f64) { self.emit_float(v as float); } - fn emit_f32(&self, v: f32) { self.emit_float(v as float); } - fn emit_float(&self, v: float) { + fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } + fn emit_float(&mut self, v: float) { self.wr.write_str(float::to_str_digits(v, 6u)); } - fn emit_char(&self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)) } + fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } + fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)) } - fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum(&mut self, _name: &str, f: &fn(&mut Encoder)) { f(self) } - fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { // enums are encoded as strings or vectors: // Bunny => "Bunny" // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] @@ -120,109 +126,128 @@ impl serialize::Encoder for Encoder { self.wr.write_char('['); self.wr.write_str(escape_str(name)); self.wr.write_char(','); - f(); + f(self); self.wr.write_char(']'); } } - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - if idx != 0 {self.wr.write_char(',');} - f(); + fn emit_enum_variant_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + if idx != 0 { + self.wr.write_char(','); + } + f(self); } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut Encoder)) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { + fn emit_struct(&mut self, _: &str, _: uint, f: &fn(&mut Encoder)) { self.wr.write_char('{'); - f(); + f(self); self.wr.write_char('}'); } - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); - f(); - } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Encoder)) { if idx != 0 { self.wr.write_char(','); } self.wr.write_str(escape_str(name)); self.wr.write_char(':'); - f(); + f(self); } - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&mut self, + _name: &str, + len: uint, + f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } + fn emit_option(&mut self, f: &fn(&mut Encoder)) { f(self); } + fn emit_option_none(&mut self) { self.emit_nil(); } + fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { f(self); } - fn emit_seq(&self, _len: uint, f: &fn()) { + fn emit_seq(&mut self, _len: uint, f: &fn(&mut Encoder)) { self.wr.write_char('['); - f(); + f(self); self.wr.write_char(']'); } - fn emit_seq_elt(&self, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - f() + fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut Encoder)) { + if idx != 0 { + self.wr.write_char(','); + } + f(self) } - fn emit_map(&self, _len: uint, f: &fn()) { + fn emit_map(&mut self, _len: uint, f: &fn(&mut Encoder)) { self.wr.write_char('{'); - f(); + f(self); self.wr.write_char('}'); } - fn emit_map_elt_key(&self, idx: uint, f: &fn()) { + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Encoder)) { if idx != 0 { self.wr.write_char(','); } - f() + f(self) } - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut Encoder)) { self.wr.write_char(':'); - f() + f(self) } } pub struct PrettyEncoder { priv wr: @io::Writer, - priv mut indent: uint, + priv indent: uint, } pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { - PrettyEncoder { wr: wr, indent: 0 } + PrettyEncoder { + wr: wr, + indent: 0, + } } impl serialize::Encoder for PrettyEncoder { - fn emit_nil(&self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { self.wr.write_str("null") } - fn emit_uint(&self, v: uint) { self.emit_float(v as float); } - fn emit_u64(&self, v: u64) { self.emit_float(v as float); } - fn emit_u32(&self, v: u32) { self.emit_float(v as float); } - fn emit_u16(&self, v: u16) { self.emit_float(v as float); } - fn emit_u8(&self, v: u8) { self.emit_float(v as float); } + fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } - fn emit_int(&self, v: int) { self.emit_float(v as float); } - fn emit_i64(&self, v: i64) { self.emit_float(v as float); } - fn emit_i32(&self, v: i32) { self.emit_float(v as float); } - fn emit_i16(&self, v: i16) { self.emit_float(v as float); } - fn emit_i8(&self, v: i8) { self.emit_float(v as float); } + fn emit_int(&mut self, v: int) { self.emit_float(v as float); } + fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } - fn emit_bool(&self, v: bool) { + fn emit_bool(&mut self, v: bool) { if v { self.wr.write_str("true"); } else { @@ -230,18 +255,24 @@ impl serialize::Encoder for PrettyEncoder { } } - fn emit_f64(&self, v: f64) { self.emit_float(v as float); } - fn emit_f32(&self, v: f32) { self.emit_float(v as float); } - fn emit_float(&self, v: float) { + fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } + fn emit_float(&mut self, v: float) { self.wr.write_str(float::to_str_digits(v, 6u)); } - fn emit_char(&self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)); } + fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } + fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)); } - fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum(&mut self, _name: &str, f: &fn(&mut PrettyEncoder)) { + f(self) + } - fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { + fn emit_enum_variant(&mut self, + name: &str, + _: uint, + cnt: uint, + f: &fn(&mut PrettyEncoder)) { if cnt == 0 { self.wr.write_str(escape_str(name)); } else { @@ -251,7 +282,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_str(spaces(self.indent)); self.wr.write_str(escape_str(name)); self.wr.write_str(",\n"); - f(); + f(self); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); @@ -259,52 +290,53 @@ impl serialize::Encoder for PrettyEncoder { } } - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { + fn emit_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut PrettyEncoder)) { if idx != 0 { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - f() + f(self) } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut PrettyEncoder)) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut PrettyEncoder)) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { + fn emit_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut PrettyEncoder)) { if len == 0 { self.wr.write_str("{}"); } else { self.wr.write_char('{'); self.indent += 2; - f(); + f(self); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); self.wr.write_char('}'); } } - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); - } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut PrettyEncoder)) { if idx == 0 { self.wr.write_char('\n'); } else { @@ -313,73 +345,88 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_str(spaces(self.indent)); self.wr.write_str(escape_str(name)); self.wr.write_str(": "); - f(); + f(self); } - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_seq_elt(idx, f) + } - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } + fn emit_option(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } + fn emit_option_none(&mut self) { self.emit_nil(); } + fn emit_option_some(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } - fn emit_seq(&self, len: uint, f: &fn()) { + fn emit_seq(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { self.wr.write_str("[]"); } else { self.wr.write_char('['); self.indent += 2; - f(); + f(self); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); self.wr.write_char(']'); } } - fn emit_seq_elt(&self, idx: uint, f: &fn()) { + + fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - f() + f(self) } - fn emit_map(&self, len: uint, f: &fn()) { + fn emit_map(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { self.wr.write_str("{}"); } else { self.wr.write_char('{'); self.indent += 2; - f(); + f(self); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); self.wr.write_char('}'); } } - fn emit_map_elt_key(&self, idx: uint, f: &fn()) { + + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - f(); + f(self); } - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut PrettyEncoder)) { self.wr.write_str(": "); - f(); + f(self); } } impl serialize::Encodable for Json { - fn encode(&self, e: &E) { + fn encode(&self, e: &mut E) { match *self { Number(v) => v.encode(e), String(ref v) => v.encode(e), @@ -393,7 +440,8 @@ impl serialize::Encodable for Json { /// Encodes a json value into a io::writer pub fn to_writer(wr: @io::Writer, json: &Json) { - json.encode(&Encoder(wr)) + let mut encoder = Encoder(wr); + json.encode(&mut encoder) } /// Encodes a json value into a string @@ -403,7 +451,8 @@ pub fn to_str(json: &Json) -> ~str { /// Encodes a json value into a io::writer pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { - json.encode(&PrettyEncoder(wr)) + let mut encoder = PrettyEncoder(wr); + json.encode(&mut encoder) } /// Encodes a json value into a string @@ -790,15 +839,17 @@ pub fn from_str(s: &str) -> Result { } pub struct Decoder { - priv mut stack: ~[Json], + priv stack: ~[Json], } pub fn Decoder(json: Json) -> Decoder { - Decoder { stack: ~[json] } + Decoder { + stack: ~[json] + } } impl serialize::Decoder for Decoder { - fn read_nil(&self) -> () { + fn read_nil(&mut self) -> () { debug!("read_nil"); match self.stack.pop() { Null => (), @@ -806,19 +857,19 @@ impl serialize::Decoder for Decoder { } } - fn read_u64(&self) -> u64 { self.read_float() as u64 } - fn read_u32(&self) -> u32 { self.read_float() as u32 } - fn read_u16(&self) -> u16 { self.read_float() as u16 } - fn read_u8 (&self) -> u8 { self.read_float() as u8 } - fn read_uint(&self) -> uint { self.read_float() as uint } + fn read_u64(&mut self) -> u64 { self.read_float() as u64 } + fn read_u32(&mut self) -> u32 { self.read_float() as u32 } + fn read_u16(&mut self) -> u16 { self.read_float() as u16 } + fn read_u8 (&mut self) -> u8 { self.read_float() as u8 } + fn read_uint(&mut self) -> uint { self.read_float() as uint } - fn read_i64(&self) -> i64 { self.read_float() as i64 } - fn read_i32(&self) -> i32 { self.read_float() as i32 } - fn read_i16(&self) -> i16 { self.read_float() as i16 } - fn read_i8 (&self) -> i8 { self.read_float() as i8 } - fn read_int(&self) -> int { self.read_float() as int } + fn read_i64(&mut self) -> i64 { self.read_float() as i64 } + fn read_i32(&mut self) -> i32 { self.read_float() as i32 } + fn read_i16(&mut self) -> i16 { self.read_float() as i16 } + fn read_i8 (&mut self) -> i8 { self.read_float() as i8 } + fn read_int(&mut self) -> int { self.read_float() as int } - fn read_bool(&self) -> bool { + fn read_bool(&mut self) -> bool { debug!("read_bool"); match self.stack.pop() { Boolean(b) => b, @@ -826,9 +877,9 @@ impl serialize::Decoder for Decoder { } } - fn read_f64(&self) -> f64 { self.read_float() as f64 } - fn read_f32(&self) -> f32 { self.read_float() as f32 } - fn read_float(&self) -> float { + fn read_f64(&mut self) -> f64 { self.read_float() as f64 } + fn read_f32(&mut self) -> f32 { self.read_float() as f32 } + fn read_float(&mut self) -> float { debug!("read_float"); match self.stack.pop() { Number(f) => f, @@ -836,14 +887,14 @@ impl serialize::Decoder for Decoder { } } - fn read_char(&self) -> char { + fn read_char(&mut self) -> char { let mut v = ~[]; for str::each_char(self.read_str()) |c| { v.push(c) } if v.len() != 1 { fail!(~"string must have one character") } v[0] } - fn read_str(&self) -> ~str { + fn read_str(&mut self) -> ~str { debug!("read_str"); match self.stack.pop() { String(s) => s, @@ -851,12 +902,15 @@ impl serialize::Decoder for Decoder { } } - fn read_enum(&self, name: &str, f: &fn() -> T) -> T { + fn read_enum(&mut self, name: &str, f: &fn(&mut Decoder) -> T) -> T { debug!("read_enum(%s)", name); - f() + f(self) } - fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_variant(&mut self, + names: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_enum_variant(names=%?)", names); let name = match self.stack.pop() { String(s) => s, @@ -875,56 +929,51 @@ impl serialize::Decoder for Decoder { Some(idx) => idx, None => fail!(fmt!("Unknown variant name: %?", name)), }; - f(idx) + f(self, idx) } - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_enum_variant_arg(idx=%u)", idx); - f() + f(self) } - fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_struct_variant(&mut self, + names: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_enum_struct_variant(names=%?)", names); self.read_enum_variant(names, f) } - fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); self.read_enum_variant_arg(idx, f) } - fn read_struct(&self, name: &str, len: uint, f: &fn() -> T) -> T { + fn read_struct(&mut self, + name: &str, + len: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_struct(name=%s, len=%u)", name, len); - let value = f(); + let value = f(self); self.stack.pop(); value } - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let value = match obj.pop(&name.to_owned()) { - None => fail!(fmt!("no such field: %s", name)), - Some(json) => { - self.stack.push(json); - f() - } - }; - self.stack.push(Object(obj)); - value - } - value => fail!(fmt!("not an object: %?", value)) - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_struct_field(name=%?, idx=%u)", name, idx); match self.stack.pop() { Object(obj) => { @@ -933,7 +982,7 @@ impl serialize::Decoder for Decoder { None => fail!(fmt!("no such field: %s", name)), Some(json) => { self.stack.push(json); - f() + f(self) } }; self.stack.push(Object(obj)); @@ -943,34 +992,43 @@ impl serialize::Decoder for Decoder { } } - fn read_tuple(&self, f: &fn(uint) -> T) -> T { + fn read_tuple(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_tuple()"); self.read_seq(f) } - fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_tuple_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_tuple_arg(idx=%u)", idx); self.read_seq_elt(idx, f) } - fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + fn read_tuple_struct(&mut self, + name: &str, + f: &fn(&mut Decoder, uint) -> T) + -> T { debug!("read_tuple_struct(name=%?)", name); self.read_tuple(f) } - fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_tuple_struct_arg(idx=%u)", idx); self.read_tuple_arg(idx, f) } - fn read_option(&self, f: &fn(bool) -> T) -> T { + fn read_option(&mut self, f: &fn(&mut Decoder, bool) -> T) -> T { match self.stack.pop() { - Null => f(false), - value => { self.stack.push(value); f(true) } + Null => f(self, false), + value => { self.stack.push(value); f(self, true) } } } - fn read_seq(&self, f: &fn(uint) -> T) -> T { + fn read_seq(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_seq()"); let len = match self.stack.pop() { List(list) => { @@ -982,15 +1040,15 @@ impl serialize::Decoder for Decoder { } _ => fail!(~"not a list"), }; - f(len) + f(self, len) } - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) -> T { debug!("read_seq_elt(idx=%u)", idx); - f() + f(self) } - fn read_map(&self, f: &fn(uint) -> T) -> T { + fn read_map(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { debug!("read_map()"); let len = match self.stack.pop() { Object(obj) => { @@ -1004,17 +1062,21 @@ impl serialize::Decoder for Decoder { } json => fail!(fmt!("not an object: %?", json)), }; - f(len) + f(self, len) } - fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T { + fn read_map_elt_key(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { debug!("read_map_elt_key(idx=%u)", idx); - f() + f(self) } - fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T { + fn read_map_elt_val(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { debug!("read_map_elt_val(idx=%u)", idx); - f() + f(self) } } @@ -1452,15 +1514,15 @@ mod tests { let animal = Dog; assert_eq!( do io::with_str_writer |wr| { - let encoder = Encoder(wr); - animal.encode(&encoder); + let mut encoder = Encoder(wr); + animal.encode(&mut encoder); }, ~"\"Dog\"" ); assert_eq!( do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - animal.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + animal.encode(&mut encoder); }, ~"\"Dog\"" ); @@ -1468,15 +1530,15 @@ mod tests { let animal = Frog(~"Henry", 349); assert_eq!( do io::with_str_writer |wr| { - let encoder = Encoder(wr); - animal.encode(&encoder); + let mut encoder = Encoder(wr); + animal.encode(&mut encoder); }, ~"[\"Frog\",\"Henry\",349]" ); assert_eq!( do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - animal.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + animal.encode(&mut encoder); }, ~"\ [\n \ @@ -1491,15 +1553,15 @@ mod tests { fn test_write_some() { let value = Some(~"jodhpurs"); let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); let value = Some(~"jodhpurs"); let s = do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - value.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); } @@ -1508,14 +1570,14 @@ mod tests { fn test_write_none() { let value: Option<~str> = None; let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"null"); let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"null"); } @@ -1563,13 +1625,16 @@ mod tests { #[test] fn test_decode_identifiers() { - let v: () = Decodable::decode(&Decoder(from_str(~"null").unwrap())); + let mut decoder = Decoder(from_str(~"null").unwrap()); + let v: () = Decodable::decode(&mut decoder); assert_eq!(v, ()); - let v: bool = Decodable::decode(&Decoder(from_str(~"true").unwrap())); + let mut decoder = Decoder(from_str(~"true").unwrap()); + let v: bool = Decodable::decode(&mut decoder); assert_eq!(v, true); - let v: bool = Decodable::decode(&Decoder(from_str(~"false").unwrap())); + let mut decoder = Decoder(from_str(~"false").unwrap()); + let v: bool = Decodable::decode(&mut decoder); assert_eq!(v, false); } @@ -1603,25 +1668,32 @@ mod tests { #[test] fn test_decode_numbers() { - let v: float = Decodable::decode(&Decoder(from_str(~"3").unwrap())); + let mut decoder = Decoder(from_str(~"3").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 3f); - let v: float = Decodable::decode(&Decoder(from_str(~"3.1").unwrap())); + let mut decoder = Decoder(from_str(~"3.1").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 3.1f); - let v: float = Decodable::decode(&Decoder(from_str(~"-1.2").unwrap())); + let mut decoder = Decoder(from_str(~"-1.2").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, -1.2f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4").unwrap())); + let mut decoder = Decoder(from_str(~"0.4").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e5").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e5").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e5f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e15").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e15").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e15f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e-01").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e-01").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e-01f); } @@ -1648,31 +1720,40 @@ mod tests { #[test] fn test_decode_str() { - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~""); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"foo\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"foo\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"foo"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\\"\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\\"\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\""); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\b\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\b\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\x08"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\n\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\n\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\n"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\r\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\r\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\r"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\t\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\t\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\t"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\u12ab\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\u12ab\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\u12ab"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\uAB12\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\uAB12\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\uAB12"); } @@ -1704,23 +1785,28 @@ mod tests { #[test] fn test_decode_list() { - let v: ~[()] = Decodable::decode(&Decoder(from_str(~"[]").unwrap())); + let mut decoder = Decoder(from_str(~"[]").unwrap()); + let v: ~[()] = Decodable::decode(&mut decoder); assert_eq!(v, ~[]); - let v: ~[()] = Decodable::decode(&Decoder(from_str(~"[null]").unwrap())); + let mut decoder = Decoder(from_str(~"[null]").unwrap()); + let v: ~[()] = Decodable::decode(&mut decoder); assert_eq!(v, ~[()]); - - let v: ~[bool] = Decodable::decode(&Decoder(from_str(~"[true]").unwrap())); + let mut decoder = Decoder(from_str(~"[true]").unwrap()); + let v: ~[bool] = Decodable::decode(&mut decoder); assert_eq!(v, ~[true]); - let v: ~[bool] = Decodable::decode(&Decoder(from_str(~"[true]").unwrap())); + let mut decoder = Decoder(from_str(~"[true]").unwrap()); + let v: ~[bool] = Decodable::decode(&mut decoder); assert_eq!(v, ~[true]); - let v: ~[int] = Decodable::decode(&Decoder(from_str(~"[3, 1]").unwrap())); + let mut decoder = Decoder(from_str(~"[3, 1]").unwrap()); + let v: ~[int] = Decodable::decode(&mut decoder); assert_eq!(v, ~[3, 1]); - let v: ~[~[uint]] = Decodable::decode(&Decoder(from_str(~"[[3], [1, 2]]").unwrap())); + let mut decoder = Decoder(from_str(~"[[3], [1, 2]]").unwrap()); + let v: ~[~[uint]] = Decodable::decode(&mut decoder); assert_eq!(v, ~[~[3], ~[1, 2]]); } @@ -1822,7 +1908,8 @@ mod tests { { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } ] }"; - let v: Outer = Decodable::decode(&Decoder(from_str(s).unwrap())); + let mut decoder = Decoder(from_str(s).unwrap()); + let v: Outer = Decodable::decode(&mut decoder); assert_eq!( v, Outer { @@ -1835,31 +1922,32 @@ mod tests { #[test] fn test_decode_option() { - let decoder = Decoder(from_str(~"null").unwrap()); - let value: Option<~str> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"null").unwrap()); + let value: Option<~str> = Decodable::decode(&mut decoder); assert_eq!(value, None); - let decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap()); - let value: Option<~str> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap()); + let value: Option<~str> = Decodable::decode(&mut decoder); assert_eq!(value, Some(~"jodhpurs")); } #[test] fn test_decode_enum() { - let decoder = Decoder(from_str(~"\"Dog\"").unwrap()); - let value: Animal = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"\"Dog\"").unwrap()); + let value: Animal = Decodable::decode(&mut decoder); assert_eq!(value, Dog); - let decoder = Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap()); - let value: Animal = Decodable::decode(&decoder); + let mut decoder = + Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap()); + let value: Animal = Decodable::decode(&mut decoder); assert_eq!(value, Frog(~"Henry", 349)); } #[test] fn test_decode_map() { let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}"; - let decoder = Decoder(from_str(s).unwrap()); - let mut map: HashMap<~str, Animal> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(s).unwrap()); + let mut map: HashMap<~str, Animal> = Decodable::decode(&mut decoder); assert_eq!(map.pop(&~"a"), Some(Dog)); assert_eq!(map.pop(&~"b"), Some(Frog(~"Henry", 349))); diff --git a/src/libstd/list.rs b/src/libstd/list.rs index 401cc121a62a8..13ef377fabeb2 100644 --- a/src/libstd/list.rs +++ b/src/libstd/list.rs @@ -16,6 +16,12 @@ pub enum List { Nil, } +#[deriving(Eq)] +pub enum MutList { + MutCons(T, @mut MutList), + MutNil, +} + /// Create a list from a vector pub fn from_vec(v: &[T]) -> @List { vec::foldr(v, @Nil::, |h, t| @Cons(*h, t)) @@ -134,6 +140,7 @@ pub fn iter(l: @List, f: &fn(&T)) { } /// Iterate over a list +#[cfg(stage0)] pub fn each(l: @List, f: &fn(&T) -> bool) { let mut cur = l; loop { @@ -146,6 +153,58 @@ pub fn each(l: @List, f: &fn(&T) -> bool) { } } } +/// Iterate over a list +#[cfg(not(stage0))] +pub fn each(l: @List, f: &fn(&T) -> bool) -> bool { + let mut cur = l; + loop { + cur = match *cur { + Cons(ref hd, tl) => { + if !f(hd) { return false; } + tl + } + Nil => { return true; } + } + } +} + +impl MutList { + /// Iterate over a mutable list + #[cfg(stage0)] + pub fn each(@mut self, f: &fn(&mut T) -> bool) { + let mut cur = self; + loop { + let borrowed = &mut *cur; + cur = match *borrowed { + MutCons(ref mut hd, tl) => { + if !f(hd) { + return; + } + tl + } + MutNil => break + } + } + } + /// Iterate over a mutable list + #[cfg(not(stage0))] + pub fn each(@mut self, f: &fn(&mut T) -> bool) -> bool { + let mut cur = self; + loop { + let borrowed = &mut *cur; + cur = match *borrowed { + MutCons(ref mut hd, tl) => { + if !f(hd) { + return false; + } + tl + } + MutNil => break + } + } + return true; + } +} #[cfg(test)] mod tests { @@ -242,11 +301,3 @@ mod tests { == list::append(list::from_vec(~[1,2]), list::from_vec(~[3,4]))); } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/md4.rs b/src/libstd/md4.rs index 24dd08c362e99..71b62ca36a5ee 100644 --- a/src/libstd/md4.rs +++ b/src/libstd/md4.rs @@ -26,7 +26,7 @@ pub fn md4(msg: &[u8]) -> Quad { let orig_len: u64 = (vec::len(msg) * 8u) as u64; // pad message - let mut msg = vec::append(vec::from_slice(msg), ~[0x80u8]); + let mut msg = vec::append(vec::to_owned(msg), ~[0x80u8]); let mut bitlen = orig_len + 8u64; while (bitlen + 64u64) % 512u64 > 0u64 { msg.push(0u8); diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 800144c0ca7be..58775c5f2e48f 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -175,7 +175,7 @@ pub mod v4 { pub fn parse_addr(ip: &str) -> IpAddr { match try_parse_addr(ip) { result::Ok(addr) => addr, - result::Err(ref err_data) => fail!(err_data.err_msg) + result::Err(ref err_data) => fail!(copy err_data.err_msg) } } // the simple, old style numberic representation of @@ -225,7 +225,7 @@ pub mod v4 { let input_is_inaddr_none = result::get(&ip_rep_result).as_u32() == INADDR_NONE; - let new_addr = uv_ip4_addr(str::from_slice(ip), 22); + let new_addr = uv_ip4_addr(str::to_owned(ip), 22); let reformatted_name = uv_ip4_name(&new_addr); debug!("try_parse_addr: input ip: %s reparsed ip: %s", ip, reformatted_name); @@ -272,13 +272,13 @@ pub mod v6 { pub fn parse_addr(ip: &str) -> IpAddr { match try_parse_addr(ip) { result::Ok(addr) => addr, - result::Err(copy err_data) => fail!(err_data.err_msg) + result::Err(copy err_data) => fail!(copy err_data.err_msg) } } pub fn try_parse_addr(ip: &str) -> result::Result { unsafe { // need to figure out how to establish a parse failure.. - let new_addr = uv_ip6_addr(str::from_slice(ip), 22); + let new_addr = uv_ip6_addr(str::to_owned(ip), 22); let reparsed_name = uv_ip6_name(&new_addr); debug!("v6::try_parse_addr ip: '%s' reparsed '%s'", ip, reparsed_name); @@ -420,12 +420,12 @@ mod test { if result::is_err(&ga_result) { fail!(~"got err result from net::ip::get_addr();") } - // note really sure how to realiably test/assert + // note really sure how to reliably test/assert // this.. mostly just wanting to see it work, atm. let results = result::unwrap(ga_result); debug!("test_get_addr: Number of results for %s: %?", localhost_name, vec::len(results)); - for vec::each(results) |r| { + for results.each |r| { let ipv_prefix = match *r { Ipv4(_) => ~"IPv4", Ipv6(_) => ~"IPv6" diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 764152d6812c5..20e1a272910cc 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -11,8 +11,6 @@ //! High-level interface to libuv's TCP functionality // FIXME #4425: Need FFI fixes -#[allow(deprecated_mode)]; - use future; use future_spawn = future::spawn; use ip = net_ip; @@ -73,14 +71,14 @@ pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket { * satisfy both the `io::Reader` and `io::Writer` traits. */ pub struct TcpSocketBuf { - data: @TcpBufferedSocketData, - mut end_of_stream: bool + data: @mut TcpBufferedSocketData, + end_of_stream: @mut bool } -pub fn TcpSocketBuf(data: @TcpBufferedSocketData) -> TcpSocketBuf { +pub fn TcpSocketBuf(data: @mut TcpBufferedSocketData) -> TcpSocketBuf { TcpSocketBuf { data: data, - end_of_stream: false + end_of_stream: @mut false } } @@ -279,8 +277,8 @@ pub fn connect(input_ip: ip::IpAddr, port: uint, as *libc::c_void); let tcp_conn_err = match err_data.err_name { ~"ECONNREFUSED" => ConnectionRefused, - _ => GenericConnectErr(err_data.err_name, - err_data.err_msg) + _ => GenericConnectErr(copy err_data.err_name, + copy err_data.err_msg) }; result::Err(tcp_conn_err) } @@ -672,7 +670,7 @@ fn listen_common(host_ip: ip::IpAddr, &ip::Ipv4(_) => { false } &ip::Ipv6(_) => { true } }, - mut active: true + active: @mut true }; let server_data_ptr: *TcpListenFcData = &server_data; @@ -753,7 +751,7 @@ fn listen_common(host_ip: ip::IpAddr, debug!( "tcp::listen post-kill recv hl interact %?", loop_ptr); - (*server_data_ptr).active = false; + *(*server_data_ptr).active = false; uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); } }; @@ -771,8 +769,8 @@ fn listen_common(host_ip: ip::IpAddr, debug!("Got '%s' '%s' libuv error", err_data.err_name, err_data.err_msg); result::Err( - GenericListenErr(err_data.err_name, - err_data.err_msg)) + GenericListenErr(copy err_data.err_name, + copy err_data.err_msg)) } } } @@ -784,7 +782,7 @@ fn listen_common(host_ip: ip::IpAddr, debug!( "tcp::listen post-kill recv hl interact %?", loop_ptr); - (*server_data_ptr).active = false; + *(*server_data_ptr).active = false; uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); } }; @@ -792,8 +790,8 @@ fn listen_common(host_ip: ip::IpAddr, match kill_result { // some failure post bind/listen Some(ref err_data) => result::Err(GenericListenErr( - err_data.err_name, - err_data.err_msg)), + copy err_data.err_name, + copy err_data.err_msg)), // clean exit None => result::Ok(()) } @@ -818,8 +816,8 @@ fn listen_common(host_ip: ip::IpAddr, * A buffered wrapper that you can cast as an `io::Reader` or `io::Writer` */ pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf { - TcpSocketBuf(@TcpBufferedSocketData { - sock: sock, mut buf: ~[], buf_off: 0 + TcpSocketBuf(@mut TcpBufferedSocketData { + sock: sock, buf: ~[], buf_off: 0 }) } @@ -885,8 +883,8 @@ impl io::Reader for TcpSocketBuf { let ncopy = uint::min(nbuffered, needed); let dst = ptr::mut_offset( vec::raw::to_mut_ptr(buf), count); - let src = ptr::const_offset( - vec::raw::to_const_ptr(self.data.buf), + let src = ptr::offset( + vec::raw::to_ptr(self.data.buf), self.data.buf_off); ptr::copy_memory(dst, src, ncopy); self.data.buf_off += ncopy; @@ -904,12 +902,15 @@ impl io::Reader for TcpSocketBuf { // need to read in data from the socket. Note that the internal // buffer is of no use anymore as we read all bytes from it, // so we can throw it away. - let read_result = read(&self.data.sock, 0u); + let read_result = { + let data = &*self.data; + read(&data.sock, 0) + }; if read_result.is_err() { let err_data = read_result.get_err(); if err_data.err_name == ~"EOF" { - self.end_of_stream = true; + *self.end_of_stream = true; break; } else { debug!("ERROR sock_buf as io::reader.read err %? %?", @@ -919,8 +920,7 @@ impl io::Reader for TcpSocketBuf { // should show up in a later call to read(). break; } - } - else { + } else { self.data.buf = result::unwrap(read_result); self.data.buf_off = 0; } @@ -936,27 +936,29 @@ impl io::Reader for TcpSocketBuf { return c as int } - let read_result = read(&self.data.sock, 0u); + let read_result = { + let data = &*self.data; + read(&data.sock, 0) + }; if read_result.is_err() { let err_data = read_result.get_err(); if err_data.err_name == ~"EOF" { - self.end_of_stream = true; + *self.end_of_stream = true; return -1 } else { debug!("ERROR sock_buf as io::reader.read err %? %?", err_data.err_name, err_data.err_msg); fail!() } - } - else { + } else { self.data.buf = result::unwrap(read_result); self.data.buf_off = 0; } } } fn eof(&self) -> bool { - self.end_of_stream + *self.end_of_stream } fn seek(&self, dist: int, seek: io::SeekStyle) { debug!("tcp_socket_buf seek stub %? %?", dist, seek); @@ -969,20 +971,18 @@ impl io::Reader for TcpSocketBuf { /// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` impl io::Writer for TcpSocketBuf { - pub fn write(&self, data: &const [u8]) { - unsafe { - 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_vec()); - if w_result.is_err() { - let err_data = w_result.get_err(); - debug!( - "ERROR sock_buf as io::writer.writer err: %? %?", - err_data.err_name, err_data.err_msg); - } + pub fn write(&self, data: &[u8]) { + 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_vec()); + if w_result.is_err() { + let err_data = w_result.get_err(); + debug!( + "ERROR sock_buf as io::writer.writer err: %? %?", + err_data.err_name, err_data.err_msg); } } fn seek(&self, dist: int, seek: io::SeekStyle) { @@ -1206,7 +1206,7 @@ struct TcpListenFcData { on_connect_cb: ~fn(*uv::ll::uv_tcp_t), iotask: IoTask, ipv6: bool, - mut active: bool, + active: @mut bool, } extern fn tcp_lfc_close_cb(handle: *uv::ll::uv_tcp_t) { @@ -1224,7 +1224,7 @@ extern fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t, let server_data_ptr = uv::ll::get_data_for_uv_handle(handle) as *TcpListenFcData; let kill_ch = (*server_data_ptr).kill_ch.clone(); - if (*server_data_ptr).active { + if *(*server_data_ptr).active { match status { 0i32 => ((*server_data_ptr).on_connect_cb)(handle), _ => { @@ -1232,7 +1232,7 @@ extern fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t, kill_ch.send( Some(uv::ll::get_last_err_data(loop_ptr) .to_tcp_err())); - (*server_data_ptr).active = false; + *(*server_data_ptr).active = false; } } } @@ -1273,7 +1273,7 @@ trait ToTcpErr { impl ToTcpErr for uv::ll::uv_err_data { fn to_tcp_err(&self) -> TcpErrData { - TcpErrData { err_name: self.err_name, err_msg: self.err_msg } + TcpErrData { err_name: copy self.err_name, err_msg: copy self.err_msg } } } @@ -1432,8 +1432,8 @@ struct TcpSocketData { struct TcpBufferedSocketData { sock: TcpSocket, - mut buf: ~[u8], - mut buf_off: uint + buf: ~[u8], + buf_off: uint } #[cfg(test)] @@ -1445,12 +1445,8 @@ mod test { use uv::iotask::IoTask; use uv; - use core::io; + use core::cell::Cell; use core::comm::{stream, SharedChan}; - use core::result; - use core::str; - use core::task; - use core::vec; // FIXME don't run on fbsd or linux 32 bit (#2064) #[cfg(target_os="win32")] @@ -1465,7 +1461,6 @@ mod test { #[test] fn test_gl_tcp_server_and_client_ipv4() { unsafe { - use net::tcp::test::tcp_ipv4_server_and_client_test::*; impl_gl_tcp_ipv4_server_and_client(); } } @@ -1556,10 +1551,10 @@ mod test { } pub fn impl_gl_tcp_ipv4_server_and_client() { let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 8888u; let expected_req = ~"ping"; - let expected_resp = ~"pong"; + let expected_resp = "pong"; let (server_result_po, server_result_ch) = stream::<~str>(); @@ -1572,7 +1567,7 @@ mod test { let actual_req = run_tcp_test_server( server_ip, server_port, - expected_resp, + expected_resp.to_str(), cont_ch.clone(), &hl_loop_clone); server_result_ch.send(actual_req); @@ -1597,9 +1592,9 @@ mod test { } pub fn impl_gl_tcp_ipv4_get_peer_addr() { let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 8887u; - let expected_resp = ~"pong"; + let expected_resp = "pong"; let (cont_po, cont_ch) = stream::<()>(); let cont_ch = SharedChan::new(cont_ch); @@ -1610,7 +1605,7 @@ mod test { run_tcp_test_server( server_ip, server_port, - expected_resp, + expected_resp.to_str(), cont_ch.clone(), &hl_loop_clone); }; @@ -1639,7 +1634,7 @@ mod test { } pub fn impl_gl_tcp_ipv4_client_error_connection_refused() { let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 8889u; let expected_req = ~"ping"; // client @@ -1656,10 +1651,10 @@ mod test { } pub fn impl_gl_tcp_ipv4_server_address_in_use() { let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 8890u; let expected_req = ~"ping"; - let expected_resp = ~"pong"; + let expected_resp = "pong"; let (cont_po, cont_ch) = stream::<()>(); let cont_ch = SharedChan::new(cont_ch); @@ -1670,7 +1665,7 @@ mod test { run_tcp_test_server( server_ip, server_port, - expected_resp, + expected_resp.to_str(), cont_ch.clone(), &hl_loop_clone); } @@ -1699,7 +1694,7 @@ mod test { } pub fn impl_gl_tcp_ipv4_server_access_denied() { let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 80u; // this one should fail.. let listen_err = run_tcp_test_server_fail( @@ -1719,10 +1714,10 @@ mod test { pub fn impl_gl_tcp_ipv4_server_client_reader_writer() { let iotask = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 8891u; let expected_req = ~"ping"; - let expected_resp = ~"pong"; + let expected_resp = "pong"; let (server_result_po, server_result_ch) = stream::<~str>(); @@ -1735,7 +1730,7 @@ mod test { let actual_req = run_tcp_test_server( server_ip, server_port, - expected_resp, + expected_resp.to_str(), cont_ch.clone(), &iotask_clone); server_result_ch.send(actual_req); @@ -1751,7 +1746,7 @@ mod test { buf_write(sock_buf, expected_req); // so contrived! - let actual_resp = do str::as_bytes(&expected_resp) |resp_buf| { + let actual_resp = do str::as_bytes(&expected_resp.to_str()) |resp_buf| { buf_read(sock_buf, resp_buf.len()) }; @@ -1768,10 +1763,10 @@ mod test { use core::io::{Reader,ReaderUtil}; let hl_loop = &uv::global_loop::get(); - let server_ip = ~"127.0.0.1"; + let server_ip = "127.0.0.1"; let server_port = 10041u; let expected_req = ~"GET /"; - let expected_resp = ~"A string\nwith multiple lines\n"; + let expected_resp = "A string\nwith multiple lines\n"; let (cont_po, cont_ch) = stream::<()>(); let cont_ch = SharedChan::new(cont_ch); @@ -1782,7 +1777,7 @@ mod test { run_tcp_test_server( server_ip, server_port, - expected_resp, + expected_resp.to_str(), cont_ch.clone(), &hl_loop_clone); }; @@ -1825,6 +1820,7 @@ mod test { let (server_po, server_ch) = stream::<~str>(); let server_ch = SharedChan::new(server_ch); let server_ip_addr = ip::v4::parse_addr(server_ip); + let resp_cell = Cell(resp); let listen_result = listen(server_ip_addr, server_port, 128, iotask, // on_establish_cb -- called when listener is set up @@ -1836,6 +1832,7 @@ mod test { // risky to run this on the loop, but some users // will want the POWER |new_conn, kill_ch| { + let resp_cell2 = Cell(resp_cell.take()); debug!("SERVER: new connection!"); let (cont_po, cont_ch) = stream(); let server_ch = server_ch.clone(); @@ -1870,7 +1867,7 @@ mod test { server_ch.send( str::from_bytes(data)); debug!("SERVER: before write"); - tcp_write_single(&sock, str::to_bytes(resp)); + tcp_write_single(&sock, str::to_bytes(resp_cell2.take())); debug!("SERVER: after write.. die"); kill_ch.send(None); } @@ -1961,7 +1958,7 @@ mod test { } fn tcp_write_single(sock: &TcpSocket, val: ~[u8]) { - let write_result_future = sock.write_future(val); + let mut write_result_future = sock.write_future(val); let write_result = write_result_future.get(); if result::is_err(&write_result) { debug!("tcp_write_single: write failed!"); diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index f3b11c132798c..e7cf710cf6797 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -10,18 +10,12 @@ //! Types/fns concerning URLs (see RFC 3986) -#[allow(deprecated_mode)]; - use core::cmp::Eq; -use core::from_str::FromStr; use core::io::{Reader, ReaderUtil}; use core::io; use core::hashmap::HashMap; use core::str; -use core::to_bytes::IterBytes; use core::to_bytes; -use core::to_str::ToStr; -use core::to_str; use core::uint; #[deriving(Clone, Eq)] @@ -703,17 +697,24 @@ pub fn to_str(url: &Url) -> ~str { fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment) } -impl to_str::ToStr for Url { +impl ToStr for Url { pub fn to_str(&self) -> ~str { to_str(self) } } -impl to_bytes::IterBytes for Url { +#[cfg(stage0)] +impl IterBytes for Url { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_str().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl IterBytes for Url { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.to_str().iter_bytes(lsb0, f) + } +} // Put a few tests outside of the 'test' module so they can test the internal // functions and those functions don't need 'pub' diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index e010340b94d8e..498c86dd8e101 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -16,12 +16,8 @@ A BigUint is represented as an array of BigDigits. A BigInt is a combination of BigUint and Sign. */ -#[deny(vecs_implicitly_copyable)]; -#[deny(deprecated_mutable_fields)]; - use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix}; -use core::*; /** A BigDigit is a BigUint's composing element. @@ -80,6 +76,7 @@ A big unsigned integer type. A BigUint-typed value BigUint { data: @[a, b, c] } represents a number (a + b * BigDigit::base + c * BigDigit::base^2). */ +#[deriving(Clone)] pub struct BigUint { priv data: ~[BigDigit] } @@ -140,7 +137,7 @@ impl ToStr for BigUint { fn to_str(&self) -> ~str { self.to_str_radix(10) } } -impl from_str::FromStr for BigUint { +impl FromStr for BigUint { #[inline(always)] fn from_str(s: &str) -> Option { FromStrRadix::from_str_radix(s, 10) @@ -293,10 +290,10 @@ impl Mul for BigUint { } } -impl Quot for BigUint { +impl Div for BigUint { #[inline(always)] - fn quot(&self, other: &BigUint) -> BigUint { - let (q, _) = self.quot_rem(other); + fn div(&self, other: &BigUint) -> BigUint { + let (q, _) = self.div_rem(other); return q; } } @@ -304,7 +301,7 @@ impl Quot for BigUint { impl Rem for BigUint { #[inline(always)] fn rem(&self, other: &BigUint) -> BigUint { - let (_, r) = self.quot_rem(other); + let (_, r) = self.div_rem(other); return r; } } @@ -316,19 +313,24 @@ impl Neg for BigUint { impl Integer for BigUint { #[inline(always)] - fn div(&self, other: &BigUint) -> BigUint { - let (d, _) = self.div_mod(other); + fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) { + self.div_mod_floor(other) + } + + #[inline(always)] + fn div_floor(&self, other: &BigUint) -> BigUint { + let (d, _) = self.div_mod_floor(other); return d; } #[inline(always)] - fn modulo(&self, other: &BigUint) -> BigUint { - let (_, m) = self.div_mod(other); + fn mod_floor(&self, other: &BigUint) -> BigUint { + let (_, m) = self.div_mod_floor(other); return m; } #[inline(always)] - fn div_mod(&self, other: &BigUint) -> (BigUint, BigUint) { + fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) { if other.is_zero() { fail!() } if self.is_zero() { return (Zero::zero(), Zero::zero()); } if *other == One::one() { return (copy *self, Zero::zero()); } @@ -346,11 +348,11 @@ impl Integer for BigUint { shift += 1; } assert!(shift < BigDigit::bits); - let (d, m) = div_mod_inner(self << shift, other << shift); + let (d, m) = div_mod_floor_inner(self << shift, other << shift); return (d, m >> shift); #[inline(always)] - fn div_mod_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { + fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { let mut m = a; let mut d = Zero::zero::(); let mut n = 1; @@ -409,11 +411,6 @@ impl Integer for BigUint { } } - #[inline(always)] - fn quot_rem(&self, other: &BigUint) -> (BigUint, BigUint) { - self.div_mod(other) - } - /** * Calculates the Greatest Common Divisor (GCD) of the number and `other` * @@ -448,7 +445,7 @@ impl Integer for BigUint { if self.data.is_empty() { true } else { - self.data.last().is_even() + self.data[0].is_even() } } @@ -485,7 +482,7 @@ impl ToStrRadix for BigUint { let mut result = ~[]; let mut m = n; while m > divider { - let (d, m0) = m.div_mod(÷r); + let (d, m0) = m.div_mod_floor(÷r); result += [m0.to_uint() as BigDigit]; m = d; } @@ -542,7 +539,7 @@ impl BigUint { /// Creates and initializes an BigUint. #[inline(always)] pub fn from_slice(slice: &[BigDigit]) -> BigUint { - return BigUint::new(vec::from_slice(slice)); + return BigUint::new(vec::to_owned(slice)); } /// Creates and initializes an BigUint. @@ -680,7 +677,7 @@ priv fn get_radix_base(radix: uint) -> (uint, uint) { } /// A Sign is a BigInt's composing element. -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum Sign { Minus, Zero, Plus } impl Ord for Sign { @@ -726,6 +723,7 @@ impl Neg for Sign { } /// A big signed integer type. +#[deriving(Clone)] pub struct BigInt { priv sign: Sign, priv data: BigUint @@ -783,7 +781,7 @@ impl ToStr for BigInt { fn to_str(&self) -> ~str { self.to_str_radix(10) } } -impl from_str::FromStr for BigInt { +impl FromStr for BigInt { #[inline(always)] fn from_str(s: &str) -> Option { FromStrRadix::from_str_radix(s, 10) @@ -825,11 +823,16 @@ impl Signed for BigInt { #[inline(always)] fn abs(&self) -> BigInt { match self.sign { - Plus | Zero => copy *self, - Minus => BigInt::from_biguint(Plus, copy self.data) + Plus | Zero => self.clone(), + Minus => BigInt::from_biguint(Plus, self.data.clone()) } } + #[inline(always)] + fn abs_sub(&self, other: &BigInt) -> BigInt { + if *self <= *other { Zero::zero() } else { *self - *other } + } + #[inline(always)] fn signum(&self) -> BigInt { match self.sign { @@ -850,8 +853,8 @@ impl Add for BigInt { #[inline(always)] fn add(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { - (Zero, _) => copy *other, - (_, Zero) => copy *self, + (Zero, _) => other.clone(), + (_, Zero) => self.clone(), (Plus, Plus) => BigInt::from_biguint(Plus, self.data + other.data), (Plus, Minus) => self - (-*other), @@ -866,7 +869,7 @@ impl Sub for BigInt { fn sub(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => -other, - (_, Zero) => copy *self, + (_, Zero) => self.clone(), (Plus, Plus) => match self.data.cmp(&other.data) { Less => BigInt::from_biguint(Minus, other.data - self.data), Greater => BigInt::from_biguint(Plus, self.data - other.data), @@ -894,10 +897,10 @@ impl Mul for BigInt { } } -impl Quot for BigInt { +impl Div for BigInt { #[inline(always)] - fn quot(&self, other: &BigInt) -> BigInt { - let (q, _) = self.quot_rem(other); + fn div(&self, other: &BigInt) -> BigInt { + let (q, _) = self.div_rem(other); return q; } } @@ -905,7 +908,7 @@ impl Quot for BigInt { impl Rem for BigInt { #[inline(always)] fn rem(&self, other: &BigInt) -> BigInt { - let (_, r) = self.quot_rem(other); + let (_, r) = self.div_rem(other); return r; } } @@ -913,27 +916,42 @@ impl Rem for BigInt { impl Neg for BigInt { #[inline(always)] fn neg(&self) -> BigInt { - BigInt::from_biguint(self.sign.neg(), copy self.data) + BigInt::from_biguint(self.sign.neg(), self.data.clone()) } } impl Integer for BigInt { #[inline(always)] - fn div(&self, other: &BigInt) -> BigInt { - let (d, _) = self.div_mod(other); + fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) { + // r.sign == self.sign + let (d_ui, r_ui) = self.data.div_mod_floor(&other.data); + let d = BigInt::from_biguint(Plus, d_ui); + let r = BigInt::from_biguint(Plus, r_ui); + match (self.sign, other.sign) { + (_, Zero) => fail!(), + (Plus, Plus) | (Zero, Plus) => ( d, r), + (Plus, Minus) | (Zero, Minus) => (-d, r), + (Minus, Plus) => (-d, -r), + (Minus, Minus) => ( d, -r) + } + } + + #[inline(always)] + fn div_floor(&self, other: &BigInt) -> BigInt { + let (d, _) = self.div_mod_floor(other); return d; } #[inline(always)] - fn modulo(&self, other: &BigInt) -> BigInt { - let (_, m) = self.div_mod(other); + fn mod_floor(&self, other: &BigInt) -> BigInt { + let (_, m) = self.div_mod_floor(other); return m; } #[inline(always)] - fn div_mod(&self, other: &BigInt) -> (BigInt, BigInt) { + fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) { // m.sign == other.sign - let (d_ui, m_ui) = self.data.quot_rem(&other.data); + let (d_ui, m_ui) = self.data.div_rem(&other.data); let d = BigInt::from_biguint(Plus, d_ui), m = BigInt::from_biguint(Plus, m_ui); match (self.sign, other.sign) { @@ -953,21 +971,6 @@ impl Integer for BigInt { } } - #[inline(always)] - fn quot_rem(&self, other: &BigInt) -> (BigInt, BigInt) { - // r.sign == self.sign - let (q_ui, r_ui) = self.data.div_mod(&other.data); - let q = BigInt::from_biguint(Plus, q_ui); - let r = BigInt::from_biguint(Plus, r_ui); - match (self.sign, other.sign) { - (_, Zero) => fail!(), - (Plus, Plus) | (Zero, Plus) => ( q, r), - (Plus, Minus) | (Zero, Minus) => (-q, r), - (Minus, Plus) => (-q, -r), - (Minus, Minus) => ( q, -r) - } - } - /** * Calculates the Greatest Common Divisor (GCD) of the number and `other` * @@ -1100,11 +1103,9 @@ pub impl BigInt { #[cfg(test)] mod biguint_tests { - - use core::*; + use super::*; use core::num::{IntConvertible, Zero, One, FromStrRadix}; use core::cmp::{Less, Equal, Greater}; - use super::{BigUint, BigDigit}; #[test] fn test_from_slice() { @@ -1347,7 +1348,7 @@ mod biguint_tests { (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; - static quot_rem_quadruples: &'static [(&'static [BigDigit], + static div_rem_quadruples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] @@ -1371,7 +1372,7 @@ mod biguint_tests { assert!(b * a == c); } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1384,7 +1385,7 @@ mod biguint_tests { } #[test] - fn test_quot_rem() { + fn test_div_rem() { for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); @@ -1392,21 +1393,21 @@ mod biguint_tests { let c = BigUint::from_slice(cVec); if !a.is_zero() { - assert!(c.quot_rem(&a) == (copy b, Zero::zero())); + assert!(c.div_rem(&a) == (b.clone(), Zero::zero())); } if !b.is_zero() { - assert!(c.quot_rem(&b) == (copy a, Zero::zero())); + assert!(c.div_rem(&b) == (a.clone(), Zero::zero())); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); let d = BigUint::from_slice(dVec); - if !b.is_zero() { assert!(a.quot_rem(&b) == (c, d)); } + if !b.is_zero() { assert!(a.div_rem(&b) == (c, d)); } } } @@ -1445,6 +1446,17 @@ mod biguint_tests { check(99, 17, 1683); } + #[test] + fn test_is_even() { + assert!(FromStr::from_str::("1").get().is_odd()); + assert!(FromStr::from_str::("2").get().is_even()); + assert!(FromStr::from_str::("1000").get().is_even()); + assert!(FromStr::from_str::("1000000000000000000000").get().is_even()); + assert!(FromStr::from_str::("1000000000000000000001").get().is_odd()); + assert!((BigUint::from_uint(1) << 64).is_even()); + assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd()); + } + fn to_str_pairs() -> ~[ (BigUint, ~[(uint, ~str)]) ] { let bits = BigDigit::bits; ~[( Zero::zero(), ~[ @@ -1557,8 +1569,7 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { - use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; - use core::*; + use super::*; use core::cmp::{Less, Equal, Greater}; use core::num::{IntConvertible, Zero, One, FromStrRadix}; @@ -1750,10 +1761,10 @@ mod bigint_tests { (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; - static quot_rem_quadruples: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] + static div_rem_quadruples: &'static [(&'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit])] = &[ (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[-1/2+1], &[1]), @@ -1777,7 +1788,7 @@ mod bigint_tests { assert!((-b) * a == -c); } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1790,9 +1801,9 @@ mod bigint_tests { } #[test] - fn test_div_mod() { + fn test_div_mod_floor() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { - let (d, m) = a.div_mod(b); + let (d, m) = a.div_mod_floor(b); if !m.is_zero() { assert!(m.sign == b.sign); } @@ -1826,7 +1837,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1841,9 +1852,9 @@ mod bigint_tests { #[test] - fn test_quot_rem() { + fn test_div_rem() { fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) { - let (q, r) = a.quot_rem(b); + let (q, r) = a.div_rem(b); if !r.is_zero() { assert!(r.sign == a.sign); } @@ -1869,7 +1880,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1922,6 +1933,15 @@ mod bigint_tests { check(11, 5, 55); } + #[test] + fn test_abs_sub() { + assert_eq!((-One::one::()).abs_sub(&One::one()), Zero::zero()); + assert_eq!(One::one::().abs_sub(&One::one()), Zero::zero()); + assert_eq!(One::one::().abs_sub(&Zero::zero()), One::one()); + assert_eq!(One::one::().abs_sub(&-One::one::()), + IntConvertible::from_int(2)); + } + #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { @@ -1959,4 +1979,3 @@ mod bigint_tests { assert!(-Zero::zero::() == Zero::zero::()); } } - diff --git a/src/libstd/num/complex.rs b/src/libstd/num/complex.rs index 02393b15cca0f..41d2b4a101cd5 100644 --- a/src/libstd/num/complex.rs +++ b/src/libstd/num/complex.rs @@ -102,9 +102,9 @@ impl Mul, Cmplx> for Cmplx { // (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d) // == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)] -impl Quot, Cmplx> for Cmplx { +impl Div, Cmplx> for Cmplx { #[inline] - fn quot(&self, other: &Cmplx) -> Cmplx { + fn div(&self, other: &Cmplx) -> Cmplx { let norm_sqr = other.norm_sqr(); Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr, (self.im*other.re - self.re*other.im) / norm_sqr) @@ -275,7 +275,7 @@ mod test { } } #[test] - fn test_quot() { + fn test_div() { assert_eq!(_neg1_1i / _0_1i, _1_1i); for all_consts.each |&c| { if c != Zero::zero() { diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index a7c170c1cd6da..9b92b7241b990 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -143,9 +143,9 @@ impl // (a/b) / (c/d) = (a*d)/(b*c) impl - Quot,Ratio> for Ratio { + Div,Ratio> for Ratio { #[inline] - fn quot(&self, rhs: &Ratio) -> Ratio { + fn div(&self, rhs: &Ratio) -> Ratio { Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer) } } @@ -395,7 +395,7 @@ mod test { } #[test] - fn test_quot() { + fn test_div() { assert_eq!(_1 / _1_2, _2); assert_eq!(_3_2 / _1_2, _1 + _2); assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2); @@ -424,7 +424,7 @@ mod test { } #[test] #[should_fail] - fn test_quot_0() { + fn test_div_0() { let _a = _1 / _0; } } diff --git a/src/libstd/par.rs b/src/libstd/par.rs index cfedbb66caac5..cf0eba9d30cea 100644 --- a/src/libstd/par.rs +++ b/src/libstd/par.rs @@ -73,10 +73,10 @@ fn map_slices( info!("num_tasks: %?", (num_tasks, futures.len())); assert!((num_tasks == futures.len())); - let r = do futures.map() |ys| { + let r = do vec::map_consume(futures) |ys| { + let mut ys = ys; ys.get() }; - assert!((r.len() == futures.len())); r } } diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 47af3576c9062..3c96a8e145d80 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -11,12 +11,8 @@ //! A priority queue implemented with a binary heap use core::old_iter::BaseIter; - -#[abi = "rust-intrinsic"] -extern "rust-intrinsic" mod rusti { - fn move_val_init(dst: &mut T, +src: T); - fn init() -> T; -} +use core::util::{replace, swap}; +use core::unstable::intrinsics::{init, move_val_init}; pub struct PriorityQueue { priv data: ~[T], @@ -26,7 +22,14 @@ impl BaseIter for PriorityQueue { /// Visit all values in the underlying vector. /// /// The values are **not** visited in order. + #[cfg(stage0)] fn each(&self, f: &fn(&T) -> bool) { self.data.each(f) } + /// Visit all values in the underlying vector. + /// + /// The values are **not** visited in order. + #[cfg(not(stage0))] + fn each(&self, f: &fn(&T) -> bool) -> bool { self.data.each(f) } + fn size_hint(&self) -> Option { self.data.size_hint() } } @@ -45,25 +48,9 @@ impl Mutable for PriorityQueue { pub impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty - #[cfg(stage0)] - fn top(&self) -> &'self T { &self.data[0] } - - /// Returns the greatest item in the queue - fails if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn top<'a>(&'a self) -> &'a T { &self.data[0] } /// Returns the greatest item in the queue - None if empty - #[cfg(stage0)] - fn maybe_top(&self) -> Option<&'self T> { - if self.is_empty() { None } else { Some(self.top()) } - } - - /// Returns the greatest item in the queue - None if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn maybe_top<'a>(&'a self) -> Option<&'a T> { if self.is_empty() { None } else { Some(self.top()) } } @@ -80,7 +67,10 @@ pub impl PriorityQueue { /// Pop the greatest item from the queue - fails if empty fn pop(&mut self) -> T { let mut item = self.data.pop(); - if !self.is_empty() { item <-> self.data[0]; self.siftdown(0); } + if !self.is_empty() { + swap(&mut item, &mut self.data[0]); + self.siftdown(0); + } item } @@ -99,7 +89,7 @@ pub impl PriorityQueue { /// Optimized version of a push followed by a pop fn push_pop(&mut self, mut item: T) -> T { if !self.is_empty() && self.data[0] > item { - item <-> self.data[0]; + swap(&mut item, &mut self.data[0]); self.siftdown(0); } item @@ -107,7 +97,7 @@ pub impl PriorityQueue { /// Optimized version of a pop followed by a push - fails if empty fn replace(&mut self, mut item: T) -> T { - item <-> self.data[0]; + swap(&mut item, &mut self.data[0]); self.siftdown(0); item } @@ -122,7 +112,7 @@ pub impl PriorityQueue { let mut end = q.len(); while end > 1 { end -= 1; - q.data[end] <-> q.data[0]; + vec::swap(q.data, 0, end); q.siftdown_range(0, end) } q.to_vec() @@ -144,33 +134,32 @@ pub impl PriorityQueue { // The implementations of siftup and siftdown use unsafe blocks in // order to move an element out of the vector (leaving behind a - // junk element), shift along the others and move it back into the + // zeroed element), shift along the others and move it back into the // vector over the junk element. This reduces the constant factor // compared to using swaps, which involves twice as many moves. priv fn siftup(&mut self, start: uint, mut pos: uint) { unsafe { - let new = *ptr::to_unsafe_ptr(&self.data[pos]); + let new = replace(&mut self.data[pos], init()); while pos > start { let parent = (pos - 1) >> 1; if new > self.data[parent] { - let mut x = rusti::init(); - x <-> self.data[parent]; - rusti::move_val_init(&mut self.data[pos], x); + let x = replace(&mut self.data[parent], init()); + move_val_init(&mut self.data[pos], x); pos = parent; loop } break } - rusti::move_val_init(&mut self.data[pos], new); + move_val_init(&mut self.data[pos], new); } } priv fn siftdown_range(&mut self, mut pos: uint, end: uint) { unsafe { let start = pos; - let new = *ptr::to_unsafe_ptr(&self.data[pos]); + let new = replace(&mut self.data[pos], init()); let mut child = 2 * pos + 1; while child < end { @@ -178,14 +167,13 @@ pub impl PriorityQueue { if right < end && !(self.data[child] > self.data[right]) { child = right; } - let mut x = rusti::init(); - x <-> self.data[child]; - rusti::move_val_init(&mut self.data[pos], x); + let x = replace(&mut self.data[child], init()); + move_val_init(&mut self.data[pos], x); pos = child; child = 2 * pos + 1; } - rusti::move_val_init(&mut self.data[pos], new); + move_val_init(&mut self.data[pos], new); self.siftup(start, pos); } } @@ -286,8 +274,8 @@ mod tests { } fn check_to_vec(data: ~[int]) { - let heap = from_vec(data); - assert!(merge_sort(heap.to_vec(), le) == merge_sort(data, le)); + let heap = from_vec(copy data); + assert!(merge_sort((copy heap).to_vec(), le) == merge_sort(data, le)); assert!(heap.to_sorted_vec() == merge_sort(data, le)); } diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs new file mode 100644 index 0000000000000..8cf2da3a1e832 --- /dev/null +++ b/src/libstd/rc.rs @@ -0,0 +1,308 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/** 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 `Owned` types in order to prevent cycles. + +*/ + +use core::libc::{c_void, size_t, malloc, free}; +use core::unstable::intrinsics; +use core::util; + +struct RcBox { + value: T, + count: uint +} + +/// Immutable reference counted pointer type +#[non_owned] +pub struct Rc { + priv ptr: *mut RcBox, +} + +pub impl Rc { + fn new(value: T) -> Rc { + unsafe { + let ptr = malloc(sys::size_of::>() as size_t) as *mut RcBox; + assert!(!ptr::is_null(ptr)); + intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1}); + Rc{ptr: ptr} + } + } + + #[inline(always)] + fn borrow<'r>(&'r self) -> &'r T { + unsafe { cast::copy_lifetime(self, &(*self.ptr).value) } + } +} + +#[unsafe_destructor] +#[cfg(not(stage0))] +impl Drop for Rc { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + util::replace_ptr(self.ptr, intrinsics::uninit()); + free(self.ptr as *c_void) + } + } + } +} + +#[unsafe_destructor] +#[cfg(stage0)] +impl Drop for Rc { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + util::replace_ptr(self.ptr, intrinsics::init()); + free(self.ptr as *c_void) + } + } + } +} + + +impl Clone for Rc { + #[inline] + fn clone(&self) -> Rc { + unsafe { + (*self.ptr).count += 1; + Rc{ptr: self.ptr} + } + } +} + +#[cfg(test)] +mod test_rc { + use super::*; + + #[test] + fn test_simple() { + let x = Rc::new(5); + assert_eq!(*x.borrow(), 5); + } + + #[test] + fn test_clone() { + let x = Rc::new(5); + let y = x.clone(); + assert_eq!(*x.borrow(), 5); + assert_eq!(*y.borrow(), 5); + } + + #[test] + fn test_destructor() { + let x = Rc::new(~5); + assert_eq!(**x.borrow(), 5); + } +} + +#[abi = "rust-intrinsic"] +extern "rust-intrinsic" { + fn init() -> T; + #[cfg(not(stage0))] + fn uninit() -> T; +} + +#[deriving(Eq)] +enum Borrow { + Mutable, + Immutable, + Nothing +} + +struct RcMutBox { + value: T, + count: uint, + borrow: Borrow +} + +/// Mutable reference counted pointer type +#[non_owned] +#[mutable] +pub struct RcMut { + priv ptr: *mut RcMutBox, +} + +pub impl RcMut { + fn new(value: T) -> RcMut { + unsafe { + let ptr = malloc(sys::size_of::>() as size_t) as *mut RcMutBox; + assert!(!ptr::is_null(ptr)); + intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing}); + RcMut{ptr: ptr} + } + } + + /// Fails if there is already a mutable borrow of the box + #[inline] + fn with_borrow(&self, f: &fn(&T)) { + unsafe { + assert!((*self.ptr).borrow != Mutable); + let previous = (*self.ptr).borrow; + (*self.ptr).borrow = Immutable; + f(&(*self.ptr).value); + (*self.ptr).borrow = previous; + } + } + + /// Fails if there is already a mutable or immutable borrow of the box + #[inline] + fn with_mut_borrow(&self, f: &fn(&mut T)) { + unsafe { + assert!((*self.ptr).borrow == Nothing); + (*self.ptr).borrow = Mutable; + f(&mut (*self.ptr).value); + (*self.ptr).borrow = Nothing; + } + } +} + +#[unsafe_destructor] +#[cfg(not(stage0))] +impl Drop for RcMut { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + util::replace_ptr(self.ptr, uninit()); + free(self.ptr as *c_void) + } + } + } +} + +#[unsafe_destructor] +#[cfg(stage0)] +impl Drop for RcMut { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + util::replace_ptr(self.ptr, init()); + free(self.ptr as *c_void) + } + } + } +} + +impl Clone for RcMut { + #[inline] + fn clone(&self) -> RcMut { + unsafe { + (*self.ptr).count += 1; + RcMut{ptr: self.ptr} + } + } +} + +#[cfg(test)] +mod test_rc_mut { + use super::*; + + #[test] + fn borrow_many() { + let x = RcMut::new(5); + let y = x.clone(); + + do x.with_borrow |a| { + assert_eq!(*a, 5); + do y.with_borrow |b| { + assert_eq!(*b, 5); + do x.with_borrow |c| { + assert_eq!(*c, 5); + } + } + } + } + + #[test] + fn modify() { + let x = RcMut::new(5); + let y = x.clone(); + + do y.with_mut_borrow |a| { + assert_eq!(*a, 5); + *a = 6; + } + + do x.with_borrow |a| { + assert_eq!(*a, 6); + } + } + + #[test] + fn release_immutable() { + let x = RcMut::new(5); + do x.with_borrow |_| {} + do x.with_mut_borrow |_| {} + } + + #[test] + fn release_mutable() { + let x = RcMut::new(5); + do x.with_mut_borrow |_| {} + do x.with_borrow |_| {} + } + + #[test] + #[should_fail] + fn frozen() { + let x = RcMut::new(5); + let y = x.clone(); + + do x.with_borrow |_| { + do y.with_mut_borrow |_| { + } + } + } + + #[test] + #[should_fail] + fn mutable_dupe() { + let x = RcMut::new(5); + let y = x.clone(); + + do x.with_mut_borrow |_| { + do y.with_mut_borrow |_| { + } + } + } + + #[test] + #[should_fail] + fn mutable_freeze() { + let x = RcMut::new(5); + let y = x.clone(); + + do x.with_mut_borrow |_| { + do y.with_borrow |_| { + } + } + } + + #[test] + #[should_fail] + fn restore_freeze() { + let x = RcMut::new(5); + let y = x.clone(); + + do x.with_borrow |_| { + do x.with_borrow |_| {} + do y.with_mut_borrow |_| {} + } + } +} diff --git a/src/libstd/rl.rs b/src/libstd/rl.rs index b2407be0b991e..81152430e784b 100644 --- a/src/libstd/rl.rs +++ b/src/libstd/rl.rs @@ -69,11 +69,11 @@ fn complete_key(_v: @CompletionCb) {} /// Bind to the main completion callback pub unsafe fn complete(cb: CompletionCb) { - task::local_data::local_data_set(complete_key, @(cb)); + local_data::local_data_set(complete_key, @(cb)); extern fn callback(line: *c_char, completions: *()) { unsafe { - let cb = *task::local_data::local_data_get(complete_key) + let cb = *local_data::local_data_get(complete_key) .get(); do cb(str::raw::from_c_str(line)) |suggestion| { diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs index 1292d2a858559..2fa12809db6f8 100644 --- a/src/libstd/rope.rs +++ b/src/libstd/rope.rs @@ -565,7 +565,7 @@ pub mod node { * * # Fields * - * * byte_offset = The number of bytes skippen in `content` + * * byte_offset = The number of bytes skipped in `content` * * byte_len - The number of bytes of `content` to use * * char_len - The number of chars in the leaf. * * content - Contents of the leaf. @@ -822,7 +822,7 @@ pub mod node { None => break, Some(x) => { //FIXME (#2744): Replace with memcpy or something similar - let local_buf: ~[u8] = cast::transmute(*x.content); + let local_buf: ~[u8] = cast::transmute(copy *x.content); let mut i = x.byte_offset; while i < x.byte_len { buf[offset] = local_buf[i]; @@ -1256,22 +1256,24 @@ mod tests { match (r) { node::Empty => return ~"", node::Content(x) => { - let str = @mut ~""; - fn aux(str: @mut ~str, node: @node::Node) { + let mut str = ~""; + fn aux(str: &mut ~str, node: @node::Node) { match (*node) { - node::Leaf(x) => { - *str += str::slice( - *x.content, x.byte_offset, - x.byte_offset + x.byte_len).to_owned(); - } - node::Concat(ref x) => { - aux(str, x.left); - aux(str, x.right); - } + node::Leaf(x) => { + str::push_str( + str, + str::slice( + *x.content, x.byte_offset, + x.byte_offset + x.byte_len)); + } + node::Concat(ref x) => { + aux(str, x.left); + aux(str, x.right); + } } } - aux(str, x); - return *str + aux(&mut str, x); + return str } } } @@ -1297,12 +1299,12 @@ mod tests { let buf = @ mut ~"1234567890"; let mut i = 0; while i < 10 { - let a = *buf; - let b = *buf; + let a = copy *buf; + let b = copy *buf; *buf = a + b; i+=1; } - let sample = @*buf; + let sample = @copy *buf; let r = of_str(sample); assert!(char_len(r) == str::char_len(*sample)); assert!(rope_to_string(r) == *sample); @@ -1333,12 +1335,12 @@ mod tests { let buf = @ mut ~"1234567890"; let mut i = 0; while i < 10 { - let a = *buf; - let b = *buf; + let a = copy *buf; + let b = copy *buf; *buf = a + b; i+=1; } - let sample = @*buf; + let sample = @copy *buf; let r = of_str(sample); let mut len = 0u; @@ -1356,15 +1358,15 @@ mod tests { #[test] fn bal1() { let init = @~"1234567890"; - let buf = @mut * init; + let buf = @mut copy *init; let mut i = 0; while i < 8 { - let a = *buf; - let b = *buf; + let a = copy *buf; + let b = copy *buf; *buf = a + b; i+=1; } - let sample = @*buf; + let sample = @copy *buf; let r1 = of_str(sample); let mut r2 = of_str(init); i = 0; diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 1ad581ba993e4..a5d2604b6f6db 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -20,394 +20,461 @@ use core::hashmap::{HashMap, HashSet}; use core::trie::{TrieMap, TrieSet}; use deque::Deque; use dlist::DList; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use treemap::{TreeMap, TreeSet}; pub trait Encoder { // Primitive types: - fn emit_nil(&self); - fn emit_uint(&self, v: uint); - fn emit_u64(&self, v: u64); - fn emit_u32(&self, v: u32); - fn emit_u16(&self, v: u16); - fn emit_u8(&self, v: u8); - fn emit_int(&self, v: int); - fn emit_i64(&self, v: i64); - fn emit_i32(&self, v: i32); - fn emit_i16(&self, v: i16); - fn emit_i8(&self, v: i8); - fn emit_bool(&self, v: bool); - fn emit_float(&self, v: float); - fn emit_f64(&self, v: f64); - fn emit_f32(&self, v: f32); - fn emit_char(&self, v: char); - fn emit_str(&self, v: &str); + fn emit_nil(&mut self); + fn emit_uint(&mut self, v: uint); + fn emit_u64(&mut self, v: u64); + fn emit_u32(&mut self, v: u32); + fn emit_u16(&mut self, v: u16); + fn emit_u8(&mut self, v: u8); + fn emit_int(&mut self, v: int); + fn emit_i64(&mut self, v: i64); + fn emit_i32(&mut self, v: i32); + fn emit_i16(&mut self, v: i16); + fn emit_i8(&mut self, v: i8); + fn emit_bool(&mut self, v: bool); + fn emit_float(&mut self, v: float); + fn emit_f64(&mut self, v: f64); + fn emit_f32(&mut self, v: f32); + fn emit_char(&mut self, v: char); + fn emit_str(&mut self, v: &str); // Compound types: - fn emit_enum(&self, name: &str, f: &fn()); - - fn emit_enum_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); - fn emit_enum_variant_arg(&self, a_idx: uint, f: &fn()); - - fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); - fn emit_enum_struct_variant_field(&self, f_name: &str, f_idx: uint, f: &fn()); - - fn emit_struct(&self, name: &str, len: uint, f: &fn()); - #[cfg(stage0)] - fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); - - fn emit_tuple(&self, len: uint, f: &fn()); - fn emit_tuple_arg(&self, idx: uint, f: &fn()); - - fn emit_tuple_struct(&self, name: &str, len: uint, f: &fn()); - fn emit_tuple_struct_arg(&self, f_idx: uint, f: &fn()); + fn emit_enum(&mut self, name: &str, f: &fn(&mut Self)); + + fn emit_enum_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn(&mut Self)); + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: &fn(&mut Self)); + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn(&mut Self)); + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self)); + + fn emit_struct(&mut self, name: &str, len: uint, f: &fn(&mut Self)); + fn emit_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self)); + + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Self)); + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Self)); + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: &fn(&mut Self)); + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: &fn(&mut Self)); // Specialized types: - fn emit_option(&self, f: &fn()); - fn emit_option_none(&self); - fn emit_option_some(&self, f: &fn()); + fn emit_option(&mut self, f: &fn(&mut Self)); + fn emit_option_none(&mut self); + fn emit_option_some(&mut self, f: &fn(&mut Self)); - fn emit_seq(&self, len: uint, f: &fn()); - fn emit_seq_elt(&self, idx: uint, f: &fn()); + fn emit_seq(&mut self, len: uint, f: &fn(this: &mut Self)); + fn emit_seq_elt(&mut self, idx: uint, f: &fn(this: &mut Self)); - fn emit_map(&self, len: uint, f: &fn()); - fn emit_map_elt_key(&self, idx: uint, f: &fn()); - fn emit_map_elt_val(&self, idx: uint, f: &fn()); + fn emit_map(&mut self, len: uint, f: &fn(&mut Self)); + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Self)); + fn emit_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self)); } pub trait Decoder { // Primitive types: - fn read_nil(&self) -> (); - fn read_uint(&self) -> uint; - fn read_u64(&self) -> u64; - fn read_u32(&self) -> u32; - fn read_u16(&self) -> u16; - fn read_u8(&self) -> u8; - fn read_int(&self) -> int; - fn read_i64(&self) -> i64; - fn read_i32(&self) -> i32; - fn read_i16(&self) -> i16; - fn read_i8(&self) -> i8; - fn read_bool(&self) -> bool; - fn read_f64(&self) -> f64; - fn read_f32(&self) -> f32; - fn read_float(&self) -> float; - fn read_char(&self) -> char; - fn read_str(&self) -> ~str; + fn read_nil(&mut self) -> (); + fn read_uint(&mut self) -> uint; + fn read_u64(&mut self) -> u64; + fn read_u32(&mut self) -> u32; + fn read_u16(&mut self) -> u16; + fn read_u8(&mut self) -> u8; + fn read_int(&mut self) -> int; + fn read_i64(&mut self) -> i64; + fn read_i32(&mut self) -> i32; + fn read_i16(&mut self) -> i16; + fn read_i8(&mut self) -> i8; + fn read_bool(&mut self) -> bool; + fn read_f64(&mut self) -> f64; + fn read_f32(&mut self) -> f32; + fn read_float(&mut self) -> float; + fn read_char(&mut self) -> char; + fn read_str(&mut self) -> ~str; // Compound types: - fn read_enum(&self, name: &str, f: &fn() -> T) -> T; - - fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; - fn read_enum_variant_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - - fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; - fn read_enum_struct_variant_field(&self, &f_name: &str, f_idx: uint, f: &fn() -> T) -> T; - - fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; - #[cfg(stage0)] - fn read_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; - - fn read_tuple(&self, f: &fn(uint) -> T) -> T; - fn read_tuple_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - - fn read_tuple_struct(&self, s_name: &str, f: &fn(uint) -> T) -> T; - fn read_tuple_struct_arg(&self, a_idx: uint, f: &fn() -> T) -> T; + fn read_enum(&mut self, name: &str, f: &fn(&mut Self) -> T) -> T; + + fn read_enum_variant(&mut self, + names: &[&str], + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_enum_variant_arg(&mut self, + a_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_enum_struct_variant(&mut self, + names: &[&str], + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_struct(&mut self, + s_name: &str, + len: uint, + f: &fn(&mut Self) -> T) + -> T; + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_tuple(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_tuple_arg(&mut self, a_idx: uint, f: &fn(&mut Self) -> T) -> T; + + fn read_tuple_struct(&mut self, + s_name: &str, + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_tuple_struct_arg(&mut self, + a_idx: uint, + f: &fn(&mut Self) -> T) + -> T; // Specialized types: - fn read_option(&self, f: &fn(bool) -> T) -> T; + fn read_option(&mut self, f: &fn(&mut Self, bool) -> T) -> T; - fn read_seq(&self, f: &fn(uint) -> T) -> T; - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; + fn read_seq(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; - fn read_map(&self, f: &fn(uint) -> T) -> T; - fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T; - fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T; + fn read_map(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_map_elt_key(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; + fn read_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; } pub trait Encodable { - fn encode(&self, s: &S); + fn encode(&self, s: &mut S); } pub trait Decodable { - fn decode(d: &D) -> Self; + fn decode(d: &mut D) -> Self; } impl Encodable for uint { - fn encode(&self, s: &S) { s.emit_uint(*self) } + fn encode(&self, s: &mut S) { + s.emit_uint(*self) + } } impl Decodable for uint { - fn decode(d: &D) -> uint { + fn decode(d: &mut D) -> uint { d.read_uint() } } impl Encodable for u8 { - fn encode(&self, s: &S) { s.emit_u8(*self) } + fn encode(&self, s: &mut S) { + s.emit_u8(*self) + } } impl Decodable for u8 { - fn decode(d: &D) -> u8 { + fn decode(d: &mut D) -> u8 { d.read_u8() } } impl Encodable for u16 { - fn encode(&self, s: &S) { s.emit_u16(*self) } + fn encode(&self, s: &mut S) { + s.emit_u16(*self) + } } impl Decodable for u16 { - fn decode(d: &D) -> u16 { + fn decode(d: &mut D) -> u16 { d.read_u16() } } impl Encodable for u32 { - fn encode(&self, s: &S) { s.emit_u32(*self) } + fn encode(&self, s: &mut S) { + s.emit_u32(*self) + } } impl Decodable for u32 { - fn decode(d: &D) -> u32 { + fn decode(d: &mut D) -> u32 { d.read_u32() } } impl Encodable for u64 { - fn encode(&self, s: &S) { s.emit_u64(*self) } + fn encode(&self, s: &mut S) { + s.emit_u64(*self) + } } impl Decodable for u64 { - fn decode(d: &D) -> u64 { + fn decode(d: &mut D) -> u64 { d.read_u64() } } impl Encodable for int { - fn encode(&self, s: &S) { s.emit_int(*self) } + fn encode(&self, s: &mut S) { + s.emit_int(*self) + } } impl Decodable for int { - fn decode(d: &D) -> int { + fn decode(d: &mut D) -> int { d.read_int() } } impl Encodable for i8 { - fn encode(&self, s: &S) { s.emit_i8(*self) } + fn encode(&self, s: &mut S) { + s.emit_i8(*self) + } } impl Decodable for i8 { - fn decode(d: &D) -> i8 { + fn decode(d: &mut D) -> i8 { d.read_i8() } } impl Encodable for i16 { - fn encode(&self, s: &S) { s.emit_i16(*self) } + fn encode(&self, s: &mut S) { + s.emit_i16(*self) + } } impl Decodable for i16 { - fn decode(d: &D) -> i16 { + fn decode(d: &mut D) -> i16 { d.read_i16() } } impl Encodable for i32 { - fn encode(&self, s: &S) { s.emit_i32(*self) } + fn encode(&self, s: &mut S) { + s.emit_i32(*self) + } } impl Decodable for i32 { - fn decode(d: &D) -> i32 { + fn decode(d: &mut D) -> i32 { d.read_i32() } } impl Encodable for i64 { - fn encode(&self, s: &S) { s.emit_i64(*self) } + fn encode(&self, s: &mut S) { + s.emit_i64(*self) + } } impl Decodable for i64 { - fn decode(d: &D) -> i64 { + fn decode(d: &mut D) -> i64 { d.read_i64() } } impl<'self, S:Encoder> Encodable for &'self str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } } impl Encodable for ~str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } } impl Decodable for ~str { - fn decode(d: &D) -> ~str { + fn decode(d: &mut D) -> ~str { d.read_str() } } impl Encodable for @str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } } impl Decodable for @str { - fn decode(d: &D) -> @str { d.read_str().to_managed() } + fn decode(d: &mut D) -> @str { + d.read_str().to_managed() + } } impl Encodable for float { - fn encode(&self, s: &S) { s.emit_float(*self) } + fn encode(&self, s: &mut S) { + s.emit_float(*self) + } } impl Decodable for float { - fn decode(d: &D) -> float { + fn decode(d: &mut D) -> float { d.read_float() } } impl Encodable for f32 { - fn encode(&self, s: &S) { s.emit_f32(*self) } + fn encode(&self, s: &mut S) { + s.emit_f32(*self) + } } impl Decodable for f32 { - fn decode(d: &D) -> f32 { - d.read_f32() } + fn decode(d: &mut D) -> f32 { + d.read_f32() + } } impl Encodable for f64 { - fn encode(&self, s: &S) { s.emit_f64(*self) } + fn encode(&self, s: &mut S) { + s.emit_f64(*self) + } } impl Decodable for f64 { - fn decode(d: &D) -> f64 { + fn decode(d: &mut D) -> f64 { d.read_f64() } } impl Encodable for bool { - fn encode(&self, s: &S) { s.emit_bool(*self) } + fn encode(&self, s: &mut S) { + s.emit_bool(*self) + } } impl Decodable for bool { - fn decode(d: &D) -> bool { + fn decode(d: &mut D) -> bool { d.read_bool() } } impl Encodable for () { - fn encode(&self, s: &S) { s.emit_nil() } + fn encode(&self, s: &mut S) { + s.emit_nil() + } } impl Decodable for () { - fn decode(d: &D) -> () { + fn decode(d: &mut D) -> () { d.read_nil() } } impl<'self, S:Encoder,T:Encodable> Encodable for &'self T { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { (**self).encode(s) } } impl> Encodable for ~T { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { (**self).encode(s) } } impl> Decodable for ~T { - fn decode(d: &D) -> ~T { + fn decode(d: &mut D) -> ~T { ~Decodable::decode(d) } } impl> Encodable for @T { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { (**self).encode(s) } } impl> Decodable for @T { - fn decode(d: &D) -> @T { + fn decode(d: &mut D) -> @T { @Decodable::decode(d) } } impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) + s.emit_seq_elt(i, |s| e.encode(s)) } } } } impl> Encodable for ~[T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) + s.emit_seq_elt(i, |s| e.encode(s)) } } } } impl> Decodable for ~[T] { - fn decode(d: &D) -> ~[T] { - do d.read_seq |len| { + fn decode(d: &mut D) -> ~[T] { + do d.read_seq |d, len| { do vec::from_fn(len) |i| { - d.read_seq_elt(i, || Decodable::decode(d)) + d.read_seq_elt(i, |d| Decodable::decode(d)) } } } } impl> Encodable for @[T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) + s.emit_seq_elt(i, |s| e.encode(s)) } } } } impl> Decodable for @[T] { - fn decode(d: &D) -> @[T] { - do d.read_seq |len| { + fn decode(d: &mut D) -> @[T] { + do d.read_seq |d, len| { do at_vec::from_fn(len) |i| { - d.read_seq_elt(i, || Decodable::decode(d)) + d.read_seq_elt(i, |d| Decodable::decode(d)) } } } } impl> Encodable for Option { - fn encode(&self, s: &S) { - do s.emit_option { + fn encode(&self, s: &mut S) { + do s.emit_option |s| { match *self { None => s.emit_option_none(), - Some(ref v) => s.emit_option_some(|| v.encode(s)), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), } } } } impl> Decodable for Option { - fn decode(d: &D) -> Option { - do d.read_option |b| { + fn decode(d: &mut D) -> Option { + do d.read_option |d, b| { if b { Some(Decodable::decode(d)) } else { @@ -418,12 +485,12 @@ impl> Decodable for Option { } impl,T1:Encodable> Encodable for (T0, T1) { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { match *self { (ref t0, ref t1) => { - do s.emit_seq(2) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); + do s.emit_seq(2) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); } } } @@ -431,12 +498,12 @@ impl,T1:Encodable> Encodable for (T0, T1) { } impl,T1:Decodable> Decodable for (T0, T1) { - fn decode(d: &D) -> (T0, T1) { - do d.read_seq |len| { + fn decode(d: &mut D) -> (T0, T1) { + do d.read_seq |d, len| { assert!(len == 2); ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)) + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)) ) } } @@ -448,13 +515,13 @@ impl< T1: Encodable, T2: Encodable > Encodable for (T0, T1, T2) { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { match *self { (ref t0, ref t1, ref t2) => { - do s.emit_seq(3) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); + do s.emit_seq(3) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); } } } @@ -467,13 +534,13 @@ impl< T1: Decodable, T2: Decodable > Decodable for (T0, T1, T2) { - fn decode(d: &D) -> (T0, T1, T2) { - do d.read_seq |len| { + fn decode(d: &mut D) -> (T0, T1, T2) { + do d.read_seq |d, len| { assert!(len == 3); ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)) + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)) ) } } @@ -486,14 +553,14 @@ impl< T2: Encodable, T3: Encodable > Encodable for (T0, T1, T2, T3) { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { match *self { (ref t0, ref t1, ref t2, ref t3) => { - do s.emit_seq(4) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); - s.emit_seq_elt(3, || t3.encode(s)); + do s.emit_seq(4) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); } } } @@ -507,14 +574,14 @@ impl< T2: Decodable, T3: Decodable > Decodable for (T0, T1, T2, T3) { - fn decode(d: &D) -> (T0, T1, T2, T3) { - do d.read_seq |len| { + fn decode(d: &mut D) -> (T0, T1, T2, T3) { + do d.read_seq |d, len| { assert!(len == 4); ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)), - d.read_seq_elt(3, || Decodable::decode(d)) + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)) ) } } @@ -528,15 +595,15 @@ impl< T3: Encodable, T4: Encodable > Encodable for (T0, T1, T2, T3, T4) { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { match *self { (ref t0, ref t1, ref t2, ref t3, ref t4) => { - do s.emit_seq(5) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); - s.emit_seq_elt(3, || t3.encode(s)); - s.emit_seq_elt(4, || t4.encode(s)); + do s.emit_seq(5) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); + s.emit_seq_elt(4, |s| t4.encode(s)); } } } @@ -551,16 +618,15 @@ impl< T3: Decodable, T4: Decodable > Decodable for (T0, T1, T2, T3, T4) { - fn decode(d: &D) - -> (T0, T1, T2, T3, T4) { - do d.read_seq |len| { + fn decode(d: &mut D) -> (T0, T1, T2, T3, T4) { + do d.read_seq |d, len| { assert!(len == 5); ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)), - d.read_seq_elt(3, || Decodable::decode(d)), - d.read_seq_elt(4, || Decodable::decode(d)) + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)), + d.read_seq_elt(4, |d| Decodable::decode(d)) ) } } @@ -570,11 +636,11 @@ impl< S: Encoder, T: Encodable + Copy > Encodable for @mut DList { - fn encode(&self, s: &S) { - do s.emit_seq(self.size) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.size) |s| { let mut i = 0; for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } } @@ -582,11 +648,11 @@ impl< } impl> Decodable for @mut DList { - fn decode(d: &D) -> @mut DList { + fn decode(d: &mut D) -> @mut DList { let list = DList(); - do d.read_seq |len| { + do d.read_seq |d, len| { for uint::range(0, len) |i| { - list.push(d.read_seq_elt(i, || Decodable::decode(d))); + list.push(d.read_seq_elt(i, |d| Decodable::decode(d))); } } list @@ -597,21 +663,21 @@ impl< S: Encoder, T: Encodable > Encodable for Deque { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); } } } } impl> Decodable for Deque { - fn decode(d: &D) -> Deque { + fn decode(d: &mut D) -> Deque { let mut deque = Deque::new(); - do d.read_seq |len| { + do d.read_seq |d, len| { for uint::range(0, len) |i| { - deque.add_back(d.read_seq_elt(i, || Decodable::decode(d))); + deque.add_back(d.read_seq_elt(i, |d| Decodable::decode(d))); } } deque @@ -623,12 +689,12 @@ impl< K: Encodable + Hash + IterBytes + Eq, V: Encodable > Encodable for HashMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { let mut i = 0; for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; } } @@ -640,12 +706,12 @@ impl< K: Decodable + Hash + IterBytes + Eq, V: Decodable > Decodable for HashMap { - fn decode(d: &D) -> HashMap { - do d.read_map |len| { + fn decode(d: &mut D) -> HashMap { + do d.read_map |d, len| { let mut map = HashMap::with_capacity(len); for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); map.insert(key, val); } map @@ -657,11 +723,11 @@ impl< S: Encoder, T: Encodable + Hash + IterBytes + Eq > Encodable for HashSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { let mut i = 0; for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } } @@ -672,11 +738,11 @@ impl< D: Decoder, T: Decodable + Hash + IterBytes + Eq > Decodable for HashSet { - fn decode(d: &D) -> HashSet { - do d.read_seq |len| { + fn decode(d: &mut D) -> HashSet { + do d.read_seq |d, len| { let mut set = HashSet::with_capacity(len); for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); } set } @@ -687,12 +753,12 @@ impl< E: Encoder, V: Encodable > Encodable for TrieMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { let mut i = 0; for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; } } @@ -703,12 +769,12 @@ impl< D: Decoder, V: Decodable > Decodable for TrieMap { - fn decode(d: &D) -> TrieMap { - do d.read_map |len| { + fn decode(d: &mut D) -> TrieMap { + do d.read_map |d, len| { let mut map = TrieMap::new(); for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); map.insert(key, val); } map @@ -717,11 +783,11 @@ impl< } impl Encodable for TrieSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { let mut i = 0; for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } } @@ -729,51 +795,45 @@ impl Encodable for TrieSet { } impl Decodable for TrieSet { - fn decode(d: &D) -> TrieSet { - do d.read_seq |len| { + fn decode(d: &mut D) -> TrieSet { + do d.read_seq |d, len| { let mut set = TrieSet::new(); for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); } set } } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< E: Encoder, K: Encodable + Eq + TotalOrd, V: Encodable + Eq > Encodable for TreeMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { let mut i = 0; for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; } } } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< D: Decoder, K: Decodable + Eq + TotalOrd, V: Decodable + Eq > Decodable for TreeMap { - fn decode(d: &D) -> TreeMap { - do d.read_map |len| { + fn decode(d: &mut D) -> TreeMap { + do d.read_map |d, len| { let mut map = TreeMap::new(); for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); map.insert(key, val); } map @@ -781,36 +841,30 @@ impl< } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< S: Encoder, T: Encodable + Eq + TotalOrd > Encodable for TreeSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { let mut i = 0; for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } } } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< D: Decoder, T: Decodable + Eq + TotalOrd > Decodable for TreeSet { - fn decode(d: &D) -> TreeSet { - do d.read_seq |len| { + fn decode(d: &mut D) -> TreeSet { + do d.read_seq |d, len| { let mut set = TreeSet::new(); for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); } set } @@ -823,15 +877,15 @@ impl< // In some cases, these should eventually be coded as traits. pub trait EncoderHelpers { - fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)); + fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut Self, v: &T)); } impl EncoderHelpers for S { - fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)) { - do self.emit_seq(v.len()) { + fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut S, &T)) { + do self.emit_seq(v.len()) |this| { for v.eachi |i, e| { - do self.emit_seq_elt(i) { - f(e) + do this.emit_seq_elt(i) |this| { + f(this, e) } } } @@ -839,14 +893,14 @@ impl EncoderHelpers for S { } pub trait DecoderHelpers { - fn read_to_vec(&self, f: &fn() -> T) -> ~[T]; + fn read_to_vec(&mut self, f: &fn(&mut Self) -> T) -> ~[T]; } impl DecoderHelpers for D { - fn read_to_vec(&self, f: &fn() -> T) -> ~[T] { - do self.read_seq |len| { + fn read_to_vec(&mut self, f: &fn(&mut D) -> T) -> ~[T] { + do self.read_seq |this, len| { do vec::from_fn(len) |i| { - self.read_seq_elt(i, || f()) + this.read_seq_elt(i, |this| f(this)) } } } diff --git a/src/libstd/sha1.rs b/src/libstd/sha1.rs index 7371250b38a91..4b410ebfdd2fc 100644 --- a/src/libstd/sha1.rs +++ b/src/libstd/sha1.rs @@ -177,7 +177,7 @@ pub fn sha1() -> @Sha1 { let b = (hpart >> 16u32 & 0xFFu32) as u8; let c = (hpart >> 8u32 & 0xFFu32) as u8; let d = (hpart & 0xFFu32) as u8; - rs = vec::append(rs, ~[a, b, c, d]); + rs = vec::append(copy rs, ~[a, b, c, d]); } return rs; } @@ -250,7 +250,7 @@ pub fn sha1() -> @Sha1 { fn result_str(&mut self) -> ~str { let rr = mk_result(self); let mut s = ~""; - for vec::each(rr) |b| { + for rr.each |b| { let hex = uint::to_str_radix(*b as uint, 16u); if hex.len() == 1 { s += "0"; @@ -378,10 +378,10 @@ mod tests { // Test that it works when accepting the message all at once let mut sh = sha1::sha1(); - for vec::each(tests) |t| { + for tests.each |t| { sh.input_str(t.input); let out = sh.result(); - check_vec_eq(t.output, out); + check_vec_eq(copy t.output, out); let out_str = sh.result_str(); assert!((out_str.len() == 40)); @@ -392,7 +392,7 @@ mod tests { // Test that it works when accepting the message in pieces - for vec::each(tests) |t| { + for tests.each |t| { let len = str::len(t.input); let mut left = len; while left > 0u { @@ -402,7 +402,7 @@ mod tests { left = left - take; } let out = sh.result(); - check_vec_eq(t.output, out); + check_vec_eq(copy t.output, out); let out_str = sh.result_str(); assert!((out_str.len() == 40)); @@ -412,11 +412,3 @@ mod tests { } } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index fb17d4e50900c..afc1d0fe65fcb 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -16,6 +16,7 @@ use core::container::{Container, Mutable, Map, Set}; use core::old_iter::{BaseIter}; use core::option::{Some, None}; +use core::util::replace; pub struct SmallIntMap { priv v: ~[Option], @@ -51,7 +52,7 @@ impl Map for SmallIntMap { /// Visit all key-value pairs in order #[cfg(stage0)] - fn each(&self, it: &fn(&uint, &'self V) -> bool) { + fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) { for uint::range(0, self.v.len()) |i| { match self.v[i] { Some(ref elt) => if !it(&i, elt) { break }, @@ -61,64 +62,63 @@ impl Map for SmallIntMap { } /// Visit all key-value pairs in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) { + #[cfg(not(stage0))] + fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { for uint::range(0, self.v.len()) |i| { match self.v[i] { - Some(ref elt) => if !it(&i, elt) { break }, + Some(ref elt) => if !it(&i, elt) { return false; }, None => () } } + return true; } /// Visit all keys in order + #[cfg(stage0)] fn each_key(&self, blk: &fn(key: &uint) -> bool) { self.each(|k, _| blk(k)) } + #[cfg(not(stage0))] + /// Visit all keys in order + fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { + self.each(|k, _| blk(k)) + } /// Visit all values in order #[cfg(stage0)] - fn each_value(&self, blk: &fn(value: &V) -> bool) { + fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) { self.each(|_, v| blk(v)) } /// Visit all values in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) { + #[cfg(not(stage0))] + fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { self.each(|_, v| blk(v)) } /// Iterate over the map and mutate the contained values + #[cfg(stage0)] fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) { for uint::range(0, self.v.len()) |i| { match self.v[i] { - Some(ref mut elt) => if !it(&i, elt) { break }, + Some(ref mut elt) => if !it(&i, elt) { return; }, None => () } } } - - /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, key: &uint) -> Option<&'self V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref value) => Some(value), - None => None + /// Iterate over the map and mutate the contained values + #[cfg(not(stage0))] + fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { + for uint::range(0, self.v.len()) |i| { + match self.v[i] { + Some(ref mut elt) => if !it(&i, elt) { return false; }, + None => () } - } else { - None } + return true; } /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { if *key < self.v.len() { match self.v[*key] { @@ -131,22 +131,6 @@ impl Map for SmallIntMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref mut value) => Some(value), - None => None - } - } else { - None - } - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut V> { if *key < self.v.len() { match self.v[*key] { @@ -174,12 +158,27 @@ impl Map for SmallIntMap { /// Remove a key-value pair from the map. Return true if the key /// was present in the map, otherwise false. fn remove(&mut self, key: &uint) -> bool { + self.pop(key).is_some() + } + + /// Insert a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise None is returned. + fn swap(&mut self, key: uint, value: V) -> Option { + match self.find_mut(&key) { + Some(loc) => { return Some(replace(loc, value)); } + None => () + } + self.insert(key, value); + return None; + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + fn pop(&mut self, key: &uint) -> Option { if *key >= self.v.len() { - return false; + return None; } - let removed = self.v[*key].is_some(); - self.v[*key] = None; - removed + replace(&mut self.v[*key], None) } } @@ -189,7 +188,7 @@ pub impl SmallIntMap { /// Visit all key-value pairs in reverse order #[cfg(stage0)] - fn each_reverse(&self, it: &fn(uint, &'self V) -> bool) { + fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) { for uint::range_rev(self.v.len(), 0) |i| { match self.v[i - 1] { Some(ref elt) => if !it(i - 1, elt) { break }, @@ -199,26 +198,17 @@ pub impl SmallIntMap { } /// Visit all key-value pairs in reverse order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) { + #[cfg(not(stage0))] + fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { for uint::range_rev(self.v.len(), 0) |i| { match self.v[i - 1] { - Some(ref elt) => if !it(i - 1, elt) { break }, + Some(ref elt) => if !it(i - 1, elt) { return false; }, None => () } } + return true; } - #[cfg(stage0)] - fn get(&self, key: &uint) -> &'self V { - self.find(key).expect("key not present") - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } @@ -314,4 +304,20 @@ mod tests { // sadly, no sevens were counted assert!(map.find(&7).is_none()); } + + #[test] + fn test_swap() { + let mut m = SmallIntMap::new(); + assert!(m.swap(1, 2) == None); + assert!(m.swap(1, 3) == Some(2)); + assert!(m.swap(1, 4) == Some(3)); + } + + #[test] + fn test_pop() { + let mut m = SmallIntMap::new(); + m.insert(1, 2); + assert!(m.pop(&1) == Some(2)); + assert!(m.pop(&1) == None); + } } diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 3e6011e80df81..876eb716a3833 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -11,9 +11,9 @@ //! Sorting methods use core::cmp::{Eq, Ord}; -use core::util; use core::vec::len; use core::vec; +use core::util::swap; type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; @@ -23,12 +23,12 @@ type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; * Has worst case O(n log n) performance, best case O(n), but * is not space efficient. This is a stable sort. */ -pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { +pub fn merge_sort(v: &[T], le: Le) -> ~[T] { type Slice = (uint, uint); return merge_sort_(v, (0u, len(v)), le); - fn merge_sort_(v: &const [T], slice: Slice, le: Le) + fn merge_sort_(v: &[T], slice: Slice, le: Le) -> ~[T] { let begin = slice.first(); let end = slice.second(); @@ -61,21 +61,39 @@ pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { } } +#[cfg(stage0)] fn part(arr: &mut [T], left: uint, right: uint, pivot: uint, compare_func: Le) -> uint { - arr[pivot] <-> arr[right]; + swap(&mut arr[pivot], &mut arr[right]); let mut storage_index: uint = left; let mut i: uint = left; while i < right { let a: &mut T = &mut arr[i]; let b: &mut T = &mut arr[right]; if compare_func(a, b) { - arr[i] <-> arr[storage_index]; + swap(&mut arr[i], &mut arr[storage_index]); storage_index += 1; } i += 1; } - arr[storage_index] <-> arr[right]; + swap(&mut arr[storage_index], &mut arr[right]); + return storage_index; +} + +#[cfg(not(stage0))] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + vec::swap(arr, pivot, right); + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + if compare_func(&arr[i], &arr[right]) { + vec::swap(arr, i, storage_index); + storage_index += 1; + } + i += 1; + } + vec::swap(arr, storage_index, right); return storage_index; } @@ -119,29 +137,29 @@ fn qsort3(arr: &mut [T], left: int, right: int) { j -= 1; } if i >= j { break; } - arr[i] <-> arr[j]; + vec::swap(arr, i as uint, j as uint); if arr[i] == v { p += 1; - arr[p] <-> arr[i]; + vec::swap(arr, p as uint, i as uint); } if v == arr[j] { q -= 1; - arr[j] <-> arr[q]; + vec::swap(arr, j as uint, q as uint); } } - arr[i] <-> arr[right]; + vec::swap(arr, i as uint, right as uint); j = i - 1; i += 1; let mut k: int = left; while k < p { - arr[k] <-> arr[j]; + vec::swap(arr, k as uint, j as uint); k += 1; j -= 1; if k == len::(arr) as int { break; } } k = right - 1; while k > q { - arr[i] <-> arr[k]; + vec::swap(arr, i as uint, k as uint); k -= 1; i += 1; if k == 0 { break; } @@ -162,7 +180,8 @@ fn qsort3(arr: &mut [T], left: int, right: int) { */ pub fn quick_sort3(arr: &mut [T]) { if arr.len() <= 1 { return; } - qsort3(arr, 0, (arr.len() - 1) as int); + let len = arr.len(); // FIXME(#5074) nested calls + qsort3(arr, 0, (len - 1) as int); } pub trait Sort { @@ -195,15 +214,20 @@ pub fn tim_sort(array: &mut [T]) { let mut idx = 0; let mut remaining = size; loop { - let arr = vec::mut_slice(array, 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); - binarysort(slice, run_len); - run_len = force; - } + let run_len: uint = { + // This scope contains the slice `arr` here: + let arr = vec::mut_slice(array, 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); + binarysort(slice, run_len); + run_len = force; + } + + run_len + }; ms.push_run(idx, run_len); ms.merge_collapse(array); @@ -240,7 +264,7 @@ fn binarysort(array: &mut [T], start: uint) { assert!(left == right); let n = start-left; - copy_vec(array, left+1, array, left, n); + shift_vec(array, left+1, left, n); array[left] = pivot; start += 1; } @@ -250,7 +274,7 @@ fn binarysort(array: &mut [T], start: uint) { fn reverse_slice(v: &mut [T], start: uint, end:uint) { let mut i = start; while i < end / 2 { - util::swap(&mut v[i], &mut v[end - i - 1]); + vec::swap(v, i, end - i - 1); i += 1; } } @@ -286,8 +310,8 @@ fn count_run_ascending(array: &mut [T]) -> uint { return run; } -fn gallop_left(key: &const T, - array: &const [T], +fn gallop_left(key: &T, + array: &[T], hint: uint) -> uint { let size = array.len(); @@ -337,8 +361,8 @@ fn gallop_left(key: &const T, return ofs; } -fn gallop_right(key: &const T, - array: &const [T], +fn gallop_right(key: &T, + array: &[T], hint: uint) -> uint { let size = array.len(); @@ -433,14 +457,17 @@ impl MergeState { self.runs[n+1].len = self.runs[n+2].len; } - let slice = vec::mut_slice(array, b1, b1+l1); - let k = gallop_right(&const array[b2], slice, 0); + let k = { // constrain lifetime of slice below + let slice = vec::slice(array, b1, b1+l1); + gallop_right(&array[b2], slice, 0) + }; b1 += k; l1 -= k; if l1 != 0 { - let slice = vec::mut_slice(array, b2, b2+l2); - let l2 = gallop_left( - &const array[b1+l1-1],slice,l2-1); + let l2 = { // constrain lifetime of slice below + let slice = vec::slice(array, b2, b2+l2); + gallop_left(&array[b1+l1-1],slice,l2-1) + }; if l2 > 0 { if l1 <= l2 { self.merge_lo(array, b1, l1, b2, l2); @@ -467,16 +494,16 @@ impl MergeState { let mut len1 = len1; let mut len2 = len2; - array[dest] <-> array[c2]; + vec::swap(array, dest, c2); dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { - copy_vec(array, dest, tmp, 0, len1); + copy_vec(array, dest, tmp.slice(0, len1)); return; } if len1 == 1 { - copy_vec(array, dest, array, c2, len2); - array[dest+len2] <-> tmp[c1]; + shift_vec(array, dest, c2, len2); + swap(&mut tmp[c1], &mut array[dest+len2]); return; } @@ -489,14 +516,14 @@ impl MergeState { loop { assert!(len1 > 1 && len2 != 0); if array[c2] < tmp[c1] { - array[dest] <-> array[c2]; + vec::swap(array, dest, c2); dest += 1; c2 += 1; len2 -= 1; count2 += 1; count1 = 0; if len2 == 0 { break_outer = true; } } else { - array[dest] <-> tmp[c1]; + swap(&mut array[dest], &mut tmp[c1]); dest += 1; c1 += 1; len1 -= 1; count1 += 1; count2 = 0; if len1 == 1 { @@ -513,25 +540,29 @@ impl MergeState { loop { assert!(len1 > 1 && len2 != 0); - let tmp_view = vec::const_slice(tmp, c1, c1+len1); - count1 = gallop_right(&const array[c2], tmp_view, 0); + count1 = { + let tmp_view = vec::slice(tmp, c1, c1+len1); + gallop_right(&array[c2], tmp_view, 0) + }; if count1 != 0 { - copy_vec(array, dest, tmp, c1, count1); + copy_vec(array, dest, tmp.slice(c1, c1+count1)); dest += count1; c1 += count1; len1 -= count1; if len1 <= 1 { break_outer = true; break; } } - array[dest] <-> array[c2]; + vec::swap(array, dest, c2); dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { break_outer = true; break; } - let tmp_view = vec::const_slice(array, c2, c2+len2); - count2 = gallop_left(&const tmp[c1], tmp_view, 0); + count2 = { + let tmp_view = vec::slice(array, c2, c2+len2); + gallop_left(&tmp[c1], tmp_view, 0) + }; if count2 != 0 { - copy_vec(array, dest, array, c2, count2); + shift_vec(array, dest, c2, count2); dest += count2; c2 += count2; len2 -= count2; if len2 == 0 { break_outer = true; break; } } - array[dest] <-> tmp[c1]; + swap(&mut array[dest], &mut tmp[c1]); dest += 1; c1 += 1; len1 -= 1; if len1 == 1 { break_outer = true; break; } min_gallop -= 1; @@ -547,14 +578,14 @@ impl MergeState { if len1 == 1 { assert!(len2 > 0); - copy_vec(array, dest, array, c2, len2); - array[dest+len2] <-> tmp[c1]; + shift_vec(array, dest, c2, len2); + swap(&mut array[dest+len2], &mut tmp[c1]); } else if len1 == 0 { fail!(~"Comparison violates its contract!"); } else { assert!(len2 == 0); assert!(len1 > 1); - copy_vec(array, dest, tmp, c1, len1); + copy_vec(array, dest, tmp.slice(c1, c1+len1)); } } @@ -573,18 +604,18 @@ impl MergeState { let mut len1 = len1; let mut len2 = len2; - array[dest] <-> array[c1]; + vec::swap(array, dest, c1); dest -= 1; c1 -= 1; len1 -= 1; if len1 == 0 { - copy_vec(array, dest-(len2-1), tmp, 0, len2); + copy_vec(array, dest-(len2-1), tmp.slice(0, len2)); return; } if len2 == 1 { dest -= len1; c1 -= len1; - copy_vec(array, dest+1, array, c1+1, len1); - array[dest] <-> tmp[c2]; + shift_vec(array, dest+1, c1+1, len1); + swap(&mut array[dest], &mut tmp[c2]); return; } @@ -597,14 +628,14 @@ impl MergeState { loop { assert!(len1 != 0 && len2 > 1); if tmp[c2] < array[c1] { - array[dest] <-> array[c1]; + vec::swap(array, dest, c1); dest -= 1; c1 -= 1; len1 -= 1; count1 += 1; count2 = 0; if len1 == 0 { break_outer = true; } } else { - array[dest] <-> tmp[c2]; + swap(&mut array[dest], &mut tmp[c2]); dest -= 1; c2 -= 1; len2 -= 1; count2 += 1; count1 = 0; if len2 == 1 { @@ -621,35 +652,36 @@ impl MergeState { loop { assert!(len2 > 1 && len1 != 0); - let tmp_view = vec::mut_slice(array, base1, base1+len1); - count1 = len1 - gallop_right( - &const tmp[c2], tmp_view, len1-1); + { // constrain scope of tmp_view: + let tmp_view = vec::mut_slice (array, base1, base1+len1); + count1 = len1 - gallop_right( + &tmp[c2], tmp_view, len1-1); + } if count1 != 0 { dest -= count1; c1 -= count1; len1 -= count1; - copy_vec(array, dest+1, array, c1+1, count1); + shift_vec(array, dest+1, c1+1, count1); if len1 == 0 { break_outer = true; break; } } - array[dest] <-> tmp[c2]; + swap(&mut array[dest], &mut tmp[c2]); dest -= 1; c2 -= 1; len2 -= 1; if len2 == 1 { break_outer = true; break; } let count2; - { + { // constrain scope of tmp_view let tmp_view = vec::mut_slice(tmp, 0, len2); - count2 = len2 - gallop_left(&const array[c1], + count2 = len2 - gallop_left(&array[c1], tmp_view, len2-1); - // Make tmp_view go out of scope to appease borrowck. } if count2 != 0 { dest -= count2; c2 -= count2; len2 -= count2; - copy_vec(array, dest+1, tmp, c2+1, count2); + copy_vec(array, dest+1, tmp.slice(c2+1, c2+1+count2)); if len2 <= 1 { break_outer = true; break; } } - array[dest] <-> array[c1]; + vec::swap(array, dest, c1); dest -= 1; c1 -= 1; len1 -= 1; if len1 == 0 { break_outer = true; break; } min_gallop -= 1; @@ -668,14 +700,14 @@ impl MergeState { assert!(len1 > 0); dest -= len1; c1 -= len1; - copy_vec(array, dest+1, array, c1+1, len1); - array[dest] <-> tmp[c2]; + shift_vec(array, dest+1, c1+1, len1); + swap(&mut array[dest], &mut tmp[c2]); } else if len2 == 0 { fail!(~"Comparison violates its contract!"); } else { assert!(len1 == 0); assert!(len2 != 0); - copy_vec(array, dest-(len2-1), tmp, 0, len2); + copy_vec(array, dest-(len2-1), tmp.slice(0, len2)); } } @@ -711,21 +743,25 @@ impl MergeState { #[inline(always)] fn copy_vec(dest: &mut [T], s1: uint, - from: &const [T], - s2: uint, - len: uint) { - assert!(s1+len <= dest.len() && s2+len <= from.len()); - - let mut slice = ~[]; - for uint::range(s2, s2+len) |i| { - slice.push(from[i]); - } + from: &[T]) { + assert!(s1+from.len() <= dest.len()); - for slice.eachi |i, v| { + for from.eachi |i, v| { dest[s1+i] = *v; } } +#[inline(always)] +fn shift_vec(dest: &mut [T], + s1: uint, + s2: uint, + len: uint) { + assert!(s1+len <= dest.len()); + + let tmp = dest.slice(s2, s2+len).to_vec(); + copy_vec(dest, s1, tmp); +} + #[cfg(test)] mod test_qsort3 { use sort::*; @@ -737,8 +773,7 @@ mod test_qsort3 { quick_sort3::(v1); let mut i = 0; while i < len { - // debug!(v2[i]); - assert!((v2[i] == v1[i])); + assert_eq!(v2[i], v1[i]); i += 1; } } @@ -825,7 +860,7 @@ mod test_qsort { let immut_names = names; let pairs = vec::zip_slice(expected, immut_names); - for vec::each(pairs) |p| { + for pairs.each |p| { let (a, b) = *p; debug!("%d %d", a, b); assert!((a == b)); @@ -912,8 +947,10 @@ mod test_tim_sort { impl Ord for CVal { fn lt(&self, other: &CVal) -> bool { - let rng = rand::rng(); - if rng.gen::() > 0.995 { fail!(~"It's happening!!!"); } + let mut rng = rand::rng(); + if rng.gen::() > 0.995 { + fail!(~"It's happening!!!"); + } (*self).val < other.val } fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } @@ -961,7 +998,7 @@ mod test_tim_sort { #[should_fail] #[cfg(unix)] fn crash_test() { - let rng = rand::rng(); + let mut rng = rand::rng(); let mut arr = do vec::from_fn(1000) |_i| { CVal { val: rng.gen() } }; @@ -981,7 +1018,7 @@ mod test_tim_sort { #[test] fn test_bad_Ord_impl() { - let rng = rand::rng(); + let mut rng = rand::rng(); let mut arr = do vec::from_fn(500) |_i| { DVal { val: rng.gen() } }; @@ -1009,7 +1046,7 @@ mod big_tests { tabulate_managed(low, high); } - fn multiplyVec(arr: &const [T], num: uint) -> ~[T] { + fn multiplyVec(arr: &[T], num: uint) -> ~[T] { let size = arr.len(); let res = do vec::from_fn(num) |i| { arr[i % size] @@ -1025,7 +1062,7 @@ mod big_tests { } fn tabulate_unique(lo: uint, hi: uint) { - fn isSorted(arr: &const [T]) { + fn isSorted(arr: &[T]) { for uint::range(0, arr.len()-1) |i| { if arr[i] > arr[i+1] { fail!(~"Array not sorted"); @@ -1033,7 +1070,7 @@ mod big_tests { } } - let rng = rand::rng(); + let mut rng = rand::rng(); for uint::range(lo, hi) |i| { let n = 1 << i; @@ -1054,7 +1091,7 @@ mod big_tests { for 3.times { let i1 = rng.gen_uint_range(0, n); let i2 = rng.gen_uint_range(0, n); - arr[i1] <-> arr[i2]; + vec::swap(arr, i1, i2); } tim_sort(arr); // 3sort isSorted(arr); @@ -1096,7 +1133,7 @@ mod big_tests { } fn tabulate_managed(lo: uint, hi: uint) { - fn isSorted(arr: &const [@T]) { + fn isSorted(arr: &[@T]) { for uint::range(0, arr.len()-1) |i| { if arr[i] > arr[i+1] { fail!(~"Array not sorted"); @@ -1104,7 +1141,7 @@ mod big_tests { } } - let rng = rand::rng(); + let mut rng = rand::rng(); for uint::range(lo, hi) |i| { let n = 1 << i; @@ -1126,7 +1163,7 @@ mod big_tests { for 3.times { let i1 = rng.gen_uint_range(0, n); let i2 = rng.gen_uint_range(0, n); - arr[i1] <-> arr[i2]; + vec::swap(arr, i1, i2); } tim_sort(arr); // 3sort isSorted(arr); @@ -1175,11 +1212,11 @@ mod big_tests { #[unsafe_destructor] impl<'self> Drop for LVal<'self> { fn finalize(&self) { - let x = unsafe { task::local_data::local_data_get(self.key) }; + let x = unsafe { local_data::local_data_get(self.key) }; match x { Some(@y) => { unsafe { - task::local_data::local_data_set(self.key, @(y+1)); + local_data::local_data_set(self.key, @(y+1)); } } _ => fail!(~"Expected key to work"), @@ -1202,11 +1239,3 @@ mod big_tests { } } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/sort_stage0.rs b/src/libstd/sort_stage0.rs new file mode 100644 index 0000000000000..00bd325dd0c21 --- /dev/null +++ b/src/libstd/sort_stage0.rs @@ -0,0 +1,1240 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sorting methods + +use core::cmp::{Eq, Ord}; +use core::vec::len; +use core::vec; +use core::util; + +type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; + +/** + * Merge sort. Returns a new vector containing the sorted list. + * + * Has worst case O(n log n) performance, best case O(n), but + * is not space efficient. This is a stable sort. + */ +pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { + type Slice = (uint, uint); + + return merge_sort_(v, (0u, len(v)), le); + + fn merge_sort_(v: &const [T], slice: Slice, le: Le) + -> ~[T] { + let begin = slice.first(); + let end = slice.second(); + + let v_len = end - begin; + if v_len == 0 { return ~[]; } + if v_len == 1 { return ~[v[begin]]; } + + 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)); + } + + fn merge(le: Le, a: &[T], b: &[T]) -> ~[T] { + let mut rs = vec::with_capacity(len(a) + len(b)); + let a_len = len(a); + let mut a_ix = 0; + let b_len = len(b); + let mut b_ix = 0; + while a_ix < a_len && b_ix < b_len { + if le(&a[a_ix], &b[b_ix]) { + rs.push(a[a_ix]); + a_ix += 1; + } else { rs.push(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 + } +} + +#[cfg(stage0)] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + vec::swap(arr, pivot, right); + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + let a: &mut T = &mut arr[i]; + let b: &mut T = &mut arr[right]; + if compare_func(a, b) { + vec::swap(arr, i, storage_index); + storage_index += 1; + } + i += 1; + } + vec::swap(arr, storage_index, right); + return storage_index; +} + +#[cfg(not(stage0))] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + vec::swap(arr, pivot, right); + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + if compare_func(&arr[i], &arr[right]) { + vec::swap(arr, i, storage_index); + storage_index += 1; + } + i += 1; + } + vec::swap(arr, storage_index, right); + return storage_index; +} + +fn qsort(arr: &mut [T], left: uint, + right: uint, compare_func: Le) { + if right > left { + let pivot = (left + right) / 2u; + let new_pivot = part::(arr, left, right, pivot, compare_func); + if new_pivot != 0u { + // Need to do this check before recursing due to overflow + qsort::(arr, left, new_pivot - 1u, compare_func); + } + qsort::(arr, new_pivot + 1u, right, compare_func); + } +} + +/** + * Quicksort. Sorts a mut vector in place. + * + * Has worst case O(n^2) performance, average case O(n log n). + * This is an unstable sort. + */ +pub fn quick_sort(arr: &mut [T], compare_func: Le) { + if len::(arr) == 0u { return; } + qsort::(arr, 0u, len::(arr) - 1u, compare_func); +} + +fn qsort3(arr: &mut [T], left: int, right: int) { + if right <= left { return; } + let v: T = arr[right]; + let mut i: int = left - 1; + let mut j: int = right; + let mut p: int = i; + let mut q: int = j; + loop { + i += 1; + while arr[i] < v { i += 1; } + j -= 1; + while v < arr[j] { + if j == left { break; } + j -= 1; + } + if i >= j { break; } + vec::swap(arr, i as uint, j as uint); + if arr[i] == v { + p += 1; + vec::swap(arr, p as uint, i as uint); + } + if v == arr[j] { + q -= 1; + vec::swap(arr, j as uint, q as uint); + } + } + vec::swap(arr, i as uint, right as uint); + j = i - 1; + i += 1; + let mut k: int = left; + while k < p { + vec::swap(arr, k as uint, j as uint); + k += 1; + j -= 1; + if k == len::(arr) as int { break; } + } + k = right - 1; + while k > q { + vec::swap(arr, i as uint, k as uint); + k -= 1; + i += 1; + if k == 0 { break; } + } + qsort3::(arr, left, j); + qsort3::(arr, i, right); +} + +/** + * Fancy quicksort. Sorts a mut vector in place. + * + * Based on algorithm presented by ~[Sedgewick and Bentley] + * (http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf). + * According to these slides this is the algorithm of choice for + * 'randomly ordered keys, abstract compare' & 'small number of key values'. + * + * This is an unstable sort. + */ +pub fn quick_sort3(arr: &mut [T]) { + if arr.len() <= 1 { return; } + let len = arr.len() - 1; // FIXME(#5074) nested calls + qsort3(arr, 0, (len - 1) as int); +} + +pub trait Sort { + fn qsort(self); +} + +impl<'self, T:Copy + Ord + Eq> Sort for &'self mut [T] { + fn qsort(self) { quick_sort3(self); } +} + +static MIN_MERGE: uint = 64; +static MIN_GALLOP: uint = 7; +static INITIAL_TMP_STORAGE: uint = 128; + +pub fn tim_sort(array: &mut [T]) { + let size = array.len(); + if size < 2 { + return; + } + + if size < MIN_MERGE { + let init_run_len = count_run_ascending(array); + binarysort(array, init_run_len); + return; + } + + let mut ms = MergeState(); + let min_run = min_run_length(size); + + let mut idx = 0; + let mut remaining = size; + loop { + let run_len: uint = { + // This scope contains the slice `arr` here: + let arr = vec::mut_slice(array, 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); + binarysort(slice, run_len); + run_len = force; + } + + run_len + }; + + ms.push_run(idx, run_len); + ms.merge_collapse(array); + + idx += run_len; + remaining -= run_len; + if remaining == 0 { break; } + } + + ms.merge_force_collapse(array); +} + +fn binarysort(array: &mut [T], start: uint) { + let size = array.len(); + let mut start = start; + assert!(start <= size); + + if start == 0 { start += 1; } + + while start < size { + let pivot = array[start]; + let mut left = 0; + let mut right = start; + assert!(left <= right); + + while left < right { + let mid = (left + right) >> 1; + if pivot < array[mid] { + right = mid; + } else { + left = mid+1; + } + } + assert!(left == right); + let n = start-left; + + copy_vec(array, left+1, array, left, n); + array[left] = pivot; + start += 1; + } +} + +// Reverse the order of elements in a slice, in place +fn reverse_slice(v: &mut [T], start: uint, end:uint) { + let mut i = start; + while i < end / 2 { + vec::swap(v, i, end - i - 1); + i += 1; + } +} + +fn min_run_length(n: uint) -> uint { + let mut n = n; + let mut r = 0; // becomes 1 if any 1 bits are shifted off + + while n >= MIN_MERGE { + r |= n & 1; + n >>= 1; + } + return n + r; +} + +fn count_run_ascending(array: &mut [T]) -> uint { + let size = array.len(); + assert!(size > 0); + if size == 1 { return 1; } + + let mut run = 2; + if array[1] < array[0] { + while run < size && array[run] < array[run-1] { + run += 1; + } + reverse_slice(array, 0, run); + } else { + while run < size && array[run] >= array[run-1] { + run += 1; + } + } + + return run; +} + +fn gallop_left(key: &const T, + array: &const [T], + hint: uint) + -> uint { + let size = array.len(); + assert!(size != 0 && hint < size); + + let mut last_ofs = 0; + let mut ofs = 1; + + if *key > array[hint] { + // Gallop right until array[hint+last_ofs] < key <= array[hint+ofs] + let max_ofs = size - hint; + while ofs < max_ofs && *key > array[hint+ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } // uint overflow guard + } + if ofs > max_ofs { ofs = max_ofs; } + + last_ofs += hint; + ofs += hint; + } else { + let max_ofs = hint + 1; + while ofs < max_ofs && *key <= array[hint-ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } // uint overflow guard + } + + if ofs > max_ofs { ofs = max_ofs; } + + let tmp = last_ofs; + last_ofs = hint - ofs; + ofs = hint - tmp; + } + assert!((last_ofs < ofs || last_ofs+1 < ofs+1) && ofs <= size); + + last_ofs += 1; + while last_ofs < ofs { + let m = last_ofs + ((ofs - last_ofs) >> 1); + if *key > array[m] { + last_ofs = m+1; + } else { + ofs = m; + } + } + assert!(last_ofs == ofs); + return ofs; +} + +fn gallop_right(key: &const T, + array: &const [T], + hint: uint) + -> uint { + let size = array.len(); + assert!(size != 0 && hint < size); + + let mut last_ofs = 0; + let mut ofs = 1; + + if *key >= array[hint] { + // Gallop right until array[hint+last_ofs] <= key < array[hint+ofs] + let max_ofs = size - hint; + while ofs < max_ofs && *key >= array[hint+ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } + } + if ofs > max_ofs { ofs = max_ofs; } + + last_ofs += hint; + ofs += hint; + } else { + // Gallop left until array[hint-ofs] <= key < array[hint-last_ofs] + let max_ofs = hint + 1; + while ofs < max_ofs && *key < array[hint-ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } + } + if ofs > max_ofs { ofs = max_ofs; } + + let tmp = last_ofs; + last_ofs = hint - ofs; + ofs = hint - tmp; + } + + assert!((last_ofs < ofs || last_ofs+1 < ofs+1) && ofs <= size); + + last_ofs += 1; + while last_ofs < ofs { + let m = last_ofs + ((ofs - last_ofs) >> 1); + + if *key >= array[m] { + last_ofs = m + 1; + } else { + ofs = m; + } + } + assert!(last_ofs == ofs); + return ofs; +} + +struct RunState { + base: uint, + len: uint, +} + +struct MergeState { + min_gallop: uint, + runs: ~[RunState], +} + +// Fixme (#3853) Move into MergeState +fn MergeState() -> MergeState { + MergeState { + min_gallop: MIN_GALLOP, + runs: ~[], + } +} + +impl MergeState { + fn push_run(&mut self, run_base: uint, run_len: uint) { + let tmp = RunState{base: run_base, len: run_len}; + self.runs.push(tmp); + } + + fn merge_at(&mut self, n: uint, array: &mut [T]) { + let size = self.runs.len(); + assert!(size >= 2); + assert!(n == size-2 || n == size-3); + + let mut b1 = self.runs[n].base; + let mut l1 = self.runs[n].len; + let b2 = self.runs[n+1].base; + let l2 = self.runs[n+1].len; + + assert!(l1 > 0 && l2 > 0); + assert!(b1 + l1 == b2); + + self.runs[n].len = l1 + l2; + if n == size-3 { + self.runs[n+1].base = self.runs[n+2].base; + self.runs[n+1].len = self.runs[n+2].len; + } + + let k = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b1, b1+l1); + gallop_right(&const array[b2], slice, 0) + }; + b1 += k; + l1 -= k; + if l1 != 0 { + let l2 = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b2, b2+l2); + gallop_left(&const array[b1+l1-1],slice,l2-1) + }; + if l2 > 0 { + if l1 <= l2 { + self.merge_lo(array, b1, l1, b2, l2); + } else { + self.merge_hi(array, b1, l1, b2, l2); + } + } + } + self.runs.pop(); + } + + fn merge_lo(&mut self, array: &mut [T], base1: uint, len1: uint, + base2: uint, len2: uint) { + assert!(len1 != 0 && len2 != 0 && base1+len1 == base2); + + let mut tmp = ~[]; + for uint::range(base1, base1+len1) |i| { + tmp.push(array[i]); + } + + let mut c1 = 0; + let mut c2 = base2; + let mut dest = base1; + let mut len1 = len1; + let mut len2 = len2; + + vec::swap(array, dest, c2); + dest += 1; c2 += 1; len2 -= 1; + + if len2 == 0 { + copy_vec(array, dest, tmp, 0, len1); + return; + } + if len1 == 1 { + copy_vec(array, dest, array, c2, len2); + util::swap(&mut array[dest+len2], &mut tmp[c1]); + return; + } + + let mut min_gallop = self.min_gallop; + loop { + let mut count1 = 0; + let mut count2 = 0; + let mut break_outer = false; + + loop { + assert!(len1 > 1 && len2 != 0); + if array[c2] < tmp[c1] { + vec::swap(array, dest, c2); + dest += 1; c2 += 1; len2 -= 1; + count2 += 1; count1 = 0; + if len2 == 0 { + break_outer = true; + } + } else { + util::swap(&mut array[dest], &mut tmp[c1]); + dest += 1; c1 += 1; len1 -= 1; + count1 += 1; count2 = 0; + if len1 == 1 { + break_outer = true; + } + } + if break_outer || ((count1 | count2) >= min_gallop) { + break; + } + } + if break_outer { break; } + + // Start to gallop + loop { + assert!(len1 > 1 && len2 != 0); + + let tmp_view = vec::const_slice(tmp, c1, c1+len1); + count1 = gallop_right(&const array[c2], tmp_view, 0); + if count1 != 0 { + copy_vec(array, dest, tmp, c1, count1); + dest += count1; c1 += count1; len1 -= count1; + if len1 <= 1 { break_outer = true; break; } + } + vec::swap(array, dest, c2); + dest += 1; c2 += 1; len2 -= 1; + if len2 == 0 { break_outer = true; break; } + + let tmp_view = vec::const_slice(array, c2, c2+len2); + count2 = gallop_left(&const tmp[c1], tmp_view, 0); + if count2 != 0 { + copy_vec(array, dest, array, c2, count2); + dest += count2; c2 += count2; len2 -= count2; + if len2 == 0 { break_outer = true; break; } + } + util::swap(&mut array[dest], &mut tmp[c1]); + dest += 1; c1 += 1; len1 -= 1; + if len1 == 1 { break_outer = true; break; } + min_gallop -= 1; + if !(count1 >= MIN_GALLOP || count2 >= MIN_GALLOP) { + break; + } + } + if break_outer { break; } + if min_gallop < 0 { min_gallop = 0; } + min_gallop += 2; // Penalize for leaving gallop + } + self.min_gallop = if min_gallop < 1 { 1 } else { min_gallop }; + + if len1 == 1 { + assert!(len2 > 0); + copy_vec(array, dest, array, c2, len2); + util::swap(&mut array[dest+len2], &mut tmp[c1]); + } else if len1 == 0 { + fail!(~"Comparison violates its contract!"); + } else { + assert!(len2 == 0); + assert!(len1 > 1); + copy_vec(array, dest, tmp, c1, len1); + } + } + + fn merge_hi(&mut self, array: &mut [T], base1: uint, len1: uint, + base2: uint, len2: uint) { + assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2); + + let mut tmp = ~[]; + for uint::range(base2, base2+len2) |i| { + tmp.push(array[i]); + } + + let mut c1 = base1 + len1 - 1; + let mut c2 = len2 - 1; + let mut dest = base2 + len2 - 1; + let mut len1 = len1; + let mut len2 = len2; + + vec::swap(array, dest, c1); + dest -= 1; c1 -= 1; len1 -= 1; + + if len1 == 0 { + copy_vec(array, dest-(len2-1), tmp, 0, len2); + return; + } + if len2 == 1 { + dest -= len1; + c1 -= len1; + copy_vec(array, dest+1, array, c1+1, len1); + util::swap(&mut array[dest], &mut tmp[c2]); + return; + } + + let mut min_gallop = self.min_gallop; + loop { + let mut count1 = 0; + let mut count2 = 0; + let mut break_outer = false; + + loop { + assert!(len1 != 0 && len2 > 1); + if tmp[c2] < array[c1] { + vec::swap(array, dest, c1); + dest -= 1; c1 -= 1; len1 -= 1; + count1 += 1; count2 = 0; + if len1 == 0 { + break_outer = true; + } + } else { + util::swap(&mut array[dest], &mut tmp[c2]); + dest -= 1; c2 -= 1; len2 -= 1; + count2 += 1; count1 = 0; + if len2 == 1 { + break_outer = true; + } + } + if break_outer || ((count1 | count2) >= min_gallop) { + break; + } + } + if break_outer { break; } + + // Start to gallop + loop { + assert!(len2 > 1 && len1 != 0); + + { // constrain scope of tmp_view: + let tmp_view = vec::mut_slice (array, base1, base1+len1); + count1 = len1 - gallop_right( + &const tmp[c2], tmp_view, len1-1); + } + + if count1 != 0 { + dest -= count1; c1 -= count1; len1 -= count1; + copy_vec(array, dest+1, array, c1+1, count1); + if len1 == 0 { break_outer = true; break; } + } + + util::swap(&mut array[dest], &mut tmp[c2]); + dest -= 1; c2 -= 1; len2 -= 1; + if len2 == 1 { break_outer = true; break; } + + let count2; + { // constrain scope of tmp_view + let tmp_view = vec::mut_slice(tmp, 0, len2); + count2 = len2 - gallop_left(&const array[c1], + tmp_view, + len2-1); + } + + if count2 != 0 { + dest -= count2; c2 -= count2; len2 -= count2; + copy_vec(array, dest+1, tmp, c2+1, count2); + if len2 <= 1 { break_outer = true; break; } + } + vec::swap(array, dest, c1); + dest -= 1; c1 -= 1; len1 -= 1; + if len1 == 0 { break_outer = true; break; } + min_gallop -= 1; + if !(count1 >= MIN_GALLOP || count2 >= MIN_GALLOP) { + break; + } + } + + if break_outer { break; } + if min_gallop < 0 { min_gallop = 0; } + min_gallop += 2; // Penalize for leaving gallop + } + self.min_gallop = if min_gallop < 1 { 1 } else { min_gallop }; + + if len2 == 1 { + assert!(len1 > 0); + dest -= len1; + c1 -= len1; + copy_vec(array, dest+1, array, c1+1, len1); + util::swap(&mut array[dest], &mut tmp[c2]); + } else if len2 == 0 { + fail!(~"Comparison violates its contract!"); + } else { + assert!(len1 == 0); + assert!(len2 != 0); + copy_vec(array, dest-(len2-1), tmp, 0, len2); + } + } + + fn merge_collapse(&mut self, array: &mut [T]) { + while self.runs.len() > 1 { + let mut n = self.runs.len()-2; + if n > 0 && + self.runs[n-1].len <= self.runs[n].len + self.runs[n+1].len + { + if self.runs[n-1].len < self.runs[n+1].len { n -= 1; } + } else if self.runs[n].len <= self.runs[n+1].len { + /* keep going */ + } else { + break; + } + self.merge_at(n, array); + } + } + + fn merge_force_collapse(&mut self, array: &mut [T]) { + while self.runs.len() > 1 { + let mut n = self.runs.len()-2; + if n > 0 { + if self.runs[n-1].len < self.runs[n+1].len { + n -= 1; + } + } + self.merge_at(n, array); + } + } +} + +#[inline(always)] +fn copy_vec(dest: &mut [T], + s1: uint, + from: &const [T], + s2: uint, + len: uint) { + assert!(s1+len <= dest.len() && s2+len <= from.len()); + + let mut slice = ~[]; + for uint::range(s2, s2+len) |i| { + slice.push(from[i]); + } + + for slice.eachi |i, v| { + dest[s1+i] = *v; + } +} + +#[cfg(test)] +mod test_qsort3 { + use sort::*; + + use core::vec; + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + quick_sort3::(v1); + let mut i = 0; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } +} + +#[cfg(test)] +mod test_qsort { + use sort::*; + + use core::int; + use core::vec; + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + fn leual(a: &int, b: &int) -> bool { *a <= *b } + quick_sort::(v1, leual); + let mut i = 0u; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + // Regression test for #750 + #[test] + fn test_simple() { + let mut names = ~[2, 1, 3]; + + let expected = ~[1, 2, 3]; + + do quick_sort(names) |x, y| { int::le(*x, *y) }; + + let immut_names = names; + + let pairs = vec::zip_slice(expected, immut_names); + for pairs.each |p| { + let (a, b) = *p; + debug!("%d %d", a, b); + assert!((a == b)); + } + } +} + +#[cfg(test)] +mod tests { + + use sort::*; + + use core::vec; + + fn check_sort(v1: &[int], v2: &[int]) { + let len = vec::len::(v1); + pub fn le(a: &int, b: &int) -> bool { *a <= *b } + let f = le; + let v3 = merge_sort::(v1, f); + let mut i = 0u; + while i < len { + debug!(v3[i]); + assert!((v3[i] == v2[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { let v1 = ~[1, 1, 1]; let v2 = ~[1, 1, 1]; check_sort(v1, v2); } + { let v1:~[int] = ~[]; let v2:~[int] = ~[]; check_sort(v1, v2); } + { let v1 = ~[9]; let v2 = ~[9]; check_sort(v1, v2); } + { + let v1 = ~[9, 3, 3, 3, 9]; + let v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + #[test] + fn test_merge_sort_mutable() { + pub fn le(a: &int, b: &int) -> bool { *a <= *b } + let mut v1 = ~[3, 2, 1]; + let v2 = merge_sort(v1, le); + assert!(v2 == ~[1, 2, 3]); + } + + #[test] + fn test_merge_sort_stability() { + // tjc: funny that we have to use parens + fn ile(x: &(&'static str), y: &(&'static str)) -> bool + { + // 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. + // (Actually, could just remove the to_str_* call, but needs an deriving(Ord) on + // Ascii) + let x = x.to_ascii().to_lower().to_str_ascii(); + let y = y.to_ascii().to_lower().to_str_ascii(); + x <= y + } + + let names1 = ~["joe bob", "Joe Bob", "Jack Brown", "JOE Bob", + "Sally Mae", "JOE BOB", "Alex Andy"]; + let names2 = ~["Alex Andy", "Jack Brown", "joe bob", "Joe Bob", + "JOE Bob", "JOE BOB", "Sally Mae"]; + let names3 = merge_sort(names1, ile); + assert!(names3 == names2); + } +} + +#[cfg(test)] +mod test_tim_sort { + use sort::tim_sort; + use core::rand::RngUtil; + + struct CVal { + val: float, + } + + impl Ord for CVal { + fn lt(&self, other: &CVal) -> bool { + let rng = rand::rng(); + if rng.gen::() > 0.995 { fail!(~"It's happening!!!"); } + (*self).val < other.val + } + fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } + fn gt(&self, other: &CVal) -> bool { (*self).val > other.val } + fn ge(&self, other: &CVal) -> bool { (*self).val >= other.val } + } + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + tim_sort::(v1); + let mut i = 0u; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1u; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + #[test] + #[should_fail] + #[cfg(unix)] + fn crash_test() { + let rng = rand::rng(); + let mut arr = do vec::from_fn(1000) |_i| { + CVal { val: rng.gen() } + }; + + tim_sort(arr); + fail!(~"Guarantee the fail"); + } + + struct DVal { val: uint } + + impl Ord for DVal { + fn lt(&self, _x: &DVal) -> bool { true } + fn le(&self, _x: &DVal) -> bool { true } + fn gt(&self, _x: &DVal) -> bool { true } + fn ge(&self, _x: &DVal) -> bool { true } + } + + #[test] + fn test_bad_Ord_impl() { + let rng = rand::rng(); + let mut arr = do vec::from_fn(500) |_i| { + DVal { val: rng.gen() } + }; + + tim_sort(arr); + } +} + +#[cfg(test)] +mod big_tests { + use sort::*; + use core::rand::RngUtil; + + #[test] + fn test_unique() { + let low = 5; + let high = 10; + tabulate_unique(low, high); + } + + #[test] + fn test_managed() { + let low = 5; + let high = 10; + tabulate_managed(low, high); + } + + fn multiplyVec(arr: &const [T], num: uint) -> ~[T] { + let size = arr.len(); + let res = do vec::from_fn(num) |i| { + arr[i % size] + }; + res + } + + fn makeRange(n: uint) -> ~[uint] { + let one = do vec::from_fn(n) |i| { i }; + let mut two = copy one; + vec::reverse(two); + vec::append(two, one) + } + + fn tabulate_unique(lo: uint, hi: uint) { + fn isSorted(arr: &const [T]) { + for uint::range(0, arr.len()-1) |i| { + if arr[i] > arr[i+1] { + fail!(~"Array not sorted"); + } + } + } + + let rng = rand::rng(); + + for uint::range(lo, hi) |i| { + let n = 1 << i; + let mut arr: ~[float] = do vec::from_fn(n) |_i| { + rng.gen() + }; + + tim_sort(arr); // *sort + isSorted(arr); + + vec::reverse(arr); + tim_sort(arr); // \sort + isSorted(arr); + + tim_sort(arr); // /sort + isSorted(arr); + + for 3.times { + let i1 = rng.gen_uint_range(0, n); + let i2 = rng.gen_uint_range(0, n); + vec::swap(arr, i1, i2); + } + tim_sort(arr); // 3sort + isSorted(arr); + + if n >= 10 { + let size = arr.len(); + let mut idx = 1; + while idx <= 10 { + arr[size-idx] = rng.gen(); + idx += 1; + } + } + tim_sort(arr); // +sort + isSorted(arr); + + for (n/100).times { + let idx = rng.gen_uint_range(0, n); + arr[idx] = rng.gen(); + } + tim_sort(arr); + isSorted(arr); + + let mut arr = if n > 4 { + let part = vec::slice(arr, 0, 4); + multiplyVec(part, n) + } else { arr }; + tim_sort(arr); // ~sort + isSorted(arr); + + let mut arr = vec::from_elem(n, -0.5); + tim_sort(arr); // =sort + isSorted(arr); + + let half = n / 2; + let mut arr = makeRange(half).map(|i| *i as float); + tim_sort(arr); // !sort + isSorted(arr); + } + } + + fn tabulate_managed(lo: uint, hi: uint) { + fn isSorted(arr: &const [@T]) { + for uint::range(0, arr.len()-1) |i| { + if arr[i] > arr[i+1] { + fail!(~"Array not sorted"); + } + } + } + + let rng = rand::rng(); + + for uint::range(lo, hi) |i| { + let n = 1 << i; + let arr: ~[@float] = do vec::from_fn(n) |_i| { + @rng.gen() + }; + let mut arr = arr; + + tim_sort(arr); // *sort + isSorted(arr); + + vec::reverse(arr); + tim_sort(arr); // \sort + isSorted(arr); + + tim_sort(arr); // /sort + isSorted(arr); + + for 3.times { + let i1 = rng.gen_uint_range(0, n); + let i2 = rng.gen_uint_range(0, n); + vec::swap(arr, i1, i2); + } + tim_sort(arr); // 3sort + isSorted(arr); + + if n >= 10 { + let size = arr.len(); + let mut idx = 1; + while idx <= 10 { + arr[size-idx] = @rng.gen(); + idx += 1; + } + } + tim_sort(arr); // +sort + isSorted(arr); + + for (n/100).times { + let idx = rng.gen_uint_range(0, n); + arr[idx] = @rng.gen(); + } + tim_sort(arr); + isSorted(arr); + + let mut arr = if n > 4 { + let part = vec::slice(arr, 0, 4); + multiplyVec(part, n) + } else { arr }; + tim_sort(arr); // ~sort + isSorted(arr); + + let mut arr = vec::from_elem(n, @(-0.5)); + tim_sort(arr); // =sort + isSorted(arr); + + let half = n / 2; + let mut arr = makeRange(half).map(|i| @(*i as float)); + tim_sort(arr); // !sort + isSorted(arr); + } + } + + struct LVal<'self> { + val: uint, + key: &'self fn(@uint), + } + + #[unsafe_destructor] + impl<'self> Drop for LVal<'self> { + fn finalize(&self) { + let x = unsafe { local_data::local_data_get(self.key) }; + match x { + Some(@y) => { + unsafe { + local_data::local_data_set(self.key, @(y+1)); + } + } + _ => fail!(~"Expected key to work"), + } + } + } + + impl<'self> Ord for LVal<'self> { + fn lt<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val < other.val + } + fn le<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val <= other.val + } + fn gt<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val > other.val + } + fn ge<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val >= other.val + } + } +} + +// Local Variables: +// mode: rust; +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: diff --git a/src/libstd/stats.rs b/src/libstd/stats.rs index 6513a671ab343..25323b4e1db8e 100644 --- a/src/libstd/stats.rs +++ b/src/libstd/stats.rs @@ -52,7 +52,7 @@ impl<'self> Stats for &'self [f64] { fn median(self) -> f64 { assert!(self.len() != 0); - let mut tmp = vec::from_slice(self); + let mut tmp = vec::to_owned(self); sort::tim_sort(tmp); if tmp.len() & 1 == 0 { let m = tmp.len() / 2; diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 0a5348d79760e..915aab59a718a 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -26,9 +26,7 @@ not required in or otherwise suitable for the core library. #[license = "MIT/ASL2"]; #[crate_type = "lib"]; -#[allow(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; -#[allow(deprecated_mutable_fields)]; pub mod uv_ll; @@ -50,6 +48,7 @@ pub mod uv_global_loop; pub mod c_vec; pub mod timer; pub mod io_util; +pub mod rc; // Concurrency @@ -69,9 +68,15 @@ pub mod list; pub mod priority_queue; pub mod rope; pub mod smallintmap; + +#[cfg(stage0)] +#[path="sort_stage0.rs"] pub mod sort; -pub mod dlist; + #[cfg(not(stage0))] +pub mod sort; + +pub mod dlist; pub mod treemap; // And ... other stuff @@ -87,22 +92,19 @@ pub mod term; pub mod time; pub mod arena; pub mod par; -pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; -#[cfg(not(stage0))] #[path="num/bigint.rs"] pub mod bigint; -#[cfg(not(stage0))] #[path="num/rational.rs"] pub mod rational; -#[cfg(not(stage0))] #[path="num/complex.rs"] pub mod complex; pub mod stats; pub mod semver; pub mod fileinput; +pub mod flate; #[cfg(unicode)] mod unicode; @@ -121,11 +123,3 @@ pub mod std { pub use serialize; pub use test; } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index e86ec79318880..108f24d60dc36 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -15,7 +15,7 @@ * in std. */ -use core::unstable::{Exclusive, exclusive}; +use core::unstable::sync::{Exclusive, exclusive}; use core::ptr; use core::task; use core::util; @@ -997,7 +997,7 @@ mod tests { } } } - for vec::each(sibling_convos) |p| { + for sibling_convos.each |p| { let _ = p.recv(); // wait for sibling to get in the mutex } do m2.lock { } diff --git a/src/libstd/task_pool.rs b/src/libstd/task_pool.rs index 820536027552b..0c52e1ff80e21 100644 --- a/src/libstd/task_pool.rs +++ b/src/libstd/task_pool.rs @@ -70,7 +70,9 @@ pub impl TaskPool { task::spawn(task_body); } Some(sched_mode) => { - task::task().sched_mode(sched_mode).spawn(task_body); + let mut task = task::task(); + task.sched_mode(sched_mode); + task.spawn(task_body); } } @@ -100,4 +102,3 @@ fn test_task_pool() { pool.execute(|i| io::println(fmt!("Hello from thread %u!", *i))); } } - diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index eec91b6845444..e02a7a337334e 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -13,7 +13,7 @@ use core::rand::RngUtil; pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { - let r = rand::rng(); + let mut r = rand::rng(); for 1000.times { let p = tmpdir.push(r.gen_str(16) + suffix); if os::make_dir(&p, 0x1c0) { // 700 @@ -27,6 +27,7 @@ pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { mod tests { use tempfile::mkdtemp; use tempfile; + use core::os; #[test] fn test_mkdtemp() { @@ -42,13 +43,18 @@ mod tests { use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::os; - let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel"); - os::change_dir(&root); - let path = Path("frob"); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); + let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel"). + expect("recursive_mkdir_rel"); + assert!(do os::change_dir_locked(&root) { + let path = Path("frob"); + debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(), + os::getcwd().to_str(), + os::path_exists(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + }); } #[test] @@ -67,18 +73,44 @@ mod tests { use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::os; - let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel_2"); - os::change_dir(&root); - let path = Path("./frob/baz"); - debug!("...Making: %s in cwd %s", path.to_str(), os::getcwd().to_str()); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::path_is_dir(&path.pop())); - let path2 = Path("quux/blat"); - debug!("Making: %s in cwd %s", path2.to_str(), os::getcwd().to_str()); - assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path2)); - assert!(os::path_is_dir(&path2.pop())); + let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2"). + expect("recursive_mkdir_rel_2"); + assert!(do os::change_dir_locked(&root) { + let path = Path("./frob/baz"); + debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(), + os::getcwd().to_str(), os::path_exists(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + assert!(os::path_is_dir(&path.pop())); + let path2 = Path("quux/blat"); + debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(), + os::getcwd().to_str()); + assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path2)); + assert!(os::path_is_dir(&path2.pop())); + }); } -} \ No newline at end of file + // Ideally this would be in core, but needs mkdtemp + #[test] + pub fn test_rmdir_recursive_ok() { + use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use core::os; + + let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; + + let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \ + couldn't create temp dir"); + let root = tmpdir.push("foo"); + + debug!("making %s", root.to_str()); + assert!(os::make_dir(&root, rwx)); + assert!(os::make_dir(&root.push("foo"), rwx)); + assert!(os::make_dir(&root.push("foo").push("bar"), rwx)); + assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx)); + assert!(os::remove_dir_recursive(&root)); + assert!(!os::path_exists(&root)); + assert!(!os::path_exists(&root.push("bar"))); + assert!(!os::path_exists(&root.push("bar").push("blat"))); + } +} diff --git a/src/libstd/term.rs b/src/libstd/term.rs index 022f1f8564ece..236c7f668c2e0 100644 --- a/src/libstd/term.rs +++ b/src/libstd/term.rs @@ -13,7 +13,6 @@ use core::io; use core::option; use core::os; -use core::vec; // FIXME (#2807): Windows support. @@ -50,7 +49,7 @@ pub fn color_supported() -> bool { ~"screen-bce", ~"xterm-256color"]; return match os::getenv(~"TERM") { option::Some(ref env) => { - for vec::each(supported_terms) |term| { + for supported_terms.each |term| { if *term == *env { return true; } } false @@ -76,10 +75,3 @@ pub fn fg(writer: @io::Writer, color: u8) { pub fn bg(writer: @io::Writer, color: u8) { return set_color(writer, '4' as u8, color); } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/test.rs b/src/libstd/test.rs index 278a326d1de95..71cbc0d7a6a5a 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -32,7 +32,7 @@ pub mod rustrt { } // The name of a test. By convention this follows the rules for rust -// paths; i.e. it should be a series of identifiers seperated by double +// paths; i.e. it should be a series of identifiers separated by double // colons. This way if some test runner wants to arrange the tests // hierarchically it may. @@ -42,9 +42,9 @@ pub enum TestName { } impl ToStr for TestName { fn to_str(&self) -> ~str { - match self { - &StaticTestName(s) => s.to_str(), - &DynTestName(s) => s.to_str() + match copy *self { + StaticTestName(s) => s.to_str(), + DynTestName(s) => s.to_str() } } } @@ -145,7 +145,7 @@ pub fn parse_opts(args: &[~str]) -> OptRes { let filter = if vec::len(matches.free) > 0 { - option::Some(matches.free[0]) + option::Some(copy (matches).free[0]) } else { option::None }; let run_ignored = getopts::opt_present(&matches, ~"ignored"); @@ -203,7 +203,7 @@ pub fn run_tests_console(opts: &TestOpts, fn callback(event: &TestEvent, st: &mut ConsoleTestState) { debug!("callback(event=%?)", event); - match *event { + match copy *event { TeFiltered(ref filtered_tests) => { st.total = filtered_tests.len(); let noun = if st.total != 1 { ~"tests" } else { ~"test" }; @@ -213,7 +213,7 @@ pub fn run_tests_console(opts: &TestOpts, fmt!("test %s ... ", test.name.to_str())), TeResult(copy test, result) => { match st.log_out { - Some(f) => write_log(f, result, &test), + Some(f) => write_log(f, copy result, &test), None => () } match result { @@ -355,7 +355,7 @@ fn print_failures(st: &ConsoleTestState) { failures.push(name.to_str()); } sort::tim_sort(failures); - for vec::each(failures) |name| { + for failures.each |name| { st.out.write_line(fmt!(" %s", name.to_str())); } } @@ -410,9 +410,10 @@ type MonitorMsg = (TestDesc, TestResult); fn run_tests(opts: &TestOpts, tests: ~[TestDescAndFn], callback: @fn(e: TestEvent)) { - let mut filtered_tests = filter_tests(opts, tests); - let filtered_descs = filtered_tests.map(|t| t.desc); + let filtered_tests = filter_tests(opts, tests); + let filtered_descs = filtered_tests.map(|t| copy t.desc); + callback(TeFiltered(filtered_descs)); let (filtered_tests, filtered_benchs) = @@ -442,7 +443,7 @@ fn run_tests(opts: &TestOpts, // We are doing one test at a time so we can print the name // of the test before we run it. Useful for debugging tests // that hang forever. - callback(TeWait(test.desc)); + callback(TeWait(copy test.desc)); } run_test(!opts.run_tests, test, ch.clone()); pending += 1; @@ -450,7 +451,7 @@ fn run_tests(opts: &TestOpts, let (desc, result) = p.recv(); if concurrency != 1 { - callback(TeWait(desc)); + callback(TeWait(copy desc)); } callback(TeResult(desc, result)); pending -= 1; @@ -556,13 +557,16 @@ pub fn run_test(force_ignore: bool, let testfn_cell = ::core::cell::Cell(testfn); do task::spawn { let mut result_future = None; // task::future_result(builder); - task::task().unlinked().future_result(|+r| { - result_future = Some(r); - }).spawn(testfn_cell.take()); + + let mut task = task::task(); + task.unlinked(); + task.future_result(|r| { result_future = Some(r) }); + task.spawn(testfn_cell.take()); + let task_result = result_future.unwrap().recv(); let test_result = calc_result(&desc, task_result == task::Success); - monitor_ch.send((desc, test_result)); + monitor_ch.send((copy desc, test_result)); } } @@ -688,7 +692,7 @@ pub mod bench { // not met, it may run as long as the Go algorithm. pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { - let rng = rand::rng(); + let mut rng = rand::rng(); let mut magnitude = 10; let mut prev_madp = 0.0; @@ -847,7 +851,7 @@ mod tests { either::Left(copy o) => o, _ => fail!(~"Malformed arg in first_free_arg_should_be_a_filter") }; - assert!(~"filter" == opts.filter.get()); + assert!("filter" == (copy opts.filter).get()); } #[test] @@ -925,10 +929,10 @@ mod tests { { fn testfn() { } let mut tests = ~[]; - for vec::each(names) |name| { + for names.each |name| { let test = TestDescAndFn { desc: TestDesc { - name: DynTestName(*name), + name: DynTestName(copy *name), ignore: false, should_fail: false }, @@ -951,7 +955,7 @@ mod tests { let pairs = vec::zip(expected, filtered); - for vec::each(pairs) |p| { + for pairs.each |p| { match *p { (ref a, ref b) => { assert!((*a == b.desc.name.to_str())); @@ -960,12 +964,3 @@ mod tests { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 8889abe6472b4..e731f679221fd 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -289,7 +289,7 @@ priv fn do_strptime(s: &str, format: &str) -> Result { let mut i = 0u; while i < digits { - let range = str::char_range_at(str::from_slice(ss), pos); + let range = str::char_range_at(str::to_owned(ss), pos); pos = range.next; match range.ch { @@ -628,7 +628,7 @@ priv fn do_strptime(s: &str, format: &str) -> Result { } } - do io::with_str_reader(str::from_slice(format)) |rdr| { + do io::with_str_reader(str::to_owned(format)) |rdr| { let mut tm = Tm { tm_sec: 0_i32, tm_min: 0_i32, @@ -840,7 +840,7 @@ priv fn do_strftime(format: &str, tm: &Tm) -> ~str { let mut buf = ~""; - do io::with_str_reader(str::from_slice(format)) |rdr| { + do io::with_str_reader(str::to_owned(format)) |rdr| { while !rdr.eof() { match rdr.read_char() { '%' => buf += parse_type(rdr.read_char(), tm), @@ -861,7 +861,6 @@ mod tests { use core::result; use core::result::{Err, Ok}; use core::str; - use core::vec; fn test_get_time() { static some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z @@ -1023,12 +1022,12 @@ mod tests { fn test(s: &str, format: &str) -> bool { match strptime(s, format) { - Ok(ref tm) => tm.strftime(format) == str::from_slice(s), + Ok(ref tm) => tm.strftime(format) == str::to_owned(s), Err(copy e) => fail!(e) } } - for vec::each([ + for [ ~"Sunday", ~"Monday", ~"Tuesday", @@ -1036,11 +1035,11 @@ mod tests { ~"Thursday", ~"Friday", ~"Saturday" - ]) |day| { + ].each |day| { assert!(test(*day, ~"%A")); } - for vec::each([ + for [ ~"Sun", ~"Mon", ~"Tue", @@ -1048,11 +1047,11 @@ mod tests { ~"Thu", ~"Fri", ~"Sat" - ]) |day| { + ].each |day| { assert!(test(*day, ~"%a")); } - for vec::each([ + for [ ~"January", ~"February", ~"March", @@ -1065,11 +1064,11 @@ mod tests { ~"October", ~"November", ~"December" - ]) |day| { + ].each |day| { assert!(test(*day, ~"%B")); } - for vec::each([ + for [ ~"Jan", ~"Feb", ~"Mar", @@ -1082,7 +1081,7 @@ mod tests { ~"Oct", ~"Nov", ~"Dec" - ]) |day| { + ].each |day| { assert!(test(*day, ~"%b")); } diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index b19b2f2889e71..234982a12bca1 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -14,10 +14,11 @@ use uv; use uv::iotask; use uv::iotask::IoTask; -use core::libc; -use core::libc::c_void; use core::cast::transmute; +use core::cast; use core::comm::{stream, Chan, SharedChan, Port, select2i}; +use core::libc::c_void; +use core::libc; /** * Wait for timeout period then send provided value over a channel @@ -120,22 +121,28 @@ pub fn sleep(iotask: &IoTask, msecs: uint) { pub fn recv_timeout(iotask: &IoTask, msecs: uint, wait_po: &Port) - -> Option { - let (timeout_po, timeout_ch) = stream::<()>(); + -> Option { + let mut (timeout_po, timeout_ch) = stream::<()>(); delayed_send(iotask, msecs, &timeout_ch, ()); - // FIXME: This could be written clearer (#2618) - either::either( - |_| { - None - }, |_| { - Some(wait_po.recv()) - }, &select2i(&timeout_po, wait_po) - ) + + // XXX: Workaround due to ports and channels not being &mut. They should + // be. + unsafe { + let wait_po = cast::transmute_mut(wait_po); + + // FIXME: This could be written clearer (#2618) + either::either( + |_| { + None + }, |_| { + Some(wait_po.recv()) + }, &select2i(&mut timeout_po, wait_po) + ) + } } // INTERNAL API -extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t, - status: libc::c_int) { +extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t, status: libc::c_int) { unsafe { debug!( "delayed_send_cb handle %? status %?", handle, status); @@ -168,9 +175,9 @@ extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) { #[cfg(test)] mod test { - use timer::*; use uv; + use core::cell::Cell; use core::rand::RngUtil; use core::pipes::{stream, SharedChan}; @@ -212,7 +219,7 @@ mod test { let hl_loop_clone = hl_loop.clone(); do task::spawn { use core::rand::*; - let rng = rng(); + let mut rng = rng(); for old_iter::repeat(times) { sleep(&hl_loop_clone, rng.next() as uint % maxms); } @@ -269,11 +276,12 @@ mod test { let hl_loop = uv::global_loop::get(); for old_iter::repeat(times as uint) { - let expected = rand::rng().gen_str(16u); + let mut rng = rand::rng(); + let expected = Cell(rng.gen_str(16u)); let (test_po, test_ch) = stream::<~str>(); let hl_loop_clone = hl_loop.clone(); do task::spawn() { - delayed_send(&hl_loop_clone, 50u, &test_ch, expected); + delayed_send(&hl_loop_clone, 50u, &test_ch, expected.take()); }; match recv_timeout(&hl_loop, 1u, &test_po) { diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 51695f2fa7d28..2b39458d32dcb 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -13,6 +13,7 @@ //! `TotalOrd`. use core::iterator::*; +use core::util::{swap, replace}; // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where where red (horizontal) nodes can only be added @@ -104,24 +105,48 @@ impl Map for TreeMap { } /// Visit all key-value pairs in order + #[cfg(stage0)] fn each<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) { + each(&self.root, f); + } + /// Visit all key-value pairs in order + #[cfg(not(stage0))] + fn each<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { each(&self.root, f) } /// Visit all keys in order + #[cfg(stage0)] fn each_key(&self, f: &fn(&K) -> bool) { self.each(|k, _| f(k)) } + /// Visit all keys in order + #[cfg(not(stage0))] + fn each_key(&self, f: &fn(&K) -> bool) -> bool { + self.each(|k, _| f(k)) + } /// Visit all values in order + #[cfg(stage0)] fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) { self.each(|_, v| f(v)) } + /// Visit all values in order + #[cfg(not(stage0))] + fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { + self.each(|_, v| f(v)) + } /// Iterate over the map and mutate the contained values + #[cfg(stage0)] fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) { mutate_values(&mut self.root, f); } + /// Iterate over the map and mutate the contained values + #[cfg(not(stage0))] + fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { + mutate_values(&mut self.root, f) + } /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, key: &K) -> Option<&'a V> { @@ -150,20 +175,33 @@ impl Map for TreeMap { /// key is replaced by the new value. Return true if the key did /// not already exist in the map. fn insert(&mut self, key: K, value: V) -> bool { - let ret = insert(&mut self.root, key, value); - if ret { self.length += 1 } - ret + self.swap(key, value).is_none() } /// Remove a key-value pair from the map. Return true if the key /// was present in the map, otherwise false. fn remove(&mut self, key: &K) -> bool { + self.pop(key).is_some() + } + + /// Insert a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise None is returned. + fn swap(&mut self, key: K, value: V) -> Option { + let ret = insert(&mut self.root, key, value); + if ret.is_none() { self.length += 1 } + ret + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + fn pop(&mut self, key: &K) -> Option { let ret = remove(&mut self.root, key); - if ret { self.length -= 1 } + if ret.is_some() { self.length -= 1 } ret } } +#[cfg(stage0)] pub impl TreeMap { /// Create an empty TreeMap fn new() -> TreeMap { TreeMap{root: None, length: 0} } @@ -189,6 +227,32 @@ pub impl TreeMap { TreeMapIterator{stack: ~[], node: &self.root} } } +#[cfg(not(stage0))] +pub impl TreeMap { + /// Create an empty TreeMap + fn new() -> TreeMap { TreeMap{root: None, length: 0} } + + /// Visit all key-value pairs in reverse order + fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { + each_reverse(&self.root, f) + } + + /// Visit all keys in reverse order + fn each_key_reverse(&self, f: &fn(&K) -> bool) -> bool { + self.each_reverse(|k, _| f(k)) + } + + /// Visit all values in reverse order + fn each_value_reverse(&self, f: &fn(&V) -> bool) -> bool { + self.each_reverse(|_, v| f(v)) + } + + /// Get a lazy iterator over the key-value pairs in the map. + /// Requires that it be frozen (immutable). + fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { + TreeMapIterator{stack: ~[], node: &self.root} + } +} /// Lazy forward iterator over a map pub struct TreeMapIterator<'self, K, V> { @@ -233,17 +297,29 @@ pub struct TreeSet { impl BaseIter for TreeSet { /// Visit all values in order #[inline(always)] + #[cfg(stage0)] fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) } + /// Visit all values in order + #[inline(always)] + #[cfg(not(stage0))] + fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } #[inline(always)] fn size_hint(&self) -> Option { Some(self.len()) } } impl ReverseIter for TreeSet { /// Visit all values in reverse order + #[cfg(stage0)] #[inline(always)] fn each_reverse(&self, f: &fn(&T) -> bool) { self.map.each_key_reverse(f) } + /// Visit all values in reverse order + #[cfg(not(stage0))] + #[inline(always)] + fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { + self.map.each_key_reverse(f) + } } impl Eq for TreeSet { @@ -348,6 +424,7 @@ impl Set for TreeSet { } /// Visit the values (in-order) representing the difference + #[cfg(stage0)] fn difference(&self, other: &TreeSet, f: &fn(&T) -> bool) { let mut x = self.iter(); let mut y = other.iter(); @@ -376,8 +453,38 @@ impl Set for TreeSet { } } } + /// Visit the values (in-order) representing the difference + #[cfg(not(stage0))] + fn difference(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { + let mut x = self.iter(); + let mut y = other.iter(); + + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + return f(a.unwrap()) && x.advance(f); + } + + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + let cmp = a1.cmp(b1); + + if cmp == Less { + if !f(a1) { return false; } + a = x.next(); + } else { + if cmp == Equal { a = x.next() } + b = y.next(); + } + } + return true; + } /// Visit the values (in-order) representing the symmetric difference + #[cfg(stage0)] fn symmetric_difference(&self, other: &TreeSet, f: &fn(&T) -> bool) { let mut x = self.iter(); @@ -414,8 +521,43 @@ impl Set for TreeSet { if f(b1) { y.next() } else { None } } } + /// Visit the values (in-order) representing the symmetric difference + #[cfg(not(stage0))] + fn symmetric_difference(&self, other: &TreeSet, + f: &fn(&T) -> bool) -> bool { + let mut x = self.iter(); + let mut y = other.iter(); + + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + return f(a.unwrap()) && x.advance(f); + } + + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + let cmp = a1.cmp(b1); + + if cmp == Less { + if !f(a1) { return false; } + a = x.next(); + } else { + if cmp == Greater { + if !f(b1) { return false; } + } else { + a = x.next(); + } + b = y.next(); + } + } + return b.each(|&x| f(x)) && y.advance(f); + } /// Visit the values (in-order) representing the intersection + #[cfg(stage0)] fn intersection(&self, other: &TreeSet, f: &fn(&T) -> bool) { let mut x = self.iter(); let mut y = other.iter(); @@ -439,8 +581,35 @@ impl Set for TreeSet { } } } + /// Visit the values (in-order) representing the intersection + #[cfg(not(stage0))] + fn intersection(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { + let mut x = self.iter(); + let mut y = other.iter(); + + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() && b.is_some() { + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + let cmp = a1.cmp(b1); + + if cmp == Less { + a = x.next(); + } else { + if cmp == Equal { + if !f(a1) { return false } + } + b = y.next(); + } + } + return true; + } /// Visit the values (in-order) representing the union + #[cfg(stage0)] fn union(&self, other: &TreeSet, f: &fn(&T) -> bool) { let mut x = self.iter(); let mut y = other.iter(); @@ -475,6 +644,38 @@ impl Set for TreeSet { if f(b1) { y.next() } else { None } } } + /// Visit the values (in-order) representing the union + #[cfg(not(stage0))] + fn union(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { + let mut x = self.iter(); + let mut y = other.iter(); + + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + return f(a.unwrap()) && x.advance(f); + } + + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + let cmp = a1.cmp(b1); + + if cmp == Greater { + if !f(b1) { return false; } + b = y.next(); + } else { + if !f(a1) { return false; } + if cmp == Equal { + b = y.next(); + } + a = x.next(); + } + } + return b.each(|&x| f(x)) && y.advance(f); + } } pub impl TreeSet { @@ -512,20 +713,28 @@ pub impl TreeNode { } } +#[cfg(stage0)] +fn each<'r, K: TotalOrd, V>(_: &'r Option<~TreeNode>, + _: &fn(&'r K, &'r V) -> bool) -> bool { + fail!(~"don't use me in stage0!") +} +#[cfg(not(stage0))] fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) { - for node.each |x| { - each(&x.left, f); - if f(&x.key, &x.value) { each(&x.right, f) } - } + f: &fn(&'r K, &'r V) -> bool) -> bool { + node.each(|x| each(&x.left, f) && f(&x.key, &x.value) && + each(&x.right, f)) } +#[cfg(stage0)] +fn each_reverse<'r, K: TotalOrd, V>(_: &'r Option<~TreeNode>, + _: &fn(&'r K, &'r V) -> bool) -> bool { + fail!(~"don't use me in stage0!") +} +#[cfg(not(stage0))] fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) { - for node.each |x| { - each_reverse(&x.right, f); - if f(&x.key, &x.value) { each_reverse(&x.left, f) } - } + f: &fn(&'r K, &'r V) -> bool) -> bool { + node.each(|x| each_reverse(&x.right, f) && f(&x.key, &x.value) && + each_reverse(&x.left, f)) } fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, @@ -547,8 +756,8 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, fn skew(node: &mut ~TreeNode) { if node.left.map_default(false, |x| x.level == node.level) { let mut save = node.left.swap_unwrap(); - node.left <-> save.right; // save.right now None - *node <-> save; + swap(&mut node.left, &mut save.right); // save.right now None + swap(node, &mut save); node.right = Some(save); } } @@ -559,9 +768,9 @@ fn split(node: &mut ~TreeNode) { if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) { let mut save = node.right.swap_unwrap(); - node.right <-> save.left; // save.left now None + swap(&mut node.right, &mut save.left); // save.left now None save.level += 1; - *node <-> save; + swap(node, &mut save); node.left = Some(save); } } @@ -581,7 +790,8 @@ fn find_mut<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, } } -fn insert(node: &mut Option<~TreeNode>, key: K, value: V) -> bool { +fn insert(node: &mut Option<~TreeNode>, + key: K, value: V) -> Option { match *node { Some(ref mut save) => { match key.cmp(&save.key) { @@ -599,41 +809,40 @@ fn insert(node: &mut Option<~TreeNode>, key: K, value: V) } Equal => { save.key = key; - save.value = value; - false + Some(replace(&mut save.value, value)) } } } None => { *node = Some(~TreeNode::new(key, value)); - true + None } } } fn remove(node: &mut Option<~TreeNode>, - key: &K) -> bool { + key: &K) -> Option { fn heir_swap(node: &mut ~TreeNode, - child: &mut Option<~TreeNode>) { + child: &mut Option<~TreeNode>) { // *could* be done without recursion, but it won't borrow check for child.each_mut |x| { if x.right.is_some() { heir_swap(node, &mut x.right); } else { - node.key <-> x.key; - node.value <-> x.value; + swap(&mut node.key, &mut x.key); + swap(&mut node.value, &mut x.value); } } } match *node { None => { - return false // bottom of tree + return None; // bottom of tree } Some(ref mut save) => { - let (removed, this) = match key.cmp(&save.key) { - Less => (remove(&mut save.left, key), false), - Greater => (remove(&mut save.right, key), false), + let (ret, rebalance) = match key.cmp(&save.key) { + Less => (remove(&mut save.left, key), true), + Greater => (remove(&mut save.right, key), true), Equal => { if save.left.is_some() { if save.right.is_some() { @@ -641,25 +850,28 @@ fn remove(node: &mut Option<~TreeNode>, if left.right.is_some() { heir_swap(save, &mut left.right); } else { - save.key <-> left.key; - save.value <-> left.value; + swap(&mut save.key, &mut left.key); + swap(&mut save.value, &mut left.value); } save.left = Some(left); - remove(&mut save.left, key); + (remove(&mut save.left, key), true) } else { + let new = save.left.swap_unwrap(); + let ~TreeNode{value, _} = replace(save, new); *save = save.left.swap_unwrap(); + (Some(value), true) } - (true, false) } else if save.right.is_some() { - *save = save.right.swap_unwrap(); - (true, false) + let new = save.right.swap_unwrap(); + let ~TreeNode{value, _} = replace(save, new); + (Some(value), true) } else { - (true, true) + (None, false) } } }; - if !this { + if rebalance { let left_level = save.left.map_default(0, |x| x.level); let right_level = save.right.map_default(0, |x| x.level); @@ -682,13 +894,13 @@ fn remove(node: &mut Option<~TreeNode>, for save.right.each_mut |x| { split(x) } } - return removed; + return ret; } } } - - *node = None; - true + return match replace(node, None) { + Some(~TreeNode{value, _}) => Some(value), None => fail!() + }; } #[cfg(test)] @@ -832,7 +1044,7 @@ mod test_treemap { check_equal(ctrl, &map); assert!(map.find(&5).is_none()); - let rng = rand::IsaacRng::new_seeded(&[42]); + let mut rng = rand::IsaacRng::new_seeded(&[42]); for 3.times { for 90.times { @@ -1114,7 +1326,7 @@ mod test_set { } fn check(a: &[int], b: &[int], expected: &[int], - f: &fn(&TreeSet, &TreeSet, f: &fn(&int) -> bool)) { + f: &fn(&TreeSet, &TreeSet, f: &fn(&int) -> bool) -> bool) { let mut set_a = TreeSet::new(); let mut set_b = TreeSet::new(); @@ -1217,4 +1429,20 @@ mod test_set { let result: Option<(&uint, & &'static str)> = z.next(); assert!(result.is_none()); } + + #[test] + fn test_swap() { + let mut m = TreeMap::new(); + assert!(m.swap(1, 2) == None); + assert!(m.swap(1, 3) == Some(2)); + assert!(m.swap(1, 4) == Some(3)); + } + + #[test] + fn test_pop() { + let mut m = TreeMap::new(); + m.insert(1, 2); + assert!(m.pop(&1) == Some(2)); + assert!(m.pop(&1) == None); + } } diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index e49cee434f81f..97df64d526617 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -62,7 +62,9 @@ fn get_monitor_task_gl() -> IoTask { } }; if installed { - do task().unlinked().spawn() { + let mut task = task(); + task.unlinked(); + do task.spawn { unsafe { debug!("global monitor task starting"); // As a weak task the runtime will notify us @@ -88,7 +90,9 @@ fn get_monitor_task_gl() -> IoTask { } fn spawn_loop() -> IoTask { - let builder = do task().add_wrapper |task_body| { + let mut builder = task(); + + do builder.add_wrapper |task_body| { let result: ~fn() = || { // The I/O loop task also needs to be weak so it doesn't keep // the runtime alive @@ -107,7 +111,8 @@ fn spawn_loop() -> IoTask { }; result }; - let builder = builder.unlinked(); + + builder.unlinked(); spawn_iotask(builder) } @@ -222,6 +227,6 @@ mod test { exit_po.recv(); }; debug!(~"test_stress_gl_uv_global_loop_high_level_global_timer"+ - ~" exiting sucessfully!"); + ~" exiting successfully!"); } } diff --git a/src/libstd/uv_iotask.rs b/src/libstd/uv_iotask.rs index e19010e8552a2..2922f403f34a6 100644 --- a/src/libstd/uv_iotask.rs +++ b/src/libstd/uv_iotask.rs @@ -36,11 +36,11 @@ impl Clone for IoTask { } } -pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { - +pub fn spawn_iotask(mut task: task::TaskBuilder) -> IoTask { let (iotask_port, iotask_chan) = stream(); - do task.sched_mode(task::SingleThreaded).spawn { + task.sched_mode(task::SingleThreaded); + do task.spawn { debug!("entering libuv task"); run_loop(&iotask_chan); debug!("libuv task exiting"); @@ -243,7 +243,7 @@ fn impl_uv_iotask_async(iotask: &IoTask) { exit_po.recv(); } -// this fn documents the bear minimum neccesary to roll your own +// this fn documents the bear minimum necessary to roll your own // high_level_loop #[cfg(test)] fn spawn_test_loop(exit_ch: ~Chan<()>) -> IoTask { diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 8d7a97e2e483c..a14c048b8ded5 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -269,7 +269,7 @@ pub struct sockaddr_in { } // unix size: 28 .. FIXME #1645 -// stuck with 32 becuse of rust padding structs? +// stuck with 32 because of rust padding structs? #[cfg(target_arch="x86_64")] pub struct sockaddr_in6 { a0: *u8, a1: *u8, @@ -286,7 +286,7 @@ pub struct sockaddr_in6 { } // unix size: 28 .. FIXME #1645 -// stuck with 32 becuse of rust padding structs? +// stuck with 32 because of rust padding structs? pub type addr_in = addr_in_impl::addr_in; #[cfg(unix)] pub mod addr_in_impl { @@ -730,8 +730,7 @@ pub mod uv_ll_struct_stubgen { } #[nolink] -extern mod rustrt { - +extern { // libuv public API unsafe fn rust_uv_loop_new() -> *libc::c_void; unsafe fn rust_uv_loop_delete(lp: *libc::c_void); @@ -780,23 +779,24 @@ extern mod rustrt { // FIXME ref #2064 unsafe fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, - ++after_cb: *u8, - ++addr: *sockaddr_in) -> libc::c_int; + after_cb: *u8, + addr: *sockaddr_in) + -> libc::c_int; // FIXME ref #2064 unsafe fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, - ++addr: *sockaddr_in) -> libc::c_int; + addr: *sockaddr_in) -> libc::c_int; // FIXME ref #2064 unsafe fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, - ++after_cb: *u8, - ++addr: *sockaddr_in6) -> libc::c_int; + after_cb: *u8, + addr: *sockaddr_in6) -> libc::c_int; // FIXME ref #2064 unsafe fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, - ++addr: *sockaddr_in6) -> libc::c_int; + addr: *sockaddr_in6) -> libc::c_int; unsafe fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, - ++name: *sockaddr_in) -> libc::c_int; + name: *sockaddr_in) -> libc::c_int; unsafe fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, - ++name: *sockaddr_in6) ->libc::c_int; + name: *sockaddr_in6) ->libc::c_int; unsafe fn rust_uv_listen(stream: *libc::c_void, backlog: libc::c_int, cb: *u8) -> libc::c_int; @@ -804,7 +804,7 @@ extern mod rustrt { -> libc::c_int; unsafe fn rust_uv_write(req: *libc::c_void, stream: *libc::c_void, - ++buf_in: *uv_buf_t, + buf_in: *uv_buf_t, buf_cnt: libc::c_int, cb: *u8) -> libc::c_int; @@ -843,7 +843,7 @@ extern mod rustrt { unsafe fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6; unsafe fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8; - unsafe fn rust_uv_free_base_of_buf(++buf: uv_buf_t); + unsafe fn rust_uv_free_base_of_buf(buf: uv_buf_t); unsafe fn rust_uv_get_stream_handle_from_connect_req( connect_req: *uv_connect_t) -> *uv_stream_t; @@ -864,8 +864,8 @@ extern mod rustrt { -> *libc::c_void; unsafe fn rust_uv_set_data_for_req(req: *libc::c_void, data: *libc::c_void); - unsafe fn rust_uv_get_base_from_buf(++buf: uv_buf_t) -> *u8; - unsafe fn rust_uv_get_len_from_buf(++buf: uv_buf_t) -> libc::size_t; + unsafe fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; + unsafe fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> libc::size_t; // sizeof testing helpers unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint; @@ -883,49 +883,49 @@ extern mod rustrt { } pub unsafe fn loop_new() -> *libc::c_void { - return rustrt::rust_uv_loop_new(); + return rust_uv_loop_new(); } pub unsafe fn loop_delete(loop_handle: *libc::c_void) { - rustrt::rust_uv_loop_delete(loop_handle); + rust_uv_loop_delete(loop_handle); } pub unsafe fn run(loop_handle: *libc::c_void) { - rustrt::rust_uv_run(loop_handle); + rust_uv_run(loop_handle); } pub unsafe fn close(handle: *T, cb: *u8) { - rustrt::rust_uv_close(handle as *libc::c_void, cb); + rust_uv_close(handle as *libc::c_void, cb); } pub unsafe fn walk(loop_handle: *libc::c_void, cb: *u8, arg: *libc::c_void) { - rustrt::rust_uv_walk(loop_handle, cb, arg); + rust_uv_walk(loop_handle, cb, arg); } pub unsafe fn idle_new() -> *uv_idle_t { - rustrt::rust_uv_idle_new() + rust_uv_idle_new() } pub unsafe fn idle_delete(handle: *uv_idle_t) { - rustrt::rust_uv_idle_delete(handle) + rust_uv_idle_delete(handle) } pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> libc::c_int { - rustrt::rust_uv_idle_init(loop_handle, handle) + rust_uv_idle_init(loop_handle, handle) } pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> libc::c_int { - rustrt::rust_uv_idle_start(handle, cb) + rust_uv_idle_start(handle, cb) } pub unsafe fn idle_stop(handle: *uv_idle_t) -> libc::c_int { - rustrt::rust_uv_idle_stop(handle) + rust_uv_idle_stop(handle) } pub unsafe fn tcp_init(loop_handle: *libc::c_void, handle: *uv_tcp_t) -> libc::c_int { - return rustrt::rust_uv_tcp_init(loop_handle, handle); + return rust_uv_tcp_init(loop_handle, handle); } // FIXME ref #2064 pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, @@ -933,7 +933,7 @@ pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> libc::c_int { - return rustrt::rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, + return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr); } // FIXME ref #2064 @@ -942,40 +942,40 @@ pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> libc::c_int { - return rustrt::rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, + return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr); } // FIXME ref #2064 pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> libc::c_int { - return rustrt::rust_uv_tcp_bind(tcp_server_ptr, + return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); } // FIXME ref #2064 pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> libc::c_int { - return rustrt::rust_uv_tcp_bind6(tcp_server_ptr, + return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr); } pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in) -> libc::c_int { - return rustrt::rust_uv_tcp_getpeername(tcp_handle_ptr, name); + return rust_uv_tcp_getpeername(tcp_handle_ptr, name); } pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->libc::c_int { - return rustrt::rust_uv_tcp_getpeername6(tcp_handle_ptr, name); + return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); } pub unsafe fn listen(stream: *T, backlog: libc::c_int, cb: *u8) -> libc::c_int { - return rustrt::rust_uv_listen(stream as *libc::c_void, backlog, cb); + return rust_uv_listen(stream as *libc::c_void, backlog, cb); } pub unsafe fn accept(server: *libc::c_void, client: *libc::c_void) -> libc::c_int { - return rustrt::rust_uv_accept(server as *libc::c_void, + return rust_uv_accept(server as *libc::c_void, client as *libc::c_void); } @@ -983,57 +983,57 @@ pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> libc::c_int { let buf_ptr = vec::raw::to_ptr(*buf_in); let buf_cnt = vec::len(*buf_in) as i32; - return rustrt::rust_uv_write(req as *libc::c_void, + return rust_uv_write(req as *libc::c_void, stream as *libc::c_void, buf_ptr, buf_cnt, cb); } pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> libc::c_int { - return rustrt::rust_uv_read_start(stream as *libc::c_void, + return rust_uv_read_start(stream as *libc::c_void, on_alloc, on_read); } pub unsafe fn read_stop(stream: *uv_stream_t) -> libc::c_int { - return rustrt::rust_uv_read_stop(stream as *libc::c_void); + return rust_uv_read_stop(stream as *libc::c_void); } pub unsafe fn last_error(loop_handle: *libc::c_void) -> uv_err_t { - return rustrt::rust_uv_last_error(loop_handle); + return rust_uv_last_error(loop_handle); } pub unsafe fn strerror(err: *uv_err_t) -> *libc::c_char { - return rustrt::rust_uv_strerror(err); + return rust_uv_strerror(err); } pub unsafe fn err_name(err: *uv_err_t) -> *libc::c_char { - return rustrt::rust_uv_err_name(err); + return rust_uv_err_name(err); } pub unsafe fn async_init(loop_handle: *libc::c_void, async_handle: *uv_async_t, cb: *u8) -> libc::c_int { - return rustrt::rust_uv_async_init(loop_handle, + return rust_uv_async_init(loop_handle, async_handle, cb); } pub unsafe fn async_send(async_handle: *uv_async_t) { - return rustrt::rust_uv_async_send(async_handle); + return rust_uv_async_send(async_handle); } pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t { let out_buf = uv_buf_t { base: ptr::null(), len: 0 as libc::size_t }; let out_buf_ptr: *uv_buf_t = &out_buf; - rustrt::rust_uv_buf_init(out_buf_ptr, input, len as size_t); + rust_uv_buf_init(out_buf_ptr, input, len as size_t); return out_buf; } pub unsafe fn ip4_addr(ip: &str, port: int) -> sockaddr_in { do str::as_c_str(ip) |ip_buf| { - rustrt::rust_uv_ip4_addr(ip_buf as *u8, + rust_uv_ip4_addr(ip_buf as *u8, port as libc::c_int) } } pub unsafe fn ip6_addr(ip: &str, port: int) -> sockaddr_in6 { do str::as_c_str(ip) |ip_buf| { - rustrt::rust_uv_ip6_addr(ip_buf as *u8, + rust_uv_ip6_addr(ip_buf as *u8, port as libc::c_int) } } @@ -1042,7 +1042,7 @@ pub unsafe fn ip4_name(src: &sockaddr_in) -> ~str { let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]; do vec::as_imm_buf(dst) |dst_buf, size| { - rustrt::rust_uv_ip4_name(to_unsafe_ptr(src), + rust_uv_ip4_name(to_unsafe_ptr(src), dst_buf, size as libc::size_t); // seems that checking the result of uv_ip4_name // doesn't work too well.. @@ -1063,7 +1063,7 @@ pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str { 0u8,0u8,0u8,0u8,0u8,0u8]; do vec::as_imm_buf(dst) |dst_buf, size| { let src_unsafe_ptr = to_unsafe_ptr(src); - let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr, + let result = rust_uv_ip6_name(src_unsafe_ptr, dst_buf, size as libc::size_t); match result { 0i32 => str::raw::from_buf(dst_buf), @@ -1072,23 +1072,23 @@ pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str { } } pub unsafe fn ip4_port(src: &sockaddr_in) -> uint { - rustrt::rust_uv_ip4_port(to_unsafe_ptr(src)) as uint + rust_uv_ip4_port(to_unsafe_ptr(src)) as uint } pub unsafe fn ip6_port(src: &sockaddr_in6) -> uint { - rustrt::rust_uv_ip6_port(to_unsafe_ptr(src)) as uint + rust_uv_ip6_port(to_unsafe_ptr(src)) as uint } pub unsafe fn timer_init(loop_ptr: *libc::c_void, timer_ptr: *uv_timer_t) -> libc::c_int { - return rustrt::rust_uv_timer_init(loop_ptr, timer_ptr); + return rust_uv_timer_init(loop_ptr, timer_ptr); } pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint, repeat: uint) -> libc::c_int { - return rustrt::rust_uv_timer_start(timer_ptr, cb, timeout as libc::c_uint, + return rust_uv_timer_start(timer_ptr, cb, timeout as libc::c_uint, repeat as libc::c_uint); } pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int { - return rustrt::rust_uv_timer_stop(timer_ptr); + return rust_uv_timer_stop(timer_ptr); } pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void, handle: *uv_getaddrinfo_t, @@ -1096,7 +1096,7 @@ pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void, node_name_ptr: *u8, service_name_ptr: *u8, hints: *addrinfo) -> libc::c_int { - rustrt::rust_uv_getaddrinfo(loop_ptr, + rust_uv_getaddrinfo(loop_ptr, handle, cb, node_name_ptr, @@ -1104,7 +1104,7 @@ pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void, hints) } pub unsafe fn freeaddrinfo(res: *addrinfo) { - rustrt::rust_uv_freeaddrinfo(res); + rust_uv_freeaddrinfo(res); } // libuv struct initializers @@ -1130,53 +1130,53 @@ pub fn getaddrinfo_t() -> uv_getaddrinfo_t { // data access helpers pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *libc::c_void { - return rustrt::rust_uv_get_loop_for_uv_handle(handle as *libc::c_void); + return rust_uv_get_loop_for_uv_handle(handle as *libc::c_void); } pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t { - return rustrt::rust_uv_get_stream_handle_from_connect_req( + return rust_uv_get_stream_handle_from_connect_req( connect); } pub unsafe fn get_stream_handle_from_write_req( write_req: *uv_write_t) -> *uv_stream_t { - return rustrt::rust_uv_get_stream_handle_from_write_req( + return rust_uv_get_stream_handle_from_write_req( write_req); } pub unsafe fn get_data_for_uv_loop(loop_ptr: *libc::c_void) -> *libc::c_void { - rustrt::rust_uv_get_data_for_uv_loop(loop_ptr) + rust_uv_get_data_for_uv_loop(loop_ptr) } pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void, data: *libc::c_void) { - rustrt::rust_uv_set_data_for_uv_loop(loop_ptr, data); + rust_uv_set_data_for_uv_loop(loop_ptr, data); } pub unsafe fn get_data_for_uv_handle(handle: *T) -> *libc::c_void { - return rustrt::rust_uv_get_data_for_uv_handle(handle as *libc::c_void); + return rust_uv_get_data_for_uv_handle(handle as *libc::c_void); } pub unsafe fn set_data_for_uv_handle(handle: *T, data: *U) { - rustrt::rust_uv_set_data_for_uv_handle(handle as *libc::c_void, + rust_uv_set_data_for_uv_handle(handle as *libc::c_void, data as *libc::c_void); } pub unsafe fn get_data_for_req(req: *T) -> *libc::c_void { - return rustrt::rust_uv_get_data_for_req(req as *libc::c_void); + return rust_uv_get_data_for_req(req as *libc::c_void); } pub unsafe fn set_data_for_req(req: *T, data: *U) { - rustrt::rust_uv_set_data_for_req(req as *libc::c_void, + rust_uv_set_data_for_req(req as *libc::c_void, data as *libc::c_void); } pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { - return rustrt::rust_uv_get_base_from_buf(buf); + return rust_uv_get_base_from_buf(buf); } pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> libc::size_t { - return rustrt::rust_uv_get_len_from_buf(buf); + return rust_uv_get_len_from_buf(buf); } pub unsafe fn malloc_buf_base_of(suggested_size: libc::size_t) -> *u8 { - return rustrt::rust_uv_malloc_buf_base_of(suggested_size); + return rust_uv_malloc_buf_base_of(suggested_size); } pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rustrt::rust_uv_free_base_of_buf(buf); + rust_uv_free_base_of_buf(buf); } pub unsafe fn get_last_err_info(uv_loop: *libc::c_void) -> ~str { @@ -1202,22 +1202,22 @@ pub struct uv_err_data { } pub unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool { - rustrt::rust_uv_is_ipv4_addrinfo(input) + rust_uv_is_ipv4_addrinfo(input) } pub unsafe fn is_ipv6_addrinfo(input: *addrinfo) -> bool { - rustrt::rust_uv_is_ipv6_addrinfo(input) + rust_uv_is_ipv6_addrinfo(input) } pub unsafe fn get_INADDR_NONE() -> u32 { - rustrt::rust_uv_helper_get_INADDR_NONE() + rust_uv_helper_get_INADDR_NONE() } pub unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo { - rustrt::rust_uv_get_next_addrinfo(input) + rust_uv_get_next_addrinfo(input) } pub unsafe fn addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in { - rustrt::rust_uv_addrinfo_as_sockaddr_in(input) + rust_uv_addrinfo_as_sockaddr_in(input) } pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 { - rustrt::rust_uv_addrinfo_as_sockaddr_in6(input) + rust_uv_addrinfo_as_sockaddr_in6(input) } #[cfg(test)] @@ -1258,7 +1258,7 @@ mod test { extern fn on_read_cb(stream: *uv_stream_t, nread: libc::ssize_t, - ++buf: uv_buf_t) { + buf: uv_buf_t) { unsafe { let nread = nread as int; debug!("CLIENT entering on_read_cb nred: %d", @@ -1376,7 +1376,7 @@ mod test { let tcp_init_result = tcp_init(test_loop as *libc::c_void, tcp_handle_ptr); if (tcp_init_result == 0) { - debug!(~"sucessful tcp_init_result"); + debug!(~"successful tcp_init_result"); debug!(~"building addr..."); let addr = ip4_addr(ip, port); @@ -1444,7 +1444,7 @@ mod test { extern fn on_server_read_cb(client_stream_ptr: *uv_stream_t, nread: libc::ssize_t, - ++buf: uv_buf_t) { + buf: uv_buf_t) { unsafe { let nread = nread as int; if (nread > 0) { @@ -1791,7 +1791,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_tcp_t", - super::rustrt::rust_uv_helper_uv_tcp_t_size() + super::rust_uv_helper_uv_tcp_t_size() ); } } @@ -1800,7 +1800,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_connect_t", - super::rustrt::rust_uv_helper_uv_connect_t_size() + super::rust_uv_helper_uv_connect_t_size() ); } } @@ -1809,7 +1809,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_buf_t", - super::rustrt::rust_uv_helper_uv_buf_t_size() + super::rust_uv_helper_uv_buf_t_size() ); } } @@ -1818,7 +1818,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_write_t", - super::rustrt::rust_uv_helper_uv_write_t_size() + super::rust_uv_helper_uv_write_t_size() ); } } @@ -1828,7 +1828,7 @@ mod test { unsafe { struct_size_check_common::( ~"sockaddr_in", - super::rustrt::rust_uv_helper_sockaddr_in_size() + super::rust_uv_helper_sockaddr_in_size() ); } } @@ -1836,7 +1836,7 @@ mod test { fn test_uv_ll_struct_size_sockaddr_in6() { unsafe { let foreign_handle_size = - super::rustrt::rust_uv_helper_sockaddr_in6_size(); + super::rust_uv_helper_sockaddr_in6_size(); let rust_handle_size = sys::size_of::(); let output = fmt!("sockaddr_in6 -- foreign: %u rust: %u", foreign_handle_size as uint, rust_handle_size); @@ -1855,7 +1855,7 @@ mod test { fn test_uv_ll_struct_size_addr_in() { unsafe { let foreign_handle_size = - super::rustrt::rust_uv_helper_addr_in_size(); + super::rust_uv_helper_addr_in_size(); let rust_handle_size = sys::size_of::(); let output = fmt!("addr_in -- foreign: %u rust: %u", foreign_handle_size as uint, rust_handle_size); @@ -1871,7 +1871,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_async_t", - super::rustrt::rust_uv_helper_uv_async_t_size() + super::rust_uv_helper_uv_async_t_size() ); } } @@ -1881,7 +1881,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_timer_t", - super::rustrt::rust_uv_helper_uv_timer_t_size() + super::rust_uv_helper_uv_timer_t_size() ); } } @@ -1892,7 +1892,7 @@ mod test { unsafe { struct_size_check_common::( ~"uv_getaddrinfo_t", - super::rustrt::rust_uv_helper_uv_getaddrinfo_t_size() + super::rust_uv_helper_uv_getaddrinfo_t_size() ); } } @@ -1903,7 +1903,7 @@ mod test { unsafe { struct_size_check_common::( ~"addrinfo", - super::rustrt::rust_uv_helper_uv_timer_t_size() + super::rust_uv_helper_uv_timer_t_size() ); } } diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index bb4a9e97ea1f4..a9e4ec50c7c09 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[allow(deprecated_mode)]; - use json; use sha1; use serialize::{Encoder, Encodable, Decoder, Decodable}; @@ -17,13 +15,14 @@ use sort; use core::cell::Cell; use core::cmp; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::either::{Either, Left, Right}; use core::hashmap::HashMap; use core::io; use core::pipes::recv; use core::run; use core::to_bytes; +use core::util::replace; /** * @@ -101,6 +100,7 @@ struct WorkKey { name: ~str } +#[cfg(stage0)] impl to_bytes::IterBytes for WorkKey { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { @@ -110,6 +110,13 @@ impl to_bytes::IterBytes for WorkKey { self.name.iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for WorkKey { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.kind.iter_bytes(lsb0, f) && self.name.iter_bytes(lsb0, f) + } +} impl cmp::Ord for WorkKey { fn lt(&self, other: &WorkKey) -> bool { @@ -141,7 +148,7 @@ impl WorkMap { } impl Encodable for WorkMap { - fn encode(&self, s: &S) { + fn encode(&self, s: &mut S) { let mut d = ~[]; for self.each |k, v| { d.push((copy *k, copy *v)) @@ -152,7 +159,7 @@ impl Encodable for WorkMap { } impl Decodable for WorkMap { - fn decode(d: &D) -> WorkMap { + fn decode(d: &mut D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); let mut w = WorkMap::new(); for v.each |&(k, v)| { @@ -171,8 +178,8 @@ struct Database { pub impl Database { fn prepare(&mut self, fn_name: &str, - declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)> - { + declared_inputs: &WorkMap) + -> Option<(WorkMap, WorkMap, ~str)> { let k = json_encode(&(fn_name, declared_inputs)); match self.db_cache.find(&k) { None => None, @@ -231,7 +238,8 @@ struct Work { fn json_encode>(t: &T) -> ~str { do io::with_str_writer |wr| { - t.encode(&json::Encoder(wr)); + let mut encoder = json::Encoder(wr); + t.encode(&mut encoder); } } @@ -239,7 +247,8 @@ fn json_encode>(t: &T) -> ~str { fn json_decode>(s: &str) -> T { do io::with_str_reader(s) |rdr| { let j = result::unwrap(json::from_reader(rdr)); - Decodable::decode(&json::Decoder(j)) + let mut decoder = json::Decoder(j); + Decodable::decode(&mut decoder) } } @@ -339,14 +348,12 @@ impl TPrep for Prep { &self.declared_inputs) && self.all_fresh("discovered input", disc_in) && self.all_fresh("discovered output", disc_out) => { - Work::new(@mut *self, Left(json_decode(*res))) + Work::new(@mut copy *self, Left(json_decode(*res))) } _ => { let (port, chan) = oneshot(); - let mut blk = None; - blk <-> bo; - let blk = blk.unwrap(); + let blk = replace(&mut bo, None).unwrap(); let chan = Cell(chan); do task::spawn { @@ -358,7 +365,7 @@ impl TPrep for Prep { let v = blk(&exe); send_one(chan, (exe, v)); } - Work::new(@mut *self, Right(port)) + Work::new(@mut copy *self, Right(port)) } } } @@ -378,9 +385,7 @@ fn unwrap>( // FIXME(#5121) w: Work) -> T { let mut ww = w; - let mut s = None; - - ww.res <-> s; + let s = replace(&mut ww.res, None); match s { None => fail!(), diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 75782e9ca673f..f266b8871a225 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -81,6 +81,7 @@ static AbiDatas: &'static [AbiData] = &[ AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch}, ]; +#[cfg(stage0)] fn each_abi(op: &fn(abi: Abi) -> bool) { /*! * @@ -93,6 +94,15 @@ fn each_abi(op: &fn(abi: Abi) -> bool) { } } } +#[cfg(not(stage0))] +fn each_abi(op: &fn(abi: Abi) -> bool) -> bool { + /*! + * + * Iterates through each of the defined ABIs. + */ + + AbiDatas.each(|abi_data| op(abi_data.abi)) +} pub fn lookup(name: &str) -> Option { /*! @@ -189,6 +199,7 @@ pub impl AbiSet { self.bits |= (1 << abi.index()); } + #[cfg(stage0)] fn each(&self, op: &fn(abi: Abi) -> bool) { for each_abi |abi| { if self.contains(abi) { @@ -198,6 +209,10 @@ pub impl AbiSet { } } } + #[cfg(not(stage0))] + fn each(&self, op: &fn(abi: Abi) -> bool) -> bool { + each_abi(|abi| !self.contains(abi) || op(abi)) + } fn is_empty(&self) -> bool { self.bits == 0 @@ -252,17 +267,31 @@ pub impl AbiSet { } } +#[cfg(stage0)] impl to_bytes::IterBytes for Abi { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.index().iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for Abi { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.index().iter_bytes(lsb0, f) + } +} +#[cfg(stage0)] impl to_bytes::IterBytes for AbiSet { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.bits.iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for AbiSet { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.bits.iter_bytes(lsb0, f) + } +} impl ToStr for Abi { fn to_str(&self) -> ~str { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ba6fe1cda4f31..f98cbe2e5b996 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -16,7 +16,6 @@ use opt_vec::OptVec; use core::cast; use core::option::{None, Option, Some}; -use core::task; use core::to_bytes; use core::to_str::ToStr; use std::serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -71,36 +70,44 @@ pub type Name = uint; pub type Mrk = uint; impl Encodable for ident { - fn encode(&self, s: &S) { - let intr = match unsafe { - task::local_data::local_data_get(interner_key!()) - } { - None => fail!(~"encode: TLS interner not set up"), - Some(intr) => intr - }; - - s.emit_str(*(*intr).get(*self)); + fn encode(&self, s: &mut S) { + unsafe { + let intr = + match local_data::local_data_get(interner_key!()) { + None => fail!(~"encode: TLS interner not set up"), + Some(intr) => intr + }; + + s.emit_str(*(*intr).get(*self)); + } } } impl Decodable for ident { - fn decode(d: &D) -> ident { + fn decode(d: &mut D) -> ident { let intr = match unsafe { - task::local_data::local_data_get(interner_key!()) + local_data::local_data_get(interner_key!()) } { None => fail!(~"decode: TLS interner not set up"), Some(intr) => intr }; - (*intr).intern(@d.read_str()) + (*intr).intern(d.read_str()) } } +#[cfg(stage0)] impl to_bytes::IterBytes for ident { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.repr.iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for ident { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + self.repr.iter_bytes(lsb0, f) + } +} // Functions may or may not have names. pub type fn_ident = Option; @@ -283,6 +290,7 @@ pub enum binding_mode { bind_infer } +#[cfg(stage0)] impl to_bytes::IterBytes for binding_mode { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { match *self { @@ -296,6 +304,18 @@ impl to_bytes::IterBytes for binding_mode { } } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for binding_mode { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + match *self { + bind_by_copy => 0u8.iter_bytes(lsb0, f), + + bind_by_ref(ref m) => to_bytes::iter_bytes_2(&1u8, m, lsb0, f), + + bind_infer => 2u8.iter_bytes(lsb0, f), + } + } +} #[auto_encode] #[auto_decode] @@ -329,11 +349,18 @@ pub enum pat_ { #[deriving(Eq)] pub enum mutability { m_mutbl, m_imm, m_const, } +#[cfg(stage0)] impl to_bytes::IterBytes for mutability { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for mutability { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (*self as u8).iter_bytes(lsb0, f) + } +} #[auto_encode] #[auto_decode] @@ -344,11 +371,18 @@ pub enum Sigil { ManagedSigil } +#[cfg(stage0)] impl to_bytes::IterBytes for Sigil { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as uint).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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 { @@ -389,7 +423,7 @@ pub enum binop { add, subtract, mul, - quot, + div, rem, and, or, @@ -534,11 +568,13 @@ pub enum expr_ { expr_copy(@expr), expr_assign(@expr, @expr), - expr_swap(@expr, @expr), expr_assign_op(binop, @expr, @expr), expr_field(@expr, ident, ~[@Ty]), expr_index(@expr, @expr), expr_path(@Path), + + /// The special identifier `self`. + expr_self, expr_addr_of(mutability, @expr), expr_break(Option), expr_again(Option), @@ -743,11 +779,18 @@ impl ToStr for int_ty { } } +#[cfg(stage0)] impl to_bytes::IterBytes for int_ty { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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) + } +} #[auto_encode] #[auto_decode] @@ -760,11 +803,18 @@ impl ToStr for uint_ty { } } +#[cfg(stage0)] impl to_bytes::IterBytes for uint_ty { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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) + } +} #[auto_encode] #[auto_decode] @@ -777,11 +827,18 @@ impl ToStr for float_ty { } } +#[cfg(stage0)] impl to_bytes::IterBytes for float_ty { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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. #[auto_encode] @@ -822,11 +879,18 @@ impl ToStr for Onceness { } } +#[cfg(stage0)] impl to_bytes::IterBytes for Onceness { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as uint).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for Onceness { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} #[auto_encode] #[auto_decode] @@ -873,11 +937,18 @@ pub enum ty_ { ty_infer, } +#[cfg(stage0)] impl to_bytes::IterBytes for Ty { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.span.lo, &self.span.hi, lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for Ty { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.span.lo, &self.span.hi, lsb0, f) + } +} #[auto_encode] #[auto_decode] @@ -940,11 +1011,18 @@ impl ToStr for purity { } } +#[cfg(stage0)] impl to_bytes::IterBytes for purity { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for purity { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (*self as u8).iter_bytes(lsb0, f) + } +} #[auto_encode] #[auto_decode] @@ -955,11 +1033,18 @@ pub enum ret_style { return_val, // everything else } +#[cfg(stage0)] impl to_bytes::IterBytes for ret_style { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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) + } +} #[auto_encode] #[auto_decode] @@ -1158,6 +1243,7 @@ pub struct struct_field_ { kind: struct_field_kind, id: node_id, ty: @Ty, + attrs: ~[attribute], } pub type struct_field = spanned; @@ -1166,7 +1252,7 @@ pub type struct_field = spanned; #[auto_decode] #[deriving(Eq)] pub enum struct_field_kind { - named_field(ident, struct_mutability, visibility), + named_field(ident, visibility), unnamed_field // element of a tuple-like struct } @@ -1174,10 +1260,7 @@ pub enum struct_field_kind { #[auto_decode] #[deriving(Eq)] pub struct struct_def { - fields: ~[@struct_field], /* fields */ - /* (not including ctor or dtor) */ - /* dtor is optional */ - dtor: Option, + fields: ~[@struct_field], /* fields, not including ctor */ /* ID of the constructor. This is only used for tuple- or enum-like * structs. */ ctor_id: Option @@ -1219,29 +1302,6 @@ pub enum item_ { item_mac(mac), } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] -pub enum struct_mutability { struct_mutable, struct_immutable } - -impl to_bytes::IterBytes for struct_mutability { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - (*self as u8).iter_bytes(lsb0, f) - } -} - -pub type struct_dtor = spanned; - -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] -pub struct struct_dtor_ { - id: node_id, - attrs: ~[attribute], - self_id: node_id, - body: blk, -} - #[auto_encode] #[auto_decode] #[deriving(Eq)] @@ -1272,7 +1332,6 @@ pub enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), ii_foreign(@foreign_item), - ii_dtor(struct_dtor, ident, Generics, def_id /* parent id */) } /* hold off on tests ... they appear in a later merge. @@ -1303,6 +1362,21 @@ mod test { assert_eq! (s,~[14]); } + #[test] fn test_marksof () { + let stopname = uints_to_name(&~[12,14,78]); + assert_eq!(s,~[]); + xorPush(&mut s,14); + assert_eq!(s,~[14]); + xorPush(&mut s,15); + assert_eq!(s,~[14,15]); + xorPush (&mut s,16); + assert_eq! (s,~[14,15,16]); + xorPush (&mut s,16); + assert_eq! (s,~[14,15]); + xorPush (&mut s,15); + assert_eq! (s,~[14]); + } + #[test] fn test_marksof () { let stopname = uints_to_name(&~[12,14,78]); let name1 = uints_to_name(&~[4,9,7]); diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index f9828ad2b9e4e..77a02adbafba7 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -14,11 +14,11 @@ use ast; use ast_util::{inlined_item_utils, stmt_id}; use ast_util; use codemap; -use codemap::spanned; use diagnostic::span_handler; use parse::token::ident_interner; use print::pprust; use visit; +use syntax::parse::token::special_idents; use core::hashmap::HashMap; @@ -89,14 +89,11 @@ pub enum ast_node { node_variant(variant, @item, @path), node_expr(@expr), node_stmt(@stmt), - // Locals are numbered, because the alias analysis needs to know in which - // order they are introduced. - node_arg(arg, uint), - node_local(uint), - // Destructor for a struct - node_dtor(Generics, @struct_dtor, def_id, @path), + node_arg, + node_local(ident), node_block(blk), node_struct_ctor(@struct_def, @item, @path), + node_callee_scope(@expr) } pub type map = @mut HashMap; @@ -104,7 +101,6 @@ pub type map = @mut HashMap; pub struct Ctx { map: map, path: path, - local_id: uint, diag: @span_handler, } @@ -120,9 +116,8 @@ pub fn mk_ast_map_visitor() -> vt { visit_expr: map_expr, visit_stmt: map_stmt, visit_fn: map_fn, - visit_local: map_local, - visit_arm: map_arm, visit_block: map_block, + visit_pat: map_pat, .. *visit::default_visitor() }); } @@ -131,7 +126,6 @@ pub fn map_crate(diag: @span_handler, c: @crate) -> map { let cx = @mut Ctx { map: @mut HashMap::new(), path: ~[], - local_id: 0u, diag: diag, }; visit::visit_crate(c, cx, mk_ast_map_visitor()); @@ -154,7 +148,6 @@ pub fn map_decoded_item(diag: @span_handler, let cx = @mut Ctx { map: map, path: copy path, - local_id: 0, diag: diag, }; let v = mk_ast_map_visitor(); @@ -163,7 +156,7 @@ pub fn map_decoded_item(diag: @span_handler, // don't decode and instantiate the impl, but just the method, we have to // add it to the table now: match *ii { - ii_item(*) | ii_dtor(*) => { /* fallthrough */ } + ii_item(*) => { /* fallthrough */ } ii_foreign(i) => { cx.map.insert(i.id, node_foreign_item(i, AbiSet::Intrinsic(), @@ -189,30 +182,7 @@ pub fn map_fn( v: visit::vt<@mut Ctx> ) { for decl.inputs.each |a| { - cx.map.insert(a.id, - node_arg(/* FIXME (#2543) */ copy *a, cx.local_id)); - cx.local_id += 1u; - } - match *fk { - visit::fk_dtor(generics, ref attrs, self_id, parent_id) => { - let dt = @spanned { - node: ast::struct_dtor_ { - id: id, - attrs: /* FIXME (#2543) */ vec::from_slice(*attrs), - self_id: self_id, - body: /* FIXME (#2543) */ copy *body, - }, - span: sp, - }; - cx.map.insert( - id, - node_dtor( - /* FIXME (#2543) */ copy *generics, - dt, - parent_id, - @/* FIXME (#2543) */ copy cx.path)); - } - _ => () + cx.map.insert(a.id, node_arg); } visit::visit_fn(fk, decl, body, sp, id, cx, v); } @@ -222,33 +192,22 @@ pub fn map_block(b: &blk, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { visit::visit_block(b, cx, v); } -pub fn number_pat(cx: @mut Ctx, pat: @pat) { - do ast_util::walk_pat(pat) |p| { - match p.node { - pat_ident(*) => { - cx.map.insert(p.id, node_local(cx.local_id)); - cx.local_id += 1u; - } - _ => () +pub fn map_pat(pat: @pat, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { + match pat.node { + pat_ident(_, path, _) => { + // Note: this is at least *potentially* a pattern... + cx.map.insert(pat.id, node_local(ast_util::path_to_ident(path))); } - }; -} - -pub fn map_local(loc: @local, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { - number_pat(cx, loc.node.pat); - visit::visit_local(loc, cx, v); -} + _ => () + } -pub fn map_arm(arm: &arm, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { - number_pat(cx, arm.pats[0]); - visit::visit_arm(arm, cx, v); + visit::visit_pat(pat, cx, v); } pub fn map_method(impl_did: def_id, impl_path: @path, m: @method, cx: @mut Ctx) { cx.map.insert(m.id, node_method(m, impl_did, impl_path)); - cx.map.insert(m.self_id, node_local(cx.local_id)); - cx.local_id += 1u; + cx.map.insert(m.self_id, node_local(special_idents::self_)); } pub fn map_item(i: @item, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { @@ -317,6 +276,7 @@ pub fn map_item(i: @item, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { } _ => () } + match i.node { item_mod(_) | item_foreign_mod(_) => { cx.path.push(path_mod(i.ident)); @@ -352,6 +312,18 @@ pub fn map_struct_def( pub fn map_expr(ex: @expr, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { cx.map.insert(ex.id, node_expr(ex)); + match ex.node { + // Expressions which are or might be calls: + ast::expr_call(*) | + ast::expr_method_call(*) | + ast::expr_index(*) | + ast::expr_binary(*) | + ast::expr_assign_op(*) | + ast::expr_unary(*) => { + cx.map.insert(ex.callee_id, node_callee_scope(ex)); + } + _ => {} + } visit::visit_expr(ex, cx, v); } @@ -401,18 +373,18 @@ pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { Some(&node_expr(expr)) => { fmt!("expr %s (id=%?)", pprust::expr_to_str(expr, itr), id) } + Some(&node_callee_scope(expr)) => { + fmt!("callee_scope %s (id=%?)", pprust::expr_to_str(expr, itr), id) + } Some(&node_stmt(stmt)) => { fmt!("stmt %s (id=%?)", pprust::stmt_to_str(stmt, itr), id) } - Some(&node_arg(_, _)) => { // add more info here + Some(&node_arg) => { fmt!("arg (id=%?)", id) } - Some(&node_local(_)) => { // add more info here - fmt!("local (id=%?)", id) - } - Some(&node_dtor(*)) => { // add more info here - fmt!("node_dtor (id=%?)", id) + Some(&node_local(ident)) => { + fmt!("local (id=%?, name=%s)", id, *itr.get(ident)) } Some(&node_block(_)) => { fmt!("block") @@ -431,11 +403,3 @@ pub fn node_item_query(items: map, id: node_id, _ => fail!(error_msg) } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 148b713a4f58f..ceff868d11f21 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -11,7 +11,7 @@ use ast::*; use ast; use ast_util; -use codemap::{span, dummy_sp, spanned}; +use codemap::{span, spanned}; use parse::token; use visit; use opt_vec; @@ -41,12 +41,12 @@ pub fn stmt_id(s: &stmt) -> node_id { } } -pub fn variant_def_ids(d: def) -> (def_id, def_id) { +pub fn variant_def_ids(d: def) -> Option<(def_id, def_id)> { match d { def_variant(enum_id, var_id) => { - return (enum_id, var_id); + Some((enum_id, var_id)) } - _ => fail!(~"non-variant in variant_def_ids") + _ => None } } @@ -73,7 +73,7 @@ pub fn binop_to_str(op: binop) -> ~str { add => return ~"+", subtract => return ~"-", mul => return ~"*", - quot => return ~"/", + div => return ~"/", rem => return ~"%", and => return ~"&&", or => return ~"||", @@ -96,7 +96,7 @@ pub fn binop_to_method_name(op: binop) -> Option<~str> { add => return Some(~"add"), subtract => return Some(~"sub"), mul => return Some(~"mul"), - quot => return Some(~"quot"), + div => return Some(~"div"), rem => return Some(~"rem"), bitxor => return Some(~"bitxor"), bitand => return Some(~"bitand"), @@ -191,12 +191,21 @@ pub fn is_call_expr(e: @expr) -> bool { } // This makes def_id hashable +#[cfg(stage0)] impl to_bytes::IterBytes for def_id { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.crate, &self.node, lsb0, f); } } +// This makes def_id hashable +#[cfg(not(stage0))] +impl to_bytes::IterBytes for def_id { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + to_bytes::iter_bytes_2(&self.crate, &self.node, lsb0, f) + } +} pub fn block_from_expr(e: @expr) -> blk { let blk_ = default_block(~[], option::Some::<@expr>(e), e.id); @@ -285,7 +294,7 @@ pub fn split_trait_methods(trait_methods: &[trait_method]) pub fn struct_field_visibility(field: ast::struct_field) -> visibility { match field.node.kind { - ast::named_field(_, _, visibility) => visibility, + ast::named_field(_, visibility) => visibility, ast::unnamed_field => ast::public } } @@ -302,7 +311,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => /* FIXME (#2543) */ copy i.ident, ii_foreign(i) => /* FIXME (#2543) */ copy i.ident, ii_method(_, m) => /* FIXME (#2543) */ copy m.ident, - ii_dtor(_, nm, _, _) => /* FIXME (#2543) */ copy nm } } @@ -311,7 +319,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => i.id, ii_foreign(i) => i.id, ii_method(_, m) => m.id, - ii_dtor(ref dtor, _, _, _) => (*dtor).node.id } } @@ -320,10 +327,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => (v.visit_item)(i, e, v), ii_foreign(i) => (v.visit_foreign_item)(i, e, v), ii_method(_, m) => visit::visit_method_helper(m, e, v), - ii_dtor(/*bad*/ copy dtor, _, ref generics, parent_id) => { - visit::visit_struct_dtor_helper(dtor, generics, - parent_id, e, v); - } } } } @@ -341,7 +344,7 @@ pub fn is_self(d: ast::def) -> bool { /// Maps a binary operator to its precedence pub fn operator_prec(op: ast::binop) -> uint { match op { - mul | quot | rem => 12u, + mul | div | rem => 12u, // 'as' sits between here with 11 add | subtract => 10u, shl | shr => 9u, @@ -359,20 +362,6 @@ pub fn operator_prec(op: ast::binop) -> uint { /// not appearing in the prior table. pub static as_prec: uint = 11u; -pub fn dtor_ty() -> @ast::Ty { - @ast::Ty {id: 0, node: ty_nil, span: dummy_sp()} -} - -pub fn dtor_dec() -> fn_decl { - let nil_t = dtor_ty(); - // dtor has no args - ast::fn_decl { - inputs: ~[], - output: nil_t, - cf: return_val, - } -} - pub fn empty_generics() -> Generics { Generics {lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty} @@ -388,8 +377,20 @@ pub struct id_range { max: node_id, } -pub fn empty(range: id_range) -> bool { - range.min >= range.max +pub impl id_range { + fn max() -> id_range { + id_range {min: int::max_value, + max: int::min_value} + } + + fn empty(&self) -> bool { + self.min >= self.max + } + + fn add(&mut self, id: node_id) { + self.min = int::min(self.min, id); + self.max = int::max(self.max, id + 1); + } } pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { @@ -457,12 +458,6 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { vfn(id); match *fk { - visit::fk_dtor(generics, _, self_id, parent_id) => { - visit_generics(generics); - vfn(id); - vfn(self_id); - vfn(parent_id.node); - } visit::fk_item_fn(_, generics, _, _) => { visit_generics(generics); } @@ -475,7 +470,7 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { } } - for vec::each(d.inputs) |arg| { + for d.inputs.each |arg| { vfn(arg.id) } }, @@ -493,13 +488,11 @@ pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(node_id)) { } pub fn compute_id_range(visit_ids_fn: &fn(@fn(node_id))) -> id_range { - let min = @mut int::max_value; - let max = @mut int::min_value; + let result = @mut id_range::max(); do visit_ids_fn |id| { - *min = int::min(*min, id); - *max = int::max(*max, id + 1); + result.add(id); } - id_range { min: *min, max: *max } + *result } pub fn compute_id_range_for_inlined_item(item: &inlined_item) -> id_range { @@ -858,11 +851,3 @@ mod test { } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2f8405c6e9689..aebe5bbfc748a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -255,7 +255,7 @@ pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str) pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] { // This is sort of stupid here, converting to a vec of mutables and back - let mut v = vec::from_slice(items); + let mut v = vec::to_owned(items); do std::sort::quick_sort(v) |ma, mb| { get_meta_item_name(*ma) <= get_meta_item_name(*mb) } @@ -341,13 +341,3 @@ pub fn require_unique_names(diagnostic: @span_handler, } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1194506a8876f..053ed76d66b2a 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -65,11 +65,18 @@ impl Sub for BytePos { } } +#[cfg(stage0)] impl to_bytes::IterBytes for BytePos { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (**self).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +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) } @@ -83,11 +90,18 @@ impl cmp::Ord for CharPos { fn gt(&self, other: &CharPos) -> bool { **self > **other } } +#[cfg(stage0)] impl to_bytes::IterBytes for CharPos { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (**self).iter_bytes(lsb0, f) } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for CharPos { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (**self).iter_bytes(lsb0, f) + } +} impl Add for CharPos { fn add(&self, rhs: &CharPos) -> CharPos { @@ -127,11 +141,13 @@ impl cmp::Eq for span { impl Encodable for span { /* Note #1972 -- spans are encoded but not decoded */ - fn encode(&self, _s: &S) { _s.emit_nil() } + fn encode(&self, s: &mut S) { + s.emit_nil() + } } impl Decodable for span { - fn decode(_d: &D) -> span { + fn decode(_d: &mut D) -> span { dummy_sp() } } @@ -246,7 +262,7 @@ pub impl FileMap { // the new charpos must be > the last one (or it's the first one). let lines = &mut *self.lines; assert!((lines.len() == 0) || (lines[lines.len() - 1] < pos)); - self.lines.push(pos); + lines.push(pos); } // get a line from the list of pre-computed line-beginnings @@ -308,7 +324,7 @@ pub impl CodeMap { multibyte_chars: @mut ~[], }; - self.files.push(filemap); + files.push(filemap); return filemap; } @@ -355,7 +371,7 @@ pub impl CodeMap { } pub fn span_to_str(&self, sp: span) -> ~str { - let files = &mut *self.files; + let files = &*self.files; if files.len() == 0 && sp == dummy_sp() { return ~"no-location"; } @@ -522,15 +538,3 @@ mod test { fm.next_line(BytePos(2)); } } - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 0f2374a892b4a..b313a2fc6fcc9 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -24,6 +24,7 @@ pub trait handler { fn fatal(@mut self, msg: &str) -> !; fn err(@mut self, msg: &str); fn bump_err_count(@mut self); + fn err_count(@mut self) -> uint; fn has_errors(@mut self) -> bool; fn abort_if_errors(@mut self); fn warn(@mut self, msg: &str); @@ -98,7 +99,12 @@ impl handler for HandlerT { fn bump_err_count(@mut self) { self.err_count += 1u; } - fn has_errors(@mut self) -> bool { self.err_count > 0u } + fn err_count(@mut self) -> uint { + self.err_count + } + fn has_errors(@mut self) -> bool { + self.err_count > 0u + } fn abort_if_errors(@mut self) { let s; match self.err_count { diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index dfebf6f786a28..00c178b6d7c16 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -41,7 +41,7 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), - vec::from_slice(tts)); + vec::to_owned(tts)); let mut asm = ~""; let mut outputs = ~[]; @@ -187,15 +187,3 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) span: sp }) } - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 2ceb6f0c4bb75..e1416230720fc 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -238,12 +238,14 @@ trait ExtCtxtMethods { fn stmt(&self, expr: @ast::expr) -> @ast::stmt; fn lit_str(&self, span: span, s: @~str) -> @ast::expr; fn lit_uint(&self, span: span, i: uint) -> @ast::expr; - fn lambda(&self, blk: ast::blk) -> @ast::expr; + fn lambda0(&self, blk: ast::blk) -> @ast::expr; + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr; fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk; fn expr_blk(&self, expr: @ast::expr) -> ast::blk; fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; - fn expr_var(&self, span: span, var: ~str) -> @ast::expr; + fn expr_var(&self, span: span, var: &str) -> @ast::expr; + fn expr_self(&self, span: span) -> @ast::expr; fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident) -> @ast::expr; fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr]) @@ -254,8 +256,15 @@ trait ExtCtxtMethods { ident: ast::ident, args: ~[@ast::expr]) -> @ast::expr; - fn lambda_expr(&self, expr: @ast::expr) -> @ast::expr; - fn lambda_stmts(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr; + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr; + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr; } impl ExtCtxtMethods for @ext_ctxt { @@ -388,12 +397,18 @@ impl ExtCtxtMethods for @ext_ctxt { span: span})) } - fn lambda(&self, blk: ast::blk) -> @ast::expr { + fn lambda0(&self, blk: ast::blk) -> @ast::expr { let ext_cx = *self; let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); quote_expr!( || $blk_e ) } + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr { + let ext_cx = *self; + let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); + quote_expr!( |$ident| $blk_e ) + } + fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk { codemap::spanned { node: ast::blk_ { @@ -432,10 +447,14 @@ impl ExtCtxtMethods for @ext_ctxt { self.expr(span, ast::expr_path(self.path_global(span, strs))) } - fn expr_var(&self, span: span, var: ~str) -> @ast::expr { + fn expr_var(&self, span: span, var: &str) -> @ast::expr { self.expr_path(span, ~[self.ident_of(var)]) } + fn expr_self(&self, span: span) -> @ast::expr { + self.expr(span, ast::expr_self) + } + fn expr_field( &self, span: span, @@ -461,15 +480,29 @@ impl ExtCtxtMethods for @ext_ctxt { ident: ast::ident, args: ~[@ast::expr] ) -> @ast::expr { - self.expr(span, ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) + self.expr(span, + ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) + } + + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr { + self.lambda0(self.expr_blk(expr)) + } + + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr { + self.lambda1(self.expr_blk(expr), ident) } - fn lambda_expr(&self, expr: @ast::expr) -> @ast::expr { - self.lambda(self.expr_blk(expr)) + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { + self.lambda0(self.blk(span, stmts)) } - fn lambda_stmts(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { - self.lambda(self.blk(span, stmts)) + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr { + self.lambda1(self.blk(span, stmts), ident) } } @@ -555,13 +588,13 @@ fn mk_ser_impl( // Make a path to the std::serialize::Encodable typaram. let ty_param = cx.bind_path( span, - cx.ident_of(~"__S"), + cx.ident_of("__S"), cx.path_global( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Encoder"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Encoder"), ] ), @opt_vec::Empty @@ -571,11 +604,11 @@ fn mk_ser_impl( let path = cx.path_tps_global( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Encodable"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Encodable"), ], - ~[cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[])] + ~[cx.ty_path(span, ~[cx.ident_of("__S")], ~[])] ); mk_impl( @@ -599,13 +632,13 @@ fn mk_deser_impl( // Make a path to the std::serialize::Decodable typaram. let ty_param = cx.bind_path( span, - cx.ident_of(~"__D"), + cx.ident_of("__D"), cx.path_global( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decoder"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decoder"), ] ), @opt_vec::Empty @@ -615,11 +648,11 @@ fn mk_deser_impl( let path = cx.path_tps_global( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decodable"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decodable"), ], - ~[cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[])] + ~[cx.ty_path(span, ~[cx.ident_of("__D")], ~[])] ); mk_impl( @@ -643,8 +676,8 @@ fn mk_ser_method( node: ast::ty_rptr( None, ast::mt { - ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]), - mutbl: ast::m_imm + ty: cx.ty_path(span, ~[cx.ident_of("__S")], ~[]), + mutbl: ast::m_mutbl } ), span: span, @@ -657,7 +690,7 @@ fn mk_ser_method( id: cx.next_id(), node: ast::pat_ident( ast::bind_by_copy, - ast_util::ident_to_path(span, cx.ident_of(~"__s")), + ast_util::ident_to_path(span, cx.ident_of("__s")), None), span: span, }, @@ -677,7 +710,7 @@ fn mk_ser_method( }; @ast::method { - ident: cx.ident_of(~"encode"), + ident: cx.ident_of("encode"), attrs: ~[], generics: ast_util::empty_generics(), self_ty: codemap::spanned { @@ -705,8 +738,8 @@ fn mk_deser_method( node: ast::ty_rptr( None, ast::mt { - ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]), - mutbl: ast::m_imm + ty: cx.ty_path(span, ~[cx.ident_of("__D")], ~[]), + mutbl: ast::m_mutbl } ), span: span, @@ -721,7 +754,7 @@ fn mk_deser_method( node: ast::pat_ident(ast::bind_by_copy, ast_util::ident_to_path(span, cx.ident_of( - ~"__d")), + "__d")), None), span: span, }, @@ -736,7 +769,7 @@ fn mk_deser_method( }; @ast::method { - ident: cx.ident_of(~"decode"), + ident: cx.ident_of("decode"), attrs: ~[], generics: ast_util::empty_generics(), self_ty: codemap::spanned { node: ast::sty_static, span: span }, @@ -758,26 +791,23 @@ fn mk_struct_ser_impl( generics: &ast::Generics ) -> @ast::item { let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|| self.$(name).encode(__s)` - let expr_lambda = cx.lambda_expr( + // ast for `|__s| self.$(name).encode(__s)` + let expr_lambda = cx.lambda_expr_1( cx.expr_method_call( span, - cx.expr_field( - span, - cx.expr_var(span, ~"self"), - field.ident - ), + cx.expr_field(span, cx.expr_self(span), field.ident), cx.ident_of(~"encode"), - ~[cx.expr_var(span, ~"__s")] - ) + ~[cx.expr_var(span, "__s")] + ), + cx.ident_of("__s") ); // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))` cx.stmt( cx.expr_method_call( span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_struct_field"), + cx.expr_var(span, "__s"), + cx.ident_of("emit_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -787,15 +817,15 @@ fn mk_struct_ser_impl( ) }; - // ast for `__s.emit_struct($(name), || $(fields))` + // ast for `__s.emit_struct($(name), |__s| $(fields))` let ser_body = cx.expr_method_call( span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_struct"), + cx.expr_var(span, "__s"), + cx.ident_of("emit_struct"), ~[ cx.lit_str(span, @cx.str_of(ident)), cx.lit_uint(span, vec::len(fields)), - cx.lambda_stmts(span, fields), + cx.lambda_stmts_1(span, fields, cx.ident_of("__s")), ] ); @@ -810,27 +840,28 @@ fn mk_struct_deser_impl( generics: &ast::Generics ) -> @ast::item { let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|| std::serialize::decode(__d)` - let expr_lambda = cx.lambda( + // ast for `|__d| std::serialize::decode(__d)` + let expr_lambda = cx.lambda1( cx.expr_blk( cx.expr_call( span, cx.expr_path_global(span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decodable"), - cx.ident_of(~"decode"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decodable"), + cx.ident_of("decode"), ]), - ~[cx.expr_var(span, ~"__d")] + ~[cx.expr_var(span, "__d")] ) - ) + ), + cx.ident_of("__d") ); // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))` let expr: @ast::expr = cx.expr_method_call( span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_struct_field"), + cx.expr_var(span, "__d"), + cx.ident_of("read_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -848,15 +879,15 @@ fn mk_struct_deser_impl( } }; - // ast for `read_struct($(name), || $(fields))` + // ast for `read_struct($(name), |__d| $(fields))` let body = cx.expr_method_call( span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_struct"), + cx.expr_var(span, "__d"), + cx.ident_of("read_struct"), ~[ cx.lit_str(span, @cx.str_of(ident)), cx.lit_uint(span, vec::len(fields)), - cx.lambda_expr( + cx.lambda_expr_1( cx.expr( span, ast::expr_struct( @@ -864,7 +895,8 @@ fn mk_struct_deser_impl( fields, None ) - ) + ), + cx.ident_of("__d") ), ] ); @@ -883,19 +915,15 @@ struct field { fn mk_struct_fields(fields: &[@ast::struct_field]) -> ~[field] { do fields.map |field| { - let (ident, mutbl) = match field.node.kind { - ast::named_field(ident, mutbl, _) => (ident, mutbl), - _ => fail!(~"[auto_encode] does not support \ - unnamed fields") + let ident = match field.node.kind { + ast::named_field(ident, _) => ident, + _ => fail!(~"[auto_encode] does not support unnamed fields") }; field { span: field.span, ident: ident, - mutbl: match mutbl { - ast::struct_mutable => ast::m_mutbl, - ast::struct_immutable => ast::m_imm, - }, + mutbl: ast::m_imm, } } } @@ -970,18 +998,19 @@ fn ser_variant( // ast for `__s.emit_enum_variant_arg` let expr_emit = cx.expr_field( span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum_variant_arg") + cx.expr_var(span, "__s"), + cx.ident_of("emit_enum_variant_arg") ); - // ast for `|| $(v).encode(__s)` - let expr_encode = cx.lambda_expr( - cx.expr_method_call( + // ast for `|__s| $(v).encode(__s)` + let expr_encode = cx.lambda_expr_1( + cx.expr_method_call( span, cx.expr_path(span, ~[names[a_idx]]), - cx.ident_of(~"encode"), - ~[cx.expr_var(span, ~"__s")] - ) + cx.ident_of("encode"), + ~[cx.expr_var(span, "__s")] + ), + cx.ident_of("__s") ); // ast for `$(expr_emit)($(a_idx), $(expr_encode))` @@ -997,13 +1026,13 @@ fn ser_variant( // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))` let body = cx.expr_method_call( span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum_variant"), + cx.expr_var(span, "__s"), + cx.ident_of("emit_enum_variant"), ~[ cx.lit_str(span, @cx.str_of(v_name)), cx.lit_uint(span, v_idx), cx.lit_uint(span, stmts.len()), - cx.lambda_stmts(span, stmts), + cx.lambda_stmts_1(span, stmts, cx.ident_of("__s")), ] ); @@ -1034,23 +1063,20 @@ fn mk_enum_ser_body( // ast for `match *self { $(arms) }` let match_expr = cx.expr( span, - ast::expr_match( - cx.expr( - span, - ast::expr_unary(ast::deref, cx.expr_var(span, ~"self")) - ), - arms - ) + ast::expr_match(cx.expr(span, + ast::expr_unary(ast::deref, + cx.expr_self(span))), + arms) ); // ast for `__s.emit_enum($(name), || $(match_expr))` cx.expr_method_call( span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum"), + cx.expr_var(span, "__s"), + cx.ident_of("emit_enum"), ~[ cx.lit_str(span, @cx.str_of(name)), - cx.lambda_expr(match_expr), + cx.lambda_expr_1(match_expr, cx.ident_of("__s")), ] ) } @@ -1062,25 +1088,26 @@ fn mk_enum_deser_variant_nary( args: ~[ast::variant_arg] ) -> @ast::expr { let args = do args.mapi |idx, _arg| { - // ast for `|| std::serialize::decode(__d)` - let expr_lambda = cx.lambda_expr( + // ast for `|__s| std::serialize::decode(__d)` + let expr_lambda = cx.lambda_expr_1( cx.expr_call( span, cx.expr_path_global(span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decodable"), - cx.ident_of(~"decode"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decodable"), + cx.ident_of("decode"), ]), - ~[cx.expr_var(span, ~"__d")] - ) + ~[cx.expr_var(span, "__d")] + ), + cx.ident_of("__d") ); // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` cx.expr_method_call( span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_enum_variant_arg"), + cx.expr_var(span, "__d"), + cx.ident_of("read_enum_variant_arg"), ~[cx.lit_uint(span, idx), expr_lambda] ) }; @@ -1163,24 +1190,44 @@ fn mk_enum_deser_body( span, ast::expr_fn_block( ast::fn_decl { - inputs: ~[ast::arg { - is_mutbl: false, - ty: @ast::Ty { + inputs: ~[ + ast::arg { + is_mutbl: false, + ty: @ast::Ty { + id: ext_cx.next_id(), + node: ast::ty_infer, + span: span + }, + pat: @ast::pat { + id: ext_cx.next_id(), + node: ast::pat_ident( + ast::bind_by_copy, + ast_util::ident_to_path(span, + ext_cx.ident_of("__d")), + None), + span: span, + }, id: ext_cx.next_id(), - node: ast::ty_infer, - span: span }, - pat: @ast::pat { + ast::arg { + is_mutbl: false, + ty: @ast::Ty { + id: ext_cx.next_id(), + node: ast::ty_infer, + span: span + }, + pat: @ast::pat { + id: ext_cx.next_id(), + node: ast::pat_ident( + ast::bind_by_copy, + ast_util::ident_to_path(span, + ext_cx.ident_of("i")), + None), + span: span, + }, id: ext_cx.next_id(), - node: ast::pat_ident( - ast::bind_by_copy, - ast_util::ident_to_path(span, - ext_cx.ident_of(~"i")), - None), - span: span, - }, - id: ext_cx.next_id(), - }], + } + ], output: @ast::Ty { id: ext_cx.next_id(), node: ast::ty_infer, @@ -1191,27 +1238,28 @@ fn mk_enum_deser_body( ext_cx.expr_blk( ext_cx.expr( span, - ast::expr_match(ext_cx.expr_var(span, ~"i"), arms) + ast::expr_match(ext_cx.expr_var(span, "i"), arms) ) ) ) ); // ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))` - let expr_lambda = ext_cx.lambda_expr( + let expr_lambda = ext_cx.lambda_expr_1( ext_cx.expr_method_call( span, - ext_cx.expr_var(span, ~"__d"), - ext_cx.ident_of(~"read_enum_variant"), + ext_cx.expr_var(span, "__d"), + ext_cx.ident_of("read_enum_variant"), ~[expr_arm_names, expr_lambda] - ) + ), + ext_cx.ident_of("__d") ); // ast for `__d.read_enum($(e_name), $(expr_lambda))` ext_cx.expr_method_call( span, - ext_cx.expr_var(span, ~"__d"), - ext_cx.ident_of(~"read_enum"), + ext_cx.expr_var(span, "__d"), + ext_cx.ident_of("read_enum"), ~[ ext_cx.lit_str(span, @ext_cx.str_of(name)), expr_lambda @@ -1256,105 +1304,147 @@ mod test { } impl Encoder for TestEncoder { - fn emit_nil(&self) { self.add_to_log(CallToEmitNil) } + fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) } - fn emit_uint(&self, v: uint) {self.add_to_log(CallToEmitUint(v)); } - fn emit_u64(&self, _v: u64) { self.add_unknown_to_log(); } - fn emit_u32(&self, _v: u32) { self.add_unknown_to_log(); } - fn emit_u16(&self, _v: u16) { self.add_unknown_to_log(); } - fn emit_u8(&self, _v: u8) { self.add_unknown_to_log(); } + fn emit_uint(&mut self, v: uint) { + self.add_to_log(CallToEmitUint(v)); + } + fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); } + fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); } + fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); } + fn emit_u8(&mut self, _v: u8) { self.add_unknown_to_log(); } - fn emit_int(&self, _v: int) { self.add_unknown_to_log(); } - fn emit_i64(&self, _v: i64) { self.add_unknown_to_log(); } - fn emit_i32(&self, _v: i32) { self.add_unknown_to_log(); } - fn emit_i16(&self, _v: i16) { self.add_unknown_to_log(); } - fn emit_i8(&self, _v: i8) { self.add_unknown_to_log(); } + fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); } + fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); } + fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); } + fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); } + fn emit_i8(&mut self, _v: i8) { self.add_unknown_to_log(); } - fn emit_bool(&self, _v: bool) { self.add_unknown_to_log(); } + fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); } - fn emit_f64(&self, _v: f64) { self.add_unknown_to_log(); } - fn emit_f32(&self, _v: f32) { self.add_unknown_to_log(); } - fn emit_float(&self, _v: float) { self.add_unknown_to_log(); } + fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); } + fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); } + fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); } - fn emit_char(&self, _v: char) { self.add_unknown_to_log(); } - fn emit_str(&self, _v: &str) { self.add_unknown_to_log(); } + fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); } + fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); } - fn emit_enum(&self, name: &str, f: &fn()) { - self.add_to_log(CallToEmitEnum(name.to_str())); f(); } + fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnum(name.to_str())); + f(self); + } - fn emit_enum_variant(&self, name: &str, id: uint, - cnt: uint, f: &fn()) { - self.add_to_log(CallToEmitEnumVariant (name.to_str(),id,cnt)); - f(); + fn emit_enum_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt)); + f(self); } - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - self.add_to_log(CallToEmitEnumVariantArg (idx)); f(); + fn emit_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariantArg(idx)); + f(self); } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, name: &str, len: uint, f: &fn()) { - self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); + fn emit_struct(&mut self, + name: &str, + len: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitStruct (name.to_str(),len)); + f(self); } - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { - self.add_to_log(CallToEmitField (name.to_str(),idx)); f(); + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitField (name.to_str(),idx)); + f(self); } - fn emit_tuple(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_arg(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple_struct(&mut self, + _name: &str, + _len: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + + fn emit_tuple_struct_arg(&mut self, + _idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_option(&self, f: &fn()) { + fn emit_option(&mut self, f: &fn(&mut TestEncoder)) { self.add_to_log(CallToEmitOption); - f(); + f(self); } - fn emit_option_none(&self) { + fn emit_option_none(&mut self) { self.add_to_log(CallToEmitOptionNone); } - fn emit_option_some(&self, f: &fn()) { + fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) { self.add_to_log(CallToEmitOptionSome); - f(); + f(self); } - fn emit_seq(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map_elt_key(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } } fn to_call_log>(val: E) -> ~[call] { - let mut te = TestEncoder {call_log: @mut ~[]}; - val.encode(&te); + let mut te = TestEncoder { + call_log: @mut ~[] + }; + val.encode(&mut te); copy *te.call_log } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2d6d74b5c1e32..95e858f6143a3 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -210,29 +210,29 @@ pub fn syntax_expander_table() -> SyntaxEnv { // when a macro expansion occurs, the resulting nodes have the backtrace() // -> expn_info of their expansion context stored into their span. pub trait ext_ctxt { - fn codemap(@mut self) -> @CodeMap; - fn parse_sess(@mut self) -> @mut parse::ParseSess; - fn cfg(@mut self) -> ast::crate_cfg; - fn call_site(@mut self) -> span; - fn print_backtrace(@mut self); - fn backtrace(@mut self) -> Option<@ExpnInfo>; - fn mod_push(@mut self, mod_name: ast::ident); - fn mod_pop(@mut self); - fn mod_path(@mut self) -> ~[ast::ident]; - fn bt_push(@mut self, ei: codemap::ExpnInfo); - fn bt_pop(@mut self); - fn span_fatal(@mut self, sp: span, msg: &str) -> !; - fn span_err(@mut self, sp: span, msg: &str); - fn span_warn(@mut self, sp: span, msg: &str); - fn span_unimpl(@mut self, sp: span, msg: &str) -> !; - fn span_bug(@mut self, sp: span, msg: &str) -> !; - fn bug(@mut self, msg: &str) -> !; - fn next_id(@mut self) -> ast::node_id; - fn trace_macros(@mut self) -> bool; - fn set_trace_macros(@mut self, x: bool); + fn codemap(&self) -> @CodeMap; + fn parse_sess(&self) -> @mut parse::ParseSess; + fn cfg(&self) -> ast::crate_cfg; + fn call_site(&self) -> span; + fn print_backtrace(&self); + fn backtrace(&self) -> Option<@ExpnInfo>; + fn mod_push(&self, mod_name: ast::ident); + fn mod_pop(&self); + fn mod_path(&self) -> ~[ast::ident]; + fn bt_push(&self, ei: codemap::ExpnInfo); + fn bt_pop(&self); + fn span_fatal(&self, sp: span, msg: &str) -> !; + fn span_err(&self, sp: span, msg: &str); + fn span_warn(&self, sp: span, msg: &str); + fn span_unimpl(&self, sp: span, msg: &str) -> !; + fn span_bug(&self, sp: span, msg: &str) -> !; + fn bug(&self, msg: &str) -> !; + fn next_id(&self) -> ast::node_id; + fn trace_macros(&self) -> bool; + fn set_trace_macros(&self, x: bool); /* for unhygienic identifier transformation */ - fn str_of(@mut self, id: ast::ident) -> ~str; - fn ident_of(@mut self, st: ~str) -> ast::ident; + fn str_of(&self, id: ast::ident) -> ~str; + fn ident_of(&self, st: &str) -> ast::ident; } pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) @@ -241,25 +241,31 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg, backtrace: @mut Option<@ExpnInfo>, - mod_path: ~[ast::ident], - trace_mac: bool + + // These two @mut's should really not be here, + // but the self types for CtxtRepr are all wrong + // and there are bugs in the code for object + // types that make this hard to get right at the + // moment. - nmatsakis + mod_path: @mut ~[ast::ident], + trace_mac: @mut bool } impl ext_ctxt for CtxtRepr { - fn codemap(@mut self) -> @CodeMap { self.parse_sess.cm } - fn parse_sess(@mut self) -> @mut parse::ParseSess { self.parse_sess } - fn cfg(@mut self) -> ast::crate_cfg { copy self.cfg } - fn call_site(@mut self) -> span { + fn codemap(&self) -> @CodeMap { self.parse_sess.cm } + fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess } + fn cfg(&self) -> ast::crate_cfg { copy self.cfg } + fn call_site(&self) -> span { match *self.backtrace { Some(@ExpandedFrom(CallInfo {call_site: cs, _})) => cs, None => self.bug(~"missing top span") } } - fn print_backtrace(@mut self) { } - fn backtrace(@mut self) -> Option<@ExpnInfo> { *self.backtrace } - fn mod_push(@mut self, i: ast::ident) { self.mod_path.push(i); } - fn mod_pop(@mut self) { self.mod_path.pop(); } - fn mod_path(@mut self) -> ~[ast::ident] { copy self.mod_path } - fn bt_push(@mut self, ei: codemap::ExpnInfo) { + fn print_backtrace(&self) { } + fn backtrace(&self) -> Option<@ExpnInfo> { *self.backtrace } + fn mod_push(&self, i: ast::ident) { self.mod_path.push(i); } + fn mod_pop(&self) { self.mod_path.pop(); } + fn mod_path(&self) -> ~[ast::ident] { copy *self.mod_path } + fn bt_push(&self, ei: codemap::ExpnInfo) { match ei { ExpandedFrom(CallInfo {call_site: cs, callee: ref callee}) => { *self.backtrace = @@ -270,7 +276,7 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) } } } - fn bt_pop(@mut self) { + fn bt_pop(&self) { match *self.backtrace { Some(@ExpandedFrom(CallInfo { call_site: span {expn_info: prev, _}, _ @@ -280,52 +286,52 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) _ => self.bug(~"tried to pop without a push") } } - fn span_fatal(@mut self, sp: span, msg: &str) -> ! { + fn span_fatal(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_fatal(sp, msg); } - fn span_err(@mut self, sp: span, msg: &str) { + fn span_err(&self, sp: span, msg: &str) { self.print_backtrace(); self.parse_sess.span_diagnostic.span_err(sp, msg); } - fn span_warn(@mut self, sp: span, msg: &str) { + fn span_warn(&self, sp: span, msg: &str) { self.print_backtrace(); self.parse_sess.span_diagnostic.span_warn(sp, msg); } - fn span_unimpl(@mut self, sp: span, msg: &str) -> ! { + fn span_unimpl(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_unimpl(sp, msg); } - fn span_bug(@mut self, sp: span, msg: &str) -> ! { + fn span_bug(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_bug(sp, msg); } - fn bug(@mut self, msg: &str) -> ! { + fn bug(&self, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.handler().bug(msg); } - fn next_id(@mut self) -> ast::node_id { + fn next_id(&self) -> ast::node_id { return parse::next_node_id(self.parse_sess); } - fn trace_macros(@mut self) -> bool { - self.trace_mac + fn trace_macros(&self) -> bool { + *self.trace_mac } - fn set_trace_macros(@mut self, x: bool) { - self.trace_mac = x + fn set_trace_macros(&self, x: bool) { + *self.trace_mac = x } - fn str_of(@mut self, id: ast::ident) -> ~str { + fn str_of(&self, id: ast::ident) -> ~str { copy *self.parse_sess.interner.get(id) } - fn ident_of(@mut self, st: ~str) -> ast::ident { - self.parse_sess.interner.intern(@/*bad*/ copy st) + fn ident_of(&self, st: &str) -> ast::ident { + self.parse_sess.interner.intern(st) } } - let imp: @mut CtxtRepr = @mut CtxtRepr { + let imp: @CtxtRepr = @CtxtRepr { parse_sess: parse_sess, cfg: cfg, backtrace: @mut None, - mod_path: ~[], - trace_mac: false + mod_path: @mut ~[], + trace_mac: @mut false }; ((imp) as @ext_ctxt) } @@ -342,7 +348,7 @@ pub fn expr_to_str(cx: @ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str { pub fn expr_to_ident(cx: @ext_ctxt, expr: @ast::expr, - err_msg: ~str) -> ast::ident { + err_msg: &str) -> ast::ident { match expr.node { ast::expr_path(p) => { if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { @@ -380,7 +386,7 @@ pub fn get_exprs_from_tts(cx: @ext_ctxt, tts: &[ast::token_tree]) -> ~[@ast::expr] { let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), - vec::from_slice(tts)); + vec::to_owned(tts)); let mut es = ~[]; while *p.token != token::EOF { if es.len() != 0 { @@ -451,17 +457,6 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - #[cfg(stage0)] - fn get_map(&self) -> &'self HashMap { - match *self { - BaseMapChain (~ref map) => map, - ConsMapChain (~ref map,_) => map - } - } - - // ugh: can't get this to compile with mut because of the - // lack of flow sensitivity. - #[cfg(not(stage0))] fn get_map<'a>(&'a self) -> &'a HashMap { match *self { BaseMapChain (~ref map) => map, @@ -543,13 +538,3 @@ mod test { assert_eq!(*(m.find(&@~"def").get()),16); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 4c876669f471d..3f90fd6267bfb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -11,6 +11,7 @@ use ast; use codemap; use codemap::span; +use fold; use ext::base::ext_ctxt; use ext::build; @@ -54,43 +55,52 @@ pub fn mk_binary(cx: @ext_ctxt, sp: span, op: ast::binop, cx.next_id(); // see ast_util::op_expr_callee_id mk_expr(cx, sp, ast::expr_binary(op, lhs, rhs)) } + +pub fn mk_deref(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { + mk_unary(cx, sp, ast::deref, e) +} pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) -> @ast::expr { cx.next_id(); // see ast_util::op_expr_callee_id mk_expr(cx, sp, ast::expr_unary(op, e)) } pub fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::Path { - mk_raw_path_(sp, idents, ~[]) + mk_raw_path_(sp, idents, None, ~[]) } pub fn mk_raw_path_(sp: span, idents: ~[ast::ident], + rp: Option<@ast::Lifetime>, types: ~[@ast::Ty]) -> @ast::Path { @ast::Path { span: sp, global: false, idents: idents, - rp: None, + rp: rp, types: types } } pub fn mk_raw_path_global(sp: span, idents: ~[ast::ident]) -> @ast::Path { - mk_raw_path_global_(sp, idents, ~[]) + mk_raw_path_global_(sp, idents, None, ~[]) } pub fn mk_raw_path_global_(sp: span, idents: ~[ast::ident], + rp: Option<@ast::Lifetime>, types: ~[@ast::Ty]) -> @ast::Path { @ast::Path { span: sp, global: true, idents: idents, - rp: None, + rp: rp, types: types } } +pub fn mk_path_raw(cx: @ext_ctxt, sp: span, path: @ast::Path)-> @ast::expr { + mk_expr(cx, sp, ast::expr_path(path)) +} pub fn mk_path(cx: @ext_ctxt, sp: span, idents: ~[ast::ident]) -> @ast::expr { - mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents))) + mk_path_raw(cx, sp, mk_raw_path(sp, idents)) } pub fn mk_path_global(cx: @ext_ctxt, sp: span, idents: ~[ast::ident]) -> @ast::expr { - mk_expr(cx, sp, ast::expr_path(mk_raw_path_global(sp, idents))) + mk_path_raw(cx, sp, mk_raw_path_global(sp, idents)) } pub fn mk_access_(cx: @ext_ctxt, sp: span, p: @ast::expr, m: ast::ident) -> @ast::expr { @@ -354,44 +364,69 @@ pub fn mk_stmt(cx: @ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt { let stmt_ = ast::stmt_semi(expr, cx.next_id()); @codemap::spanned { node: stmt_, span: span } } + +pub fn mk_ty_mt(ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt { + ast::mt { + ty: ty, + mutbl: mutbl + } +} + +pub fn mk_ty(cx: @ext_ctxt, + span: span, + ty: ast::ty_) -> @ast::Ty { + @ast::Ty { + id: cx.next_id(), + span: span, + node: ty + } +} + pub fn mk_ty_path(cx: @ext_ctxt, span: span, idents: ~[ ast::ident ]) -> @ast::Ty { let ty = build::mk_raw_path(span, idents); - let ty = ast::ty_path(ty, cx.next_id()); - let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span }; - ty + mk_ty_path_path(cx, span, ty) } + pub fn mk_ty_path_global(cx: @ext_ctxt, span: span, idents: ~[ ast::ident ]) -> @ast::Ty { let ty = build::mk_raw_path_global(span, idents); - let ty = ast::ty_path(ty, cx.next_id()); - let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span }; - ty + mk_ty_path_path(cx, span, ty) } + +pub fn mk_ty_path_path(cx: @ext_ctxt, + span: span, + path: @ast::Path) + -> @ast::Ty { + let ty = ast::ty_path(path, cx.next_id()); + mk_ty(cx, span, ty) +} + pub fn mk_ty_rptr(cx: @ext_ctxt, span: span, ty: @ast::Ty, + lifetime: Option<@ast::Lifetime>, mutbl: ast::mutability) -> @ast::Ty { - @ast::Ty { - id: cx.next_id(), - span: span, - node: ast::ty_rptr( - None, - ast::mt { ty: ty, mutbl: mutbl } - ), - } + mk_ty(cx, span, + ast::ty_rptr(lifetime, mk_ty_mt(ty, mutbl))) +} +pub fn mk_ty_uniq(cx: @ext_ctxt, span: span, ty: @ast::Ty) -> @ast::Ty { + mk_ty(cx, span, ast::ty_uniq(mk_ty_mt(ty, ast::m_imm))) } +pub fn mk_ty_box(cx: @ext_ctxt, span: span, + ty: @ast::Ty, mutbl: ast::mutability) -> @ast::Ty { + mk_ty(cx, span, ast::ty_box(mk_ty_mt(ty, mutbl))) +} + + + pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty { - @ast::Ty { - id: cx.next_id(), - node: ast::ty_infer, - span: span, - } + mk_ty(cx, span, ast::ty_infer) } pub fn mk_trait_ref_global(cx: @ext_ctxt, span: span, @@ -467,10 +502,10 @@ pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr { cx, span, ~[ - cx.ident_of(~"core"), - cx.ident_of(~"sys"), - cx.ident_of(~"FailWithCause"), - cx.ident_of(~"fail_with"), + cx.ident_of("core"), + cx.ident_of("sys"), + cx.ident_of("FailWithCause"), + cx.ident_of("fail_with"), ], ~[ mk_base_str(cx, span, ~"internal error: entered unreachable code"), @@ -482,3 +517,24 @@ pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr { pub fn mk_unreachable_arm(cx: @ext_ctxt, span: span) -> ast::arm { mk_arm(cx, span, ~[mk_pat_wild(cx, span)], mk_unreachable(cx, span)) } + +pub fn make_self(cx: @ext_ctxt, span: span) -> @ast::expr { + build::mk_expr(cx, span, ast::expr_self) +} + +// +// Duplication functions +// +// These functions just duplicate AST nodes. +// + +pub fn duplicate_expr(cx: @ext_ctxt, expr: @ast::expr) -> @ast::expr { + let folder = fold::default_ast_fold(); + let folder = @fold::AstFoldFns { + new_id: |_| cx.next_id(), + ..*folder + }; + let folder = fold::make_fold(folder); + folder.fold_expr(expr) +} + diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 55e25e6993695..96e5e4143226c 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -33,7 +33,7 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) } } } - let res = cx.parse_sess().interner.intern(@res_str); + let res = cx.parse_sess().interner.intern(res_str); let e = @ast::expr { id: cx.next_id(), diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index d996bca60a367..1c33fe3507076 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -13,7 +13,6 @@ use codemap::span; use ext::base::ext_ctxt; use ext::build; use ext::deriving::generic::*; -use core::option::{None,Some}; pub fn expand_deriving_clone(cx: @ext_ctxt, @@ -22,13 +21,16 @@ pub fn expand_deriving_clone(cx: @ext_ctxt, in_items: ~[@item]) -> ~[@item] { let trait_def = TraitDef { - path: ~[~"core", ~"clone", ~"Clone"], + path: Path::new(~[~"core", ~"clone", ~"Clone"]), additional_bounds: ~[], + generics: LifetimeBounds::empty(), methods: ~[ MethodDef { name: ~"clone", - nargs: 0, - output_type: None, // return Self + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[], + ret_ty: Self, const_nonmatching: false, combine_substructure: cs_clone } @@ -66,7 +68,8 @@ fn cs_clone(cx: @ext_ctxt, span: span, ctor_ident = ~[ variant.node.name ]; all_fields = af; }, - EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`") + EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"), + StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`") } match all_fields { diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index c0060cc67dc33..e431e1f78bff9 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -8,15 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ext_ctxt; use ext::build; use ext::deriving::generic::*; -use core::option::Some; - pub fn expand_deriving_eq(cx: @ext_ctxt, span: span, mitem: @meta_item, @@ -24,28 +21,32 @@ pub fn expand_deriving_eq(cx: @ext_ctxt, // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { - cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cs_and(|cx, span, _, _| build::mk_bool(cx, span, false), cx, span, substr) } fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { - cs_or(|cx, span, _| build::mk_bool(cx, span, true), + cs_or(|cx, span, _, _| build::mk_bool(cx, span, true), cx, span, substr) } + macro_rules! md ( ($name:expr, $f:ident) => { MethodDef { name: $name, - output_type: Some(~[~"bool"]), - nargs: 1, + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[borrowed_self()], + ret_ty: Literal(Path::new(~[~"bool"])), const_nonmatching: true, combine_substructure: $f }, } - ) + ); let trait_def = TraitDef { - path: ~[~"core", ~"cmp", ~"Eq"], + path: Path::new(~[~"core", ~"cmp", ~"Eq"]), additional_bounds: ~[], + generics: LifetimeBounds::empty(), methods: ~[ md!(~"eq", cs_eq), md!(~"ne", cs_ne) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 398e27eb3e385..a9234c858f418 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -14,29 +14,33 @@ use codemap::span; use ext::base::ext_ctxt; use ext::build; use ext::deriving::generic::*; -use core::option::Some; - -macro_rules! md { - ($name:expr, $less:expr, $equal:expr) => { - MethodDef { - name: $name, - output_type: Some(~[~"bool"]), - nargs: 1, - const_nonmatching: false, - combine_substructure: |cx, span, substr| - cs_ord($less, $equal, cx, span, substr) - } - } -} pub fn expand_deriving_ord(cx: @ext_ctxt, span: span, mitem: @meta_item, in_items: ~[@item]) -> ~[@item] { + macro_rules! md ( + ($name:expr, $less:expr, $equal:expr) => { + MethodDef { + name: $name, + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[borrowed_self()], + ret_ty: Literal(Path::new(~[~"bool"])), + const_nonmatching: false, + combine_substructure: |cx, span, substr| + cs_ord($less, $equal, cx, span, substr) + } + } + ); + + + let trait_def = TraitDef { - path: ~[~"core", ~"cmp", ~"Ord"], + path: Path::new(~[~"core", ~"cmp", ~"Ord"]), // XXX: Ord doesn't imply Eq yet - additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]], + additional_bounds: ~[Literal(Path::new(~[~"core", ~"cmp", ~"Eq"]))], + generics: LifetimeBounds::empty(), methods: ~[ md!(~"lt", true, false), md!(~"le", true, true), @@ -54,9 +58,9 @@ fn cs_ord(less: bool, equal: bool, cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { let binop = if less { - cx.ident_of(~"lt") + cx.ident_of("lt") } else { - cx.ident_of(~"gt") + cx.ident_of("gt") }; let false_blk_expr = build::mk_block(cx, span, ~[], ~[], @@ -97,19 +101,19 @@ fn cs_ord(less: bool, equal: bool, } let cmp = build::mk_method_call(cx, span, - self_f, cx.ident_of(~"eq"), other_fs); + self_f, cx.ident_of("eq"), other_fs.to_owned()); let subexpr = build::mk_simple_block(cx, span, subexpr); let elseif = expr_if(cmp, subexpr, Some(false_blk_expr)); let elseif = build::mk_expr(cx, span, elseif); let cmp = build::mk_method_call(cx, span, - self_f, binop, other_fs); + self_f, binop, other_fs.to_owned()); let if_ = expr_if(cmp, true_blk, Some(elseif)); build::mk_expr(cx, span, if_) }, base, - |cx, span, args| { + |cx, span, args, _| { // nonmatching enums, order by the order the variants are // written match args { diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs index fc8ec103a6021..068a7bc06b1e5 100644 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -15,26 +15,27 @@ use ext::base::ext_ctxt; use ext::build; use ext::deriving::generic::*; -use core::option::Some; - pub fn expand_deriving_totaleq(cx: @ext_ctxt, span: span, mitem: @meta_item, in_items: ~[@item]) -> ~[@item] { fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { - cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cs_and(|cx, span, _, _| build::mk_bool(cx, span, false), cx, span, substr) } let trait_def = TraitDef { - path: ~[~"core", ~"cmp", ~"TotalEq"], + path: Path::new(~[~"core", ~"cmp", ~"TotalEq"]), additional_bounds: ~[], + generics: LifetimeBounds::empty(), methods: ~[ MethodDef { name: ~"equals", - output_type: Some(~[~"bool"]), - nargs: 1, + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[borrowed_self()], + ret_ty: Literal(Path::new(~[~"bool"])), const_nonmatching: true, combine_substructure: cs_equals } diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index a098a7463d3e7..7d560a197d08b 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -14,20 +14,22 @@ use ext::base::ext_ctxt; use ext::build; use ext::deriving::generic::*; use core::cmp::{Ordering, Equal, Less, Greater}; -use core::option::Some; pub fn expand_deriving_totalord(cx: @ext_ctxt, span: span, mitem: @meta_item, in_items: ~[@item]) -> ~[@item] { let trait_def = TraitDef { - path: ~[~"core", ~"cmp", ~"TotalOrd"], + path: Path::new(~[~"core", ~"cmp", ~"TotalOrd"]), additional_bounds: ~[], + generics: LifetimeBounds::empty(), methods: ~[ MethodDef { name: ~"cmp", - output_type: Some(~[~"core", ~"cmp", ~"Ordering"]), - nargs: 1, + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[borrowed_self()], + ret_ty: Literal(Path::new(~[~"core", ~"cmp", ~"Ordering"])), const_nonmatching: false, combine_substructure: cs_cmp } @@ -41,21 +43,21 @@ pub fn expand_deriving_totalord(cx: @ext_ctxt, pub fn ordering_const(cx: @ext_ctxt, span: span, cnst: Ordering) -> @expr { let cnst = match cnst { - Less => ~"Less", - Equal => ~"Equal", - Greater => ~"Greater" + Less => "Less", + Equal => "Equal", + Greater => "Greater" }; build::mk_path_global(cx, span, - ~[cx.ident_of(~"core"), - cx.ident_of(~"cmp"), + ~[cx.ident_of("core"), + cx.ident_of("cmp"), cx.ident_of(cnst)]) } pub fn cs_cmp(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { - let lexical_ord = ~[cx.ident_of(~"core"), - cx.ident_of(~"cmp"), - cx.ident_of(~"lexical_ordering")]; + let lexical_ord = ~[cx.ident_of("core"), + cx.ident_of("cmp"), + cx.ident_of("lexical_ordering")]; cs_same_method_fold( // foldr (possibly) nests the matches in lexical_ordering better @@ -64,7 +66,7 @@ pub fn cs_cmp(cx: @ext_ctxt, span: span, build::mk_call_global(cx, span, lexical_ord, ~[old, new]) }, ordering_const(cx, span, Equal), - |cx, span, list| { + |cx, span, list, _| { match list { // an earlier nonmatching variant is Less than a // later one diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 48f6d5baa8b9f..fd5d26a178707 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -41,15 +41,15 @@ fn create_derived_decodable_impl( ) -> @item { let decoder_ty_param = build::mk_ty_param( cx, - cx.ident_of(~"__D"), + cx.ident_of("__D"), @opt_vec::with( build::mk_trait_ty_param_bound_global( cx, span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decoder"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decoder"), ] ) ) @@ -62,12 +62,13 @@ fn create_derived_decodable_impl( let trait_path = build::mk_raw_path_global_( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decodable") + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decodable") ], + None, ~[ - build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")) + build::mk_simple_ty_path(cx, span, cx.ident_of("__D")) ] ); create_derived_impl( @@ -77,7 +78,7 @@ fn create_derived_decodable_impl( generics, methods, trait_path, - generic_ty_params, + Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty }, opt_vec::Empty ) } @@ -95,10 +96,11 @@ fn create_decode_method( let d_arg_type = build::mk_ty_rptr( cx, span, - build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")), - ast::m_imm + build::mk_simple_ty_path(cx, span, cx.ident_of("__D")), + None, + ast::m_mutbl ); - let d_ident = cx.ident_of(~"__d"); + let d_ident = cx.ident_of("__d"); let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type); // Create the type of the return value. @@ -118,7 +120,7 @@ fn create_decode_method( // Create the method. let self_ty = spanned { node: sty_static, span: span }; - let method_ident = cx.ident_of(~"decode"); + let method_ident = cx.ident_of("decode"); @ast::method { ident: method_ident, attrs: ~[], @@ -146,14 +148,14 @@ fn call_substructure_decode_method( cx, span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Decodable"), - cx.ident_of(~"decode"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Decodable"), + cx.ident_of("decode"), ] ), ~[ - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]) + build::mk_path(cx, span, ~[cx.ident_of("__d")]) ] ) } @@ -219,15 +221,24 @@ fn create_read_struct_field( // Call the substructure method. let decode_expr = call_substructure_decode_method(cx, span); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of("__d"), + build::mk_ty_infer(cx, span)); + let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), - cx.ident_of(~"read_struct_field"), + build::mk_path(cx, span, ~[cx.ident_of("__d")]), + cx.ident_of("read_struct_field"), ~[ build::mk_base_str(cx, span, cx.str_of(ident)), build::mk_uint(cx, span, idx), - build::mk_lambda_no_args(cx, span, decode_expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], + build::mk_ty_infer(cx, span)), + decode_expr), ] ); @@ -246,8 +257,8 @@ fn create_read_struct_arg( let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), - cx.ident_of(~"read_struct_arg"), + build::mk_path(cx, span, ~[cx.ident_of("__d")]), + cx.ident_of("read_struct_arg"), ~[ build::mk_uint(cx, span, idx), build::mk_lambda_no_args(cx, span, decode_expr), @@ -269,7 +280,7 @@ fn expand_deriving_decodable_struct_method( let mut fields = ~[]; for struct_def.fields.each |struct_field| { match struct_field.node.kind { - named_field(ident, _, _) => { + named_field(ident, _) => { fields.push(create_read_struct_field(cx, span, i, ident)); } unnamed_field => { @@ -282,21 +293,27 @@ fn expand_deriving_decodable_struct_method( i += 1; } + let d_arg = build::mk_arg(cx, + span, + cx.ident_of("__d"), + build::mk_ty_infer(cx, span)); + let read_struct_expr = build::mk_method_call( cx, span, build::mk_path( cx, span, - ~[cx.ident_of(~"__d")] + ~[cx.ident_of("__d")] ), - cx.ident_of(~"read_struct"), + cx.ident_of("read_struct"), ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), build::mk_uint(cx, span, fields.len()), - build::mk_lambda_no_args( + build::mk_lambda( cx, span, + build::mk_fn_decl(~[d_arg], build::mk_ty_infer(cx, span)), build::mk_struct_e( cx, span, @@ -334,14 +351,23 @@ fn create_read_variant_arg( // Call the substructure method. let expr = call_substructure_decode_method(cx, span); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of("__d"), + build::mk_ty_infer(cx, span)); + let t_infer = build::mk_ty_infer(cx, span); + let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), - cx.ident_of(~"read_enum_variant_arg"), + build::mk_path(cx, span, ~[cx.ident_of("__d")]), + cx.ident_of("read_enum_variant_arg"), ~[ build::mk_uint(cx, span, j), - build::mk_lambda_no_args(cx, span, expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], t_infer), + expr), ] ); @@ -390,8 +416,8 @@ fn create_read_enum_variant( build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), - cx.ident_of(~"read_enum_variant"), + build::mk_path(cx, span, ~[cx.ident_of("__d")]), + cx.ident_of("read_enum_variant"), ~[ expr_arm_names, build::mk_lambda( @@ -402,7 +428,13 @@ fn create_read_enum_variant( build::mk_arg( cx, span, - cx.ident_of(~"__i"), + cx.ident_of("__d"), + build::mk_ty_infer(cx, span) + ), + build::mk_arg( + cx, + span, + cx.ident_of("__i"), build::mk_ty_infer(cx, span) ) ], @@ -412,7 +444,7 @@ fn create_read_enum_variant( cx, span, ast::expr_match( - build::mk_path(cx, span, ~[cx.ident_of(~"__i")]), + build::mk_path(cx, span, ~[cx.ident_of("__i")]), arms ) ) @@ -434,15 +466,24 @@ fn expand_deriving_decodable_enum_method( enum_definition ); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of("__d"), + build::mk_ty_infer(cx, span)); + // Create the read_enum expression let read_enum_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), - cx.ident_of(~"read_enum"), + build::mk_path(cx, span, ~[cx.ident_of("__d")]), + cx.ident_of("read_enum"), ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), - build::mk_lambda_no_args(cx, span, read_enum_variant_expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], + build::mk_ty_infer(cx, span)), + read_enum_variant_expr), ] ); diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 640d0d0ff2d23..a5edd92022f78 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -41,15 +41,15 @@ fn create_derived_encodable_impl( ) -> @item { let encoder_ty_param = build::mk_ty_param( cx, - cx.ident_of(~"__E"), + cx.ident_of("__E"), @opt_vec::with( build::mk_trait_ty_param_bound_global( cx, span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Encoder"), + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Encoder"), ] ) ) @@ -62,12 +62,13 @@ fn create_derived_encodable_impl( let trait_path = build::mk_raw_path_global_( span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialize"), - cx.ident_of(~"Encodable") + cx.ident_of("std"), + cx.ident_of("serialize"), + cx.ident_of("Encodable") ], + None, ~[ - build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")) + build::mk_simple_ty_path(cx, span, cx.ident_of("__E")) ] ); create_derived_impl( @@ -77,7 +78,7 @@ fn create_derived_encodable_impl( generics, methods, trait_path, - generic_ty_params, + Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty }, opt_vec::Empty ) } @@ -93,11 +94,11 @@ fn create_encode_method( let e_arg_type = build::mk_ty_rptr( cx, span, - build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")), - ast::m_imm + build::mk_simple_ty_path(cx, span, cx.ident_of("__E")), + None, + ast::m_mutbl ); - let e_ident = cx.ident_of(~"__e"); - let e_arg = build::mk_arg(cx, span, e_ident, e_arg_type); + let e_arg = build::mk_arg(cx, span, cx.ident_of("__e"), e_arg_type); // Create the type of the return value. let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; @@ -111,7 +112,7 @@ fn create_encode_method( // Create the method. let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of(~"encode"); + let method_ident = cx.ident_of("encode"); @ast::method { ident: method_ident, attrs: ~[], @@ -133,11 +134,11 @@ fn call_substructure_encode_method( self_field: @expr ) -> @ast::expr { // Gather up the parameters we want to chain along. - let e_ident = cx.ident_of(~"__e"); + let e_ident = cx.ident_of("__e"); let e_expr = build::mk_path(cx, span, ~[e_ident]); // Call the substructure method. - let encode_ident = cx.ident_of(~"encode"); + let encode_ident = cx.ident_of("encode"); build::mk_method_call( cx, span, @@ -203,21 +204,17 @@ fn expand_deriving_encodable_struct_method( type_ident: ident, struct_def: &struct_def ) -> @method { - let self_ident = cx.ident_of(~"self"); - // Create the body of the method. let mut idx = 0; let mut statements = ~[]; for struct_def.fields.each |struct_field| { match struct_field.node.kind { - named_field(ident, _, _) => { + named_field(ident, _) => { // Create the accessor for this field. - let self_field = build::mk_access( - cx, - span, - ~[self_ident], - ident - ); + let self_field = build::mk_access_(cx, + span, + build::make_self(cx, span), + ident); // Call the substructure method. let encode_expr = call_substructure_encode_method( @@ -226,18 +223,24 @@ fn expand_deriving_encodable_struct_method( self_field ); + let e_ident = cx.ident_of("__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + let blk_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), encode_expr ); let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), - cx.ident_of(~"emit_struct_field"), + build::mk_path(cx, span, ~[cx.ident_of("__e")]), + cx.ident_of("emit_struct_field"), ~[ build::mk_base_str(cx, span, cx.str_of(ident)), build::mk_uint(cx, span, idx), @@ -257,22 +260,27 @@ fn expand_deriving_encodable_struct_method( idx += 1; } + let e_arg = build::mk_arg(cx, + span, + cx.ident_of("__e"), + build::mk_ty_infer(cx, span)); + let emit_struct_stmt = build::mk_method_call( cx, span, build::mk_path( cx, span, - ~[cx.ident_of(~"__e")] + ~[cx.ident_of("__e")] ), - cx.ident_of(~"emit_struct"), + cx.ident_of("emit_struct"), ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), build::mk_uint(cx, span, statements.len()), build::mk_lambda_stmts( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), statements ), ] @@ -293,7 +301,7 @@ fn expand_deriving_encodable_enum_method( // Create the arms of the match in the method body. let arms = do enum_definition.variants.mapi |i, variant| { // Create the matching pattern. - let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); + let (pat, fields) = create_enum_variant_pattern(cx, span, variant, "__self", ast::m_imm); // Feed the discriminant to the encode function. let mut stmts = ~[]; @@ -301,26 +309,28 @@ fn expand_deriving_encodable_enum_method( // Feed each argument in this variant to the encode function // as well. let variant_arg_len = variant_arg_count(cx, span, variant); - for uint::range(0, variant_arg_len) |j| { - // Create the expression for this field. - let field_ident = cx.ident_of(~"__self_" + j.to_str()); - let field = build::mk_path(cx, span, ~[ field_ident ]); - + for fields.eachi |j, &(_, field)| { // Call the substructure method. let expr = call_substructure_encode_method(cx, span, field); + let e_ident = cx.ident_of("__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + let blk_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), expr ); let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), - cx.ident_of(~"emit_enum_variant_arg"), + build::mk_path(cx, span, ~[cx.ident_of("__e")]), + cx.ident_of("emit_enum_variant_arg"), ~[ build::mk_uint(cx, span, j), blk_expr, @@ -331,11 +341,15 @@ fn expand_deriving_encodable_enum_method( } // Create the pattern body. + let e_arg = build::mk_arg(cx, + span, + cx.ident_of("__e"), + build::mk_ty_infer(cx, span)); let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), - cx.ident_of(~"emit_enum_variant"), + build::mk_path(cx, span, ~[cx.ident_of("__e")]), + cx.ident_of("emit_enum_variant"), ~[ build::mk_base_str(cx, span, cx.str_of(variant.node.name)), build::mk_uint(cx, span, i), @@ -343,7 +357,7 @@ fn expand_deriving_encodable_enum_method( build::mk_lambda_stmts( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), stmts ) ] @@ -359,19 +373,25 @@ fn expand_deriving_encodable_enum_method( } }; + let e_ident = cx.ident_of("__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + // Create the method body. let lambda_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), expand_enum_or_struct_match(cx, span, arms) ); let call_expr = build::mk_method_call( cx, span, - build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), - cx.ident_of(~"emit_enum"), + build::mk_path(cx, span, ~[cx.ident_of("__e")]), + cx.ident_of("emit_enum"), ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), lambda_expr, diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 05941f4cbd655..d785f3816de30 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -16,23 +16,22 @@ access to the fields of the 4 different sorts of structs and enum variants, as well as creating the method and impl ast instances. Supported features (fairly exhaustive): -- Methods taking any number of parameters of type `&Self`, including - none other than `self`. (`MethodDef.nargs`) -- Methods returning `Self` or a non-parameterised type - (e.g. `bool` or `core::cmp::Ordering`). (`MethodDef.output_type`) -- Generating `impl`s for types with type parameters +- Methods taking any number of parameters of any type, and returning + any type, other than vectors, bottom and closures. +- Generating `impl`s for types with type parameters and lifetimes (e.g. `Option`), the parameters are automatically given the - current trait as a bound. + current trait as a bound. (This includes separate type parameters + and lifetimes for methods.) - Additional bounds on the type parameters, e.g. the `Ord` instance requires an explicit `Eq` bound at the moment. (`TraitDef.additional_bounds`) -(Key unsupported things: methods with arguments of non-`&Self` type, -traits with parameters, methods returning parameterised types, static -methods.) +Unsupported: FIXME #6257: calling methods on borrowed pointer fields, +e.g. deriving TotalEq/TotalOrd/Clone don't work on `struct A(&int)`, +because of how the auto-dereferencing happens. The most important thing for implementers is the `Substructure` and -`SubstructureFields` objects. The latter groups 3 possibilities of the +`SubstructureFields` objects. The latter groups 5 possibilities of the arguments: - `Struct`, when `Self` is a struct (including tuple structs, e.g @@ -42,42 +41,57 @@ arguments: - `EnumNonMatching` when `Self` is an enum and the arguments are not the same variant (e.g. `None`, `Some(1)` and `None`). If `const_nonmatching` is true, this will contain an empty list. +- `StaticEnum` and `StaticStruct` for static methods, where the type + being derived upon is either a enum or struct respectively. (Any + argument with type Self is just grouped among the non-self + arguments.) In the first two cases, the values from the corresponding fields in all the arguments are grouped together. In the `EnumNonMatching` case this isn't possible (different variants have different fields), so the -fields are grouped by which argument they come from. +fields are grouped by which argument they come from. There are no +fields with values in the static cases, so these are treated entirely +differently. -All of the cases have `Option` in several places associated +The non-static cases have `Option` in several places associated with field `expr`s. This represents the name of the field it is associated with. It is only not `None` when the associated field has an identifier in the source code. For example, the `x`s in the following snippet - struct A { x : int } +~~~ +struct A { x : int } - struct B(int); +struct B(int); - enum C { - C0(int), - C1 { x: int } - } +enum C { + C0(int), + C1 { x: int } +} The `int`s in `B` and `C0` don't have an identifier, so the `Option`s would be `None` for them. +In the static cases, the structure is summarised, either into the +number of fields or a list of field idents (for tuple structs and +record structs, respectively), or a list of these, for enums (one for +each variant). For empty struct and empty enum variants, it is +represented as a count of 0. + # Examples The following simplified `Eq` is used for in-code examples: - trait Eq { - fn eq(&self, other: &Self); - } - impl Eq for int { - fn eq(&self, other: &int) -> bool { - *self == *other - } +~~~ +trait Eq { + fn eq(&self, other: &Self); +} +impl Eq for int { + fn eq(&self, other: &int) -> bool { + *self == *other } +} +~~~ Some examples of the values of `SubstructureFields` follow, using the above `Eq`, `A`, `B` and `C`. @@ -86,65 +100,85 @@ above `Eq`, `A`, `B` and `C`. When generating the `expr` for the `A` impl, the `SubstructureFields` is - Struct(~[(Some(), - , - ~[), + , + ~[ - ~[])]) +~~~ +Struct(~[(None, + + ~[])]) +~~~ ## Enums When generating the `expr` for a call with `self == C0(a)` and `other == C0(b)`, the SubstructureFields is - EnumMatching(0, , - ~[None, - , - ~[]]) +~~~ +EnumMatching(0, , + ~[None, + , + ~[]]) +~~~ For `C1 {x}` and `C1 {x}`, - EnumMatching(1, , - ~[Some(), - , - ~[]]) +~~~ +EnumMatching(1, , + ~[Some(), + , + ~[]]) +~~~ For `C0(a)` and `C1 {x}` , - EnumNonMatching(~[(0, , - ~[(None, )]), - (1, , - ~[(Some(), - )])]) +~~~ +EnumNonMatching(~[(0, , + ~[(None, )]), + (1, , + ~[(Some(), + )])]) +~~~ + +(and vice versa, but with the order of the outermost list flipped.) -(and vice verse, but with the order of the outermost list flipped.) +## Static + +A static method on the above would result in, + +~~~~ +StaticStruct(, Right(~[])) + +StaticStruct(, Left(1)) + +StaticEnum(, ~[(, Left(1)), + (, Right(~[]))]) +~~~ */ use ast; +use ast::{enum_def, expr, ident, Generics, struct_def}; -use ast::{ - and, binop, deref, enum_def, expr, expr_match, ident, impure_fn, - item, Generics, m_imm, meta_item, method, named_field, or, - pat_wild, public, struct_def, sty_region, ty_rptr, ty_path, - variant}; - -use ast_util; use ext::base::ext_ctxt; use ext::build; use ext::deriving::*; use codemap::{span,respan}; use opt_vec; +pub use self::ty::*; +mod ty; + pub fn expand_deriving_generic(cx: @ext_ctxt, span: span, - _mitem: @meta_item, - in_items: ~[@item], - trait_def: &TraitDef) -> ~[@item] { + _mitem: @ast::meta_item, + in_items: ~[@ast::item], + trait_def: &TraitDef) -> ~[@ast::item] { let expand_enum: ExpandDerivingEnumDefFn = |cx, span, enum_def, type_ident, generics| { trait_def.expand_enum_def(cx, span, enum_def, type_ident, generics) @@ -160,25 +194,38 @@ pub fn expand_deriving_generic(cx: @ext_ctxt, } pub struct TraitDef<'self> { - /// Path of the trait - path: ~[~str], - /// Additional bounds required of any type parameters, other than - /// the current trait - additional_bounds: ~[~[~str]], + /// Path of the trait, including any type parameters + path: Path, + /// Additional bounds required of any type parameters of the type, + /// other than the current trait + additional_bounds: ~[Ty], + + /// Any extra lifetimes and/or bounds, e.g. `D: std::serialize::Decoder` + generics: LifetimeBounds, + methods: ~[MethodDef<'self>] } + pub struct MethodDef<'self> { /// name of the method name: ~str, - /// The path of return type of the method, e.g. `~[~"core", - /// ~"cmp", ~"Eq"]`. `None` for `Self`. - output_type: Option<~[~str]>, - /// Number of arguments other than `self` (all of type `&Self`) - nargs: uint, + /// List of generics, e.g. `R: core::rand::Rng` + generics: LifetimeBounds, + + /// Whether there is a self argument (outer Option) i.e. whether + /// this is a static function, and whether it is a pointer (inner + /// Option) + self_ty: Option>, + + /// Arguments other than the self argument + args: ~[Ty], + + /// Return type + ret_ty: Ty, /// if the value of the nonmatching enums is independent of the - /// actual enums, i.e. can use _ => .. match. + /// actual enum variants, i.e. can use _ => .. match. const_nonmatching: bool, combine_substructure: CombineSubstructureFunc<'self> @@ -186,18 +233,24 @@ pub struct MethodDef<'self> { /// All the data about the data structure/method being derived upon. pub struct Substructure<'self> { + /// ident of self type_ident: ident, + /// ident of the method method_ident: ident, - fields: &'self SubstructureFields + /// dereferenced access to any Self or Ptr(Self, _) arguments + self_args: &'self [@expr], + /// verbatim access to any other arguments + nonself_args: &'self [@expr], + fields: &'self SubstructureFields<'self> } /// A summary of the possible sets of fields. See above for details /// and examples -pub enum SubstructureFields { +pub enum SubstructureFields<'self> { /** - Vec of `(field ident, self, [others])` where the field ident is - the ident of the current field (`None` for all fields in tuple - structs) + Vec of `(field ident, self_or_other)` where the field + ident is the ident of the current field (`None` for all fields in tuple + structs). */ Struct(~[(Option, @expr, ~[@expr])]), @@ -206,17 +259,23 @@ pub enum SubstructureFields { fields: `(field ident, self, [others])`, where the field ident is only non-`None` in the case of a struct variant. */ - EnumMatching(uint, variant, ~[(Option, @expr, ~[@expr])]), + EnumMatching(uint, ast::variant, ~[(Option, @expr, ~[@expr])]), /** non-matching variants of the enum, [(variant index, ast::variant, [field ident, fields])] (i.e. all fields for self are in the first tuple, for other1 are in the second tuple, etc.) */ - EnumNonMatching(~[(uint, variant, ~[(Option, @expr)])]) + EnumNonMatching(~[(uint, ast::variant, ~[(Option, @expr)])]), + + /// A static method where Self is a struct + StaticStruct(&'self ast::struct_def, Either), + /// A static method where Self is an enum + StaticEnum(&'self ast::enum_def, ~[(ident, Either)]) } + /** Combine the values of all the fields together. The last argument is all the fields of all the structures, see above for details. @@ -225,31 +284,34 @@ pub type CombineSubstructureFunc<'self> = &'self fn(@ext_ctxt, span, &Substructure) -> @expr; /** -Deal with non-matching enum variants, the argument is a list +Deal with non-matching enum variants, the arguments are a list representing each variant: (variant index, ast::variant instance, -[variant fields]) +[variant fields]), and a list of the nonself args of the type */ pub type EnumNonMatchFunc<'self> = - &'self fn(@ext_ctxt, span, ~[(uint, variant, ~[(Option, @expr)])]) -> @expr; - + &'self fn(@ext_ctxt, span, + ~[(uint, ast::variant, + ~[(Option, @expr)])], + &[@expr]) -> @expr; impl<'self> TraitDef<'self> { fn create_derived_impl(&self, cx: @ext_ctxt, span: span, type_ident: ident, generics: &Generics, - methods: ~[@method]) -> @item { - let trait_path = build::mk_raw_path_global( - span, - do self.path.map |&s| { cx.ident_of(s) }); + methods: ~[@ast::method]) -> @ast::item { + let trait_path = self.path.to_path(cx, span, type_ident, generics); + + let trait_generics = self.generics.to_generics(cx, span, type_ident, generics); let additional_bounds = opt_vec::from( - do self.additional_bounds.map |v| { - do v.map |&s| { cx.ident_of(s) } + do self.additional_bounds.map |p| { + p.to_path(cx, span, type_ident, generics) }); + create_derived_impl(cx, span, type_ident, generics, methods, trait_path, - opt_vec::Empty, + trait_generics, additional_bounds) } @@ -257,22 +319,28 @@ impl<'self> TraitDef<'self> { span: span, struct_def: &struct_def, type_ident: ident, - generics: &Generics) - -> @item { - let is_tuple = is_struct_tuple(struct_def); - + generics: &Generics) -> @ast::item { let methods = do self.methods.map |method_def| { - let body = if is_tuple { - method_def.expand_struct_tuple_method_body(cx, span, - struct_def, - type_ident) + let (self_ty, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, span, type_ident, generics); + + let body = if method_def.is_static() { + method_def.expand_static_struct_method_body( + cx, span, + struct_def, + type_ident, + self_args, nonself_args) } else { method_def.expand_struct_method_body(cx, span, struct_def, - type_ident) + type_ident, + self_args, nonself_args) }; - method_def.create_method(cx, span, type_ident, generics, body) + method_def.create_method(cx, span, + type_ident, generics, + self_ty, tys, + body) }; self.create_derived_impl(cx, span, type_ident, generics, methods) @@ -282,13 +350,28 @@ impl<'self> TraitDef<'self> { cx: @ext_ctxt, span: span, enum_def: &enum_def, type_ident: ident, - generics: &Generics) -> @item { + generics: &Generics) -> @ast::item { let methods = do self.methods.map |method_def| { - let body = method_def.expand_enum_method_body(cx, span, - enum_def, - type_ident); + let (self_ty, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, span, type_ident, generics); + + let body = if method_def.is_static() { + method_def.expand_static_enum_method_body( + cx, span, + enum_def, + type_ident, + self_args, nonself_args) + } else { + method_def.expand_enum_method_body(cx, span, + enum_def, + type_ident, + self_args, nonself_args) + }; - method_def.create_method(cx, span, type_ident, generics, body) + method_def.create_method(cx, span, + type_ident, generics, + self_ty, tys, + body) }; self.create_derived_impl(cx, span, type_ident, generics, methods) @@ -300,266 +383,241 @@ impl<'self> MethodDef<'self> { cx: @ext_ctxt, span: span, type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr], fields: &SubstructureFields) -> @expr { let substructure = Substructure { type_ident: type_ident, method_ident: cx.ident_of(self.name), + self_args: self_args, + nonself_args: nonself_args, fields: fields }; (self.combine_substructure)(cx, span, &substructure) } - fn get_output_type_path(&self, cx: @ext_ctxt, span: span, - generics: &Generics, type_ident: ident) -> @ast::Path { - match self.output_type { - None => { // Self, add any type parameters - let out_ty_params = do vec::build |push| { - for generics.ty_params.each |ty_param| { - push(build::mk_ty_path(cx, span, ~[ ty_param.ident ])); - } - }; + fn get_ret_ty(&self, cx: @ext_ctxt, span: span, + generics: &Generics, type_ident: ident) -> @ast::Ty { + self.ret_ty.to_ty(cx, span, type_ident, generics) + } + + fn is_static(&self) -> bool { + self.self_ty.is_none() + } + + fn split_self_nonself_args(&self, cx: @ext_ctxt, span: span, + type_ident: ident, generics: &Generics) + -> (ast::self_ty, ~[@expr], ~[@expr], ~[(ident, @ast::Ty)]) { + + let mut self_args = ~[], nonself_args = ~[], arg_tys = ~[]; + let mut ast_self_ty = respan(span, ast::sty_static); + let mut nonstatic = false; + + match self.self_ty { + Some(self_ptr) => { + let (self_expr, self_ty) = ty::get_explicit_self(cx, span, self_ptr); - build::mk_raw_path_(span, ~[ type_ident ], out_ty_params) + ast_self_ty = self_ty; + self_args.push(self_expr); + nonstatic = true; } - Some(str_path) => { - let p = do str_path.map |&s| { cx.ident_of(s) }; - build::mk_raw_path_global(span, p) + _ => {} + } + + for self.args.eachi |i, ty| { + let ast_ty = ty.to_ty(cx, span, type_ident, generics); + let ident = cx.ident_of(fmt!("__arg_%u", i)); + arg_tys.push((ident, ast_ty)); + + let arg_expr = build::mk_path(cx, span, ~[ident]); + + match *ty { + // for static methods, just treat any Self + // arguments as a normal arg + Self if nonstatic => { + self_args.push(arg_expr); + } + Ptr(~Self, _) if nonstatic => { + self_args.push(build::mk_deref(cx, span, arg_expr)) + } + _ => { + nonself_args.push(arg_expr); + } } } + + (ast_self_ty, self_args, nonself_args, arg_tys) } fn create_method(&self, cx: @ext_ctxt, span: span, type_ident: ident, - generics: &Generics, body: @expr) -> @method { - // Create the `Self` type of the `other` parameters. - let arg_path_type = create_self_type_with_params(cx, - span, - type_ident, - generics); - let arg_type = ty_rptr( - None, - ast::mt { ty: arg_path_type, mutbl: m_imm } - ); - let arg_type = @ast::Ty { - id: cx.next_id(), - node: arg_type, - span: span, - }; - - // create the arguments - let other_idents = create_other_idents(cx, self.nargs); - let args = do other_idents.map |&id| { - build::mk_arg(cx, span, id, arg_type) + generics: &Generics, + self_ty: ast::self_ty, + arg_types: ~[(ident, @ast::Ty)], + body: @expr) -> @ast::method { + // create the generics that aren't for Self + let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); + + let args = do arg_types.map |&(id, ty)| { + build::mk_arg(cx, span, id, ty) }; - let output_type = self.get_output_type_path(cx, span, generics, type_ident); - let output_type = ty_path(output_type, cx.next_id()); - let output_type = @ast::Ty { - id: cx.next_id(), - node: output_type, - span: span, - }; + let ret_type = self.get_ret_ty(cx, span, generics, type_ident); let method_ident = cx.ident_of(self.name); - let fn_decl = build::mk_fn_decl(args, output_type); + let fn_decl = build::mk_fn_decl(args, ret_type); let body_block = build::mk_simple_block(cx, span, body); + // Create the method. - let self_ty = respan(span, sty_region(None, m_imm)); @ast::method { ident: method_ident, attrs: ~[], - generics: ast_util::empty_generics(), + generics: fn_generics, self_ty: self_ty, - purity: impure_fn, + purity: ast::impure_fn, decl: fn_decl, body: body_block, id: cx.next_id(), span: span, self_id: cx.next_id(), - vis: public + vis: ast::public } } /** - ``` + ~~~ #[deriving(Eq)] - struct A(int, int); + struct A { x: int, y: int } // equivalent to: - impl Eq for A { - fn eq(&self, __other_1: &A) -> bool { + fn eq(&self, __arg_1: &A) -> bool { match *self { - (ref self_1, ref self_2) => { - match *__other_1 { - (ref __other_1_1, ref __other_1_2) => { - self_1.eq(__other_1_1) && self_2.eq(__other_1_2) + A {x: ref __self_0_0, y: ref __self_0_1} => { + match *__arg_1 { + A {x: ref __self_1_0, y: ref __self_1_1} => { + __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) } } } } } } - ``` + ~~~ */ - fn expand_struct_tuple_method_body(&self, - cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident) -> @expr { - let self_str = ~"self"; - let other_strs = create_other_strs(self.nargs); - let num_fields = struct_def.fields.len(); - - - let fields = do struct_def.fields.mapi |i, _| { - let other_fields = do other_strs.map |&other_str| { - let other_field_ident = cx.ident_of(fmt!("%s_%u", other_str, i)); - build::mk_path(cx, span, ~[ other_field_ident ]) - }; - - let self_field_ident = cx.ident_of(fmt!("%s_%u", self_str, i)); - let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); + fn expand_struct_method_body(&self, + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr]) + -> @expr { - (None, self_field, other_fields) + let mut raw_fields = ~[], // ~[[fields of self], [fields of next Self arg], [etc]] + patterns = ~[]; + for uint::range(0, self_args.len()) |i| { + let (pat, ident_expr) = create_struct_pattern(cx, span, + type_ident, struct_def, + fmt!("__self_%u", i), ast::m_imm); + patterns.push(pat); + raw_fields.push(ident_expr); }; - let mut match_body = self.call_substructure_method(cx, span, type_ident, &Struct(fields)); - - let type_path = build::mk_raw_path(span, ~[type_ident]); - - // create the matches from inside to out (i.e. other_{self.nargs} to other_1) - for other_strs.each_reverse |&other_str| { - match_body = create_deref_match(cx, span, type_path, - other_str, num_fields, - match_body) - } - - // create the match on self - return create_deref_match(cx, span, type_path, - ~"self", num_fields, match_body); - - /** - Creates a match expression against a tuple that needs to - be dereferenced, but nothing else + // transpose raw_fields + let fields = match raw_fields { + [self_arg, .. rest] => { + do self_arg.mapi |i, &(opt_id, field)| { + let other_fields = do rest.map |l| { + match &l[i] { + &(_, ex) => ex + } + }; + (opt_id, field, other_fields) + } + } + [] => { cx.span_bug(span, ~"No self arguments to non-static \ + method in generic `deriving`") } + }; - ``` - match *`to_match` { - (`to_match`_1, ..., `to_match`_`num_fields`) => `match_body` - } - ``` - */ - fn create_deref_match(cx: @ext_ctxt, - span: span, - type_path: @ast::Path, - to_match: ~str, - num_fields: uint, - match_body: @expr) -> @expr { - let match_subpats = create_subpatterns(cx, span, to_match, num_fields); + // body of the inner most destructuring match + let mut body = self.call_substructure_method( + cx, span, + type_ident, + self_args, + nonself_args, + &Struct(fields)); + + // make a series of nested matches, to destructure the + // structs. This is actually right-to-left, but it shoudn't + // matter. + for vec::each2(self_args, patterns) |&arg_expr, &pat| { let match_arm = ast::arm { - pats: ~[ build::mk_pat_enum(cx, span, type_path, match_subpats) ], + pats: ~[ pat ], guard: None, - body: build::mk_simple_block(cx, span, match_body), + body: build::mk_simple_block(cx, span, body) }; - let deref_expr = build::mk_unary(cx, span, deref, - build::mk_path(cx, span, - ~[ cx.ident_of(to_match)])); - let match_expr = build::mk_expr(cx, span, expr_match(deref_expr, ~[match_arm])); - - match_expr + body = build::mk_expr(cx, span, ast::expr_match(arg_expr, ~[match_arm])) } + body } - /** - ``` - #[deriving(Eq)] - struct A { x: int, y: int } - - // equivalent to: - - impl Eq for A { - fn eq(&self, __other_1: &A) -> bool { - self.x.eq(&__other_1.x) && - self.y.eq(&__other_1.y) - } - } - ``` - */ - fn expand_struct_method_body(&self, - cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident) + fn expand_static_struct_method_body(&self, + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr]) -> @expr { - let self_ident = cx.ident_of(~"self"); - let other_idents = create_other_idents(cx, self.nargs); - - let fields = do struct_def.fields.map |struct_field| { - match struct_field.node.kind { - named_field(ident, _, _) => { - // Create the accessor for this field in the other args. - let other_fields = do other_idents.map |&id| { - build::mk_access(cx, span, ~[id], ident) - }; - let other_field_refs = do other_fields.map |&other_field| { - build::mk_addr_of(cx, span, other_field) - }; - - // Create the accessor for this field in self. - let self_field = - build::mk_access( - cx, span, - ~[ self_ident ], - ident); + let summary = summarise_struct(cx, span, struct_def); - (Some(ident), self_field, other_field_refs) - } - unnamed_field => { - cx.span_unimpl(span, ~"unnamed fields with `deriving_generic`"); - } - } - }; - - self.call_substructure_method(cx, span, type_ident, &Struct(fields)) + self.call_substructure_method(cx, span, + type_ident, + self_args, nonself_args, + &StaticStruct(struct_def, summary)) } /** - ``` + ~~~ #[deriving(Eq)] enum A { A1 A2(int) } - // is equivalent to + // is equivalent to (with const_nonmatching == false) impl Eq for A { - fn eq(&self, __other_1: &A) { + fn eq(&self, __arg_1: &A) { match *self { - A1 => match *__other_1 { - A1 => true, - A2(ref __other_1_1) => false + A1 => match *__arg_1 { + A1 => true + A2(ref __arg_1_1) => false }, - A2(self_1) => match *__other_1 { + A2(self_1) => match *__arg_1 { A1 => false, - A2(ref __other_1_1) => self_1.eq(__other_1_1) + A2(ref __arg_1_1) => self_1.eq(__arg_1_1) } } } } - ``` + ~~~ */ fn expand_enum_method_body(&self, cx: @ext_ctxt, span: span, enum_def: &enum_def, - type_ident: ident) + type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr]) -> @expr { self.build_enum_match(cx, span, enum_def, type_ident, + self_args, nonself_args, None, ~[], 0) } @@ -567,13 +625,13 @@ impl<'self> MethodDef<'self> { /** Creates the nested matches for an enum definition recursively, i.e. - ``` + ~~~ match self { Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... }, Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... }, ... } - ``` + ~~~ It acts in the most naive way, so every branch (and subbranch, subsubbranch, etc) exists, not just the ones where all the variants in @@ -589,15 +647,17 @@ impl<'self> MethodDef<'self> { cx: @ext_ctxt, span: span, enum_def: &enum_def, type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr], matching: Option, - matches_so_far: ~[(uint, variant, + matches_so_far: ~[(uint, ast::variant, ~[(Option, @expr)])], match_count: uint) -> @expr { - if match_count == self.nargs + 1 { + if match_count == self_args.len() { // we've matched against all arguments, so make the final // expression at the bottom of the match tree match matches_so_far { - [] => cx.bug(~"no self match on an enum in `deriving_generic`"), + [] => cx.span_bug(span, ~"no self match on an enum in generic `deriving`"), _ => { // we currently have a vec of vecs, where each // subvec is the fields of one of the arguments, @@ -637,16 +697,17 @@ impl<'self> MethodDef<'self> { substructure = EnumNonMatching(matches_so_far); } } - self.call_substructure_method(cx, span, type_ident, &substructure) + self.call_substructure_method(cx, span, type_ident, + self_args, nonself_args, + &substructure) } } } else { // there are still matches to create - let (current_match_ident, current_match_str) = if match_count == 0 { - (cx.ident_of(~"self"), ~"__self") + let current_match_str = if match_count == 0 { + ~"__self" } else { - let s = fmt!("__other_%u", matches_so_far.len() - 1); - (cx.ident_of(s), s) + fmt!("__arg_%u", match_count) }; let mut arms = ~[]; @@ -654,80 +715,50 @@ impl<'self> MethodDef<'self> { // this is used as a stack let mut matches_so_far = matches_so_far; - macro_rules! mk_arm( - ($pat:expr, $expr:expr) => { - { - let blk = build::mk_simple_block(cx, span, $expr); - let arm = ast::arm { - pats: ~[$ pat ], - guard: None, - body: blk - }; - arm - } - } - ) - // the code for nonmatching variants only matters when // we've seen at least one other variant already if self.const_nonmatching && match_count > 0 { // make a matching-variant match, and a _ match. let index = match matching { Some(i) => i, - None => cx.span_bug(span, ~"Non-matching variants when required to\ - be matching in `deriving_generic`") + None => cx.span_bug(span, ~"Non-matching variants when required to \ + be matching in generic `deriving`") }; // matching-variant match let variant = &enum_def.variants[index]; - let pattern = create_enum_variant_pattern(cx, span, - variant, - current_match_str); - - let idents = do vec::build |push| { - for each_variant_arg_ident(cx, span, variant) |i, field_id| { - let id = cx.ident_of(fmt!("%s_%u", current_match_str, i)); - push((field_id, build::mk_path(cx, span, ~[ id ]))); - } - }; + let (pattern, idents) = create_enum_variant_pattern(cx, span, + variant, + current_match_str, + ast::m_imm); matches_so_far.push((index, *variant, idents)); let arm_expr = self.build_enum_match(cx, span, enum_def, type_ident, + self_args, nonself_args, matching, matches_so_far, match_count + 1); matches_so_far.pop(); - let arm = mk_arm!(pattern, arm_expr); - arms.push(arm); + arms.push(build::mk_arm(cx, span, ~[ pattern ], arm_expr)); if enum_def.variants.len() > 1 { - // _ match, if necessary - let wild_pat = @ast::pat { - id: cx.next_id(), - node: pat_wild, - span: span - }; - let wild_expr = self.call_substructure_method(cx, span, type_ident, + self_args, nonself_args, &EnumNonMatching(~[])); - let wild_arm = mk_arm!(wild_pat, wild_expr); + let wild_arm = build::mk_arm(cx, span, + ~[ build::mk_pat_wild(cx, span) ], + wild_expr); arms.push(wild_arm); } } else { // create an arm matching on each variant for enum_def.variants.eachi |index, variant| { - let pattern = create_enum_variant_pattern(cx, span, - variant, - current_match_str); - - let idents = do vec::build |push| { - for each_variant_arg_ident(cx, span, variant) |i, field_id| { - let id = cx.ident_of(fmt!("%s_%u", current_match_str, i)); - push((field_id, build::mk_path(cx, span, ~[ id ]))); - } - }; + let (pattern, idents) = create_enum_variant_pattern(cx, span, + variant, + current_match_str, + ast::m_imm); matches_so_far.push((index, *variant, idents)); let new_matching = @@ -739,44 +770,71 @@ impl<'self> MethodDef<'self> { let arm_expr = self.build_enum_match(cx, span, enum_def, type_ident, + self_args, nonself_args, new_matching, matches_so_far, match_count + 1); matches_so_far.pop(); - let arm = mk_arm!(pattern, arm_expr); + let arm = build::mk_arm(cx, span, ~[ pattern ], arm_expr); arms.push(arm); } } - let deref_expr = build::mk_unary(cx, span, deref, - build::mk_path(cx, span, - ~[ current_match_ident ])); - let match_expr = build::mk_expr(cx, span, - expr_match(deref_expr, arms)); - match_expr + // match foo { arm, arm, arm, ... } + build::mk_expr(cx, span, + ast::expr_match(self_args[match_count], arms)) } } + + fn expand_static_enum_method_body(&self, + cx: @ext_ctxt, + span: span, + enum_def: &enum_def, + type_ident: ident, + self_args: &[@expr], + nonself_args: &[@expr]) + -> @expr { + let summary = do enum_def.variants.map |v| { + let ident = v.node.name; + let summary = match v.node.kind { + ast::tuple_variant_kind(ref args) => Left(args.len()), + ast::struct_variant_kind(struct_def) => { + summarise_struct(cx, span, struct_def) + } + }; + (ident, summary) + }; + self.call_substructure_method(cx, + span, type_ident, + self_args, nonself_args, + &StaticEnum(enum_def, summary)) + } } -/// Create variable names (as strings) to refer to the non-self -/// parameters -fn create_other_strs(n: uint) -> ~[~str] { - do vec::build |push| { - for uint::range(0, n) |i| { - push(fmt!("__other_%u", i)); +fn summarise_struct(cx: @ext_ctxt, span: span, + struct_def: &struct_def) -> Either { + let mut named_idents = ~[]; + let mut unnamed_count = 0; + for struct_def.fields.each |field| { + match field.node.kind { + ast::named_field(ident, _) => named_idents.push(ident), + ast::unnamed_field => unnamed_count += 1, } } -} -/// Like `create_other_strs`, but returns idents for the strings -fn create_other_idents(cx: @ext_ctxt, n: uint) -> ~[ident] { - do create_other_strs(n).map |&s| { - cx.ident_of(s) + + match (unnamed_count > 0, named_idents.is_empty()) { + (true, false) => cx.span_bug(span, + "A struct with named and unnamed \ + fields in generic `deriving`"), + // named fields + (_, false) => Right(named_idents), + // tuple structs (includes empty structs) + (_, _) => Left(unnamed_count) } } - /* helpful premade recipes */ /** @@ -786,7 +844,7 @@ left-to-right (`true`) or right-to-left (`false`). pub fn cs_fold(use_foldl: bool, f: &fn(@ext_ctxt, span, old: @expr, - self_f: @expr, other_fs: ~[@expr]) -> @expr, + self_f: @expr, other_fs: &[@expr]) -> @expr, base: @expr, enum_nonmatch_f: EnumNonMatchFunc, cx: @ext_ctxt, span: span, @@ -803,7 +861,11 @@ pub fn cs_fold(use_foldl: bool, } } }, - EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, all_enums) + EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, + all_enums, substructure.nonself_args), + StaticEnum(*) | StaticStruct(*) => { + cx.span_bug(span, "Static function in `deriving`") + } } } @@ -812,11 +874,12 @@ pub fn cs_fold(use_foldl: bool, Call the method that is being derived on all the fields, and then process the collected results. i.e. -``` -f(cx, span, ~[self_1.method(__other_1_1, __other_2_1), - self_2.method(__other_1_2, __other_2_2)]) -``` +~~~ +f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1), + self_2.method(__arg_1_2, __arg_2_2)]) +~~~ */ +#[inline(always)] pub fn cs_same_method(f: &fn(@ext_ctxt, span, ~[@expr]) -> @expr, enum_nonmatch_f: EnumNonMatchFunc, cx: @ext_ctxt, span: span, @@ -833,7 +896,11 @@ pub fn cs_same_method(f: &fn(@ext_ctxt, span, ~[@expr]) -> @expr, f(cx, span, called) }, - EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, all_enums) + EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, + all_enums, substructure.nonself_args), + StaticEnum(*) | StaticStruct(*) => { + cx.span_bug(span, "Static function in `deriving`") + } } } @@ -842,6 +909,7 @@ Fold together the results of calling the derived method on all the fields. `use_foldl` controls whether this is done left-to-right (`true`) or right-to-left (`false`). */ +#[inline(always)] pub fn cs_same_method_fold(use_foldl: bool, f: &fn(@ext_ctxt, span, @expr, @expr) -> @expr, base: @expr, @@ -869,7 +937,8 @@ pub fn cs_same_method_fold(use_foldl: bool, Use a given binop to combine the result of calling the derived method on all the fields. */ -pub fn cs_binop(binop: binop, base: @expr, +#[inline(always)] +pub fn cs_binop(binop: ast::binop, base: @expr, enum_nonmatch_f: EnumNonMatchFunc, cx: @ext_ctxt, span: span, substructure: &Substructure) -> @expr { @@ -887,18 +956,20 @@ pub fn cs_binop(binop: binop, base: @expr, } /// cs_binop with binop == or +#[inline(always)] pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc, cx: @ext_ctxt, span: span, substructure: &Substructure) -> @expr { - cs_binop(or, build::mk_bool(cx, span, false), + cs_binop(ast::or, build::mk_bool(cx, span, false), enum_nonmatch_f, cx, span, substructure) } /// cs_binop with binop == and +#[inline(always)] pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc, cx: @ext_ctxt, span: span, substructure: &Substructure) -> @expr { - cs_binop(and, build::mk_bool(cx, span, true), + cs_binop(ast::and, build::mk_bool(cx, span, true), enum_nonmatch_f, cx, span, substructure) } diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index f03306ea07ac8..9eb246ffe2228 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,25 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; -use ast::*; +use ast::{meta_item, item, expr, and}; +use codemap::span; use ext::base::ext_ctxt; use ext::build; -use ext::deriving::*; -use codemap::{span, spanned}; -use ast_util; -use opt_vec; +use ext::deriving::generic::*; pub fn expand_deriving_iter_bytes(cx: @ext_ctxt, span: span, - _mitem: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - expand_deriving(cx, - span, - in_items, - expand_deriving_iter_bytes_struct_def, - expand_deriving_iter_bytes_enum_def) + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: Path::new(~[~"core", ~"to_bytes", ~"IterBytes"]), + additional_bounds: ~[], + generics: LifetimeBounds::empty(), + methods: ~[ + MethodDef { + name: ~"iter_bytes", + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[ + Literal(Path::new(~[~"bool"])), + Literal(Path::new(~[~"core", ~"to_bytes", ~"Cb"])) + ], + ret_ty: Literal(Path::new(~[~"bool"])), + const_nonmatching: false, + combine_substructure: iter_bytes_substructure + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, &trait_def) } pub fn expand_deriving_obsolete(cx: @ext_ctxt, @@ -39,217 +51,47 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt, in_items } -fn create_derived_iter_bytes_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - method: @method) - -> @item { - let methods = [ method ]; - let trait_path = ~[ - cx.ident_of(~"core"), - cx.ident_of(~"to_bytes"), - cx.ident_of(~"IterBytes") - ]; - let trait_path = build::mk_raw_path_global(span, trait_path); - create_derived_impl(cx, span, type_ident, generics, methods, trait_path, - opt_vec::Empty, opt_vec::Empty) -} - -// Creates a method from the given set of statements conforming to the -// signature of the `iter_bytes` method. -fn create_iter_bytes_method(cx: @ext_ctxt, - span: span, - statements: ~[@stmt]) - -> @method { - // Create the `lsb0` parameter. - let bool_ident = cx.ident_of(~"bool"); - let lsb0_arg_type = build::mk_simple_ty_path(cx, span, bool_ident); - let lsb0_ident = cx.ident_of(~"__lsb0"); - let lsb0_arg = build::mk_arg(cx, span, lsb0_ident, lsb0_arg_type); - - // Create the `f` parameter. - let core_ident = cx.ident_of(~"core"); - let to_bytes_ident = cx.ident_of(~"to_bytes"); - let cb_ident = cx.ident_of(~"Cb"); - let core_to_bytes_cb_ident = ~[ core_ident, to_bytes_ident, cb_ident ]; - let f_arg_type = build::mk_ty_path(cx, span, core_to_bytes_cb_ident); - let f_ident = cx.ident_of(~"__f"); - let f_arg = build::mk_arg(cx, span, f_ident, f_arg_type); - - // Create the type of the return value. - let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; - - // Create the function declaration. - let inputs = ~[ lsb0_arg, f_arg ]; - let fn_decl = build::mk_fn_decl(inputs, output_type); - - // Create the body block. - let body_block = build::mk_block_(cx, span, statements); - - // Create the method. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of(~"iter_bytes"); - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } -} - -fn call_substructure_iter_bytes_method(cx: @ext_ctxt, - span: span, - self_field: @expr) - -> @stmt { - // Gather up the parameters we want to chain along. - let lsb0_ident = cx.ident_of(~"__lsb0"); - let f_ident = cx.ident_of(~"__f"); - let lsb0_expr = build::mk_path(cx, span, ~[ lsb0_ident ]); - let f_expr = build::mk_path(cx, span, ~[ f_ident ]); - - // Call the substructure method. - let iter_bytes_ident = cx.ident_of(~"iter_bytes"); - let self_call = build::mk_method_call(cx, - span, - self_field, - iter_bytes_ident, - ~[ lsb0_expr, f_expr ]); - - // Create a statement out of this expression. - build::mk_stmt(cx, span, self_call) -} - -fn expand_deriving_iter_bytes_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = expand_deriving_iter_bytes_struct_method(cx, - span, - struct_def); - - // Create the implementation. - return create_derived_iter_bytes_impl(cx, - span, - type_ident, - generics, - method); -} - -fn expand_deriving_iter_bytes_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = expand_deriving_iter_bytes_enum_method(cx, - span, - enum_definition); - - // Create the implementation. - return create_derived_iter_bytes_impl(cx, - span, - type_ident, - generics, - method); -} - -fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def) - -> @method { - let self_ident = cx.ident_of(~"self"); - - // Create the body of the method. - let mut statements = ~[]; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _, _) => { - // Create the accessor for this field. - let self_field = build::mk_access(cx, - span, - ~[ self_ident ], - ident); - - // Call the substructure method. - let stmt = call_substructure_iter_bytes_method(cx, - span, - self_field); - statements.push(stmt); - } - unnamed_field => { - cx.span_unimpl(span, - ~"unnamed fields with `deriving(IterBytes)`"); - } - } - } - - // Create the method itself. - return create_iter_bytes_method(cx, span, statements); -} - -fn expand_deriving_iter_bytes_enum_method(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def) - -> @method { - // Create the arms of the match in the method body. - let arms = do enum_definition.variants.mapi |i, variant| { - // Create the matching pattern. - let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); - - // Determine the discriminant. We will feed this value to the byte - // iteration function. - let discriminant; - match variant.node.disr_expr { - Some(copy disr_expr) => discriminant = disr_expr, - None => discriminant = build::mk_uint(cx, span, i), +fn iter_bytes_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + let lsb0_f = match substr.nonself_args { + [l, f] => ~[l, f], + _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`") + }; + let iter_bytes_ident = substr.method_ident; + let call_iterbytes = |thing_expr| { + build::mk_method_call(cx, span, + thing_expr, iter_bytes_ident, + copy lsb0_f) + }; + let mut exprs = ~[]; + let fields; + match *substr.fields { + Struct(ref fs) => { + fields = fs } + EnumMatching(copy index, ref variant, ref fs) => { + // Determine the discriminant. We will feed this value to the byte + // iteration function. + let discriminant = match variant.node.disr_expr { + Some(copy d)=> d, + None => build::mk_uint(cx, span, index) + }; - // Feed the discriminant to the byte iteration function. - let mut stmts = ~[]; - let discrim_stmt = call_substructure_iter_bytes_method(cx, - span, - discriminant); - stmts.push(discrim_stmt); + exprs.push(call_iterbytes(discriminant)); - // Feed each argument in this variant to the byte iteration function - // as well. - for uint::range(0, variant_arg_count(cx, span, variant)) |j| { - // Create the expression for this field. - let field_ident = cx.ident_of(~"__self_" + j.to_str()); - let field = build::mk_path(cx, span, ~[ field_ident ]); - - // Call the substructure method. - let stmt = call_substructure_iter_bytes_method(cx, span, field); - stmts.push(stmt); + fields = fs; } + _ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`") + } - // Create the pattern body. - let match_body_block = build::mk_block_(cx, span, stmts); - - // Create the arm. - ast::arm { - pats: ~[ pat ], - guard: None, - body: match_body_block, - } - }; + for fields.each |&(_, field, _)| { + exprs.push(call_iterbytes(field)); + } - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, arms); - let self_match_stmt = build::mk_stmt(cx, span, self_match_expr); + if exprs.len() == 0 { + cx.span_bug(span, "#[deriving(IterBytes)] needs at least one field"); + } - // Create the method. - create_iter_bytes_method(cx, span, ~[ self_match_stmt ]) + do vec::foldl(exprs[0], exprs.slice(1, exprs.len())) |prev, me| { + build::mk_binary(cx, span, and, prev, *me) + } } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 5aeeef2b17aee..3b94a95dfe032 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -12,14 +12,7 @@ /// #[deriving(IterBytes)] extensions. use ast; -use ast::{Ty, bind_by_ref, deref, enum_def}; -use ast::{expr, expr_match, ident, item, item_}; -use ast::{item_enum, item_impl, item_struct, Generics}; -use ast::{m_imm, meta_item, method}; -use ast::{named_field, pat, pat_ident, public}; -use ast::{struct_def, struct_variant_kind}; -use ast::{tuple_variant_kind}; -use ast::{ty_path, unnamed_field, variant}; +use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def}; use ext::base::ext_ctxt; use ext::build; use codemap::{span, respan}; @@ -30,6 +23,8 @@ pub mod clone; pub mod iter_bytes; pub mod encodable; pub mod decodable; +pub mod rand; +pub mod to_str; #[path="cmp/eq.rs"] pub mod eq; @@ -78,23 +73,25 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, meta_name_value(tname, _) | meta_list(tname, _) | meta_word(tname) => { + macro_rules! expand(($func:path) => ($func(cx, titem.span, + titem, in_items))); match *tname { - ~"Clone" => clone::expand_deriving_clone(cx, - titem.span, titem, in_items), - ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx, - titem.span, titem, in_items), - ~"Encodable" => encodable::expand_deriving_encodable(cx, - titem.span, titem, in_items), - ~"Decodable" => decodable::expand_deriving_decodable(cx, - titem.span, titem, in_items), - ~"Eq" => eq::expand_deriving_eq(cx, titem.span, - titem, in_items), - ~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span, - titem, in_items), - ~"Ord" => ord::expand_deriving_ord(cx, titem.span, - titem, in_items), - ~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span, - titem, in_items), + ~"Clone" => expand!(clone::expand_deriving_clone), + + ~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes), + + ~"Encodable" => expand!(encodable::expand_deriving_encodable), + ~"Decodable" => expand!(decodable::expand_deriving_decodable), + + ~"Eq" => expand!(eq::expand_deriving_eq), + ~"TotalEq" => expand!(totaleq::expand_deriving_totaleq), + ~"Ord" => expand!(ord::expand_deriving_ord), + ~"TotalOrd" => expand!(totalord::expand_deriving_totalord), + + ~"Rand" => expand!(rand::expand_deriving_rand), + + ~"ToStr" => expand!(to_str::expand_deriving_to_str), + tname => { cx.span_err(titem.span, fmt!("unknown \ `deriving` trait: `%s`", tname)); @@ -118,14 +115,14 @@ pub fn expand_deriving(cx: @ext_ctxt, for in_items.each |item| { result.push(copy *item); match item.node { - item_struct(struct_def, ref generics) => { + ast::item_struct(struct_def, ref generics) => { result.push(expand_deriving_struct_def(cx, span, struct_def, item.ident, generics)); } - item_enum(ref enum_definition, ref generics) => { + ast::item_enum(ref enum_definition, ref generics) => { result.push(expand_deriving_enum_def(cx, span, enum_definition, @@ -138,7 +135,7 @@ pub fn expand_deriving(cx: @ext_ctxt, result } -fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item { +fn create_impl_item(cx: @ext_ctxt, span: span, item: ast::item_) -> @item { let doc_attr = respan(span, ast::lit_str(@~"Automatically derived.")); let doc_attr = respan(span, ast::meta_name_value(@~"doc", doc_attr)); @@ -154,7 +151,7 @@ fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item { attrs: ~[doc_attr], id: cx.next_id(), node: item, - vis: public, + vis: ast::public, span: span, } } @@ -173,22 +170,29 @@ pub fn create_self_type_with_params(cx: @ext_ctxt, self_ty_params.push(self_ty_param); } + let lifetime = if generics.lifetimes.is_empty() { + None + } else { + Some(@*generics.lifetimes.get(0)) + }; + + // Create the type of `self`. let self_type = build::mk_raw_path_(span, ~[ type_ident ], + lifetime, self_ty_params); - let self_type = ty_path(self_type, cx.next_id()); - @ast::Ty { id: cx.next_id(), node: self_type, span: span } + build::mk_ty_path_path(cx, span, self_type) } pub fn create_derived_impl(cx: @ext_ctxt, span: span, type_ident: ident, generics: &Generics, - methods: &[@method], + methods: &[@ast::method], trait_path: @ast::Path, - mut impl_ty_params: opt_vec::OptVec, - bounds_paths: opt_vec::OptVec<~[ident]>) + mut impl_generics: Generics, + bounds_paths: opt_vec::OptVec<@ast::Path>) -> @item { /*! * @@ -204,21 +208,22 @@ pub fn create_derived_impl(cx: @ext_ctxt, */ // Copy the lifetimes - let impl_lifetimes = generics.lifetimes.map(|l| { - build::mk_lifetime(cx, l.span, l.ident) - }); + for generics.lifetimes.each |l| { + impl_generics.lifetimes.push(copy *l) + }; // Create the type parameters. for generics.ty_params.each |ty_param| { + // extra restrictions on the generics parameters to the type being derived upon let mut bounds = do bounds_paths.map |&bound_path| { - build::mk_trait_ty_param_bound_global(cx, span, bound_path) + build::mk_trait_ty_param_bound_(cx, bound_path) }; let this_trait_bound = build::mk_trait_ty_param_bound_(cx, trait_path); bounds.push(this_trait_bound); - impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds)); + impl_generics.ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds)); } // Create the reference to the trait. @@ -231,8 +236,7 @@ pub fn create_derived_impl(cx: @ext_ctxt, generics); // Create the impl item. - let impl_item = item_impl(Generics {lifetimes: impl_lifetimes, - ty_params: impl_ty_params}, + let impl_item = ast::item_impl(impl_generics, Some(trait_ref), self_type, methods.map(|x| *x)); @@ -240,114 +244,135 @@ pub fn create_derived_impl(cx: @ext_ctxt, } pub fn create_subpatterns(cx: @ext_ctxt, - span: span, - prefix: ~str, - n: uint) - -> ~[@pat] { - let mut subpats = ~[]; - for uint::range(0, n) |_i| { - // Create the subidentifier. - let index = subpats.len(); - let ident = cx.ident_of(fmt!("%s_%u", prefix, index)); - - // Create the subpattern. - let subpath = build::mk_raw_path(span, ~[ ident ]); - let subpat = pat_ident(bind_by_ref(m_imm), subpath, None); - let subpat = build::mk_pat(cx, span, subpat); - subpats.push(subpat); + span: span, + field_paths: ~[@ast::Path], + mutbl: ast::mutability) + -> ~[@ast::pat] { + do field_paths.map |&path| { + build::mk_pat(cx, span, + ast::pat_ident(ast::bind_by_ref(mutbl), path, None)) } - return subpats; } -pub fn is_struct_tuple(struct_def: &struct_def) -> bool { - struct_def.fields.len() > 0 && struct_def.fields.all(|f| { - match f.node.kind { - named_field(*) => false, - unnamed_field => true - } - }) +#[deriving(Eq)] // dogfooding! +enum StructType { + Unknown, Record, Tuple +} + +pub fn create_struct_pattern(cx: @ext_ctxt, + span: span, + struct_ident: ident, + struct_def: &struct_def, + prefix: &str, + mutbl: ast::mutability) + -> (@ast::pat, ~[(Option, @expr)]) { + if struct_def.fields.is_empty() { + return ( + build::mk_pat_ident_with_binding_mode( + cx, span, struct_ident, ast::bind_infer), + ~[]); + } + + let matching_path = build::mk_raw_path(span, ~[ struct_ident ]); + + let mut paths = ~[], ident_expr = ~[]; + + let mut struct_type = Unknown; + + for struct_def.fields.eachi |i, struct_field| { + let opt_id = match struct_field.node.kind { + ast::named_field(ident, _) if (struct_type == Unknown || + struct_type == Record) => { + struct_type = Record; + Some(ident) + } + ast::unnamed_field if (struct_type == Unknown || + struct_type == Tuple) => { + struct_type = Tuple; + None + } + _ => { + cx.span_bug(span, "A struct with named and unnamed fields in `deriving`"); + } + }; + let path = build::mk_raw_path(span, + ~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]); + paths.push(path); + ident_expr.push((opt_id, build::mk_path_raw(cx, span, path))); + } + + let subpats = create_subpatterns(cx, span, paths, mutbl); + + // struct_type is definitely not Unknown, since struct_def.fields + // must be nonempty to reach here + let pattern = if struct_type == Record { + let field_pats = do vec::build |push| { + for vec::each2(subpats, ident_expr) |&pat, &(id, _)| { + // id is guaranteed to be Some + push(ast::field_pat { ident: id.get(), pat: pat }) + } + }; + build::mk_pat_struct(cx, span, matching_path, field_pats) + } else { + build::mk_pat_enum(cx, span, matching_path, subpats) + }; + + (pattern, ident_expr) } pub fn create_enum_variant_pattern(cx: @ext_ctxt, - span: span, - variant: &variant, - prefix: ~str) - -> @pat { + span: span, + variant: &ast::variant, + prefix: &str, + mutbl: ast::mutability) + -> (@ast::pat, ~[(Option, @expr)]) { + let variant_ident = variant.node.name; match variant.node.kind { - tuple_variant_kind(ref variant_args) => { - if variant_args.len() == 0 { - return build::mk_pat_ident_with_binding_mode( - cx, span, variant_ident, ast::bind_infer); + ast::tuple_variant_kind(ref variant_args) => { + if variant_args.is_empty() { + return (build::mk_pat_ident_with_binding_mode( + cx, span, variant_ident, ast::bind_infer), ~[]); } let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); - let subpats = create_subpatterns(cx, - span, - prefix, - variant_args.len()); - return build::mk_pat_enum(cx, span, matching_path, subpats); - } - struct_variant_kind(struct_def) => { - let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); - let subpats = create_subpatterns(cx, - span, - prefix, - struct_def.fields.len()); - - let field_pats = do struct_def.fields.mapi |i, struct_field| { - let ident = match struct_field.node.kind { - named_field(ident, _, _) => ident, - unnamed_field => { - cx.span_bug(span, ~"unexpected unnamed field"); - } - }; - ast::field_pat { ident: ident, pat: subpats[i] } - }; + let mut paths = ~[], ident_expr = ~[]; + for uint::range(0, variant_args.len()) |i| { + let path = build::mk_raw_path(span, + ~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]); - build::mk_pat_struct(cx, span, matching_path, field_pats) - } - } -} + paths.push(path); + ident_expr.push((None, build::mk_path_raw(cx, span, path))); + } -pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &variant) -> uint { - match variant.node.kind { - tuple_variant_kind(ref args) => args.len(), - struct_variant_kind(ref struct_def) => struct_def.fields.len(), - } -} + let subpats = create_subpatterns(cx, span, paths, mutbl); -/// Iterate through the idents of the variant arguments. The field is -/// unnamed (i.e. it's not a struct-like enum), then `None`. -pub fn each_variant_arg_ident(_cx: @ext_ctxt, _span: span, - variant: &variant, it: &fn(uint, Option) -> bool) { - match variant.node.kind { - tuple_variant_kind(ref args) => { - for uint::range(0, args.len()) |i| { - if !it(i, None) { break } - } + (build::mk_pat_enum(cx, span, matching_path, subpats), + ident_expr) } - struct_variant_kind(ref struct_def) => { - for struct_def.fields.eachi |i, f| { - let id = match f.node.kind { - named_field(ident, _, _) => Some(ident), - unnamed_field => None - }; - if !it(i, id) { break } - } + ast::struct_variant_kind(struct_def) => { + create_struct_pattern(cx, span, + variant_ident, struct_def, + prefix, + mutbl) } } } +pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &ast::variant) -> uint { + match variant.node.kind { + ast::tuple_variant_kind(ref args) => args.len(), + ast::struct_variant_kind(ref struct_def) => struct_def.fields.len(), + } +} pub fn expand_enum_or_struct_match(cx: @ext_ctxt, span: span, arms: ~[ ast::arm ]) -> @expr { - let self_ident = cx.ident_of(~"self"); - let self_expr = build::mk_path(cx, span, ~[ self_ident ]); - let self_expr = build::mk_unary(cx, span, deref, self_expr); - let self_match_expr = expr_match(self_expr, arms); + let self_expr = build::make_self(cx, span); + let self_expr = build::mk_unary(cx, span, ast::deref, self_expr); + let self_match_expr = ast::expr_match(self_expr, arms); build::mk_expr(cx, span, self_match_expr) } diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs new file mode 100644 index 0000000000000..9030be86f39d0 --- /dev/null +++ b/src/libsyntax/ext/deriving/rand.rs @@ -0,0 +1,141 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ast; +use ast::{meta_item, item, expr, ident}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +pub fn expand_deriving_rand(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) + -> ~[@item] { + let trait_def = TraitDef { + path: Path::new(~[~"core", ~"rand", ~"Rand"]), + additional_bounds: ~[], + generics: LifetimeBounds::empty(), + methods: ~[ + MethodDef { + name: ~"rand", + generics: LifetimeBounds { + lifetimes: ~[], + bounds: ~[(~"R", + ~[ Path::new(~[~"core", ~"rand", ~"Rng"]) ])] + }, + self_ty: None, + args: ~[ + Ptr(~Literal(Path::new_local(~"R")), + Borrowed(None, ast::m_mutbl)) + ], + ret_ty: Self, + const_nonmatching: false, + combine_substructure: rand_substructure + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, &trait_def) +} + +fn rand_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + let rng = match substr.nonself_args { + [rng] => ~[ rng ], + _ => cx.bug("Incorrect number of arguments to `rand` in `deriving(Rand)`") + }; + let rand_ident = ~[ + cx.ident_of("core"), + cx.ident_of("rand"), + cx.ident_of("Rand"), + cx.ident_of("rand") + ]; + let rand_call = || { + build::mk_call_global(cx, + span, + copy rand_ident, + ~[ build::duplicate_expr(cx, rng[0]) ]) + }; + + return match *substr.fields { + StaticStruct(_, ref summary) => { + rand_thing(cx, span, substr.type_ident, summary, rand_call) + } + StaticEnum(_, ref variants) => { + if variants.is_empty() { + cx.span_fatal(span, "`Rand` cannot be derived for enums with no variants"); + } + + let variant_count = build::mk_uint(cx, span, variants.len()); + + // need to specify the uint-ness of the random number + let u32_ty = build::mk_ty_path(cx, span, ~[cx.ident_of("uint")]); + let r_ty = build::mk_ty_path(cx, span, ~[cx.ident_of("R")]); + let rand_name = build::mk_raw_path_(span, copy rand_ident, None, ~[ u32_ty, r_ty ]); + let rand_name = build::mk_path_raw(cx, span, rand_name); + + let rv_call = build::mk_call_(cx, + span, + rand_name, + ~[ build::duplicate_expr(cx, rng[0]) ]); + + // rand() % variants.len() + let rand_variant = build::mk_binary(cx, span, ast::rem, + rv_call, variant_count); + + let mut arms = do variants.mapi |i, id_sum| { + let i_expr = build::mk_uint(cx, span, i); + let pat = build::mk_pat_lit(cx, span, i_expr); + + match *id_sum { + (ident, ref summary) => { + build::mk_arm(cx, span, + ~[ pat ], + rand_thing(cx, span, ident, summary, rand_call)) + } + } + }; + + // _ => {} at the end. Should never occur + arms.push(build::mk_unreachable_arm(cx, span)); + + build::mk_expr(cx, span, + ast::expr_match(rand_variant, arms)) + } + _ => cx.bug("Non-static method in `deriving(Rand)`") + }; + + fn rand_thing(cx: @ext_ctxt, span: span, + ctor_ident: ident, + summary: &Either, + rand_call: &fn() -> @expr) -> @expr { + let ctor_ident = ~[ ctor_ident ]; + match *summary { + Left(copy count) => { + if count == 0 { + build::mk_path(cx, span, ctor_ident) + } else { + let exprs = vec::from_fn(count, |_| rand_call()); + build::mk_call(cx, span, ctor_ident, exprs) + } + } + Right(ref fields) => { + let rand_fields = do fields.map |ident| { + build::Field { + ident: *ident, + ex: rand_call() + } + }; + build::mk_struct_e(cx, span, ctor_ident, rand_fields) + } + } + } +} diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs new file mode 100644 index 0000000000000..6010354349e64 --- /dev/null +++ b/src/libsyntax/ext/deriving/to_str.rs @@ -0,0 +1,54 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +pub fn expand_deriving_to_str(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) + -> ~[@item] { + let trait_def = TraitDef { + path: Path::new(~[~"core", ~"to_str", ~"ToStr"]), + additional_bounds: ~[], + generics: LifetimeBounds::empty(), + methods: ~[ + MethodDef { + name: ~"to_str", + generics: LifetimeBounds::empty(), + self_ty: borrowed_explicit_self(), + args: ~[], + ret_ty: Ptr(~Literal(Path::new_local(~"str")), Owned), + const_nonmatching: false, + combine_substructure: to_str_substructure + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, &trait_def) +} + +fn to_str_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + match substr.self_args { + [self_obj] => { + let self_addr = build::mk_addr_of(cx, span, self_obj); + build::mk_call_global(cx, span, + ~[cx.ident_of("core"), + cx.ident_of("sys"), + cx.ident_of("log_str")], + ~[self_addr]) + } + _ => cx.span_bug(span, ~"Invalid number of arguments in `deriving(ToStr)`") + } +} diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs new file mode 100644 index 0000000000000..0bb88dae26b2a --- /dev/null +++ b/src/libsyntax/ext/deriving/ty.rs @@ -0,0 +1,242 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +A mini version of ast::Ty, which is easier to use, and features an +explicit `Self` type to use when specifying impls to be derived. +*/ + +use ast; +use ast::{expr,Generics,ident}; +use ext::base::ext_ctxt; +use ext::build; +use codemap::{span,respan}; +use opt_vec; + +/// The types of pointers +#[deriving(Eq)] +pub enum PtrTy { + Owned, // ~ + Managed(ast::mutability), // @[mut] + Borrowed(Option<~str>, ast::mutability), // &['lifetime] [mut] +} + +/// A path, e.g. `::core::option::Option::` (global). Has support +/// for type parameters and a lifetime. +#[deriving(Eq)] +pub struct Path { + path: ~[~str], + lifetime: Option<~str>, + params: ~[~Ty], + global: bool +} + +pub impl Path { + fn new(path: ~[~str]) -> Path { + Path::new_(path, None, ~[], true) + } + fn new_local(path: ~str) -> Path { + Path::new_(~[ path ], None, ~[], false) + } + fn new_(path: ~[~str], lifetime: Option<~str>, params: ~[~Ty], global: bool) -> Path { + Path { + path: path, + lifetime: lifetime, + params: params, + global: global + } + } + + fn to_ty(&self, cx: @ext_ctxt, span: span, + self_ty: ident, self_generics: &Generics) -> @ast::Ty { + build::mk_ty_path_path(cx, span, + self.to_path(cx, span, + self_ty, self_generics)) + } + fn to_path(&self, cx: @ext_ctxt, span: span, + self_ty: ident, self_generics: &Generics) -> @ast::Path { + let idents = self.path.map(|s| cx.ident_of(*s) ); + let lt = mk_lifetime(cx, span, self.lifetime); + let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics)); + + if self.global { + build::mk_raw_path_global_(span, idents, lt, tys) + } else { + build::mk_raw_path_(span, idents, lt, tys) + } + } +} + +/// A type. Supports pointers (except for *), Self, and literals +#[deriving(Eq)] +pub enum Ty { + Self, + // &/~/@ Ty + Ptr(~Ty, PtrTy), + // mod::mod::Type<[lifetime], [Params...]>, including a plain type + // parameter, and things like `int` + Literal(Path), + // includes nil + Tuple(~[Ty]) +} + +pub fn borrowed_ptrty() -> PtrTy { + Borrowed(None, ast::m_imm) +} +pub fn borrowed(ty: ~Ty) -> Ty { + Ptr(ty, borrowed_ptrty()) +} + +pub fn borrowed_explicit_self() -> Option> { + Some(Some(borrowed_ptrty())) +} + +pub fn borrowed_self() -> Ty { + borrowed(~Self) +} + +pub fn nil_ty() -> Ty { + Tuple(~[]) +} + +fn mk_lifetime(cx: @ext_ctxt, span: span, lt: Option<~str>) -> Option<@ast::Lifetime> { + match lt { + Some(s) => Some(@build::mk_lifetime(cx, span, cx.ident_of(s))), + None => None + } +} + +pub impl Ty { + fn to_ty(&self, cx: @ext_ctxt, span: span, + self_ty: ident, self_generics: &Generics) -> @ast::Ty { + match *self { + Ptr(ref ty, ref ptr) => { + let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); + match *ptr { + Owned => { + build::mk_ty_uniq(cx, span, raw_ty) + } + Managed(copy mutbl) => { + build::mk_ty_box(cx, span, raw_ty, mutbl) + } + Borrowed(copy lt, copy mutbl) => { + let lt = mk_lifetime(cx, span, lt); + build::mk_ty_rptr(cx, span, raw_ty, lt, mutbl) + } + } + } + Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } + Self => { + build::mk_ty_path_path(cx, span, self.to_path(cx, span, self_ty, self_generics)) + } + Tuple(ref fields) => { + let ty = if fields.is_empty() { + ast::ty_nil + } else { + ast::ty_tup(fields.map(|f| f.to_ty(cx, span, self_ty, self_generics))) + }; + + build::mk_ty(cx, span, ty) + } + } + } + + fn to_path(&self, cx: @ext_ctxt, span: span, + self_ty: ident, self_generics: &Generics) -> @ast::Path { + match *self { + Self => { + let self_params = do self_generics.ty_params.map |ty_param| { + build::mk_ty_path(cx, span, ~[ ty_param.ident ]) + }; + let lifetime = if self_generics.lifetimes.is_empty() { + None + } else { + Some(@*self_generics.lifetimes.get(0)) + }; + + build::mk_raw_path_(span, ~[self_ty], lifetime, + opt_vec::take_vec(self_params)) + } + Literal(ref p) => { + p.to_path(cx, span, self_ty, self_generics) + } + Ptr(*) => { cx.span_bug(span, ~"Pointer in a path in generic `deriving`") } + Tuple(*) => { cx.span_bug(span, ~"Tuple in a path in generic `deriving`") } + } + } +} + + +fn mk_ty_param(cx: @ext_ctxt, span: span, name: ~str, bounds: ~[Path], + self_ident: ident, self_generics: &Generics) -> ast::TyParam { + let bounds = opt_vec::from( + do bounds.map |b| { + let path = b.to_path(cx, span, self_ident, self_generics); + build::mk_trait_ty_param_bound_(cx, path) + }); + build::mk_ty_param(cx, cx.ident_of(name), @bounds) +} + +fn mk_generics(lifetimes: ~[ast::Lifetime], ty_params: ~[ast::TyParam]) -> Generics { + Generics { + lifetimes: opt_vec::from(lifetimes), + ty_params: opt_vec::from(ty_params) + } +} + +/// Lifetimes and bounds on type parameters +pub struct LifetimeBounds { + lifetimes: ~[~str], + bounds: ~[(~str, ~[Path])] +} + +pub impl LifetimeBounds { + fn empty() -> LifetimeBounds { + LifetimeBounds { + lifetimes: ~[], bounds: ~[] + } + } + fn to_generics(&self, cx: @ext_ctxt, span: span, + self_ty: ident, self_generics: &Generics) -> Generics { + let lifetimes = do self.lifetimes.map |<| { + build::mk_lifetime(cx, span, cx.ident_of(lt)) + }; + let ty_params = do self.bounds.map |&(name, bounds)| { + mk_ty_param(cx, span, name, bounds, self_ty, self_generics) + }; + mk_generics(lifetimes, ty_params) + } +} + + +pub fn get_explicit_self(cx: @ext_ctxt, span: span, self_ptr: Option) + -> (@expr, ast::self_ty) { + let self_path = build::make_self(cx, span); + match self_ptr { + None => { + (self_path, respan(span, ast::sty_value)) + } + Some(ptr) => { + let self_ty = respan( + span, + match ptr { + Owned => ast::sty_uniq(ast::m_imm), + Managed(mutbl) => ast::sty_box(mutbl), + Borrowed(lt, mutbl) => { + let lt = lt.map(|s| @build::mk_lifetime(cx, span, + cx.ident_of(*s))); + ast::sty_region(lt, mutbl) + } + }); + let self_expr = build::mk_deref(cx, span, self_path); + (self_expr, self_ty) + } + } +} diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 5e5fd7d97b19f..5b1e3737b236b 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -34,13 +34,3 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) }; MRExpr(e) } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fde5a2594226e..0fe28dadbc708 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -112,6 +112,7 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv, fld: @ast_fold, orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod) -> ast::_mod { + // Fold the contents first: let module_ = orig(module_, fld); @@ -192,18 +193,8 @@ pub fn expand_item(extsbox: @mut SyntaxEnv, } // does this attribute list contain "macro_escape" ? -pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool{ - let mut accum = false; - do attrs.each |attr| { - let mname = attr::get_attr_name(attr); - if (mname == @~"macro_escape") { - accum = true; - false - } else { - true - } - } - accum +pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool { + attrs.any(|attr| "macro_escape" == *attr::get_attr_name(attr)) } // this macro disables (one layer of) macro @@ -483,11 +474,62 @@ pub fn core_macros() -> ~str { ) ) + macro_rules! assert_approx_eq ( + ($given:expr , $expected:expr) => ( + { + use core::cmp::ApproxEq; + + let given_val = $given; + let expected_val = $expected; + // check both directions of equality.... + if !( + given_val.approx_eq(&expected_val) && + expected_val.approx_eq(&given_val) + ) { + fail!(\"left: %? does not approximately equal right: %?\", + given_val, expected_val); + } + } + ); + ($given:expr , $expected:expr , $epsilon:expr) => ( + { + use core::cmp::ApproxEq; + + let given_val = $given; + let expected_val = $expected; + let epsilon_val = $epsilon; + // check both directions of equality.... + if !( + given_val.approx_eq_eps(&expected_val, &epsilon_val) && + expected_val.approx_eq_eps(&given_val, &epsilon_val) + ) { + fail!(\"left: %? does not approximately equal right: %? with epsilon: %?\", + given_val, expected_val, epsilon_val); + } + } + ) + ) + macro_rules! condition ( + { pub $c:ident: $in:ty -> $out:ty; } => { + + pub mod $c { + fn key(_x: @::core::condition::Handler<$in,$out>) { } + + pub static cond : + ::core::condition::Condition<'static,$in,$out> = + ::core::condition::Condition { + name: stringify!($c), + key: key + }; + } + }; + { $c:ident: $in:ty -> $out:ty; } => { - mod $c { + // FIXME (#6009): remove mod's `pub` below once variant above lands. + pub mod $c { fn key(_x: @::core::condition::Handler<$in,$out>) { } pub static cond : @@ -721,11 +763,3 @@ mod test { } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 9bbe617eb070b..1a8edec37145c 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -49,12 +49,12 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) fn pieces_to_expr(cx: @ext_ctxt, sp: span, pieces: ~[Piece], args: ~[@ast::expr]) -> @ast::expr { - fn make_path_vec(cx: @ext_ctxt, ident: @~str) -> ~[ast::ident] { + fn make_path_vec(cx: @ext_ctxt, ident: &str) -> ~[ast::ident] { let intr = cx.parse_sess().interner; - return ~[intr.intern(@~"unstable"), intr.intern(@~"extfmt"), - intr.intern(@~"rt"), intr.intern(ident)]; + return ~[intr.intern("unstable"), intr.intern("extfmt"), + intr.intern("rt"), intr.intern(ident)]; } - fn make_rt_path_expr(cx: @ext_ctxt, sp: span, nm: @~str) -> @ast::expr { + fn make_rt_path_expr(cx: @ext_ctxt, sp: span, nm: &str) -> @ast::expr { let path = make_path_vec(cx, nm); return mk_path_global(cx, sp, path); } @@ -63,28 +63,28 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, fn make_rt_conv_expr(cx: @ext_ctxt, sp: span, cnv: &Conv) -> @ast::expr { fn make_flags(cx: @ext_ctxt, sp: span, flags: ~[Flag]) -> @ast::expr { - let mut tmp_expr = make_rt_path_expr(cx, sp, @~"flag_none"); + let mut tmp_expr = make_rt_path_expr(cx, sp, "flag_none"); for flags.each |f| { let fstr = match *f { - FlagLeftJustify => ~"flag_left_justify", - FlagLeftZeroPad => ~"flag_left_zero_pad", - FlagSpaceForSign => ~"flag_space_for_sign", - FlagSignAlways => ~"flag_sign_always", - FlagAlternate => ~"flag_alternate" + FlagLeftJustify => "flag_left_justify", + FlagLeftZeroPad => "flag_left_zero_pad", + FlagSpaceForSign => "flag_space_for_sign", + FlagSignAlways => "flag_sign_always", + FlagAlternate => "flag_alternate" }; tmp_expr = mk_binary(cx, sp, ast::bitor, tmp_expr, - make_rt_path_expr(cx, sp, @fstr)); + make_rt_path_expr(cx, sp, fstr)); } return tmp_expr; } fn make_count(cx: @ext_ctxt, sp: span, cnt: Count) -> @ast::expr { match cnt { CountImplied => { - return make_rt_path_expr(cx, sp, @~"CountImplied"); + return make_rt_path_expr(cx, sp, "CountImplied"); } CountIs(c) => { let count_lit = mk_uint(cx, sp, c as uint); - let count_is_path = make_path_vec(cx, @~"CountIs"); + let count_is_path = make_path_vec(cx, "CountIs"); let count_is_args = ~[count_lit]; return mk_call_global(cx, sp, count_is_path, count_is_args); } @@ -92,17 +92,16 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, } } fn make_ty(cx: @ext_ctxt, sp: span, t: Ty) -> @ast::expr { - let rt_type; - match t { + let rt_type = match t { TyHex(c) => match c { - CaseUpper => rt_type = ~"TyHexUpper", - CaseLower => rt_type = ~"TyHexLower" + CaseUpper => "TyHexUpper", + CaseLower => "TyHexLower" }, - TyBits => rt_type = ~"TyBits", - TyOctal => rt_type = ~"TyOctal", - _ => rt_type = ~"TyDefault" - } - return make_rt_path_expr(cx, sp, @rt_type); + TyBits => "TyBits", + TyOctal => "TyOctal", + _ => "TyDefault" + }; + return make_rt_path_expr(cx, sp, rt_type); } fn make_conv_struct(cx: @ext_ctxt, sp: span, flags_expr: @ast::expr, width_expr: @ast::expr, precision_expr: @ast::expr, @@ -111,19 +110,19 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, mk_global_struct_e( cx, sp, - make_path_vec(cx, @~"Conv"), + make_path_vec(cx, "Conv"), ~[ build::Field { - ident: intr.intern(@~"flags"), ex: flags_expr + ident: intr.intern("flags"), ex: flags_expr }, build::Field { - ident: intr.intern(@~"width"), ex: width_expr + ident: intr.intern("width"), ex: width_expr }, build::Field { - ident: intr.intern(@~"precision"), ex: precision_expr + ident: intr.intern("precision"), ex: precision_expr }, build::Field { - ident: intr.intern(@~"ty"), ex: ty_expr + ident: intr.intern("ty"), ex: ty_expr }, ] ) @@ -138,7 +137,7 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, fn make_conv_call(cx: @ext_ctxt, sp: span, conv_type: &str, cnv: &Conv, arg: @ast::expr, buf: @ast::expr) -> @ast::expr { let fname = ~"conv_" + conv_type; - let path = make_path_vec(cx, @fname); + let path = make_path_vec(cx, fname); let cnv_expr = make_rt_conv_expr(cx, sp, cnv); let args = ~[cnv_expr, arg, buf]; return mk_call_global(cx, arg.span, path, args); @@ -259,10 +258,10 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, let nargs = args.len(); /* 'ident' is the local buffer building up the result of fmt! */ - let ident = cx.parse_sess().interner.intern(@~"__fmtbuf"); + let ident = cx.parse_sess().interner.intern("__fmtbuf"); let buf = || mk_path(cx, fmt_sp, ~[ident]); - let str_ident = cx.parse_sess().interner.intern(@~"str"); - let push_ident = cx.parse_sess().interner.intern(@~"push_str"); + let str_ident = cx.parse_sess().interner.intern("str"); + let push_ident = cx.parse_sess().interner.intern("push_str"); let mut stms = ~[]; /* Translate each piece (portion of the fmt expression) by invoking the @@ -273,15 +272,13 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, match pc { /* Raw strings get appended via str::push_str */ PieceString(s) => { - let portion = mk_uniq_str(cx, fmt_sp, s); - /* If this is the first portion, then initialize the local buffer with it directly. If it's actually the only piece, then there's no need for it to be mutable */ if i == 0 { - stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, portion)); + stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, mk_uniq_str(cx, fmt_sp, s))); } else { - let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), portion]; + let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), mk_base_str(cx, fmt_sp, s)]; let call = mk_call_global(cx, fmt_sp, ~[str_ident, push_ident], @@ -322,12 +319,3 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, return mk_block(cx, fmt_sp, ~[], stms, Some(buf())); } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 34d6978abdddd..76d9a9420ce50 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -22,7 +22,7 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, cx.print_backtrace(); io::stdout().write_line( print::pprust::tt_to_str( - ast::tt_delim(vec::from_slice(tt)), + ast::tt_delim(vec::to_owned(tt)), cx.parse_sess().interner)); //trivial expression diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index deaf1b1c754a0..a514828725866 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -138,9 +138,9 @@ pub trait ext_ctxt_ast_builder { impl ext_ctxt_ast_builder for @ext_ctxt { fn ty_option(&self, ty: @ast::Ty) -> @ast::Ty { self.ty_path_ast_builder(path_global(~[ - self.ident_of(~"core"), - self.ident_of(~"option"), - self.ident_of(~"Option") + self.ident_of("core"), + self.ident_of("option"), + self.ident_of("Option") ], dummy_sp()).add_ty(ty)) } @@ -360,12 +360,12 @@ impl ext_ctxt_ast_builder for @ext_ctxt { let vi = ast::view_item_use(~[ @codemap::spanned { node: ast::view_path_simple( - self.ident_of(~"Owned"), + self.ident_of("Owned"), path( ~[ - self.ident_of(~"core"), - self.ident_of(~"kinds"), - self.ident_of(~"Owned") + self.ident_of("core"), + self.ident_of("kinds"), + self.ident_of("Owned") ], codemap::dummy_sp() ), diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs index c2c0c06342bae..38e43d1ade562 100644 --- a/src/libsyntax/ext/pipes/check.rs +++ b/src/libsyntax/ext/pipes/check.rs @@ -80,4 +80,3 @@ impl proto::visitor<(), (), ()> for @ext_ctxt { } } } - diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index 4597dab89cbfe..8799bd064f658 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -38,11 +38,11 @@ updating the states using rule (2) until there are no changes. */ use ext::base::ext_ctxt; -use ext::pipes::proto::protocol; +use ext::pipes::proto::{protocol_}; use std::bitv::Bitv; -pub fn analyze(proto: protocol, _cx: @ext_ctxt) { +pub fn analyze(proto: @mut protocol_, _cx: @ext_ctxt) { debug!("initializing colive analysis"); let num_states = proto.num_states(); let mut colive = do (copy proto.states).map_to_vec |state| { @@ -104,4 +104,3 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) { proto.bounded = Some(true); } } - diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs index 81b2442ea8257..642f22e973680 100644 --- a/src/libsyntax/ext/pipes/mod.rs +++ b/src/libsyntax/ext/pipes/mod.rs @@ -74,7 +74,7 @@ pub fn expand_proto(cx: @ext_ctxt, _sp: span, id: ast::ident, let rdr = tt_rdr as @reader; let rust_parser = Parser(sess, cfg, rdr.dup()); - let mut proto = rust_parser.parse_proto(cx.str_of(id)); + let proto = rust_parser.parse_proto(cx.str_of(id)); // check for errors visit(proto, cx); @@ -85,4 +85,3 @@ pub fn expand_proto(cx: @ext_ctxt, _sp: span, id: ast::ident, // compile base::MRItem(proto.compile(cx)) } - diff --git a/src/libsyntax/ext/pipes/parse_proto.rs b/src/libsyntax/ext/pipes/parse_proto.rs index f9346f49b61f0..5c99ddc9040ab 100644 --- a/src/libsyntax/ext/pipes/parse_proto.rs +++ b/src/libsyntax/ext/pipes/parse_proto.rs @@ -32,7 +32,7 @@ impl proto_parser for parser::Parser { sep: None, trailing_sep_allowed: false, }, - |self| self.parse_state(proto) + |this| this.parse_state(proto) ); return proto; @@ -70,7 +70,7 @@ impl proto_parser for parser::Parser { sep: Some(token::COMMA), trailing_sep_allowed: true, }, - |self| self.parse_message(state) + |this| this.parse_message(state) ); } diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 3311c61de8b64..b537ef87d543f 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -58,12 +58,13 @@ impl gen_send for message { path(~[this.data_name()], span) .add_tys(cx.ty_vars_global(&this.generics.ty_params))); let args_ast = vec::append( - ~[cx.arg(cx.ident_of(~"pipe"), + ~[cx.arg(cx.ident_of("pipe"), pipe_ty)], args_ast); let mut body = ~"{\n"; body += fmt!("use super::%s;\n", name); + body += ~"let mut pipe = pipe;\n"; if this.proto.is_bounded() { let (sp, rp) = match (this.dir, next.dir) { @@ -73,12 +74,12 @@ impl gen_send for message { (recv, recv) => (~"c", ~"s") }; - body += ~"let b = pipe.reuse_buffer();\n"; + body += ~"let mut b = pipe.reuse_buffer();\n"; body += fmt!("let %s = ::core::pipes::SendPacketBuffered(\ - &(b.buffer.data.%s));\n", + &mut (b.buffer.data.%s));\n", sp, next.name); body += fmt!("let %s = ::core::pipes::RecvPacketBuffered(\ - &(b.buffer.data.%s));\n", + &mut (b.buffer.data.%s));\n", rp, next.name); } else { @@ -135,7 +136,7 @@ impl gen_send for message { }; let args_ast = vec::append( - ~[cx.arg(cx.ident_of(~"pipe"), + ~[cx.arg(cx.ident_of("pipe"), cx.ty_path_ast_builder( path(~[this.data_name()], span) .add_tys(cx.ty_vars_global( @@ -211,8 +212,8 @@ impl to_type_decls for state { let next_name = cx.str_of(next.data_name()); let dir = match this.dir { - send => ~"server", - recv => ~"client" + send => "server", + recv => "client" }; vec::append_one(tys, @@ -264,12 +265,12 @@ impl to_type_decls for state { self.data_name(), self.span, cx.ty_path_ast_builder( - path_global(~[cx.ident_of(~"core"), - cx.ident_of(~"pipes"), - cx.ident_of(dir.to_str() + ~"Packet")], + path_global(~[cx.ident_of("core"), + cx.ident_of("pipes"), + cx.ident_of(dir.to_str() + "Packet")], dummy_sp()) .add_ty(cx.ty_path_ast_builder( - path(~[cx.ident_of(~"super"), + path(~[cx.ident_of("super"), self.data_name()], dummy_sp()) .add_tys(cx.ty_vars_global( @@ -282,13 +283,13 @@ impl to_type_decls for state { self.data_name(), self.span, cx.ty_path_ast_builder( - path_global(~[cx.ident_of(~"core"), - cx.ident_of(~"pipes"), + path_global(~[cx.ident_of("core"), + cx.ident_of("pipes"), cx.ident_of(dir.to_str() - + ~"PacketBuffered")], + + "PacketBuffered")], dummy_sp()) .add_tys(~[cx.ty_path_ast_builder( - path(~[cx.ident_of(~"super"), + path(~[cx.ident_of("super"), self.data_name()], dummy_sp()) .add_tys(cx.ty_vars_global( @@ -340,7 +341,7 @@ impl gen_init for protocol { } fn gen_buffer_init(&self, ext_cx: @ext_ctxt) -> @ast::expr { - ext_cx.struct_expr(path(~[ext_cx.ident_of(~"__Buffer")], + ext_cx.struct_expr(path(~[ext_cx.ident_of("__Buffer")], dummy_sp()), self.states.map_to_vec(|s| { let fty = s.to_ty(ext_cx); @@ -366,7 +367,7 @@ impl gen_init for protocol { fmt!("data.%s.set_buffer(buffer)", s.name))), ext_cx.parse_expr(fmt!( - "::core::ptr::to_unsafe_ptr(&(data.%s))", + "::core::ptr::to_mut_unsafe_ptr(&mut (data.%s))", self.states[0].name)))); quote_expr!({ @@ -388,8 +389,8 @@ impl gen_init for protocol { } } - cx.ty_path_ast_builder(path(~[cx.ident_of(~"super"), - cx.ident_of(~"__Buffer")], + cx.ty_path_ast_builder(path(~[cx.ident_of("super"), + cx.ident_of("__Buffer")], copy self.span) .add_tys(cx.ty_vars_global(¶ms))) } @@ -410,12 +411,11 @@ impl gen_init for protocol { @spanned { node: ast::struct_field_ { - kind: ast::named_field( - cx.ident_of(s.name), - ast::struct_immutable, - ast::inherited), + kind: ast::named_field(cx.ident_of(s.name), + ast::inherited), id: cx.next_id(), - ty: fty + ty: fty, + attrs: ~[], }, span: dummy_sp() } @@ -427,11 +427,10 @@ impl gen_init for protocol { }; cx.item_struct_poly( - cx.ident_of(~"__Buffer"), + cx.ident_of("__Buffer"), dummy_sp(), ast::struct_def { fields: fields, - dtor: None, ctor_id: None }, cx.strip_bounds(&generics)) @@ -453,13 +452,13 @@ impl gen_init for protocol { items.push(self.gen_buffer_type(cx)) } - items.push(cx.item_mod(cx.ident_of(~"client"), + items.push(cx.item_mod(cx.ident_of("client"), copy self.span, client_states)); - items.push(cx.item_mod(cx.ident_of(~"server"), + items.push(cx.item_mod(cx.ident_of("server"), copy self.span, server_states)); - cx.item_mod(cx.ident_of(self.name), copy self.span, items) + cx.item_mod(cx.ident_of(copy self.name), copy self.span, items) } } diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 79072a2f577ff..7c78ec066d031 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -100,6 +100,7 @@ pub impl state_ { /// Iterate over the states that can be reached in one message /// from this state. + #[cfg(stage0)] fn reachable(&self, f: &fn(state) -> bool) { for self.messages.each |m| { match *m { @@ -111,6 +112,21 @@ pub impl state_ { } } } + /// Iterate over the states that can be reached in one message + /// from this state. + #[cfg(not(stage0))] + fn reachable(&self, f: &fn(state) -> bool) -> bool { + for self.messages.each |m| { + match *m { + message(_, _, _, _, Some(next_state { state: ref id, _ })) => { + let state = self.proto.get_state((*id)); + if !f(state) { return false; } + } + _ => () + } + } + return true; + } } pub type protocol = @mut protocol_; @@ -138,26 +154,26 @@ pub struct protocol_ { pub impl protocol_ { /// Get a state. - fn get_state(&mut self, name: ~str) -> state { + fn get_state(&self, name: ~str) -> state { self.states.find(|i| i.name == name).get() } - fn get_state_by_id(&mut self, id: uint) -> state { self.states[id] } + fn get_state_by_id(&self, id: uint) -> state { self.states[id] } - fn has_state(&mut self, name: ~str) -> bool { + fn has_state(&self, name: ~str) -> bool { self.states.find(|i| i.name == name).is_some() } - fn filename(&mut self) -> ~str { + fn filename(&self) -> ~str { ~"proto://" + self.name } - fn num_states(&mut self) -> uint { + fn num_states(&self) -> uint { let states = &mut *self.states; states.len() } - fn has_ty_params(&mut self) -> bool { + fn has_ty_params(&self) -> bool { for self.states.each |s| { if s.generics.ty_params.len() > 0 { return true; @@ -165,7 +181,7 @@ pub impl protocol_ { } false } - fn is_bounded(&mut self) -> bool { + fn is_bounded(&self) -> bool { let bounded = self.bounded.get(); bounded } @@ -179,7 +195,7 @@ pub impl protocol_ { generics: ast::Generics) -> state { let messages = @mut ~[]; - let states = &*self.states; + let states = &mut *self.states; let state = @state_ { id: states.len(), @@ -192,7 +208,7 @@ pub impl protocol_ { proto: self }; - self.states.push(state); + states.push(state); state } } @@ -217,4 +233,3 @@ pub fn visit>( }; visitor.visit_proto(proto, states) } - diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index f7412a4502c16..9344a49c9a9eb 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -123,7 +123,7 @@ pub mod rt { impl<'self> ToSource for &'self str { fn to_source(&self, _cx: @ext_ctxt) -> ~str { - let lit = dummy_spanned(ast::lit_str(@str::from_slice(*self))); + let lit = dummy_spanned(ast::lit_str(@str::to_owned(*self))); pprust::lit_to_str(@lit) } } @@ -377,14 +377,14 @@ pub fn expand_quote_tokens(cx: @ext_ctxt, pub fn expand_quote_expr(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { - base::MRExpr(expand_parse_call(cx, sp, ~"parse_expr", ~[], tts)) + base::MRExpr(expand_parse_call(cx, sp, "parse_expr", ~[], tts)) } pub fn expand_quote_item(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let e_attrs = build::mk_uniq_vec_e(cx, sp, ~[]); - base::MRExpr(expand_parse_call(cx, sp, ~"parse_item", + base::MRExpr(expand_parse_call(cx, sp, "parse_item", ~[e_attrs], tts)) } @@ -392,7 +392,7 @@ pub fn expand_quote_pat(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let e_refutable = build::mk_lit(cx, sp, ast::lit_bool(true)); - base::MRExpr(expand_parse_call(cx, sp, ~"parse_pat", + base::MRExpr(expand_parse_call(cx, sp, "parse_pat", ~[e_refutable], tts)) } @@ -400,7 +400,7 @@ pub fn expand_quote_ty(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let e_param_colons = build::mk_lit(cx, sp, ast::lit_bool(false)); - base::MRExpr(expand_parse_call(cx, sp, ~"parse_ty", + base::MRExpr(expand_parse_call(cx, sp, "parse_ty", ~[e_param_colons], tts)) } @@ -408,16 +408,16 @@ pub fn expand_quote_stmt(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let e_attrs = build::mk_uniq_vec_e(cx, sp, ~[]); - base::MRExpr(expand_parse_call(cx, sp, ~"parse_stmt", + base::MRExpr(expand_parse_call(cx, sp, "parse_stmt", ~[e_attrs], tts)) } fn ids_ext(cx: @ext_ctxt, strs: ~[~str]) -> ~[ast::ident] { - strs.map(|str| cx.parse_sess().interner.intern(@copy *str)) + strs.map(|str| cx.parse_sess().interner.intern(*str)) } -fn id_ext(cx: @ext_ctxt, str: ~str) -> ast::ident { - cx.parse_sess().interner.intern(@str) +fn id_ext(cx: @ext_ctxt, str: &str) -> ast::ident { + cx.parse_sess().interner.intern(str) } // Lift an ident to the expr that evaluates to that ident. @@ -425,7 +425,7 @@ fn mk_ident(cx: @ext_ctxt, sp: span, ident: ast::ident) -> @ast::expr { let e_str = build::mk_uniq_str(cx, sp, cx.str_of(ident)); build::mk_method_call(cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"ext_cx"])), - id_ext(cx, ~"ident_of"), + id_ext(cx, "ident_of"), ~[e_str]) } @@ -616,7 +616,7 @@ fn mk_tt(cx: @ext_ctxt, sp: span, tt: &ast::token_tree) let e_push = build::mk_method_call(cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"tt"])), - id_ext(cx, ~"push"), + id_ext(cx, "push"), ~[e_tok]); ~[build::mk_stmt(cx, sp, e_push)] @@ -632,14 +632,14 @@ fn mk_tt(cx: @ext_ctxt, sp: span, tt: &ast::token_tree) let e_to_toks = build::mk_method_call(cx, sp, build::mk_path(cx, sp, ~[ident]), - id_ext(cx, ~"to_tokens"), + id_ext(cx, "to_tokens"), ~[build::mk_path(cx, sp, ids_ext(cx, ~[~"ext_cx"]))]); let e_push = build::mk_method_call(cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"tt"])), - id_ext(cx, ~"push_all_move"), + id_ext(cx, "push_all_move"), ~[e_to_toks]); ~[build::mk_stmt(cx, sp, e_push)] @@ -669,7 +669,7 @@ fn expand_tts(cx: @ext_ctxt, let p = parse::new_parser_from_tts( cx.parse_sess(), cx.cfg(), - vec::from_slice(tts) + vec::to_owned(tts) ); *p.quote_depth += 1u; let tts = p.parse_all_token_trees(); @@ -697,7 +697,7 @@ fn expand_tts(cx: @ext_ctxt, // compiler (which we don't really want to do) and, in any case, only // pushed the problem a very small step further back: an error // resulting from a parse of the resulting quote is still attributed to - // the site the string literal occured, which was in a source file + // the site the string literal occurred, which was in a source file // _other_ than the one the user has control over. For example, an // error in a quote from the protocol compiler, invoked in user code // using proto! for example, will be attributed to the pipec.rs file in @@ -711,15 +711,15 @@ fn expand_tts(cx: @ext_ctxt, let e_sp = build::mk_method_call(cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"ext_cx"])), - id_ext(cx, ~"call_site"), + id_ext(cx, "call_site"), ~[]); let stmt_let_sp = build::mk_local(cx, sp, false, - id_ext(cx, ~"sp"), + id_ext(cx, "sp"), e_sp); let stmt_let_tt = build::mk_local(cx, sp, true, - id_ext(cx, ~"tt"), + id_ext(cx, "tt"), build::mk_uniq_vec_e(cx, sp, ~[])); build::mk_block(cx, sp, uses, @@ -731,18 +731,18 @@ fn expand_tts(cx: @ext_ctxt, fn expand_parse_call(cx: @ext_ctxt, sp: span, - parse_method: ~str, + parse_method: &str, arg_exprs: ~[@ast::expr], tts: &[ast::token_tree]) -> @ast::expr { let tts_expr = expand_tts(cx, sp, tts); let cfg_call = || build::mk_method_call( cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"ext_cx"])), - id_ext(cx, ~"cfg"), ~[]); + id_ext(cx, "cfg"), ~[]); let parse_sess_call = || build::mk_method_call( cx, sp, build::mk_path(cx, sp, ids_ext(cx, ~[~"ext_cx"])), - id_ext(cx, ~"parse_sess"), ~[]); + id_ext(cx, "parse_sess"), ~[]); let new_parser_call = build::mk_call_global(cx, sp, @@ -760,4 +760,3 @@ fn expand_parse_call(cx: @ext_ctxt, id_ext(cx, parse_method), arg_exprs) } - diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 70aa9472c855b..ab22b3152f477 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -150,13 +150,3 @@ fn res_rel_file(cx: @ext_ctxt, sp: codemap::span, arg: &Path) -> Path { copy *arg } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index a29a0f33e0d0c..9660afb1bc08d 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -25,7 +25,7 @@ pub fn expand_trace_macros(cx: @ext_ctxt, copy cx.parse_sess().span_diagnostic, cx.parse_sess().interner, None, - vec::from_slice(tt) + vec::to_owned(tt) ); let rdr = tt_rdr as @reader; let rust_parser = Parser( diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index e4e033e0ffff7..46b09aca8b298 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -247,8 +247,8 @@ pub fn parse( let TokenAndSpan {tok: tok, sp: sp} = rdr.peek(); /* we append new items to this while we go */ - while cur_eis.len() > 0u { /* for each Earley Item */ - let mut ei = cur_eis.pop(); + while !cur_eis.is_empty() { /* for each Earley Item */ + let ei = cur_eis.pop(); let idx = ei.idx; let len = ei.elts.len(); @@ -438,11 +438,3 @@ pub fn parse_nt(p: &Parser, name: ~str) -> nonterminal { _ => p.fatal(~"Unsupported builtin nonterminal parser: " + name) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 39c3c63a9b7fc..169652b112037 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -36,8 +36,8 @@ pub fn add_new_extension(cx: @ext_ctxt, spanned { node: copy m, span: dummy_sp() } } - let lhs_nm = cx.parse_sess().interner.gensym(@~"lhs"); - let rhs_nm = cx.parse_sess().interner.gensym(@~"rhs"); + let lhs_nm = cx.parse_sess().interner.gensym("lhs"); + let rhs_nm = cx.parse_sess().interner.gensym("rhs"); // The grammar for macro_rules! is: // $( $lhs:mtcs => $rhs:tt );+ @@ -82,7 +82,7 @@ pub fn add_new_extension(cx: @ext_ctxt, io::println(fmt!("%s! { %s }", cx.str_of(name), print::pprust::tt_to_str( - ast::tt_delim(vec::from_slice(arg)), + ast::tt_delim(vec::to_owned(arg)), cx.parse_sess().interner))); } @@ -101,7 +101,7 @@ pub fn add_new_extension(cx: @ext_ctxt, s_d, itr, None, - vec::from_slice(arg) + vec::to_owned(arg) ) as @reader; match parse(cx.parse_sess(), cx.cfg(), arg_rdr, (*mtcs)) { success(named_matches) => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d82608846ab98..842f9e9ab3379 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -222,9 +222,12 @@ pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> { fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold) -> @struct_field { + let fold_attribute = |x| fold_attribute_(x, fld); + @spanned { node: ast::struct_field_ { kind: copy sf.node.kind, id: sf.node.id, - ty: fld.fold_ty(sf.node.ty) }, + ty: fld.fold_ty(sf.node.ty), + attrs: sf.node.attrs.map(|e| fold_attribute(*e)) }, span: sf.span } } @@ -290,21 +293,8 @@ pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ { fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold) -> @ast::struct_def { - let dtor = do struct_def.dtor.map |dtor| { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_id = fld.new_id(dtor.node.id); - spanned { - node: ast::struct_dtor_ { - body: dtor_body, - id: dtor_id, - .. copy dtor.node - }, - span: copy dtor.span - } - }; @ast::struct_def { fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), - dtor: dtor, ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), } } @@ -322,6 +312,7 @@ fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field { kind: copy f.node.kind, id: fld.new_id(f.node.id), ty: fld.fold_ty(f.node.ty), + attrs: /* FIXME (#2543) */ copy f.node.attrs, }, span: fld.new_span(f.span), } @@ -520,9 +511,6 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_assign(el, er) => { expr_assign(fld.fold_expr(el), fld.fold_expr(er)) } - expr_swap(el, er) => { - expr_swap(fld.fold_expr(el), fld.fold_expr(er)) - } expr_assign_op(op, el, er) => { expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er)) } @@ -536,6 +524,7 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_index(fld.fold_expr(el), fld.fold_expr(er)) } expr_path(pth) => expr_path(fld.fold_path(pth)), + expr_self => expr_self, expr_break(ref opt_ident) => { expr_break(opt_ident.map(|x| fld.fold_ident(*x))) } @@ -655,22 +644,9 @@ fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { }) } struct_variant_kind(struct_def) => { - let dtor = do struct_def.dtor.map |dtor| { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_id = fld.new_id(dtor.node.id); - spanned { - node: ast::struct_dtor_ { - body: dtor_body, - id: dtor_id, - .. copy dtor.node - }, - .. copy *dtor - } - }; kind = struct_variant_kind(@ast::struct_def { fields: vec::map(struct_def.fields, |f| fld.fold_struct_field(*f)), - dtor: dtor, ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) }) } @@ -783,6 +759,7 @@ impl ast_fold for AstFoldFns { kind: copy sf.node.kind, id: sf.node.id, ty: (self as @ast_fold).fold_ty(sf.node.ty), + attrs: copy sf.node.attrs, }, span: (self.new_span)(sf.span), } @@ -881,12 +858,3 @@ pub fn make_fold(afp: ast_fold_fns) -> @ast_fold { afp as @ast_fold } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 6cf7bba600ec0..6110579863dbf 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -61,15 +61,6 @@ impl OptVec { } } - #[cfg(stage0)] - fn get(&self, i: uint) -> &'self T { - match *self { - Empty => fail!(fmt!("Invalid index %u", i)), - Vec(ref v) => &v[i] - } - } - - #[cfg(not(stage0))] fn get<'a>(&'a self, i: uint) -> &'a T { match *self { Empty => fail!(fmt!("Invalid index %u", i)), @@ -141,12 +132,20 @@ impl Eq for OptVec { } impl BaseIter for OptVec { + #[cfg(stage0)] fn each(&self, blk: &fn(v: &A) -> bool) { match *self { Empty => {} Vec(ref v) => v.each(blk) } } + #[cfg(not(stage0))] + fn each(&self, blk: &fn(v: &A) -> bool) -> bool { + match *self { + Empty => true, + Vec(ref v) => v.each(blk) + } + } fn size_hint(&self) -> Option { Some(self.len()) @@ -155,10 +154,16 @@ impl BaseIter for OptVec { impl old_iter::ExtendedIter for OptVec { #[inline(always)] + #[cfg(stage0)] fn eachi(&self, blk: &fn(v: uint, v: &A) -> bool) { old_iter::eachi(self, blk) } #[inline(always)] + #[cfg(not(stage0))] + fn eachi(&self, blk: &fn(v: uint, v: &A) -> bool) -> bool { + old_iter::eachi(self, blk) + } + #[inline(always)] fn all(&self, blk: &fn(&A) -> bool) -> bool { old_iter::all(self, blk) } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index cc580155d70cf..93584b00d39e6 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -156,7 +156,7 @@ impl parser_attr for Parser { @spanned(lo, hi, ast::meta_list(name, inner_items)) } _ => { - let hi = self.span.hi; + let hi = self.last_span.hi; @spanned(lo, hi, ast::meta_word(name)) } } @@ -179,13 +179,3 @@ impl parser_attr for Parser { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 4e29c3dcf183b..acfd18c74de11 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -202,15 +202,14 @@ fn all_whitespace(s: ~str, begin: uint, end: uint) -> bool { fn trim_whitespace_prefix_and_push_line(lines: &mut ~[~str], s: ~str, col: CharPos) { - let mut s1; - let len = str::len(s); + let len = s.len(); // FIXME #3961: Doing bytewise comparison and slicing with CharPos let col = col.to_uint(); - if all_whitespace(s, 0u, uint::min(len, col)) { + let s1 = if all_whitespace(s, 0, uint::min(len, col)) { if col < len { - s1 = str::slice(s, col, len).to_owned(); - } else { s1 = ~""; } - } else { s1 = s; } + str::slice(s, col, len).to_owned() + } else { ~"" } + } else { s }; debug!("pushing line: %s", s1); lines.push(s1); } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 01f80c032e9a0..322f294836b04 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -122,7 +122,7 @@ pub impl Parser { fn parse_path_list_ident(&self) -> ast::path_list_ident { let lo = self.span.lo; let ident = self.parse_ident(); - let hi = self.span.hi; + let hi = self.last_span.hi; spanned(lo, hi, ast::path_list_ident_ { name: ident, id: self.get_id() }) } @@ -222,7 +222,8 @@ pub impl Parser { // signal an error if the given string is a strict keyword fn check_strict_keywords_(&self, w: &~str) { if self.is_strict_keyword(w) { - self.fatal(fmt!("found `%s` in ident position", *w)); + self.span_err(*self.last_span, + fmt!("found `%s` in ident position", *w)); } } diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 60d6ce504fd9a..764dec0eeb391 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -163,7 +163,7 @@ fn string_advance_token(r: @mut StringReader) { } } -fn byte_offset(rdr: @mut StringReader) -> BytePos { +fn byte_offset(rdr: &StringReader) -> BytePos { (rdr.pos - rdr.filemap.start_pos) } @@ -176,7 +176,7 @@ pub fn get_str_from(rdr: @mut StringReader, start: BytePos) -> ~str { // EFFECT: advance the StringReader by one character. If a newline is // discovered, add it to the FileMap's list of line start offsets. -pub fn bump(rdr: @mut StringReader) { +pub fn bump(rdr: &mut StringReader) { rdr.last_pos = rdr.pos; let current_byte_offset = byte_offset(rdr).to_uint();; if current_byte_offset < (*rdr.src).len() { @@ -271,7 +271,7 @@ fn consume_any_line_comment(rdr: @mut StringReader) // but comments with only "/"s are not if !is_line_non_doc_comment(acc) { return Some(TokenAndSpan{ - tok: token::DOC_COMMENT(rdr.interner.intern(@acc)), + tok: token::DOC_COMMENT(rdr.interner.intern(acc)), sp: codemap::mk_sp(start_bpos, rdr.pos) }); } @@ -325,7 +325,7 @@ fn consume_block_comment(rdr: @mut StringReader) // but comments with only "*"s between two "/"s are not if !is_block_non_doc_comment(acc) { return Some(TokenAndSpan{ - tok: token::DOC_COMMENT(rdr.interner.intern(@acc)), + tok: token::DOC_COMMENT(rdr.interner.intern(acc)), sp: codemap::mk_sp(start_bpos, rdr.pos) }); } @@ -467,12 +467,12 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { if c == '3' && n == '2' { bump(rdr); bump(rdr); - return token::LIT_FLOAT(rdr.interner.intern(@num_str), + return token::LIT_FLOAT(rdr.interner.intern(num_str), ast::ty_f32); } else if c == '6' && n == '4' { bump(rdr); bump(rdr); - return token::LIT_FLOAT(rdr.interner.intern(@num_str), + return token::LIT_FLOAT(rdr.interner.intern(num_str), ast::ty_f64); /* FIXME (#2252): if this is out of range for either a 32-bit or 64-bit float, it won't be noticed till the @@ -484,9 +484,9 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { } if is_float { if is_machine_float { - return token::LIT_FLOAT(rdr.interner.intern(@num_str), ast::ty_f); + return token::LIT_FLOAT(rdr.interner.intern(num_str), ast::ty_f); } - return token::LIT_FLOAT_UNSUFFIXED(rdr.interner.intern(@num_str)); + return token::LIT_FLOAT_UNSUFFIXED(rdr.interner.intern(num_str)); } else { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); @@ -548,7 +548,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token { let is_mod_name = c == ':' && nextch(rdr) == ':'; // FIXME: perform NFKC normalization here. (Issue #2253) - return token::IDENT(rdr.interner.intern(@accum_str), is_mod_name); + return token::IDENT(rdr.interner.intern(accum_str), is_mod_name); } if is_dec_digit(c) { return scan_number(c, rdr); @@ -658,7 +658,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token { lifetime_name.push_char(rdr.curr); bump(rdr); } - return token::LIFETIME(rdr.interner.intern(@lifetime_name)); + return token::LIFETIME(rdr.interner.intern(lifetime_name)); } // Otherwise it is a character constant: @@ -731,7 +731,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token { } } bump(rdr); - return token::LIT_STR(rdr.interner.intern(@accum_str)); + return token::LIT_STR(rdr.interner.intern(accum_str)); } '-' => { if nextch(rdr) == '>' { @@ -799,7 +799,7 @@ mod test { let Env {interner: ident_interner, string_reader} = setup(~"/* my source file */ \ fn main() { io::println(~\"zebra\"); }\n"); - let id = ident_interner.intern(@~"fn"); + let id = ident_interner.intern("fn"); let tok1 = string_reader.next_token(); let tok2 = TokenAndSpan{ tok:token::IDENT(id, false), @@ -810,7 +810,7 @@ mod test { // read another token: let tok3 = string_reader.next_token(); let tok4 = TokenAndSpan{ - tok:token::IDENT(ident_interner.intern (@~"main"), false), + tok:token::IDENT(ident_interner.intern("main"), false), sp:span {lo:BytePos(24),hi:BytePos(28),expn_info: None}}; assert_eq!(tok3,tok4); // the lparen is already read: @@ -828,39 +828,39 @@ mod test { } // make the identifier by looking up the string in the interner - fn mk_ident (env: Env, id: ~str, is_mod_name: bool) -> token::Token { - token::IDENT (env.interner.intern(@id),is_mod_name) + fn mk_ident (env: Env, id: &str, is_mod_name: bool) -> token::Token { + token::IDENT (env.interner.intern(id),is_mod_name) } #[test] fn doublecolonparsing () { let env = setup (~"a b"); check_tokenization (env, - ~[mk_ident (env,~"a",false), - mk_ident (env,~"b",false)]); + ~[mk_ident (env,"a",false), + mk_ident (env,"b",false)]); } #[test] fn dcparsing_2 () { let env = setup (~"a::b"); check_tokenization (env, - ~[mk_ident (env,~"a",true), + ~[mk_ident (env,"a",true), token::MOD_SEP, - mk_ident (env,~"b",false)]); + mk_ident (env,"b",false)]); } #[test] fn dcparsing_3 () { let env = setup (~"a ::b"); check_tokenization (env, - ~[mk_ident (env,~"a",false), + ~[mk_ident (env,"a",false), token::MOD_SEP, - mk_ident (env,~"b",false)]); + mk_ident (env,"b",false)]); } #[test] fn dcparsing_4 () { let env = setup (~"a:: b"); check_tokenization (env, - ~[mk_ident (env,~"a",true), + ~[mk_ident (env,"a",true), token::MOD_SEP, - mk_ident (env,~"b",false)]); + mk_ident (env,"b",false)]); } #[test] fn character_a() { @@ -888,17 +888,7 @@ mod test { let env = setup(~"'abc"); let TokenAndSpan {tok, sp: _} = env.string_reader.next_token(); - let id = env.interner.intern(@~"abc"); + let id = env.interner.intern("abc"); assert_eq!(tok, token::LIFETIME(id)); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7e7931bbb606b..bbd93b71d36d0 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,7 +24,7 @@ use parse::token::{ident_interner, mk_ident_interner}; use core::io; use core::option::{None, Option, Some}; use core::path::Path; -use core::result::{Err, Ok, Result}; +use core::result::{Err, Ok}; pub mod lexer; pub mod parser; @@ -375,13 +375,13 @@ mod test { assert!(i.len() < 100); for int::range(0,100-((i.len()).to_int())) |_dc| { - i.gensym(@~"dontcare"); + i.gensym("dontcare"); } - i.intern(@~"a"); - i.intern(@~"b"); - i.intern(@~"c"); - i.intern(@~"d"); - i.intern(@~"return"); + i.intern("a"); + i.intern("b"); + i.intern("c"); + i.intern("d"); + i.intern("return"); assert!(i.get(ast::ident{repr:101,ctxt:0}) == @~"b"); i } @@ -418,9 +418,10 @@ mod test { new_parser_from_source_str(ps,~[],~"bogofile",source_str) } - #[test] fn to_json_str>(val: @E) -> ~str { + #[cfg(test)] fn to_json_str>(val: @E) -> ~str { do io::with_str_writer |writer| { - val.encode(~std::json::Encoder(writer)); + let mut encoder = std::json::Encoder(writer); + val.encode(&mut encoder); } } @@ -474,10 +475,12 @@ mod test { span:sp(0,6)}) } - #[should_fail] + // FIXME (#6416): For some reason, this fails and causes a test failure, even though it's + // marked as `#[should_fail]`. + /*#[should_fail] #[test] fn bad_path_expr_1() { string_to_expr(@~"::abc::def::return"); - } + }*/ #[test] fn string_to_tts_1 () { let (tts,ps) = string_to_tts_t(@~"fn a (b : int) { b; }"); @@ -590,7 +593,7 @@ mod test { types: ~[]}, None // no idea ), - span: sp(0,3)}, // really? + span: sp(0,1)}, id: 4 // fixme }) } @@ -627,7 +630,7 @@ mod test { types: ~[]}, None // no idea ), - span: sp(6,9)}, // bleah. + span: sp(6,7)}, id: 4 // fixme }], output: @ast::Ty{id:5, // fixme @@ -674,13 +677,3 @@ mod test { string_to_expr(@~"a::z.froob(b,@(987+3))"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ce21e0f672d45..3e64133e893f2 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -18,7 +18,7 @@ removed. */ -use ast::{expr, expr_lit, lit_nil}; +use ast::{expr, expr_lit, lit_nil, attribute}; use ast; use codemap::{span, respan}; use parse::parser::Parser; @@ -40,6 +40,7 @@ pub enum ObsoleteSyntax { ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove, + ObsoleteSwap, ObsoleteUnsafeBlock, ObsoleteUnenforcedBound, ObsoleteImplSyntax, @@ -60,14 +61,23 @@ pub enum ObsoleteSyntax { ObsoleteStaticMethod, ObsoleteConstItem, ObsoleteFixedLengthVectorType, + ObsoleteNamedExternModule, } +#[cfg(stage0)] impl to_bytes::IterBytes for ObsoleteSyntax { #[inline(always)] fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (*self as uint).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl to_bytes::IterBytes for ObsoleteSyntax { + #[inline(always)] + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} pub impl Parser { /// Reports an obsolete syntax non-fatal error. @@ -121,6 +131,10 @@ pub impl Parser { "binary move", "Write `foo = move bar` instead" ), + ObsoleteSwap => ( + "swap", + "Use core::util::{swap, replace} instead" + ), ObsoleteUnsafeBlock => ( "non-standalone unsafe block", "use an inner `unsafe { ... }` block instead" @@ -212,6 +226,11 @@ pub impl Parser { "fixed-length vector notation", "instead of `[T * N]`, write `[T, ..N]`" ), + ObsoleteNamedExternModule => ( + "named external module", + "instead of `extern mod foo { ... }`, write `mod foo { \ + extern { ... } }`" + ), }; self.report(sp, kind, kind_str, desc); @@ -282,13 +301,13 @@ pub impl Parser { } } - fn try_parse_obsolete_priv_section(&self) -> bool { + fn try_parse_obsolete_priv_section(&self, attrs: ~[attribute]) -> bool { if self.is_keyword(&~"priv") && self.look_ahead(1) == token::LBRACE { self.obsolete(copy *self.span, ObsoletePrivSection); self.eat_keyword(&~"priv"); self.bump(); while *self.token != token::RBRACE { - self.parse_single_struct_field(ast::private); + self.parse_single_struct_field(ast::private, attrs); } self.bump(); true @@ -298,4 +317,3 @@ pub impl Parser { } } - diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50bdfb2f55726..b35ae169e1a26 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -19,14 +19,14 @@ use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer}; use ast::{bind_by_copy, bitand, bitor, bitxor, blk}; use ast::{blk_check_mode, box}; use ast::{crate, crate_cfg, decl, decl_item}; -use ast::{decl_local, default_blk, deref, quot, enum_def}; +use ast::{decl_local, default_blk, deref, div, enum_def}; use ast::{expr, expr_, expr_addr_of, expr_match, expr_again}; use ast::{expr_assign, expr_assign_op, expr_binary, expr_block}; use ast::{expr_break, expr_call, expr_cast, expr_copy, expr_do_body}; use ast::{expr_field, expr_fn_block, expr_if, expr_index}; use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac}; use ast::{expr_method_call, expr_paren, expr_path, expr_repeat}; -use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary}; +use ast::{expr_ret, expr_self, expr_struct, expr_tup, expr_unary}; use ast::{expr_vec, expr_vstore, expr_vstore_mut_box}; use ast::{expr_vstore_slice, expr_vstore_box}; use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl}; @@ -45,7 +45,7 @@ use ast::{pat_tup, pat_uniq, pat_wild, private}; use ast::{rem, required}; use ast::{ret_style, return_val, self_ty, shl, shr, stmt, stmt_decl}; use ast::{stmt_expr, stmt_semi, stmt_mac, struct_def, struct_field}; -use ast::{struct_immutable, struct_mutable, struct_variant_kind, subtract}; +use ast::{struct_variant_kind, subtract}; use ast::{sty_box, sty_region, sty_static, sty_uniq, sty_value}; use ast::{token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok}; use ast::{tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot, ty_box}; @@ -70,7 +70,7 @@ use parse::lexer::reader; use parse::lexer::TokenAndSpan; use parse::obsolete::{ObsoleteClassTraits}; use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator}; -use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove}; +use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap}; use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds}; use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax}; use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer}; @@ -82,6 +82,7 @@ use parse::obsolete::ObsoleteMode; use parse::obsolete::{ObsoleteLifetimeNotation, ObsoleteConstManagedPointer}; use parse::obsolete::{ObsoletePurity, ObsoleteStaticMethod}; use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType}; +use parse::obsolete::{ObsoleteNamedExternModule}; use parse::token::{can_begin_expr, is_ident, is_ident_or_path}; use parse::token::{is_plain_ident, INTERPOLATED, special_idents, token_to_binop}; use parse::token; @@ -102,11 +103,6 @@ enum restriction { RESTRICT_NO_BAR_OR_DOUBLEBAR_OP, } -// So that we can distinguish a class dtor from other class members - -enum class_contents { dtor_decl(blk, ~[attribute], codemap::span), - members(~[@struct_field]) } - type arg_or_capture_item = Either; type item_info = (ident, item_, Option<~[attribute]>); @@ -313,22 +309,22 @@ pub impl Parser { } return copy self.buffer[(*self.buffer_start + dist - 1) & 3].tok; } - fn fatal(&self, m: ~str) -> ! { + fn fatal(&self, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(*copy self.span, m) } - fn span_fatal(&self, sp: span, m: ~str) -> ! { + fn span_fatal(&self, sp: span, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(sp, m) } - fn span_note(&self, sp: span, m: ~str) { + fn span_note(&self, sp: span, m: &str) { self.sess.span_diagnostic.span_note(sp, m) } - fn bug(&self, m: ~str) -> ! { + fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(*copy self.span, m) } - fn warn(&self, m: ~str) { + fn warn(&self, m: &str) { self.sess.span_diagnostic.span_warn(*copy self.span, m) } - fn span_err(&self, sp: span, m: ~str) { + fn span_err(&self, sp: span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } fn abort_if_errors(&self) { @@ -395,8 +391,8 @@ pub impl Parser { // parse a ty_closure type fn parse_ty_closure(&self, sigil: ast::Sigil, - region: Option<@ast::Lifetime>) -> ty_ - { + region: Option<@ast::Lifetime>) + -> ty_ { /* (&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T @@ -420,8 +416,7 @@ pub impl Parser { self.expect_keyword(&~"fn"); if self.parse_fn_ty_sigil().is_some() { - self.obsolete(*self.span, - ObsoletePostFnTySigil); + self.obsolete(*self.span, ObsoletePostFnTySigil); } let (decl, lifetimes) = self.parse_ty_fn_decl(); @@ -435,8 +430,12 @@ pub impl Parser { lifetimes: lifetimes, }); - fn parse_onceness(self: &Parser) -> Onceness { - if self.eat_keyword(&~"once") { Once } else { Many } + fn parse_onceness(this: &Parser) -> Onceness { + if this.eat_keyword(&~"once") { + Once + } else { + Many + } } } @@ -778,20 +777,17 @@ pub impl Parser { return ty_rptr(opt_lifetime, mt); } - // parse an optional mode. - // XXX: Remove after snapshot. + // parse an optional, obsolete argument mode. fn parse_arg_mode(&self) { if self.eat(&token::BINOP(token::MINUS)) { self.obsolete(*self.span, ObsoleteMode); } else if self.eat(&token::ANDAND) { - // Ignore. + self.obsolete(*self.span, ObsoleteMode); } else if self.eat(&token::BINOP(token::PLUS)) { if self.eat(&token::BINOP(token::PLUS)) { - // ++ mode is obsolete, but we need a snapshot - // to stop parsing it. - // Ignore. + self.obsolete(*self.span, ObsoleteMode); } else { - // Ignore. + self.obsolete(*self.span, ObsoleteMode); } } else { // Ignore. @@ -919,6 +915,24 @@ pub impl Parser { codemap::spanned { node: lit, span: mk_sp(lo, self.last_span.hi) } } + // matches '-' lit | lit + fn parse_literal_maybe_minus(&self) -> @expr { + let minus_lo = self.span.lo; + let minus_present = self.eat(&token::BINOP(token::MINUS)); + + let lo = self.span.lo; + let literal = @self.parse_lit(); + let hi = self.span.hi; + let expr = self.mk_expr(lo, hi, expr_lit(literal)); + + if minus_present { + let minus_hi = self.span.hi; + self.mk_expr(minus_lo, minus_hi, expr_unary(neg, expr)) + } else { + expr + } + } + // parse a path into a vector of idents, whether the path starts // with ::, and a span. fn parse_path(&self) -> (~[ast::ident],bool,span) { @@ -937,8 +951,8 @@ pub impl Parser { loop { match *self.token { token::MOD_SEP => { - match self.look_ahead(1u) { - token::IDENT(id,_) => { + match self.look_ahead(1) { + token::IDENT(*) => { self.bump(); ids.push(self.parse_ident()); } @@ -1232,6 +1246,9 @@ pub impl Parser { expr_block(blk)); } else if token::is_bar(&*self.token) { return self.parse_lambda_expr(); + } else if self.eat_keyword(&~"self") { + ex = expr_self; + hi = self.span.hi; } else if self.eat_keyword(&~"if") { return self.parse_if_expr(); } else if self.eat_keyword(&~"for") { @@ -1607,9 +1624,9 @@ pub impl Parser { token::LBRACE | token::LPAREN | token::LBRACKET => { self.parse_matcher_subseq( name_idx, - &*self.token, + *self.token, // tjc: not sure why we need a copy - &token::flip_delimiter(&*self.token) + token::flip_delimiter(&*self.token) ) } _ => self.fatal(~"expected open delimiter") @@ -1623,15 +1640,15 @@ pub impl Parser { fn parse_matcher_subseq( &self, name_idx: @mut uint, - bra: &token::Token, - ket: &token::Token + bra: token::Token, + ket: token::Token ) -> ~[matcher] { let mut ret_val = ~[]; let mut lparens = 0u; - self.expect(bra); + self.expect(&bra); - while *self.token != *ket || lparens > 0u { + while *self.token != ket || lparens > 0u { if *self.token == token::LPAREN { lparens += 1u; } if *self.token == token::RPAREN { lparens -= 1u; } ret_val.push(self.parse_matcher(name_idx)); @@ -1651,8 +1668,8 @@ pub impl Parser { let name_idx_lo = *name_idx; let ms = self.parse_matcher_subseq( name_idx, - &token::LPAREN, - &token::RPAREN + token::LPAREN, + token::RPAREN ); if ms.len() == 0u { self.fatal(~"repetition body must be nonempty"); @@ -1836,7 +1853,7 @@ pub impl Parser { token::PLUS => aop = add, token::MINUS => aop = subtract, token::STAR => aop = mul, - token::SLASH => aop = quot, + token::SLASH => aop = div, token::PERCENT => aop = rem, token::CARET => aop = bitxor, token::AND => aop = bitand, @@ -1857,9 +1874,11 @@ pub impl Parser { expr_break(None)) } token::DARROW => { + self.obsolete(*self.span, ObsoleteSwap); self.bump(); - let rhs = self.parse_expr(); - self.mk_expr(lo, rhs.span.hi, expr_swap(lhs, rhs)) + // Ignore what we get, this is an error anyway + self.parse_expr(); + self.mk_expr(lo, self.span.hi, expr_break(None)) } _ => { lhs @@ -2034,8 +2053,7 @@ pub impl Parser { // This is a 'continue' expression if opt_ident.is_some() { self.span_err(*self.last_span, - ~"a label may not be used with a `loop` \ - expression"); + "a label may not be used with a `loop` expression"); } let lo = self.span.lo; @@ -2172,7 +2190,7 @@ pub impl Parser { @ast::pat { node: pat_wild, _ } => (), @ast::pat { node: pat_ident(_, _, _), _ } => (), @ast::pat { span, _ } => self.span_fatal( - span, ~"expected an identifier or `_`" + span, "expected an identifier or `_`" ) } slice = Some(subpat); @@ -2360,10 +2378,19 @@ pub impl Parser { || self.is_keyword(&~"true") || self.is_keyword(&~"false") { - // parse an expression pattern or exp .. exp - let val = self.parse_expr_res(RESTRICT_NO_BAR_OP); + // Parse an expression pattern or exp .. exp. + // + // These expressions are limited to literals (possibly + // preceded by unary-minus) or identifiers. + let val = self.parse_literal_maybe_minus(); if self.eat(&token::DOTDOT) { - let end = self.parse_expr_res(RESTRICT_NO_BAR_OP); + let end = if is_ident_or_path(&tok) { + let path = self.parse_path_with_tps(true); + let hi = self.span.hi; + self.mk_expr(lo, hi, expr_path(path)) + } else { + self.parse_literal_maybe_minus() + }; pat = pat_range(val, end); } else { pat = pat_lit(val); @@ -2389,7 +2416,13 @@ pub impl Parser { can_be_enum_or_struct = false } - if is_plain_ident(&*self.token) && !can_be_enum_or_struct { + if self.look_ahead(1) == token::DOTDOT { + let start = self.parse_expr_res(RESTRICT_NO_BAR_OP); + self.eat(&token::DOTDOT); + let end = self.parse_expr_res(RESTRICT_NO_BAR_OP); + pat = pat_range(start, end); + } + else if is_plain_ident(&*self.token) && !can_be_enum_or_struct { let name = self.parse_path_without_tps(); let sub; if self.eat(&token::AT) { @@ -2398,7 +2431,7 @@ pub impl Parser { } else { // or just foo sub = None; - }; + } pat = pat_ident(binding_mode, name, sub); } else { // parse an enum pat @@ -2450,7 +2483,7 @@ pub impl Parser { } } } - hi = self.span.hi; + hi = self.last_span.hi; } } @ast::pat { id: self.get_id(), node: pat, span: mk_sp(lo, hi) } @@ -2464,7 +2497,7 @@ pub impl Parser { -> ast::pat_ { if !is_plain_ident(&*self.token) { self.span_fatal(*self.last_span, - ~"expected identifier, found path"); + "expected identifier, found path"); } // why a path here, and not just an identifier? let name = self.parse_path_without_tps(); @@ -2483,7 +2516,7 @@ pub impl Parser { if *self.token == token::LPAREN { self.span_fatal( *self.last_span, - ~"expected identifier, found enum pattern"); + "expected identifier, found enum pattern"); } pat_ident(binding_mode, name, sub) @@ -2525,11 +2558,13 @@ pub impl Parser { } // parse a structure field - fn parse_name_and_ty(&self, pr: visibility) -> @struct_field { - let mut is_mutbl = struct_immutable; + fn parse_name_and_ty(&self, + pr: visibility, + attrs: ~[attribute]) -> @struct_field { let lo = self.span.lo; if self.eat_keyword(&~"mut") { - is_mutbl = struct_mutable; + // Do nothing, for backwards compatibility. + // XXX: Remove after snapshot. } if !is_plain_ident(&*self.token) { self.fatal(~"expected ident"); @@ -2538,9 +2573,10 @@ pub impl Parser { self.expect(&token::COLON); let ty = self.parse_ty(false); @spanned(lo, self.last_span.hi, ast::struct_field_ { - kind: named_field(name, is_mutbl, pr), + kind: named_field(name, pr), id: self.get_id(), - ty: ty + ty: ty, + attrs: attrs, }) } @@ -2611,19 +2647,19 @@ pub impl Parser { match self.parse_item_or_view_item(/*bad*/ copy item_attrs, false) { - iovi_item(i) => { - let hi = i.span.hi; - let decl = @spanned(lo, hi, decl_item(i)); - return @spanned(lo, hi, stmt_decl(decl, self.get_id())); - } - iovi_view_item(vi) => { - self.span_fatal(vi.span, ~"view items must be declared at \ - the top of the block"); - } - iovi_foreign_item(_) => { - self.fatal(~"foreign items are not allowed here"); - } - iovi_none() => { /* fallthrough */ } + iovi_item(i) => { + let hi = i.span.hi; + let decl = @spanned(lo, hi, decl_item(i)); + return @spanned(lo, hi, stmt_decl(decl, self.get_id())); + } + iovi_view_item(vi) => { + self.span_fatal(vi.span, + "view items must be declared at the top of the block"); + } + iovi_foreign_item(_) => { + self.fatal(~"foreign items are not allowed here"); + } + iovi_none() => { /* fallthrough */ } } check_expected_item(self, item_attrs); @@ -2824,8 +2860,7 @@ pub impl Parser { result.push(RegionTyParamBound); } else { self.span_err(*self.span, - ~"`'static` is the only permissible \ - region bound here"); + "`'static` is the only permissible region bound here"); } self.bump(); } @@ -2983,9 +3018,7 @@ pub impl Parser { } } - fn maybe_parse_borrowed_self_ty( - self: &Parser - ) -> ast::self_ty_ { + fn maybe_parse_borrowed_self_ty(this: &Parser) -> ast::self_ty_ { // The following things are possible to see here: // // fn(&self) @@ -2995,37 +3028,29 @@ pub impl Parser { // // We already know that the current token is `&`. - if ( - self.token_is_keyword(&~"self", &self.look_ahead(1))) - { - self.bump(); - self.expect_self_ident(); + if (this.token_is_keyword(&~"self", &this.look_ahead(1))) { + this.bump(); + this.expect_self_ident(); sty_region(None, m_imm) - } else if ( - self.token_is_mutability(&self.look_ahead(1)) && - self.token_is_keyword(&~"self", &self.look_ahead(2))) - { - self.bump(); - let mutability = self.parse_mutability(); - self.expect_self_ident(); + } else if (this.token_is_mutability(&this.look_ahead(1)) && + this.token_is_keyword(&~"self", &this.look_ahead(2))) { + this.bump(); + let mutability = this.parse_mutability(); + this.expect_self_ident(); sty_region(None, mutability) - } else if ( - self.token_is_lifetime(&self.look_ahead(1)) && - self.token_is_keyword(&~"self", &self.look_ahead(2))) - { - self.bump(); - let lifetime = @self.parse_lifetime(); - self.expect_self_ident(); + } else if (this.token_is_lifetime(&this.look_ahead(1)) && + this.token_is_keyword(&~"self", &this.look_ahead(2))) { + this.bump(); + let lifetime = @this.parse_lifetime(); + this.expect_self_ident(); sty_region(Some(lifetime), m_imm) - } else if ( - self.token_is_lifetime(&self.look_ahead(1)) && - self.token_is_mutability(&self.look_ahead(2)) && - self.token_is_keyword(&~"self", &self.look_ahead(3))) - { - self.bump(); - let lifetime = @self.parse_lifetime(); - let mutability = self.parse_mutability(); - self.expect_self_ident(); + } else if (this.token_is_lifetime(&this.look_ahead(1)) && + this.token_is_mutability(&this.look_ahead(2)) && + this.token_is_keyword(&~"self", &this.look_ahead(3))) { + this.bump(); + let lifetime = @this.parse_lifetime(); + let mutability = this.parse_mutability(); + this.expect_self_ident(); sty_region(Some(lifetime), mutability) } else { sty_static @@ -3240,7 +3265,7 @@ pub impl Parser { }) } _ => { - self.span_err(*self.span, ~"not a trait"); + self.span_err(*self.span, "not a trait"); None } }; @@ -3299,7 +3324,6 @@ pub impl Parser { } let mut fields: ~[@struct_field]; - let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None; let is_tuple_like; if self.eat(&token::LBRACE) { @@ -3307,30 +3331,12 @@ pub impl Parser { is_tuple_like = false; fields = ~[]; while *self.token != token::RBRACE { - match self.parse_struct_decl_field() { - dtor_decl(ref blk, ref attrs, s) => { - match the_dtor { - Some((_, _, s_first)) => { - self.span_note(s, fmt!("Duplicate destructor \ - declaration for class %s", - *self.interner.get(class_name))); - self.span_fatal(copy s_first, ~"First destructor \ - declared here"); - } - None => { - the_dtor = Some((copy *blk, copy *attrs, s)); - } - } - } - members(mms) => { - for mms.each |struct_field| { - fields.push(*struct_field) - } - } + for self.parse_struct_decl_field().each |struct_field| { + fields.push(*struct_field) } } if fields.len() == 0 { - self.fatal(fmt!("Unit-like struct should be written as: struct %s;", + self.fatal(fmt!("Unit-like struct should be written as `struct %s;`", *self.interner.get(class_name))); } self.bump(); @@ -3342,11 +3348,13 @@ pub impl Parser { &token::RPAREN, seq_sep_trailing_allowed(token::COMMA) ) |p| { + let attrs = self.parse_outer_attributes(); let lo = p.span.lo; let struct_field_ = ast::struct_field_ { kind: unnamed_field, id: self.get_id(), - ty: p.parse_ty(false) + ty: p.parse_ty(false), + attrs: attrs, }; @spanned(lo, p.span.hi, struct_field_) }; @@ -3365,19 +3373,11 @@ pub impl Parser { ); } - let actual_dtor = do the_dtor.map |dtor| { - let (d_body, d_attrs, d_s) = copy *dtor; - codemap::spanned { node: ast::struct_dtor_ { id: self.get_id(), - attrs: d_attrs, - self_id: self.get_id(), - body: d_body}, - span: d_s}}; let _ = self.get_id(); // XXX: Workaround for crazy bug. let new_id = self.get_id(); (class_name, item_struct(@ast::struct_def { fields: fields, - dtor: actual_dtor, ctor_id: if is_tuple_like { Some(new_id) } else { None } }, generics), None) @@ -3391,12 +3391,14 @@ pub impl Parser { } // parse a structure field declaration - fn parse_single_struct_field(&self, vis: visibility) -> @struct_field { + fn parse_single_struct_field(&self, + vis: visibility, + attrs: ~[attribute]) -> @struct_field { if self.eat_obsolete_ident("let") { self.obsolete(*self.last_span, ObsoleteLet); } - let a_var = self.parse_name_and_ty(vis); + let a_var = self.parse_name_and_ty(vis, attrs); match *self.token { token::SEMI => { self.obsolete(copy *self.span, ObsoleteFieldTerminator); @@ -3420,34 +3422,27 @@ pub impl Parser { } // parse an element of a struct definition - fn parse_struct_decl_field(&self) -> class_contents { - - if self.try_parse_obsolete_priv_section() { - return members(~[]); - } + fn parse_struct_decl_field(&self) -> ~[@struct_field] { let attrs = self.parse_outer_attributes(); + if self.try_parse_obsolete_priv_section(attrs) { + return ~[]; + } + if self.eat_keyword(&~"priv") { - return members(~[self.parse_single_struct_field(private)]) + return ~[self.parse_single_struct_field(private, attrs)] } if self.eat_keyword(&~"pub") { - return members(~[self.parse_single_struct_field(public)]); + return ~[self.parse_single_struct_field(public, attrs)]; } if self.try_parse_obsolete_struct_ctor() { - return members(~[]); + return ~[]; } - if self.eat_keyword(&~"drop") { - let lo = self.last_span.lo; - let body = self.parse_block(); - return dtor_decl(body, attrs, mk_sp(lo, self.last_span.hi)) - } - else { - return members(~[self.parse_single_struct_field(inherited)]); - } + return ~[self.parse_single_struct_field(inherited, attrs)]; } // parse visiility: PUB, PRIV, or nothing @@ -3499,9 +3494,8 @@ pub impl Parser { ) { iovi_item(item) => items.push(item), iovi_view_item(view_item) => { - self.span_fatal(view_item.span, ~"view items must be \ - declared at the top of the \ - module"); + self.span_fatal(view_item.span, "view items must be declared at the top of the \ + module"); } _ => { self.fatal( @@ -3718,17 +3712,17 @@ pub impl Parser { // at this point, this is essentially a wrapper for // parse_foreign_items. - fn parse_foreign_mod_items(&self, sort: ast::foreign_mod_sort, + fn parse_foreign_mod_items(&self, + sort: ast::foreign_mod_sort, abis: AbiSet, first_item_attrs: ~[attribute]) - -> foreign_mod { + -> foreign_mod { let ParsedItemsAndViewItems { - attrs_remaining: attrs_remaining, + attrs_remaining: _, view_items: view_items, items: _, foreign_items: foreign_items } = self.parse_foreign_items(first_item_attrs, true); - let mut initial_attrs = attrs_remaining; assert!(*self.token == token::RBRACE); ast::foreign_mod { sort: sort, @@ -3745,8 +3739,7 @@ pub impl Parser { visibility: visibility, attrs: ~[attribute], items_allowed: bool) - -> item_or_view_item - { + -> item_or_view_item { let mut must_be_named_mod = false; if self.is_keyword(&~"mod") { must_be_named_mod = true; @@ -3781,6 +3774,11 @@ pub impl Parser { // extern mod foo { ... } or extern { ... } if items_allowed && self.eat(&token::LBRACE) { + // `extern mod foo { ... }` is obsolete. + if sort == ast::named { + self.obsolete(*self.last_span, ObsoleteNamedExternModule); + } + let abis = opt_abis.get_or_default(AbiSet::C()); let (inner, next) = self.parse_inner_attrs_and_next(); @@ -3794,7 +3792,7 @@ pub impl Parser { } if opt_abis.is_some() { - self.span_err(*self.span, ~"an ABI may not be specified here"); + self.span_err(*self.span, "an ABI may not be specified here"); } // extern mod foo; @@ -3830,44 +3828,16 @@ pub impl Parser { // parse a structure-like enum variant definition // this should probably be renamed or refactored... fn parse_struct_def(&self) -> @struct_def { - let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None; let mut fields: ~[@struct_field] = ~[]; while *self.token != token::RBRACE { - match self.parse_struct_decl_field() { - dtor_decl(ref blk, ref attrs, s) => { - match the_dtor { - Some((_, _, s_first)) => { - self.span_note(s, ~"duplicate destructor \ - declaration"); - self.span_fatal(copy s_first, - ~"first destructor \ - declared here"); - } - None => { - the_dtor = Some((copy *blk, copy *attrs, s)); - } - } - } - members(mms) => { - for mms.each |struct_field| { - fields.push(*struct_field); - } - } + for self.parse_struct_decl_field().each |struct_field| { + fields.push(*struct_field); } } self.bump(); - let actual_dtor = do the_dtor.map |dtor| { - let (d_body, d_attrs, d_s) = copy *dtor; - codemap::spanned { node: ast::struct_dtor_ { id: self.get_id(), - attrs: d_attrs, - self_id: self.get_id(), - body: d_body }, - span: d_s } - }; return @ast::struct_def { fields: fields, - dtor: actual_dtor, ctor_id: None }; } @@ -4371,7 +4341,7 @@ pub impl Parser { rp: None, types: ~[] }; return @spanned(lo, - self.span.hi, + self.last_span.hi, view_path_simple(last, path, self.get_id())); } @@ -4457,9 +4427,7 @@ pub impl Parser { view_item_extern_mod(*) if !extern_mod_allowed => { self.span_err(view_item.span, - ~"\"extern mod\" \ - declarations are not \ - allowed here"); + "\"extern mod\" declarations are not allowed here"); } view_item_extern_mod(*) => {} } @@ -4485,8 +4453,7 @@ pub impl Parser { iovi_none => break, iovi_view_item(view_item) => { self.span_err(view_item.span, - ~"`use` and `extern mod` declarations \ - must precede items"); + "`use` and `extern mod` declarations must precede items"); } iovi_item(item) => { items.push(item) @@ -4521,8 +4488,7 @@ pub impl Parser { iovi_view_item(view_item) => { // I think this can't occur: self.span_err(view_item.span, - ~"`use` and `extern mod` declarations \ - must precede items"); + "`use` and `extern mod` declarations must precede items"); } iovi_item(_) => { // FIXME #5668: this will occur for a macro invocation: @@ -4569,14 +4535,3 @@ pub impl Parser { } } } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0327a3b80da87..fde383b445c95 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -11,7 +11,7 @@ use ast; use ast_util; use parse::token; -use util::interner::Interner; +use util::interner::StrInterner; use util::interner; use core::cmp::Equiv; @@ -305,50 +305,47 @@ pub fn is_bar(t: &Token) -> bool { pub mod special_idents { use ast::ident; - pub static underscore : ident = ident { repr: 0u, ctxt: 0}; - pub static anon : ident = ident { repr: 1u, ctxt: 0}; - pub static dtor : ident = ident { repr: 2u, ctxt: 0}; // 'drop', but that's - // reserved - pub static invalid : ident = ident { repr: 3u, ctxt: 0}; // '' - pub static unary : ident = ident { repr: 4u, ctxt: 0}; - pub static not_fn : ident = ident { repr: 5u, ctxt: 0}; - pub static idx_fn : ident = ident { repr: 6u, ctxt: 0}; - pub static unary_minus_fn : ident = ident { repr: 7u, ctxt: 0}; - pub static clownshoes_extensions : ident = ident { repr: 8u, ctxt: 0}; + pub static underscore : ident = ident { repr: 0, ctxt: 0}; + pub static anon : ident = ident { repr: 1, ctxt: 0}; + pub static invalid : ident = ident { repr: 2, ctxt: 0}; // '' + pub static unary : ident = ident { repr: 3, ctxt: 0}; + pub static not_fn : ident = ident { repr: 4, ctxt: 0}; + pub static idx_fn : ident = ident { repr: 5, ctxt: 0}; + pub static unary_minus_fn : ident = ident { repr: 6, ctxt: 0}; + pub static clownshoes_extensions : ident = ident { repr: 7, ctxt: 0}; - pub static self_ : ident = ident { repr: 9u, ctxt: 0}; // 'self' + pub static self_ : ident = ident { repr: 8, ctxt: 0}; // 'self' /* for matcher NTs */ - pub static item : ident = ident { repr: 10u, ctxt: 0}; - pub static block : ident = ident { repr: 11u, ctxt: 0}; - pub static stmt : ident = ident { repr: 12u, ctxt: 0}; - pub static pat : ident = ident { repr: 13u, ctxt: 0}; - pub static expr : ident = ident { repr: 14u, ctxt: 0}; - pub static ty : ident = ident { repr: 15u, ctxt: 0}; - pub static ident : ident = ident { repr: 16u, ctxt: 0}; - pub static path : ident = ident { repr: 17u, ctxt: 0}; - pub static tt : ident = ident { repr: 18u, ctxt: 0}; - pub static matchers : ident = ident { repr: 19u, ctxt: 0}; - - pub static str : ident = ident { repr: 20u, ctxt: 0}; // for the type + pub static item : ident = ident { repr: 9, ctxt: 0}; + pub static block : ident = ident { repr: 10, ctxt: 0}; + pub static stmt : ident = ident { repr: 11, ctxt: 0}; + pub static pat : ident = ident { repr: 12, ctxt: 0}; + pub static expr : ident = ident { repr: 13, ctxt: 0}; + pub static ty : ident = ident { repr: 14, ctxt: 0}; + pub static ident : ident = ident { repr: 15, ctxt: 0}; + pub static path : ident = ident { repr: 16, ctxt: 0}; + pub static tt : ident = ident { repr: 17, ctxt: 0}; + pub static matchers : ident = ident { repr: 18, ctxt: 0}; + + pub static str : ident = ident { repr: 19, ctxt: 0}; // for the type /* outside of libsyntax */ - pub static ty_visitor : ident = ident { repr: 21u, ctxt: 0}; - pub static arg : ident = ident { repr: 22u, ctxt: 0}; - pub static descrim : ident = ident { repr: 23u, ctxt: 0}; - pub static clownshoe_abi : ident = ident { repr: 24u, ctxt: 0}; - pub static clownshoe_stack_shim : ident = ident { repr: 25u, ctxt: 0}; - pub static tydesc : ident = ident { repr: 26u, ctxt: 0}; - pub static literally_dtor : ident = ident { repr: 27u, ctxt: 0}; - pub static main : ident = ident { repr: 28u, ctxt: 0}; - pub static opaque : ident = ident { repr: 29u, ctxt: 0}; - pub static blk : ident = ident { repr: 30u, ctxt: 0}; - pub static static : ident = ident { repr: 31u, ctxt: 0}; - pub static intrinsic : ident = ident { repr: 32u, ctxt: 0}; - pub static clownshoes_foreign_mod: ident = ident { repr: 33u, ctxt: 0}; - pub static unnamed_field: ident = ident { repr: 34u, ctxt: 0}; - pub static c_abi: ident = ident { repr: 35u, ctxt: 0}; - pub static type_self: ident = ident { repr: 36u, ctxt: 0}; // `Self` + pub static ty_visitor : ident = ident { repr: 20, ctxt: 0}; + pub static arg : ident = ident { repr: 21, ctxt: 0}; + pub static descrim : ident = ident { repr: 22, ctxt: 0}; + pub static clownshoe_abi : ident = ident { repr: 23, ctxt: 0}; + pub static clownshoe_stack_shim : ident = ident { repr: 24, ctxt: 0}; + pub static tydesc : ident = ident { repr: 25, ctxt: 0}; + pub static main : ident = ident { repr: 26, ctxt: 0}; + pub static opaque : ident = ident { repr: 27, ctxt: 0}; + pub static blk : ident = ident { repr: 28, ctxt: 0}; + pub static statik : ident = ident { repr: 29, ctxt: 0}; + pub static intrinsic : ident = ident { repr: 30, ctxt: 0}; + pub static clownshoes_foreign_mod: ident = ident { repr: 31, ctxt: 0}; + pub static unnamed_field: ident = ident { repr: 32, ctxt: 0}; + pub static c_abi: ident = ident { repr: 33, ctxt: 0}; + pub static type_self: ident = ident { repr: 34, ctxt: 0}; // `Self` } pub struct StringRef<'self>(&'self str); @@ -358,11 +355,18 @@ impl<'self> Equiv<@~str> for StringRef<'self> { fn equiv(&self, other: &@~str) -> bool { str::eq_slice(**self, **other) } } +#[cfg(stage0)] impl<'self> to_bytes::IterBytes for StringRef<'self> { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { (**self).iter_bytes(lsb0, f); } } +#[cfg(not(stage0))] +impl<'self> to_bytes::IterBytes for StringRef<'self> { + fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { + (**self).iter_bytes(lsb0, f) + } +} /** * Maps a token to a record specifying the corresponding binary @@ -371,7 +375,7 @@ impl<'self> to_bytes::IterBytes for StringRef<'self> { pub fn token_to_binop(tok: Token) -> Option { match tok { BINOP(STAR) => Some(ast::mul), - BINOP(SLASH) => Some(ast::quot), + BINOP(SLASH) => Some(ast::div), BINOP(PERCENT) => Some(ast::rem), BINOP(PLUS) => Some(ast::add), BINOP(MINUS) => Some(ast::subtract), @@ -393,14 +397,14 @@ pub fn token_to_binop(tok: Token) -> Option { } pub struct ident_interner { - priv interner: Interner<@~str>, + priv interner: StrInterner, } pub impl ident_interner { - fn intern(&self, val: @~str) -> ast::ident { + fn intern(&self, val: &str) -> ast::ident { ast::ident { repr: self.interner.intern(val), ctxt: 0 } } - fn gensym(&self, val: @~str) -> ast::ident { + fn gensym(&self, val: &str) -> ast::ident { ast::ident { repr: self.interner.gensym(val), ctxt: 0 } } fn get(&self, idx: ast::ident) -> @~str { @@ -424,50 +428,48 @@ pub fn mk_fresh_ident_interner() -> @ident_interner { // the indices here must correspond to the numbers in // special_idents. let init_vec = ~[ - @~"_", // 0 - @~"anon", // 1 - @~"drop", // 2 - @~"", // 3 - @~"unary", // 4 - @~"!", // 5 - @~"[]", // 6 - @~"unary-", // 7 - @~"__extensions__", // 8 - @~"self", // 9 - @~"item", // 10 - @~"block", // 11 - @~"stmt", // 12 - @~"pat", // 13 - @~"expr", // 14 - @~"ty", // 15 - @~"ident", // 16 - @~"path", // 17 - @~"tt", // 18 - @~"matchers", // 19 - @~"str", // 20 - @~"TyVisitor", // 21 - @~"arg", // 22 - @~"descrim", // 23 - @~"__rust_abi", // 24 - @~"__rust_stack_shim", // 25 - @~"TyDesc", // 26 - @~"dtor", // 27 - @~"main", // 28 - @~"", // 29 - @~"blk", // 30 - @~"static", // 31 - @~"intrinsic", // 32 - @~"__foreign_mod__", // 33 - @~"__field__", // 34 - @~"C", // 35 - @~"Self", // 36 + "_", // 0 + "anon", // 1 + "", // 2 + "unary", // 3 + "!", // 4 + "[]", // 5 + "unary-", // 6 + "__extensions__", // 7 + "self", // 8 + "item", // 9 + "block", // 10 + "stmt", // 11 + "pat", // 12 + "expr", // 13 + "ty", // 14 + "ident", // 15 + "path", // 16 + "tt", // 17 + "matchers", // 18 + "str", // 19 + "TyVisitor", // 20 + "arg", // 21 + "descrim", // 22 + "__rust_abi", // 23 + "__rust_stack_shim", // 24 + "TyDesc", // 25 + "main", // 26 + "", // 27 + "blk", // 28 + "static", // 29 + "intrinsic", // 30 + "__foreign_mod__", // 31 + "__field__", // 32 + "C", // 33 + "Self", // 34 ]; let rv = @ident_interner { - interner: interner::Interner::prefill(init_vec) + interner: interner::StrInterner::prefill(init_vec) }; unsafe { - task::local_data::local_data_set(interner_key!(), @rv); + local_data::local_data_set(interner_key!(), @rv); } rv } @@ -476,7 +478,7 @@ pub fn mk_fresh_ident_interner() -> @ident_interner { // fresh one. pub fn mk_ident_interner() -> @ident_interner { unsafe { - match task::local_data::local_data_get(interner_key!()) { + match local_data::local_data_get(interner_key!()) { Some(interner) => *interner, None => { mk_fresh_ident_interner() @@ -488,7 +490,7 @@ pub fn mk_ident_interner() -> @ident_interner { /* for when we don't care about the contents; doesn't interact with TLD or serialization */ pub fn mk_fake_ident_interner() -> @ident_interner { - @ident_interner { interner: interner::Interner::new() } + @ident_interner { interner: interner::StrInterner::new() } } /** @@ -502,26 +504,17 @@ pub fn mk_fake_ident_interner() -> @ident_interner { */ pub fn keyword_table() -> HashSet<~str> { let mut keywords = HashSet::new(); - let mut tmp = temporary_keyword_table(); let mut strict = strict_keyword_table(); let mut reserved = reserved_keyword_table(); - do tmp.consume |word| { keywords.insert(word); } - do strict.consume |word| { keywords.insert(word); } - do reserved.consume |word| { keywords.insert(word); } - return keywords; -} - -/// Keywords that may be used as identifiers -pub fn temporary_keyword_table() -> HashSet<~str> { - let mut words = HashSet::new(); - let keys = ~[ - ~"self", ~"static", - ]; - do vec::consume(keys) |_, s| { - words.insert(s); + do strict.consume |word| { + keywords.insert(word); } - return words; + do reserved.consume |word| { + keywords.insert(word); + } + + keywords } /// Full keywords. May not appear anywhere else. @@ -540,7 +533,7 @@ pub fn strict_keyword_table() -> HashSet<~str> { ~"once", ~"priv", ~"pub", ~"pure", ~"ref", ~"return", - ~"struct", ~"super", + ~"static", ~"self", ~"struct", ~"super", ~"true", ~"trait", ~"type", ~"unsafe", ~"use", ~"while" @@ -561,11 +554,3 @@ pub fn reserved_keyword_table() -> HashSet<~str> { } return words; } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index e2ad5becb123b..43f62d72a9fad 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -491,9 +491,9 @@ pub impl Printer { } END => { debug!("print END -> pop END"); - let print_stack = &*self.print_stack; + let print_stack = &mut *self.print_stack; assert!((print_stack.len() != 0u)); - self.print_stack.pop(); + print_stack.pop(); } BREAK(b) => { let top = self.get_top(); @@ -587,14 +587,3 @@ pub fn hardbreak_tok_offset(off: int) -> token { } pub fn hardbreak_tok() -> token { return hardbreak_tok_offset(0); } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d5645ada9294a..2e7c35807e5b1 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -72,6 +72,12 @@ pub fn end(s: @ps) { } pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { + return rust_printer_annotated(writer, intr, no_ann()); +} + +pub fn rust_printer_annotated(writer: @io::Writer, + intr: @ident_interner, + ann: pp_ann) -> @ps { return @ps { s: pp::mk_printer(writer, default_columns), cm: None::<@CodeMap>, @@ -83,7 +89,7 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { cur_lit: 0 }, boxes: @mut ~[], - ann: no_ann() + ann: ann }; } @@ -693,24 +699,15 @@ pub fn print_struct(s: @ps, nbsp(s); bopen(s); hardbreak_if_not_bol(s); - for struct_def.dtor.each |dtor| { - hardbreak_if_not_bol(s); - maybe_print_comment(s, dtor.span.lo); - print_outer_attributes(s, dtor.node.attrs); - head(s, ~"drop"); - print_block(s, &dtor.node.body); - } for struct_def.fields.each |field| { match field.node.kind { ast::unnamed_field => fail!(~"unexpected unnamed field"), - ast::named_field(ident, mutability, visibility) => { + ast::named_field(ident, visibility) => { hardbreak_if_not_bol(s); maybe_print_comment(s, field.span.lo); + print_outer_attributes(s, field.node.attrs); print_visibility(s, visibility); - if mutability == ast::struct_mutable { - word_nbsp(s, ~"mut"); - } print_ident(s, ident); word_nbsp(s, ~":"); print_type(s, field.node.ty); @@ -1331,12 +1328,6 @@ pub fn print_expr(s: @ps, expr: @ast::expr) { word_space(s, ~"="); print_expr(s, rhs); } - ast::expr_swap(lhs, rhs) => { - print_expr(s, lhs); - space(s.s); - word_space(s, ~"<->"); - print_expr(s, rhs); - } ast::expr_assign_op(op, lhs, rhs) => { print_expr(s, lhs); space(s.s); @@ -1361,6 +1352,7 @@ pub fn print_expr(s: @ps, expr: @ast::expr) { word(s.s, ~"]"); } ast::expr_path(path) => print_path(s, path, true), + ast::expr_self => word(s.s, ~"self"), ast::expr_break(opt_ident) => { word(s.s, ~"break"); space(s.s); @@ -2252,7 +2244,7 @@ mod test { #[test] fn test_fun_to_str() { let mock_interner = parse::token::mk_fake_ident_interner(); - let abba_ident = mock_interner.intern(@~"abba"); + let abba_ident = mock_interner.intern("abba"); let decl = ast::fn_decl { inputs: ~[], @@ -2270,7 +2262,7 @@ mod test { #[test] fn test_variant_to_str() { let mock_interner = parse::token::mk_fake_ident_interner(); - let ident = mock_interner.intern(@~"principal_skinner"); + let ident = mock_interner.intern("principal_skinner"); let var = codemap::respan(codemap::dummy_sp(), ast::variant_ { name: ident, @@ -2286,13 +2278,3 @@ mod test { assert_eq!(&varstr,&~"pub principal_skinner"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index a401d9eb8ace7..b8327de0f1320 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -22,7 +22,6 @@ #[allow(vecs_implicitly_copyable)]; #[allow(non_camel_case_types)]; -#[deny(deprecated_mode)]; #[deny(deprecated_pattern)]; extern mod std(vers = "0.7-pre"); @@ -90,4 +89,3 @@ pub mod ext { pub mod trace_macros; } - diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 9ab7d4bc443ef..cca2ec89fd421 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -17,6 +17,7 @@ use core::cmp::Equiv; use core::hashmap::HashMap; +use syntax::parse::token::StringRef; pub struct Interner { priv map: @mut HashMap, @@ -44,10 +45,10 @@ pub impl Interner { None => (), } - let vect = &*self.vect; + let vect = &mut *self.vect; let new_idx = vect.len(); self.map.insert(val, new_idx); - self.vect.push(val); + vect.push(val); new_idx } @@ -77,6 +78,61 @@ pub impl Interner { } } +pub struct StrInterner { + priv map: @mut HashMap<@~str, uint>, + priv vect: @mut ~[@~str], +} + +// when traits can extend traits, we should extend index to get [] +pub impl StrInterner { + fn new() -> StrInterner { + StrInterner { + map: @mut HashMap::new(), + vect: @mut ~[], + } + } + + fn prefill(init: &[&str]) -> StrInterner { + let rv = StrInterner::new(); + for init.each() |v| { rv.intern(*v); } + rv + } + + fn intern(&self, val: &str) -> uint { + match self.map.find_equiv(&StringRef(val)) { + Some(&idx) => return idx, + None => (), + } + + let new_idx = self.len(); + self.map.insert(@val.to_owned(), new_idx); + self.vect.push(@val.to_owned()); + new_idx + } + + fn gensym(&self, val: &str) -> uint { + let new_idx = self.len(); + // leave out of .map to avoid colliding + self.vect.push(@val.to_owned()); + new_idx + } + + // this isn't "pure" in the traditional sense, because it can go from + // failing to returning a value as items are interned. But for typestate, + // where we first check a pred and then rely on it, ceasing to fail is ok. + fn get(&self, idx: uint) -> @~str { self.vect[idx] } + + fn len(&self) -> uint { let vect = &*self.vect; vect.len() } + + fn find_equiv>(&self, val: &Q) + -> Option { + match self.map.find_equiv(val) { + Some(v) => Some(*v), + None => None, + } + } +} + /* Key for thread-local data for sneaking interner information to the * encoder/decoder. It sounds like a hack because it is one. * Bonus ultra-hack: functions as keys don't work across crates, @@ -84,7 +140,7 @@ pub impl Interner { * for another case of this. */ macro_rules! interner_key ( () => (cast::transmute::<(uint, uint), - &fn(+v: @@::parse::token::ident_interner)>( + &fn(v: @@::parse::token::ident_interner)>( (-3 as uint, 0u))) ) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 80df8fb91a515..ea02d84ddaca1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -11,7 +11,6 @@ use abi::AbiSet; use ast::*; use ast; -use ast_util; use codemap::span; use parse; use opt_vec; @@ -22,6 +21,12 @@ use opt_vec::OptVec; // children (potentially passing in different contexts to each), call // visit::visit_* to apply the default traversal algorithm (again, it can // override the context), or prevent deeper traversal by doing nothing. +// +// Note: it is an important invariant that the default visitor walks the body +// of a function in "execution order" (more concretely, reverse post-order +// with respect to the CFG implied by the AST), meaning that if AST node A may +// execute before AST node B, then A is visited first. The borrow checker in +// particular relies on this property. // Our typesystem doesn't do circular types, so the visitor record can not // hold functions that take visitors. A vt enum is used to break the cycle. @@ -39,13 +44,6 @@ pub enum fn_kind<'self> { // |x, y| ... fk_fn_block, - - fk_dtor( // class destructor - &'self Generics, - &'self [attribute], - node_id /* self id */, - def_id /* parent class id */ - ) } pub fn name_of_fn(fk: &fn_kind) -> ident { @@ -54,15 +52,13 @@ pub fn name_of_fn(fk: &fn_kind) -> ident { name } fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon, - fk_dtor(*) => parse::token::special_idents::dtor } } pub fn generics_of_fn(fk: &fn_kind) -> Generics { match *fk { fk_item_fn(_, generics, _, _) | - fk_method(_, generics, _) | - fk_dtor(generics, _, _, _) => { + fk_method(_, generics, _) => { copy *generics } fk_anon(*) | fk_fn_block(*) => { @@ -369,25 +365,6 @@ pub fn visit_method_helper(m: &method, e: E, v: vt) { ); } -pub fn visit_struct_dtor_helper(dtor: struct_dtor, generics: &Generics, - parent_id: def_id, e: E, v: vt) { - (v.visit_fn)( - &fk_dtor( - generics, - dtor.node.attrs, - dtor.node.self_id, - parent_id - ), - &ast_util::dtor_dec(), - &dtor.node.body, - dtor.span, - dtor.node.id, - e, - v - ) - -} - pub fn visit_fn(fk: &fn_kind, decl: &fn_decl, body: &blk, _sp: span, _id: node_id, e: E, v: vt) { visit_fn_decl(decl, e, v); @@ -412,23 +389,14 @@ pub fn visit_trait_method(m: &trait_method, e: E, v: vt) { pub fn visit_struct_def( sd: @struct_def, _nm: ast::ident, - generics: &Generics, - id: node_id, + _generics: &Generics, + _id: node_id, e: E, v: vt ) { for sd.fields.each |f| { (v.visit_struct_field)(*f, e, v); } - for sd.dtor.each |dtor| { - visit_struct_dtor_helper( - *dtor, - generics, - ast_util::local_def(id), - e, - v - ) - } } pub fn visit_struct_field(sf: @struct_field, e: E, v: vt) { @@ -548,10 +516,6 @@ pub fn visit_expr(ex: @expr, e: E, v: vt) { (v.visit_expr)(a, e, v); } expr_copy(a) => (v.visit_expr)(a, e, v), - expr_swap(a, b) => { - (v.visit_expr)(a, e, v); - (v.visit_expr)(b, e, v); - } expr_assign_op(_, a, b) => { (v.visit_expr)(b, e, v); (v.visit_expr)(a, e, v); @@ -565,6 +529,7 @@ pub fn visit_expr(ex: @expr, e: E, v: vt) { (v.visit_expr)(b, e, v); } expr_path(p) => visit_path(p, e, v), + expr_self => (), expr_break(_) => (), expr_again(_) => (), expr_ret(eo) => visit_expr_opt(eo, e, v), @@ -795,11 +760,3 @@ pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> { v_struct_method(v.visit_struct_method, a, b, c) }); } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libuv b/src/libuv index 218ab86721eef..97ac7c087a0ca 160000 --- a/src/libuv +++ b/src/libuv @@ -1 +1 @@ -Subproject commit 218ab86721eefd7b7e97fa6d9f95a80a1fa8686c +Subproject commit 97ac7c087a0caf6b0f611b80e14f7fe3cb18bb27 diff --git a/src/llvm b/src/llvm index 56dd407f4f97a..2e9f0d21fe321 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 56dd407f4f97a01b8df6554c569170d2fc276fcb +Subproject commit 2e9f0d21fe321849a4759a01fc28eae82ef196d6 diff --git a/src/rt/arch/arm/_context.S b/src/rt/arch/arm/_context.S index 9097ebfc07004..6441f59a4d30c 100644 --- a/src/rt/arch/arm/_context.S +++ b/src/rt/arch/arm/_context.S @@ -48,5 +48,3 @@ swap_registers: msr cpsr_cxsf, r2 mov pc, lr - - diff --git a/src/rt/arch/arm/gpr.cpp b/src/rt/arch/arm/gpr.cpp index 6dd385fb33025..77ec9d5182a17 100644 --- a/src/rt/arch/arm/gpr.cpp +++ b/src/rt/arch/arm/gpr.cpp @@ -14,4 +14,3 @@ void rust_gpr::load() { LOAD(r8); LOAD(r9); LOAD(r10); LOAD(r11); LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15); } - diff --git a/src/rt/arch/arm/gpr.h b/src/rt/arch/arm/gpr.h index 49db1429903d9..c8a3e916a371c 100644 --- a/src/rt/arch/arm/gpr.h +++ b/src/rt/arch/arm/gpr.h @@ -21,4 +21,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/arm/morestack.S b/src/rt/arch/arm/morestack.S index 4f1431a33927a..f0ec3f4b7a511 100644 --- a/src/rt/arch/arm/morestack.S +++ b/src/rt/arch/arm/morestack.S @@ -35,7 +35,7 @@ __morestack: mov r0, r4 // The amount of stack needed add r1, fp, #20 // Address of stack arguments mov r2, r5 // Size of stack arguments - + // Create new stack bl upcall_new_stack@plt @@ -64,7 +64,7 @@ __morestack: // Restore return value mov r0, r4 mov r1, r5 - + // Return pop {r6, fp, lr} mov pc, lr diff --git a/src/rt/arch/arm/record_sp.S b/src/rt/arch/arm/record_sp.S index fe680004a89aa..95fce8746a118 100644 --- a/src/rt/arch/arm/record_sp.S +++ b/src/rt/arch/arm/record_sp.S @@ -28,4 +28,3 @@ get_sp_limit: get_sp: mov r0, sp mov pc, lr - diff --git a/src/rt/arch/arm/regs.h b/src/rt/arch/arm/regs.h index 2b44bd3af357d..0d1c24e0fb749 100644 --- a/src/rt/arch/arm/regs.h +++ b/src/rt/arch/arm/regs.h @@ -19,5 +19,3 @@ # define RUSTRT_ARG1_S r1 # define RUSTRT_ARG2_S r2 # define RUSTRT_ARG3_S r3 - - diff --git a/src/rt/arch/i386/_context.S b/src/rt/arch/i386/_context.S index d2643d07c3df6..e2e4ffe35b4e4 100644 --- a/src/rt/arch/i386/_context.S +++ b/src/rt/arch/i386/_context.S @@ -63,5 +63,3 @@ SWAP_REGISTERS: // Return! jmp *48(%eax) - - diff --git a/src/rt/arch/i386/gpr.cpp b/src/rt/arch/i386/gpr.cpp index bebf801942730..e5a59d664b0d0 100644 --- a/src/rt/arch/i386/gpr.cpp +++ b/src/rt/arch/i386/gpr.cpp @@ -20,4 +20,3 @@ void rust_gpr::load() { LOAD(eax); LOAD(ebx); LOAD(ecx); LOAD(edx); LOAD(esi); LOAD(edi); LOAD(ebp); LOAD(esi); } - diff --git a/src/rt/arch/i386/gpr.h b/src/rt/arch/i386/gpr.h index 6ae53e113f4da..1953170301c53 100644 --- a/src/rt/arch/i386/gpr.h +++ b/src/rt/arch/i386/gpr.h @@ -29,4 +29,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S index e8a9c1312ed2c..c1cd11fa432af 100644 --- a/src/rt/arch/i386/morestack.S +++ b/src/rt/arch/i386/morestack.S @@ -97,7 +97,7 @@ #endif .globl MORESTACK -// FIXME: What about _WIN32? +// FIXME: What about _WIN32? #if defined(__linux__) || defined(__FreeBSD__) .hidden MORESTACK #else @@ -253,4 +253,3 @@ L_upcall_del_stack$stub: .subsections_via_symbols #endif - diff --git a/src/rt/arch/mips/ccall.S b/src/rt/arch/mips/ccall.S index abbbad164fd37..cdcdc07db555d 100644 --- a/src/rt/arch/mips/ccall.S +++ b/src/rt/arch/mips/ccall.S @@ -8,7 +8,6 @@ .align 2 .globl __morestack .hidden __morestack -.cfi_sections .eh_frame_entry .cfi_startproc .set nomips16 .ent __morestack diff --git a/src/rt/arch/mips/gpr.h b/src/rt/arch/mips/gpr.h index 4ff0729633a64..b48c1d4e732a5 100644 --- a/src/rt/arch/mips/gpr.h +++ b/src/rt/arch/mips/gpr.h @@ -30,4 +30,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/mips/morestack.S b/src/rt/arch/mips/morestack.S new file mode 100644 index 0000000000000..e534ac059133d --- /dev/null +++ b/src/rt/arch/mips/morestack.S @@ -0,0 +1,97 @@ +// Mark stack as non-executable +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack, "", @progbits +#endif + +.text + +.globl upcall_new_stack +.globl upcall_del_stack +.globl __morestack + +.hidden __morestack + +.cfi_startproc +.set nomips16 +.ent __morestack +__morestack: + .set noreorder + .set nomacro + + addiu $29, $29, -12 + sw $31, 8($29) + sw $30, 4($29) + sw $23, 0($29) + + // 24 = 12 (current) + 12 (previous) + .cfi_def_cfa_offset 24 + .cfi_offset 31, -4 + .cfi_offset 30, -20 + .cfi_offset 23, -24 + + move $23, $28 + move $30, $29 + .cfi_def_cfa_register 30 + + // Save argument registers of the original function + addiu $29, $29, -32 + sw $4, 16($29) + sw $5, 20($29) + sw $6, 24($29) + sw $7, 28($29) + + move $4, $14 // Size of stack arguments + addu $5, $30, 24 // Address of stack arguments + move $6, $15 // The amount of stack needed + + move $28, $23 + lw $25, %call16(upcall_new_stack)($23) + jalr $25 + nop + + // Pop the saved arguments + lw $4, 16($29) + lw $5, 20($29) + lw $6, 24($29) + lw $7, 28($29) + addiu $29, $29, 32 + + lw $24, 8($30) // Grab the return pointer. + addiu $24, $24, 12 // Skip past the `lw`, `jr`, `addiu` in our parent frame + move $29, $2 // Switch to the new stack. + + // for PIC + lw $2, 12($30) + lw $25, 16($30) + + move $28, $23 + jalr $24 // Reenter the caller function + nop + + // Switch back to the rust stack + move $29, $30 + + // Save the return value + addiu $29, $29, -24 + sw $2, 16($29) + sw $3, 20($29) + + move $28, $23 + lw $25, %call16(upcall_del_stack)($23) + jalr $25 + nop + + // Restore the return value + lw $2, 16($29) + lw $3, 20($29) + addiu $29, $29, 24 + + lw $31, 8($29) + lw $30, 4($29) + lw $23, 0($29) + addiu $29, $29, 12 + + jr $31 + nop +.end __morestack +.cfi_endproc diff --git a/src/rt/arch/mips/record_sp.S b/src/rt/arch/mips/record_sp.S index dd4d2f393754d..a88fefead049f 100644 --- a/src/rt/arch/mips/record_sp.S +++ b/src/rt/arch/mips/record_sp.S @@ -16,8 +16,8 @@ record_sp_limit: .set mips32r2 rdhwr $3, $29 .set pop - addiu $3, $3, -0x7008 - sw $4, 4($3) + addiu $3, $3, -0x7004 + sw $4, 0($3) jr $31 nop .end record_sp_limit @@ -33,8 +33,8 @@ get_sp_limit: .set mips32r2 rdhwr $3, $29 .set pop - addiu $3, $3, -0x7008 - lw $2, 4($3) + addiu $3, $3, -0x7004 + lw $2, 0($3) jr $31 nop .end get_sp_limit diff --git a/src/rt/arch/x86_64/_context.S b/src/rt/arch/x86_64/_context.S index bedd685546756..f718cac963470 100644 --- a/src/rt/arch/x86_64/_context.S +++ b/src/rt/arch/x86_64/_context.S @@ -121,4 +121,3 @@ SWAP_REGISTERS: // Jump to the instruction pointer // found in regs: jmp *(RUSTRT_IP*8)(ARG1) - diff --git a/src/rt/arch/x86_64/gpr.cpp b/src/rt/arch/x86_64/gpr.cpp index cf43125923ade..37247d1dfdc8b 100644 --- a/src/rt/arch/x86_64/gpr.cpp +++ b/src/rt/arch/x86_64/gpr.cpp @@ -22,4 +22,3 @@ void rust_gpr::load() { LOAD(r8); LOAD(r9); LOAD(r10); LOAD(r11); LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15); } - diff --git a/src/rt/arch/x86_64/gpr.h b/src/rt/arch/x86_64/gpr.h index 75c3b081e77e8..18ef77dbba631 100644 --- a/src/rt/arch/x86_64/gpr.h +++ b/src/rt/arch/x86_64/gpr.h @@ -30,4 +30,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/x86_64/regs.h b/src/rt/arch/x86_64/regs.h index 7d0efd1eec87c..1aca452df108b 100644 --- a/src/rt/arch/x86_64/regs.h +++ b/src/rt/arch/x86_64/regs.h @@ -43,5 +43,3 @@ # define RUSTRT_ARG4_S %r8 # define RUSTRT_ARG5_S %r9 #endif - - diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index d159df03dc3c0..a49b52bffe153 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -27,11 +27,11 @@ rust_opaque_box *boxed_region::malloc(type_desc *td, size_t body_size) { if (live_allocs) live_allocs->prev = box; live_allocs = box; - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@malloc()=%p with td %p, size %lu==%lu+%lu, " "align %lu, prev %p, next %p\n", box, td, total_size, sizeof(rust_opaque_box), body_size, - td->align, box->prev, box->next); + td->align, box->prev, box->next);*/ return box; } @@ -50,9 +50,9 @@ rust_opaque_box *boxed_region::realloc(rust_opaque_box *box, if (new_box->next) new_box->next->prev = new_box; if (live_allocs == box) live_allocs = new_box; - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@realloc()=%p with orig=%p, size %lu==%lu+%lu", - new_box, box, total_size, sizeof(rust_opaque_box), new_size); + new_box, box, total_size, sizeof(rust_opaque_box), new_size);*/ return new_box; } @@ -74,15 +74,15 @@ void boxed_region::free(rust_opaque_box *box) { // double frees (kind of). assert(box->td != NULL); - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@free(%p) with td %p, prev %p, next %p\n", - box, box->td, box->prev, box->next); + box, box->td, box->prev, box->next);*/ if (box->prev) box->prev->next = box->next; if (box->next) box->next->prev = box->prev; if (live_allocs == box) live_allocs = box->next; - if (env->poison_on_free) { + if (poison_on_free) { memset(box_body(box), 0xab, box->td->size); } diff --git a/src/rt/boxed_region.h b/src/rt/boxed_region.h index 4097b6d41b756..178772007e518 100644 --- a/src/rt/boxed_region.h +++ b/src/rt/boxed_region.h @@ -24,7 +24,7 @@ struct rust_env; * a type descr which describes the payload (what follows the header). */ class boxed_region { private: - rust_env *env; + bool poison_on_free; memory_region *backing_region; rust_opaque_box *live_allocs; @@ -41,8 +41,8 @@ class boxed_region { boxed_region& operator=(const boxed_region& rhs); public: - boxed_region(rust_env *e, memory_region *br) - : env(e) + boxed_region(memory_region *br, bool poison_on_free) + : poison_on_free(poison_on_free) , backing_region(br) , live_allocs(NULL) {} diff --git a/src/rt/isaac/rand.h b/src/rt/isaac/rand.h index 3da2d71b20b2d..c28b35e688d5a 100644 --- a/src/rt/isaac/rand.h +++ b/src/rt/isaac/rand.h @@ -52,5 +52,3 @@ void isaac(randctx *r); (r)->randrsl[(r)->randcnt]) #endif /* RAND */ - - diff --git a/src/rt/memory_region.cpp b/src/rt/memory_region.cpp index 6de9d5a1df4a2..f3406712cb012 100644 --- a/src/rt/memory_region.cpp +++ b/src/rt/memory_region.cpp @@ -11,7 +11,6 @@ #include "sync/sync.h" #include "memory_region.h" -#include "rust_env.h" #if RUSTRT_TRACK_ALLOCATIONS >= 3 #include @@ -35,15 +34,19 @@ void *memory_region::get_data(alloc_header *ptr) { return (void*)((char *)ptr + HEADER_SIZE); } -memory_region::memory_region(rust_env *env, bool synchronized) : - _env(env), _parent(NULL), _live_allocations(0), - _detailed_leaks(env->detailed_leaks), +memory_region::memory_region(bool synchronized, + bool detailed_leaks, + bool poison_on_free) : + _parent(NULL), _live_allocations(0), + _detailed_leaks(detailed_leaks), + _poison_on_free(poison_on_free), _synchronized(synchronized) { } memory_region::memory_region(memory_region *parent) : - _env(parent->_env), _parent(parent), _live_allocations(0), + _parent(parent), _live_allocations(0), _detailed_leaks(parent->_detailed_leaks), + _poison_on_free(parent->_poison_on_free), _synchronized(parent->_synchronized) { } @@ -241,7 +244,7 @@ memory_region::claim_alloc(void *mem) { void memory_region::maybe_poison(void *mem) { - if (!_env->poison_on_free) + if (!_poison_on_free) return; # if RUSTRT_TRACK_ALLOCATIONS >= 1 diff --git a/src/rt/memory_region.h b/src/rt/memory_region.h index 999a992eefaea..4ad57c11809cc 100644 --- a/src/rt/memory_region.h +++ b/src/rt/memory_region.h @@ -54,11 +54,11 @@ class memory_region { inline alloc_header *get_header(void *mem); inline void *get_data(alloc_header *); - rust_env *_env; memory_region *_parent; int _live_allocations; array_list _allocation_list; const bool _detailed_leaks; + const bool _poison_on_free; const bool _synchronized; lock_and_signal _lock; @@ -75,7 +75,8 @@ class memory_region { memory_region& operator=(const memory_region& rhs); public: - memory_region(rust_env *env, bool synchronized); + memory_region(bool synchronized, + bool detailed_leaks, bool poison_on_free); memory_region(memory_region *parent); void *malloc(size_t size, const char *tag); void *realloc(void *mem, size_t size); diff --git a/src/rt/rust_abi.cpp b/src/rt/rust_abi.cpp index ca8448b39a152..fd1b7860b29a4 100644 --- a/src/rt/rust_abi.cpp +++ b/src/rt/rust_abi.cpp @@ -86,4 +86,3 @@ symbolicate(const std::vector &frames) { } } // end namespace stack_walk - diff --git a/src/rt/rust_abi.h b/src/rt/rust_abi.h index c56bf96291fb2..4179bf751579f 100644 --- a/src/rt/rust_abi.h +++ b/src/rt/rust_abi.h @@ -76,4 +76,3 @@ std::string symbolicate(const std::vector &frames); uint32_t get_abi_version(); #endif - diff --git a/src/rt/rust_android_dummy.cpp b/src/rt/rust_android_dummy.cpp index 3c7034a2f9561..b6fe78288e97a 100644 --- a/src/rt/rust_android_dummy.cpp +++ b/src/rt/rust_android_dummy.cpp @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifdef __ANDROID__ + #include "rust_android_dummy.h" #include #include -#ifdef __ANDROID__ - int backtrace(void **array, int size) { return 0; } char **backtrace_symbols(void *const *array, int size) { return 0; } @@ -59,7 +59,21 @@ extern "C" void srand() extern "C" void atof() { } + extern "C" void tgammaf() { } + +extern "C" int glob(const char *pattern, + int flags, + int (*errfunc) (const char *epath, int eerrno), + glob_t *pglob) +{ + return 0; +} + +extern "C" void globfree(glob_t *pglob) +{ +} + #endif diff --git a/src/rt/rust_android_dummy.h b/src/rt/rust_android_dummy.h index 95a1774894bc5..d2329a46c831a 100644 --- a/src/rt/rust_android_dummy.h +++ b/src/rt/rust_android_dummy.h @@ -11,5 +11,27 @@ char **backtrace_symbols (void *__const *__array, int __size); void backtrace_symbols_fd (void *__const *__array, int __size, int __fd); -#endif +#include + +struct stat; +typedef struct { + size_t gl_pathc; /* Count of total paths so far. */ + size_t gl_matchc; /* Count of paths matching pattern. */ + size_t gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct stat *); +} glob_t; + +#endif diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index ee025a39ff472..903289281222b 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -88,8 +88,7 @@ rand_seed_size() { extern "C" CDECL void rand_gen_seed(uint8_t* dest, size_t size) { - rust_task *task = rust_get_current_task(); - rng_gen_seed(task->kernel, dest, size); + rng_gen_seed(dest, size); } extern "C" CDECL void * @@ -101,14 +100,14 @@ rand_new_seeded(uint8_t* seed, size_t seed_size) { task->fail(); return NULL; } - rng_init(task->kernel, rng, seed, seed_size); + char *env_seed = task->kernel->env->rust_seed; + rng_init(rng, env_seed, seed, seed_size); return rng; } extern "C" CDECL uint32_t rand_next(rust_rng *rng) { - rust_task *task = rust_get_current_task(); - return rng_gen_u32(task->kernel, rng); + return rng_gen_u32(rng); } extern "C" CDECL void @@ -683,6 +682,20 @@ rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) { task->task_local_data_cleanup = cleanup_fn; } +// set/get/atexit task_borrow_list can run on the rust stack for speed. +extern "C" void * +rust_take_task_borrow_list(rust_task *task) { + void *r = task->borrow_list; + task->borrow_list = NULL; + return r; +} +extern "C" void +rust_set_task_borrow_list(rust_task *task, void *data) { + assert(task->borrow_list == NULL); + assert(data != NULL); + task->borrow_list = data; +} + extern "C" void task_clear_event_reject(rust_task *task) { task->clear_event_reject(); @@ -816,13 +829,6 @@ rust_get_rt_env() { return task->kernel->env; } -typedef void *(*nullary_fn)(); - -extern "C" CDECL void -rust_call_nullary_fn(nullary_fn f) { - f(); -} - #ifndef _WIN32 pthread_key_t sched_key; #else @@ -856,6 +862,63 @@ rust_initialize_global_state() { } } +extern "C" CDECL memory_region* +rust_new_memory_region(uintptr_t synchronized, + uintptr_t detailed_leaks, + uintptr_t poison_on_free) { + return new memory_region((bool)synchronized, + (bool)detailed_leaks, + (bool)poison_on_free); +} + +extern "C" CDECL void +rust_delete_memory_region(memory_region *region) { + delete region; +} + +extern "C" CDECL boxed_region* +rust_new_boxed_region(memory_region *region, + uintptr_t poison_on_free) { + return new boxed_region(region, poison_on_free); +} + +extern "C" CDECL void +rust_delete_boxed_region(boxed_region *region) { + delete region; +} + +extern "C" CDECL rust_opaque_box* +rust_boxed_region_malloc(boxed_region *region, type_desc *td, size_t size) { + return region->malloc(td, size); +} + +extern "C" CDECL void +rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) { + region->free(box); +} + +typedef void *(rust_try_fn)(void*, void*); + +extern "C" CDECL uintptr_t +rust_try(rust_try_fn f, void *fptr, void *env) { + try { + f(fptr, env); + } catch (uintptr_t token) { + assert(token != 0); + return token; + } + return 0; +} + +extern "C" CDECL void +rust_begin_unwind(uintptr_t token) { +#ifndef __WIN32__ + throw token; +#else + abort(); +#endif +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_debug.cpp b/src/rt/rust_debug.cpp index 5c5be45bef8b8..f403b0434b649 100644 --- a/src/rt/rust_debug.cpp +++ b/src/rt/rust_debug.cpp @@ -58,4 +58,3 @@ dump_origin(rust_task *task, void *ptr) { } } // end namespace debug - diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h index c9aad098d38f8..7f025bb908e2a 100644 --- a/src/rt/rust_debug.h +++ b/src/rt/rust_debug.h @@ -70,4 +70,3 @@ void dump_origin(rust_task *task, void *ptr); } // end namespace debug #endif - diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp index 041b4efac52a2..360d611492853 100644 --- a/src/rt/rust_env.cpp +++ b/src/rt/rust_env.cpp @@ -24,6 +24,7 @@ #define RUST_SEED "RUST_SEED" #define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE" #define RUST_DEBUG_MEM "RUST_DEBUG_MEM" +#define RUST_DEBUG_BORROW "RUST_DEBUG_BORROW" #if defined(__WIN32__) static int @@ -130,6 +131,7 @@ load_env(int argc, char **argv) { env->argc = argc; env->argv = argv; env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL; + env->debug_borrow = getenv(RUST_DEBUG_BORROW) != NULL; return env; } diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h index df27f7674f265..b897f0c09a90b 100644 --- a/src/rt/rust_env.h +++ b/src/rt/rust_env.h @@ -28,6 +28,7 @@ struct rust_env { int argc; char **argv; rust_bool debug_mem; + rust_bool debug_borrow; }; rust_env* load_env(int argc, char **argv); diff --git a/src/rt/rust_globals.h b/src/rt/rust_globals.h index ff57af0833713..5a75ab5ea1b0b 100644 --- a/src/rt/rust_globals.h +++ b/src/rt/rust_globals.h @@ -20,7 +20,7 @@ #endif #if defined(__GNUC__) -#define ALWAYS_INLINE __attribute((always_inline)) INLINE +#define ALWAYS_INLINE __attribute__((always_inline)) INLINE #elif defined(_MSC_VER) #define ALWAYS_INLINE __forceinline #else diff --git a/src/rt/rust_gpr_base.h b/src/rt/rust_gpr_base.h index 4df6ea3e9adbc..7ec2dda9cd40c 100644 --- a/src/rt/rust_gpr_base.h +++ b/src/rt/rust_gpr_base.h @@ -31,4 +31,3 @@ class rust_gpr_base { #endif - diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 761dbeade538b..bf48554696ebd 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -257,25 +257,6 @@ rust_kernel::generate_task_id() { return id; } -#ifdef __WIN32__ -void -rust_kernel::win32_require(LPCTSTR fn, BOOL ok) { - if (!ok) { - LPTSTR buf; - DWORD err = GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &buf, 0, NULL ); - KLOG_ERR_(dom, "%s failed with error %ld: %s", fn, err, buf); - LocalFree((HLOCAL)buf); - assert(ok); - } -} -#endif - void rust_kernel::set_exit_status(int code) { scoped_lock with(rval_lock); diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index ec0515faeafc0..4976dec149a02 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -147,10 +147,6 @@ class rust_kernel { void wait_for_schedulers(); int run(); -#ifdef __WIN32__ - void win32_require(LPCTSTR fn, BOOL ok); -#endif - rust_task_id generate_task_id(); void set_exit_status(int code); diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index 32723cf31bc6f..c2b58c9fda732 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -24,7 +24,7 @@ */ static lock_and_signal _log_lock; /** - * Indicates whether we are outputing to the console. + * Indicates whether we are outputting to the console. * Protected by _log_lock; */ static bool _log_to_console = true; diff --git a/src/rt/rust_rng.cpp b/src/rt/rust_rng.cpp index 2c11691bf86b9..27015891feebd 100644 --- a/src/rt/rust_rng.cpp +++ b/src/rt/rust_rng.cpp @@ -12,6 +12,26 @@ #include "rust_rng.h" #include "rust_util.h" + +#ifdef __WIN32__ +void +win32_require(LPCTSTR fn, BOOL ok) { + if (!ok) { + LPTSTR buf; + DWORD err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, 0, NULL ); + fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf); + LocalFree((HLOCAL)buf); + abort(); + } +} +#endif + size_t rng_seed_size() { randctx rctx; @@ -21,44 +41,50 @@ rng_seed_size() { // Initialization helpers for ISAAC RNG void -rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size) { +rng_gen_seed(uint8_t* dest, size_t size) { #ifdef __WIN32__ HCRYPTPROV hProv; - kernel->win32_require + win32_require (_T("CryptAcquireContext"), CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); - kernel->win32_require + win32_require (_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest)); - kernel->win32_require + win32_require (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0)); #else int fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - kernel->fatal("error opening /dev/urandom: %s", strerror(errno)); + if (fd == -1) { + fprintf(stderr, "error opening /dev/urandom: %s", strerror(errno)); + abort(); + } size_t amount = 0; do { ssize_t ret = read(fd, dest+amount, size-amount); - if (ret < 0) - kernel->fatal("error reading /dev/urandom: %s", strerror(errno)); - else if (ret == 0) - kernel->fatal("somehow hit eof reading from /dev/urandom"); + if (ret < 0) { + fprintf(stderr, "error reading /dev/urandom: %s", strerror(errno)); + abort(); + } + else if (ret == 0) { + fprintf(stderr, "somehow hit eof reading from /dev/urandom"); + abort(); + } amount += (size_t)ret; } while (amount < size); int ret = close(fd); - // FIXME #3697: Why does this fail sometimes? - if (ret != 0) - kernel->log(log_warn, "error closing /dev/urandom: %s", - strerror(errno)); + if (ret != 0) { + fprintf(stderr, "error closing /dev/urandom: %s", strerror(errno)); + // FIXME #3697: Why does this fail sometimes? + // abort(); + } #endif } static void -isaac_init(rust_kernel *kernel, randctx *rctx, +isaac_init(randctx *rctx, char *env_seed, uint8_t* user_seed, size_t seed_len) { memset(rctx, 0, sizeof(randctx)); - char *env_seed = kernel->env->rust_seed; if (user_seed != NULL) { // ignore bytes after the required length if (seed_len > sizeof(rctx->randrsl)) { @@ -72,8 +98,7 @@ isaac_init(rust_kernel *kernel, randctx *rctx, seed = (seed + 0x7ed55d16) + (seed << 12); } } else { - rng_gen_seed(kernel, - (uint8_t*)&rctx->randrsl, + rng_gen_seed((uint8_t*)&rctx->randrsl, sizeof(rctx->randrsl)); } @@ -81,14 +106,14 @@ isaac_init(rust_kernel *kernel, randctx *rctx, } void -rng_init(rust_kernel* kernel, rust_rng* rng, +rng_init(rust_rng* rng, char* env_seed, uint8_t *user_seed, size_t seed_len) { - isaac_init(kernel, &rng->rctx, user_seed, seed_len); - rng->reseedable = !user_seed && !kernel->env->rust_seed; + isaac_init(&rng->rctx, env_seed, user_seed, seed_len); + rng->reseedable = !user_seed && !env_seed; } static void -rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) { +rng_maybe_reseed(rust_rng* rng) { // If this RNG has generated more than 32KB of random data and was not // seeded by the user or RUST_SEED, then we should reseed now. const size_t RESEED_THRESHOLD = 32 * 1024; @@ -96,16 +121,15 @@ rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) { if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) { return; } - rng_gen_seed(kernel, - (uint8_t*)rng->rctx.randrsl, + rng_gen_seed((uint8_t*)rng->rctx.randrsl, sizeof(rng->rctx.randrsl)); randinit(&rng->rctx, 1); } uint32_t -rng_gen_u32(rust_kernel* kernel, rust_rng* rng) { +rng_gen_u32(rust_rng* rng) { uint32_t x = isaac_rand(&rng->rctx); - rng_maybe_reseed(kernel, rng); + rng_maybe_reseed(rng); return x; } diff --git a/src/rt/rust_rng.h b/src/rt/rust_rng.h index 3879b1138fa20..a13b5acd0eff2 100644 --- a/src/rt/rust_rng.h +++ b/src/rt/rust_rng.h @@ -23,11 +23,10 @@ struct rust_rng { }; size_t rng_seed_size(); -void rng_gen_seed(rust_kernel* kernel, - uint8_t* dest, size_t size); -void rng_init(rust_kernel *kernel, rust_rng *rng, +void rng_gen_seed(uint8_t* dest, size_t size); +void rng_init(rust_rng *rng, char *env_seed, uint8_t *user_seed, size_t seed_len); -uint32_t rng_gen_u32(rust_kernel *kernel, rust_rng *rng); +uint32_t rng_gen_u32(rust_rng *rng); // // Local Variables: diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp index cf4beed1a00c6..0ba7607869140 100644 --- a/src/rt/rust_run_program.cpp +++ b/src/rt/rust_run_program.cpp @@ -15,212 +15,44 @@ #include #endif -struct RunProgramResult { - pid_t pid; - void* handle; -}; - #if defined(__WIN32__) -#include -#include - -bool backslash_run_ends_in_quote(char const *c) { - while (*c == '\\') ++c; - return *c == '"'; -} - -void append_first_char(char *&buf, char const *c) { - switch (*c) { - - case '"': - // Escape quotes. - *buf++ = '\\'; - *buf++ = '"'; - break; - - - case '\\': - if (backslash_run_ends_in_quote(c)) { - // Double all backslashes that are in runs before quotes. - *buf++ = '\\'; - *buf++ = '\\'; - } else { - // Pass other backslashes through unescaped. - *buf++ = '\\'; - } - break; - - default: - *buf++ = *c; - } +extern "C" CDECL void +rust_unset_sigprocmask() { + // empty stub for windows to keep linker happy } -bool contains_whitespace(char const *arg) { - while (*arg) { - switch (*arg++) { - case ' ': - case '\t': - return true; - } - } - return false; -} - -void append_arg(char *& buf, char const *arg, bool last) { - bool quote = contains_whitespace(arg); - if (quote) - *buf++ = '"'; - while (*arg) - append_first_char(buf, arg++); - if (quote) - *buf++ = '"'; - - if (! last) { - *buf++ = ' '; - } else { - *buf++ = '\0'; - } -} - -extern "C" CDECL RunProgramResult -rust_run_program(const char* argv[], - void* envp, - const char* dir, - int in_fd, int out_fd, int err_fd) { - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESTDHANDLES; - - RunProgramResult result = {-1, NULL}; - - HANDLE curproc = GetCurrentProcess(); - HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0); - if (!DuplicateHandle(curproc, origStdin, - curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1); - if (!DuplicateHandle(curproc, origStdout, - curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2); - if (!DuplicateHandle(curproc, origStderr, - curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - - size_t cmd_len = 0; - for (const char** arg = argv; *arg; arg++) { - cmd_len += strlen(*arg); - cmd_len += 3; // Two quotes plus trailing space or \0 - } - cmd_len *= 2; // Potentially backslash-escape everything. - - char* cmd = (char*)malloc(cmd_len); - char* pos = cmd; - for (const char** arg = argv; *arg; arg++) { - append_arg(pos, *arg, *(arg+1) == NULL); - } - - PROCESS_INFORMATION pi; - BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, - 0, envp, dir, &si, &pi); - - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - free(cmd); - - if (!created) { - return result; - } - - // We close the thread handle because we don't care about keeping the thread id valid, - // and we aren't keeping the thread handle around to be able to close it later. We don't - // close the process handle however because we want the process id to stay valid at least - // until the calling rust code closes the process handle. - CloseHandle(pi.hThread); - result.pid = pi.dwProcessId; - result.handle = pi.hProcess; - return result; -} - -extern "C" CDECL int -rust_process_wait(int pid) { - - HANDLE proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); - if (proc == NULL) { - return -1; - } - - DWORD status; - while (true) { - if (!GetExitCodeProcess(proc, &status)) { - CloseHandle(proc); - return -1; - } - if (status != STILL_ACTIVE) { - CloseHandle(proc); - return (int) status; - } - WaitForSingleObject(proc, INFINITE); - } +extern "C" CDECL void +rust_set_environ(void* envp) { + // empty stub for windows to keep linker happy } #elif defined(__GNUC__) -#include #include -#include #include -#include #ifdef __FreeBSD__ extern char **environ; #endif -extern "C" CDECL RunProgramResult -rust_run_program(const char* argv[], - void* envp, - const char* dir, - int in_fd, int out_fd, int err_fd) { - int pid = fork(); - if (pid != 0) { - RunProgramResult result = {pid, NULL}; - return result; - } - +extern "C" CDECL void +rust_unset_sigprocmask() { + // this can't be safely converted to rust code because the + // representation of sigset_t is platform-dependent sigset_t sset; sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); +} - if (in_fd) dup2(in_fd, 0); - if (out_fd) dup2(out_fd, 1); - if (err_fd) dup2(err_fd, 2); - /* Close all other fds. */ - for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd); - if (dir) { - int result = chdir(dir); - // FIXME (#2674): need error handling - assert(!result && "chdir failed"); - } - - if (envp) { +extern "C" CDECL void +rust_set_environ(void* envp) { + // FIXME: this could actually be converted to rust (see issue #2674) #ifdef __APPLE__ - *_NSGetEnviron() = (char **)envp; + *_NSGetEnviron() = (char **) envp; #else - environ = (char **)envp; + environ = (char **) envp; #endif - } - - execvp(argv[0], (char * const *)argv); - exit(1); -} - -extern "C" CDECL int -rust_process_wait(int pid) { - // FIXME: stub; exists to placate linker. (#2692) - return 0; } #else diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp index dbcbd7b83cf23..1f718df32aac9 100644 --- a/src/rt/rust_sched_loop.cpp +++ b/src/rt/rust_sched_loop.cpp @@ -38,12 +38,12 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) : sched(sched), log_lvl(log_debug), min_stack_size(kernel->env->min_stack_size), - local_region(kernel->env, false), + local_region(false, kernel->env->detailed_leaks, kernel->env->poison_on_free), // FIXME #2891: calculate a per-scheduler name. name("main") { LOGPTR(this, "new dom", (uintptr_t)this); - rng_init(kernel, &rng, NULL, 0); + rng_init(&rng, kernel->env->rust_seed, NULL, 0); if (!tls_initialized) init_tls(); @@ -154,7 +154,7 @@ rust_sched_loop::schedule_task() { lock.must_have_lock(); size_t tasks = running_tasks.length(); if (tasks > 0) { - size_t i = (tasks > 1) ? (rng_gen_u32(kernel, &rng) % tasks) : 0; + size_t i = (tasks > 1) ? (rng_gen_u32(&rng) % tasks) : 0; return running_tasks[i]; } return NULL; diff --git a/src/rt/rust_signal.h b/src/rt/rust_signal.h index bfea68a1aad50..4281092f83511 100644 --- a/src/rt/rust_signal.h +++ b/src/rt/rust_signal.h @@ -11,7 +11,7 @@ #ifndef RUST_SIGNAL_H #define RUST_SIGNAL_H -// Just an abstrict class that reperesents something that can be signalled +// Just an abstract class that represents something that can be signalled class rust_signal { public: virtual void signal() = 0; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index e6293aa5c1de0..266c0652c6e59 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -36,12 +36,13 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, kernel(sched_loop->kernel), name(name), list_index(-1), - boxed(sched_loop->kernel->env, &local_region), + boxed(&local_region, sched_loop->kernel->env->poison_on_free), local_region(&sched_loop->local_region), unwinding(false), total_stack_sz(0), task_local_data(NULL), task_local_data_cleanup(NULL), + borrow_list(NULL), state(state), cond(NULL), cond_name("none"), @@ -75,6 +76,9 @@ rust_task::delete_this() assert(ref_count == 0); // || // (ref_count == 1 && this == sched->root_task)); + // The borrow list should be freed in the task annihilator + assert(!borrow_list); + sched_loop->release_task(this); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 4aa1199cabc3f..672af608db863 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -144,7 +144,7 @@ #define RED_ZONE_SIZE RZ_LINUX_64 #endif #ifdef __mips__ -#define RED_ZONE_SIZE RZ_LINUX_32 +#define RED_ZONE_SIZE RZ_MAC_32 #endif #endif #ifdef __APPLE__ @@ -175,6 +175,10 @@ #define RED_ZONE_SIZE RZ_MAC_32 #endif +#ifndef RED_ZONE_SIZE +# error "Red zone not defined for this platform" +#endif + struct frame_glue_fns { uintptr_t mark_glue_off; uintptr_t drop_glue_off; @@ -241,6 +245,11 @@ rust_task : public kernel_owned void *task_local_data; void (*task_local_data_cleanup)(void *data); + // Contains a ~[BorrowRecord] pointer, or NULL. + // + // Used by borrow management code in libcore/unstable/lang.rs. + void *borrow_list; + private: // Protects state, cond, cond_name diff --git a/src/rt/rust_test_helpers.cpp b/src/rt/rust_test_helpers.cpp index 64966bd345489..d82c39d6838ec 100644 --- a/src/rt/rust_test_helpers.cpp +++ b/src/rt/rust_test_helpers.cpp @@ -165,3 +165,14 @@ extern "C" CDECL TwoDoubles rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) { return u; } + +// Generates increasing port numbers for network testing +extern "C" CDECL uintptr_t +rust_dbg_next_port() { + static lock_and_signal dbg_port_lock; + static uintptr_t next_port = 9600; + scoped_lock with(dbg_port_lock); + uintptr_t this_port = next_port; + next_port += 1; + return this_port; +} diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 59f06feee4b93..658fdec6df2c3 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -293,7 +293,13 @@ upcall_rust_personality(int version, s_rust_personality_args args = {(_Unwind_Reason_Code)0, version, actions, exception_class, ue_header, context}; - rust_task *task = rust_get_current_task(); + rust_task *task = rust_try_get_current_task(); + + if (task == NULL) { + // Assuming we're running with the new scheduler + upcall_s_rust_personality(&args); + return args.retval; + } // The personality function is run on the stack of the // last function that threw or landed, which is going @@ -330,8 +336,12 @@ upcall_del_stack() { // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { - rust_task *task = rust_get_current_task(); - task->reset_stack_limit(); + rust_task *task = rust_try_get_current_task(); + if (task != NULL) { + task->reset_stack_limit(); + } else { + // We must be in a newsched task + } } // diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 977e0248ca206..6be41251f1bd9 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -37,8 +37,8 @@ rust_list_dir_wfd_size rust_list_dir_wfd_fp_buf rust_log_console_on rust_log_console_off -rust_process_wait -rust_run_program +rust_set_environ +rust_unset_sigprocmask rust_sched_current_nonlazy_threads rust_sched_threads rust_set_exit_status @@ -222,6 +222,15 @@ rust_uv_ip4_addrp rust_uv_ip6_addrp rust_uv_free_ip4_addr rust_uv_free_ip6_addr -rust_call_nullary_fn rust_initialize_global_state - +rust_dbg_next_port +rust_new_memory_region +rust_delete_memory_region +rust_new_boxed_region +rust_delete_boxed_region +rust_boxed_region_malloc +rust_boxed_region_free +rust_try +rust_begin_unwind +rust_take_task_borrow_list +rust_set_task_borrow_list diff --git a/src/rustllvm/README b/src/rustllvm/README index 31495f22c0a50..c0db3f68a7620 100644 --- a/src/rustllvm/README +++ b/src/rustllvm/README @@ -1,3 +1,2 @@ This directory currently contains some LLVM support code. This will generally be sent upstream to LLVM in time; for now it lives here. - diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 451a390876c6b..8c081858d602a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -120,18 +120,18 @@ void LLVMRustInitializeTargets() { LLVMInitializeX86TargetMC(); LLVMInitializeX86AsmPrinter(); LLVMInitializeX86AsmParser(); - + LLVMInitializeARMTargetInfo(); LLVMInitializeARMTarget(); LLVMInitializeARMTargetMC(); LLVMInitializeARMAsmPrinter(); - LLVMInitializeARMAsmParser(); + LLVMInitializeARMAsmParser(); LLVMInitializeMipsTargetInfo(); LLVMInitializeMipsTarget(); LLVMInitializeMipsTargetMC(); LLVMInitializeMipsAsmPrinter(); - LLVMInitializeMipsAsmParser(); + LLVMInitializeMipsAsmParser(); } // Custom memory manager for MCJITting. It needs special features @@ -438,7 +438,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, const char *path, TargetMachine::CodeGenFileType FileType, CodeGenOpt::Level OptLevel, - bool EnableSegmentedStacks) { + bool EnableSegmentedStacks) { LLVMRustInitializeTargets(); @@ -449,7 +449,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, if (!EnableARMEHABI) { int argc = 3; const char* argv[] = {"rustc", "-arm-enable-ehabi", - "-arm-enable-ehabi-descriptors"}; + "-arm-enable-ehabi-descriptors"}; cl::ParseCommandLineOptions(argc, argv); } @@ -467,8 +467,8 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, const Target *TheTarget = TargetRegistry::lookupTarget(Trip, Err); TargetMachine *Target = TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr, - Options, Reloc::PIC_, - CodeModel::Default, OptLevel); + Options, Reloc::PIC_, + CodeModel::Default, OptLevel); Target->addAnalysisPasses(*PM); bool NoVerify = false; @@ -511,10 +511,10 @@ extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N, return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend); } -extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, - unsigned N_hi, - unsigned N_lo, - LLVMBool SignExtend) { +extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, + unsigned N_hi, + unsigned N_lo, + LLVMBool SignExtend) { unsigned long long N = N_hi; N <<= 32; N |= N_lo; @@ -545,6 +545,28 @@ extern "C" LLVMTypeRef LLVMMetadataType(void) { return LLVMMetadataTypeInContext(LLVMGetGlobalContext()); } +extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, + LLVMValueRef source, + const char* Name, + AtomicOrdering order) { + LoadInst* li = new LoadInst(unwrap(source),0); + li->setVolatile(true); + li->setAtomic(order); + li->setAlignment(sizeof(intptr_t)); + return wrap(unwrap(B)->Insert(li)); +} + +extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, + LLVMValueRef val, + LLVMValueRef target, + AtomicOrdering order) { + StoreInst* si = new StoreInst(unwrap(val),unwrap(target)); + si->setVolatile(true); + si->setAtomic(order); + si->setAlignment(sizeof(intptr_t)); + return wrap(unwrap(B)->Insert(si)); +} + extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 73bf1af90cd34..dd5dc7102d1e9 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -84,6 +84,8 @@ LLVMArrayType LLVMBasicBlockAsValue LLVMBlockAddress LLVMBuildAShr +LLVMBuildAtomicLoad +LLVMBuildAtomicStore LLVMBuildAtomicCmpXchg LLVMBuildAtomicRMW LLVMBuildAdd diff --git a/src/snapshots.txt b/src/snapshots.txt index fafd5467655ce..c643b4dd25d43 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2013-05-03 213f7b2 + macos-i386 0bf8b88ea01cc4cdd81ac4db1d301ea9b3371f13 + macos-x86_64 2da3990639ab5a9c9d51b3478c437cb459de84e3 + linux-i386 094500e587bfac27d7be752b635c242e07774c0d + linux-x86_64 75733a5a58f53aa783253c8cfd56923b78676705 + winnt-i386 bd07c935a917c0796d4dc803d973b864d4794ade + freebsd-x86_64 b95d648d9bfeacdd04cc5213bdc803b0fd94add7 + S 2013-03-28 f7a2371 macos-i386 2e05a33716fc4982db53946c3b0dccf0194826fe macos-x86_64 fbd3feec8dd17a6b6c8df114e6e9b4cd17cc6172 @@ -151,7 +159,7 @@ S 2012-10-03 5585514 winnt-i386 25680d15a358cf4163e08f4e56e54fb497de5eb4 S 2012-10-02 4d30b34 - macos-i386 2bcce3cde8a7e53df202972cda85b0b59ce4e50d + macos-i386 2bcce3cde8a7e53df202972cda85b0b59ce4e50d macos-x86_64 fc5592828392f9eabe8b51cc59639be6d709cc26 freebsd-x86_64 5e09dad0800f16f5d79286330bcb82b6d2b8782e linux-i386 92fc541d4dde19fe2af5930d72a5a50ca67bad60 diff --git a/src/test/auxiliary/anon_trait_static_method_lib.rs b/src/test/auxiliary/anon_trait_static_method_lib.rs index 9a778b1887414..6e111381cba34 100644 --- a/src/test/auxiliary/anon_trait_static_method_lib.rs +++ b/src/test/auxiliary/anon_trait_static_method_lib.rs @@ -17,4 +17,3 @@ pub impl Foo { Foo { x: 3 } } } - diff --git a/src/test/auxiliary/cci_class_2.rs b/src/test/auxiliary/cci_class_2.rs index 9dc27054ef738..b120a4d759f90 100644 --- a/src/test/auxiliary/cci_class_2.rs +++ b/src/test/auxiliary/cci_class_2.rs @@ -27,4 +27,3 @@ pub mod kitties { } } } - diff --git a/src/test/auxiliary/cci_class_6.rs b/src/test/auxiliary/cci_class_6.rs index 80990099cdab5..7ad617cebdbb3 100644 --- a/src/test/auxiliary/cci_class_6.rs +++ b/src/test/auxiliary/cci_class_6.rs @@ -23,7 +23,7 @@ pub mod kitties { fn meow_count(&mut self) -> uint { self.meows } } - pub fn cat(in_x : uint, in_y : int, +in_info: ~[U]) -> cat { + pub fn cat(in_x : uint, in_y : int, in_info: ~[U]) -> cat { cat { meows: in_x, how_hungry: in_y, @@ -31,4 +31,3 @@ pub mod kitties { } } } - diff --git a/src/test/auxiliary/cci_class_cast.rs b/src/test/auxiliary/cci_class_cast.rs index edda0644b16a6..ae0407a5bed33 100644 --- a/src/test/auxiliary/cci_class_cast.rs +++ b/src/test/auxiliary/cci_class_cast.rs @@ -56,5 +56,3 @@ pub mod kitty { } } } - - diff --git a/src/test/auxiliary/cci_no_inline_lib.rs b/src/test/auxiliary/cci_no_inline_lib.rs index 407f62adb0251..f79227d87cd1f 100644 --- a/src/test/auxiliary/cci_no_inline_lib.rs +++ b/src/test/auxiliary/cci_no_inline_lib.rs @@ -19,4 +19,3 @@ pub fn iter(v: ~[uint], f: &fn(uint)) { i += 1u; } } - diff --git a/src/test/auxiliary/explicit_self_xcrate.rs b/src/test/auxiliary/explicit_self_xcrate.rs index c790252244f6b..058cb53f9186b 100644 --- a/src/test/auxiliary/explicit_self_xcrate.rs +++ b/src/test/auxiliary/explicit_self_xcrate.rs @@ -23,5 +23,3 @@ impl Foo for Bar { io::println((*self).x); } } - - diff --git a/src/test/auxiliary/extern_mod_ordering_lib.rs b/src/test/auxiliary/extern_mod_ordering_lib.rs index 8276cea465fd5..d04351203da36 100644 --- a/src/test/auxiliary/extern_mod_ordering_lib.rs +++ b/src/test/auxiliary/extern_mod_ordering_lib.rs @@ -3,4 +3,3 @@ pub mod extern_mod_ordering_lib { pub fn f() {} } - diff --git a/src/test/auxiliary/foreign_lib.rs b/src/test/auxiliary/foreign_lib.rs index 1561ec51ede0e..fe5b9e45593e3 100644 --- a/src/test/auxiliary/foreign_lib.rs +++ b/src/test/auxiliary/foreign_lib.rs @@ -15,4 +15,3 @@ pub mod rustrt { pub fn rust_get_argc() -> libc::c_int; } } - diff --git a/src/test/auxiliary/impl_privacy_xc_1.rs b/src/test/auxiliary/impl_privacy_xc_1.rs index 92452cbe8fdc4..4d98c4d9d2b54 100644 --- a/src/test/auxiliary/impl_privacy_xc_1.rs +++ b/src/test/auxiliary/impl_privacy_xc_1.rs @@ -7,4 +7,3 @@ pub struct Fish { pub impl Fish { fn swim(&self) {} } - diff --git a/src/test/auxiliary/impl_privacy_xc_2.rs b/src/test/auxiliary/impl_privacy_xc_2.rs index 0fa15fa14f613..7ef36b1fb6627 100644 --- a/src/test/auxiliary/impl_privacy_xc_2.rs +++ b/src/test/auxiliary/impl_privacy_xc_2.rs @@ -11,5 +11,3 @@ mod unexported { fn ne(&self, _: &Fish) -> bool { false } } } - - diff --git a/src/test/auxiliary/issue-2196-c.rc b/src/test/auxiliary/issue-2196-c.rc deleted file mode 100644 index 59c1e8108c08c..0000000000000 --- a/src/test/auxiliary/issue-2196-c.rc +++ /dev/null @@ -1,16 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "issue2196c", vers = "0.1")]; -#[crate_type = "lib"]; - -use b(name = "issue2196b"); -#[path = "issue-2196-d.rs"] -mod d; diff --git a/src/test/auxiliary/issue-2196-d.rs b/src/test/auxiliary/issue-2196-d.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/test/auxiliary/issue-2414-a.rs b/src/test/auxiliary/issue-2414-a.rs index 9f4f369b70def..54bb39fd2dfad 100644 --- a/src/test/auxiliary/issue-2414-a.rs +++ b/src/test/auxiliary/issue-2414-a.rs @@ -20,4 +20,3 @@ trait foo { impl foo for ~str { fn foo(&self) {} } - diff --git a/src/test/auxiliary/issue-2414-b.rs b/src/test/auxiliary/issue-2414-b.rs index 4bebe4e14208f..f4ef02a2b7f87 100644 --- a/src/test/auxiliary/issue-2414-b.rs +++ b/src/test/auxiliary/issue-2414-b.rs @@ -14,4 +14,3 @@ #[crate_type = "lib"]; extern mod a; - diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index fa32b9603a5da..0e9cf39929f1c 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -55,4 +55,3 @@ fn context_res() -> context_res { } pub type context = arc_destruct; - diff --git a/src/test/auxiliary/issue2378a.rs b/src/test/auxiliary/issue2378a.rs index ead338c4bc803..1873aca5909ca 100644 --- a/src/test/auxiliary/issue2378a.rs +++ b/src/test/auxiliary/issue2378a.rs @@ -8,13 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[link (name = "issue2378a")]; +#[crate_type = "lib"]; + enum maybe { just(T), nothing } -impl copy> for maybe for methods T { +impl Index for maybe { + fn index(&self, idx: &uint) -> T { match self { - just(t) { t } - nothing { fail!(); } + &just(ref t) => copy *t, + ¬hing => { fail!(); } } } } diff --git a/src/test/auxiliary/issue2378b.rs b/src/test/auxiliary/issue2378b.rs index 9037417ef6224..20f07a5cb546b 100644 --- a/src/test/auxiliary/issue2378b.rs +++ b/src/test/auxiliary/issue2378b.rs @@ -8,15 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use issue2378a; +#[link (name = "issue2378b")]; +#[crate_type = "lib"]; + +extern mod issue2378a; use issue2378a::maybe; -use issue2378a::methods; -type two_maybes = {a: maybe, b: maybe}; +struct two_maybes {a: maybe, b: maybe} -impl copy> for two_maybes for methods (T, T) { - (self.a[idx], self.b[idx]) +impl Index for two_maybes { + fn index(&self, idx: &uint) -> (T, T) { + (self.a[*idx], self.b[*idx]) } } diff --git a/src/test/auxiliary/issue4516_ty_param_lib.rs b/src/test/auxiliary/issue4516_ty_param_lib.rs index dd2ffd5002c94..391e9b39610c0 100644 --- a/src/test/auxiliary/issue4516_ty_param_lib.rs +++ b/src/test/auxiliary/issue4516_ty_param_lib.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn to_closure(x: A) -> @fn() -> A { +pub fn to_closure(x: A) -> @fn() -> A { let result: @fn() -> A = || copy x; result } diff --git a/src/test/auxiliary/issue_2316_b.rs b/src/test/auxiliary/issue_2316_b.rs index ed8e69cb4da04..32283e5373ca6 100644 --- a/src/test/auxiliary/issue_2316_b.rs +++ b/src/test/auxiliary/issue_2316_b.rs @@ -17,5 +17,3 @@ pub mod cloth { gingham, flannel, calico } } - - diff --git a/src/test/auxiliary/issue_3136_a.rs b/src/test/auxiliary/issue_3136_a.rs index f7c866da9ae29..55de208cc905a 100644 --- a/src/test/auxiliary/issue_3136_a.rs +++ b/src/test/auxiliary/issue_3136_a.rs @@ -12,7 +12,7 @@ trait x { fn use_x(&self); } struct y(()); -impl x for y { +impl x for y { fn use_x(&self) { struct foo { //~ ERROR quux i: () @@ -20,6 +20,5 @@ impl x for y { fn new_foo(i: ()) -> foo { foo { i: i } } - } + } } - diff --git a/src/test/auxiliary/issue_3882.rs b/src/test/auxiliary/issue_3882.rs index 63275a05598eb..bb75758c741e9 100644 --- a/src/test/auxiliary/issue_3882.rs +++ b/src/test/auxiliary/issue_3882.rs @@ -12,7 +12,7 @@ mod issue_3882 { struct Completions { len: libc::size_t, } - + mod c { extern { fn linenoiseAddCompletion(lc: *mut Completions); diff --git a/src/test/auxiliary/issue-2196-b.rs b/src/test/auxiliary/mod_trait_with_static_methods_lib.rs similarity index 74% rename from src/test/auxiliary/issue-2196-b.rs rename to src/test/auxiliary/mod_trait_with_static_methods_lib.rs index 1ef9334b7cdf3..b060c7aee49a2 100644 --- a/src/test/auxiliary/issue-2196-b.rs +++ b/src/test/auxiliary/mod_trait_with_static_methods_lib.rs @@ -8,11 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "issue2196b", vers = "0.1")]; -#[crate_type = "lib"]; +pub use sub_foo::Foo; -use a(name = "issue2196a"); +pub mod sub_foo { + pub trait Foo { + pub fn foo() -> Self; + } -type d = str; -impl d for d { } + impl Foo for int { + pub fn foo() -> int { 42 } + } +} diff --git a/src/test/auxiliary/moves_based_on_type_lib.rs b/src/test/auxiliary/moves_based_on_type_lib.rs index 826bd0db12964..857593a84d2c0 100644 --- a/src/test/auxiliary/moves_based_on_type_lib.rs +++ b/src/test/auxiliary/moves_based_on_type_lib.rs @@ -25,4 +25,3 @@ pub fn f() { let y = x; let z = y; } - diff --git a/src/test/auxiliary/newtype_struct_xc.rs b/src/test/auxiliary/newtype_struct_xc.rs index 90036e0f96cd8..e0d2541dbe3d1 100644 --- a/src/test/auxiliary/newtype_struct_xc.rs +++ b/src/test/auxiliary/newtype_struct_xc.rs @@ -1,4 +1,3 @@ #[crate_type="lib"]; pub struct Au(int); - diff --git a/src/test/auxiliary/packed.rs b/src/test/auxiliary/packed.rs new file mode 100644 index 0000000000000..478d51b540cdf --- /dev/null +++ b/src/test/auxiliary/packed.rs @@ -0,0 +1,5 @@ +#[packed] +struct S { + a: u8, + b: u32 +} diff --git a/src/test/auxiliary/pub_use_mods_xcrate.rs b/src/test/auxiliary/pub_use_mods_xcrate.rs index e085f2312dc50..e4890f4fe2d87 100644 --- a/src/test/auxiliary/pub_use_mods_xcrate.rs +++ b/src/test/auxiliary/pub_use_mods_xcrate.rs @@ -18,4 +18,3 @@ pub mod a { } } } - diff --git a/src/test/auxiliary/static_fn_inline_xc_aux.rs b/src/test/auxiliary/static_fn_inline_xc_aux.rs index 5fc6621f18658..a17a78bcea773 100644 --- a/src/test/auxiliary/static_fn_inline_xc_aux.rs +++ b/src/test/auxiliary/static_fn_inline_xc_aux.rs @@ -21,4 +21,3 @@ pub mod float { fn from_int2(n: int) -> float { return n as float; } } } - diff --git a/src/test/auxiliary/struct_destructuring_cross_crate.rs b/src/test/auxiliary/struct_destructuring_cross_crate.rs index ab7b1a636d3e3..8887cbee3fe2b 100644 --- a/src/test/auxiliary/struct_destructuring_cross_crate.rs +++ b/src/test/auxiliary/struct_destructuring_cross_crate.rs @@ -14,4 +14,3 @@ pub struct S { x: int, y: int } - diff --git a/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs index 1c7ebd941c34b..7d6178db485f1 100644 --- a/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs +++ b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs @@ -17,5 +17,3 @@ pub struct A { x: int } impl Foo for A { fn f(&self) -> int { 10 } } impl Bar for A { fn g(&self) -> int { 20 } } impl Baz for A { fn h(&self) -> int { 30 } } - - diff --git a/src/test/auxiliary/trait_inheritance_overloading_xc.rs b/src/test/auxiliary/trait_inheritance_overloading_xc.rs index 1b480ff17b330..1fb0db25b31a8 100644 --- a/src/test/auxiliary/trait_inheritance_overloading_xc.rs +++ b/src/test/auxiliary/trait_inheritance_overloading_xc.rs @@ -38,4 +38,3 @@ impl Eq for MyInt { impl MyNum for MyInt; fn mi(v: int) -> MyInt { MyInt { val: v } } - diff --git a/src/test/auxiliary/xc_private_method_lib.rs b/src/test/auxiliary/xc_private_method_lib.rs index f9fda2b0810b3..05325c3b935c4 100644 --- a/src/test/auxiliary/xc_private_method_lib.rs +++ b/src/test/auxiliary/xc_private_method_lib.rs @@ -7,4 +7,3 @@ pub struct Foo { impl Foo { fn new() -> Foo { Foo { x: 1 } } } - diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index e216215ace7f9..cb494ec9d206a 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -103,7 +103,7 @@ fn main() { let mut rand = vec::with_capacity(n_keys); { - let rng = core::rand::IsaacRng::new_seeded([1, 1, 1, 1, 1, 1, 1]); + let mut rng = core::rand::IsaacRng::new_seeded([1, 1, 1, 1, 1, 1, 1]); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.next() as uint; diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index b3e3d295c0fad..bae21c6d4a325 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -31,8 +31,13 @@ fn timed(result: &mut float, op: &fn()) { } pub impl Results { - fn bench_int, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, - rand_cap: uint, f: &fn() -> T) { + fn bench_int, + R: rand::Rng>( + &mut self, + rng: &mut R, + num_keys: uint, + rand_cap: uint, + f: &fn() -> T) { { let mut set = f(); do timed(&mut self.sequential_ints) { @@ -69,8 +74,12 @@ pub impl Results { } } - fn bench_str, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, - f: &fn() -> T) { + fn bench_str, + R:rand::Rng>( + &mut self, + rng: &mut R, + num_keys: uint, + f: &fn() -> T) { { let mut set = f(); do timed(&mut self.sequential_strings) { @@ -155,25 +164,25 @@ fn main() { let max = 200000; { - let rng = rand::IsaacRng::new_seeded(seed); + let mut rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(&rng, num_keys, max, || HashSet::new::()); - results.bench_str(&rng, num_keys, || HashSet::new::<~str>()); + results.bench_int(&mut rng, num_keys, max, || HashSet::new::()); + results.bench_str(&mut rng, num_keys, || HashSet::new::<~str>()); write_results("core::hashmap::HashSet", &results); } { - let rng = rand::IsaacRng::new_seeded(seed); + let mut rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(&rng, num_keys, max, || TreeSet::new::()); - results.bench_str(&rng, num_keys, || TreeSet::new::<~str>()); + results.bench_int(&mut rng, num_keys, max, || TreeSet::new::()); + results.bench_str(&mut rng, num_keys, || TreeSet::new::<~str>()); write_results("std::treemap::TreeSet", &results); } { - let rng = rand::IsaacRng::new_seeded(seed); + let mut rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(&rng, num_keys, max, || BitvSet::new()); + results.bench_int(&mut rng, num_keys, max, || BitvSet::new()); write_results("std::bitv::BitvSet", &results); } } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 1af3538a0219d..e6b3b3bbe20d3 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -14,6 +14,7 @@ extern mod std; use std::time::precise_time_s; use core::rand::RngUtil; +use core::util; macro_rules! bench ( ($id:ident) => (maybe_run_test(argv, stringify!($id).to_owned(), $id)) @@ -33,12 +34,15 @@ fn main() { fn maybe_run_test(argv: &[~str], name: ~str, test: &fn()) { let mut run_test = false; - if os::getenv(~"RUST_BENCH").is_some() { run_test = true } - else if argv.len() > 0 { + if os::getenv(~"RUST_BENCH").is_some() { + run_test = true + } else if argv.len() > 0 { run_test = argv.contains(&~"all") || argv.contains(&name) } - if !run_test { return } + if !run_test { + return + } let start = precise_time_s(); test(); @@ -69,7 +73,7 @@ fn read_line() { } fn vec_plus() { - let r = rand::rng(); + let mut r = rand::rng(); let mut v = ~[]; let mut i = 0; @@ -86,7 +90,7 @@ fn vec_plus() { } fn vec_append() { - let r = rand::rng(); + let mut r = rand::rng(); let mut v = ~[]; let mut i = 0; @@ -103,7 +107,7 @@ fn vec_append() { } fn vec_push_all() { - let r = rand::rng(); + let mut r = rand::rng(); let mut v = ~[]; for uint::range(0, 1500) |i| { @@ -112,7 +116,7 @@ fn vec_push_all() { v.push_all(rv); } else { - v <-> rv; + util::swap(&mut v, &mut rv); v.push_all(rv); } } diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index c8555ab1286b1..fb27672354371 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -10,8 +10,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[allow(deprecated_mode)]; - /*! An implementation of the Graph500 Breadth First Search problem in Rust. @@ -23,7 +21,7 @@ use std::arc; use std::time; use std::deque::Deque; use std::par; -use core::hashmap::{HashMap, HashSet}; +use core::hashmap::HashSet; use core::int::abs; use core::rand::RngUtil; @@ -32,19 +30,20 @@ type graph = ~[~[node_id]]; type bfs_result = ~[node_id]; fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { - let r = rand::XorShiftRng::new(); - - fn choose_edge(i: node_id, j: node_id, scale: uint, r: &R) - -> (node_id, node_id) { + let mut r = rand::XorShiftRng::new(); + fn choose_edge(i: node_id, + j: node_id, + scale: uint, + r: &mut R) + -> (node_id, node_id) { let A = 0.57; let B = 0.19; let C = 0.19; if scale == 0u { (i, j) - } - else { + } else { let i = i * 2i64; let j = j * 2i64; let scale = scale - 1u; @@ -73,7 +72,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { } do vec::from_fn((1u << scale) * edgefactor) |_i| { - choose_edge(0i64, 0i64, scale, &r) + choose_edge(0i64, 0i64, scale, &mut r) } } @@ -82,14 +81,13 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { HashSet::new() }; - do vec::each(edges) |e| { + for vec::each(edges) |e| { match *e { (i, j) => { graph[i].insert(j); graph[j].insert(i); } } - true } do vec::map_consume(graph) |mut v| { @@ -103,7 +101,7 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { fn gen_search_keys(graph: &[~[node_id]], n: uint) -> ~[node_id] { let mut keys = HashSet::new(); - let r = rand::rng(); + let mut r = rand::rng(); while keys.len() < n { let k = r.gen_uint_range(0u, graph.len()); @@ -272,7 +270,7 @@ fn pbfs(graph: &arc::ARC, key: node_id) -> bfs_result { colors = do par::mapi(*color_vec) { let colors = arc::clone(&color); let graph = arc::clone(graph); - let result: ~fn(+x: uint, +y: &color) -> color = |i, c| { + let result: ~fn(x: uint, y: &color) -> color = |i, c| { let colors = arc::get(&colors); let graph = arc::get(&graph); match *c { @@ -394,7 +392,7 @@ fn validate(edges: ~[(node_id, node_id)], let status = do par::alli(tree) { let edges = copy edges; - let result: ~fn(+x: uint, v: &i64) -> bool = |u, v| { + let result: ~fn(x: uint, v: &i64) -> bool = |u, v| { let u = u as node_id; if *v == -1i64 || u == root { true diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 3833c88465254..95758b3fe6406 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -65,15 +65,15 @@ fn run(args: &[~str]) { let mut worker_results = ~[]; for uint::range(0, workers) |_i| { let to_child = to_child.clone(); - do task::task().future_result(|+r| { - worker_results.push(r); - }).spawn || { + let mut builder = task::task(); + builder.future_result(|r| worker_results.push(r)); + do builder.spawn { for uint::range(0, size / workers) |_i| { //error!("worker %?: sending %? bytes", i, num_bytes); to_child.send(bytes(num_bytes)); } //error!("worker %? exiting", i); - }; + } } do task::spawn || { server(&from_parent, &to_parent); @@ -104,7 +104,7 @@ fn main() { ~[~"", ~"10000", ~"4"] } else { copy args - }; + }; debug!("%?", args); run(args); diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index c4044d45f36c8..e213a44b49ae7 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -62,9 +62,9 @@ fn run(args: &[~str]) { for uint::range(0, workers) |_i| { let (from_parent_, to_child) = stream(); from_parent.add(from_parent_); - do task::task().future_result(|+r| { - worker_results.push(r); - }).spawn || { + let mut builder = task::task(); + builder.future_result(|r| worker_results.push(r)); + do builder.spawn { for uint::range(0, size / workers) |_i| { //error!("worker %?: sending %? bytes", i, num_bytes); to_child.send(bytes(num_bytes)); @@ -101,7 +101,7 @@ fn main() { ~[~"", ~"10000", ~"4"] } else { copy args - }; + }; debug!("%?", args); run(args); diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index a1ab7384d62a5..2d234634cc8ba 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -45,10 +45,7 @@ fn init() -> (pipe,pipe) { } -fn thread_ring(i: uint, - count: uint, - +num_chan: pipe, - +num_port: pipe) { +fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { let mut num_chan = Some(num_chan); let mut num_port = Some(num_port); // Send/Receive lots of messages. @@ -72,7 +69,7 @@ fn main() { ~[~"", ~"10", ~"100"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); @@ -103,7 +100,9 @@ fn main() { thread_ring(0, msg_per_task, num_chan.take(), num_port); // synchronize - for futures.each |f| { f.get() }; + for futures.each_mut |f| { + f.get() + } let stop = time::precise_time_s(); diff --git a/src/test/bench/msgsend-ring-pipes.rs b/src/test/bench/msgsend-ring-pipes.rs index 14e955dd7bdae..f698b2c3c1137 100644 --- a/src/test/bench/msgsend-ring-pipes.rs +++ b/src/test/bench/msgsend-ring-pipes.rs @@ -20,6 +20,7 @@ extern mod std; use core::cell::Cell; use core::pipes::recv; +use core::util; use std::time; use std::future; @@ -35,17 +36,15 @@ macro_rules! move_out ( fn thread_ring(i: uint, count: uint, - +num_chan: ring::client::num, - +num_port: ring::server::num) { + num_chan: ring::client::num, + num_port: ring::server::num) { let mut num_chan = Some(num_chan); let mut num_port = Some(num_port); // Send/Receive lots of messages. for uint::range(0, count) |j| { //error!("task %?, iter %?", i, j); - let mut num_chan2 = None; - let mut num_port2 = None; - num_chan2 <-> num_chan; - num_port2 <-> num_port; + let num_chan2 = util::replace(&mut num_chan, None); + let num_port2 = util::replace(&mut num_port, None); num_chan = Some(ring::client::num(num_chan2.unwrap(), i * j)); let port = num_port2.unwrap(); match recv(port) { @@ -65,7 +64,7 @@ fn main() { ~[~"", ~"100", ~"1000"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); @@ -96,7 +95,9 @@ fn main() { thread_ring(0, msg_per_task, num_chan.take(), num_port); // synchronize - for futures.each |f| { f.get() }; + for futures.each_mut |f| { + let _ = f.get(); + } let stop = time::precise_time_s(); diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs index 8e819cc4aba00..02415c4bcfce7 100644 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ b/src/test/bench/msgsend-ring-rw-arcs.rs @@ -46,10 +46,7 @@ fn init() -> (pipe,pipe) { } -fn thread_ring(i: uint, - count: uint, - +num_chan: pipe, - +num_port: pipe) { +fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { let mut num_chan = Some(num_chan); let mut num_port = Some(num_port); // Send/Receive lots of messages. @@ -73,7 +70,7 @@ fn main() { ~[~"", ~"10", ~"100"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); @@ -104,7 +101,9 @@ fn main() { thread_ring(0, msg_per_task, num_chan.take(), num_port); // synchronize - for futures.each |f| { f.get() }; + for futures.each_mut |f| { + let _ = f.get(); + } let stop = time::precise_time_s(); diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 0da3a2e5d68d0..992ce73a4bff7 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -13,7 +13,7 @@ fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } #[inline(always)] fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } -fn random_gradient(r: &R) -> Vec2 { +fn random_gradient(r: &mut R) -> Vec2 { let v = 2.0 * float::consts::pi * r.gen(); Vec2 { x: float::cos(v) as f32, @@ -33,11 +33,15 @@ struct Noise2DContext { pub impl Noise2DContext { fn new() -> Noise2DContext { - let r = rand::rng(); + let mut r = rand::rng(); let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; - for int::range(0, 256) |i| { rgradients[i] = random_gradient(&r); } + for int::range(0, 256) |i| { + rgradients[i] = random_gradient(&mut r); + } let mut permutations = [ 0, ..256 ]; - for int::range(0, 256) |i| { permutations[i] = i; } + for int::range(0, 256) |i| { + permutations[i] = i; + } r.shuffle_mut(permutations); Noise2DContext { @@ -53,7 +57,11 @@ pub impl Noise2DContext { } #[inline] - fn get_gradients(&self, gradients: &mut [Vec2, ..4], origins: &mut [Vec2, ..4], x: f32, y: f32) { + fn get_gradients(&self, + gradients: &mut [Vec2, ..4], + origins: &mut [Vec2, ..4], + x: f32, + y: f32) { let x0f = f32::floor(x); let y0f = f32::floor(y); let x0 = x0f as int; diff --git a/src/test/bench/pingpong.rs b/src/test/bench/pingpong.rs index 4a6e90f411686..cfad253cfed5b 100644 --- a/src/test/bench/pingpong.rs +++ b/src/test/bench/pingpong.rs @@ -11,7 +11,7 @@ // Compare bounded and unbounded protocol performance. // xfail-pretty - + extern mod std; use core::cell::Cell; @@ -117,8 +117,9 @@ pub fn spawn_service_recv( client } -fn switch(+endp: core::pipes::RecvPacketBuffered, - f: &fn(+v: Option) -> U) -> U { +fn switch(endp: core::pipes::RecvPacketBuffered, + f: &fn(v: Option) -> U) + -> U { f(core::pipes::try_recv(endp)) } diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index 8d0675d0884e5..c420e0cbb2fd0 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -1,3 +1,7 @@ +// xfail-test + +// Broken due to arena API problems. + // 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. @@ -10,7 +14,6 @@ extern mod std; use std::arena; -use methods = std::arena::Arena; enum tree<'self> { nil, @@ -26,9 +29,7 @@ fn item_check(t: &tree) -> int { } } -fn bottom_up_tree<'r>(arena: &'r arena::Arena, - item: int, - depth: int) +fn bottom_up_tree<'r>(arena: &'r mut arena::Arena, item: int, depth: int) -> &'r tree<'r> { if depth > 0 { return arena.alloc( @@ -58,25 +59,25 @@ fn main() { max_depth = n; } - let stretch_arena = arena::Arena(); + let mut stretch_arena = arena::Arena(); let stretch_depth = max_depth + 1; - let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth); + let stretch_tree = bottom_up_tree(&mut stretch_arena, 0, stretch_depth); io::println(fmt!("stretch tree of depth %d\t check: %d", stretch_depth, item_check(stretch_tree))); - let long_lived_arena = arena::Arena(); - let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth); + let mut long_lived_arena = arena::Arena(); + let long_lived_tree = bottom_up_tree(&mut long_lived_arena, 0, max_depth); let mut depth = min_depth; while depth <= max_depth { let iterations = int::pow(2, (max_depth - depth + min_depth) as uint); let mut chk = 0; let mut i = 1; while i <= iterations { - let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth); + let mut temp_tree = bottom_up_tree(&mut long_lived_arena, i, depth); chk += item_check(temp_tree); - temp_tree = bottom_up_tree(&long_lived_arena, -i, depth); + temp_tree = bottom_up_tree(&mut long_lived_arena, -i, depth); chk += item_check(temp_tree); i += 1; } @@ -87,5 +88,5 @@ fn main() { } io::println(fmt!("long lived trees of depth %d\t check: %d", max_depth, - item_check(long_lived_tree))); + item_check(long_lived_tree))); } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 9dad24646ded2..5d893d4ec07d0 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -218,4 +218,3 @@ fn main() { rendezvous(nn, ~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]); } - diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 21f38245ca359..cb32e0e496e95 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -92,4 +92,3 @@ fn main() { let n: i32 = FromStr::from_str(os::args()[1]).get(); println(fmt!("Pfannkuchen(%d) = %d", n as int, fannkuch_redux(n) as int)); } - diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 5ece98102063b..d6a0f4b8b255e 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -201,4 +201,3 @@ fn main() { fputc('\n' as c_int, stdout); } } - diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 0fcf8341ac852..7316b68f8bd42 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -63,7 +63,10 @@ fn make_random_fasta(wr: @io::Writer, genelist: ~[AminoAcids], n: int) { wr.write_line(~">" + id + ~" " + desc); - let rng = @mut MyRandom {last: rand::rng().next()}; + let mut rng = rand::rng(); + let rng = @mut MyRandom { + last: rng.next() + }; let mut op: ~str = ~""; for uint::range(0u, n as uint) |_i| { str::push_char(&mut op, select_random(myrandom_next(rng, 100u32), diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 4cd7b58ce12a0..fa6b7066e405e 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -17,6 +17,7 @@ use core::hashmap::HashMap; use core::io::ReaderUtil; use core::comm::{stream, Port, Chan}; use core::cmp::Ord; +use core::util; // given a map, print a sorted version of it fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { @@ -159,8 +160,7 @@ fn main() { let mut from_child = ~[]; let to_child = vec::mapi(sizes, |ii, sz| { let sz = *sz; - let mut stream = None; - stream <-> streams[ii]; + let stream = util::replace(&mut streams[ii], None); let (from_child_, to_parent_) = stream.unwrap(); from_child.push(from_child_); @@ -184,10 +184,10 @@ fn main() { if str::len(line) == 0u { loop; } - match (line[0], proc_mode) { + match (line[0] as char, proc_mode) { // start processing if this is the one - ('>' as u8, false) => { + ('>', false) => { match str::find_str_from(line, ~"THREE", 1u) { option::Some(_) => { proc_mode = true; } option::None => { } @@ -195,7 +195,7 @@ fn main() { } // break our processing - ('>' as u8, true) => { break; } + ('>', true) => { break; } // process the sequence for k-mers (_, true) => { @@ -222,4 +222,3 @@ fn main() { io::println(from_child[ii].recv()); } } - diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 224885a3f79b1..1791af67ed040 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -252,7 +252,7 @@ fn generate_frequencies(frequencies: &mut Table, mut input: &[u8], frame: i32) { let mut code = Code(0); - + // Pull first frame. for (frame as uint).times { code = code.push_char(input[0]); @@ -313,4 +313,3 @@ fn main() { print_occurrences(frequencies, occurrence); } } - diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e62cb8ea849d1..7d2b25792ec57 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -57,4 +57,3 @@ fn main() { } } } - diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index acb8a6bcbeed6..b7ae331c8f376 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -26,7 +26,6 @@ use core::int::range; use core::comm::*; use core::io::WriterUtil; -use core::result; use core::result::{Ok, Err}; fn fib(n: int) -> int { @@ -67,7 +66,7 @@ fn parse_opts(argv: ~[~str]) -> Config { } } -fn stress_task(&&id: int) { +fn stress_task(id: int) { let mut i = 0; loop { let n = 15; @@ -80,13 +79,15 @@ fn stress_task(&&id: int) { fn stress(num_tasks: int) { let mut results = ~[]; for range(0, num_tasks) |i| { - do task::task().future_result(|+r| { - results.push(r); - }).spawn { + let mut builder = task::task(); + builder.future_result(|r| results.push(r)); + do builder.spawn { stress_task(i); } } - for results.each |r| { r.recv(); } + for results.each |r| { + r.recv(); + } } fn main() { diff --git a/src/test/bench/shootout-pidigits.rs b/src/test/bench/shootout-pidigits.rs index 38e87358ee214..cb7fa969be7a7 100644 --- a/src/test/bench/shootout-pidigits.rs +++ b/src/test/bench/shootout-pidigits.rs @@ -175,4 +175,3 @@ fn main() { let n: u32 = FromStr::from_str(os::args()[1]).get(); pidigits(n); } - diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 72c01c8d55cfb..a9cb3c7636a9b 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -152,4 +152,3 @@ fn main() { fwrite(transmute(out.unsafe_ref(0)), 1, pos as size_t, stdout); } } - diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 9221da8b55738..8afddd3a31e91 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -274,4 +274,3 @@ fn main() { sudoku.solve(); sudoku.write(io::stdout()); } - diff --git a/src/test/bench/task-perf-linked-failure.rs b/src/test/bench/task-perf-linked-failure.rs index 90c9d6b33e4ad..6015f21be727f 100644 --- a/src/test/bench/task-perf-linked-failure.rs +++ b/src/test/bench/task-perf-linked-failure.rs @@ -46,9 +46,12 @@ fn grandchild_group(num_tasks: uint) { // Master grandchild task exits early. } -fn spawn_supervised_blocking(myname: &str, +f: ~fn()) { +fn spawn_supervised_blocking(myname: &str, f: ~fn()) { let mut res = None; - task::task().future_result(|+r| res = Some(r)).supervised().spawn(f); + let mut builder = task::task(); + builder.future_result(|r| res = Some(r)); + builder.supervised(); + builder.spawn(f); error!("%s group waiting", myname); let x = res.unwrap().recv(); assert!(x == task::Success); diff --git a/src/test/bench/task-perf-spawnalot.rs b/src/test/bench/task-perf-spawnalot.rs index 8c5bbe257bdd2..e6da898a03493 100644 --- a/src/test/bench/task-perf-spawnalot.rs +++ b/src/test/bench/task-perf-spawnalot.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(&&n: uint) { +fn f(n: uint) { let mut i = 0u; while i < n { task::try(|| g() ); diff --git a/src/test/compile-fail/access-mode-in-closures.rs b/src/test/compile-fail/access-mode-in-closures.rs index f6b9a82ec676c..61fb754f7619f 100644 --- a/src/test/compile-fail/access-mode-in-closures.rs +++ b/src/test/compile-fail/access-mode-in-closures.rs @@ -16,6 +16,6 @@ fn unpack(_unpack: &fn(v: &sty) -> ~[int]) {} fn main() { let _foo = unpack(|s| { // Test that `s` is moved here. - match *s { sty(v) => v } //~ ERROR moving out of dereference of immutable & pointer + match *s { sty(v) => v } //~ ERROR cannot move out }); } diff --git a/src/test/compile-fail/alt-join.rs b/src/test/compile-fail/alt-join.rs index 73f2c81302c6f..3caac6dbcfee0 100644 --- a/src/test/compile-fail/alt-join.rs +++ b/src/test/compile-fail/alt-join.rs @@ -16,6 +16,6 @@ fn my_fail() -> ! { fail!(); } fn main() { match true { false => { my_fail(); } true => { } } - debug!(x); //~ ERROR unresolved name: `x`. + debug!(x); //~ ERROR unresolved name `x`. let x: int; } diff --git a/src/test/compile-fail/alt-tag-nullary.rs b/src/test/compile-fail/alt-tag-nullary.rs index c74ee3d852a52..2b0c3dbf8e80f 100644 --- a/src/test/compile-fail/alt-tag-nullary.rs +++ b/src/test/compile-fail/alt-tag-nullary.rs @@ -14,4 +14,3 @@ enum a { A, } enum b { B, } fn main() { let x: a = A; match x { B => { } } } - diff --git a/src/test/compile-fail/alt-tag-unary.rs b/src/test/compile-fail/alt-tag-unary.rs index e01b9a045e531..a129ff19ac63e 100644 --- a/src/test/compile-fail/alt-tag-unary.rs +++ b/src/test/compile-fail/alt-tag-unary.rs @@ -14,4 +14,3 @@ enum a { A(int), } enum b { B(int), } fn main() { let x: a = A(0); match x { B(y) => { } } } - diff --git a/src/test/compile-fail/alt-vec-mismatch-2.rs b/src/test/compile-fail/alt-vec-mismatch-2.rs index 9e8fb84951d30..6ea0300cf1e7d 100644 --- a/src/test/compile-fail/alt-vec-mismatch-2.rs +++ b/src/test/compile-fail/alt-vec-mismatch-2.rs @@ -1,5 +1,5 @@ fn main() { match () { - [()] => { } //~ ERROR mismatched type: expected `()` but found vector + [()] => { } //~ ERROR mismatched types: expected `()` but found a vector pattern } } diff --git a/src/test/compile-fail/alt-vec-mismatch.rs b/src/test/compile-fail/alt-vec-mismatch.rs index ef4d92ea4913b..85ed8761ee935 100644 --- a/src/test/compile-fail/alt-vec-mismatch.rs +++ b/src/test/compile-fail/alt-vec-mismatch.rs @@ -1,6 +1,6 @@ fn main() { match ~"foo" { - ['f', 'o', .._] => { } //~ ERROR mismatched type: expected `~str` but found vector + ['f', 'o', .._] => { } //~ ERROR mismatched types: expected `~str` but found a vector pattern _ => { } } } diff --git a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs index e2dd13a4405d1..85f60f34bdb80 100644 --- a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs @@ -17,6 +17,7 @@ fn main() { y = Some(x.downgrade(write_mode)); //~^ ERROR cannot infer an appropriate lifetime } + y.get(); // Adding this line causes a method unification failure instead // do (&option::unwrap(y)).read |state| { assert!(*state == 1); } } diff --git a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs index 78a50a4f21242..c7ae6a0dc6c52 100644 --- a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs @@ -17,6 +17,7 @@ fn main() { do x.write_downgrade |write_mode| { y = Some(write_mode); } + y.get(); // Adding this line causes a method unification failure instead // do (&option::unwrap(y)).write |state| { assert!(*state == 1); } } diff --git a/src/test/compile-fail/attempted-access-non-fatal.rs b/src/test/compile-fail/attempted-access-non-fatal.rs index ba15abc3f8965..1d9249bc17b1f 100644 --- a/src/test/compile-fail/attempted-access-non-fatal.rs +++ b/src/test/compile-fail/attempted-access-non-fatal.rs @@ -11,6 +11,6 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - debug!(x.foo); //~ ERROR attempted access of field - debug!(x.bar); //~ ERROR attempted access of field + let _ = x.foo; //~ ERROR attempted access of field + let _ = x.bar; //~ ERROR attempted access of field } diff --git a/src/test/compile-fail/bad-expr-path.rs b/src/test/compile-fail/bad-expr-path.rs index 30014817308f4..c17baf40d6446 100644 --- a/src/test/compile-fail/bad-expr-path.rs +++ b/src/test/compile-fail/bad-expr-path.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unresolved name: `m1::a`. Did you mean: `args`? +// error-pattern: unresolved name `m1::a`. Did you mean `args`? mod m1 {} diff --git a/src/test/compile-fail/bad-expr-path2.rs b/src/test/compile-fail/bad-expr-path2.rs index 88239a4cc3fee..936f893ae8e66 100644 --- a/src/test/compile-fail/bad-expr-path2.rs +++ b/src/test/compile-fail/bad-expr-path2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unresolved name: `m1::a`. Did you mean: `args`? +// error-pattern: unresolved name `m1::a`. Did you mean `args`? mod m1 { pub mod a {} diff --git a/src/test/compile-fail/bad-for-loop.rs b/src/test/compile-fail/bad-for-loop.rs index 8835c577fa8fd..7ff51eff8eeb6 100644 --- a/src/test/compile-fail/bad-for-loop.rs +++ b/src/test/compile-fail/bad-for-loop.rs @@ -11,4 +11,5 @@ fn main() { fn baz(_x: &fn(y: int) -> int) {} for baz |_e| { } //~ ERROR A `for` loop iterator should expect a closure that returns `bool` + //~^ ERROR expected `for` closure to return `bool` } diff --git a/src/test/compile-fail/block-coerce-no.rs b/src/test/compile-fail/block-coerce-no.rs index bdde5144b04d1..df9eb9fdda69b 100644 --- a/src/test/compile-fail/block-coerce-no.rs +++ b/src/test/compile-fail/block-coerce-no.rs @@ -12,9 +12,9 @@ // other tycons. fn coerce(b: &fn()) -> extern fn() { - fn lol(+f: extern fn(+v: &fn()) -> extern fn(), - +g: &fn()) -> extern fn() { return f(g); } - fn fn_id(+f: extern fn()) -> extern fn() { return f } + fn lol(f: extern fn(v: &fn()) -> extern fn(), + g: &fn()) -> extern fn() { return f(g); } + fn fn_id(f: extern fn()) -> extern fn() { return f } return lol(fn_id, b); //~^ ERROR mismatched types } diff --git a/src/test/compile-fail/bogus-tag.rs b/src/test/compile-fail/bogus-tag.rs index 12e8ba56532cb..89ad7b4245a07 100644 --- a/src/test/compile-fail/bogus-tag.rs +++ b/src/test/compile-fail/bogus-tag.rs @@ -21,4 +21,3 @@ fn main() { hsl(h, s, l) => { debug!("hsl"); } } } - diff --git a/src/test/compile-fail/borrowck-addr-of-upvar.rs b/src/test/compile-fail/borrowck-addr-of-upvar.rs index 640bc887731f9..83baedc789277 100644 --- a/src/test/compile-fail/borrowck-addr-of-upvar.rs +++ b/src/test/compile-fail/borrowck-addr-of-upvar.rs @@ -9,12 +9,12 @@ // except according to those terms. fn foo(x: @int) -> @fn() -> &'static int { - let result: @fn() -> &'static int = || &*x; //~ ERROR illegal borrow + let result: @fn() -> &'static int = || &*x; //~ ERROR cannot root result } fn bar(x: @int) -> @fn() -> &int { - let result: @fn() -> &int = || &*x; //~ ERROR illegal borrow + let result: @fn() -> &int = || &*x; //~ ERROR cannot root result } diff --git a/src/test/compile-fail/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck-assign-comp-idx.rs index 25b56abb5ba00..9b21cbf9768f7 100644 --- a/src/test/compile-fail/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck-assign-comp-idx.rs @@ -17,9 +17,11 @@ fn a() { let mut p = ~[1]; // Create an immutable pointer into p's contents: - let _q: &int = &p[0]; //~ NOTE loan of mutable vec content granted here + let q: &int = &p[0]; - p[0] = 5; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + p[0] = 5; //~ ERROR cannot assign + + debug!("%d", *q); } fn borrow(_x: &[int], _f: &fn()) {} @@ -30,8 +32,8 @@ fn b() { let mut p = ~[1]; - do borrow(p) { //~ NOTE loan of mutable vec content granted here - p[0] = 5; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + do borrow(p) { + p[0] = 5; //~ ERROR cannot assign to } } @@ -45,4 +47,3 @@ fn c() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck-assign-comp.rs index 283f04a283f4e..ccd0542ca7f59 100644 --- a/src/test/compile-fail/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck-assign-comp.rs @@ -12,12 +12,13 @@ struct point { x: int, y: int } fn a() { let mut p = point {x: 3, y: 4}; - let _q = &p; //~ NOTE loan of mutable local variable granted here + let q = &p; // This assignment is illegal because the field x is not // inherently mutable; since `p` was made immutable, `p.x` is now // immutable. Otherwise the type of &_q.x (&int) would be wrong. - p.x = 5; //~ ERROR assigning to mutable field prohibited due to outstanding loan + p.x = 5; //~ ERROR cannot assign to `p.x` + q.x; } fn c() { @@ -25,9 +26,10 @@ fn c() { // and then try to overwrite `p` as a whole. let mut p = point {x: 3, y: 4}; - let _q = &p.y; //~ NOTE loan of mutable local variable granted here - p = point {x: 5, y: 7};//~ ERROR assigning to mutable local variable prohibited due to outstanding loan - copy p; + let q = &p.y; + p = point {x: 5, y: 7};//~ ERROR cannot assign to `p` + p.x; // silence warning + *q; // stretch loan } fn d() { @@ -35,11 +37,10 @@ fn d() { // address of a subcomponent and then modify that subcomponent: let mut p = point {x: 3, y: 4}; - let _q = &p.y; //~ NOTE loan of mutable field granted here - p.y = 5; //~ ERROR assigning to mutable field prohibited due to outstanding loan - copy p; + let q = &p.y; + p.y = 5; //~ ERROR cannot assign to `p.y` + *q; } fn main() { } - diff --git a/src/test/compile-fail/borrowck-assign-to-constants.rs b/src/test/compile-fail/borrowck-assign-to-constants.rs index 0d65aacb65b7a..f0dc28b736d16 100644 --- a/src/test/compile-fail/borrowck-assign-to-constants.rs +++ b/src/test/compile-fail/borrowck-assign-to-constants.rs @@ -12,6 +12,6 @@ static foo: int = 5; fn main() { // assigning to various global constants - None = Some(3); //~ ERROR assigning to static item - foo = 6; //~ ERROR assigning to static item + None = Some(3); //~ ERROR cannot assign to immutable static item + foo = 6; //~ ERROR cannot assign to immutable static item } diff --git a/src/test/compile-fail/borrowck-assign-to-enum.rs b/src/test/compile-fail/borrowck-assign-to-enum.rs index a35d88a76f393..fcaba0adc46eb 100644 --- a/src/test/compile-fail/borrowck-assign-to-enum.rs +++ b/src/test/compile-fail/borrowck-assign-to-enum.rs @@ -12,5 +12,5 @@ struct foo(int); fn main() { let x = foo(3); - *x = 4; //~ ERROR assigning to anonymous field + *x = 4; //~ ERROR cannot assign to immutable anonymous field } diff --git a/src/test/compile-fail/borrowck-assign-to-subfield.rs b/src/test/compile-fail/borrowck-assign-to-subfield.rs index 610802ca68b31..2ee5ecfcb9ce0 100644 --- a/src/test/compile-fail/borrowck-assign-to-subfield.rs +++ b/src/test/compile-fail/borrowck-assign-to-subfield.rs @@ -34,6 +34,6 @@ fn main() { // in these cases we pass through a box, so the mut // of the box is dominant - p.x.a = 2; //~ ERROR assigning to immutable field + p.x.a = 2; //~ ERROR cannot assign to immutable field p.z.a = 2; } diff --git a/src/test/compile-fail/auto-ref-borrowck-failure.rs b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs similarity index 81% rename from src/test/compile-fail/auto-ref-borrowck-failure.rs rename to src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs index 90b9b44cfbea3..2ba5d0473cc62 100644 --- a/src/test/compile-fail/auto-ref-borrowck-failure.rs +++ b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs @@ -14,18 +14,13 @@ struct Foo { x: int } -trait Stuff { - fn printme(self); -} - -impl<'self> Stuff for &'self mut Foo { - fn printme(self) { +pub impl Foo { + fn printme(&mut self) { io::println(fmt!("%d", self.x)); } } fn main() { let x = Foo { x: 3 }; - x.printme(); //~ ERROR illegal borrow + x.printme(); //~ ERROR cannot borrow } - diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs index c95b93445adca..192fe669f57ae 100644 --- a/src/test/compile-fail/borrowck-autoref-3261.rs +++ b/src/test/compile-fail/borrowck-autoref-3261.rs @@ -17,10 +17,10 @@ pub impl X { } fn main() { let mut x = X(Right(main)); - do (&mut x).with |opt| { //~ ERROR illegal borrow + do (&mut x).with |opt| { match opt { &Right(ref f) => { - x = X(Left((0,0))); //~ ERROR assigning to captured outer mutable variable + x = X(Left((0,0))); //~ ERROR cannot assign to `x` (*f)() }, _ => fail!() diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-free.rs b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs new file mode 100644 index 0000000000000..ff1ec38ad6406 --- /dev/null +++ b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs @@ -0,0 +1,43 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + +fn rewrite(v: &mut ~uint) -> uint { + *v = ~22; + **v +} + +fn add(v: &uint, w: uint) -> uint { + *v + w +} + +fn implicit() { + let mut a = ~1; + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets freed when evaluating the second + // argument! + add( + a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn explicit() { + let mut a = ~1; + add( + &*a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-move.rs b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs new file mode 100644 index 0000000000000..0adf486b8b3ab --- /dev/null +++ b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs @@ -0,0 +1,43 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + +fn rewrite(v: &mut ~uint) -> uint { + *v = ~22; + **v +} + +fn add(v: &uint, w: ~uint) -> uint { + *v + *w +} + +fn implicit() { + let mut a = ~1; + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets moved when evaluating the second + // argument! + add( + a, + a); //~ ERROR cannot move +} + +fn explicit() { + let mut a = ~1; + add( + &*a, + a); //~ ERROR cannot move +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs index 005908f86d87d..1051c5829ec38 100644 --- a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs +++ b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs @@ -22,32 +22,37 @@ fn make_foo() -> ~Foo { fail!() } fn borrow_same_field_twice_mut_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_mut_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; + let bar1 = &foo.bar1; let _bar2 = &foo.bar1; + *bar1; } -fn borrow_both_mut() { +fn borrow_both_fields_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _bar2 = &mut foo.bar2; + *bar1; } fn borrow_both_mut_pattern() { @@ -59,66 +64,77 @@ fn borrow_both_mut_pattern() { fn borrow_var_and_pattern() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; match *foo { Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + //~^ ERROR cannot borrow } + *bar1; } fn borrow_mut_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &*foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; + let bar1 = &foo.bar1.int1; let _foo1 = &foo.bar1; let _foo2 = &*foo; + *bar1; } fn borrow_mut_and_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _foo1 = &foo.bar2; + *bar1; } fn borrow_mut_from_imm() { let foo = make_foo(); - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_long_path_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar2.int2; + let bar1 = &mut foo.bar1.int1; + let foo1 = &mut foo.bar2.int2; + *bar1; + *foo1; } fn main() {} diff --git a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs index 035e293bc36b6..cdcf50c906e36 100644 --- a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs +++ b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs @@ -22,32 +22,37 @@ fn make_foo() -> Foo { fail!() } fn borrow_same_field_twice_mut_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_mut_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; + let bar1 = &foo.bar1; let _bar2 = &foo.bar1; + *bar1; } fn borrow_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _bar2 = &mut foo.bar2; + *bar1; } fn borrow_both_mut_pattern() { @@ -59,66 +64,76 @@ fn borrow_both_mut_pattern() { fn borrow_var_and_pattern() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; match foo { - Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + Foo { bar1: ref mut _bar1, bar2: _ } => {} // + //~^ ERROR cannot borrow } + *bar1; } fn borrow_mut_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &foo; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo2 = &mut foo; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; + let bar1 = &foo.bar1.int1; let _foo1 = &foo.bar1; let _foo2 = &foo; + *bar1; } fn borrow_mut_and_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _foo1 = &foo.bar2; + *bar1; } fn borrow_mut_from_imm() { let foo = make_foo(); - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_long_path_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; + let bar1 = &mut foo.bar1.int1; let _foo1 = &mut foo.bar2.int2; + *bar1; } fn main() {} diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs index 4a6a90ae5167f..1e5c4c5cc410c 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs @@ -28,5 +28,6 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> { } fn main() { - let _x = defer(~["Goodbye", "world!"]); //~ ERROR illegal borrow + let x = defer(~["Goodbye", "world!"]); //~ ERROR borrowed value does not live long enough + x.x[0]; } diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index bda659aa7b97e..887cb59930ebc 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -15,7 +15,7 @@ use core::hashmap::HashMap; fn main() { let mut buggy_map :HashMap = HashMap::new::(); - buggy_map.insert(42, &*~1); //~ ERROR illegal borrow + buggy_map.insert(42, &*~1); //~ ERROR borrowed value does not live long enough // but it is ok if we use a temporary let tmp = ~2; diff --git a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs index 2c68429baec92..3abd19e5a1136 100644 --- a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs +++ b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs @@ -27,15 +27,16 @@ fn a(x: &mut Foo) { fn b(x: &Foo) { x.f(); x.g(); - x.h(); //~ ERROR illegal borrow + x.h(); //~ ERROR cannot borrow } fn c(x: &const Foo) { - x.f(); //~ ERROR illegal borrow unless pure + x.f(); //~ ERROR cannot borrow + //~^ ERROR unsafe borrow x.g(); - x.h(); //~ ERROR illegal borrow + x.h(); //~ ERROR cannot borrow + //~^ ERROR unsafe borrow } fn main() { } - diff --git a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs index 88db5f5434116..8af10231921aa 100644 --- a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs +++ b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs @@ -10,9 +10,9 @@ fn main() { let mut _a = 3; - let _b = &mut _a; //~ NOTE loan of mutable local variable granted here + let _b = &mut _a; { let _c = &*_b; - _a = 4; //~ ERROR assigning to mutable local variable prohibited + _a = 4; //~ ERROR cannot assign to `_a` } } diff --git a/src/test/compile-fail/borrowck-insert-during-each.rs b/src/test/compile-fail/borrowck-insert-during-each.rs index 17c0efe225e4d..109753b38e70b 100644 --- a/src/test/compile-fail/borrowck-insert-during-each.rs +++ b/src/test/compile-fail/borrowck-insert-during-each.rs @@ -23,8 +23,8 @@ pub impl Foo { } fn bar(f: &mut Foo) { - do f.foo |a| { //~ NOTE prior loan as mutable granted here - f.n.insert(*a); //~ ERROR conflicts with prior loan + do f.foo |a| { + f.n.insert(*a); //~ ERROR cannot borrow } } diff --git a/src/test/compile-fail/borrowck-issue-2657-1.rs b/src/test/compile-fail/borrowck-issue-2657-1.rs index ce183c1888f13..8bcd5f9a72e70 100644 --- a/src/test/compile-fail/borrowck-issue-2657-1.rs +++ b/src/test/compile-fail/borrowck-issue-2657-1.rs @@ -10,9 +10,9 @@ fn main() { let x = Some(~1); -match x { //~ NOTE loan of immutable local variable granted here +match x { Some(ref _y) => { - let _a = x; //~ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _a = x; //~ ERROR cannot move } _ => {} } diff --git a/src/test/compile-fail/borrowck-issue-2657-2.rs b/src/test/compile-fail/borrowck-issue-2657-2.rs index d2217778d4148..fac805c57ca09 100644 --- a/src/test/compile-fail/borrowck-issue-2657-2.rs +++ b/src/test/compile-fail/borrowck-issue-2657-2.rs @@ -12,7 +12,7 @@ fn main() { let x = Some(~1); match x { Some(ref y) => { - let _b = *y; //~ ERROR moving out of dereference of immutable & pointer + let _b = *y; //~ ERROR cannot move out } _ => {} } diff --git a/src/test/compile-fail/borrowck-lend-flow-if.rs b/src/test/compile-fail/borrowck-lend-flow-if.rs new file mode 100644 index 0000000000000..563f63b98be05 --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-if.rs @@ -0,0 +1,52 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + +fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) { fail!() } +fn produce() -> T { fail!(); } + +fn inc(v: &mut ~int) { + *v = ~(**v + 1); +} + +fn pre_freeze_cond() { + // In this instance, the freeze is conditional and starts before + // the mut borrow. + + let mut v = ~3; + let _w; + if cond() { + _w = &v; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn pre_freeze_else() { + // In this instance, the freeze and mut borrow are on separate sides + // of the if. + + let mut v = ~3; + let _w; + if cond() { + _w = &v; + } else { + borrow_mut(v); + } +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck-lend-flow-loop.rs new file mode 100644 index 0000000000000..f7a72d6e6108c --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-loop.rs @@ -0,0 +1,164 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + +fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) -> bool { fail!() } +fn produce() -> T { fail!(); } + +fn inc(v: &mut ~int) { + *v = ~(**v + 1); +} + +fn loop_overarching_alias_mut() { + // In this instance, the borrow encompasses the entire loop. + + let mut v = ~3; + let mut x = &mut v; + **x += 1; + loop { + borrow(v); //~ ERROR cannot borrow + } +} + +fn block_overarching_alias_mut() { + // In this instance, the borrow encompasses the entire closure call. + + let mut v = ~3; + let mut x = &mut v; + for 3.times { + borrow(v); //~ ERROR cannot borrow + } + *x = ~5; +} + +fn loop_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + loop { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn while_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + while cond() { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn for_loop_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + for for_func { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn loop_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + loop { + borrow_mut(v); + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn while_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + while cond() { + borrow_mut(v); + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn for_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + for for_func { + // here we cannot be sure that `for_func` respects the break below + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn while_aliased_mut_cond(cond: bool, cond2: bool) { + let mut v = ~3, w = ~4; + let mut x = &mut w; + while cond { + **x += 1; + borrow(v); //~ ERROR cannot borrow + if cond2 { + x = &mut v; //~ ERROR cannot borrow + } + } +} + +fn loop_break_pops_scopes<'r>(_v: &'r mut [uint], f: &fn(&'r mut uint) -> bool) { + // Here we check that when you break out of an inner loop, the + // borrows that go out of scope as you exit the inner loop are + // removed from the bitset. + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut uint = produce(); + if !f(&mut *r) { + break; // ...so it is not live as exit the `while` loop here + } + } + } +} + +fn loop_loop_pops_scopes<'r>(_v: &'r mut [uint], f: &fn(&'r mut uint) -> bool) { + // Similar to `loop_break_pops_scopes` but for the `loop` keyword + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut uint = produce(); + if !f(&mut *r) { + loop; // ...so it is not live as exit (and re-enter) the `while` loop here + } + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow-match.rs b/src/test/compile-fail/borrowck-lend-flow-match.rs new file mode 100644 index 0000000000000..fcb31b7b7e039 --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-match.rs @@ -0,0 +1,60 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-pretty -- comments are unfaithfully preserved + +#[allow(unused_variable)]; +#[allow(dead_assignment)]; + +fn cond() -> bool { fail!() } +fn link<'a>(v: &'a uint, w: &mut &'a uint) -> bool { *w = v; true } + +fn separate_arms() { + // Here both arms perform assignments, but only is illegal. + + let mut x = None; + match x { + None => { + // It is ok to reassign x here, because there is in + // fact no outstanding loan of x! + x = Some(0); + } + Some(ref _i) => { + x = Some(1); //~ ERROR cannot assign + } + } + copy x; // just to prevent liveness warnings +} + +fn guard() { + // Here the guard performs a borrow. This borrow "infects" all + // subsequent arms (but not the prior ones). + + let mut a = ~3; + let mut b = ~4; + let mut w = &*a; + match 22 { + _ if cond() => { + b = ~5; + } + + _ if link(&*b, &mut w) => { + b = ~6; //~ ERROR cannot assign + } + + _ => { + b = ~7; //~ ERROR cannot assign + } + } + + b = ~8; //~ ERROR cannot assign +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index ed6446a6311b8..59cac0c5d953a 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -15,96 +15,37 @@ // cases are noted. fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) { fail!() } +fn produce() -> T { fail!(); } fn inc(v: &mut ~int) { *v = ~(**v + 1); } -fn post_aliased_const() { - let mut v = ~3; - borrow(v); - let _w = &const v; -} - -fn post_aliased_mut() { - // SPURIOUS--flow - let mut v = ~3; - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - let _w = &mut v; //~ NOTE prior loan as mutable granted here -} +fn pre_freeze() { + // In this instance, the freeze starts before the mut borrow. -fn post_aliased_scope(cond: bool) { let mut v = ~3; - borrow(v); - if cond { inc(&mut v); } + let _w = &v; + borrow_mut(v); //~ ERROR cannot borrow } -fn loop_overarching_alias_mut() { - let mut v = ~3; - let mut _x = &mut v; //~ NOTE prior loan as mutable granted here - loop { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - } -} +fn pre_const() { + // In this instance, the freeze starts before the mut borrow. -fn block_overarching_alias_mut() { let mut v = ~3; - let mut _x = &mut v; //~ NOTE prior loan as mutable granted here - for 3.times { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - } -} - -fn loop_aliased_mut() { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - loop { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } -} - -fn while_aliased_mut(cond: bool) { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - while cond { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } -} - -fn while_aliased_mut_cond(cond: bool, cond2: bool) { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - while cond { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - if cond2 { - _x = &mut v; //~ NOTE prior loan as mutable granted here - } - } -} - -fn loop_in_block() { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - for uint::range(0u, 10u) |_i| { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } + let _w = &const v; + borrow_mut(v); } -fn at_most_once_block() { - fn at_most_once(f: &fn()) { f() } +fn post_freeze() { + // In this instance, the const alias starts after the borrow. - // Here, the borrow check has no way of knowing that the block is - // executed at most once. - - let mut v = ~3, w = ~4; - let mut _x = &mut w; - do at_most_once { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } + let mut v = ~3; + borrow_mut(v); + let _w = &v; } fn main() {} diff --git a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs index 784fce1300f76..50dd815d49302 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs @@ -14,17 +14,17 @@ fn borrow(v: &int, f: &fn(x: &int)) { fn box_imm() { let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here + let _w = &v; do task::spawn { debug!("v=%d", *v); - //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan + //~^ ERROR cannot move `v` into closure } let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here + let _w = &v; task::spawn(|| { debug!("v=%d", *v); - //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan + //~^ ERROR cannot move }); } diff --git a/src/test/compile-fail/borrowck-loan-blocks-move.rs b/src/test/compile-fail/borrowck-loan-blocks-move.rs index 3af77d2df7f01..b9a79f4f3b1b1 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move.rs @@ -13,8 +13,8 @@ fn take(_v: ~int) { fn box_imm() { let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here - take(v); //~ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _w = &v; + take(v); //~ ERROR cannot move out of `v` because it is borrowed } fn main() { diff --git a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs index 14cb37d775c43..f8415a38573c4 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs @@ -14,8 +14,8 @@ fn borrow(v: &int, f: &fn(x: &int)) { fn box_imm() { let mut v = ~3; - do borrow(v) |w| { //~ NOTE loan of mutable local variable granted here - v = ~4; //~ ERROR assigning to captured outer mutable variable in a stack closure prohibited due to outstanding loan + do borrow(v) |w| { + v = ~4; //~ ERROR cannot assign to `v` because it is borrowed assert!(*v == 3); assert!(*w == 4); } diff --git a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs index 482d1b6b8b617..0361213af2226 100644 --- a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs @@ -8,18 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test #3387 - struct foo(~uint); impl Add for foo { - fn add(f: &foo) -> foo { - foo(~(**self + **(*f))) + fn add(&self, f: &foo) -> foo { + foo(~(***self + **(*f))) } } fn main() { let x = foo(~3); - let _y = x + x; - //~^ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _y = x + {x}; // the `{x}` forces a move to occur + //~^ ERROR cannot move out of `x` } diff --git a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs index a2ba5ad489167..6e8e3da143e4f 100644 --- a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs @@ -22,14 +22,14 @@ use core::either::{Either, Left, Right}; fn g() { let mut x: Either = Left(3); - io::println(f(&mut x, &x).to_str()); //~ ERROR conflicts with prior loan + io::println(f(&mut x, &x).to_str()); //~ ERROR cannot borrow } fn h() { let mut x: Either = Left(3); let y: &Either = &x; - let z: &mut Either = &mut x; //~ ERROR conflicts with prior loan + let z: &mut Either = &mut x; //~ ERROR cannot borrow *z = *y; - } + } fn main() {} diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index a4ad7e69b3336..061a6c553e4b0 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Point { +struct Point { x: int, y: int, } @@ -38,12 +38,13 @@ fn b() { // Here I create an outstanding loan and check that we get conflicts: - let q = &mut p; //~ NOTE prior loan as mutable granted here + let q = &mut p; - p + 3; // ok for pure fns - p.times(3); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + p + 3; //~ ERROR cannot borrow `p` + p.times(3); //~ ERROR cannot borrow `p` - q.x += 1; + *q + 3; // OK to use the new alias `q` + q.x += 1; // and OK to mutate it } fn c() { @@ -56,4 +57,3 @@ fn c() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-loan-rcvr.rs b/src/test/compile-fail/borrowck-loan-rcvr.rs index 4473574926a34..27a66557434b0 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr.rs @@ -13,7 +13,6 @@ struct point { x: int, y: int } trait methods { fn impurem(&self); fn blockm(&self, f: &fn()); - fn purem(&self); } impl methods for point { @@ -21,9 +20,6 @@ impl methods for point { } fn blockm(&self, f: &fn()) { f() } - - fn purem(&self) { - } } fn a() { @@ -31,12 +27,11 @@ fn a() { // Here: it's ok to call even though receiver is mutable, because we // can loan it out. - p.purem(); p.impurem(); // But in this case we do not honor the loan: - do p.blockm { //~ NOTE loan of mutable local variable granted here - p.x = 10; //~ ERROR assigning to mutable field prohibited due to outstanding loan + do p.blockm { + p.x = 10; //~ ERROR cannot assign } } @@ -45,22 +40,22 @@ fn b() { // Here I create an outstanding loan and check that we get conflicts: - let l = &mut p; //~ NOTE prior loan as mutable granted here - //~^ NOTE prior loan as mutable granted here - - p.purem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - p.impurem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + let l = &mut p; + p.impurem(); //~ ERROR cannot borrow l.x += 1; } fn c() { - // Loaning @mut as & is considered legal due to dynamic checks: + // Loaning @mut as & is considered legal due to dynamic checks... let q = @mut point {x: 3, y: 4}; - q.purem(); q.impurem(); + + // ...but we still detect errors statically when we can. + do q.blockm { + q.x = 10; //~ ERROR cannot assign + } } fn main() { } - diff --git a/src/test/compile-fail/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck-loan-vec-content.rs index d27d690437aff..6a8e64377aab2 100644 --- a/src/test/compile-fail/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck-loan-vec-content.rs @@ -24,8 +24,8 @@ fn has_mut_vec_and_does_not_try_to_change_it() { fn has_mut_vec_but_tries_to_change_it() { let mut v = ~[1, 2, 3]; - do takes_imm_elt(&v[0]) { //~ NOTE loan of mutable vec content granted here - v[1] = 4; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + do takes_imm_elt(&v[0]) { + v[1] = 4; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index 18b4ce0640c41..c199c8795756d 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -4,7 +4,7 @@ fn main() { let foo = ~3; let _pfoo = &foo; let _f: @fn() -> int = || *foo + 5; - //~^ ERROR by-move capture + //~^ ERROR cannot move `foo` let bar = ~3; let _g = || { diff --git a/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs b/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs index d0b0f51d0cf77..e4e449822768b 100644 --- a/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs +++ b/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs @@ -10,7 +10,7 @@ fn main() { let x: int = 3; - let y: &mut int = &mut x; //~ ERROR illegal borrow + let y: &mut int = &mut x; //~ ERROR cannot borrow *y = 5; debug!(*y); } diff --git a/src/test/compile-fail/borrowck-mut-boxed-vec.rs b/src/test/compile-fail/borrowck-mut-boxed-vec.rs index d4c0b5a1e9bf9..716f70b291398 100644 --- a/src/test/compile-fail/borrowck-mut-boxed-vec.rs +++ b/src/test/compile-fail/borrowck-mut-boxed-vec.rs @@ -10,8 +10,7 @@ fn main() { let v = @mut [ 1, 2, 3 ]; - for v.each |_x| { //~ ERROR illegal borrow - v[1] = 4; + for v.each |_x| { + v[1] = 4; //~ ERROR cannot assign } } - diff --git a/src/test/compile-fail/borrowck-mut-deref-comp.rs b/src/test/compile-fail/borrowck-mut-deref-comp.rs index 540793d4135f2..d1dc296197892 100644 --- a/src/test/compile-fail/borrowck-mut-deref-comp.rs +++ b/src/test/compile-fail/borrowck-mut-deref-comp.rs @@ -11,8 +11,8 @@ struct foo(~int); fn borrow(x: @mut foo) { - let _y = &***x; //~ ERROR illegal borrow unless pure - *x = foo(~4); //~ NOTE impure due to assigning to dereference of mutable @ pointer + let _y = &***x; + *x = foo(~4); //~ ERROR cannot assign } fn main() { diff --git a/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs b/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs index bc0340983ae34..ec17976c5065c 100644 --- a/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs +++ b/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs @@ -14,5 +14,5 @@ fn write(v: &mut [int]) { fn main() { let v = ~[1, 2, 3]; - write(v); //~ ERROR illegal borrow + write(v); //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs b/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs index 4af3bc17240ce..ed270de51e2ed 100644 --- a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs +++ b/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs @@ -19,9 +19,9 @@ enum cycle { fn main() { let mut x = ~node(node_ {a: ~empty}); // Create a cycle! - match *x { //~ NOTE loan of mutable local variable granted here + match *x { node(ref mut y) => { - y.a = x; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan + y.a = x; //~ ERROR cannot move out of } empty => {} }; diff --git a/src/test/compile-fail/borrowck-pat-by-value-binding.rs b/src/test/compile-fail/borrowck-pat-by-value-binding.rs index d8c8841d391a2..d60ed3d0e372b 100644 --- a/src/test/compile-fail/borrowck-pat-by-value-binding.rs +++ b/src/test/compile-fail/borrowck-pat-by-value-binding.rs @@ -12,23 +12,24 @@ fn process(_t: T) {} fn match_const_opt_by_mut_ref(v: &const Option) { match *v { - Some(ref mut i) => process(i), //~ ERROR illegal borrow + Some(ref mut i) => process(i), //~ ERROR cannot borrow + //~^ ERROR unsafe borrow of aliasable, const value None => () } } fn match_const_opt_by_const_ref(v: &const Option) { match *v { - Some(ref const i) => process(i), //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to + Some(ref const i) => process(i), + //~^ ERROR unsafe borrow of aliasable, const value None => () } } fn match_const_opt_by_imm_ref(v: &const Option) { match *v { - Some(ref i) => process(i), //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to + Some(ref i) => process(i), //~ ERROR cannot borrow + //~^ ERROR unsafe borrow of aliasable, const value None => () } } diff --git a/src/test/compile-fail/borrowck-pat-enum.rs b/src/test/compile-fail/borrowck-pat-enum.rs index 4aa1ecc0ce3fe..f1cca89b227d6 100644 --- a/src/test/compile-fail/borrowck-pat-enum.rs +++ b/src/test/compile-fail/borrowck-pat-enum.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn match_ref(&&v: Option) -> int { +fn match_ref(v: Option) -> int { match v { Some(ref i) => { *i @@ -17,7 +17,7 @@ fn match_ref(&&v: Option) -> int { } } -fn match_ref_unused(&&v: Option) { +fn match_ref_unused(v: Option) { match v { Some(_) => {} None => {} @@ -26,7 +26,8 @@ fn match_ref_unused(&&v: Option) { fn match_const_reg(v: &const Option) -> int { match *v { - Some(ref i) => {*i} // OK because this is pure + Some(ref i) => {*i} //~ ERROR cannot borrow + //~^ ERROR unsafe borrow None => {0} } } @@ -43,8 +44,8 @@ fn match_const_reg_unused(v: &const Option) { fn match_const_reg_impure(v: &const Option) { match *v { - Some(ref i) => {impure(*i)} //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to access to impure function + Some(ref i) => {impure(*i)} //~ ERROR cannot borrow + //~^ ERROR unsafe borrow None => {} } } @@ -56,5 +57,12 @@ fn match_imm_reg(v: &Option) { } } +fn match_mut_reg(v: &mut Option) { + match *v { + Some(ref i) => {impure(*i)} // OK, frozen + None => {} + } +} + fn main() { } diff --git a/src/test/compile-fail/borrowck-pat-reassign-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-binding.rs index ca1fdc97c22f8..be2aee5d1b82c 100644 --- a/src/test/compile-fail/borrowck-pat-reassign-binding.rs +++ b/src/test/compile-fail/borrowck-pat-reassign-binding.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-pretty -- comments are infaithfully preserved +// xfail-pretty -- comments are unfaithfully preserved fn main() { let mut x: Option = None; - match x { //~ NOTE loan of mutable local variable granted here - None => {} + match x { + None => { + // Note: on this branch, no borrow has occurred. + x = Some(0); + } Some(ref i) => { - // Not ok: i is an outstanding ptr into x. - x = Some(*i+1); //~ ERROR assigning to mutable local variable prohibited due to outstanding loan + // But on this branch, `i` is an outstanding borrow + x = Some(*i+1); //~ ERROR cannot assign to `x` } } copy x; // just to prevent liveness warnings diff --git a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs deleted file mode 100644 index dd6eca951b8f3..0000000000000 --- a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs +++ /dev/null @@ -1,26 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-pretty -- comments are infaithfully preserved - -fn main() { - let mut x = None; - match x { //~ NOTE loan of mutable local variable granted here - None => { - // It is ok to reassign x here, because there is in - // fact no outstanding loan of x! - x = Some(0); - } - Some(ref _i) => { - x = Some(1); //~ ERROR assigning to mutable local variable prohibited due to outstanding loan - } - } - copy x; // just to prevent liveness warnings -} diff --git a/src/test/compile-fail/borrowck-reborrow-from-mut.rs b/src/test/compile-fail/borrowck-reborrow-from-mut.rs index 60f817dee0c54..b4bd64f213586 100644 --- a/src/test/compile-fail/borrowck-reborrow-from-mut.rs +++ b/src/test/compile-fail/borrowck-reborrow-from-mut.rs @@ -20,17 +20,17 @@ struct Bar { fn borrow_same_field_twice_mut_mut(foo: &mut Foo) { let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_mut_imm(foo: &mut Foo) { let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_imm_mut(foo: &mut Foo) { let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_imm_imm(foo: &mut Foo) { @@ -53,34 +53,34 @@ fn borrow_var_and_pattern(foo: &mut Foo) { let _bar1 = &mut foo.bar1; match *foo { Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + //~^ ERROR cannot borrow } } fn borrow_mut_and_base_imm(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &*foo; //~ ERROR conflicts with prior loan + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow } fn borrow_mut_and_base_mut(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_mut_and_base_mut2(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let _foo2 = &mut *foo; //~ ERROR cannot borrow } fn borrow_imm_and_base_mut(foo: &mut Foo) { let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_imm_and_base_mut2(foo: &mut Foo) { let _bar1 = &foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let _foo2 = &mut *foo; //~ ERROR cannot borrow } fn borrow_imm_and_base_imm(foo: &mut Foo) { @@ -95,7 +95,7 @@ fn borrow_mut_and_imm(foo: &mut Foo) { } fn borrow_mut_from_imm(foo: &Foo) { - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_long_path_both_mut(foo: &mut Foo) { diff --git a/src/test/compile-fail/borrowck-ref-into-rvalue.rs b/src/test/compile-fail/borrowck-ref-into-rvalue.rs index 37ee747069ccf..7026f06c2b7bb 100644 --- a/src/test/compile-fail/borrowck-ref-into-rvalue.rs +++ b/src/test/compile-fail/borrowck-ref-into-rvalue.rs @@ -10,12 +10,11 @@ fn main() { let msg; - match Some(~"Hello") { //~ ERROR illegal borrow - Some(ref m) => { + match Some(~"Hello") { + Some(ref m) => { //~ ERROR borrowed value does not live long enough msg = m; - }, + }, None => { fail!() } - } + } io::println(*msg); } - diff --git a/src/test/compile-fail/borrowck-ref-mut-of-imm.rs b/src/test/compile-fail/borrowck-ref-mut-of-imm.rs index aad86241e9a43..3a37116a1664d 100644 --- a/src/test/compile-fail/borrowck-ref-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck-ref-mut-of-imm.rs @@ -11,7 +11,7 @@ fn destructure(x: Option) -> int { match x { None => 0, - Some(ref mut v) => *v //~ ERROR illegal borrow + Some(ref mut v) => *v //~ ERROR cannot borrow } } diff --git a/src/test/compile-fail/borrowck-unary-move-2.rs b/src/test/compile-fail/borrowck-unary-move-2.rs index 520772f1ceea9..898830bbe55ba 100644 --- a/src/test/compile-fail/borrowck-unary-move-2.rs +++ b/src/test/compile-fail/borrowck-unary-move-2.rs @@ -28,5 +28,5 @@ struct wrapper(noncopyable); fn main() { let x1 = wrapper(noncopyable()); - let _x2 = *x1; //~ ERROR moving out of anonymous field + let _x2 = *x1; //~ ERROR cannot move out } diff --git a/src/test/compile-fail/borrowck-unary-move.rs b/src/test/compile-fail/borrowck-unary-move.rs index f95b365ee2ef9..cf7529865118a 100644 --- a/src/test/compile-fail/borrowck-unary-move.rs +++ b/src/test/compile-fail/borrowck-unary-move.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(+x: ~int) -> int { - let y = &*x; //~ NOTE loan of argument granted here - free(x); //~ ERROR moving out of argument prohibited due to outstanding loan +fn foo(x: ~int) -> int { + let y = &*x; + free(x); //~ ERROR cannot move out of `*x` because it is borrowed *y } -fn free(+_x: ~int) { +fn free(_x: ~int) { } fn main() { diff --git a/src/test/compile-fail/borrowck-uniq-via-box.rs b/src/test/compile-fail/borrowck-uniq-via-box.rs deleted file mode 100644 index e1c0e67ff8dcc..0000000000000 --- a/src/test/compile-fail/borrowck-uniq-via-box.rs +++ /dev/null @@ -1,55 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct Rec { - f: ~int, -} - -struct Outer { - f: Inner -} - -struct Inner { - g: Innermost -} - -struct Innermost { - h: ~int, -} - -fn borrow(_v: &int) {} - -fn box_mut(v: @mut ~int) { - borrow(*v); //~ ERROR illegal borrow unless pure -} - -fn box_mut_rec(v: @mut Rec) { - borrow(v.f); //~ ERROR illegal borrow unless pure -} - -fn box_mut_recs(v: @mut Outer) { - borrow(v.f.g.h); //~ ERROR illegal borrow unless pure -} - -fn box_imm(v: @~int) { - borrow(*v); // OK -} - -fn box_imm_rec(v: @Rec) { - borrow(v.f); // OK -} - -fn box_imm_recs(v: @Outer) { - borrow(v.f.g.h); // OK -} - -fn main() { -} - diff --git a/src/test/compile-fail/borrowck-uniq-via-lend.rs b/src/test/compile-fail/borrowck-uniq-via-lend.rs index ee96237a26c82..80ba1968bc751 100644 --- a/src/test/compile-fail/borrowck-uniq-via-lend.rs +++ b/src/test/compile-fail/borrowck-uniq-via-lend.rs @@ -43,8 +43,8 @@ fn aliased_const() { fn aliased_mut() { let mut v = ~3; - let _w = &mut v; //~ NOTE prior loan as mutable granted here - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + let _w = &mut v; + borrow(v); //~ ERROR cannot borrow `*v` } fn aliased_other() { @@ -56,8 +56,8 @@ fn aliased_other() { fn aliased_other_reassign() { let mut v = ~3, w = ~4; let mut _x = &mut w; - _x = &mut v; //~ NOTE prior loan as mutable granted here - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + _x = &mut v; + borrow(v); //~ ERROR cannot borrow `*v` } fn main() { diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/compile-fail/borrowck-uniq-via-ref.rs index 2cf363e13ee09..8bf627d991911 100644 --- a/src/test/compile-fail/borrowck-uniq-via-ref.rs +++ b/src/test/compile-fail/borrowck-uniq-via-ref.rs @@ -25,6 +25,7 @@ struct Innermost { } fn borrow(_v: &int) {} +fn borrow_const(_v: &const int) {} fn box_mut(v: &mut ~int) { borrow(*v); // OK: &mut -> &imm @@ -51,15 +52,15 @@ fn box_imm_recs(v: &Outer) { } fn box_const(v: &const ~int) { - borrow(*v); //~ ERROR illegal borrow unless pure + borrow_const(*v); //~ ERROR unsafe borrow } fn box_const_rec(v: &const Rec) { - borrow(v.f); //~ ERROR illegal borrow unless pure + borrow_const(v.f); //~ ERROR unsafe borrow } fn box_const_recs(v: &const Outer) { - borrow(v.f.g.h); //~ ERROR illegal borrow unless pure + borrow_const(v.f.g.h); //~ ERROR unsafe borrow } fn main() { diff --git a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index c8a0dbedd5d95..0c21b64bb0fb0 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &[int] { let vec = [1, 2, 3, 4]; - let tail = match vec { //~ ERROR illegal borrow - [_, ..tail] => tail, + let tail = match vec { + [_, ..tail] => tail, //~ ERROR does not live long enough _ => fail!(~"a") }; tail @@ -9,8 +9,8 @@ fn a() -> &[int] { fn b() -> &[int] { let vec = [1, 2, 3, 4]; - let init = match vec { //~ ERROR illegal borrow - [..init, _] => init, + let init = match vec { + [..init, _] => init, //~ ERROR does not live long enough _ => fail!(~"b") }; init @@ -18,8 +18,8 @@ fn b() -> &[int] { fn c() -> &[int] { let vec = [1, 2, 3, 4]; - let slice = match vec { //~ ERROR illegal borrow - [_, ..slice, _] => slice, + let slice = match vec { + [_, ..slice, _] => slice, //~ ERROR does not live long enough _ => fail!(~"c") }; slice diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs index 27902100373a9..635ce77bb8a5b 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -2,11 +2,10 @@ fn a() { let mut v = ~[1, 2, 3]; match v { [_a, ..tail] => { - v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan + v.push(tail[0] + tail[1]); //~ ERROR cannot borrow } _ => {} }; } fn main() {} - diff --git a/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs index 16b48aedb0c7f..2898e312930fe 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs @@ -1,8 +1,9 @@ fn main() { let mut a = [1, 2, 3, 4]; - let _ = match a { + let t = match a { [1, 2, ..tail] => tail, _ => core::util::unreachable() }; - a[0] = 0; //~ ERROR: assigning to mutable vec content prohibited due to outstanding loan + a[0] = 0; //~ ERROR cannot assign to `a[]` because it is borrowed + t[0]; } diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 05ff85d612c82..941455d086c8c 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -2,7 +2,7 @@ fn a() { let mut vec = [~1, ~2, ~3]; match vec { [~ref _a] => { - vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed } _ => fail!(~"foo") } @@ -12,10 +12,9 @@ fn b() { let mut vec = [~1, ~2, ~3]; match vec { [.._b] => { - vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed } } } fn main() {} - diff --git a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index 714a80def9358..dbdd8f0809a6e 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &int { let vec = [1, 2, 3, 4]; - let tail = match vec { //~ ERROR illegal borrow - [_a, ..tail] => &tail[0], + let tail = match vec { + [_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough _ => fail!(~"foo") }; tail diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs index e47ad721b0d7b..451f023f5fcf7 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs @@ -1,6 +1,5 @@ fn main() { let mut b = ~3; - let _x = &mut *b; //~ NOTE prior loan as mutable granted here - let _y = &mut *b; //~ ERROR loan of dereference of mutable ~ pointer as mutable conflicts with prior loan + let _x = &mut *b; + let _y = &mut *b; //~ ERROR cannot borrow } - diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs index 015f368ecb068..c455de888a330 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs @@ -1,8 +1,7 @@ fn main() { let mut a = ~3; - let mut b = &mut a; //~ NOTE loan of mutable local variable granted here + let mut b = &mut a; let _c = &mut *b; - let mut d = /*move*/ a; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan + let mut d = /*move*/ a; //~ ERROR cannot move out *d += 1; } - diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs index 36d32fddda150..e18808dfe538a 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs @@ -1,7 +1,6 @@ fn main() { let mut b = ~3; - let _x = &mut *b; //~ NOTE loan of mutable local variable granted here - let mut y = /*move*/ b; //~ ERROR moving out of mutable local variable prohibited + let _x = &mut *b; + let mut y = /*move*/ b; //~ ERROR cannot move out *y += 1; } - diff --git a/src/test/compile-fail/borrowck-wg-move-base-2.rs b/src/test/compile-fail/borrowck-wg-move-base-2.rs index ba85616e63f28..4050b4c5971a0 100644 --- a/src/test/compile-fail/borrowck-wg-move-base-2.rs +++ b/src/test/compile-fail/borrowck-wg-move-base-2.rs @@ -2,10 +2,8 @@ fn foo(x: &mut int) { let mut a = 3; let mut _y = &mut *x; let _z = &mut *_y; - _y = &mut a; //~ ERROR assigning to mutable local variable prohibited + _y = &mut a; //~ ERROR cannot assign } fn main() { } - - diff --git a/src/test/compile-fail/by-move-pattern-binding.rs b/src/test/compile-fail/by-move-pattern-binding.rs index 95091f15ce0e5..1efed154286ec 100644 --- a/src/test/compile-fail/by-move-pattern-binding.rs +++ b/src/test/compile-fail/by-move-pattern-binding.rs @@ -20,4 +20,3 @@ fn main() { &Bar(ref identifier) => io::println(*identifier) }; } - diff --git a/src/test/run-pass/tstate-loop-break.rs b/src/test/compile-fail/core-tls-store-pointer.rs similarity index 68% rename from src/test/run-pass/tstate-loop-break.rs rename to src/test/compile-fail/core-tls-store-pointer.rs index 4228f72b7caa4..fcb25069de6dd 100644 --- a/src/test/run-pass/tstate-loop-break.rs +++ b/src/test/compile-fail/core-tls-store-pointer.rs @@ -8,20 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// Testing that we can't store a borrowed pointer it task-local storage -fn is_even(i: int) -> bool { (i%2) == 0 } -fn even(i: int) : is_even(i) -> int { i } +use core::local_data::*; -fn test() { - let v = 4; - loop { - check is_even(v); - break; - } - even(v); -} +fn key(_x: @&int) { } -pub fn main() { - test(); +fn main() { + unsafe { + local_data_set(key, @&0); //~ ERROR does not fulfill `'static` + } } diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 182a41c1b1735..5fa796db88444 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -10,9 +10,12 @@ // except according to those terms. -// error-pattern: dead - -fn f(caller: str) { debug!(caller); } - -fn main() { return f("main"); debug!("Paul is dead"); } +fn f(caller: &str) { + debug!(caller); + let x: uint = 0u32; // induce type error //~ ERROR mismatched types +} +fn main() { + return f("main"); + debug!("Paul is dead"); //~ WARNING unreachable +} diff --git a/src/test/compile-fail/die-not-static.rs b/src/test/compile-fail/die-not-static.rs index b30e3942e6330..d33c591d8c87f 100644 --- a/src/test/compile-fail/die-not-static.rs +++ b/src/test/compile-fail/die-not-static.rs @@ -1,7 +1,6 @@ -// error-pattern:illegal borrow: borrowed value does not live long enough - fn main() { let v = ~"test"; let sslice = str::slice(v, 0, v.len()); + //~^ ERROR borrowed value does not live long enough fail!(sslice); } diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs similarity index 85% rename from src/test/compile-fail/disallowed-deconstructing-destructing-struct.rs rename to src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs index 9019d338d0903..c363f172d2f46 100644 --- a/src/test/compile-fail/disallowed-deconstructing-destructing-struct.rs +++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs @@ -1,3 +1,4 @@ +// xfail-test #3024 // 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. @@ -18,8 +19,8 @@ impl Drop for X { } } -fn unwrap(+x: X) -> ~str { - let X { x: y } = x; //~ ERROR deconstructing struct not allowed in pattern +fn unwrap(x: X) -> ~str { + let X { x: y } = x; //~ ERROR cannot bind by-move within struct y } diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs new file mode 100644 index 0000000000000..40305ba8b95c9 --- /dev/null +++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + x: ~str, +} + +impl Drop for X { + fn finalize(&self) { + error!("value: %s", self.x); + } +} + +fn main() { + let x = X { x: ~"hello" }; + + match x { + X { x: y } => error!("contents: %s", y) + //~^ ERROR cannot bind by-move within struct + } +} diff --git a/src/test/compile-fail/does-nothing.rs b/src/test/compile-fail/does-nothing.rs index a360d6579574f..1dacbe9a1994c 100644 --- a/src/test/compile-fail/does-nothing.rs +++ b/src/test/compile-fail/does-nothing.rs @@ -1,3 +1,2 @@ -// error-pattern: unresolved name: `this_does_nothing_what_the`. +// error-pattern: unresolved name `this_does_nothing_what_the`. fn main() { debug!("doing"); this_does_nothing_what_the; debug!("boing"); } - diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index 4e5b64c8f3db4..b2f87686ac664 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -19,5 +19,3 @@ impl Drop for Foo { //~ ERROR the Drop trait may only be implemented fn main() { } - - diff --git a/src/test/compile-fail/elided-test.rs b/src/test/compile-fail/elided-test.rs index eaae721e0e555..b62214b12f9a0 100644 --- a/src/test/compile-fail/elided-test.rs +++ b/src/test/compile-fail/elided-test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: entry function not found +// error-pattern: main function not found // Since we're not compiling a test runner this function should be elided // and the build will fail because main doesn't exist diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 0123341957903..f92dad961d134 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -1,5 +1,5 @@ enum test { - quot_zero = 1/0, //~ERROR expected constant: attempted quotient with a divisor of zero + div_zero = 1/0, //~ERROR expected constant: attempted to divide by zero rem_zero = 1%0 //~ERROR expected constant: attempted remainder with a divisor of zero } diff --git a/src/test/compile-fail/explicit-call-to-dtor.rs b/src/test/compile-fail/explicit-call-to-dtor.rs index 71674186b6125..24fedaaabe3a0 100644 --- a/src/test/compile-fail/explicit-call-to-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-dtor.rs @@ -22,4 +22,3 @@ fn main() { let x = Foo { x: 3 }; x.finalize(); //~ ERROR explicit call to destructor } - diff --git a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs index 26b13566f7a0e..fd49889a3f796 100644 --- a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs @@ -31,5 +31,3 @@ impl Bar for Foo { fn main() { let x = Foo { x: 3 }; } - - diff --git a/src/test/compile-fail/float-literal-inference-restrictions.rs b/src/test/compile-fail/float-literal-inference-restrictions.rs index 80aefbbf48f81..48dbdd86b11f9 100644 --- a/src/test/compile-fail/float-literal-inference-restrictions.rs +++ b/src/test/compile-fail/float-literal-inference-restrictions.rs @@ -12,4 +12,3 @@ fn main() { let x: f32 = 1; //~ ERROR mismatched types let y: f32 = 1f; //~ ERROR mismatched types } - diff --git a/src/test/compile-fail/fn-variance-3.rs b/src/test/compile-fail/fn-variance-3.rs index 5df2007721def..4d145d3f9ea3a 100644 --- a/src/test/compile-fail/fn-variance-3.rs +++ b/src/test/compile-fail/fn-variance-3.rs @@ -31,5 +31,5 @@ fn main() { // mutability check will fail, because the // type of r has been inferred to be // fn(@const int) -> @const int - *r(@mut 3) = 4; //~ ERROR assigning to dereference of const @ pointer + *r(@mut 3) = 4; //~ ERROR cannot assign to const dereference of @ pointer } diff --git a/src/test/compile-fail/for-loop-decl.rs b/src/test/compile-fail/for-loop-decl.rs deleted file mode 100644 index de28d72677728..0000000000000 --- a/src/test/compile-fail/for-loop-decl.rs +++ /dev/null @@ -1,35 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: mismatched types -extern mod std; -use std::bitv; -use core::hashmap::HashMap; - -struct FnInfo { - vars: HashMap -} - -struct VarInfo { - a: uint, - b: uint, -} - -fn bitv_to_str(enclosing: FnInfo, v: ~bitv::Bitv) -> str { - let s = ""; - - // error is that the value type in the hash map is var_info, not a box - for enclosing.vars.each_value |val| { - if *v.get(val) { s += "foo"; } - } - return s; -} - -fn main() { debug!("OK"); } diff --git a/src/test/compile-fail/foreign-unsafe-fn-called.rs b/src/test/compile-fail/foreign-unsafe-fn-called.rs index 9122abab71321..ed8b8088ee41a 100644 --- a/src/test/compile-fail/foreign-unsafe-fn-called.rs +++ b/src/test/compile-fail/foreign-unsafe-fn-called.rs @@ -21,4 +21,3 @@ fn main() { test::free(); //~^ ERROR access to unsafe function requires unsafe function or block } - diff --git a/src/test/compile-fail/foreign-unsafe-fn.rs b/src/test/compile-fail/foreign-unsafe-fn.rs index 32fafe296466c..3633267d02c40 100644 --- a/src/test/compile-fail/foreign-unsafe-fn.rs +++ b/src/test/compile-fail/foreign-unsafe-fn.rs @@ -21,5 +21,3 @@ fn main() { let x = test::free; //~^ ERROR access to unsafe function requires unsafe function or block } - - diff --git a/src/test/run-pass/too-much-recursion.rs b/src/test/compile-fail/forget-init-unsafe.rs similarity index 54% rename from src/test/run-pass/too-much-recursion.rs rename to src/test/compile-fail/forget-init-unsafe.rs index adccc786926dc..2361b5ad6a9cf 100644 --- a/src/test/run-pass/too-much-recursion.rs +++ b/src/test/compile-fail/forget-init-unsafe.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,15 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-win32 -// error-pattern:ran out of stack - -// Test that the task fails after hitting the recursion limit, but -// that it doesn't bring down the whole proc +use core::unstable::intrinsics::{init, forget}; +// Test that the `forget` and `init` intrinsics are really unsafe pub fn main() { - do task::spawn_unlinked { - fn f() { f() }; - f(); - }; -} + let stuff = init::(); //~ ERROR access to unsafe function requires unsafe + forget(stuff); //~ ERROR access to unsafe function requires unsafe +} \ No newline at end of file diff --git a/src/test/compile-fail/immut-function-arguments.rs b/src/test/compile-fail/immut-function-arguments.rs index 2084729372d1d..66b5bd172cace 100644 --- a/src/test/compile-fail/immut-function-arguments.rs +++ b/src/test/compile-fail/immut-function-arguments.rs @@ -9,11 +9,11 @@ // except according to those terms. fn f(y: ~int) { - *y = 5; //~ ERROR assigning to dereference of immutable ~ pointer + *y = 5; //~ ERROR cannot assign } fn g() { - let _frob: &fn(~int) = |q| { *q = 2; }; //~ ERROR assigning to dereference of immutable ~ pointer + let _frob: &fn(~int) = |q| { *q = 2; }; //~ ERROR cannot assign } diff --git a/src/test/compile-fail/import2.rs b/src/test/compile-fail/import2.rs index 5ee4a01f2b9c5..7cb017091e0c6 100644 --- a/src/test/compile-fail/import2.rs +++ b/src/test/compile-fail/import2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use baz::zed::bar; //~ ERROR unresolved name +use baz::zed::bar; //~ ERROR unresolved import //~^ ERROR failed to resolve import mod baz {} diff --git a/src/test/compile-fail/index_message.rs b/src/test/compile-fail/index_message.rs index 3611dbb6866cb..26dd98757a8c2 100644 --- a/src/test/compile-fail/index_message.rs +++ b/src/test/compile-fail/index_message.rs @@ -10,5 +10,5 @@ fn main() { let z = (); - debug!(z[0]); //~ ERROR cannot index a value of type `()` + let _ = z[0]; //~ ERROR cannot index a value of type `()` } diff --git a/src/test/compile-fail/issue-1448-2.rs b/src/test/compile-fail/issue-1448-2.rs index 17402e8973023..e329ed4d6710d 100644 --- a/src/test/compile-fail/issue-1448-2.rs +++ b/src/test/compile-fail/issue-1448-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regresion test for issue #1448 and #1386 +// Regression test for issue #1448 and #1386 fn main() { debug!("%u", 10i); //~ ERROR mismatched types diff --git a/src/test/compile-fail/issue-1451.rs b/src/test/compile-fail/issue-1451.rs index acc371076e704..a295e8eb7edb0 100644 --- a/src/test/compile-fail/issue-1451.rs +++ b/src/test/compile-fail/issue-1451.rs @@ -30,4 +30,3 @@ fn main() { fooT(T {f: x}); fooT(T {f: bar}); } - diff --git a/src/test/compile-fail/issue-1476.rs b/src/test/compile-fail/issue-1476.rs index 1d58a4229d3eb..f223cd428ec13 100644 --- a/src/test/compile-fail/issue-1476.rs +++ b/src/test/compile-fail/issue-1476.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - error!(x); //~ ERROR unresolved name: `x`. + error!(x); //~ ERROR unresolved name `x`. } diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index a0d2536d85f0e..71b319a27d073 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -10,7 +10,7 @@ // Testing that we don't fail abnormally after hitting the errors -use unresolved::*; //~ ERROR unresolved name +use unresolved::*; //~ ERROR unresolved import. maybe a missing //~^ ERROR failed to resolve import fn main() { diff --git a/src/test/compile-fail/issue-1896-1.rs b/src/test/compile-fail/issue-1896-1.rs index fc5132d65104f..13adcd42da2b8 100644 --- a/src/test/compile-fail/issue-1896-1.rs +++ b/src/test/compile-fail/issue-1896-1.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that we require managed closures to be rooted when borrowed. + struct boxedFn<'self> { theFn: &'self fn() -> uint } fn createClosure (closedUint: uint) -> boxedFn { let theFn: @fn() -> uint = || closedUint; - boxedFn {theFn: theFn} //~ ERROR illegal borrow + boxedFn {theFn: theFn} //~ ERROR cannot root } fn main () { diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 2842d884c9918..cdc8d546dd848 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -23,5 +23,4 @@ impl vec_monad for ~[A] { fn main() { ["hi"].bind(|x| [x] ); //~^ ERROR type `[&'static str, .. 1]` does not implement any method in scope named `bind` - //~^^ ERROR Unconstrained region variable } diff --git a/src/test/compile-fail/issue-2151.rs b/src/test/compile-fail/issue-2151.rs index e2bbda7d65a99..bb6d47a47622b 100644 --- a/src/test/compile-fail/issue-2151.rs +++ b/src/test/compile-fail/issue-2151.rs @@ -10,7 +10,6 @@ fn main() { for vec::each(fail!()) |i| { - debug!(i * 2); - //~^ ERROR the type of this value must be known + let _ = i * 2; //~ ERROR the type of this value must be known }; } diff --git a/src/test/compile-fail/issue-2281-part1.rs b/src/test/compile-fail/issue-2281-part1.rs index 3951eaad6d197..60c80c1a3158b 100644 --- a/src/test/compile-fail/issue-2281-part1.rs +++ b/src/test/compile-fail/issue-2281-part1.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unresolved name: `foobar`. +// error-pattern: unresolved name `foobar`. fn main(args: ~[str]) { debug!(foobar); } diff --git a/src/test/compile-fail/issue-2590.rs b/src/test/compile-fail/issue-2590.rs index 7a99ab8a94f16..a0b967d59593a 100644 --- a/src/test/compile-fail/issue-2590.rs +++ b/src/test/compile-fail/issue-2590.rs @@ -18,7 +18,7 @@ trait parse { impl parse for parser { fn parse(&self) -> ~[int] { - self.tokens //~ ERROR moving out of immutable field + self.tokens //~ ERROR cannot move out of field } } diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/compile-fail/issue-2611-4.rs index cf644fc198caf..2385be5723e2a 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(_x: F) -> F { fail!() } //~ ERROR in method `b`, type parameter 0 has 2 bounds, but + fn b(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Const` } fn main() {} diff --git a/src/test/compile-fail/issue-2766-a.rs b/src/test/compile-fail/issue-2766-a.rs index 5e3eb9ef09bc6..5b55cc772fde8 100644 --- a/src/test/compile-fail/issue-2766-a.rs +++ b/src/test/compile-fail/issue-2766-a.rs @@ -15,10 +15,10 @@ pub mod stream { use core::pipes; pub impl Stream { - pub fn recv() -> extern fn(+v: Stream) -> ::stream::Stream { + pub fn recv() -> extern fn(v: Stream) -> ::stream::Stream { // resolve really should report just one error here. // Change the test case when it changes. - pub fn recv(+pipe: Stream) -> ::stream::Stream { //~ ERROR attempt to use a type argument out of scope + pub fn recv(pipe: Stream) -> ::stream::Stream { //~ ERROR attempt to use a type argument out of scope //~^ ERROR use of undeclared type name //~^^ ERROR attempt to use a type argument out of scope //~^^^ ERROR use of undeclared type name diff --git a/src/test/compile-fail/issue-2817-2.rs b/src/test/compile-fail/issue-2817-2.rs index 6084552f0ed6d..17b0d88a6a827 100644 --- a/src/test/compile-fail/issue-2817-2.rs +++ b/src/test/compile-fail/issue-2817-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn not_bool(f: &fn(int) -> ~str) {} +fn not_bool(f: &fn(int) -> ~str) -> bool {} fn main() { for uint::range(0, 100000) |_i| { //~ ERROR A for-loop body must return (), but diff --git a/src/test/compile-fail/issue-2817.rs b/src/test/compile-fail/issue-2817.rs index 8c28fcdc7fcd7..77585d15b6b3e 100644 --- a/src/test/compile-fail/issue-2817.rs +++ b/src/test/compile-fail/issue-2817.rs @@ -16,10 +16,10 @@ fn uuid_random() -> uint { fail!(); } fn main() { do uint::range(0, 100000) |_i| { //~ ERROR Do-block body must return bool, but - } + }; // should get a more general message if the callback // doesn't return nil do uint::range(0, 100000) |_i| { //~ ERROR mismatched types ~"str" - } + }; } diff --git a/src/test/compile-fail/issue-2937.rs b/src/test/compile-fail/issue-2937.rs index ba4e25ea952a9..56f0c5e3dd066 100644 --- a/src/test/compile-fail/issue-2937.rs +++ b/src/test/compile-fail/issue-2937.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:failed to resolve imports -use x = m::f; +use x = m::f; //~ ERROR failed to resolve import mod m { } diff --git a/src/test/compile-fail/issue-2951.rs b/src/test/compile-fail/issue-2951.rs index 3874d9b13f5ca..e57d4f0917579 100644 --- a/src/test/compile-fail/issue-2951.rs +++ b/src/test/compile-fail/issue-2951.rs @@ -15,5 +15,4 @@ fn foo(x: T, y: U) { } fn main() { - } diff --git a/src/test/compile-fail/issue-2995.rs b/src/test/compile-fail/issue-2995.rs index 5c48416667fe1..3e771eef970f7 100644 --- a/src/test/compile-fail/issue-2995.rs +++ b/src/test/compile-fail/issue-2995.rs @@ -11,3 +11,5 @@ fn bad (p: *int) { let _q: &int = p as ∫ //~ ERROR non-scalar cast } + +fn main() { } \ No newline at end of file diff --git a/src/test/compile-fail/issue-3021-b.rs b/src/test/compile-fail/issue-3021-b.rs index e6d16042445e8..3769154c9d948 100644 --- a/src/test/compile-fail/issue-3021-b.rs +++ b/src/test/compile-fail/issue-3021-b.rs @@ -19,7 +19,7 @@ fn siphash(k0 : u64) { pub impl siphash { fn reset(&mut self) { self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture - //~^ ERROR unresolved name: `k0`. + //~^ ERROR unresolved name `k0`. } } } diff --git a/src/test/compile-fail/issue-3021-d.rs b/src/test/compile-fail/issue-3021-d.rs index 2daf3e7a210aa..55c8e8aa51dd8 100644 --- a/src/test/compile-fail/issue-3021-d.rs +++ b/src/test/compile-fail/issue-3021-d.rs @@ -31,9 +31,9 @@ fn siphash(k0 : u64, k1 : u64) -> siphash { impl siphash for SipState { fn reset(&self) { self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture - //~^ ERROR unresolved name: `k0`. + //~^ ERROR unresolved name `k0`. self.v1 = k1 ^ 0x646f72616e646f6d; //~ ERROR attempted dynamic environment-capture - //~^ ERROR unresolved name: `k1`. + //~^ ERROR unresolved name `k1`. } fn result(&self) -> u64 { return mk_result(self); } } diff --git a/src/test/compile-fail/issue-3021.rs b/src/test/compile-fail/issue-3021.rs index 343683d79c105..f2cf2d19a864e 100644 --- a/src/test/compile-fail/issue-3021.rs +++ b/src/test/compile-fail/issue-3021.rs @@ -22,7 +22,7 @@ fn siphash(k0 : u64) -> SipHash { impl SipHash for SipState { fn reset(&self) { self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture - //~^ ERROR unresolved name: `k0`. + //~^ ERROR unresolved name `k0`. } } fail!(); diff --git a/src/test/compile-fail/issue-3038.rs b/src/test/compile-fail/issue-3038.rs index 4ed21bc30e1ce..1cdb226e39e5d 100644 --- a/src/test/compile-fail/issue-3038.rs +++ b/src/test/compile-fail/issue-3038.rs @@ -20,16 +20,16 @@ fn main() let _z = match g(1, 2) { g(x, x) => { debug!(x + x); } - //~^ ERROR Identifier x is bound more than once in the same pattern + //~^ ERROR Identifier `x` is bound more than once in the same pattern }; let _z = match i(l(1, 2), m(3, 4)) { - i(l(x, _), m(_, x)) //~ ERROR Identifier x is bound more than once in the same pattern + i(l(x, _), m(_, x)) //~ ERROR Identifier `x` is bound more than once in the same pattern => { error!(x + x); } }; let _z = match (1, 2) { - (x, x) => { x } //~ ERROR Identifier x is bound more than once in the same pattern + (x, x) => { x } //~ ERROR Identifier `x` is bound more than once in the same pattern }; } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index fcd5b1deee552..06fb18d7e4777 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -11,10 +11,8 @@ fn main() { let needlesArr: ~[char] = ~['a', 'f']; do vec::foldr(needlesArr) |x, y| { - //~^ ERROR Unconstrained region variable #2 } //~^ ERROR 2 parameters were supplied (including the closure passed by the `do` keyword) // // the first error is, um, non-ideal. } - diff --git a/src/test/compile-fail/issue-3096-2.rs b/src/test/compile-fail/issue-3096-2.rs index da13d450273ba..eb58cf3e13b36 100644 --- a/src/test/compile-fail/issue-3096-2.rs +++ b/src/test/compile-fail/issue-3096-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum bottom { } +enum bottom { } fn main() { let x = ptr::to_unsafe_ptr(&()) as *bottom; diff --git a/src/test/compile-fail/issue-3099-a.rs b/src/test/compile-fail/issue-3099-a.rs index b663087aa8975..1b11fcac8a385 100644 --- a/src/test/compile-fail/issue-3099-a.rs +++ b/src/test/compile-fail/issue-3099-a.rs @@ -10,6 +10,6 @@ enum a { b, c } -enum a { d, e } //~ ERROR duplicate definition of type a +enum a { d, e } //~ ERROR duplicate definition of type `a` fn main() {} diff --git a/src/test/compile-fail/issue-3099-b.rs b/src/test/compile-fail/issue-3099-b.rs index 1acfb753a4f03..3d22a59d6bd40 100644 --- a/src/test/compile-fail/issue-3099-b.rs +++ b/src/test/compile-fail/issue-3099-b.rs @@ -10,6 +10,6 @@ pub mod a {} -pub mod a {} //~ ERROR duplicate definition of type a +pub mod a {} //~ ERROR duplicate definition of type `a` fn main() {} diff --git a/src/test/compile-fail/issue-3099.rs b/src/test/compile-fail/issue-3099.rs index 7cb8a0cfbadec..abc76b9da0fd7 100644 --- a/src/test/compile-fail/issue-3099.rs +++ b/src/test/compile-fail/issue-3099.rs @@ -12,7 +12,7 @@ fn a(x: ~str) -> ~str { fmt!("First function with %s", x) } -fn a(x: ~str, y: ~str) -> ~str { //~ ERROR duplicate definition of value a +fn a(x: ~str, y: ~str) -> ~str { //~ ERROR duplicate definition of value `a` fmt!("Second function with %s and %s", x, y) } diff --git a/src/test/compile-fail/issue-3296.rs b/src/test/compile-fail/issue-3296.rs index 00425825e3ff2..062ee8fd01e46 100644 --- a/src/test/compile-fail/issue-3296.rs +++ b/src/test/compile-fail/issue-3296.rs @@ -18,7 +18,7 @@ struct Foo { a: () } -fn deserialize_foo<__D: std::serialization::deserializer>(&&__d: __D) { +fn deserialize_foo<__D: std::serialization::deserializer>(__d: __D) { } fn main() { let des = Deserializer(); let foo = deserialize_foo(des); } diff --git a/src/test/compile-fail/issue-3651-2.rs b/src/test/compile-fail/issue-3651-2.rs index 2431313df631c..98a02b6b74691 100644 --- a/src/test/compile-fail/issue-3651-2.rs +++ b/src/test/compile-fail/issue-3651-2.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - do 5.times {} //~ ERROR Do-block body must return bool, but returns () here. Perhaps + do 5.times {}; //~ ERROR Do-block body must return bool, but returns () here. Perhaps } diff --git a/src/test/compile-fail/issue-3651.rs b/src/test/compile-fail/issue-3651.rs index 38e9348155ac3..8d704859fe574 100644 --- a/src/test/compile-fail/issue-3651.rs +++ b/src/test/compile-fail/issue-3651.rs @@ -10,4 +10,5 @@ fn main() { for task::spawn { return true; } //~ ERROR A `for` loop iterator should expect a closure that + //~^ ERROR expected `for` closure to return `bool` } diff --git a/src/test/compile-fail/issue-3707.rs b/src/test/compile-fail/issue-3707.rs index 2c8f94c4695b0..5e8230686d506 100644 --- a/src/test/compile-fail/issue-3707.rs +++ b/src/test/compile-fail/issue-3707.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test struct Obj { member: uint } @@ -17,8 +16,8 @@ pub impl Obj { fn boom() -> bool { return 1+1 == 2 } - fn chirp() { - self.boom(); //~ ERROR wat + fn chirp(&self) { + self.boom(); //~ ERROR `&Obj` does not implement any method in scope named `boom` } } diff --git a/src/test/compile-fail/issue-3991.rs b/src/test/compile-fail/issue-3991.rs index d1c9057b8807b..d3016f893b467 100644 --- a/src/test/compile-fail/issue-3991.rs +++ b/src/test/compile-fail/issue-3991.rs @@ -12,11 +12,11 @@ struct HasNested { mut nest: ~[~[int]], } - + impl HasNested { fn method_push_local(&self) { self.nest[0].push(0); } } - + fn main() {} diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs index b6a32f5febae4..a1a77092b12a5 100644 --- a/src/test/compile-fail/issue-4265.rs +++ b/src/test/compile-fail/issue-4265.rs @@ -11,13 +11,13 @@ struct Foo { baz: uint } - + impl Foo { fn bar() { Foo { baz: 0 }.bar(); } - - fn bar() { //~ ERROR duplicate definition of value bar + + fn bar() { //~ ERROR duplicate definition of value `bar` } } diff --git a/src/test/compile-fail/issue-4366.rs b/src/test/compile-fail/issue-4366.rs index 7d97932d9af6b..98599b5d08081 100644 --- a/src/test/compile-fail/issue-4366.rs +++ b/src/test/compile-fail/issue-4366.rs @@ -25,7 +25,7 @@ mod a { } pub mod sub { use a::b::*; - fn sub() -> bar { foo(); 1 } //~ ERROR: unresolved name: `foo` + fn sub() -> bar { foo(); 1 } //~ ERROR: unresolved name `foo` //~^ ERROR: use of undeclared type name `bar` } } @@ -35,6 +35,5 @@ mod m1 { } fn main() { - foo(); //~ ERROR: unresolved name: `foo` + foo(); //~ ERROR: unresolved name `foo` } - diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index 4bb3a5119448e..3a0db4246be62 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regresion test for issue #4935 +// Regression test for issue #4935 fn foo(a: uint) {} fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index fc0c29e9a7987..700d8a61c3a39 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,4 +14,3 @@ static A: (int,int) = (4,2); fn main() { match 42 { A => () } //~ ERROR mismatched types: expected `` but found `(int,int)` (expected integral variable but found tuple) } - diff --git a/src/test/compile-fail/issue-5099.rs b/src/test/compile-fail/issue-5099.rs index 80720f9e863a3..c2e1fc615cca3 100644 --- a/src/test/compile-fail/issue-5099.rs +++ b/src/test/compile-fail/issue-5099.rs @@ -9,6 +9,6 @@ // except according to those terms. -trait B < A > { fn a() -> A { self.a} } //~ ERROR unresolved name +trait B < A > { fn a() -> A { this.a } } //~ ERROR unresolved name fn main() {} diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs new file mode 100644 index 0000000000000..8cc047230dc97 --- /dev/null +++ b/src/test/compile-fail/issue-5100.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum A { B, C } + +fn main() { + match (true, false) { + B => (), //~ ERROR expected `(bool,bool)` but found an enum or structure pattern + _ => () + } + + match (true, false) { + (true, false, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found tuple (expected a tuple with 2 elements but found one with 3 elements) + } + + match (true, false) { + @(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an @-box pattern + } + + match (true, false) { + ~(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found a ~-box pattern + } + + match (true, false) { + &(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an &-pointer pattern + } + + + let v = [('a', 'b') //~ ERROR expected function but found `(char,char)` + ('c', 'd'), + ('e', 'f')]; + + for v.each |&(x,y)| {} // should be OK + + // Make sure none of the errors above were fatal + let x: char = true; //~ ERROR expected `char` but found `bool` +} diff --git a/src/test/compile-fail/issue-511.rs b/src/test/compile-fail/issue-511.rs index 90c46e5d602c9..c872f89d88450 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/compile-fail/issue-511.rs @@ -17,5 +17,5 @@ fn f(o: &mut Option) { fn main() { f::(&mut option::None); - //~^ ERROR illegal borrow: creating mutable alias to static item + //~^ ERROR cannot borrow } diff --git a/src/test/compile-fail/issue-5358-1.rs b/src/test/compile-fail/issue-5358-1.rs new file mode 100644 index 0000000000000..0b6e2fb0ff5f2 --- /dev/null +++ b/src/test/compile-fail/issue-5358-1.rs @@ -0,0 +1,18 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S(Either); + +fn main() { + match S(Left(5)) { + Right(_) => {} //~ ERROR mismatched types: expected `S` but found `core::either::Either + _ => {} + } +} diff --git a/src/test/compile-fail/issue-5358.rs b/src/test/compile-fail/issue-5358.rs new file mode 100644 index 0000000000000..7d11a127f9ae8 --- /dev/null +++ b/src/test/compile-fail/issue-5358.rs @@ -0,0 +1,17 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S(Either); + +fn main() { + match *S(Left(5)) { + S(_) => {} //~ ERROR mismatched types: expected `core::either::Either` but found a structure pattern + } +} diff --git a/src/test/compile-fail/swap-no-lval.rs b/src/test/compile-fail/issue-5927.rs similarity index 70% rename from src/test/compile-fail/swap-no-lval.rs rename to src/test/compile-fail/issue-5927.rs index 4fe30792e4b31..a1b4ee7aa3445 100644 --- a/src/test/compile-fail/swap-no-lval.rs +++ b/src/test/compile-fail/issue-5927.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. + + +// error-pattern:unresolved enum variant + fn main() { - 5 <-> 3; - //~^ ERROR swapping to and from non-lvalue - //~^^ ERROR swapping to and from non-lvalue + let z = match 3 { + x() => x + }; + assert_eq!(z,3); } diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index e956f95b4229c..faad36a15d2fa 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -9,4 +9,3 @@ impl Drop for Foo { //~ ERROR cannot implement a destructor on a struct that is } fn main() { } - diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index 54ee8bcc70e37..6bb90bff228d4 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -29,4 +29,7 @@ fn main() { }; assert!(3 == *(y.get())); //~ ERROR dereference of reference outside its lifetime //~^ ERROR reference is not valid outside of its lifetime + //~^^ ERROR reference is not valid outside of its lifetime + //~^^^ ERROR reference is not valid outside of its lifetime + //~^^^^ ERROR cannot infer an appropriate lifetime } diff --git a/src/test/compile-fail/lambda-mutate-nested.rs b/src/test/compile-fail/lambda-mutate-nested.rs index 8b009b91af96c..bfd1e12f3a6e0 100644 --- a/src/test/compile-fail/lambda-mutate-nested.rs +++ b/src/test/compile-fail/lambda-mutate-nested.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to captured outer immutable variable in a stack closure // Make sure that nesting a block within a @fn doesn't let us // mutate upvars from a @fn. fn f2(x: &fn()) { x(); } @@ -16,6 +15,7 @@ fn f2(x: &fn()) { x(); } fn main() { let i = 0; let ctr: @fn() -> int = || { f2(|| i = i + 1 ); i }; + //~^ ERROR cannot assign error!(ctr()); error!(ctr()); error!(ctr()); diff --git a/src/test/compile-fail/lambda-mutate.rs b/src/test/compile-fail/lambda-mutate.rs index ee5b3d8968418..a848d8698a3d6 100644 --- a/src/test/compile-fail/lambda-mutate.rs +++ b/src/test/compile-fail/lambda-mutate.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to captured outer variable in a heap closure // Make sure we can't write to upvars from @fns fn main() { let i = 0; let ctr: @fn() -> int = || { i = i + 1; i }; + //~^ ERROR cannot assign error!(ctr()); error!(ctr()); error!(ctr()); diff --git a/src/test/compile-fail/lint-default-methods.rs b/src/test/compile-fail/lint-default-methods.rs index 1350c3e3ad1cd..89b99fcebca5d 100644 --- a/src/test/compile-fail/lint-default-methods.rs +++ b/src/test/compile-fail/lint-default-methods.rs @@ -5,4 +5,3 @@ trait Foo { //~ ERROR default methods are experimental } fn main() {} - diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index e45ef38e97a94..2eb794fd1c296 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -32,4 +32,3 @@ fn qux() { i += 1; } } - diff --git a/src/test/compile-fail/liveness-if-no-else.rs b/src/test/compile-fail/liveness-if-no-else.rs index e37ee5bd4d4f2..22b1b5edbac70 100644 --- a/src/test/compile-fail/liveness-if-no-else.rs +++ b/src/test/compile-fail/liveness-if-no-else.rs @@ -11,6 +11,6 @@ fn foo(x: int) { debug!(x); } fn main() { - let x: int; if 1 > 2 { x = 10; } - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + let x: int; if 1 > 2 { x = 10; } + foo(x); //~ ERROR use of possibly uninitialized variable: `x` } diff --git a/src/test/compile-fail/liveness-return.rs b/src/test/compile-fail/liveness-return.rs index 12f7aa434cce3..6558bc579685a 100644 --- a/src/test/compile-fail/liveness-return.rs +++ b/src/test/compile-fail/liveness-return.rs @@ -9,8 +9,8 @@ // except according to those terms. fn f() -> int { - let x: int; - return x; //~ ERROR use of possibly uninitialized variable: `x` + let x: int; + return x; //~ ERROR use of possibly uninitialized variable: `x` } fn main() { f(); } diff --git a/src/test/compile-fail/liveness-uninit-after-item.rs b/src/test/compile-fail/liveness-uninit-after-item.rs index b3ab005388837..a828b1d6b9f52 100644 --- a/src/test/compile-fail/liveness-uninit-after-item.rs +++ b/src/test/compile-fail/liveness-uninit-after-item.rs @@ -13,4 +13,3 @@ fn main() { fn baz(_x: int) { } baz(bar); //~ ERROR use of possibly uninitialized variable: `bar` } - diff --git a/src/test/compile-fail/liveness-uninit.rs b/src/test/compile-fail/liveness-uninit.rs index 8797132fd5083..a360f8e85a67d 100644 --- a/src/test/compile-fail/liveness-uninit.rs +++ b/src/test/compile-fail/liveness-uninit.rs @@ -11,6 +11,6 @@ fn foo(x: int) { debug!(x); } fn main() { - let x: int; - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + let x: int; + foo(x); //~ ERROR use of possibly uninitialized variable: `x` } diff --git a/src/test/compile-fail/liveness-use-after-send.rs b/src/test/compile-fail/liveness-use-after-send.rs index fdc0392a74c7c..23d3fff01cf3c 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(ch: _chan, +data: T) { +fn send(ch: _chan, data: T) { debug!(ch); debug!(data); fail!(); diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs index 74c040238ac05..95250e36b8685 100644 --- a/src/test/compile-fail/macro-with-seps-err-msg.rs +++ b/src/test/compile-fail/macro-with-seps-err-msg.rs @@ -13,5 +13,3 @@ fn main() { globnar::brotz!(); } - - diff --git a/src/test/auxiliary/issue-2196-c.rs b/src/test/compile-fail/main-wrong-location.rs similarity index 72% rename from src/test/auxiliary/issue-2196-c.rs rename to src/test/compile-fail/main-wrong-location.rs index 290267cbf3258..90ef7843d4bf9 100644 --- a/src/test/auxiliary/issue-2196-c.rs +++ b/src/test/compile-fail/main-wrong-location.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use b::d; - -type t = uint; - +mod m { + // An inferred main entry point (that doesn't use #[main]) + // must appear at the top of the crate + fn main() { } //~ NOTE here is a function named 'main' +} \ No newline at end of file diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs index 67cf67bfa5a04..eb27d51061fcc 100644 --- a/src/test/compile-fail/missing-derivable-attr.rs +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -24,4 +24,3 @@ impl MyEq for A; //~ ERROR missing method fn main() { } - diff --git a/src/test/compile-fail/missing-main.rs b/src/test/compile-fail/missing-main.rs index 4f1b604b5070d..4bfdaf69480e6 100644 --- a/src/test/compile-fail/missing-main.rs +++ b/src/test/compile-fail/missing-main.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:entry function not found +// error-pattern:main function not found fn mian() { } diff --git a/src/test/compile-fail/missing-return.rs b/src/test/compile-fail/missing-return.rs index c0007d2bee807..1dc817cc6e6be 100644 --- a/src/test/compile-fail/missing-return.rs +++ b/src/test/compile-fail/missing-return.rs @@ -13,4 +13,3 @@ fn f() -> int { } fn main() { f(); } - diff --git a/src/test/compile-fail/moves-based-on-type-block-bad.rs b/src/test/compile-fail/moves-based-on-type-block-bad.rs index 020dadfc96cd2..76d50710bb8c1 100644 --- a/src/test/compile-fail/moves-based-on-type-block-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-block-bad.rs @@ -16,7 +16,7 @@ fn main() { let s = S { x: ~Bar(~42) }; loop { do f(&s) |hellothere| { - match hellothere.x { //~ ERROR moving out of immutable field + match hellothere.x { //~ ERROR cannot move out ~Foo(_) => {} ~Bar(x) => io::println(x.to_str()), ~Baz => {} @@ -24,4 +24,3 @@ fn main() { } } } - diff --git a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs index 57829e72674e6..6dce011ddc896 100644 --- a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs @@ -5,4 +5,3 @@ fn main() { } io::println(x); //~ ERROR use of moved value } - diff --git a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs index bee9596df727d..2b9291ce3284c 100644 --- a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs @@ -29,4 +29,3 @@ fn consume(v: ~List) -> int { } fn main() {} - diff --git a/src/test/compile-fail/moves-based-on-type-exprs.rs b/src/test/compile-fail/moves-based-on-type-exprs.rs index 7356c227360c8..5b733129ee5dc 100644 --- a/src/test/compile-fail/moves-based-on-type-exprs.rs +++ b/src/test/compile-fail/moves-based-on-type-exprs.rs @@ -87,7 +87,7 @@ fn f110() { fn f120() { let x = ~[~"hi", ~"ho"]; - x[0] <-> x[1]; + vec::swap(x, 0, 1); touch(&x[0]); touch(&x[1]); } diff --git a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs index 3c15047a29697..ecd58d485a89d 100644 --- a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs +++ b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs @@ -13,6 +13,6 @@ fn test(_x: ~uint) {} fn main() { let i = ~3; for uint::range(0, 10) |_x| { - test(i); //~ ERROR moving out of captured outer immutable variable in a stack closure + test(i); //~ ERROR cannot move out } } diff --git a/src/test/compile-fail/mutable-class-fields-2.rs b/src/test/compile-fail/mutable-class-fields-2.rs index 56c715c9847a5..f5d24b316414e 100644 --- a/src/test/compile-fail/mutable-class-fields-2.rs +++ b/src/test/compile-fail/mutable-class-fields-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable field struct cat { priv mut meows : uint, @@ -17,7 +16,7 @@ struct cat { pub impl cat { fn eat(&self) { - self.how_hungry -= 5; + self.how_hungry -= 5; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/mutable-class-fields.rs b/src/test/compile-fail/mutable-class-fields.rs index 6d11a98c0cb2f..8bebec7134cc3 100644 --- a/src/test/compile-fail/mutable-class-fields.rs +++ b/src/test/compile-fail/mutable-class-fields.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable field struct cat { priv mut meows : uint, - how_hungry : int, - } fn cat(in_x : uint, in_y : int) -> cat { @@ -25,5 +22,5 @@ fn cat(in_x : uint, in_y : int) -> cat { fn main() { let nyan : cat = cat(52u, 99); - nyan.how_hungry = 0; + nyan.how_hungry = 0; //~ ERROR cannot assign } diff --git a/src/test/compile-fail/mutable-enum.rs b/src/test/compile-fail/mutable-enum.rs new file mode 100644 index 0000000000000..2368e5eb5c51f --- /dev/null +++ b/src/test/compile-fail/mutable-enum.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[mutable] +enum Foo { A } + +fn bar(_: T) {} + +fn main() { + let x = A; + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Const` +} diff --git a/src/test/compile-fail/mutable-huh-ptr-assign.rs b/src/test/compile-fail/mutable-huh-ptr-assign.rs index ed356f4001dd6..c907eb4be49f8 100644 --- a/src/test/compile-fail/mutable-huh-ptr-assign.rs +++ b/src/test/compile-fail/mutable-huh-ptr-assign.rs @@ -11,8 +11,8 @@ extern mod std; fn main() { - unsafe fn f(&&v: *const int) { - *v = 1 //~ ERROR assigning to dereference of const * pointer + unsafe fn f(v: *const int) { + *v = 1 //~ ERROR cannot assign } unsafe { diff --git a/src/test/compile-fail/mutable-struct.rs b/src/test/compile-fail/mutable-struct.rs new file mode 100644 index 0000000000000..ee040506c40bd --- /dev/null +++ b/src/test/compile-fail/mutable-struct.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[mutable] +struct Foo { a: int } + +fn bar(_: 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` +} diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index da75dfd010685..2c8c98ad5d6de 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -16,7 +16,7 @@ use std::arc; fn main() { let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = arc::ARC(v); - + do task::spawn() { let v = *arc::get(&arc_v); assert!(v[3] == 4); diff --git a/src/test/compile-fail/noexporttypeexe.rs b/src/test/compile-fail/noexporttypeexe.rs index 8d9796c7c419b..95428568e4c35 100644 --- a/src/test/compile-fail/noexporttypeexe.rs +++ b/src/test/compile-fail/noexporttypeexe.rs @@ -20,4 +20,3 @@ fn main() { let x: int = noexporttypelib::foo(); //~^ ERROR expected `int` but found `core::option::Option` } - diff --git a/src/test/compile-fail/non-exhaustive-match-nested.rs b/src/test/compile-fail/non-exhaustive-match-nested.rs index 4d1db36237640..34fe6b0f67870 100644 --- a/src/test/compile-fail/non-exhaustive-match-nested.rs +++ b/src/test/compile-fail/non-exhaustive-match-nested.rs @@ -20,4 +20,3 @@ fn main() { b => { fail!(~"goodbye"); } } } - diff --git a/src/test/compile-fail/non_owned-enum.rs b/src/test/compile-fail/non_owned-enum.rs new file mode 100644 index 0000000000000..79c2be8183a62 --- /dev/null +++ b/src/test/compile-fail/non_owned-enum.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[non_owned] +enum Foo { A } + +fn bar(_: T) {} + +fn main() { + let x = A; + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Owned` +} diff --git a/src/test/compile-fail/non_owned-struct.rs b/src/test/compile-fail/non_owned-struct.rs new file mode 100644 index 0000000000000..2d0bc9a7e8e46 --- /dev/null +++ b/src/test/compile-fail/non_owned-struct.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[non_owned] +struct Foo { a: int } + +fn bar(_: 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` +} diff --git a/src/test/compile-fail/noncopyable-match-pattern.rs b/src/test/compile-fail/noncopyable-match-pattern.rs index e8b01765a447d..155b398148339 100644 --- a/src/test/compile-fail/noncopyable-match-pattern.rs +++ b/src/test/compile-fail/noncopyable-match-pattern.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let x = Some(unstable::exclusive(false)); + let x = Some(unstable::sync::exclusive(false)); match x { Some(copy z) => { //~ ERROR copying a value of non-copyable type do z.with |b| { assert!(!*b); } diff --git a/src/test/compile-fail/once-fn-subtyping.rs b/src/test/compile-fail/once-fn-subtyping.rs index 00009c706e33e..178c04dfc793c 100644 --- a/src/test/compile-fail/once-fn-subtyping.rs +++ b/src/test/compile-fail/once-fn-subtyping.rs @@ -14,4 +14,3 @@ fn main() { let h: &fn() = ||(); let i: &once fn() = h; // ok } - diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs index 74bdcdc7f82d0..a6728f82ec3b3 100644 --- a/src/test/compile-fail/private-impl-method.rs +++ b/src/test/compile-fail/private-impl-method.rs @@ -22,4 +22,3 @@ fn main() { let s = a::Foo { x: 1 }; s.foo(); //~ ERROR method `foo` is private } - diff --git a/src/test/compile-fail/private-item-simple.rs b/src/test/compile-fail/private-item-simple.rs index e8038df188b7c..8776739db2d76 100644 --- a/src/test/compile-fail/private-item-simple.rs +++ b/src/test/compile-fail/private-item-simple.rs @@ -15,4 +15,3 @@ mod a { fn main() { a::f(); //~ ERROR unresolved name } - diff --git a/src/test/compile-fail/private-method-inherited.rs b/src/test/compile-fail/private-method-inherited.rs index 7b64623e16c3e..bc27027e886ba 100644 --- a/src/test/compile-fail/private-method-inherited.rs +++ b/src/test/compile-fail/private-method-inherited.rs @@ -12,4 +12,3 @@ fn main() { let x = a::Foo; x.f(); //~ ERROR method `f` is private } - diff --git a/src/test/compile-fail/private-method.rs b/src/test/compile-fail/private-method.rs index c918758ad7c68..0d84bc2fc605c 100644 --- a/src/test/compile-fail/private-method.rs +++ b/src/test/compile-fail/private-method.rs @@ -18,7 +18,7 @@ mod kitties { } pub impl cat { - priv fn nap(&self) { uint::range(1u, 10000u, |_i| false)} + priv fn nap(&self) { uint::range(1u, 10000u, |_i| false); } } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/compile-fail/private-struct-field-ctor.rs b/src/test/compile-fail/private-struct-field-ctor.rs index 43e7427dd740f..7ab28d72965fa 100644 --- a/src/test/compile-fail/private-struct-field-ctor.rs +++ b/src/test/compile-fail/private-struct-field-ctor.rs @@ -17,4 +17,3 @@ mod a { fn main() { let s = a::Foo { x: 1 }; //~ ERROR field `x` is private } - diff --git a/src/test/compile-fail/private-struct-field-pattern.rs b/src/test/compile-fail/private-struct-field-pattern.rs index 864c9bd98d7b3..6f524a8eaa401 100644 --- a/src/test/compile-fail/private-struct-field-pattern.rs +++ b/src/test/compile-fail/private-struct-field-pattern.rs @@ -25,4 +25,3 @@ fn main() { Foo { x: _ } => {} //~ ERROR field `x` is private } } - diff --git a/src/test/compile-fail/qquote-1.rs b/src/test/compile-fail/qquote-1.rs index eda207f711d68..1241190b5371f 100644 --- a/src/test/compile-fail/qquote-1.rs +++ b/src/test/compile-fail/qquote-1.rs @@ -26,7 +26,7 @@ trait fake_ext_ctxt { fn cfg() -> ast::crate_cfg; fn parse_sess() -> parse::parse_sess; fn call_site() -> span; - fn ident_of(st: ~str) -> ast::ident; + fn ident_of(st: &str) -> ast::ident; } type fake_session = parse::parse_sess; @@ -41,8 +41,8 @@ impl fake_ext_ctxt for fake_session { expn_info: None } } - fn ident_of(st: ~str) -> ast::ident { - self.interner.intern(@st) + fn ident_of(st: &str) -> ast::ident { + self.interner.intern(st) } } @@ -65,4 +65,3 @@ fn main() { fn check_pp(expr: T, f: &fn(pprust::ps, T), expect: str) { fail!(); } - diff --git a/src/test/compile-fail/qquote-2.rs b/src/test/compile-fail/qquote-2.rs index c669053400831..07500825a952b 100644 --- a/src/test/compile-fail/qquote-2.rs +++ b/src/test/compile-fail/qquote-2.rs @@ -25,7 +25,7 @@ trait fake_ext_ctxt { fn cfg() -> ast::crate_cfg; fn parse_sess() -> parse::parse_sess; fn call_site() -> span; - fn ident_of(st: ~str) -> ast::ident; + fn ident_of(st: &str) -> ast::ident; } type fake_session = parse::parse_sess; @@ -40,8 +40,8 @@ impl fake_ext_ctxt for fake_session { expn_info: None } } - fn ident_of(st: ~str) -> ast::ident { - self.interner.intern(@st) + fn ident_of(st: &str) -> ast::ident { + self.interner.intern(st) } } @@ -60,4 +60,3 @@ fn main() { fn check_pp(expr: T, f: &fn(pprust::ps, T), expect: str) { fail!(); } - diff --git a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs index 5e157c1bd7b19..957925709e179 100644 --- a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs +++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs @@ -12,4 +12,3 @@ fn main() { let f = |3: int| io::println("hello"); //~ ERROR refutable pattern f(4); } - diff --git a/src/test/compile-fail/regions-addr-of-arg.rs b/src/test/compile-fail/regions-addr-of-arg.rs index 7f2140d96e16c..4fff5a6f87c78 100644 --- a/src/test/compile-fail/regions-addr-of-arg.rs +++ b/src/test/compile-fail/regions-addr-of-arg.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo(a: int) { - let _p: &'static int = &a; //~ ERROR illegal borrow + let _p: &'static int = &a; //~ ERROR borrowed value does not live long enough } fn bar(a: int) { diff --git a/src/test/compile-fail/regions-addr-of-self.rs b/src/test/compile-fail/regions-addr-of-self.rs index 732d946bf9ee5..f96ef639e756c 100644 --- a/src/test/compile-fail/regions-addr-of-self.rs +++ b/src/test/compile-fail/regions-addr-of-self.rs @@ -35,4 +35,3 @@ fn main() { d.chase_cat(); debug!("cats_chased: %u", d.cats_chased); } - diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index cccd135e9f836..ab2620d46fdc5 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -23,10 +23,8 @@ fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { return e; //~ ERROR mismatched types: expected `a_class/&'b ` but found `a_class/&'a ` } -fn a_fn4<'a,'b>(e: int<'a>) -> int<'b> { - //~^ ERROR region parameters are not allowed on this type - //~^^ ERROR region parameters are not allowed on this type - return e; +fn a_fn4<'a,'b>() { + let _: int<'a> = 1; //~ ERROR region parameters are not allowed on this type } fn main() { } diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index 120428e02f4cb..2ab0c14b49b65 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -30,12 +30,12 @@ fn compute(x: &ast) -> uint { fn map_nums(x: &ast, f: &fn(uint) -> uint) -> &ast { match *x { num(x) => { - return &num(f(x)); //~ ERROR illegal borrow + 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); - return &add(m_x, m_y); //~ ERROR illegal borrow + return &add(m_x, m_y); //~ ERROR borrowed value does not live long enough } } } diff --git a/src/test/compile-fail/regions-creating-enums4.rs b/src/test/compile-fail/regions-creating-enums4.rs index 1cb378cf406f8..8f764745697c7 100644 --- a/src/test/compile-fail/regions-creating-enums4.rs +++ b/src/test/compile-fail/regions-creating-enums4.rs @@ -14,8 +14,7 @@ enum ast<'self> { } fn mk_add_bad2<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast { - add(x, y) - //~^ ERROR cannot infer an appropriate lifetime + add(x, y) //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-escape-bound-fn.rs b/src/test/compile-fail/regions-escape-bound-fn.rs index c81ef77f497db..5ac5e334be23d 100644 --- a/src/test/compile-fail/regions-escape-bound-fn.rs +++ b/src/test/compile-fail/regions-escape-bound-fn.rs @@ -14,6 +14,6 @@ fn with_int(f: &fn(x: &int)) { } fn main() { - let mut x: Option<&int> = None; //~ ERROR cannot infer + let mut x: Option<&int> = None; //~ ERROR cannot infer with_int(|y| x = Some(y)); } diff --git a/src/test/compile-fail/regions-escape-loop-via-variable.rs b/src/test/compile-fail/regions-escape-loop-via-variable.rs index ac10b5c454a85..19bd0bf9747bb 100644 --- a/src/test/compile-fail/regions-escape-loop-via-variable.rs +++ b/src/test/compile-fail/regions-escape-loop-via-variable.rs @@ -18,6 +18,6 @@ fn main() { loop { let x = 1 + *p; - p = &x; //~ ERROR illegal borrow + p = &x; //~ ERROR borrowed value does not live long enough } } diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index da5e3c2660ef7..92e2cd73dfbd8 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -14,8 +14,8 @@ fn broken() { let mut _y = ~[&mut x]; while x < 10 { let mut z = x; - _y.push(&mut z); //~ ERROR illegal borrow - x += 1; //~ ERROR assigning to mutable local variable prohibited due to outstanding loan + _y.push(&mut z); //~ ERROR borrowed value does not live long enough + x += 1; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index f7165784c7975..aa431d6b81c6e 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -23,13 +23,8 @@ fn with(f: &fn(x: &int) -> R) -> int { } fn return_it() -> int { - with(|o| o) - //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements - //~^^ ERROR reference is not valid outside of its lifetime - //~^^^ ERROR reference is not valid outside of its lifetime + with(|o| o) //~ ERROR reference is not valid outside of its lifetime } fn main() { - let x = return_it(); - debug!("foo=%d", x); } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs index a8b7ae1b9c8e4..d519397f68c58 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs @@ -18,10 +18,9 @@ fn x_coord<'r>(p: &'r point) -> &'r int { } fn foo(p: @point) -> &int { - let xc = x_coord(p); //~ ERROR illegal borrow + let xc = x_coord(p); //~ ERROR cannot root assert!(*xc == 3); return xc; } fn main() {} - diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs index bf8f227b5730e..50ac5f65772fc 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs @@ -15,9 +15,9 @@ fn foo(cond: &fn() -> bool, box: &fn() -> @int) { loop { let x = box(); - // Here we complain because the resulting region - // of this borrow is the fn body as a whole. - y = borrow(x); //~ ERROR illegal borrow: cannot root managed value long enough + // Here we complain because the resulting region + // of this borrow is the fn body as a whole. + y = borrow(x); //~ ERROR cannot root assert!(*x == *y); if cond() { break; } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index 2e9a4eb141037..fe995052c52e4 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -13,7 +13,7 @@ fn ignore(_f: &fn<'z>(&'z int) -> &'z int) {} fn nested() { let y = 3; ignore(|z| { - if false { &y } else { z } //~ ERROR illegal borrow + if false { &y } else { z } //~ ERROR borrowed value does not live long enough }); } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 3089c362a5044..74399967446ea 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -16,7 +16,7 @@ fn nested<'x>(x: &'x int) { ignore::<&fn<'z>(&'z int)>(|z| { ay = x; - ay = &y; //~ ERROR cannot infer an appropriate lifetime + ay = &y; ay = z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index f916b0d95c2ee..a572d90313b6a 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -18,7 +18,6 @@ fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) //~ ERROR mismatched types - //~^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index 157b99de9e806..ec9a908ba9876 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -21,7 +21,6 @@ fn with(f: &fn(x: &int) -> R) -> R { fn return_it() -> &int { with(|o| o) //~ ERROR mismatched types - //~^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret.rs b/src/test/compile-fail/regions-ret.rs index be7b28f6ef4b5..eccffb4051e23 100644 --- a/src/test/compile-fail/regions-ret.rs +++ b/src/test/compile-fail/regions-ret.rs @@ -9,9 +9,8 @@ // except according to those terms. fn f<'a>(_x : &'a int) -> &'a int { - return &3; //~ ERROR illegal borrow + return &3; //~ ERROR borrowed value does not live long enough } fn main() { } - diff --git a/src/test/compile-fail/regions-var-type-out-of-scope.rs b/src/test/compile-fail/regions-var-type-out-of-scope.rs index 7d75ac7434931..addf20fd70249 100644 --- a/src/test/compile-fail/regions-var-type-out-of-scope.rs +++ b/src/test/compile-fail/regions-var-type-out-of-scope.rs @@ -14,7 +14,7 @@ fn foo(cond: bool) { let mut x; if cond { - x = &3; //~ ERROR illegal borrow: borrowed value does not live long enough + x = &3; //~ ERROR borrowed value does not live long enough assert!((*x == 3)); } } diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index 18bdb564441d3..e1e1e2313f42a 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -26,4 +26,3 @@ fn main() { let a = Foo { x: 3 }; let _ = [ a, ..5 ]; //~ ERROR copying a value of non-copyable type } - diff --git a/src/test/compile-fail/simd-type.rs b/src/test/compile-fail/simd-type.rs new file mode 100644 index 0000000000000..8387b2bc723fa --- /dev/null +++ b/src/test/compile-fail/simd-type.rs @@ -0,0 +1,13 @@ +#[simd] +struct vec4(T, T, T, T); //~ ERROR SIMD vector cannot be generic + +#[simd] +struct empty; //~ ERROR SIMD vector cannot be empty + +#[simd] +struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous + +#[simd] +struct int4(int, int, int, int); //~ ERROR SIMD vector element type should be machine type + +fn main() {} diff --git a/src/test/compile-fail/static-method-privacy.rs b/src/test/compile-fail/static-method-privacy.rs index 50df4f04971c8..0fd82b5ace3a7 100644 --- a/src/test/compile-fail/static-method-privacy.rs +++ b/src/test/compile-fail/static-method-privacy.rs @@ -8,4 +8,3 @@ mod a { fn main() { let _ = a::S::new(); //~ ERROR function `new` is private } - diff --git a/src/test/compile-fail/static-region-bound.rs b/src/test/compile-fail/static-region-bound.rs index 500a5b0c8bcbc..ada3aebb2f420 100644 --- a/src/test/compile-fail/static-region-bound.rs +++ b/src/test/compile-fail/static-region-bound.rs @@ -6,4 +6,3 @@ fn main() { let x = &3; f(x); //~ ERROR instantiating a type parameter with an incompatible type } - diff --git a/src/test/compile-fail/struct-like-enum-nonexhaustive.rs b/src/test/compile-fail/struct-like-enum-nonexhaustive.rs index 52a61628c3562..91709e2ea7da0 100644 --- a/src/test/compile-fail/struct-like-enum-nonexhaustive.rs +++ b/src/test/compile-fail/struct-like-enum-nonexhaustive.rs @@ -20,5 +20,3 @@ fn main() { B { x: None } => {} } } - - diff --git a/src/test/compile-fail/struct-no-fields.rs b/src/test/compile-fail/struct-no-fields.rs index 08a590f73965a..546931d20dc74 100644 --- a/src/test/compile-fail/struct-no-fields.rs +++ b/src/test/compile-fail/struct-no-fields.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: Unit-like struct should be written as: struct Foo; +// error-pattern: Unit-like struct should be written as `struct Foo;` struct Foo {} fn main() {} diff --git a/src/test/compile-fail/super-at-top-level.rs b/src/test/compile-fail/super-at-top-level.rs index 21b9e5292b19e..f1064a6290561 100644 --- a/src/test/compile-fail/super-at-top-level.rs +++ b/src/test/compile-fail/super-at-top-level.rs @@ -2,6 +2,4 @@ use super::f; //~ ERROR unresolved name //~^ ERROR failed to resolve import fn main() { - } - diff --git a/src/test/compile-fail/suppressed-error.rs b/src/test/compile-fail/suppressed-error.rs new file mode 100644 index 0000000000000..b4a72548cfc0d --- /dev/null +++ b/src/test/compile-fail/suppressed-error.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let (x, y) = (); //~ ERROR expected `()` but found tuple (types differ) + return x; +} \ No newline at end of file diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs index af99c0e5f2953..22f6a34a181fb 100644 --- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs +++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs @@ -15,7 +15,7 @@ extern mod core; -fn last(v: ~[&T]) -> core::Option { +fn last(v: ~[&T]) -> core::option::Option { fail!(); } diff --git a/src/test/compile-fail/tag-variant-disr-dup.rs b/src/test/compile-fail/tag-variant-disr-dup.rs index be53b6a0ba3fa..216779fac7c46 100644 --- a/src/test/compile-fail/tag-variant-disr-dup.rs +++ b/src/test/compile-fail/tag-variant-disr-dup.rs @@ -19,3 +19,5 @@ enum color { black = 0x000000, white = 0x000000, } + +fn main() { } \ No newline at end of file diff --git a/src/test/compile-fail/test-cfg.rs b/src/test/compile-fail/test-cfg.rs index a090dd9de5d12..a8c528135135a 100644 --- a/src/test/compile-fail/test-cfg.rs +++ b/src/test/compile-fail/test-cfg.rs @@ -14,5 +14,5 @@ fn foo() {} fn main() { - foo(); //~ ERROR unresolved name: `foo`. + foo(); //~ ERROR unresolved name `foo`. } diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index 7f4c227d2d083..54fa62f797766 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -19,7 +19,3 @@ impl Mumbo for uint { } fn main() {} - - - - diff --git a/src/test/compile-fail/trait-inheritance-missing-requirement.rs b/src/test/compile-fail/trait-inheritance-missing-requirement.rs index a341c24261135..5968c296e1382 100644 --- a/src/test/compile-fail/trait-inheritance-missing-requirement.rs +++ b/src/test/compile-fail/trait-inheritance-missing-requirement.rs @@ -30,4 +30,3 @@ impl Bar for A { fn main() { } - diff --git a/src/test/compile-fail/tuple-struct-nonexhaustive.rs b/src/test/compile-fail/tuple-struct-nonexhaustive.rs index 7cfdab2e96d57..de28a06ababcb 100644 --- a/src/test/compile-fail/tuple-struct-nonexhaustive.rs +++ b/src/test/compile-fail/tuple-struct-nonexhaustive.rs @@ -17,5 +17,3 @@ fn main() { Foo(2, b) => io::println(fmt!("%d", b)) } } - - diff --git a/src/test/compile-fail/tutorial-suffix-inference-test.rs b/src/test/compile-fail/tutorial-suffix-inference-test.rs index c68af84b95be0..d92aa8d640ab5 100644 --- a/src/test/compile-fail/tutorial-suffix-inference-test.rs +++ b/src/test/compile-fail/tutorial-suffix-inference-test.rs @@ -22,11 +22,11 @@ fn main() { //~^ ERROR mismatched types: expected `u16` but found `i32` let a = 3i; - + fn identity_i(n: int) -> int { n } identity_i(a); // ok - identity_u16(a); + identity_u16(a); //~^ ERROR mismatched types: expected `u16` but found `int` } diff --git a/src/test/compile-fail/type-shadow.rs b/src/test/compile-fail/type-shadow.rs index a9b4a85e6385c..c4a412f64c8d4 100644 --- a/src/test/compile-fail/type-shadow.rs +++ b/src/test/compile-fail/type-shadow.rs @@ -9,14 +9,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -// error-pattern: mismatched types - fn main() { type X = int; type Y = X; if true { - type X = str; - let y: Y = "hello"; + type X = &'static str; + let y: Y = "hello"; //~ ERROR mismatched types } } diff --git a/src/test/compile-fail/uninhabited-enum-cast.rs b/src/test/compile-fail/uninhabited-enum-cast.rs new file mode 100644 index 0000000000000..c4a5dc4710cba --- /dev/null +++ b/src/test/compile-fail/uninhabited-enum-cast.rs @@ -0,0 +1,7 @@ +enum E {} + +fn f(e: E) { + println((e as int).to_str()); //~ ERROR non-scalar cast +} + +fn main() {} diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs index edc8a47822d72..95945b0b5baa4 100644 --- a/src/test/compile-fail/unique-object-noncopyable.rs +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -31,4 +31,3 @@ fn main() { let y: ~Foo = x as ~Foo; let _z = copy y; //~ ERROR copying a value of non-copyable type } - diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index a3c51e2b7b1fc..003e8ccf30956 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -21,7 +21,7 @@ impl Drop for r { } } -fn f(+_i: ~[T], +_j: ~[T]) { +fn f(_i: ~[T], _j: ~[T]) { } fn main() { diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs new file mode 100644 index 0000000000000..1bd3efeadcbba --- /dev/null +++ b/src/test/compile-fail/unresolved-import.rs @@ -0,0 +1,12 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use foo::bar; //~ ERROR unresolved import. maybe a missing + //~^ ERROR failed to resolve import diff --git a/src/test/compile-fail/unused-unsafe.rs b/src/test/compile-fail/unused-unsafe.rs index 9552badb57f67..465e5548f679c 100644 --- a/src/test/compile-fail/unused-unsafe.rs +++ b/src/test/compile-fail/unused-unsafe.rs @@ -12,8 +12,10 @@ #[deny(unused_unsafe)]; -extern mod foo { - fn bar(); +mod foo { + pub extern { + pub fn bar(); + } } fn callback(_f: &fn() -> T) -> T { fail!() } diff --git a/src/test/compile-fail/use-after-move-based-on-type.rs b/src/test/compile-fail/use-after-move-based-on-type.rs index 6c268c5e13c83..3d176bb339d83 100644 --- a/src/test/compile-fail/use-after-move-based-on-type.rs +++ b/src/test/compile-fail/use-after-move-based-on-type.rs @@ -13,4 +13,3 @@ fn main() { let _y = x; io::println(x); //~ ERROR use of moved value } - diff --git a/src/test/compile-fail/use-after-move-self-based-on-type.rs b/src/test/compile-fail/use-after-move-self-based-on-type.rs index b0a2bc8ec1275..d19b4dfbd57d0 100644 --- a/src/test/compile-fail/use-after-move-self-based-on-type.rs +++ b/src/test/compile-fail/use-after-move-self-based-on-type.rs @@ -9,7 +9,7 @@ impl Drop for S { pub impl S { fn foo(self) -> int { self.bar(); - return self.x; //~ ERROR use of moved value + return self.x; //~ ERROR use of partially moved value } fn bar(self) {} @@ -19,4 +19,3 @@ fn main() { let x = S { x: 1 }; io::println(x.foo().to_str()); } - diff --git a/src/test/compile-fail/use-after-move-self.rs b/src/test/compile-fail/use-after-move-self.rs index 3eded9fd4f39c..b2eaffdd06605 100644 --- a/src/test/compile-fail/use-after-move-self.rs +++ b/src/test/compile-fail/use-after-move-self.rs @@ -5,7 +5,7 @@ struct S { pub impl S { fn foo(self) -> int { self.bar(); - return *self.x; //~ ERROR use of moved value + return *self.x; //~ ERROR use of partially moved value } fn bar(self) {} @@ -15,4 +15,3 @@ fn main() { let x = S { x: ~1 }; io::println(x.foo().to_str()); } - diff --git a/src/test/compile-fail/view-items-at-top.rs b/src/test/compile-fail/view-items-at-top.rs index a637836320df4..023be703cca77 100644 --- a/src/test/compile-fail/view-items-at-top.rs +++ b/src/test/compile-fail/view-items-at-top.rs @@ -19,4 +19,3 @@ use std::net; //~ ERROR view items must be declared at the top fn main() { } - diff --git a/src/test/compile-fail/while-type-error.rs b/src/test/compile-fail/while-type-error.rs index f9d3dce750890..ecab746373a98 100644 --- a/src/test/compile-fail/while-type-error.rs +++ b/src/test/compile-fail/while-type-error.rs @@ -11,4 +11,3 @@ // error-pattern: mismatched types fn main() { while main { } } - diff --git a/src/test/compile-fail/writing-to-immutable-vec.rs b/src/test/compile-fail/writing-to-immutable-vec.rs index 3f4c8ccef8175..faa3d6cfe47e7 100644 --- a/src/test/compile-fail/writing-to-immutable-vec.rs +++ b/src/test/compile-fail/writing-to-immutable-vec.rs @@ -8,5 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable vec content -fn main() { let v: ~[int] = ~[1, 2, 3]; v[1] = 4; } +fn main() { + let v: ~[int] = ~[1, 2, 3]; + v[1] = 4; //~ ERROR cannot assign +} diff --git a/src/test/compile-fail/xc-private-method.rs b/src/test/compile-fail/xc-private-method.rs index d194820df9408..e8777a0a9f256 100644 --- a/src/test/compile-fail/xc-private-method.rs +++ b/src/test/compile-fail/xc-private-method.rs @@ -6,4 +6,3 @@ extern mod xc_private_method_lib; fn main() { let _ = xc_private_method_lib::Foo::new(); //~ ERROR function `new` is private } - diff --git a/src/test/pretty/doc-comments.rs b/src/test/pretty/doc-comments.rs index a866afd240592..45e242c0ca049 100644 --- a/src/test/pretty/doc-comments.rs +++ b/src/test/pretty/doc-comments.rs @@ -22,7 +22,7 @@ fn b() { ////////////////////////////////// // some single-line non-doc comment preceded by a separator -////////////////////////////////// +////////////////////////////////// /// some single-line outer-docs preceded by a separator /// (and trailing whitespaces) fn c() { } diff --git a/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs b/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs new file mode 100644 index 0000000000000..c0c20f7af4351 --- /dev/null +++ b/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:left: 1.0000001 does not approximately equal right: 1 with epsilon: 0.0000001 +pub fn main() { + assert_approx_eq!(1.0000001f, 1.0f, 1.0e-7); +} diff --git a/src/test/run-fail/assert-approx-eq-macro-fail.rs b/src/test/run-fail/assert-approx-eq-macro-fail.rs new file mode 100644 index 0000000000000..43de4f92b63b1 --- /dev/null +++ b/src/test/run-fail/assert-approx-eq-macro-fail.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:left: 1.00001 does not approximately equal right: 1 +pub fn main() { + assert_approx_eq!(1.00001f, 1.0f); +} diff --git a/src/test/run-fail/assert-as-macro.rs b/src/test/run-fail/assert-as-macro.rs index 07813b91e571d..f715e21f781bd 100644 --- a/src/test/run-fail/assert-as-macro.rs +++ b/src/test/run-fail/assert-as-macro.rs @@ -3,4 +3,3 @@ fn main() { assert!(1 == 2); } - diff --git a/src/test/run-fail/borrowck-wg-autoderef-and-autoborrowvec-combined-fail-issue-6272.rs b/src/test/run-fail/borrowck-wg-autoderef-and-autoborrowvec-combined-fail-issue-6272.rs new file mode 100644 index 0000000000000..2d3e7dd616d33 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-autoderef-and-autoborrowvec-combined-fail-issue-6272.rs @@ -0,0 +1,21 @@ +// error-pattern:borrowed + +// Issue #6272. Tests that freezing correctly accounts for all the +// implicit derefs that can occur and freezes the innermost box. See +// the companion test +// +// run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs +// +// for a detailed explanation of what is going on here. + +fn main() { + let a = @mut [3i]; + let b = @mut [a]; + let c = @mut b; + + // this should freeze `a` only + let x: &mut [int] = c[0]; + + // hence this should fail + a[0] = a[0]; +} diff --git a/src/test/run-fail/borrowck-wg-fail-2.rs b/src/test/run-fail/borrowck-wg-fail-2.rs index 126135772ade0..59a5fecd34003 100644 --- a/src/test/run-fail/borrowck-wg-fail-2.rs +++ b/src/test/run-fail/borrowck-wg-fail-2.rs @@ -1,5 +1,8 @@ // error-pattern:borrowed +// Test that write guards trigger when there is a write to a field +// of a frozen structure. + struct S { x: int } @@ -7,5 +10,6 @@ struct S { fn main() { let x = @mut S { x: 3 }; let y: &S = x; - x.x = 5; + let z = x; + z.x = 5; } diff --git a/src/test/run-fail/borrowck-wg-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs index ad4c794212121..a40faa1ac6fc3 100644 --- a/src/test/run-fail/borrowck-wg-fail-3.rs +++ b/src/test/run-fail/borrowck-wg-fail-3.rs @@ -1,8 +1,11 @@ // error-pattern:borrowed +// Test that write guards trigger when there is a write to a directly +// frozen @mut box. + fn main() { let x = @mut 3; let y: &mut int = x; - *x = 5; + let z = x; + *z = 5; } - diff --git a/src/test/run-fail/borrowck-wg-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs index d393832c6e862..201db14eb17d5 100644 --- a/src/test/run-fail/borrowck-wg-fail.rs +++ b/src/test/run-fail/borrowck-wg-fail.rs @@ -1,13 +1,13 @@ // error-pattern:borrowed -fn f(x: &int, y: @mut int) { - unsafe { - *y = 2; - } +// Test that write guards trigger when mut box is frozen +// as part of argument coercion. + +fn f(_x: &int, y: @mut int) { + *y = 2; } fn main() { let x = @mut 3; f(x, x); } - diff --git a/src/test/run-fail/borrowck-wg-imm-then-mut.rs b/src/test/run-fail/borrowck-wg-imm-then-mut.rs new file mode 100644 index 0000000000000..e2c8a0b549c36 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-imm-then-mut.rs @@ -0,0 +1,19 @@ +// error-pattern:borrowed + +// Test that if you imm borrow then mut borrow it fails. + +fn add1(a:@mut int) +{ + add2(a); // already frozen +} + +fn add2(_:&mut int) +{ +} + +pub fn main() +{ + let a = @mut 3; + let b = &*a; // freezes a + add1(a); +} diff --git a/src/test/run-fail/borrowck-wg-mut-then-imm.rs b/src/test/run-fail/borrowck-wg-mut-then-imm.rs new file mode 100644 index 0000000000000..58b2a1d87beed --- /dev/null +++ b/src/test/run-fail/borrowck-wg-mut-then-imm.rs @@ -0,0 +1,19 @@ +// error-pattern:borrowed + +// Test that if you mut borrow then imm borrow it fails. + +fn add1(a:@mut int) +{ + add2(a); // already frozen +} + +fn add2(_:&int) +{ +} + +pub fn main() +{ + let a = @mut 3; + let b = &mut *a; // freezes a + add1(a); +} diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs new file mode 100644 index 0000000000000..91df90f8b3ac9 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs @@ -0,0 +1,37 @@ +// error-pattern:borrowed + +// Test that write guards trigger when there is a coercion to +// a slice on the receiver of a method. + +trait MyMutSlice { + fn my_mut_slice(self) -> Self; +} + +impl<'self, T> MyMutSlice for &'self mut [T] { + fn my_mut_slice(self) -> &'self mut [T] { + self + } +} + +trait MySlice { + fn my_slice(self) -> Self; +} + +impl<'self, T> MySlice for &'self [T] { + fn my_slice(self) -> &'self [T] { + self + } +} + +fn add(x:&mut [int], y:&[int]) +{ + x[0] = x[0] + y[0]; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(z.my_mut_slice(), z2.my_slice()); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs new file mode 100644 index 0000000000000..bae693ce4eae2 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs @@ -0,0 +1,16 @@ +// error-pattern:borrowed + +// Test that write guards trigger when arguments are coerced to slices. + +fn add(x:&mut [int], y:&[int]) +{ + x[0] = x[0] + y[0]; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(z, z2); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs new file mode 100644 index 0000000000000..9e2a02b32dfed --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs @@ -0,0 +1,17 @@ +// error-pattern:borrowed + +// Test that write guards trigger when we are indexing into +// an @mut vector. + +fn add(x:&mut int, y:&int) +{ + *x = *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&mut z[0], &z2[0]); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-two-array-indices.rs b/src/test/run-fail/borrowck-wg-two-array-indices.rs new file mode 100644 index 0000000000000..ad68448876028 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-two-array-indices.rs @@ -0,0 +1,17 @@ +// error-pattern:borrowed + +// Test that arguments trigger when there are *two mutable* borrows +// of indices. + +fn add(x:&mut int, y:&mut int) +{ + *x = *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&mut z[0], &mut z2[0]); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index d4f3828ea7174..9c996807ad866 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:attempted quotient with a divisor of zero +// error-pattern:attempted to divide by zero fn main() { let y = 0; let z = 1 / y; diff --git a/src/test/run-fail/morestack3.rs b/src/test/run-fail/morestack3.rs index 14fc40a43cc9a..012e9d19b1218 100644 --- a/src/test/run-fail/morestack3.rs +++ b/src/test/run-fail/morestack3.rs @@ -14,7 +14,7 @@ extern mod std; -fn getbig_and_fail(&&i: int) { +fn getbig_and_fail(i: int) { let _r = and_then_get_big_again(5); if i != 0 { getbig_and_fail(i - 1); diff --git a/src/test/run-fail/morestack4.rs b/src/test/run-fail/morestack4.rs index e45853937037e..6fc187491cf8c 100644 --- a/src/test/run-fail/morestack4.rs +++ b/src/test/run-fail/morestack4.rs @@ -14,7 +14,7 @@ extern mod std; -fn getbig_and_fail(&&i: int) { +fn getbig_and_fail(i: int) { let r = and_then_get_big_again(5); if i != 0 { getbig_and_fail(i - 1); diff --git a/src/test/run-fail/too-much-recursion-unwinding.rs b/src/test/run-fail/too-much-recursion-unwinding.rs index 3890e24cdfe05..1c668dfc90d41 100644 --- a/src/test/run-fail/too-much-recursion-unwinding.rs +++ b/src/test/run-fail/too-much-recursion-unwinding.rs @@ -11,7 +11,7 @@ // xfail-test leaks // error-pattern:ran out of stack -// Test that the task fails after hiting the recursion limit +// Test that the task fails after hitting the recursion limit // during unwinding fn recurse() { diff --git a/src/test/run-fail/unwind-move.rs b/src/test/run-fail/unwind-move.rs index 51e2eaa44fa37..8f1b34d17cd99 100644 --- a/src/test/run-fail/unwind-move.rs +++ b/src/test/run-fail/unwind-move.rs @@ -9,7 +9,7 @@ // except according to those terms. // error-pattern:fail -fn f(+_a: @int) { +fn f(_a: @int) { fail!(); } diff --git a/src/test/run-fail/unwind-resource-fail3.rs b/src/test/run-fail/unwind-resource-fail3.rs index d3ba5737b71f6..bfbad0b5aea62 100644 --- a/src/test/run-fail/unwind-resource-fail3.rs +++ b/src/test/run-fail/unwind-resource-fail3.rs @@ -14,7 +14,7 @@ struct faily_box { i: @int } // What happens to the box pointer owned by this class? - + fn faily_box(i: @int) -> faily_box { faily_box { i: i } } #[unsafe_destructor] diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 9bfe29a5e8e4c..84edb990a7598 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -27,7 +27,7 @@ trait fake_ext_ctxt { fn cfg() -> ast::crate_cfg; fn parse_sess() -> parse::parse_sess; fn call_site() -> span; - fn ident_of(st: ~str) -> ast::ident; + fn ident_of(st: &str) -> ast::ident; } type fake_session = parse::parse_sess; @@ -42,8 +42,8 @@ impl fake_ext_ctxt for fake_session { expn_info: None } } - fn ident_of(st: ~str) -> ast::ident { - self.interner.intern(@copy st) + fn ident_of(st: &str) -> ast::ident { + self.interner.intern(st) } } @@ -85,4 +85,3 @@ fn check_pp(cx: fake_ext_ctxt, assert!(s == expect); } } - diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index ccee163eafe5b..3ec54955229d3 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -27,4 +27,3 @@ fn syntax_extension(ext_cx: @ext_ctxt) { fn main() { } - diff --git a/src/test/run-pass/alt-ref-binding-in-guard-3256.rs b/src/test/run-pass/alt-ref-binding-in-guard-3256.rs index 1ece3b5fd93b6..ed7a631637433 100644 --- a/src/test/run-pass/alt-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/alt-ref-binding-in-guard-3256.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let x = Some(unstable::exclusive(true)); + let x = Some(unstable::sync::exclusive(true)); match x { Some(ref z) if z.with(|b| *b) => { do z.with |b| { assert!(*b); } diff --git a/src/test/run-pass/anon-trait-static-method.rs b/src/test/run-pass/anon-trait-static-method.rs index 8e11786786ff9..91bbbf5c0a0df 100644 --- a/src/test/run-pass/anon-trait-static-method.rs +++ b/src/test/run-pass/anon-trait-static-method.rs @@ -22,4 +22,3 @@ pub fn main() { let x = Foo::new(); io::println(x.x.to_str()); } - diff --git a/src/test/run-pass/anon_trait_static_method_exe.rs b/src/test/run-pass/anon_trait_static_method_exe.rs index 5d8b79836883d..1baeca00083fd 100644 --- a/src/test/run-pass/anon_trait_static_method_exe.rs +++ b/src/test/run-pass/anon_trait_static_method_exe.rs @@ -18,6 +18,3 @@ pub fn main() { let x = Foo::new(); io::println(x.x.to_str()); } - - - diff --git a/src/test/run-pass/argument-passing.rs b/src/test/run-pass/argument-passing.rs index d61c1214633fc..8c84187ff6f06 100644 --- a/src/test/run-pass/argument-passing.rs +++ b/src/test/run-pass/argument-passing.rs @@ -10,9 +10,11 @@ // xfail-fast -struct X { x: int } +struct X { + x: int +} -fn f1(a: &mut X, b: &mut int, +c: int) -> int { +fn f1(a: &mut X, b: &mut int, c: int) -> int { let r = a.x + *b + c; a.x = 0; *b = 10; diff --git a/src/test/run-pass/assert-approx-eq-macro-success.rs b/src/test/run-pass/assert-approx-eq-macro-success.rs new file mode 100644 index 0000000000000..5c7c11ef50343 --- /dev/null +++ b/src/test/run-pass/assert-approx-eq-macro-success.rs @@ -0,0 +1,16 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + assert_approx_eq!(1.0f, 1.0f); + assert_approx_eq!(1.0000001f, 1.0f); + assert_approx_eq!(1.0000001f, 1.0f, 1.0e-6); + assert_approx_eq!(1.000001f, 1.0f, 1.0e-5); +} diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index c557aa7e22383..6946ed3fbcfc0 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -13,22 +13,18 @@ // it. trait iterable { - fn iterate(&self, blk: &fn(x: &A) -> bool); + fn iterate(&self, blk: &fn(x: &A) -> bool) -> bool; } impl<'self,A> iterable for &'self [A] { - fn iterate(&self, f: &fn(x: &A) -> bool) { - for vec::each(*self) |e| { - if !f(e) { break; } - } + fn iterate(&self, f: &fn(x: &A) -> bool) -> bool { + vec::each(*self, f) } } impl iterable for ~[A] { - fn iterate(&self, f: &fn(x: &A) -> bool) { - for vec::each(*self) |e| { - if !f(e) { break; } - } + fn iterate(&self, f: &fn(x: &A) -> bool) -> bool { + vec::each(*self, f) } } diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index bfc15acaa763c..cfac8e8cd061f 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -31,11 +31,12 @@ fn test_ebml >(a1: &A) { let bytes = do io::with_bytes_writer |wr| { - let ebml_w = &EBWriter::Encoder(wr); - a1.encode(ebml_w) + let mut ebml_w = EBWriter::Encoder(wr); + a1.encode(&mut ebml_w) }; let d = EBReader::Doc(@bytes); - let a2: A = Decodable::decode(&EBReader::Decoder(d)); + let mut decoder = EBReader::Decoder(d); + let a2: A = Decodable::decode(&mut decoder); assert!(*a1 == a2); } diff --git a/src/test/run-pass/auto-ref-newtype.rs b/src/test/run-pass/auto-ref-newtype.rs index bac6d1aa740a8..a9fca0ccb1589 100644 --- a/src/test/run-pass/auto-ref-newtype.rs +++ b/src/test/run-pass/auto-ref-newtype.rs @@ -21,4 +21,3 @@ pub fn main() { let m = Foo(3); assert!(m.len() == 3); } - diff --git a/src/test/run-pass/auto-ref-slice-plus-ref.rs b/src/test/run-pass/auto-ref-slice-plus-ref.rs index 1dc56132875d4..58a477900c324 100644 --- a/src/test/run-pass/auto-ref-slice-plus-ref.rs +++ b/src/test/run-pass/auto-ref-slice-plus-ref.rs @@ -17,13 +17,13 @@ trait MyIter { } impl<'self> MyIter for &'self [int] { - fn test_imm(&self) { assert!(self[0] == 1) } - fn test_const(&const self) { assert!(self[0] == 1) } + fn test_imm(&self) { assert_eq!(self[0], 1) } + fn test_const(&const self) { assert_eq!(self[0], 1) } } impl<'self> MyIter for &'self str { - fn test_imm(&self) { assert!(*self == "test") } - fn test_const(&const self) { assert!(*self == "test") } + fn test_imm(&self) { assert_eq!(*self, "test") } + fn test_const(&const self) { assert_eq!(self[0], 't' as u8) } } pub fn main() { diff --git a/src/test/run-pass/auto-ref-sliceable.rs b/src/test/run-pass/auto-ref-sliceable.rs index 03e847e237d3a..f74d78f99d0b2 100644 --- a/src/test/run-pass/auto-ref-sliceable.rs +++ b/src/test/run-pass/auto-ref-sliceable.rs @@ -9,11 +9,11 @@ // except according to those terms. trait Pushable { - fn push_val(&mut self, +t: T); + fn push_val(&mut self, t: T); } impl Pushable for ~[T] { - fn push_val(&mut self, +t: T) { + fn push_val(&mut self, t: T) { self.push(t); } } diff --git a/src/test/run-pass/auto-ref.rs b/src/test/run-pass/auto-ref.rs index f7c0f513a9df6..ee250b972190c 100644 --- a/src/test/run-pass/auto-ref.rs +++ b/src/test/run-pass/auto-ref.rs @@ -26,4 +26,3 @@ pub fn main() { let x = Foo { x: 3 }; x.printme(); } - diff --git a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs index 883cffa792bfb..2bc6df4703042 100644 --- a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs +++ b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs @@ -22,4 +22,3 @@ fn g(x: &mut Foo) { pub fn main() { } - diff --git a/src/test/run-pass/bare-static-string.rs b/src/test/run-pass/bare-static-string.rs index d8015f0b92c7e..6208a9c3cc3e4 100644 --- a/src/test/run-pass/bare-static-string.rs +++ b/src/test/run-pass/bare-static-string.rs @@ -12,4 +12,3 @@ pub fn main() { let x: &'static str = "foo"; io::println(x); } - diff --git a/src/test/run-pass/bind-by-move.rs b/src/test/run-pass/bind-by-move.rs index d3d0e48f5b0f7..8752102c3a513 100644 --- a/src/test/run-pass/bind-by-move.rs +++ b/src/test/run-pass/bind-by-move.rs @@ -11,7 +11,7 @@ // xfail-fast extern mod std; use std::arc; -fn dispose(+_x: arc::ARC) { unsafe { } } +fn dispose(_x: arc::ARC) { unsafe { } } pub fn main() { let p = arc::ARC(true); diff --git a/src/test/run-pass/binops.rs b/src/test/run-pass/binops.rs index e7624c9e3b939..e755a34f0589e 100644 --- a/src/test/run-pass/binops.rs +++ b/src/test/run-pass/binops.rs @@ -104,7 +104,7 @@ fn p(x: int, y: int) -> p { fn test_class() { let mut q = p(1, 2); let mut r = p(1, 2); - + unsafe { error!("q = %x, r = %x", (::core::cast::transmute::<*p, uint>(&q)), diff --git a/src/test/run-pass/block-arg-in-parentheses.rs b/src/test/run-pass/block-arg-in-parentheses.rs index ce0b85f414b39..ad53bd2275451 100644 --- a/src/test/run-pass/block-arg-in-parentheses.rs +++ b/src/test/run-pass/block-arg-in-parentheses.rs @@ -33,4 +33,3 @@ pub fn main() { assert!(w_paren2(~[0, 1, 2, 3]) == -4); assert!(w_ret(~[0, 1, 2, 3]) == -4); } - diff --git a/src/test/run-pass/borrow-by-val-method-receiver.rs b/src/test/run-pass/borrow-by-val-method-receiver.rs index fdb51124f0eb9..fb4316ca1f520 100644 --- a/src/test/run-pass/borrow-by-val-method-receiver.rs +++ b/src/test/run-pass/borrow-by-val-method-receiver.rs @@ -20,4 +20,3 @@ pub fn main() { let items = ~[ 3, 5, 1, 2, 4 ]; items.foo(); } - diff --git a/src/test/run-pass/borrowck-lend-args.rs b/src/test/run-pass/borrowck-lend-args.rs index 0d51993e226ef..a912e1ef65c42 100644 --- a/src/test/run-pass/borrowck-lend-args.rs +++ b/src/test/run-pass/borrowck-lend-args.rs @@ -10,7 +10,7 @@ fn borrow(_v: &int) {} -fn borrow_from_arg_imm_ref(&&v: ~int) { +fn borrow_from_arg_imm_ref(v: ~int) { borrow(v); } @@ -18,7 +18,7 @@ fn borrow_from_arg_mut_ref(v: &mut ~int) { borrow(*v); } -fn borrow_from_arg_copy(+v: ~int) { +fn borrow_from_arg_copy(v: ~int) { borrow(v); } diff --git a/src/test/run-pass/borrowck-mut-uniq.rs b/src/test/run-pass/borrowck-mut-uniq.rs index 5f5b9c59d7680..023eaae0a7648 100644 --- a/src/test/run-pass/borrowck-mut-uniq.rs +++ b/src/test/run-pass/borrowck-mut-uniq.rs @@ -8,17 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + struct Ints {sum: ~int, values: ~[int]} fn add_int(x: &mut Ints, v: int) { *x.sum += v; let mut values = ~[]; - x.values <-> values; + util::swap(&mut values, &mut x.values); values.push(v); - x.values <-> values; + util::swap(&mut values, &mut x.values); } -fn iter_ints(x: &Ints, f: &fn(x: &int) -> bool) { +fn iter_ints(x: &Ints, f: &fn(x: &int) -> bool) -> bool { let l = x.values.len(); uint::range(0, l, |i| f(&x.values[i])) } diff --git a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs index 6929a98d9e1a9..8f66faab01451 100644 --- a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs @@ -14,7 +14,7 @@ fn want_slice(v: &[int]) -> int { return sum; } -fn has_mut_vec(+v: ~[int]) -> int { +fn has_mut_vec(v: ~[int]) -> int { want_slice(v) } diff --git a/src/test/compile-fail/liveness-assign-imm-local-in-swap.rs b/src/test/run-pass/borrowck-nested-calls.rs similarity index 53% rename from src/test/compile-fail/liveness-assign-imm-local-in-swap.rs rename to src/test/run-pass/borrowck-nested-calls.rs index 40ccfca919b67..4494f5f2fa337 100644 --- a/src/test/compile-fail/liveness-assign-imm-local-in-swap.rs +++ b/src/test/run-pass/borrowck-nested-calls.rs @@ -8,21 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test1() { - let v: int; - let mut w: int; - v = 1; //~ NOTE prior assignment occurs here - w = 2; - v <-> w; //~ ERROR re-assignment of immutable variable -} +// xfail-test #5074 nested method calls + +// Test that (safe) nested calls with `&mut` receivers are permitted. + +struct Foo {a: uint, b: uint} + +pub impl Foo { + fn inc_a(&mut self, v: uint) { self.a += v; } -fn test2() { - let v: int; - let mut w: int; - v = 1; //~ NOTE prior assignment occurs here - w = 2; - w <-> v; //~ ERROR re-assignment of immutable variable + fn next_b(&mut self) -> uint { + let b = self.b; + self.b += 1; + b + } } fn main() { + let mut f = Foo {a: 22, b: 23}; + f.inc_a(f.next_b()); + assert_eq!(f.a, 22+23); + assert_eq!(f.b, 24); } diff --git a/src/test/run-pass/borrowck-newtype-issue-2573.rs b/src/test/run-pass/borrowck-newtype-issue-2573.rs index 7724836b5db9e..5f0c7cad6191c 100644 --- a/src/test/run-pass/borrowck-newtype-issue-2573.rs +++ b/src/test/run-pass/borrowck-newtype-issue-2573.rs @@ -25,7 +25,7 @@ impl frob for foo { } // Override default mode so that we are passing by value -fn really_impure(++bar: baz) { +fn really_impure(bar: baz) { bar.baz = 3; } diff --git a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs new file mode 100644 index 0000000000000..59e82a038bc79 --- /dev/null +++ b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs @@ -0,0 +1,50 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that the scope of the pointer returned from `get()` is +// limited to the deref operation itself, and does not infect the +// block as a whole. + +struct Box { + x: uint +} + +impl Box { + fn get<'a>(&'a self) -> &'a uint { + &self.x + } + fn set(&mut self, x: uint) { + self.x = x; + } +} + +fn fun1() { + // in the past, borrow checker behaved differently when + // init and decl of `v` were distinct + let v; + let mut box = Box {x: 0}; + box.set(22); + v = *box.get(); + box.set(v+1); + assert_eq!(23, *box.get()); +} + +fn fun2() { + let mut box = Box {x: 0}; + box.set(22); + let v = *box.get(); + box.set(v+1); + assert_eq!(23, *box.get()); +} + +pub fn main() { + fun1(); + fun2(); +} \ No newline at end of file diff --git a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs new file mode 100644 index 0000000000000..056397f55ff26 --- /dev/null +++ b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs @@ -0,0 +1,41 @@ +// Issue #6272. Tests that freezing correctly accounts for all the +// implicit derefs that can occur. +// +// In this particular case, the expression: +// +// let x: &mut [int] = c[0]; +// +// is seen by borrowck as this sequence of derefs +// and pointer offsets: +// +// &*((**c)[0]) +// +// or, written using `x.*` for `*x` (so that everything +// is a postfix operation): +// +// &c.*.*.[0].* +// ^ ^ +// | | +// b a +// +// Here I also indicated where the evaluation yields the boxes `a` and +// `b`. It is important then that we only freeze the innermost box +// (`a`), and not the other ones (`b`, `c`). +// +// Also see the companion test: +// +// run-fail/borrowck-wg-autoderef-and-autoborrowvec-combined-fail-issue-6272.rs + + +fn main() { + let a = @mut [3i]; + let b = @mut [a]; + let c = @mut b; + + // this should freeze `a` only + let _x: &mut [int] = c[0]; + + // hence these writes should not fail: + b[0] = b[0]; + c[0] = c[0]; +} diff --git a/src/test/run-pass/borrowck-wg-simple.rs b/src/test/run-pass/borrowck-wg-simple.rs index adf2403ec63d6..f28b0e4c4ec13 100644 --- a/src/test/run-pass/borrowck-wg-simple.rs +++ b/src/test/run-pass/borrowck-wg-simple.rs @@ -6,4 +6,3 @@ pub fn main() { let x = @mut 3; f(x); } - diff --git a/src/test/run-pass/borrowck-wg-two-imm-borrows.rs b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs new file mode 100644 index 0000000000000..20f824e969a48 --- /dev/null +++ b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs @@ -0,0 +1,14 @@ +// Test that we can borrow the same @mut box twice, so long as both are imm. + +fn add(x:&int, y:&int) +{ + *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&z[0], &z2[0]); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-pass/boxed-trait-with-vstore.rs b/src/test/run-pass/boxed-trait-with-vstore.rs index 1aac86238dc58..1313a17f81db0 100644 --- a/src/test/run-pass/boxed-trait-with-vstore.rs +++ b/src/test/run-pass/boxed-trait-with-vstore.rs @@ -22,4 +22,3 @@ pub fn main() { let x = @3 as @Foo; x.foo(); } - diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index b3f524c0ad713..a182dcf2ca0b2 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - pub fn main() { let mut i = 0; while i < 20 { i += 1; if i == 10 { break; } } @@ -22,8 +20,8 @@ pub fn main() { i = 0; while i < 10 { i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); } i = 0; - loop { - i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); + loop { + i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); if i >= 10 { break; } } for vec::each(~[1, 2, 3, 4, 5, 6]) |x| { diff --git a/src/test/run-pass/capture_nil.rs b/src/test/run-pass/capture_nil.rs index 99d8fab4bba50..817891c114640 100644 --- a/src/test/run-pass/capture_nil.rs +++ b/src/test/run-pass/capture_nil.rs @@ -26,7 +26,7 @@ use core::comm::*; -fn foo(&&x: ()) -> Port<()> { +fn foo(x: ()) -> Port<()> { let (p, c) = stream::<()>(); do task::spawn() { c.send(x); diff --git a/src/test/run-pass/child-outlives-parent.rs b/src/test/run-pass/child-outlives-parent.rs index 50c6b82114326..4eb3cea3a2586 100644 --- a/src/test/run-pass/child-outlives-parent.rs +++ b/src/test/run-pass/child-outlives-parent.rs @@ -12,6 +12,8 @@ extern mod std; -fn child2(&&s: ~str) { } +fn child2(s: ~str) { } -pub fn main() { let x = task::spawn(|| child2(~"hi") ); } +pub fn main() { + let x = task::spawn(|| child2(~"hi")); +} diff --git a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs index 68bc567cf5108..76f4e3b68f7c2 100644 --- a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs @@ -24,4 +24,3 @@ pub fn main() { let nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr; print_out(nyan, ~"nyan"); } - diff --git a/src/test/run-pass/class-impl-parameterized-trait.rs b/src/test/run-pass/class-impl-parameterized-trait.rs index 53ae0021a91b9..04784b5c51507 100644 --- a/src/test/run-pass/class-impl-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-parameterized-trait.rs @@ -48,7 +48,7 @@ class cat : map { } fn size() -> uint { self.meows as uint } - fn insert(+k: int, +v: bool) -> bool { + fn insert(+k: int, +v: bool) -> bool { if v { self.meows += k; } else { self.meows -= k; }; true } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index cf887758bff7d..39d4b25f262be 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -59,25 +59,26 @@ impl Mutable for cat { } impl Map for cat { - fn each<'a>(&'a self, f: &fn(&int, &'a T) -> bool) { + fn each<'a>(&'a self, f: &fn(&int, &'a T) -> bool) -> bool { let mut n = int::abs(self.meows); while n > 0 { - if !f(&n, &self.name) { break; } + if !f(&n, &self.name) { return false; } n -= 1; } + return true; } fn contains_key(&self, k: &int) -> bool { *k <= self.meows } - fn each_key(&self, f: &fn(v: &int) -> bool) { - for self.each |k, _| { if !f(k) { break; } loop;}; + fn each_key(&self, f: &fn(v: &int) -> bool) -> bool { + self.each(|k, _| f(k)) } - fn each_value<'a>(&'a self, f: &fn(v: &'a T) -> bool) { - for self.each |_, v| { if !f(v) { break; } loop;}; + fn each_value<'a>(&'a self, f: &fn(v: &'a T) -> bool) -> bool { + self.each(|_, v| f(v)) } - fn mutate_values(&mut self, _f: &fn(&int, &mut T) -> bool) { + fn mutate_values(&mut self, _f: &fn(&int, &mut T) -> bool) -> bool { fail!(~"nope") } @@ -103,6 +104,10 @@ impl Map for cat { false } } + + fn pop(&mut self, _k: &int) -> Option { fail!() } + + fn swap(&mut self, _k: int, _v: T) -> Option { fail!() } } pub impl cat { diff --git a/src/test/run-pass/class-poly-methods.rs b/src/test/run-pass/class-poly-methods.rs index adcab8b40aa47..9774d8d14882e 100644 --- a/src/test/run-pass/class-poly-methods.rs +++ b/src/test/run-pass/class-poly-methods.rs @@ -22,7 +22,7 @@ pub impl cat { fn meow_count(&mut self) -> uint { self.meows } } -fn cat(in_x : uint, in_y : int, +in_info: ~[U]) -> cat { +fn cat(in_x : uint, in_y : int, in_info: ~[U]) -> cat { cat { meows: in_x, how_hungry: in_y, diff --git a/src/test/run-pass/cleanup-copy-mode.rs b/src/test/run-pass/cleanup-copy-mode.rs index 41f76b1b4f2f3..cb378da13ea60 100644 --- a/src/test/run-pass/cleanup-copy-mode.rs +++ b/src/test/run-pass/cleanup-copy-mode.rs @@ -9,11 +9,10 @@ // except according to those terms. // xfail-win32 -fn adder(+x: @int, +y: @int) -> int { return *x + *y; } +fn adder(x: @int, y: @int) -> int { return *x + *y; } fn failer() -> @int { fail!(); } pub fn main() { assert!(result::is_err(&task::try(|| { adder(@2, failer()); () }))); } - diff --git a/src/test/run-pass/clone-with-exterior.rs b/src/test/run-pass/clone-with-exterior.rs index 57c4f91142dd8..ae2983b159425 100644 --- a/src/test/run-pass/clone-with-exterior.rs +++ b/src/test/run-pass/clone-with-exterior.rs @@ -18,7 +18,7 @@ struct Pair { pub fn main() { let z = ~Pair { a : 10, b : 12}; - + let f: ~fn() = || { assert!((z.a == 10)); assert!((z.b == 12)); diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs index 0e67532d7a1fc..b0d06dae10dc0 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -1,10 +1,10 @@ trait Reverser { - fn reverse(&self); + fn reverse(self); } impl<'self> Reverser for &'self mut [uint] { - fn reverse(&self) { - vec::reverse(*self); + fn reverse(self) { + vec::reverse(self); } } diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 609bfe7a4cb2a..73fdb219c1941 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -27,7 +27,7 @@ mod rustrt { // module was translated pub fn bogus(); } - + #[abi = "cdecl"] pub extern {} } diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 01bab0778329f..4c81eaae1d802 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -14,7 +14,7 @@ static C0: E = C[0]; static C1: E = C[1]; pub fn main() { - match C0 { + match C0 { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-enum-vec-ptr.rs b/src/test/run-pass/const-enum-vec-ptr.rs index 8615356965e35..95c4ed836c769 100644 --- a/src/test/run-pass/const-enum-vec-ptr.rs +++ b/src/test/run-pass/const-enum-vec-ptr.rs @@ -16,7 +16,7 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } - match C[2] { + match C[2] { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-enum-vector.rs b/src/test/run-pass/const-enum-vector.rs index 7ae2c5a2fee7c..3dc5b918f7f58 100644 --- a/src/test/run-pass/const-enum-vector.rs +++ b/src/test/run-pass/const-enum-vector.rs @@ -16,7 +16,7 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } - match C[2] { + match C[2] { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-expr-in-fixed-length-vec.rs b/src/test/run-pass/const-expr-in-fixed-length-vec.rs index c593fd39aaacd..48b41d0463307 100644 --- a/src/test/run-pass/const-expr-in-fixed-length-vec.rs +++ b/src/test/run-pass/const-expr-in-fixed-length-vec.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that constant expressions can be used for declaring the +// Check that constant expressions can be used for declaring the // type of a fixed length vector. pub fn main() { diff --git a/src/test/run-pass/const-expr-in-vec-repeat.rs b/src/test/run-pass/const-expr-in-vec-repeat.rs index be54c6eb7be49..f10cef520ad24 100644 --- a/src/test/run-pass/const-expr-in-vec-repeat.rs +++ b/src/test/run-pass/const-expr-in-vec-repeat.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that constant expressions can be used in vec repeat syntax. +// Check that constant expressions can be used in vec repeat syntax. pub fn main() { diff --git a/src/test/run-pass/const-tuple-struct.rs b/src/test/run-pass/const-tuple-struct.rs index a68e12b7b107a..828c20912a1cb 100644 --- a/src/test/run-pass/const-tuple-struct.rs +++ b/src/test/run-pass/const-tuple-struct.rs @@ -20,4 +20,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/const-unit-struct.rs b/src/test/run-pass/const-unit-struct.rs index b4acde098baf3..7e6d9f0bee9b9 100644 --- a/src/test/run-pass/const-unit-struct.rs +++ b/src/test/run-pass/const-unit-struct.rs @@ -17,4 +17,3 @@ pub fn main() { Foo => {} } } - diff --git a/src/test/run-pass/const-vec-syntax.rs b/src/test/run-pass/const-vec-syntax.rs index c3e882ac04f9e..625f6ec30cc13 100644 --- a/src/test/run-pass/const-vec-syntax.rs +++ b/src/test/run-pass/const-vec-syntax.rs @@ -14,4 +14,3 @@ pub fn main() { let v = [ 1, 2, 3 ]; f(v); } - diff --git a/src/test/run-pass/consts-in-patterns.rs b/src/test/run-pass/consts-in-patterns.rs index 408c0e612f431..c0520cf737ffc 100644 --- a/src/test/run-pass/consts-in-patterns.rs +++ b/src/test/run-pass/consts-in-patterns.rs @@ -20,4 +20,3 @@ pub fn main() { }; assert!(y == 2); } - diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs new file mode 100644 index 0000000000000..a4f3f59f46baa --- /dev/null +++ b/src/test/run-pass/core-run-destroy.rs @@ -0,0 +1,89 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-fast +// compile-flags:--test + +// NB: These tests kill child processes. Valgrind sees these children as leaking +// memory, which makes for some *confusing* logs. That's why these are here +// instead of in core. + +use core::run; +use core::run::*; + +#[test] +fn test_destroy_once() { + let mut p = run::start_program("echo", []); + p.destroy(); // this shouldn't crash (and nor should the destructor) +} + +#[test] +fn test_destroy_twice() { + let mut p = run::start_program("echo", []); + p.destroy(); // this shouldnt crash... + p.destroy(); // ...and nor should this (and nor should the destructor) +} + +fn test_destroy_actually_kills(force: bool) { + + #[cfg(unix)] + static BLOCK_COMMAND: &'static str = "cat"; + + #[cfg(windows)] + static BLOCK_COMMAND: &'static str = "cmd"; + + #[cfg(unix)] + fn process_exists(pid: libc::pid_t) -> bool { + run::program_output("ps", [~"-p", pid.to_str()]).out.contains(pid.to_str()) + } + + #[cfg(windows)] + fn process_exists(pid: libc::pid_t) -> bool { + + use core::libc::types::os::arch::extra::DWORD; + use core::libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess}; + use core::libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE }; + + unsafe { + let proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + return false; + } + // proc will be non-null if the process is alive, or if it died recently + let mut status = 0; + GetExitCodeProcess(proc, &mut status); + CloseHandle(proc); + return status == STILL_ACTIVE; + } + } + + // this program will stay alive indefinitely trying to read from stdin + let mut p = run::start_program(BLOCK_COMMAND, []); + + assert!(process_exists(p.get_id())); + + if force { + p.force_destroy(); + } else { + p.destroy(); + } + + assert!(!process_exists(p.get_id())); +} + +#[test] +fn test_unforced_destroy_actually_kills() { + test_destroy_actually_kills(false); +} + +#[test] +fn test_forced_destroy_actually_kills() { + test_destroy_actually_kills(true); +} diff --git a/src/test/run-pass/cycle-collection.rs b/src/test/run-pass/cycle-collection.rs index 0512b8a1267cf..0e9be022113d6 100644 --- a/src/test/run-pass/cycle-collection.rs +++ b/src/test/run-pass/cycle-collection.rs @@ -21,4 +21,3 @@ fn f() { pub fn main() { f(); } - diff --git a/src/test/run-pass/default-method-simple.rs b/src/test/run-pass/default-method-simple.rs index 62b29d4e4eb2f..3f44f3f1ef88c 100644 --- a/src/test/run-pass/default-method-simple.rs +++ b/src/test/run-pass/default-method-simple.rs @@ -32,4 +32,3 @@ pub fn main() { let a = A { x: 1 }; a.f(); } - diff --git a/src/test/run-pass/deriving-clone-enum.rs b/src/test/run-pass/deriving-clone-enum.rs index 6caceeb2d7015..969e1fb5dd60e 100644 --- a/src/test/run-pass/deriving-clone-enum.rs +++ b/src/test/run-pass/deriving-clone-enum.rs @@ -16,4 +16,3 @@ enum E { } pub fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-enum.rs b/src/test/run-pass/deriving-clone-generic-enum.rs index a868db2425cc2..23841017e933e 100644 --- a/src/test/run-pass/deriving-clone-generic-enum.rs +++ b/src/test/run-pass/deriving-clone-generic-enum.rs @@ -6,4 +6,3 @@ enum E { } fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-struct.rs b/src/test/run-pass/deriving-clone-generic-struct.rs index b157cd321cf5a..0a7a5a3aa7549 100644 --- a/src/test/run-pass/deriving-clone-generic-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-struct.rs @@ -16,4 +16,3 @@ struct S { } pub fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs index aeaa9ed726d2b..d6a69e8e6ac52 100644 --- a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs @@ -2,4 +2,3 @@ struct S(T, ()); fn main() {} - diff --git a/src/test/run-pass/deriving-clone-tuple-struct.rs b/src/test/run-pass/deriving-clone-tuple-struct.rs index c534883f600ce..1e5c8c80f8c49 100644 --- a/src/test/run-pass/deriving-clone-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-tuple-struct.rs @@ -12,4 +12,3 @@ struct S((), ()); pub fn main() {} - diff --git a/src/libcore/rt/io/net/mod.rs b/src/test/run-pass/deriving-rand.rs similarity index 51% rename from src/libcore/rt/io/net/mod.rs rename to src/test/run-pass/deriving-rand.rs index 130ff6b38fa82..dd4664e7446fb 100644 --- a/src/libcore/rt/io/net/mod.rs +++ b/src/test/run-pass/deriving-rand.rs @@ -1,3 +1,4 @@ +// xfail-fast #6330 // 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. @@ -8,24 +9,31 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; +#[deriving(Rand)] +struct A; -pub mod tcp; -pub mod udp; -pub mod ip; -#[cfg(unix)] -pub mod unix; -pub mod http; +#[deriving(Rand)] +struct B(int, int); -/// A listener is a value that listens for connections -pub trait Listener { - /// Wait for and accept an incoming connection - /// - /// Returns `None` on timeout. - /// - /// # Failure - /// - /// Raises `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option; +#[deriving(Rand)] +struct C { + x: f64, + y: (u8, u8) } + +#[deriving(Rand)] +enum D { + D0, + D1(uint), + D2 { x: (), y: () } +} + +fn main() { + // check there's no segfaults + for 20.times { + rand::random::(); + rand::random::(); + rand::random::(); + rand::random::(); + } +} \ No newline at end of file diff --git a/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs new file mode 100644 index 0000000000000..b0b03d8419b8c --- /dev/null +++ b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs @@ -0,0 +1,32 @@ +// xfail-test FIXME #6257 + +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::cmp::{Less,Equal,Greater}; + +#[deriving(TotalEq,TotalOrd)] +struct A<'self> { + x: &'self int +} + +fn main() { + let a = A { x: &1 }, b = A { x: &2 }; + + assert!(a.equals(&a)); + assert!(b.equals(&b)); + + + assert_eq!(a.cmp(&a), Equal); + assert_eq!(b.cmp(&b), Equal); + + assert_eq!(a.cmp(&b), Less); + assert_eq!(b.cmp(&a), Greater); +} diff --git a/src/test/run-pass/deriving-self-lifetime.rs b/src/test/run-pass/deriving-self-lifetime.rs new file mode 100644 index 0000000000000..549a9b398a219 --- /dev/null +++ b/src/test/run-pass/deriving-self-lifetime.rs @@ -0,0 +1,33 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq,Ord)] +struct A<'self> { + x: &'self int +} + +fn main() { + let a = A { x: &1 }, b = A { x: &2 }; + + assert_eq!(a, a); + assert_eq!(b, b); + + + assert!(a < b); + assert!(b > a); + + assert!(a <= b); + assert!(a <= a); + assert!(b <= b); + + assert!(b >= a); + assert!(b >= b); + assert!(a >= a); +} diff --git a/src/test/run-pass/deriving-to-str.rs b/src/test/run-pass/deriving-to-str.rs new file mode 100644 index 0000000000000..4b98f9a73c586 --- /dev/null +++ b/src/test/run-pass/deriving-to-str.rs @@ -0,0 +1,45 @@ +// xfail-fast #6330 +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Rand,ToStr)] +struct A; + +#[deriving(Rand,ToStr)] +struct B(int, int); + +#[deriving(Rand,ToStr)] +struct C { + x: f64, + y: (u8, u8) +} + +#[deriving(Rand,ToStr)] +enum D { + D0, + D1(uint), + D2 { x: (), y: () } +} + +fn main() { + macro_rules! t( + ($ty:ty) => {{ + let x =rand::random::<$ty>(); + assert_eq!(x.to_str(), fmt!("%?", x)); + }} + ); + + for 20.times { + t!(A); + t!(B); + t!(C); + t!(D); + } +} \ No newline at end of file diff --git a/src/test/run-pass/deriving-via-extension-c-enum.rs b/src/test/run-pass/deriving-via-extension-c-enum.rs index 67893ae9c1eec..81c4ce013f24c 100644 --- a/src/test/run-pass/deriving-via-extension-c-enum.rs +++ b/src/test/run-pass/deriving-via-extension-c-enum.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-enum.rs b/src/test/run-pass/deriving-via-extension-enum.rs index 7481bae508b68..fac0d402a3826 100644 --- a/src/test/run-pass/deriving-via-extension-enum.rs +++ b/src/test/run-pass/deriving-via-extension-enum.rs @@ -22,4 +22,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs index 5ceb8c48750d9..b08117b71fa2f 100644 --- a/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs @@ -25,4 +25,3 @@ enum A { } pub fn main(){} - diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs index 9f18cb6ac58a7..8369d12ecddcb 100644 --- a/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs @@ -18,5 +18,3 @@ struct Foo { } pub fn main() {} - - diff --git a/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs index 712767efacfa0..4ef8fb6b5d9b7 100644 --- a/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs +++ b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs @@ -9,4 +9,3 @@ pub fn main() { assert!(x == x); assert!(!(x != x)); } - diff --git a/src/test/run-pass/deriving-via-extension-struct.rs b/src/test/run-pass/deriving-via-extension-struct.rs index 1e004d1a8c00a..c0e7ee36b16da 100644 --- a/src/test/run-pass/deriving-via-extension-struct.rs +++ b/src/test/run-pass/deriving-via-extension-struct.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-type-params.rs b/src/test/run-pass/deriving-via-extension-type-params.rs index f310643f94393..85a89c629895d 100644 --- a/src/test/run-pass/deriving-via-extension-type-params.rs +++ b/src/test/run-pass/deriving-via-extension-type-params.rs @@ -26,4 +26,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/do-for-empty-args.rs b/src/test/run-pass/do-for-empty-args.rs index c86c1768111f7..fb1bc37fd5efa 100644 --- a/src/test/run-pass/do-for-empty-args.rs +++ b/src/test/run-pass/do-for-empty-args.rs @@ -11,14 +11,15 @@ // no-reformat // Testing various forms of `do` and `for` with empty arg lists -fn f(f: &fn() -> bool) { +fn f(f: &fn() -> bool) -> bool { + true } pub fn main() { - do f() || { true } - do f() { true } - do f || { true } - do f { true } + do f() || { true }; + do f() { true }; + do f || { true }; + do f { true }; for f() || { } for f() { } for f || { } diff --git a/src/test/run-pass/do-for-no-args.rs b/src/test/run-pass/do-for-no-args.rs index c89d693c81635..e9d7c946a9a11 100644 --- a/src/test/run-pass/do-for-no-args.rs +++ b/src/test/run-pass/do-for-no-args.rs @@ -10,7 +10,7 @@ // Testing that we can drop the || in for/do exprs -fn f(f: @fn() -> bool) { } +fn f(f: @fn() -> bool) -> bool { true } fn d(f: @fn()) { } diff --git a/src/test/run-pass/drop-trait-generic.rs b/src/test/run-pass/drop-trait-generic.rs index 21b85084117c4..65c3faac2b304 100644 --- a/src/test/run-pass/drop-trait-generic.rs +++ b/src/test/run-pass/drop-trait-generic.rs @@ -22,4 +22,3 @@ impl ::core::ops::Drop for S { pub fn main() { let x = S { x: 1 }; } - diff --git a/src/test/run-pass/drop-trait.rs b/src/test/run-pass/drop-trait.rs index 3eddda376a836..b516c6f6de4bd 100644 --- a/src/test/run-pass/drop-trait.rs +++ b/src/test/run-pass/drop-trait.rs @@ -21,4 +21,3 @@ impl Drop for Foo { pub fn main() { let x: Foo = Foo { x: 3 }; } - diff --git a/src/test/run-pass/dupe-first-attr.rc b/src/test/run-pass/dupe-first-attr.rc index d39a2aa447623..9bd63a8d646d3 100644 --- a/src/test/run-pass/dupe-first-attr.rc +++ b/src/test/run-pass/dupe-first-attr.rc @@ -25,3 +25,5 @@ mod hello; #[cfg(target_os = "android")] mod hello; + +fn main() { } \ No newline at end of file diff --git a/src/test/run-pass/enum-discrim-range-overflow.rs b/src/test/run-pass/enum-discrim-range-overflow.rs index a6806fba14269..37e457d547bf9 100644 --- a/src/test/run-pass/enum-discrim-range-overflow.rs +++ b/src/test/run-pass/enum-discrim-range-overflow.rs @@ -9,23 +9,23 @@ // except according to those terms. pub enum E64 { - H64 = 0x7FFF_FFFF_FFFF_FFFF, - L64 = 0x8000_0000_0000_0000 + H64 = 0x7FFF_FFFF_FFFF_FFFF, + L64 = 0x8000_0000_0000_0000 } pub enum E32 { - H32 = 0x7FFF_FFFF, - L32 = 0x8000_0000 + H32 = 0x7FFF_FFFF, + L32 = 0x8000_0000 } pub fn f(e64: E64, e32: E32) -> (bool,bool) { - (match e64 { - H64 => true, - L64 => false - }, - match e32 { - H32 => true, - L32 => false - }) + (match e64 { + H64 => true, + L64 => false + }, + match e32 { + H32 => true, + L32 => false + }) } pub fn main() { } diff --git a/src/test/run-pass/enum-disr-val-pretty.rs b/src/test/run-pass/enum-disr-val-pretty.rs index 39a807789ecec..2c61351cf44a5 100644 --- a/src/test/run-pass/enum-disr-val-pretty.rs +++ b/src/test/run-pass/enum-disr-val-pretty.rs @@ -23,4 +23,3 @@ fn test_color(color: color, val: int, name: ~str) { assert!(color as int == val); assert!(color as float == val as float); } - diff --git a/src/test/run-pass/enum-export-inheritance.rs b/src/test/run-pass/enum-export-inheritance.rs index c3beebdb8ae85..49823155043f4 100644 --- a/src/test/run-pass/enum-export-inheritance.rs +++ b/src/test/run-pass/enum-export-inheritance.rs @@ -19,4 +19,3 @@ mod a { pub fn main() { let x = a::Bar; } - diff --git a/src/test/run-pass/issue-1989.rs b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs similarity index 50% rename from src/test/run-pass/issue-1989.rs rename to src/test/run-pass/enum-nullable-simplifycfg-misopt.rs index e3327283a8162..4764dbb9417fb 100644 --- a/src/test/run-pass/issue-1989.rs +++ b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,26 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// exec-env:RUST_CC_ZEAL=1 - -enum maybe_pointy { - none, - p(@mut Pointy) -} - -struct Pointy { - a : maybe_pointy, - f : @fn()->(), -} - -fn empty_pointy() -> @mut Pointy { - return @mut Pointy{ - a : none, - f : || {}, - } -} +/*! + * This is a regression test for a bug in LLVM, fixed in upstream r179587, + * where the switch instructions generated for destructuring enums + * represented with nullable pointers could be misoptimized in some cases. + */ +enum List { Nil, Cons(X, @List) } pub fn main() { - let v = ~[empty_pointy(), empty_pointy()]; - v[0].a = p(v[0]); + match Cons(10, @Nil) { + Cons(10, _) => {} + Nil => {} + _ => fail!() + } } diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index 1a2a8cab3032c..ac19592accf8b 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -40,4 +40,3 @@ pub fn main() { let mut m = ~linear_map::<(),()>(); assert!(m.len() == 0); } - diff --git a/src/test/run-pass/explicit-self-objects-box.rs b/src/test/run-pass/explicit-self-objects-box.rs index 105aad03083d7..12a1780e029b1 100644 --- a/src/test/run-pass/explicit-self-objects-box.rs +++ b/src/test/run-pass/explicit-self-objects-box.rs @@ -30,5 +30,3 @@ pub fn main() { y.f(); y.f(); } - - diff --git a/src/test/run-pass/explicit-self-objects-simple.rs b/src/test/run-pass/explicit-self-objects-simple.rs index de2926b0e7efc..814365a835429 100644 --- a/src/test/run-pass/explicit-self-objects-simple.rs +++ b/src/test/run-pass/explicit-self-objects-simple.rs @@ -27,5 +27,3 @@ pub fn main() { let y = x as @Foo; y.f(); } - - diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index e99a6bbedc06c..dadf53fb9bc6a 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -27,5 +27,3 @@ pub fn main() { let y = x as ~Foo; y.f(); } - - diff --git a/src/test/run-pass/explicit_self_xcrate_exe.rs b/src/test/run-pass/explicit_self_xcrate_exe.rs index e217e6ebd411d..6f6520e804043 100644 --- a/src/test/run-pass/explicit_self_xcrate_exe.rs +++ b/src/test/run-pass/explicit_self_xcrate_exe.rs @@ -18,4 +18,3 @@ pub fn main() { let x = Bar { x: ~"hello" }; x.f(); } - diff --git a/src/test/run-pass/expr-repeat-vstore.rs b/src/test/run-pass/expr-repeat-vstore.rs index 972b2763b1b59..e48abc5753492 100644 --- a/src/test/run-pass/expr-repeat-vstore.rs +++ b/src/test/run-pass/expr-repeat-vstore.rs @@ -20,4 +20,3 @@ fn main() { println((copy v[3]).to_str()); println((copy v[4]).to_str()); } - diff --git a/src/test/run-pass/extern-mod-abi.rs b/src/test/run-pass/extern-mod-abi.rs index 7eada51b7c719..84fd1b40bf7a5 100644 --- a/src/test/run-pass/extern-mod-abi.rs +++ b/src/test/run-pass/extern-mod-abi.rs @@ -13,4 +13,3 @@ extern "C" { } pub fn main() {} - diff --git a/src/test/run-pass/extern-mod-ordering-exe.rs b/src/test/run-pass/extern-mod-ordering-exe.rs index b60302277b326..5836245ff78cf 100644 --- a/src/test/run-pass/extern-mod-ordering-exe.rs +++ b/src/test/run-pass/extern-mod-ordering-exe.rs @@ -8,4 +8,3 @@ use extern_mod_ordering_lib::extern_mod_ordering_lib; fn main() { extern_mod_ordering_lib::f(); } - diff --git a/src/test/run-pass/extern-mod-syntax.rs b/src/test/run-pass/extern-mod-syntax.rs index b6b2e0042633d..c98b5ebc23854 100644 --- a/src/test/run-pass/extern-mod-syntax.rs +++ b/src/test/run-pass/extern-mod-syntax.rs @@ -16,4 +16,3 @@ use std::json::Object; pub fn main() { io::println("Hello world!"); } - diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index f0343c4d2a267..ec65cbb5670b9 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 16d14a96cfe4f..6ac5967c54fd5 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -27,4 +27,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU64s-ref.rs b/src/test/run-pass/extern-pass-TwoU64s-ref.rs index 56d3f8ebbff7f..19b99eaccc956 100644 --- a/src/test/run-pass/extern-pass-TwoU64s-ref.rs +++ b/src/test/run-pass/extern-pass-TwoU64s-ref.rs @@ -16,7 +16,7 @@ struct TwoU64s { } pub extern { - pub fn rust_dbg_extern_identity_TwoU64s(&&u: TwoU64s) -> TwoU64s; + pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s; } pub fn main() { @@ -26,4 +26,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index 24dd3db8aca1c..cd6226b61c984 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -13,7 +13,7 @@ // xfail-fast This works standalone on windows but not with check-fast. // possibly because there is another test that uses this extern fn but gives it -// a diferent signature +// a different signature #[deriving(Eq)] struct TwoU64s { @@ -31,4 +31,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index 213e9a68a7f89..7d08b436908dc 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index f4fa6bde392b9..645396e5a988d 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u8 == rust_dbg_extern_identity_u8(22_u8)); } } - diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index 4e16acb4ad580..3a6dd26a9dc6c 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -17,4 +17,3 @@ pub fn main() { assert!(22.0_f64 == rust_dbg_extern_identity_double(22.0_f64)); } } - diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index 14d05f821770a..19c4d6e153998 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u32 == rust_dbg_extern_identity_u32(22_u32)); } } - diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 2b5a03a4d7122..cce669999222a 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u64 == rust_dbg_extern_identity_u64(22_u64)); } } - diff --git a/src/test/run-pass/extern-pub.rs b/src/test/run-pass/extern-pub.rs index 9bfeec8c7d6ce..1cd709ee91b9d 100644 --- a/src/test/run-pass/extern-pub.rs +++ b/src/test/run-pass/extern-pub.rs @@ -1,10 +1,8 @@ extern { - pub unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc, - ++v: **vec::raw::VecRepr, - ++n: libc::size_t); + pub unsafe fn vec_reserve_shared_actual(t: *sys::TypeDesc, + v: **vec::raw::VecRepr, + n: libc::size_t); } pub fn main() { } - - diff --git a/src/test/run-pass/fat-arrow-alt.rs b/src/test/run-pass/fat-arrow-alt.rs index 4b8b552bfaed3..f6b49960fad70 100644 --- a/src/test/run-pass/fat-arrow-alt.rs +++ b/src/test/run-pass/fat-arrow-alt.rs @@ -23,4 +23,3 @@ pub fn main() { blue => { 3 } }); } - diff --git a/src/test/run-pass/fixed_length_copy.rs b/src/test/run-pass/fixed_length_copy.rs index 5daa525d9b161..7ee3f5173b030 100644 --- a/src/test/run-pass/fixed_length_copy.rs +++ b/src/test/run-pass/fixed_length_copy.rs @@ -10,7 +10,7 @@ // error on implicit copies to check fixed length vectors -// are implicitly copyable +// are implicitly copyable #[deny(implicit_copies)] pub fn main() { let arr = [1,2,3]; diff --git a/src/test/run-pass/float-literal-inference.rs b/src/test/run-pass/float-literal-inference.rs index 2b59d7bfceeb2..a5246eef0b0ed 100644 --- a/src/test/run-pass/float-literal-inference.rs +++ b/src/test/run-pass/float-literal-inference.rs @@ -20,4 +20,3 @@ pub fn main() { let z = S { z: 1.0 }; io::println(z.z.to_str()); } - diff --git a/src/test/run-pass/fn-bare-spawn.rs b/src/test/run-pass/fn-bare-spawn.rs index 857a8cdb3d02f..b78bd488bc6ea 100644 --- a/src/test/run-pass/fn-bare-spawn.rs +++ b/src/test/run-pass/fn-bare-spawn.rs @@ -14,7 +14,7 @@ fn spawn(val: T, f: extern fn(T)) { f(val); } -fn f(+i: int) { +fn f(i: int) { assert!(i == 100); } diff --git a/src/test/run-pass/fn-pattern-expected-type-2.rs b/src/test/run-pass/fn-pattern-expected-type-2.rs index f9bf9b5915eb1..501bd81d5589c 100644 --- a/src/test/run-pass/fn-pattern-expected-type-2.rs +++ b/src/test/run-pass/fn-pattern-expected-type-2.rs @@ -15,4 +15,3 @@ pub fn main() { io::println(x.to_str()); } } - diff --git a/src/test/run-pass/fn-pattern-expected-type.rs b/src/test/run-pass/fn-pattern-expected-type.rs index dc3f33a1991a4..f3949a0f43bf3 100644 --- a/src/test/run-pass/fn-pattern-expected-type.rs +++ b/src/test/run-pass/fn-pattern-expected-type.rs @@ -15,4 +15,3 @@ pub fn main() { }; f((1, 2)); } - diff --git a/src/test/run-pass/foreign-mod-unused-const.rs b/src/test/run-pass/foreign-mod-unused-const.rs index 430da7a3f608b..4909e9d7e568f 100644 --- a/src/test/run-pass/foreign-mod-unused-const.rs +++ b/src/test/run-pass/foreign-mod-unused-const.rs @@ -17,4 +17,3 @@ mod foo { pub fn main() { } - diff --git a/src/test/run-pass/foreign-struct.rs b/src/test/run-pass/foreign-struct.rs index 9ac17c27ed4ad..2dbc60e9a14ac 100644 --- a/src/test/run-pass/foreign-struct.rs +++ b/src/test/run-pass/foreign-struct.rs @@ -18,7 +18,7 @@ mod bindgen { #[nolink] pub extern { - pub fn printf(++v: void); + pub fn printf(v: void); } } diff --git a/src/test/run-pass/functional-struct-update.rs b/src/test/run-pass/functional-struct-update.rs index f1db6db417a23..297b5e78a921c 100644 --- a/src/test/run-pass/functional-struct-update.rs +++ b/src/test/run-pass/functional-struct-update.rs @@ -18,4 +18,3 @@ pub fn main() { let c = Foo { x: 4, .. a}; io::println(fmt!("%?", c)); } - diff --git a/src/test/run-pass/generic-ivec-leak.rs b/src/test/run-pass/generic-ivec-leak.rs index 8d9b0fa6ddb85..ac6e3e1a69a99 100644 --- a/src/test/run-pass/generic-ivec-leak.rs +++ b/src/test/run-pass/generic-ivec-leak.rs @@ -11,4 +11,3 @@ enum wrapper { wrapped(T), } pub fn main() { let w = wrapped(~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/generic-ivec.rs b/src/test/run-pass/generic-ivec.rs index 031821d990965..2a288c8abbf35 100644 --- a/src/test/run-pass/generic-ivec.rs +++ b/src/test/run-pass/generic-ivec.rs @@ -10,4 +10,3 @@ fn f(v: @T) { } pub fn main() { f(@~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/generic-newtype-struct.rs b/src/test/run-pass/generic-newtype-struct.rs index 7c7d73eda1092..cf4279d67b84d 100644 --- a/src/test/run-pass/generic-newtype-struct.rs +++ b/src/test/run-pass/generic-newtype-struct.rs @@ -4,4 +4,3 @@ pub fn main() { let s = S(2i); io::println(s.to_str()); } - diff --git a/src/test/run-pass/generic-object.rs b/src/test/run-pass/generic-object.rs index ebfc362c72c43..54ae2c58e42ea 100644 --- a/src/test/run-pass/generic-object.rs +++ b/src/test/run-pass/generic-object.rs @@ -27,4 +27,3 @@ pub fn main() { let y = x as @Foo; assert!(y.get() == 1); } - diff --git a/src/test/run-pass/global-scope.rs b/src/test/run-pass/global-scope.rs index 3dd912dea9a13..9b292a325c03a 100644 --- a/src/test/run-pass/global-scope.rs +++ b/src/test/run-pass/global-scope.rs @@ -18,4 +18,3 @@ pub mod foo { } pub fn main() { return foo::g(); } - diff --git a/src/test/run-pass/impl-privacy-xc-1.rs b/src/test/run-pass/impl-privacy-xc-1.rs index df001c7ab212e..19d3caf818d19 100644 --- a/src/test/run-pass/impl-privacy-xc-1.rs +++ b/src/test/run-pass/impl-privacy-xc-1.rs @@ -7,4 +7,3 @@ pub fn main() { let fish = impl_privacy_xc_1::Fish { x: 1 }; fish.swim(); } - diff --git a/src/test/run-pass/impl-privacy-xc-2.rs b/src/test/run-pass/impl-privacy-xc-2.rs index 69bd31ab766da..74d9a34e1618c 100644 --- a/src/test/run-pass/impl-privacy-xc-2.rs +++ b/src/test/run-pass/impl-privacy-xc-2.rs @@ -8,4 +8,3 @@ pub fn main() { let fish2 = impl_privacy_xc_2::Fish { x: 2 }; io::println(if fish1.eq(&fish2) { "yes" } else { "no " }); } - diff --git a/src/test/run-pass/infinite-loops.rs b/src/test/run-pass/infinite-loops.rs index 611a4b9ccabdd..b2ed6d95c206a 100644 --- a/src/test/run-pass/infinite-loops.rs +++ b/src/test/run-pass/infinite-loops.rs @@ -21,9 +21,9 @@ fn loopy(n: int) { loop { } } -pub fn main() { +pub fn main() { // Commenting this out, as this will hang forever otherwise. // Even after seeing the comment above, I'm not sure what the // intention of this test is. - // do spawn { loopy(5) }; + // do spawn { loopy(5) }; } diff --git a/src/test/run-pass/instantiable.rs b/src/test/run-pass/instantiable.rs index c140a66ffe4d6..2173bae85e1e1 100644 --- a/src/test/run-pass/instantiable.rs +++ b/src/test/run-pass/instantiable.rs @@ -18,4 +18,3 @@ struct X { x: uint, nxt: *foo } pub fn main() { let x = foo(X {x: 0, nxt: ptr::null()}); } - diff --git a/src/test/run-pass/int-conversion-coherence.rs b/src/test/run-pass/int-conversion-coherence.rs index 235fab107e781..ef2a84da219c9 100644 --- a/src/test/run-pass/int-conversion-coherence.rs +++ b/src/test/run-pass/int-conversion-coherence.rs @@ -23,4 +23,3 @@ impl foo of plus for int { fn plus() -> int { self + 10 } } pub fn main() { assert!(10.plus() == 20); } - diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index adc085d210853..cce3d8066ec19 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -22,6 +22,7 @@ mod rusti { #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] mod m { + #[main] #[cfg(target_arch = "x86")] pub fn main() { unsafe { @@ -30,6 +31,7 @@ mod m { } } + #[main] #[cfg(target_arch = "x86_64")] pub fn main() { unsafe { @@ -41,6 +43,7 @@ mod m { #[cfg(target_os = "win32")] mod m { + #[main] #[cfg(target_arch = "x86")] pub fn main() { unsafe { @@ -52,6 +55,7 @@ mod m { #[cfg(target_os = "android")] mod m { + #[main] #[cfg(target_arch = "arm")] pub fn main() { unsafe { diff --git a/src/test/run-pass/intrinsic-atomics.rs b/src/test/run-pass/intrinsic-atomics.rs index 42d4f5e4d2078..d4701f74488c8 100644 --- a/src/test/run-pass/intrinsic-atomics.rs +++ b/src/test/run-pass/intrinsic-atomics.rs @@ -15,6 +15,12 @@ mod rusti { pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; + pub fn atomic_load(src: &int) -> int; + pub fn atomic_load_acq(src: &int) -> int; + + pub fn atomic_store(dst: &mut int, val: int); + pub fn atomic_store_rel(dst: &mut int, val: int); + pub fn atomic_xchg(dst: &mut int, src: int) -> int; pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; @@ -33,6 +39,15 @@ pub fn main() { unsafe { let mut x = ~1; + assert!(rusti::atomic_load(x) == 1); + *x = 5; + assert!(rusti::atomic_load_acq(x) == 5); + + rusti::atomic_store(x,3); + assert!(*x == 3); + rusti::atomic_store_rel(x,1); + assert!(*x == 1); + assert!(rusti::atomic_cxchg(x, 1, 2) == 1); assert!(*x == 2); diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index 966061a80856d..9f683d2089877 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -11,8 +11,8 @@ mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { - pub fn move_val_init(dst: &mut T, +src: T); - pub fn move_val(dst: &mut T, +src: T); + pub fn move_val_init(dst: &mut T, src: T); + pub fn move_val(dst: &mut T, src: T); } } diff --git a/src/test/run-pass/issue-1466.rs b/src/test/run-pass/intrinsic-uninit.rs similarity index 75% rename from src/test/run-pass/issue-1466.rs rename to src/test/run-pass/intrinsic-uninit.rs index 1915f1b3a4100..a835c9531bf78 100644 --- a/src/test/run-pass/issue-1466.rs +++ b/src/test/run-pass/intrinsic-uninit.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// exec-env:RUST_CC_ZEAL=1 -// xfail-test - +mod rusti { + #[abi = "rust-intrinsic"] + pub extern "rust-intrinsic" { + fn uninit() -> T; + } +} pub fn main() { - error!("%?", os::getenv(~"RUST_CC_ZEAL")); - let _x = @{a: @10, b: ~true}; + let _a : int = unsafe {rusti::uninit()}; } diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index b96ea8cbb7b43..1a0d97a5c5b03 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -89,7 +89,7 @@ pub fn main() { assert!((cttz16(-1i16) == 0i16)); assert!((cttz32(-1i32) == 0i32)); assert!((cttz64(-1i64) == 0i64)); - + assert!((cttz8(0i8) == 8i8)); assert!((cttz16(0i16) == 16i16)); assert!((cttz32(0i32) == 32i32)); diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index 60e32a56ee5d8..c73df8209e8b9 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -10,10 +10,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod std; - -use std::cmp::FuzzyEq; - mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { @@ -54,50 +50,50 @@ pub fn main() { unsafe { use rusti::*; - assert!((sqrtf32(64f32).fuzzy_eq(&8f32))); - assert!((sqrtf64(64f64).fuzzy_eq(&8f64))); + assert!((sqrtf32(64f32).approx_eq(&8f32))); + assert!((sqrtf64(64f64).approx_eq(&8f64))); - assert!((powif32(25f32, -2i32).fuzzy_eq(&0.0016f32))); - assert!((powif64(23.2f64, 2i32).fuzzy_eq(&538.24f64))); + assert!((powif32(25f32, -2i32).approx_eq(&0.0016f32))); + assert!((powif64(23.2f64, 2i32).approx_eq(&538.24f64))); - assert!((sinf32(0f32).fuzzy_eq(&0f32))); - assert!((sinf64(f64::consts::pi / 2f64).fuzzy_eq(&1f64))); + assert!((sinf32(0f32).approx_eq(&0f32))); + assert!((sinf64(f64::consts::pi / 2f64).approx_eq(&1f64))); - assert!((cosf32(0f32).fuzzy_eq(&1f32))); - assert!((cosf64(f64::consts::pi * 2f64).fuzzy_eq(&1f64))); + assert!((cosf32(0f32).approx_eq(&1f32))); + assert!((cosf64(f64::consts::pi * 2f64).approx_eq(&1f64))); - assert!((powf32(25f32, -2f32).fuzzy_eq(&0.0016f32))); - assert!((powf64(400f64, 0.5f64).fuzzy_eq(&20f64))); + assert!((powf32(25f32, -2f32).approx_eq(&0.0016f32))); + assert!((powf64(400f64, 0.5f64).approx_eq(&20f64))); - assert!((fabsf32(expf32(1f32) - f32::consts::e).fuzzy_eq(&0f32))); - assert!((expf64(1f64).fuzzy_eq(&f64::consts::e))); + assert!((fabsf32(expf32(1f32) - f32::consts::e).approx_eq(&0f32))); + assert!((expf64(1f64).approx_eq(&f64::consts::e))); - assert!((exp2f32(10f32).fuzzy_eq(&1024f32))); - assert!((exp2f64(50f64).fuzzy_eq(&1125899906842624f64))); + assert!((exp2f32(10f32).approx_eq(&1024f32))); + assert!((exp2f64(50f64).approx_eq(&1125899906842624f64))); - assert!((fabsf32(logf32(f32::consts::e) - 1f32).fuzzy_eq(&0f32))); - assert!((logf64(1f64).fuzzy_eq(&0f64))); + assert!((fabsf32(logf32(f32::consts::e) - 1f32).approx_eq(&0f32))); + assert!((logf64(1f64).approx_eq(&0f64))); - assert!((log10f32(10f32).fuzzy_eq(&1f32))); - assert!((log10f64(f64::consts::e).fuzzy_eq(&f64::consts::log10_e))); + assert!((log10f32(10f32).approx_eq(&1f32))); + assert!((log10f64(f64::consts::e).approx_eq(&f64::consts::log10_e))); - assert!((log2f32(8f32).fuzzy_eq(&3f32))); - assert!((log2f64(f64::consts::e).fuzzy_eq(&f64::consts::log2_e))); - - assert!((fmaf32(1.0f32, 2.0f32, 5.0f32).fuzzy_eq(&7.0f32))); - assert!((fmaf64(0.0f64, -2.0f64, f64::consts::e).fuzzy_eq(&f64::consts::e))); + assert!((log2f32(8f32).approx_eq(&3f32))); + assert!((log2f64(f64::consts::e).approx_eq(&f64::consts::log2_e))); - assert!((fabsf32(-1.0f32).fuzzy_eq(&1.0f32))); - assert!((fabsf64(34.2f64).fuzzy_eq(&34.2f64))); + assert!((fmaf32(1.0f32, 2.0f32, 5.0f32).approx_eq(&7.0f32))); + assert!((fmaf64(0.0f64, -2.0f64, f64::consts::e).approx_eq(&f64::consts::e))); - assert!((floorf32(3.8f32).fuzzy_eq(&3.0f32))); - assert!((floorf64(-1.1f64).fuzzy_eq(&-2.0f64))); + assert!((fabsf32(-1.0f32).approx_eq(&1.0f32))); + assert!((fabsf64(34.2f64).approx_eq(&34.2f64))); + + assert!((floorf32(3.8f32).approx_eq(&3.0f32))); + assert!((floorf64(-1.1f64).approx_eq(&-2.0f64))); // Causes linker error // undefined reference to llvm.ceil.f32/64 //assert!((ceilf32(-2.3f32) == -2.0f32)); //assert!((ceilf64(3.8f64) == 4.0f64)); - + // Causes linker error // undefined reference to llvm.trunc.f32/64 //assert!((truncf32(0.1f32) == 0.0f32)); diff --git a/src/test/run-pass/issue-1516.rs b/src/test/run-pass/issue-1516.rs index 33be716cc5f48..fe3feeb3dbf90 100644 --- a/src/test/run-pass/issue-1516.rs +++ b/src/test/run-pass/issue-1516.rs @@ -10,4 +10,3 @@ // xfail-test pub fn main() { let early_error: @fn(str) -> ! = {|msg| fail!() }; } - diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs index ac680d3d12e41..5b320ddc06bb6 100644 --- a/src/test/run-pass/issue-2185.rs +++ b/src/test/run-pass/issue-2185.rs @@ -8,22 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test FIXME #2263 +// does the second one subsume the first? +// xfail-test // xfail-fast + +// notes on this test case: +// On Thu, Apr 18, 2013 at 6:30 PM, John Clements wrote: +// the "issue-2185.rs" test was xfailed with a ref to #2263. Issue #2263 is now fixed, so I tried it again, and after adding some &self parameters, I got this error: +// +// Running /usr/local/bin/rustc: +// issue-2185.rs:24:0: 26:1 error: conflicting implementations for a trait +// issue-2185.rs:24 impl iterable for @fn(&fn(uint)) { +// issue-2185.rs:25 fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } +// issue-2185.rs:26 } +// issue-2185.rs:20:0: 22:1 note: note conflicting implementation here +// issue-2185.rs:20 impl iterable for @fn(&fn(A)) { +// issue-2185.rs:21 fn iter(&self, blk: &fn(A)) { self(blk); } +// issue-2185.rs:22 } +// +// … so it looks like it's just not possible to implement both the generic iterable and iterable for the type iterable. Is it okay if I just remove this test? +// +// but Niko responded: +// think it's fine to remove this test, just because it's old and cruft and not hard to reproduce. *However* it should eventually be possible to implement the same interface for the same type multiple times with different type parameters, it's just that our current trait implementation has accidental limitations. + +// so I'm leaving it in. +// actually, it looks like this is related to bug #3429. I'll rename this bug. + // This test had to do with an outdated version of the iterable trait. // However, the condition it was testing seemed complex enough to // warrant still having a test, so I inlined the old definitions. trait iterable { - fn iter(blk: &fn(A)); + fn iter(&self, blk: &fn(A)); } impl iterable for @fn(&fn(A)) { - fn iter(blk: &fn(A)) { self(blk); } + fn iter(&self, blk: &fn(A)) { self(blk); } } impl iterable for @fn(&fn(uint)) { - fn iter(blk: &fn(&&v: uint)) { self( |i| blk(i) ) } + fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } } fn filter>(self: IA, prd: @fn(A) -> bool, blk: &fn(A)) { diff --git a/src/test/run-pass/issue-2196.rs b/src/test/run-pass/issue-2196.rs deleted file mode 100644 index 3fce821561a90..0000000000000 --- a/src/test/run-pass/issue-2196.rs +++ /dev/null @@ -1,19 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -// aux-build:issue-2196-a.rs -// aux-build:issue-2196-b.rs -// aux-build:issue-2196-c.rc - -use c(name = "issue2196c"); -use c::t; - -pub fn main() { } diff --git a/src/test/run-pass/issue-2216.rs b/src/test/run-pass/issue-2216.rs index 98965cb6d9102..c3a2a4c0b7e24 100644 --- a/src/test/run-pass/issue-2216.rs +++ b/src/test/run-pass/issue-2216.rs @@ -10,7 +10,7 @@ pub fn main() { let mut x = 0; - + 'foo: loop { 'bar: loop { 'quux: loop { diff --git a/src/test/run-pass/issue-2526-a.rs b/src/test/run-pass/issue-2526-a.rs index c91b5dd303c09..39ce74947e997 100644 --- a/src/test/run-pass/issue-2526-a.rs +++ b/src/test/run-pass/issue-2526-a.rs @@ -15,4 +15,3 @@ extern mod issue_2526; use issue_2526::*; pub fn main() {} - diff --git a/src/test/compile-fail/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs similarity index 68% rename from src/test/compile-fail/issue-2611-3.rs rename to src/test/run-pass/issue-2611-3.rs index 248bea2d9b55c..acc6ffd0dd1b3 100644 --- a/src/test/compile-fail/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that impl methods are matched to traits exactly: -// we might be tempted to think matching is contravariant, but if -// we let an impl method can have more permissive bounds than the trait -// method it's implementing, the return type might be less specific than -// needed. Just punt and make it invariant. +// Tests that impls are allowed to have looser, more permissive bounds +// than the traits require. trait A { fn b(x: C) -> C; diff --git a/src/test/run-pass/issue-2633-2.rs b/src/test/run-pass/issue-2633-2.rs index 2c3b4b71bb8e3..71a491b8a3955 100644 --- a/src/test/run-pass/issue-2633-2.rs +++ b/src/test/run-pass/issue-2633-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn a_val(&&x: ~int, +y: ~int) -> int { +fn a_val(x: ~int, y: ~int) -> int { *x + *y } diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index f54d3d39831f4..60daaea57d758 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -10,8 +10,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + // tjc: I don't know why pub mod pipes { + use core::util; use core::cast::{forget, transmute}; pub struct Stuff { @@ -53,23 +56,23 @@ pub mod pipes { // We should consider moving this to ::core::unsafe, although I // suspect graydon would want us to use void pointers instead. - pub unsafe fn uniquify(+x: *T) -> ~T { + pub unsafe fn uniquify(x: *T) -> ~T { unsafe { cast::transmute(x) } } - pub fn swap_state_acq(+dst: &mut state, src: state) -> state { + pub fn swap_state_acq(dst: &mut state, src: state) -> state { unsafe { transmute(rusti::atomic_xchg_acq(transmute(dst), src as int)) } } - pub fn swap_state_rel(+dst: &mut state, src: state) -> state { + pub fn swap_state_rel(dst: &mut state, src: state) -> state { unsafe { transmute(rusti::atomic_xchg_rel(transmute(dst), src as int)) } } - pub fn send(mut p: send_packet, +payload: T) { + pub fn send(mut p: send_packet, payload: T) { let mut p = p.unwrap(); let mut p = unsafe { uniquify(p) }; assert!((*p).payload.is_none()); @@ -104,8 +107,7 @@ pub mod pipes { match old_state { empty | blocked => { task::yield(); } full => { - let mut payload = None; - payload <-> (*p).payload; + let payload = util::replace(&mut p.payload, None); return Some(payload.unwrap()) } terminated => { @@ -159,10 +161,9 @@ pub mod pipes { fn finalize(&self) { unsafe { if self.p != None { - let mut p = None; let self_p: &mut Option<*packet> = cast::transmute(&self.p); - p <-> *self_p; + let p = util::replace(self_p, None); sender_terminate(p.unwrap()) } } @@ -171,9 +172,7 @@ pub mod pipes { pub impl send_packet { fn unwrap(&mut self) -> *packet { - let mut p = None; - p <-> self.p; - p.unwrap() + util::replace(&mut self.p, None).unwrap() } } @@ -192,10 +191,9 @@ pub mod pipes { fn finalize(&self) { unsafe { if self.p != None { - let mut p = None; let self_p: &mut Option<*packet> = cast::transmute(&self.p); - p <-> *self_p; + let p = util::replace(self_p, None); receiver_terminate(p.unwrap()) } } @@ -204,9 +202,7 @@ pub mod pipes { pub impl recv_packet { fn unwrap(&mut self) -> *packet { - let mut p = None; - p <-> self.p; - p.unwrap() + util::replace(&mut self.p, None).unwrap() } } @@ -225,11 +221,12 @@ pub mod pipes { pub mod pingpong { use core::cast; use core::ptr; + use core::util; pub struct ping(::pipes::send_packet); pub struct pong(::pipes::send_packet); - pub fn liberate_ping(+p: ping) -> ::pipes::send_packet { + pub fn liberate_ping(p: ping) -> ::pipes::send_packet { unsafe { let addr : *::pipes::send_packet = match &p { &ping(ref x) => { cast::transmute(x) } @@ -240,7 +237,7 @@ pub mod pingpong { } } - pub fn liberate_pong(+p: pong) -> ::pipes::send_packet { + pub fn liberate_pong(p: pong) -> ::pipes::send_packet { unsafe { let addr : *::pipes::send_packet = match &p { &pong(ref x) => { cast::transmute(x) } @@ -262,14 +259,14 @@ pub mod pingpong { pub type ping = ::pipes::send_packet; pub type pong = ::pipes::recv_packet; - pub fn do_ping(+c: ping) -> pong { + pub fn do_ping(c: ping) -> pong { let (sp, rp) = ::pipes::entangle(); ::pipes::send(c, pingpong::ping(sp)); rp } - pub fn do_pong(+c: pong) -> (ping, ()) { + pub fn do_pong(c: pong) -> (ping, ()) { let packet = ::pipes::recv(c); if packet.is_none() { fail!(~"sender closed the connection") @@ -284,7 +281,7 @@ pub mod pingpong { pub type ping = ::pipes::recv_packet; pub type pong = ::pipes::send_packet; - pub fn do_ping(+c: ping) -> (pong, ()) { + pub fn do_ping(c: ping) -> (pong, ()) { let packet = ::pipes::recv(c); if packet.is_none() { fail!(~"sender closed the connection") @@ -292,7 +289,7 @@ pub mod pingpong { (pingpong::liberate_ping(packet.unwrap()), ()) } - pub fn do_pong(+c: pong) -> ping { + pub fn do_pong(c: pong) -> ping { let (sp, rp) = ::pipes::entangle(); ::pipes::send(c, pingpong::pong(sp)); rp @@ -300,14 +297,14 @@ pub mod pingpong { } } -fn client(+chan: pingpong::client::ping) { +fn client(chan: pingpong::client::ping) { let chan = pingpong::client::do_ping(chan); error!(~"Sent ping"); let (_chan, _data) = pingpong::client::do_pong(chan); error!(~"Received pong"); } -fn server(+chan: pingpong::server::ping) { +fn server(chan: pingpong::server::ping) { let (chan, _data) = pingpong::server::do_ping(chan); error!(~"Received ping"); let _chan = pingpong::server::do_pong(chan); diff --git a/src/test/run-pass/issue-2734.rs b/src/test/run-pass/issue-2734.rs index 7125e89287cbd..319146d0a810d 100644 --- a/src/test/run-pass/issue-2734.rs +++ b/src/test/run-pass/issue-2734.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait hax { } -impl hax for A { } +trait hax { } +impl hax for A { } fn perform_hax(x: @T) -> @hax { @x as @hax diff --git a/src/test/run-pass/issue-2735-2.rs b/src/test/run-pass/issue-2735-2.rs index 96f76b0fd6ba6..ca584e1a6e3b8 100644 --- a/src/test/run-pass/issue-2735-2.rs +++ b/src/test/run-pass/issue-2735-2.rs @@ -9,27 +9,25 @@ // except according to those terms. // This test should behave exactly like issue-2735-3 -struct defer<'self> { - b: &'self mut bool, +struct defer { + b: @mut bool, } #[unsafe_destructor] -impl<'self> Drop for defer<'self> { +impl Drop for defer { fn finalize(&self) { - unsafe { - *(self.b) = true; - } + *self.b = true; } } -fn defer<'r>(b: &'r mut bool) -> defer<'r> { +fn defer(b: @mut bool) -> defer { defer { b: b } } pub fn main() { - let mut dtor_ran = false; - let _ = defer(&mut dtor_ran); - assert!((dtor_ran)); + let dtor_ran = @mut false; + let _ = defer(dtor_ran); + assert!(*dtor_ran); } diff --git a/src/test/run-pass/issue-2735-3.rs b/src/test/run-pass/issue-2735-3.rs index 50e3c946f50ef..44ca5d6929bd6 100644 --- a/src/test/run-pass/issue-2735-3.rs +++ b/src/test/run-pass/issue-2735-3.rs @@ -9,27 +9,25 @@ // except according to those terms. // This test should behave exactly like issue-2735-2 -struct defer<'self> { - b: &'self mut bool, +struct defer { + b: @mut bool, } #[unsafe_destructor] -impl<'self> Drop for defer<'self> { +impl Drop for defer { fn finalize(&self) { - unsafe { - *(self.b) = true; - } + *self.b = true; } } -fn defer<'r>(b: &'r mut bool) -> defer<'r> { +fn defer(b: @mut bool) -> defer { defer { b: b } } pub fn main() { - let mut dtor_ran = false; - defer(&mut dtor_ran); - assert!((dtor_ran)); + let dtor_ran = @mut false; + defer(dtor_ran); + assert!(*dtor_ran); } diff --git a/src/test/run-pass/issue-2869.rs b/src/test/run-pass/issue-2869.rs deleted file mode 100644 index 619f4b4d7db8a..0000000000000 --- a/src/test/run-pass/issue-2869.rs +++ /dev/null @@ -1,24 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -enum pat { pat_ident(Option) } - -fn f(pat: pat) -> bool { true } - -fn num_bindings(pat: pat) -> uint { - match pat { - pat_ident(_) if f(pat) { 0 } - pat_ident(None) { 1 } - pat_ident(Some(sub)) { sub } - } -} - -pub fn main() {} diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index ef7fd69157791..9ea8caef7bc21 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -37,7 +37,7 @@ impl to_str::ToStr for square { closed_lift => { ~"L" } open_lift => { ~"O" } earth => { ~"." } - empty => { ~" " } + empty => { ~" " } } } } @@ -59,7 +59,7 @@ fn square_from_char(c: char) -> square { } } -fn read_board_grid(+in: rdr) -> ~[~[square]] { +fn read_board_grid(in: rdr) -> ~[~[square]] { let in = @in as @io::Reader; let mut grid = ~[]; for in.each_line |line| { @@ -79,12 +79,6 @@ mod test { pub fn trivial_to_str() { assert!(lambda.to_str() == "\\") } - - #[test] - pub fn read_simple_board() { - let s = include_str!("./maps/contest1.map"); - io::with_str_reader(s, read_board_grid) - } } pub fn main() {} diff --git a/src/test/run-pass/issue-2989.rs b/src/test/run-pass/issue-2989.rs index af8190f32a75e..fb5df6d50e01f 100644 --- a/src/test/run-pass/issue-2989.rs +++ b/src/test/run-pass/issue-2989.rs @@ -21,7 +21,7 @@ impl methods for () { } // the position of this function is significant! - if it comes before methods -// then it works, if it comes after it then it doesnt! +// then it works, if it comes after it then it doesn't! fn to_bools(bitv: Storage) -> ~[bool] { vec::from_fn(8, |i| { let w = i / 64; diff --git a/src/test/run-pass/issue-3176.rs b/src/test/run-pass/issue-3176.rs index 03b1c127c55ff..d22c7e82ad5de 100644 --- a/src/test/run-pass/issue-3176.rs +++ b/src/test/run-pass/issue-3176.rs @@ -20,15 +20,16 @@ pub fn main() { p2.recv(); error!("sibling fails"); fail!(); - } + } let (p3,c3) = comm::stream(); c.send(c3); c2.send(()); error!("child blocks"); let (p, c) = comm::stream(); - (p, p3).select(); + let mut tuple = (p, p3); + tuple.select(); c.send(()); - }; + }; error!("parent tries"); assert!(!p.recv().try_send(())); error!("all done!"); diff --git a/src/test/run-pass/issue-3250.rs b/src/test/run-pass/issue-3250.rs index a563544b5c70d..0a93b89a94d42 100644 --- a/src/test/run-pass/issue-3250.rs +++ b/src/test/run-pass/issue-3250.rs @@ -2,6 +2,4 @@ type t = (uint, uint); - - pub fn main() { } diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index d79eef46f0523..70a01f8cf02d2 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -16,12 +16,11 @@ use core::path::{Path}; type rsrc_loader = ~fn(path: &Path) -> result::Result<~str, ~str>; -#[test] fn tester() { let loader: rsrc_loader = |_path| {result::Ok(~"more blah")}; - let path = path::from_str("blah"); + let path = path::Path("blah"); assert!(loader(&path).is_ok()); } diff --git a/src/test/run-pass/issue-1895.rs b/src/test/run-pass/issue-3429.rs similarity index 99% rename from src/test/run-pass/issue-1895.rs rename to src/test/run-pass/issue-3429.rs index 67877795cc0d8..7bfb928e86d7d 100644 --- a/src/test/run-pass/issue-1895.rs +++ b/src/test/run-pass/issue-3429.rs @@ -13,4 +13,3 @@ pub fn main() { let y: @fn() -> int = || x; let z = y(); } - diff --git a/src/test/run-pass/issue-3461.rs b/src/test/run-pass/issue-3461.rs index 4c4144f28e891..dae35d7237b85 100644 --- a/src/test/run-pass/issue-3461.rs +++ b/src/test/run-pass/issue-3461.rs @@ -12,6 +12,6 @@ pub fn main() { fn foo() { } - + let bar: ~fn() = ~foo; } diff --git a/src/test/run-pass/issue-3480.rs b/src/test/run-pass/issue-3480.rs deleted file mode 100644 index aaff822398d6f..0000000000000 --- a/src/test/run-pass/issue-3480.rs +++ /dev/null @@ -1,26 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -type IMap = ~[(K, V)]; - -trait ImmutableMap -{ - fn contains_key(key: K) -> bool; -} - -impl IMap : ImmutableMap -{ - fn contains_key(key: K) -> bool { - vec::find(self, |e| {e.first() == key}).is_some() - } -} - -pub fn main() {} diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 703dcd54f0ac8..ff2fa80102bfc 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -10,7 +10,7 @@ extern mod std; use core::io::WriterUtil; - + enum Token { Text(@~str), ETag(@~[~str], @~str), @@ -19,7 +19,7 @@ enum Token { IncompleteSection(@~[~str], bool, @~str, bool), Partial(@~str, @~str, @~str), } - + fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected @@ -29,12 +29,12 @@ fn check_strs(actual: &str, expected: &str) -> bool } return true; } - + pub fn main() { // assert!(check_strs(fmt!("%?", Text(@~"foo")), "Text(@~\"foo\")")); // assert!(check_strs(fmt!("%?", ETag(@~[~"foo"], @~"bar")), "ETag(@~[ ~\"foo\" ], @~\"bar\")")); - + let t = Text(@~"foo"); let u = Section(@~[~"alpha"], true, @~[t], @~"foo", @~"foo", @~"foo", @~"foo", @~"foo"); let v = fmt!("%?", u); // this is the line that causes the seg fault diff --git a/src/test/run-pass/issue-3559.rs b/src/test/run-pass/issue-3559.rs index 334831fea4d03..b3f3aed9ea1f9 100644 --- a/src/test/run-pass/issue-3559.rs +++ b/src/test/run-pass/issue-3559.rs @@ -1,4 +1,4 @@ -// xfail-fast +// xfail-test #4276 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -15,7 +15,6 @@ extern mod std; use core::io::{WriterUtil}; -#[cfg(test)] fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected @@ -26,10 +25,9 @@ fn check_strs(actual: &str, expected: &str) -> bool return true; } -#[test] fn tester() { - let mut table = core::hashmap::HashMap(); + let mut table = core::hashmap::HashMap::new(); table.insert(@~"one", 1); table.insert(@~"two", 2); assert!(check_strs(table.to_str(), ~"xxx")); // not sure what expected should be diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 9b7ab67c1a3e8..96925a97a1016 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -62,7 +62,7 @@ impl Drop for AsciiArt { // It's common to define a constructor sort of function to create struct instances. // If there is a canonical constructor it is typically named the same as the type. -// Other constructor sort of functions are typically named from_foo, from_bar, etc. +// Other constructor sort of functions are typically named from_foo, from_bar, etc. fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt { // Use an anonymous function to build a vector of vectors containing @@ -72,7 +72,7 @@ fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt { for height.times { - let mut line = ~[]; + let mut line = ~[]; vec::grow_set(&mut line, width-1, &'.', '.'); push(line); } @@ -208,4 +208,3 @@ pub fn main() { test_add_pt(); test_shapes(); } - diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index fc6ceb4130fcd..6c26ac3f65e1c 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -24,4 +24,3 @@ fn foo(name: ~str, samples_chan: Chan) { } pub fn main() {} - diff --git a/src/test/run-pass/issue-3656.rs b/src/test/run-pass/issue-3656.rs index b59810fc18875..895e90beef4aa 100644 --- a/src/test/run-pass/issue-3656.rs +++ b/src/test/run-pass/issue-3656.rs @@ -24,7 +24,7 @@ struct KEYGEN { extern { // Bogus signature, just need to test if it compiles. - pub fn malloc(++data: KEYGEN); + pub fn malloc(data: KEYGEN); } pub fn main() { diff --git a/src/test/run-pass/issue-3860.rs b/src/test/run-pass/issue-3860.rs index 46aa7187c9a02..778b2b72b13d9 100644 --- a/src/test/run-pass/issue-3860.rs +++ b/src/test/run-pass/issue-3860.rs @@ -19,6 +19,6 @@ pub impl Foo { pub fn main() { let mut x = @mut Foo { x: 3 }; // Neither of the next two lines should cause an error - let _ = x.stuff(); + let _ = x.stuff(); x.stuff(); } diff --git a/src/test/run-pass/issue-3895.rs b/src/test/run-pass/issue-3895.rs index d3820c1e54712..388e09ddb3e39 100644 --- a/src/test/run-pass/issue-3895.rs +++ b/src/test/run-pass/issue-3895.rs @@ -11,7 +11,7 @@ // xfail-test pub fn main() { enum State { BadChar, BadSyntax } - + match BadChar { _ if true => BadChar, BadChar | BadSyntax => fail!() , diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index c485590f4aa17..a04e35108028c 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -24,4 +24,3 @@ trait C: B { } pub fn main() {} - diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index d26e9f1ba7b43..57962911538de 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -32,7 +32,7 @@ impl Positioned for Point { } } -impl Point: Movable; +impl Movable for Point; pub fn main() { let p = Point{ x: 1, y: 2}; diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass/issue-4036.rs index f24875cbf8e0b..8b514b11625e4 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass/issue-4036.rs @@ -17,5 +17,6 @@ use self::std::serialize; pub fn main() { let json = json::from_str("[1]").unwrap(); - let _x: ~[int] = serialize::Decodable::decode(&json::Decoder(json)); + let mut decoder = json::Decoder(json); + let _x: ~[int] = serialize::Decodable::decode(&mut decoder); } diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index 18bc471afab1d..e5905e7a5be21 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -55,7 +55,7 @@ priv fn parse_list(len: uint, io: @io::Reader) -> Result { priv fn chop(s: ~str) -> ~str { s.slice(0, s.len() - 1).to_owned() } - + priv fn parse_bulk(io: @io::Reader) -> Result { match int::from_str(chop(io.read_line())) { None => fail!(), diff --git a/src/test/run-pass/issue-4875.rs b/src/test/run-pass/issue-4875.rs index 51c23e7680826..81947791881fe 100644 --- a/src/test/run-pass/issue-4875.rs +++ b/src/test/run-pass/issue-4875.rs @@ -19,4 +19,3 @@ fn foo(Foo{_}: Foo) { pub fn main() { } - diff --git a/src/test/compile-fail/multiple-main.rs b/src/test/run-pass/issue-5315.rs similarity index 75% rename from src/test/compile-fail/multiple-main.rs rename to src/test/run-pass/issue-5315.rs index ef8cd58abf992..326b3fb12460c 100644 --- a/src/test/compile-fail/multiple-main.rs +++ b/src/test/run-pass/issue-5315.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { -} +// xfail-test +struct A(bool); -mod foo { - fn main() { //~ ERROR multiple 'main' functions - } +fn main() { + let f = A; + f(true); } diff --git a/src/test/run-pass/issue-5353.rs b/src/test/run-pass/issue-5353.rs new file mode 100644 index 0000000000000..f933b616119fa --- /dev/null +++ b/src/test/run-pass/issue-5353.rs @@ -0,0 +1,26 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static INVALID_ENUM : u32 = 0; +static INVALID_VALUE : u32 = 1; + +fn gl_err_str(err: u32) -> ~str +{ + match err + { + INVALID_ENUM => { ~"Invalid enum" }, + INVALID_VALUE => { ~"Invalid value" }, + _ => { ~"Unknown error" } + } +} + +fn main() {} + + diff --git a/src/test/auxiliary/issue-2196-a.rs b/src/test/run-pass/issue-5517.rs similarity index 71% rename from src/test/auxiliary/issue-2196-a.rs rename to src/test/run-pass/issue-5517.rs index 959164d85dd2f..b929dbf51d395 100644 --- a/src/test/auxiliary/issue-2196-a.rs +++ b/src/test/run-pass/issue-5517.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "issue2196a", vers = "0.1")]; -#[crate_type = "lib"]; - +fn main() { + let box1 = @mut 42; + let _x = *(&mut *box1) == 42 || *(&mut *box1) == 31337; +} diff --git a/src/test/compile-fail/issue-4500.rs b/src/test/run-pass/issue-6117.rs similarity index 73% rename from src/test/compile-fail/issue-4500.rs rename to src/test/run-pass/issue-6117.rs index 356a64498219a..73e9391f01683 100644 --- a/src/test/compile-fail/issue-4500.rs +++ b/src/test/run-pass/issue-6117.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main () { - let mut _p: & int = & 4; - _p = &*~3; //~ ERROR illegal borrow +pub fn main() { + match Left(@17) { + Right(()) => {} + _ => {} + } } diff --git a/src/test/run-pass/issue-6141-leaking-owned-fn.rs b/src/test/run-pass/issue-6141-leaking-owned-fn.rs new file mode 100644 index 0000000000000..fe11bb0a972ad --- /dev/null +++ b/src/test/run-pass/issue-6141-leaking-owned-fn.rs @@ -0,0 +1,8 @@ +fn run(f: &fn()) { + f() +} + +fn main() { + let f: ~fn() = || (); + run(f); +} \ No newline at end of file diff --git a/src/test/run-pass/issue-6341.rs b/src/test/run-pass/issue-6341.rs new file mode 100644 index 0000000000000..394345556fcf3 --- /dev/null +++ b/src/test/run-pass/issue-6341.rs @@ -0,0 +1,18 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq)] +struct A { x: uint } + +impl Drop for A { + fn finalize(&self) {} +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/issue-6344-let.rs b/src/test/run-pass/issue-6344-let.rs new file mode 100644 index 0000000000000..916131b6b711c --- /dev/null +++ b/src/test/run-pass/issue-6344-let.rs @@ -0,0 +1,22 @@ +// xfail-test #3874 +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +struct A { x: uint } + +impl Drop for A { + fn finalize(&self) {} +} + +fn main() { + let a = A { x: 0 }; + + let A { x: ref x } = a; + debug!("%?", x) +} diff --git a/src/test/run-pass/issue-6344-match.rs b/src/test/run-pass/issue-6344-match.rs new file mode 100644 index 0000000000000..5bf57aa711692 --- /dev/null +++ b/src/test/run-pass/issue-6344-match.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +struct A { x: uint } + +impl Drop for A { + fn finalize(&self) {} +} + +fn main() { + let a = A { x: 0 }; + + match a { + A { x : ref x } => { + debug!("%?", x) + } + } +} diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs index 16e8fa18c2a02..2a82f559d547c 100644 --- a/src/test/run-pass/issue-868.rs +++ b/src/test/run-pass/issue-868.rs @@ -22,4 +22,3 @@ pub fn main() { let _ = f(||{}); let _ = (||{}); } - diff --git a/src/test/run-pass/issue2378c.rs b/src/test/run-pass/issue2378c.rs index ea8c47a3eb91a..98e60c56476d8 100644 --- a/src/test/run-pass/issue2378c.rs +++ b/src/test/run-pass/issue2378c.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -- #2378 unfixed // aux-build:issue2378a.rs // aux-build:issue2378b.rs +// xfail-fast - check-fast doesn't understand aux-build -use issue2378a; -use issue2378b; +extern mod issue2378a; +extern mod issue2378b; -use issue2378a::{just, methods}; -use issue2378b::{methods}; +use issue2378a::{just}; +use issue2378b::{two_maybes}; pub fn main() { - let x = {a: just(3), b: just(5)}; + let x = two_maybes{a: just(3), b: just(5)}; assert!(x[0u] == (3, 5)); } diff --git a/src/test/run-pass/issue_3136_b.rs b/src/test/run-pass/issue_3136_b.rs index c5b6b6b220cd0..b1d28a1eb67e9 100644 --- a/src/test/run-pass/issue_3136_b.rs +++ b/src/test/run-pass/issue_3136_b.rs @@ -13,4 +13,3 @@ extern mod issue_3136_a; pub fn main() {} - diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 24fe671337287..c616d46a8336c 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -195,13 +195,3 @@ fn test_fn_inner() { } pub fn main() { } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/test/run-pass/iter-min-max.rs b/src/test/run-pass/iter-min-max.rs index a8831a9c5ad59..5f427861e7917 100644 --- a/src/test/run-pass/iter-min-max.rs +++ b/src/test/run-pass/iter-min-max.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn is_even(&&x: uint) -> bool { (x % 2u) == 0u } +fn is_even(x: uint) -> bool { (x % 2u) == 0u } pub fn main() { assert!([1u, 3u].min() == 1u); diff --git a/src/test/run-pass/ivec-add.rs b/src/test/run-pass/ivec-add.rs index 1b9e818421e2e..bd58ae6565143 100644 --- a/src/test/run-pass/ivec-add.rs +++ b/src/test/run-pass/ivec-add.rs @@ -21,4 +21,3 @@ pub fn main() { assert!((d[0] == 1)); assert!((d[1] == 1)); } - diff --git a/src/test/run-pass/ivec-pass-by-value.rs b/src/test/run-pass/ivec-pass-by-value.rs index 756f38196fded..3a3b5746b9d6f 100644 --- a/src/test/run-pass/ivec-pass-by-value.rs +++ b/src/test/run-pass/ivec-pass-by-value.rs @@ -10,4 +10,3 @@ fn f(a: ~[int]) { } pub fn main() { f(~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/labeled-break.rs b/src/test/run-pass/labeled-break.rs index 06ca401a136e7..32cd7f0c7f8a7 100644 --- a/src/test/run-pass/labeled-break.rs +++ b/src/test/run-pass/labeled-break.rs @@ -18,4 +18,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/lambda-infer-unresolved.rs b/src/test/run-pass/lambda-infer-unresolved.rs index 2e70e90038971..4aeeda8312cac 100644 --- a/src/test/run-pass/lambda-infer-unresolved.rs +++ b/src/test/run-pass/lambda-infer-unresolved.rs @@ -17,5 +17,5 @@ struct Refs { refs: ~[int], n: int } pub fn main() { let e = @mut Refs{refs: ~[], n: 0}; let f: @fn() = || error!(copy e.n); - e.refs += ~[1]; + e.refs.push(1); } diff --git a/src/test/run-pass/let-assignability.rs b/src/test/run-pass/let-assignability.rs index 51fa84613cae9..0afc3ee87e0f4 100644 --- a/src/test/run-pass/let-assignability.rs +++ b/src/test/run-pass/let-assignability.rs @@ -17,4 +17,3 @@ fn f() { pub fn main() { f(); } - diff --git a/src/test/run-pass/liveness-assign-imm-local-after-loop.rs b/src/test/run-pass/liveness-assign-imm-local-after-loop.rs index f352a2b527306..5d59c4c14716f 100644 --- a/src/test/run-pass/liveness-assign-imm-local-after-loop.rs +++ b/src/test/run-pass/liveness-assign-imm-local-after-loop.rs @@ -16,5 +16,5 @@ fn test(cond: bool) { } pub fn main() { - // note: don't call test()... :) + // note: don't call test()... :) } diff --git a/src/test/run-pass/liveness-move-in-loop.rs b/src/test/run-pass/liveness-move-in-loop.rs index 658885124c2ef..acdf388a8ff03 100644 --- a/src/test/run-pass/liveness-move-in-loop.rs +++ b/src/test/run-pass/liveness-move-in-loop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn take(+x: int) -> int {x} +fn take(x: int) -> int {x} fn the_loop() { let mut list = ~[]; diff --git a/src/test/run-pass/log-linearized.rs b/src/test/run-pass/log-linearized.rs index 919c53e033066..0f388489000fe 100644 --- a/src/test/run-pass/log-linearized.rs +++ b/src/test/run-pass/log-linearized.rs @@ -32,4 +32,3 @@ fn f() { pub fn main() { f::(); } - diff --git a/src/test/run-pass/match-range-static.rs b/src/test/run-pass/match-range-static.rs new file mode 100644 index 0000000000000..3eefc386250ed --- /dev/null +++ b/src/test/run-pass/match-range-static.rs @@ -0,0 +1,10 @@ +static s: int = 1; +static e: int = 42; + +fn main() { + match 7 { + s..e => (), + _ => (), + } +} + diff --git a/src/test/run-pass/max-min-classes.rs b/src/test/run-pass/max-min-classes.rs index 58dcb24edf917..d986d7e676a12 100644 --- a/src/test/run-pass/max-min-classes.rs +++ b/src/test/run-pass/max-min-classes.rs @@ -37,4 +37,3 @@ pub fn main() { let foo = Foo(3, 20); io::println(fmt!("%d %d", foo.sum(), foo.product())); } - diff --git a/src/test/run-pass/mlist-cycle.rs b/src/test/run-pass/mlist-cycle.rs index e886c941a4b6a..a67f1574f64af 100644 --- a/src/test/run-pass/mlist-cycle.rs +++ b/src/test/run-pass/mlist-cycle.rs @@ -10,16 +10,18 @@ // xfail-test // -*- rust -*- -extern mod std; +extern mod core; +use core::gc; +use core::gc::rustrt; -type cell = {c: @list}; +struct cell {c: @list} enum list { link(@mut cell), nil, } pub fn main() { - let first: @cell = @mut {c: @nil()}; - let second: @cell = @mut {c: @link(first)}; + let first: @cell = @mut cell{c: @nil()}; + let second: @cell = @mut cell{c: @link(first)}; first._0 = @link(second); - sys.rustrt.gc(); - let third: @cell = @mut {c: @nil()}; + rustrt::gc(); + let third: @cell = @mut cell{c: @nil()}; } diff --git a/src/test/run-pass/module-qualified-struct-destructure.rs b/src/test/run-pass/module-qualified-struct-destructure.rs index 6fb6d21f13f1a..87c854d32be8b 100644 --- a/src/test/run-pass/module-qualified-struct-destructure.rs +++ b/src/test/run-pass/module-qualified-struct-destructure.rs @@ -19,4 +19,3 @@ pub fn main() { let x = m::S { x: 1, y: 2 }; let m::S { x: a, y: b } = x; } - diff --git a/src/test/run-pass/morestack5.rs b/src/test/run-pass/morestack5.rs index 1d232cc5cbd8d..e1561db8b9162 100644 --- a/src/test/run-pass/morestack5.rs +++ b/src/test/run-pass/morestack5.rs @@ -12,7 +12,7 @@ extern mod std; -fn getbig(&&i: int) { +fn getbig(i: int) { if i != 0 { getbig(i - 1); } diff --git a/src/test/run-pass/morestack6.rs b/src/test/run-pass/morestack6.rs index 1f908936aef47..dafdd0fba48c3 100644 --- a/src/test/run-pass/morestack6.rs +++ b/src/test/run-pass/morestack6.rs @@ -62,7 +62,7 @@ pub fn main() { calllink09, calllink10 ]; - let rng = rand::rng(); + let mut rng = rand::rng(); for fns.each |f| { let f = *f; let sz = rng.next() % 256u32 + 256u32; diff --git a/src/test/run-pass/move-arg-2-unique.rs b/src/test/run-pass/move-arg-2-unique.rs index dbc73c20e6b21..ed3cdc81c3179 100644 --- a/src/test/run-pass/move-arg-2-unique.rs +++ b/src/test/run-pass/move-arg-2-unique.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test(+foo: ~~[int]) { assert!((foo[0] == 10)); } +fn test(foo: ~~[int]) { assert!((foo[0] == 10)); } pub fn main() { let x = ~~[10]; diff --git a/src/test/run-pass/move-arg-2.rs b/src/test/run-pass/move-arg-2.rs index 5cc309d1a3ea4..fc909da8b0323 100644 --- a/src/test/run-pass/move-arg-2.rs +++ b/src/test/run-pass/move-arg-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test(+foo: @~[int]) { assert!((foo[0] == 10)); } +fn test(foo: @~[int]) { assert!((foo[0] == 10)); } pub fn main() { let x = @~[10]; diff --git a/src/test/run-pass/move-arg.rs b/src/test/run-pass/move-arg.rs index ca3a5509c5cfd..87db5cbe2f13e 100644 --- a/src/test/run-pass/move-arg.rs +++ b/src/test/run-pass/move-arg.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test(+foo: int) { assert!((foo == 10)); } +fn test(foo: int) { assert!((foo == 10)); } pub fn main() { let x = 10; test(x); } diff --git a/src/test/run-pass/move-nullary-fn.rs b/src/test/run-pass/move-nullary-fn.rs index eb4c5f871af48..ab66bb936354f 100644 --- a/src/test/run-pass/move-nullary-fn.rs +++ b/src/test/run-pass/move-nullary-fn.rs @@ -9,9 +9,9 @@ // except according to those terms. // Issue #922 -fn f2(+thing: @fn()) { } +fn f2(thing: @fn()) { } -fn f(+thing: @fn()) { +fn f(thing: @fn()) { f2(thing); } diff --git a/src/test/run-pass/move-self.rs b/src/test/run-pass/move-self.rs index d84646957283a..4ed1faf65b628 100644 --- a/src/test/run-pass/move-self.rs +++ b/src/test/run-pass/move-self.rs @@ -16,4 +16,3 @@ pub fn main() { let x = S { x: ~"Hello!" }; x.foo(); } - diff --git a/src/test/run-pass/moves-based-on-type-capture-clause.rs b/src/test/run-pass/moves-based-on-type-capture-clause.rs index 2f427ca48aab2..26d4773d961aa 100644 --- a/src/test/run-pass/moves-based-on-type-capture-clause.rs +++ b/src/test/run-pass/moves-based-on-type-capture-clause.rs @@ -4,4 +4,3 @@ pub fn main() { io::println(x); } } - diff --git a/src/test/run-pass/multiple-trait-bounds.rs b/src/test/run-pass/multiple-trait-bounds.rs index 3c6559b9c0dfd..cdfa93d309459 100644 --- a/src/test/run-pass/multiple-trait-bounds.rs +++ b/src/test/run-pass/multiple-trait-bounds.rs @@ -4,4 +4,3 @@ fn f(_: T) { pub fn main() { f(3); } - diff --git a/src/test/run-pass/mut-vstore-expr.rs b/src/test/run-pass/mut-vstore-expr.rs index 0ababc43c3f30..fa6dde5b3ef88 100644 --- a/src/test/run-pass/mut-vstore-expr.rs +++ b/src/test/run-pass/mut-vstore-expr.rs @@ -11,4 +11,3 @@ pub fn main() { let x: &mut [int] = &mut [ 1, 2, 3 ]; } - diff --git a/src/test/run-pass/nested-class.rs b/src/test/run-pass/nested-class.rs index 44348223b605d..83820f87d5030 100644 --- a/src/test/run-pass/nested-class.rs +++ b/src/test/run-pass/nested-class.rs @@ -9,14 +9,13 @@ // except according to those terms. pub fn main() { - - struct b { - i: int, - } + struct b { + i: int, + } - pub impl b { - fn do_stuff(&self) -> int { return 37; } - } + pub impl b { + fn do_stuff(&self) -> int { return 37; } + } fn b(i:int) -> b { b { @@ -24,10 +23,9 @@ pub fn main() { } } - // fn b(x:int) -> int { fail!(); } + // fn b(x:int) -> int { fail!(); } - let z = b(42); - assert!((z.i == 42)); - assert!((z.do_stuff() == 37)); - + let z = b(42); + assert!((z.i == 42)); + assert!((z.do_stuff() == 37)); } diff --git a/src/test/run-pass/new-impl-syntax.rs b/src/test/run-pass/new-impl-syntax.rs index 12b41fc91485e..2603353f0cff8 100644 --- a/src/test/run-pass/new-impl-syntax.rs +++ b/src/test/run-pass/new-impl-syntax.rs @@ -23,4 +23,3 @@ pub fn main() { io::println(Thingy { x: 1, y: 2 }.to_str()); io::println(PolymorphicThingy { x: Thingy { x: 1, y: 2 } }.to_str()); } - diff --git a/src/test/run-pass/new-import-syntax.rs b/src/test/run-pass/new-import-syntax.rs index 267f365c7134c..1390ae5f7ebe0 100644 --- a/src/test/run-pass/new-import-syntax.rs +++ b/src/test/run-pass/new-import-syntax.rs @@ -13,4 +13,3 @@ use core::io::println; pub fn main() { println("Hello world!"); } - diff --git a/src/test/run-pass/new-style-constants.rs b/src/test/run-pass/new-style-constants.rs index 9a319ea6a5c50..6fe4a88d07183 100644 --- a/src/test/run-pass/new-style-constants.rs +++ b/src/test/run-pass/new-style-constants.rs @@ -15,4 +15,3 @@ static FOO: int = 3; pub fn main() { println(fmt!("%d", FOO)); } - diff --git a/src/test/run-pass/new-style-fixed-length-vec.rs b/src/test/run-pass/new-style-fixed-length-vec.rs index 5d37a42af4242..6eea23f6b2b06 100644 --- a/src/test/run-pass/new-style-fixed-length-vec.rs +++ b/src/test/run-pass/new-style-fixed-length-vec.rs @@ -15,6 +15,3 @@ static FOO: [int, ..3] = [1, 2, 3]; pub fn main() { println(fmt!("%d %d %d", FOO[0], FOO[1], FOO[2])); } - - - diff --git a/src/test/run-pass/new-vstore-mut-box-syntax.rs b/src/test/run-pass/new-vstore-mut-box-syntax.rs index 971e870d1f8c0..63569c7198260 100644 --- a/src/test/run-pass/new-vstore-mut-box-syntax.rs +++ b/src/test/run-pass/new-vstore-mut-box-syntax.rs @@ -12,4 +12,3 @@ pub fn main() { let x: @mut [int] = @mut [ 1, 2, 3 ]; } - diff --git a/src/test/run-pass/newtype-struct-drop-run.rs b/src/test/run-pass/newtype-struct-drop-run.rs new file mode 100644 index 0000000000000..dd5da3b09bb69 --- /dev/null +++ b/src/test/run-pass/newtype-struct-drop-run.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure the destructor is run for newtype structs. + +struct Foo(@mut int); + +#[unsafe_destructor] +impl Drop for Foo { + fn finalize(&self) { + ***self = 23; + } +} + +fn main() { + let y = @mut 32; + { + let x = Foo(y); + } + assert_eq!(*y, 23); +} diff --git a/src/test/run-pass/newtype-struct-with-dtor.rs b/src/test/run-pass/newtype-struct-with-dtor.rs index b33bfa0388a59..eb3b74553b7ba 100644 --- a/src/test/run-pass/newtype-struct-with-dtor.rs +++ b/src/test/run-pass/newtype-struct-with-dtor.rs @@ -13,5 +13,3 @@ impl Drop for Fd { pub fn main() { } - - diff --git a/src/test/run-pass/newtype-struct-xc-2.rs b/src/test/run-pass/newtype-struct-xc-2.rs index 1fca01f737327..cedf1d42c3dcd 100644 --- a/src/test/run-pass/newtype-struct-xc-2.rs +++ b/src/test/run-pass/newtype-struct-xc-2.rs @@ -11,4 +11,3 @@ fn f() -> Au { pub fn main() { let _ = f(); } - diff --git a/src/test/run-pass/newtype-struct-xc.rs b/src/test/run-pass/newtype-struct-xc.rs index 49ce618e37b4c..2280b335f3f93 100644 --- a/src/test/run-pass/newtype-struct-xc.rs +++ b/src/test/run-pass/newtype-struct-xc.rs @@ -6,4 +6,3 @@ extern mod newtype_struct_xc; pub fn main() { let _ = newtype_struct_xc::Au(2); } - diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index 0c4d297403cfb..206381bcef72d 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -20,7 +20,7 @@ use core::{option, cast}; enum E { Thing(int, T), Nothing((), ((), ()), [i8, ..0]) } impl E { - fn is_none(&self) -> bool { + fn is_none(&self) -> bool { match *self { Thing(*) => false, Nothing(*) => true diff --git a/src/test/run-pass/one-tuple.rs b/src/test/run-pass/one-tuple.rs index 2efa0b98b6a27..eb32e7cda1ad8 100644 --- a/src/test/run-pass/one-tuple.rs +++ b/src/test/run-pass/one-tuple.rs @@ -21,4 +21,3 @@ pub fn main() { let (y,) = x; assert!(y == 'd'); } - diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index ffd6903d7f7a4..8c26dfa1fac56 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -40,7 +40,7 @@ impl ops::Not for Point { } impl ops::Index for Point { - fn index(&self, +x: &bool) -> int { + fn index(&self, x: &bool) -> int { if *x { self.x } else { self.y } } } diff --git a/src/test/run-pass/option-unwrap.rs b/src/test/run-pass/option-unwrap.rs index 0efed2708f485..8698d1f39a88f 100644 --- a/src/test/run-pass/option-unwrap.rs +++ b/src/test/run-pass/option-unwrap.rs @@ -23,7 +23,7 @@ impl Drop for dtor { } } -fn unwrap(+o: Option) -> T { +fn unwrap(o: Option) -> T { match o { Some(v) => v, None => fail!() diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs new file mode 100644 index 0000000000000..ddfc2b17aa706 --- /dev/null +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -0,0 +1,8 @@ +// xfail-fast +// aux-build:packed.rs + +extern mod packed; + +fn main() { + assert_eq!(sys::size_of::(), 5); +} diff --git a/src/test/run-pass/pass-by-copy.rs b/src/test/run-pass/pass-by-copy.rs index c3ab589b66cf7..c4f328940c49f 100644 --- a/src/test/run-pass/pass-by-copy.rs +++ b/src/test/run-pass/pass-by-copy.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn magic(+x: A) { debug!(x); } -fn magic2(+x: @int) { debug!(x); } +fn magic(x: A) { debug!(x); } +fn magic2(x: @int) { debug!(x); } struct A { a: @int } diff --git a/src/test/run-pass/pattern-in-closure.rs b/src/test/run-pass/pattern-in-closure.rs index 7194fca519b7a..08c749235c2c8 100644 --- a/src/test/run-pass/pattern-in-closure.rs +++ b/src/test/run-pass/pattern-in-closure.rs @@ -19,4 +19,3 @@ pub fn main() { f((2, 3)); g(Foo { x: 1, y: 2 }); } - diff --git a/src/test/run-pass/pipe-bank-proto.rs b/src/test/run-pass/pipe-bank-proto.rs index c4ce1434165e3..5e2be7e6d081a 100644 --- a/src/test/run-pass/pipe-bank-proto.rs +++ b/src/test/run-pass/pipe-bank-proto.rs @@ -48,12 +48,12 @@ macro_rules! move_it ( { $x:expr } => { unsafe { let y = *ptr::to_unsafe_ptr(&($x)); y } } ) -fn switch(+endp: pipes::RecvPacket, - f: &fn(+v: Option) -> U) -> U { +fn switch(endp: pipes::RecvPacket, + f: &fn(v: Option) -> U) -> U { f(pipes::try_recv(endp)) } -fn move_it(+x: T) -> T { x } +fn move_it(x: T) -> T { x } macro_rules! follow ( { @@ -68,7 +68,7 @@ macro_rules! follow ( ); ) -fn client_follow(+bank: bank::client::login) { +fn client_follow(bank: bank::client::login) { use bank::*; let bank = client::login(bank, ~"theincredibleholk", ~"1234"); @@ -89,7 +89,7 @@ fn client_follow(+bank: bank::client::login) { )); } -fn bank_client(+bank: bank::client::login) { +fn bank_client(bank: bank::client::login) { use bank::*; let bank = client::login(bank, ~"theincredibleholk", ~"1234"); diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs index bd0ffa6459067..55e43075204cc 100644 --- a/src/test/run-pass/pipe-detect-term.rs +++ b/src/test/run-pass/pipe-detect-term.rs @@ -29,7 +29,7 @@ proto! oneshot ( pub fn main() { let iotask = &uv::global_loop::get(); - + let (chan, port) = oneshot::init(); let port = Cell(port); do spawn { @@ -48,7 +48,7 @@ pub fn main() { fn failtest() { let (c, p) = oneshot::init(); - do task::spawn_with(c) |_c| { + do task::spawn_with(c) |_c| { fail!(); } diff --git a/src/test/run-pass/pipe-peek.rs b/src/test/run-pass/pipe-peek.rs index 46fbb88aef2e1..985eaecdc781b 100644 --- a/src/test/run-pass/pipe-peek.rs +++ b/src/test/run-pass/pipe-peek.rs @@ -22,11 +22,11 @@ proto! oneshot ( ) pub fn main() { - let (c, p) = oneshot::init(); + let mut (c, p) = oneshot::init(); - assert!(!pipes::peek(&p)); + assert!(!pipes::peek(&mut p)); oneshot::client::signal(c); - assert!(pipes::peek(&p)); + assert!(pipes::peek(&mut p)); } diff --git a/src/test/run-pass/pipe-pingpong-bounded.rs b/src/test/run-pass/pipe-pingpong-bounded.rs index 6d82663d19560..3c37371a5371c 100644 --- a/src/test/run-pass/pipe-pingpong-bounded.rs +++ b/src/test/run-pass/pipe-pingpong-bounded.rs @@ -40,7 +40,7 @@ mod pingpong { do pipes::entangle_buffer(buffer) |buffer, data| { data.ping.set_buffer(buffer); data.pong.set_buffer(buffer); - ptr::to_unsafe_ptr(&(data.ping)) + ptr::to_mut_unsafe_ptr(&mut (data.ping)) } } pub struct ping(server::pong); @@ -50,11 +50,11 @@ mod pingpong { use core::pipes::*; use core::ptr; - pub fn ping(+pipe: ping) -> pong { + pub fn ping(mut pipe: ping) -> pong { { - let b = pipe.reuse_buffer(); - let s = SendPacketBuffered(&b.buffer.data.pong); - let c = RecvPacketBuffered(&b.buffer.data.pong); + let mut b = pipe.reuse_buffer(); + let s = SendPacketBuffered(&mut b.buffer.data.pong); + let c = RecvPacketBuffered(&mut b.buffer.data.pong); let message = ::pingpong::ping(s); send(pipe, message); c @@ -72,11 +72,11 @@ mod pingpong { pub type ping = pipes::RecvPacketBuffered<::pingpong::ping, ::pingpong::Packets>; - pub fn pong(+pipe: pong) -> ping { + pub fn pong(mut pipe: pong) -> ping { { - let b = pipe.reuse_buffer(); - let s = SendPacketBuffered(&b.buffer.data.ping); - let c = RecvPacketBuffered(&b.buffer.data.ping); + let mut b = pipe.reuse_buffer(); + let s = SendPacketBuffered(&mut b.buffer.data.ping); + let c = RecvPacketBuffered(&mut b.buffer.data.ping); let message = ::pingpong::pong(s); send(pipe, message); c @@ -91,7 +91,7 @@ mod test { use core::pipes::recv; use pingpong::{ping, pong}; - pub fn client(+chan: ::pingpong::client::ping) { + pub fn client(chan: ::pingpong::client::ping) { use pingpong::client; let chan = client::ping(chan); return; @@ -99,8 +99,8 @@ mod test { let pong(_chan) = recv(chan); error!("Received pong"); } - - pub fn server(+chan: ::pingpong::server::ping) { + + pub fn server(chan: ::pingpong::server::ping) { use pingpong::server; let ping(chan) = recv(chan); return; diff --git a/src/test/run-pass/pipe-pingpong-proto.rs b/src/test/run-pass/pipe-pingpong-proto.rs index 65a5672941f28..5978438ef7635 100644 --- a/src/test/run-pass/pipe-pingpong-proto.rs +++ b/src/test/run-pass/pipe-pingpong-proto.rs @@ -29,7 +29,7 @@ mod test { use core::pipes::recv; use pingpong::{ping, pong}; - pub fn client(+chan: ::pingpong::client::ping) { + pub fn client(chan: ::pingpong::client::ping) { use pingpong::client; let chan = client::ping(chan); @@ -37,8 +37,8 @@ mod test { let pong(_chan) = recv(chan); error!(~"Received pong"); } - - pub fn server(+chan: ::pingpong::server::ping) { + + pub fn server(chan: ::pingpong::server::ping) { use pingpong::server; let ping(chan) = recv(chan); diff --git a/src/test/run-pass/pipe-presentation-examples.rs b/src/test/run-pass/pipe-presentation-examples.rs index 01f68929b90a7..fcfd77dab0aa3 100644 --- a/src/test/run-pass/pipe-presentation-examples.rs +++ b/src/test/run-pass/pipe-presentation-examples.rs @@ -1,4 +1,8 @@ // xfail-fast +// xfail-test + +// XFAIL'd because this is going to be revamped, and it's not compatible as +// written with the new mutability rules. // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index 12d60c9d6ab01..8782f6f6ebd15 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -55,8 +55,8 @@ pub fn main() { use stream::client::*; let iotask = &uv::global_loop::get(); - - let c = spawn_service(stream::init, |p| { + + let c = spawn_service(stream::init, |p| { error!("waiting for pipes"); let stream::send(x, p) = recv(p); error!("got pipes"); @@ -86,7 +86,7 @@ pub fn main() { let (_c2, p2) = oneshot::init(); let c = send(c, (p1, p2)); - + sleep(iotask, 100); signal(c1); diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index 86ffc96e89aec..da49a4303a6d7 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -55,6 +55,6 @@ pub fn main() { let iotask = &uv::global_loop::get(); sleep(iotask, 500); - + signal(c); } diff --git a/src/test/run-pass/placement-new-arena.rs b/src/test/run-pass/placement-new-arena.rs index 12c804219328e..166435cbc3d50 100644 --- a/src/test/run-pass/placement-new-arena.rs +++ b/src/test/run-pass/placement-new-arena.rs @@ -14,7 +14,8 @@ extern mod std; use std::arena; pub fn main() { - let p = &arena::Arena(); + let mut arena = arena::Arena(); + let p = &mut arena; let x = p.alloc(|| 4u); io::print(fmt!("%u", *x)); assert!(*x == 4u); diff --git a/src/test/run-pass/platform_thread.rs b/src/test/run-pass/platform_thread.rs index 5e4830b0bbdc3..774f2470b3cd3 100644 --- a/src/test/run-pass/platform_thread.rs +++ b/src/test/run-pass/platform_thread.rs @@ -24,9 +24,15 @@ fn run(i: int) { return; } - do task::task().sched_mode(task::PlatformThread).unlinked().spawn { + let mut builder = task::task(); + builder.sched_mode(task::PlatformThread); + builder.unlinked(); + do builder.spawn { task::yield(); - do task::task().sched_mode(task::SingleThreaded).unlinked().spawn { + let mut builder = task::task(); + builder.sched_mode(task::SingleThreaded); + builder.unlinked(); + do builder.spawn { task::yield(); run(i - 1); task::yield(); diff --git a/src/test/run-pass/preempt.rs b/src/test/run-pass/preempt.rs index e0434c14048a0..3d3e178f064ae 100644 --- a/src/test/run-pass/preempt.rs +++ b/src/test/run-pass/preempt.rs @@ -13,7 +13,7 @@ fn starve_main(alive: chan) { debug!("signalling main"); - alive <| 1; + alive.recv(1); debug!("starving main"); let i: int = 0; loop { i += 1; } @@ -22,10 +22,12 @@ fn starve_main(alive: chan) { pub fn main() { let alive: port = port(); debug!("main started"); - let s: task = spawn starve_main(chan(alive)); + let s: task = do task::spawn { + starve_main(chan(alive)); + }; let i: int; debug!("main waiting for alive signal"); - alive |> i; + alive.send(i); debug!("main got alive signal"); while i < 50 { debug!("main iterated"); i += 1; } debug!("main completed"); diff --git a/src/test/run-pass/pub-use-xcrate.rs b/src/test/run-pass/pub-use-xcrate.rs index 03004e5e47522..74ae81e63e239 100644 --- a/src/test/run-pass/pub-use-xcrate.rs +++ b/src/test/run-pass/pub-use-xcrate.rs @@ -21,4 +21,3 @@ pub fn main() { name: 0 }; } - diff --git a/src/test/run-pass/pub_use_mods_xcrate_exe.rs b/src/test/run-pass/pub_use_mods_xcrate_exe.rs index 1d60cab3a82ef..953a99e1fd5be 100644 --- a/src/test/run-pass/pub_use_mods_xcrate_exe.rs +++ b/src/test/run-pass/pub_use_mods_xcrate_exe.rs @@ -15,4 +15,3 @@ extern mod pub_use_mods_xcrate; use pub_use_mods_xcrate::a::c; pub fn main(){} - diff --git a/src/test/run-pass/reexport-star.rs b/src/test/run-pass/reexport-star.rs index 3b9fe688d4d1e..3cc250b170744 100644 --- a/src/test/run-pass/reexport-star.rs +++ b/src/test/run-pass/reexport-star.rs @@ -25,4 +25,3 @@ pub fn main() { b::f(); b::g(); } - diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index e520d221c9935..5255c13bead62 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -513,16 +513,16 @@ impl TyVisitor for my_visitor { fn visit_bot(&self) -> bool { true } fn visit_nil(&self) -> bool { true } fn visit_bool(&self) -> bool { - do self.get::() |b| { - self.vals += ~[bool::to_str(b)]; - }; - true + do self.get::() |b| { + self.vals.push(bool::to_str(b)); + }; + true } fn visit_int(&self) -> bool { - do self.get::() |i| { - self.vals += ~[int::to_str(i)]; - }; - true + do self.get::() |i| { + self.vals.push(int::to_str(i)); + }; + true } fn visit_i8(&self) -> bool { true } fn visit_i16(&self) -> bool { true } @@ -633,7 +633,7 @@ impl TyVisitor for my_visitor { fn visit_closure_ptr(&self, _ck: uint) -> bool { true } } -fn get_tydesc_for(&&_t: T) -> *TyDesc { +fn get_tydesc_for(_t: T) -> *TyDesc { get_tydesc::() } diff --git a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs index 1fb9c126e74e2..7efe62236f35e 100644 --- a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs +++ b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs @@ -26,4 +26,3 @@ fn get_x<'r>(x: &'r Character) -> &'r int { pub fn main() { } - diff --git a/src/test/run-pass/regions-addr-of-ret.rs b/src/test/run-pass/regions-addr-of-ret.rs index a9c65d012954c..9e19618f332e0 100644 --- a/src/test/run-pass/regions-addr-of-ret.rs +++ b/src/test/run-pass/regions-addr-of-ret.rs @@ -16,4 +16,3 @@ pub fn main() { let three = &3; error!(fmt!("%d", *f(three))); } - diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index 308528ef57200..2e9ff88f96e90 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -12,7 +12,7 @@ struct closure_box<'self> { cl: &'self fn(), } -fn box_it<'r>(+x: &'r fn()) -> closure_box<'r> { +fn box_it<'r>(x: &'r fn()) -> closure_box<'r> { closure_box {cl: x} } diff --git a/src/test/run-pass/regions-fn-subtyping-2.rs b/src/test/run-pass/regions-fn-subtyping-2.rs index a995b3d969352..ef8d9970c2b47 100644 --- a/src/test/run-pass/regions-fn-subtyping-2.rs +++ b/src/test/run-pass/regions-fn-subtyping-2.rs @@ -8,23 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - // Issue #2263. // Here, `f` is a function that takes a pointer `x` and a function // `g`, where `g` requires its argument `y` to be in the same region // that `x` is in. -fn has_same_region(f: &fn(x: &a.int, g: &fn(y: &a.int))) { +fn has_same_region(f: &fn<'a>(x: &'a int, g: &fn(y: &'a int))) { // `f` should be the type that `wants_same_region` wants, but // right now the compiler complains that it isn't. wants_same_region(f); } -fn wants_same_region(_f: &fn(x: &b.int, g: &fn(y: &b.int))) { +fn wants_same_region(_f: &fn<'b>(x: &'b int, g: &fn(y: &'b int))) { } pub fn main() { } - - diff --git a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs index ee2682ff4ab93..a87a899cafeaf 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs @@ -8,22 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + pub fn main() { let mut x = 4; for uint::range(0, 3) |i| { // ensure that the borrow in this alt - // does not inferfere with the swap - // below. note that it would it you - // naively borrowed &x for the lifetime - // of the variable x, as we once did + // does not inferfere with the swap + // below. note that it would it you + // naively borrowed &x for the lifetime + // of the variable x, as we once did match i { - i => { - let y = &x; - assert!(i < *y); - } + i => { + let y = &x; + assert!(i < *y); + } } let mut y = 4; - y <-> x; + util::swap(&mut y, &mut x); } } diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 9358ea8a77724..8f7452f2d06ed 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -16,4 +16,3 @@ pub fn main() { let y = view(x); assert!((v[0] == x[0]) && (v[0] == y[0])); } - diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index 08c54c790b1f0..73535f52043eb 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -15,6 +15,6 @@ pub fn main() { loop { let y = borrow(x); assert!(*x == *y); - break; + break; } } diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index e06a2fea1c194..61b9000aea318 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -19,4 +19,3 @@ pub fn main() { let xc = x_coord(p); assert!(*xc == 3); } - diff --git a/src/test/run-pass/regions-mock-trans-impls.rs b/src/test/run-pass/regions-mock-trans-impls.rs deleted file mode 100644 index c1f7a713ca679..0000000000000 --- a/src/test/run-pass/regions-mock-trans-impls.rs +++ /dev/null @@ -1,51 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern mod std; -use core::libc; -use core::sys; -use core::cast; -use std::arena::Arena; - -struct Bcx<'self> { - fcx: &'self Fcx<'self> -} - -struct Fcx<'self> { - arena: &'self Arena, - ccx: &'self Ccx -} - -struct Ccx { - x: int -} - -fn h<'r>(bcx : &'r Bcx<'r>) -> &'r Bcx<'r> { - return bcx.fcx.arena.alloc(|| Bcx { fcx: bcx.fcx }); -} - -fn g(fcx : &Fcx) { - let bcx = Bcx { fcx: fcx }; - h(&bcx); -} - -fn f(ccx : &Ccx) { - let a = Arena(); - let fcx = &Fcx { arena: &a, ccx: ccx }; - return g(fcx); -} - -pub fn main() { - let ccx = Ccx { x: 0 }; - f(&ccx); -} - diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index c46e41ab0eb1c..0ea6f852a897c 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -52,4 +52,3 @@ pub fn main() { let ccx = Ccx { x: 0 }; f(&ccx); } - diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs index 2f4eefe5243ad..c43fd0db5666c 100644 --- a/src/test/run-pass/regions-self-impls.rs +++ b/src/test/run-pass/regions-self-impls.rs @@ -25,4 +25,3 @@ pub fn main() { debug!(*clam.get_chowder()); clam.get_chowder(); } - diff --git a/src/test/run-pass/regions-self-in-enums.rs b/src/test/run-pass/regions-self-in-enums.rs index 78045e5e5d410..5f8b9ee333289 100644 --- a/src/test/run-pass/regions-self-in-enums.rs +++ b/src/test/run-pass/regions-self-in-enums.rs @@ -21,4 +21,3 @@ pub fn main() { } debug!(*z); } - diff --git a/src/test/run-pass/regions-simple.rs b/src/test/run-pass/regions-simple.rs index f7a50e6b114a3..436fede4dc11e 100644 --- a/src/test/run-pass/regions-simple.rs +++ b/src/test/run-pass/regions-simple.rs @@ -14,5 +14,3 @@ pub fn main() { *y = 5; debug!(*y); } - - diff --git a/src/test/run-pass/regions-static-closure.rs b/src/test/run-pass/regions-static-closure.rs index 5221bc28fb838..eab057548ef5e 100644 --- a/src/test/run-pass/regions-static-closure.rs +++ b/src/test/run-pass/regions-static-closure.rs @@ -12,7 +12,7 @@ struct closure_box<'self> { cl: &'self fn(), } -fn box_it<'r>(+x: &'r fn()) -> closure_box<'r> { +fn box_it<'r>(x: &'r fn()) -> closure_box<'r> { closure_box {cl: x} } diff --git a/src/test/run-pass/repeated-vector-syntax.rs b/src/test/run-pass/repeated-vector-syntax.rs index a22384a6b53d0..f3d6c1640d881 100644 --- a/src/test/run-pass/repeated-vector-syntax.rs +++ b/src/test/run-pass/repeated-vector-syntax.rs @@ -21,4 +21,3 @@ pub fn main() { error!("%?", x); error!("%?", y); } - diff --git a/src/test/run-pass/resource-cycle.rs b/src/test/run-pass/resource-cycle.rs index fdb8c2a496c6b..f498553834a1e 100644 --- a/src/test/run-pass/resource-cycle.rs +++ b/src/test/run-pass/resource-cycle.rs @@ -57,7 +57,7 @@ pub fn main() { debug!("r = %x", cast::transmute::<*r, uint>(&rs)); rs } }); - + debug!("x1 = %x, x1.r = %x", cast::transmute::<@mut t, uint>(x1), cast::transmute::<*r, uint>(&x1.r)); @@ -70,7 +70,7 @@ pub fn main() { rs } }); - + debug!("x2 = %x, x2.r = %x", cast::transmute::<@mut t, uint>(x2), cast::transmute::<*r, uint>(&(x2.r))); diff --git a/src/test/run-pass/resource-cycle3.rs b/src/test/run-pass/resource-cycle3.rs index 0d699a6e49b6c..ef71372477862 100644 --- a/src/test/run-pass/resource-cycle3.rs +++ b/src/test/run-pass/resource-cycle3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// same as resource-cycle2, but be sure to give r multiple fields... +// same as resource-cycle2, but be sure to give r multiple fields... // Don't leak the unique pointers @@ -50,7 +50,7 @@ struct Node { r: R } -pub fn main() { +pub fn main() { unsafe { let i1 = ~0xA; let i1p = cast::transmute_copy(&i1); diff --git a/src/test/run-pass/ret-break-cont-in-block.rs b/src/test/run-pass/ret-break-cont-in-block.rs index ab61cee422300..1792a89d64f1e 100644 --- a/src/test/run-pass/ret-break-cont-in-block.rs +++ b/src/test/run-pass/ret-break-cont-in-block.rs @@ -12,12 +12,13 @@ use core::cmp::Eq; -fn iter(v: ~[T], it: &fn(&T) -> bool) { +fn iter(v: ~[T], it: &fn(&T) -> bool) -> bool { let mut i = 0u, l = v.len(); while i < l { - if !it(&v[i]) { break; } + if !it(&v[i]) { return false; } i += 1u; } + return true; } fn find_pos(n: T, h: ~[T]) -> Option { diff --git a/src/test/run-pass/self-type-param.rs b/src/test/run-pass/self-type-param.rs index 0af197968040f..d90ec51bedfa2 100644 --- a/src/test/run-pass/self-type-param.rs +++ b/src/test/run-pass/self-type-param.rs @@ -13,4 +13,3 @@ impl MyTrait for S { } pub fn main() {} - diff --git a/src/test/run-pass/sendfn-spawn-with-fn-arg.rs b/src/test/run-pass/sendfn-spawn-with-fn-arg.rs index afed0bd9ac3f8..2a69b2ca01779 100644 --- a/src/test/run-pass/sendfn-spawn-with-fn-arg.rs +++ b/src/test/run-pass/sendfn-spawn-with-fn-arg.rs @@ -12,7 +12,7 @@ use core::cell::Cell; pub fn main() { test05(); } -fn test05_start(&&f: ~fn(int)) { +fn test05_start(f: ~fn(int)) { f(22); } diff --git a/src/test/run-pass/simd-type.rs b/src/test/run-pass/simd-type.rs new file mode 100644 index 0000000000000..c3bcc9d0b7a02 --- /dev/null +++ b/src/test/run-pass/simd-type.rs @@ -0,0 +1,9 @@ +#[simd] +struct RGBA { + r: f32, + g: f32, + b: f32, + a: f32 +} + +fn main() {} diff --git a/src/test/run-pass/spawn.rs b/src/test/run-pass/spawn.rs index db4ca7b3ed863..9a5131ef23000 100644 --- a/src/test/run-pass/spawn.rs +++ b/src/test/run-pass/spawn.rs @@ -17,12 +17,4 @@ pub fn main() { task::spawn(|| child(10) ); } -fn child(&&i: int) { error!(i); assert!((i == 10)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: +fn child(i: int) { error!(i); assert!((i == 10)); } diff --git a/src/test/run-pass/spawn2.rs b/src/test/run-pass/spawn2.rs index f9350746349b3..642babb5a1e5c 100644 --- a/src/test/run-pass/spawn2.rs +++ b/src/test/run-pass/spawn2.rs @@ -11,7 +11,7 @@ pub fn main() { task::spawn(|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) ); } -fn child(&&args: (int, int, int, int, int, int, int, int, int)) { +fn child(args: (int, int, int, int, int, int, int, int, int)) { let (i1, i2, i3, i4, i5, i6, i7, i8, i9) = args; error!(i1); error!(i2); @@ -32,11 +32,3 @@ fn child(&&args: (int, int, int, int, int, int, int, int, int)) { assert!((i8 == 80)); assert!((i9 == 90)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/static-method-test.rs b/src/test/run-pass/static-method-test.rs index 973897cd14521..e06d09c564c00 100644 --- a/src/test/run-pass/static-method-test.rs +++ b/src/test/run-pass/static-method-test.rs @@ -13,7 +13,7 @@ // A trait for objects that can be used to do an if-then-else // (No actual need for this to be static, but it is a simple test.) trait bool_like { - fn select(b: Self, +x1: A, +x2: A) -> A; + fn select(b: Self, x1: A, x2: A) -> A; } fn andand(x1: T, x2: T) -> T { @@ -21,38 +21,38 @@ fn andand(x1: T, x2: T) -> T { } impl bool_like for bool { - fn select(&&b: bool, +x1: A, +x2: A) -> A { + fn select(b: bool, x1: A, x2: A) -> A { if b { x1 } else { x2 } } } impl bool_like for int { - fn select(&&b: int, +x1: A, +x2: A) -> A { + fn select(b: int, x1: A, x2: A) -> A { if b != 0 { x1 } else { x2 } } } // A trait for sequences that can be constructed imperatively. trait buildable { - fn build_sized(size: uint, builder: &fn(push: &fn(+v: A))) -> Self; + fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> Self; } impl buildable for @[A] { #[inline(always)] - fn build_sized(size: uint, builder: &fn(push: &fn(+v: A))) -> @[A] { + fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { at_vec::build_sized(size, builder) } } impl buildable for ~[A] { #[inline(always)] - fn build_sized(size: uint, builder: &fn(push: &fn(+v: A))) -> ~[A] { + fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> ~[A] { vec::build_sized(size, builder) } } #[inline(always)] -fn build>(builder: &fn(push: &fn(+v: A))) -> B { +fn build>(builder: &fn(push: &fn(v: A))) -> B { buildable::build_sized(4, builder) } diff --git a/src/test/run-pass/static-methods-in-traits.rs b/src/test/run-pass/static-methods-in-traits.rs index d171434aa482d..42d0f02d6425c 100644 --- a/src/test/run-pass/static-methods-in-traits.rs +++ b/src/test/run-pass/static-methods-in-traits.rs @@ -9,27 +9,26 @@ // except according to those terms. mod a { - pub trait Foo { - pub fn foo() -> Self; - } + pub trait Foo { + pub fn foo() -> Self; + } - impl Foo for int { - pub fn foo() -> int { - 3 - } - } - - impl Foo for uint { - pub fn foo() -> uint { - 5u - } - } + impl Foo for int { + pub fn foo() -> int { + 3 + } + } + + impl Foo for uint { + pub fn foo() -> uint { + 5u + } + } } pub fn main() { - let x: int = a::Foo::foo(); - let y: uint = a::Foo::foo(); - assert!(x == 3); - assert!(y == 5); + let x: int = a::Foo::foo(); + let y: uint = a::Foo::foo(); + assert!(x == 3); + assert!(y == 5); } - diff --git a/src/test/run-pass/struct-deref.rs b/src/test/run-pass/struct-deref.rs index f71bc06a1cf8d..a52a2851689bb 100644 --- a/src/test/run-pass/struct-deref.rs +++ b/src/test/run-pass/struct-deref.rs @@ -14,4 +14,3 @@ pub fn main() { let x: Foo = Foo(2); assert!(*x == 2); } - diff --git a/src/test/run-pass/struct-field-assignability.rs b/src/test/run-pass/struct-field-assignability.rs index 1e13c7b86bf8c..0aca1a3d05fdf 100644 --- a/src/test/run-pass/struct-field-assignability.rs +++ b/src/test/run-pass/struct-field-assignability.rs @@ -6,4 +6,3 @@ pub fn main() { let f = Foo { x: @3 }; assert!(*f.x == 3); } - diff --git a/src/test/run-pass/struct-like-variant-construct.rs b/src/test/run-pass/struct-like-variant-construct.rs index 0d14d90c1f1aa..bc2dce680c956 100644 --- a/src/test/run-pass/struct-like-variant-construct.rs +++ b/src/test/run-pass/struct-like-variant-construct.rs @@ -22,4 +22,3 @@ enum Foo { pub fn main() { let x = Bar { a: 2, b: 3 }; } - diff --git a/src/test/run-pass/struct-like-variant-match.rs b/src/test/run-pass/struct-like-variant-match.rs index 3158d2836ddde..64a75ddab22b7 100644 --- a/src/test/run-pass/struct-like-variant-match.rs +++ b/src/test/run-pass/struct-like-variant-match.rs @@ -38,4 +38,3 @@ pub fn main() { let y = Baz { x: 1.0, y: 2.0 }; f(&y); } - diff --git a/src/test/run-pass/struct-order-of-eval-1.rs b/src/test/run-pass/struct-order-of-eval-1.rs index db7c73cbfc5ea..884459cf069f4 100644 --- a/src/test/run-pass/struct-order-of-eval-1.rs +++ b/src/test/run-pass/struct-order-of-eval-1.rs @@ -12,5 +12,5 @@ struct S { f0: ~str, f1: int } pub fn main() { let s = ~"Hello, world!"; - let _s = S { f0: str::from_slice(s), ..S { f0: s, f1: 23 } }; + let _s = S { f0: str::to_owned(s), ..S { f0: s, f1: 23 } }; } diff --git a/src/test/run-pass/struct-order-of-eval-2.rs b/src/test/run-pass/struct-order-of-eval-2.rs index 413f185659a6f..419c4ac3942f8 100644 --- a/src/test/run-pass/struct-order-of-eval-2.rs +++ b/src/test/run-pass/struct-order-of-eval-2.rs @@ -12,5 +12,5 @@ struct S { f0: ~str, f1: ~str } pub fn main() { let s = ~"Hello, world!"; - let _s = S { f1: str::from_slice(s), f0: s }; + let _s = S { f1: str::to_owned(s), f0: s }; } diff --git a/src/test/run-pass/struct-pattern-matching.rs b/src/test/run-pass/struct-pattern-matching.rs index 1d7bcb2585fbd..1bda2d2412d2a 100644 --- a/src/test/run-pass/struct-pattern-matching.rs +++ b/src/test/run-pass/struct-pattern-matching.rs @@ -19,6 +19,3 @@ pub fn main() { Foo { x: x, y: y } => io::println(fmt!("yes, %d, %d", x, y)) } } - - - diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs index 5427ee38b430c..7ac74fd52175f 100644 --- a/src/test/run-pass/struct-return.rs +++ b/src/test/run-pass/struct-return.rs @@ -16,8 +16,8 @@ mod rustrt { #[nolink] pub extern { - pub fn debug_abi_1(++q: Quad) -> Quad; - pub fn debug_abi_2(++f: Floats) -> Floats; + pub fn debug_abi_1(q: Quad) -> Quad; + pub fn debug_abi_2(f: Floats) -> Floats; } } diff --git a/src/test/run-pass/super.rs b/src/test/run-pass/super.rs index 2fe0696b2f261..b5eb6e850456e 100644 --- a/src/test/run-pass/super.rs +++ b/src/test/run-pass/super.rs @@ -9,4 +9,3 @@ pub mod a { pub fn main() { } - diff --git a/src/test/run-pass/swap-1.rs b/src/test/run-pass/swap-1.rs index feb7a88dc3480..ed69fa41d711f 100644 --- a/src/test/run-pass/swap-1.rs +++ b/src/test/run-pass/swap-1.rs @@ -8,7 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + pub fn main() { let mut x = 3; let mut y = 7; - x <-> y; assert!((x == 7)); assert!((y == 3)); + util::swap(&mut x, &mut y); + assert!((x == 7)); assert!((y == 3)); } diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs index 24794b0359168..63b377b26d83e 100644 --- a/src/test/run-pass/swap-2.rs +++ b/src/test/run-pass/swap-2.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn swap(v: &mut [T], i: int, j: int) { v[i] <-> v[j]; } +use core::util; pub fn main() { let mut a: ~[int] = ~[0, 1, 2, 3, 4, 5, 6]; - swap(a, 2, 4); + vec::swap(a, 2, 4); assert!((a[2] == 4)); assert!((a[4] == 2)); let mut n = 42; - n <-> a[0]; + util::swap(&mut n, &mut a[0]); assert!((a[0] == 42)); assert!((n == 0)); } diff --git a/src/test/run-pass/swap-overlapping.rs b/src/test/run-pass/swap-overlapping.rs index 90b2ceef71a76..05f943bf928ca 100644 --- a/src/test/run-pass/swap-overlapping.rs +++ b/src/test/run-pass/swap-overlapping.rs @@ -10,6 +10,8 @@ // Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same +use core::util; + pub fn main() { let mut test = TestDescAndFn { desc: TestDesc { @@ -22,7 +24,10 @@ pub fn main() { } fn do_swap(test: &mut TestDescAndFn) { - *test <-> *test; + unsafe { + util::swap_ptr(ptr::to_mut_unsafe_ptr(test), + ptr::to_mut_unsafe_ptr(test)); + } } pub enum TestName { diff --git a/src/test/run-pass/tag-align-dyn-u64.rs b/src/test/run-pass/tag-align-dyn-u64.rs index a9c59de49eeaa..a09ee23f1478a 100644 --- a/src/test/run-pass/tag-align-dyn-u64.rs +++ b/src/test/run-pass/tag-align-dyn-u64.rs @@ -10,25 +10,25 @@ // xfail-test -tag a_tag { - a_tag(A); +enum a_tag { + a_tag(A) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} fn mk_rec() -> t_rec { - return { c8:0u8, t:a_tag(0u64) }; + return t_rec { c8:0u8, t:a_tag(0u64) }; } -fn is_8_byte_aligned(&&u: a_tag) -> bool { +fn is_8_byte_aligned(u: &a_tag) -> bool { let p = ptr::to_unsafe_ptr(u) as uint; return (p & 7u) == 0u; } pub fn main() { let x = mk_rec(); - assert!(is_8_byte_aligned(x.t)); + assert!(is_8_byte_aligned(&x.t)); } diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index 4fc6410f8f3d0..cd94bd30c21e0 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -10,62 +10,62 @@ // xfail-test -tag a_tag { - varA(A); - varB(B); +enum a_tag { + varA(A), + varB(B) } -type t_rec = { +struct t_rec { chA: u8, tA: a_tag, chB: u8, tB: a_tag -}; +} -fn mk_rec(a: A, b: B) -> t_rec { - return { chA:0u8, tA:varA(a), chB:1u8, tB:varB(b) }; +fn mk_rec(a: A, b: B) -> t_rec { + return t_rec{ chA:0u8, tA:varA(a), chB:1u8, tB:varB(b) }; } -fn is_aligned(amnt: uint, &&u: A) -> bool { +fn is_aligned(amnt: uint, u: &A) -> bool { let p = ptr::to_unsafe_ptr(u) as uint; return (p & (amnt-1u)) == 0u; } -fn variant_data_is_aligned(amnt: uint, &&u: a_tag) -> bool { +fn variant_data_is_aligned(amnt: uint, u: &a_tag) -> bool { match u { - varA(a) { is_aligned(amnt, a) } - varB(b) { is_aligned(amnt, b) } + &varA(ref a) => is_aligned(amnt, a), + &varB(ref b) => is_aligned(amnt, b) } } pub fn main() { let x = mk_rec(22u64, 23u64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); let x = mk_rec(22u64, 23u32); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(4u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(4u, &x.tB)); let x = mk_rec(22u32, 23u64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(4u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(4u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); let x = mk_rec(22u32, 23u32); - assert!(is_aligned(4u, x.tA)); - assert!(variant_data_is_aligned(4u, x.tA)); - assert!(is_aligned(4u, x.tB)); - assert!(variant_data_is_aligned(4u, x.tB)); + assert!(is_aligned(4u, &x.tA)); + assert!(variant_data_is_aligned(4u, &x.tA)); + assert!(is_aligned(4u, &x.tB)); + assert!(variant_data_is_aligned(4u, &x.tB)); let x = mk_rec(22f64, 23f64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); } diff --git a/src/test/run-pass/tag-align-shape.rs b/src/test/run-pass/tag-align-shape.rs index 052bacad7ce19..43a793a34c89d 100644 --- a/src/test/run-pass/tag-align-shape.rs +++ b/src/test/run-pass/tag-align-shape.rs @@ -8,22 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -// -// See issue #1535 - -tag a_tag { - a_tag(u64); +enum a_tag { + a_tag(u64) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} pub fn main() { - let x = {c8: 22u8, t: a_tag(44u64)}; + let x = t_rec {c8: 22u8, t: a_tag(44u64)}; let y = fmt!("%?", x); debug!("y = %s", y); - assert!(y == "(22, a_tag(44))"); + assert_eq!(y, ~"{c8: 22, t: a_tag(44)}"); } diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index fd96d7d0242c3..ea60f389663cf 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -10,25 +10,25 @@ // xfail-test -tag a_tag { - a_tag(u64); +enum a_tag { + a_tag(u64) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} fn mk_rec() -> t_rec { - return { c8:0u8, t:a_tag(0u64) }; + return t_rec { c8:0u8, t:a_tag(0u64) }; } -fn is_8_byte_aligned(&&u: a_tag) -> bool { +fn is_8_byte_aligned(u: &a_tag) -> bool { let p = ptr::to_unsafe_ptr(u) as u64; return (p & 7u64) == 0u64; } pub fn main() { let x = mk_rec(); - assert!(is_8_byte_aligned(x.t)); + assert!(is_8_byte_aligned(&x.t)); } diff --git a/src/test/run-pass/tag-disr-val-shape.rs b/src/test/run-pass/tag-disr-val-shape.rs index 50ab17fdeeae9..dd78dff0d6ea7 100644 --- a/src/test/run-pass/tag-disr-val-shape.rs +++ b/src/test/run-pass/tag-disr-val-shape.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(~"green" == fmt!("%?", green)); assert!(~"white" == fmt!("%?", white)); } - diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index 0806f1ea92aec..d4eadd366de06 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -69,5 +69,3 @@ fn get_color_if(color: color) -> ~str { else if color == orange {~"orange"} else {~"unknown"} } - - diff --git a/src/test/run-pass/task-comm-12.rs b/src/test/run-pass/task-comm-12.rs index b426212d872f2..0f0b82d7c21df 100644 --- a/src/test/run-pass/task-comm-12.rs +++ b/src/test/run-pass/task-comm-12.rs @@ -12,12 +12,14 @@ extern mod std; pub fn main() { test00(); } -fn start(&&task_number: int) { debug!("Started / Finished task."); } +fn start(task_number: int) { debug!("Started / Finished task."); } fn test00() { let i: int = 0; let mut result = None; - do task::task().future_result(|+r| { result = Some(r); }).spawn { + let mut builder = task::task(); + builder.future_result(|r| result = Some(r)); + do builder.spawn { start(i) } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index cf06deb1923a6..fd700475988cf 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -40,9 +40,9 @@ fn test00() { let mut results = ~[]; while i < number_of_tasks { let ch = po.chan(); - task::task().future_result(|+r| { - results.push(r); - }).spawn({ + let mut builder = task::task(); + builder.future_result(|r| results.push(r)); + builder.spawn({ let i = i; || test00_start(&ch, i, number_of_messages) }); diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index a3c8dc554a663..798e9d37b5534 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -27,8 +27,9 @@ fn test00() { let ch = p.chan(); let mut result = None; - do task::task().future_result(|+r| { result = Some(r); }).spawn - || { + let mut builder = task::task(); + builder.future_result(|r| result = Some(r)); + do builder.spawn { test00_start(&ch, number_of_messages); } diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index 7cd08695da0f0..879f668577f86 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -83,11 +83,3 @@ fn supervisor() { pub fn main() { join(joinable(supervisor)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/task-killjoin.rs b/src/test/run-pass/task-killjoin.rs index 563e35be3d63b..73c069e560cd0 100644 --- a/src/test/run-pass/task-killjoin.rs +++ b/src/test/run-pass/task-killjoin.rs @@ -33,11 +33,3 @@ fn supervisor() { pub fn main() { task::spawn_unlinked(supervisor) } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/task-life-0.rs b/src/test/run-pass/task-life-0.rs index 3e27ffb415239..9885c5d6f3fc0 100644 --- a/src/test/run-pass/task-life-0.rs +++ b/src/test/run-pass/task-life-0.rs @@ -13,6 +13,6 @@ pub fn main() { task::spawn(|| child(~"Hello") ); } -fn child(&&s: ~str) { +fn child(s: ~str) { } diff --git a/src/test/run-pass/threads.rs b/src/test/run-pass/threads.rs index f736ded3db2a5..a72d3dd40f4ca 100644 --- a/src/test/run-pass/threads.rs +++ b/src/test/run-pass/threads.rs @@ -18,5 +18,4 @@ pub fn main() { debug!("main thread exiting"); } -fn child(&&x: int) { debug!(x); } - +fn child(x: int) { debug!(x); } diff --git a/src/test/run-pass/trait-composition-trivial.rs b/src/test/run-pass/trait-composition-trivial.rs index 328c0b6888cc9..de130bf1b41fe 100644 --- a/src/test/run-pass/trait-composition-trivial.rs +++ b/src/test/run-pass/trait-composition-trivial.rs @@ -17,5 +17,3 @@ trait Bar : Foo { } pub fn main() {} - - diff --git a/src/test/run-pass/trait-inheritance-auto-xc-2.rs b/src/test/run-pass/trait-inheritance-auto-xc-2.rs index 446dd4b3d8ee1..996f55d4019a8 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc-2.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc-2.rs @@ -30,4 +30,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-auto-xc.rs b/src/test/run-pass/trait-inheritance-auto-xc.rs index 03287809a9be1..3af8d606bf4ae 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc.rs @@ -31,4 +31,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs index b74064591d3bc..fb97dd5e7741a 100644 --- a/src/test/run-pass/trait-inheritance-auto.rs +++ b/src/test/run-pass/trait-inheritance-auto.rs @@ -34,4 +34,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs index 26b96f933269b..805c9655d81d4 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs @@ -25,4 +25,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(gg(a) == 10); } - diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs index 5e612bbca6487..0b35fd90bbd19 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs @@ -28,4 +28,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(gg(a) == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs index 6efd854e01b42..df9cc4fb8b6d4 100644 --- a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs +++ b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs @@ -38,4 +38,3 @@ pub fn main() { assert!(afoo.f() == 10); assert!(abar.g() == 20); } - diff --git a/src/test/run-pass/trait-inheritance-cast.rs b/src/test/run-pass/trait-inheritance-cast.rs index 023827977976e..75c121e10b014 100644 --- a/src/test/run-pass/trait-inheritance-cast.rs +++ b/src/test/run-pass/trait-inheritance-cast.rs @@ -40,4 +40,3 @@ pub fn main() { assert!(abar.g() == 20); assert!(abar.f() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index 3c1bf2035aa71..976c9a0243927 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -27,4 +27,3 @@ pub fn main() { let a = &aux::A { x: 3 }; assert!(a.g() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call.rs b/src/test/run-pass/trait-inheritance-cross-trait-call.rs index 997f13d0e5e35..20dac16b4927d 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call.rs @@ -24,4 +24,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(a.g() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 0fb2a6b2e724b..5179d13813cea 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -14,11 +14,10 @@ extern mod std; use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -use std::cmp::FuzzyEq; pub trait NumExt: Num + NumCast + Eq + Ord {} -pub trait FloatExt: NumExt + FuzzyEq {} +pub trait FloatExt: NumExt + ApproxEq {} fn greater_than_one(n: &T) -> bool { *n > from(1) } fn greater_than_one_float(n: &T) -> bool { *n > from(1) } diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index b40f647814f0c..f7edd2855a4cd 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -16,7 +16,6 @@ extern mod std; use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -use std::cmp::FuzzyEq; pub trait TypeExt {} @@ -94,7 +93,7 @@ impl IntegerExt for i64 {} impl IntegerExt for int {} -pub trait FloatExt: NumExt + FuzzyEq {} +pub trait FloatExt: NumExt + ApproxEq {} impl FloatExt for f32 {} impl FloatExt for f64 {} diff --git a/src/test/run-pass/trait-inheritance-overloading-simple.rs b/src/test/run-pass/trait-inheritance-overloading-simple.rs index 711571e8c64f5..3a1c3716df442 100644 --- a/src/test/run-pass/trait-inheritance-overloading-simple.rs +++ b/src/test/run-pass/trait-inheritance-overloading-simple.rs @@ -32,4 +32,3 @@ pub fn main() { assert!(x != y); assert!(x == z); } - diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index 9f745db76386c..d89852e2b05f9 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -27,4 +27,3 @@ pub fn main() { assert!(b == mi(-2)); assert!(c == mi(15)); } - diff --git a/src/test/run-pass/trait-inheritance-overloading.rs b/src/test/run-pass/trait-inheritance-overloading.rs index 5b68aff269e3c..e58ec24f1b7d4 100644 --- a/src/test/run-pass/trait-inheritance-overloading.rs +++ b/src/test/run-pass/trait-inheritance-overloading.rs @@ -46,4 +46,3 @@ pub fn main() { assert!(b == mi(-2)); assert!(c == mi(15)); } - diff --git a/src/test/run-pass/trait-inheritance-self.rs b/src/test/run-pass/trait-inheritance-self.rs index 02ed518ff6591..5eb87b7a96b8b 100644 --- a/src/test/run-pass/trait-inheritance-self.rs +++ b/src/test/run-pass/trait-inheritance-self.rs @@ -26,4 +26,3 @@ pub fn main() { let s = S { x: 1 }; s.g(); } - diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs index 779dfb65944c9..2da1f02779e0a 100644 --- a/src/test/run-pass/trait-inheritance-simple.rs +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(ff(a) == 10); assert!(gg(a) == 20); } - diff --git a/src/test/run-pass/trait-inheritance-subst.rs b/src/test/run-pass/trait-inheritance-subst.rs index 22efdabec83ab..479f293a396e3 100644 --- a/src/test/run-pass/trait-inheritance-subst.rs +++ b/src/test/run-pass/trait-inheritance-subst.rs @@ -33,4 +33,3 @@ pub fn main() { let z = f(x, y); assert!(z.val == 8) } - diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs index 4f3b808f8ebc0..5d1741a45f327 100644 --- a/src/test/run-pass/trait-inheritance-subst2.rs +++ b/src/test/run-pass/trait-inheritance-subst2.rs @@ -43,4 +43,3 @@ pub fn main() { let z = f(x, y); assert!(z.val == 13); } - diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs index 5d6913d4146b9..adb7ab018d6c4 100644 --- a/src/test/run-pass/trait-inheritance2.rs +++ b/src/test/run-pass/trait-inheritance2.rs @@ -31,4 +31,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-region-pointer-simple.rs b/src/test/run-pass/trait-region-pointer-simple.rs index 285b0e65daf67..a2742828a1bc0 100644 --- a/src/test/run-pass/trait-region-pointer-simple.rs +++ b/src/test/run-pass/trait-region-pointer-simple.rs @@ -28,4 +28,3 @@ pub fn main() { let b = (&a) as &Foo; assert!(b.f() == 3); } - diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs index a8a579422a372..86ebc5356ebdc 100644 --- a/src/test/run-pass/trait-static-method-overwriting.rs +++ b/src/test/run-pass/trait-static-method-overwriting.rs @@ -21,7 +21,7 @@ mod base { impl ::base::HasNew for Foo { fn new() -> Foo { - unsafe { io::println("Foo"); } + unsafe { io::println("Foo"); } Foo { dummy: () } } } @@ -32,7 +32,7 @@ mod base { impl ::base::HasNew for Bar { fn new() -> Bar { - unsafe { io::println("Bar"); } + unsafe { io::println("Bar"); } Bar { dummy: () } } } @@ -40,5 +40,5 @@ mod base { pub fn main() { let f: base::Foo = base::HasNew::new::(); - let b: base::Bar = base::HasNew::new::(); + let b: base::Bar = base::HasNew::new::(); } diff --git a/src/test/compile-fail/liveness-swap-uninit.rs b/src/test/run-pass/trait_with_static_methods_cross_crate.rs similarity index 69% rename from src/test/compile-fail/liveness-swap-uninit.rs rename to src/test/run-pass/trait_with_static_methods_cross_crate.rs index b2d475dd78926..1af8629468024 100644 --- a/src/test/compile-fail/liveness-swap-uninit.rs +++ b/src/test/run-pass/trait_with_static_methods_cross_crate.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - let mut x = 3; - let y; - x <-> y; //~ ERROR use of possibly uninitialized variable: `y` - copy x; +// xfail-fast +// aux-build:mod_trait_with_static_methods_lib.rs +extern mod mod_trait_with_static_methods_lib; + +use mod_trait_with_static_methods_lib::Foo; + +pub fn main() { + assert!(42 == Foo::foo()); } diff --git a/src/test/run-pass/traits-default-method-self.rs b/src/test/run-pass/traits-default-method-self.rs index a377c86068cd7..c17b45d6ea1fd 100644 --- a/src/test/run-pass/traits-default-method-self.rs +++ b/src/test/run-pass/traits-default-method-self.rs @@ -10,16 +10,16 @@ //xfail-test -// Currently failing with an ICE in trans. (FIXME: #2794) +// Currently failing with an ICE in trans. (FIXME: #4350) trait Cat { - fn meow() -> bool; - fn scratch() -> bool { self.purr() } - fn purr() -> bool { true } + fn meow(&self) -> bool; + fn scratch(&self) -> bool { self.purr() } + fn purr(&self) -> bool { true } } impl Cat for int { - fn meow() -> bool { + fn meow(&self) -> bool { self.scratch() } } diff --git a/src/test/run-pass/traits.rs b/src/test/run-pass/traits.rs index c4ec15ff2730a..ba3e8e082b345 100644 --- a/src/test/run-pass/traits.rs +++ b/src/test/run-pass/traits.rs @@ -53,4 +53,3 @@ impl Ord for int { self == (*a) } } - diff --git a/src/test/run-pass/tuple-struct-construct.rs b/src/test/run-pass/tuple-struct-construct.rs index ea410093c4bd2..c5ea3e14d3924 100644 --- a/src/test/run-pass/tuple-struct-construct.rs +++ b/src/test/run-pass/tuple-struct-construct.rs @@ -14,4 +14,3 @@ pub fn main() { let x = Foo(1, 2); io::println(fmt!("%?", x)); } - diff --git a/src/test/run-pass/tuple-struct-destructuring.rs b/src/test/run-pass/tuple-struct-destructuring.rs index 7e6b9570defae..1cb944da0403e 100644 --- a/src/test/run-pass/tuple-struct-destructuring.rs +++ b/src/test/run-pass/tuple-struct-destructuring.rs @@ -17,4 +17,3 @@ pub fn main() { assert!(y == 1); assert!(z == 2); } - diff --git a/src/test/run-pass/tuple-struct-matching.rs b/src/test/run-pass/tuple-struct-matching.rs index 405616f9b1fef..e3cbd1201c127 100644 --- a/src/test/run-pass/tuple-struct-matching.rs +++ b/src/test/run-pass/tuple-struct-matching.rs @@ -20,4 +20,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/tuple-struct-trivial.rs b/src/test/run-pass/tuple-struct-trivial.rs index 8ddc04a186f2c..c6c32cf49c682 100644 --- a/src/test/run-pass/tuple-struct-trivial.rs +++ b/src/test/run-pass/tuple-struct-trivial.rs @@ -14,4 +14,3 @@ struct Foo(int, int, int); pub fn main() { } - diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index bc2ca20d642d9..134f1e4098f07 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,9 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -use sys::rustrt::size_of; -extern mod std; +extern mod core; +use core::sys::size_of; + +struct t {a: u8, b: i8} +struct u {a: u8, b: i8, c: u8} +struct v {a: u8, b: i8, c: v2, d: u32} +struct v2 {u: char, v: u8} +struct w {a: int, b: ()} +struct x {a: int, b: (), c: ()} +struct y {x: int} pub fn main() { assert!((size_of::() == 1 as uint)); @@ -18,14 +25,14 @@ pub fn main() { assert!((size_of::() == 4 as uint)); assert!((size_of::() == 1 as uint)); assert!((size_of::() == 4 as uint)); - assert!((size_of::<{a: u8, b: i8}>() == 2 as uint)); - assert!((size_of::<{a: u8, b: i8, c: u8}>() == 3 as uint)); + assert!((size_of::() == 2 as uint)); + assert!((size_of::() == 3 as uint)); // Alignment causes padding before the char and the u32. - assert!(size_of::<{a: u8, b: i8, c: {u: char, v: u8}, d: u32}>() == + assert!(size_of::() == 16 as uint); assert!((size_of::() == size_of::())); - assert!((size_of::<{a: int, b: ()}>() == size_of::())); - assert!((size_of::<{a: int, b: (), c: ()}>() == size_of::())); - assert!((size_of::() == size_of::<{x: int}>())); + assert!((size_of::() == size_of::())); + assert!((size_of::() == size_of::())); + assert!((size_of::() == size_of::())); } diff --git a/src/test/run-pass/typeclasses-eq-example-static.rs b/src/test/run-pass/typeclasses-eq-example-static.rs index 9c5f8c3218a93..c14dd0471f91e 100644 --- a/src/test/run-pass/typeclasses-eq-example-static.rs +++ b/src/test/run-pass/typeclasses-eq-example-static.rs @@ -38,7 +38,7 @@ impl Equal for ColorTree { fn isEq(a: ColorTree, b: ColorTree) -> bool { match (a, b) { (leaf(x), leaf(y)) => { Equal::isEq(x, y) } - (branch(l1, r1), branch(l2, r2)) => { + (branch(l1, r1), branch(l2, r2)) => { Equal::isEq(*l1, *l2) && Equal::isEq(*r1, *r2) } _ => { false } diff --git a/src/test/run-pass/typeclasses-eq-example.rs b/src/test/run-pass/typeclasses-eq-example.rs index 51c19cef50afd..18a68bc1c34f9 100644 --- a/src/test/run-pass/typeclasses-eq-example.rs +++ b/src/test/run-pass/typeclasses-eq-example.rs @@ -37,7 +37,7 @@ impl Equal for ColorTree { fn isEq(&self, a: ColorTree) -> bool { match (*self, a) { (leaf(x), leaf(y)) => { x.isEq(y) } - (branch(l1, r1), branch(l2, r2)) => { + (branch(l1, r1), branch(l2, r2)) => { (*l1).isEq(*l2) && (*r1).isEq(*r2) } _ => { false } diff --git a/src/test/run-pass/unique-fn-arg-move.rs b/src/test/run-pass/unique-fn-arg-move.rs index bbb33560e32dd..4a6386244f177 100644 --- a/src/test/run-pass/unique-fn-arg-move.rs +++ b/src/test/run-pass/unique-fn-arg-move.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(+i: ~int) { +fn f(i: ~int) { assert!(*i == 100); } diff --git a/src/test/run-pass/unique-object.rs b/src/test/run-pass/unique-object.rs index 1cf4cf09b81cd..5e0954969ef8d 100644 --- a/src/test/run-pass/unique-object.rs +++ b/src/test/run-pass/unique-object.rs @@ -27,4 +27,3 @@ pub fn main() { let y = x as ~Foo; assert!(y.f() == 10); } - diff --git a/src/test/run-pass/unique-swap.rs b/src/test/run-pass/unique-swap.rs index 6cd7b358c55e7..bf58e2c7cb53b 100644 --- a/src/test/run-pass/unique-swap.rs +++ b/src/test/run-pass/unique-swap.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + pub fn main() { let mut i = ~100; let mut j = ~200; - i <-> j; + util::swap(&mut i, &mut j); assert!(i == ~200); assert!(j == ~100); } diff --git a/src/test/run-pass/unit-like-struct.rs b/src/test/run-pass/unit-like-struct.rs index 837bfa50b8e05..1b81015b02910 100644 --- a/src/test/run-pass/unit-like-struct.rs +++ b/src/test/run-pass/unit-like-struct.rs @@ -16,4 +16,3 @@ pub fn main() { Foo => { io::println("hi"); } } } - diff --git a/src/test/run-pass/unsafe-pointer-assignability.rs b/src/test/run-pass/unsafe-pointer-assignability.rs index 05c9cd8a57400..f19558fbb1d01 100644 --- a/src/test/run-pass/unsafe-pointer-assignability.rs +++ b/src/test/run-pass/unsafe-pointer-assignability.rs @@ -17,6 +17,3 @@ fn f(x: *int) { pub fn main() { f(&3); } - - - diff --git a/src/test/run-pass/vec-each2_mut.rs b/src/test/run-pass/vec-each2_mut.rs new file mode 100644 index 0000000000000..3c6b7da9f1478 --- /dev/null +++ b/src/test/run-pass/vec-each2_mut.rs @@ -0,0 +1,38 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// -*- rust -*- +fn main(){ + let mut t1 = ~[]; + t1.push('a'); + + let mut t2 = ~[]; + t2.push('b'); + + for vec::each2_mut(t1, t2) | i1, i2 | { + assert!(*i1 == 'a'); + assert!(*i2 == 'b'); + } + + for vec::each2(t1, t2) | i1, i2 | { + io::println(fmt!("after t1: %?, t2: %?", i1, i2)); + } + + for vec::each2_mut(t1, t2) | i1, i2 | { + *i1 = 'b'; + *i2 = 'a'; + assert!(*i1 == 'b'); + assert!(*i2 == 'a'); + } + + for vec::each2(t1, t2) | i1, i2 | { + io::println(fmt!("before t1: %?, t2: %?", i1, i2)); + } +} diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index 5ce1b04dbe9a0..2c4add63e8b87 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -12,4 +12,3 @@ pub fn main() { let x: [int, ..4] = [1, 2, 3, 4]; io::println(fmt!("%d", x[0])); } - diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index ed0032b93eafe..38aa56b65125b 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::util; + // Just a grab bag of stuff that you wouldn't want to actually write. fn strange() -> bool { let _x: bool = return true; } @@ -52,7 +54,7 @@ fn notsure() { let mut _y = (_x = 0) == (_x = 0); let mut _z = (_x = 0) < (_x = 0); let _a = (_x += 0) == (_x = 0); - let _b = (_y <-> _z) == (_y <-> _z); + let _b = util::swap(&mut _y, &mut _z) == util::swap(&mut _y, &mut _z); } fn canttouchthis() -> uint { diff --git a/src/test/run-pass/while-cont.rs b/src/test/run-pass/while-cont.rs index 37528a7cfaece..add9ba54aa6aa 100644 --- a/src/test/run-pass/while-cont.rs +++ b/src/test/run-pass/while-cont.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Issue #825: Should recheck the loop contition after continuing +// Issue #825: Should recheck the loop condition after continuing pub fn main() { let mut i = 1; while i > 0 { diff --git a/src/test/run-pass/yield.rs b/src/test/run-pass/yield.rs index 75d9979807b47..2d916abf0da69 100644 --- a/src/test/run-pass/yield.rs +++ b/src/test/run-pass/yield.rs @@ -11,7 +11,9 @@ pub fn main() { let mut result = None; - task::task().future_result(|+r| { result = Some(r); }).spawn(child); + let mut builder = task::task(); + builder.future_result(|r| { result = Some(r); }); + builder.spawn(child); error!("1"); task::yield(); error!("2"); diff --git a/src/test/run-pass/yield1.rs b/src/test/run-pass/yield1.rs index 51483121f50fc..f3ca5b1211899 100644 --- a/src/test/run-pass/yield1.rs +++ b/src/test/run-pass/yield1.rs @@ -11,7 +11,9 @@ pub fn main() { let mut result = None; - task::task().future_result(|+r| { result = Some(r); }).spawn(child); + let mut builder = task::task(); + builder.future_result(|r| { result = Some(r); }); + builder.spawn(child); error!("1"); task::yield(); result.unwrap().recv();