From: Alex Crichton Date: Tue, 6 Jan 2015 02:37:25 +0000 (-0800) Subject: rollup merge of #20518: nagisa/weighted-bool X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=a73c35249d7a9ddf92e5c203b244a4a10a6e8119;hp=e723fe07783cd9b797c9f1456d359879bba44907;p=rust.git rollup merge of #20518: nagisa/weighted-bool 1 in 1 chance to return true always results in true. --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a4b38d1b42..2b3609e28a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,5 +47,14 @@ example, if it's 2014, and you change a Rust file that was created in // Copyright 2010-2014 The Rust Project Developers. ``` +# Coordination and communication + +Get feedback from other developers on +[discuss.rust-lang.org][discuss], and +[#rust-internals][pound-rust-internals]. + +[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals +[discuss]: http://discuss.rust-lang.org + For more details, please refer to [Note-development-policy](https://github.com/rust-lang/rust/wiki/Note-development-policy). diff --git a/man/rustc.1 b/man/rustc.1 index 4457ac8cce7..3d8b27a408a 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -34,7 +34,7 @@ Specify the name of the crate being built \fB\-\-emit\fR [asm|llvm-bc|llvm-ir|obj|link|dep-info] Configure the output that rustc will produce .TP -\fB\-\-print\fR [crate-name|output-file-names|sysroot] +\fB\-\-print\fR [crate-name|file-names|sysroot] Comma separated list of compiler information to print on stdout .TP \fB\-g\fR diff --git a/mk/docs.mk b/mk/docs.mk index 2a7ef5164f0..274598feada 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -49,8 +49,10 @@ RUSTDOC_HTML_OPTS_NO_CSS = --html-before-content=doc/version_info.html \ RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css PANDOC_BASE_OPTS := --standalone --toc --number-sections -PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --include-before-body=doc/version.tex \ - --from=markdown --include-before-body=doc/footer.tex --to=latex +PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --from=markdown --to=latex \ + --include-before-body=doc/version.tex \ + --include-before-body=doc/footer.tex \ + --include-in-header=doc/uptack.tex PANDOC_EPUB_OPTS = $(PANDOC_BASE_OPTS) --to=epub # The rustdoc executable... @@ -155,6 +157,9 @@ doc/footer.tex: $(D)/footer.inc | doc/ @$(call E, pandoc: $@) $(CFG_PANDOC) --from=html --to=latex $< --output=$@ +doc/uptack.tex: $(D)/uptack.tex | doc/ + $(Q)cp $< $@ + # HTML (rustdoc) DOC_TARGETS += doc/not_found.html doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/ @@ -180,7 +185,7 @@ doc/$(1).epub: $$(D)/$(1).md | doc/ # PDF (md =(pandoc)=> tex =(pdflatex)=> pdf) DOC_TARGETS += doc/$(1).tex -doc/$(1).tex: $$(D)/$(1).md doc/footer.tex doc/version.tex | doc/ +doc/$(1).tex: $$(D)/$(1).md doc/uptack.tex doc/footer.tex doc/version.tex | doc/ @$$(call E, pandoc: $$@) $$(CFG_PANDOC) $$(PANDOC_TEX_OPTS) $$< --output=$$@ diff --git a/mk/install.mk b/mk/install.mk index a8dfdffb59d..60c0a6bb4c7 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -28,11 +28,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -ifeq ($(CFG_DISABLE_DOCS),) -prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz dist/$(DOC_PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir -else -prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir -endif +prepare_install: dist-tar-bins | tmp/empty_dir uninstall: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) @@ -48,7 +44,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -prepare_uninstall: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir +prepare_uninstall: dist-tar-bins | tmp/empty_dir .PHONY: install prepare_install uninstall prepare_uninstall diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 350a10ce483..48610b6b526 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -339,8 +339,9 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool { return valid; } -pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn) - -> test::TestDescAndFn { +pub fn make_test(config: &Config, testfile: &Path, f: F) -> test::TestDescAndFn where + F: FnOnce() -> test::TestFn, +{ test::TestDescAndFn { desc: test::TestDesc { name: make_test_name(config, testfile), diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 27be6c6d835..2413a001ee8 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -220,7 +220,9 @@ fn ignore_lldb(config: &Config, line: &str) -> bool { !val } -fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool { +fn iter_header(testfile: &Path, mut it: F) -> bool where + F: FnMut(&str) -> bool, +{ use std::io::{BufferedReader, File}; let mut rdr = BufferedReader::new(File::open(testfile).unwrap()); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index c513aec0b84..875061e69b7 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -1233,12 +1233,14 @@ enum TargetLocation { ThisDirectory(Path), } -fn make_compile_args(config: &Config, - props: &TestProps, - extras: Vec , - xform: |&Config, &Path| -> TargetLocation, - testfile: &Path) - -> ProcArgs { +fn make_compile_args(config: &Config, + props: &TestProps, + extras: Vec , + xform: F, + testfile: &Path) + -> ProcArgs where + F: FnOnce(&Config, &Path) -> TargetLocation, +{ let xform_file = xform(config, testfile); let target = if props.force_host { config.host.as_slice() diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 9e73863239f..a9a9e0858ec 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -17,7 +17,7 @@ Some examples that demonstrate different aspects of the language: * [sprocketnes], an NES emulator with no GC, using modern Rust conventions * The language's general-purpose [hash] function, SipHash-2-4. Bit twiddling, OO, macros * The standard library's [HashMap], a sendable hash map in an OO style -* The extra library's [json] module. Enums and pattern matching +* The standard library's [json] module. Enums and pattern matching [sprocketnes]: https://github.com/pcwalton/sprocketnes [hash]: https://github.com/rust-lang/rust/blob/master/src/libstd/hash/mod.rs diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index b8808eaf57d..7ee1c1a7032 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -451,7 +451,7 @@ them. ~~~no_run extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; use std::ptr; #[link(name = "readline")] @@ -460,11 +460,10 @@ extern { } fn main() { - "[my-awesome-shell] $".with_c_str(|buf| { - unsafe { rl_prompt = buf; } - // get a line, process it - unsafe { rl_prompt = ptr::null(); } - }); + let prompt = CString::from_slice(b"[my-awesome-shell] $"); + unsafe { rl_prompt = prompt.as_ptr(); } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } } ~~~ @@ -509,23 +508,28 @@ to define a block for all windows systems, not just x86 ones. # Interoperability with foreign code -Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C -only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out -struct members without padding. `#[repr(C)]` can also be applied to an enum. - -Rust's owned boxes (`Box`) use non-nullable pointers as handles which point to the contained -object. However, they should not be manually created because they are managed by internal -allocators. References can safely be assumed to be non-nullable pointers directly to the type. -However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer -using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about -them. - -Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and -`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a -NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function. - -The standard library includes type aliases and function definitions for the C standard library in -the `libc` module, and Rust links against `libc` and `libm` by default. +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. + +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. + +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. + +The standard library includes type aliases and function definitions for the C +standard library in the `libc` module, and Rust links against `libc` and `libm` +by default. # The "nullable pointer optimization" diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index bf750ecaa8f..414a874082e 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -230,8 +230,9 @@ fn add_one(num: &int) -> int { ``` Rust has a feature called 'lifetime elision,' which allows you to not write -lifetime annotations in certain circumstances. This is one of them. Without -eliding the lifetimes, `add_one` looks like this: +lifetime annotations in certain circumstances. This is one of them. We will +cover the others later. Without eliding the lifetimes, `add_one` looks like +this: ```rust fn add_one<'a>(num: &'a int) -> int { @@ -449,6 +450,80 @@ This is the simplest kind of multiple ownership possible. For example, there's also `Arc`, which uses more expensive atomic instructions to be the thread-safe counterpart of `Rc`. +## Lifetime Elision + +Earlier, we mentioned 'lifetime elision,' a feature of Rust which allows you to +not write lifetime annotations in certain circumstances. All references have a +lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust +will do three things to determine what those lifetimes should be. + +When talking about lifetime elision, we use the term 'input lifetime' and +'output lifetime'. An 'input liftime' is a lifetime associated with a parameter +of a function, and an 'output lifetime' is a lifetime associated with the return +value of a function. For example, this function has an input lifetime: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) +``` + +This one has an output lifetime: + +```{rust,ignore} +fn foo<'a>() -> &'a str +``` + +This one has a lifetime in both positions: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) -> &'a str +``` + +Here are the three rules: + +* Each elided lifetime in a function's arguments becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime, elided or not, that lifetime is + assigned to all elided lifetimes in the return values of that function.. + +* If there are multiple input lifetimes, but one of them is `&self` or `&mut + self`, the lifetime of `self` is assigned to all elided output lifetimes. + +Otherwise, it is an error to elide an output lifetime. + +### Examples + +Here are some examples of functions with elided lifetimes, and the version of +what the elided lifetimes are expand to: + +```{rust,ignore} +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: uint, s: &str); // elided +fn debug<'a>(lvl: uint, s: &'a str); // expanded + +// In the preceeding example, `lvl` doesn't need a lifetime because it's not a +// reference (`&`). Only things relating to references (such as a `struct` +// which contains a reference) need lifetimes. + +fn substr(s: &str, until: uint) -> &str; // elided +fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL, no inputs + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded +``` + # Related Resources Coming Soon. diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 682c89fcc53..4c3d93bdfbe 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -503,6 +503,8 @@ Advice on writing benchmarks: * Make the code in the `iter` loop do something simple, to assist in pinpointing performance improvements (or regressions) +## Gotcha: optimizations + There's another tricky part to writing benchmarks: benchmarks compiled with optimizations activated can be dramatically changed by the optimizer so that the benchmark is no longer benchmarking what one expects. For example, the @@ -537,7 +539,8 @@ computation entirely. This could be done for the example above by adjusting the `b.iter` call to ```rust -# struct X; impl X { fn iter(&self, _: || -> T) {} } let b = X; +# struct X; +# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; b.iter(|| { // note lack of `;` (could also use an explicit `return`). range(0u, 1000).fold(0, |old, new| old ^ new) @@ -552,10 +555,15 @@ argument as used. extern crate test; # fn main() { -# struct X; impl X { fn iter(&self, _: || -> T) {} } let b = X; +# struct X; +# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; b.iter(|| { - test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new)); -}); + let mut n = 1000_u32; + + test::black_box(&mut n); // pretend to modify `n` + + range(0, n).fold(0, |a, b| a ^ b) +}) # } ``` @@ -571,3 +579,6 @@ test bench_xor_1000_ints ... bench: 1 ns/iter (+/- 0) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured ``` + +However, the optimizer can still modify a testcase in an undesirable manner +even when using either of the above. diff --git a/src/doc/guide.md b/src/doc/guide.md index 55465651cfb..66551ec499a 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -23,15 +23,15 @@ Linux or a Mac, all you need to do is this (note that you don't need to type in the `$`s, they just indicate the start of each command): ```bash -curl -L https://static.rust-lang.org/rustup.sh | sudo sh +$ curl -L https://static.rust-lang.org/rustup.sh | sudo sh ``` If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: ```bash -curl -L https://static.rust-lang.org/rustup.sh -O -sudo sh rustup.sh +$ curl -L https://static.rust-lang.org/rustup.sh -O +$ sudo sh rustup.sh ``` If you're on Windows, please download either the [32-bit @@ -101,7 +101,7 @@ you can access through [Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click that link, and you'll be chatting with other Rustaceans (a silly nickname we call ourselves), and we can help you out. Other great resources include [our -mailing list](https://mail.mozilla.org/listinfo/rust-dev), [the /r/rust +forum](http://discuss.rust-lang.org/), [the /r/rust subreddit](http://www.reddit.com/r/rust), and [Stack Overflow](http://stackoverflow.com/questions/tagged/rust). @@ -284,13 +284,14 @@ program doesn't have any dependencies, so we'll only be using the first part of its functionality. Eventually, we'll add more. Since we started off by using Cargo, it'll be easy to add later. -Let's convert Hello World to Cargo. The first thing we need to do to begin -using Cargo is to install Cargo. Luckily for us, the script we ran to install -Rust includes Cargo by default. If you installed Rust some other way, you may -want to [check the Cargo +If you installed Rust via the official installers you will also have +Cargo. If you installed Rust some other way, you may want to [check +the Cargo README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) for specific instructions about installing it. +Let's convert Hello World to Cargo. + To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` configuration file, and put our source file in the right place. Let's do that part first: @@ -354,7 +355,7 @@ Hello, world! Bam! We build our project with `cargo build`, and run it with `./target/hello_world`. This hasn't bought us a whole lot over our simple use of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` twice, and pass it a bunch of options to +file, we would need to call `rustc` more than once, and pass it a bunch of options to tell it to build everything together. With Cargo, as our project grows, we can just `cargo build` and it'll work the right way. @@ -384,7 +385,7 @@ The first thing we'll learn about are 'variable bindings.' They look like this: ```{rust} fn main() { - let x = 5i; + let x = 5; } ``` @@ -399,15 +400,13 @@ hand side of a `let` expression is a full pattern, not just a variable name. This means we can do things like: ```{rust} -let (x, y) = (1i, 2i); +let (x, y) = (1, 2); ``` After this expression is evaluated, `x` will be one, and `y` will be two. Patterns are really powerful, but this is about all we can do with them so far. So let's just keep this in the back of our minds as we go forward. -By the way, in these examples, `i` indicates that the number is an integer. - Rust is a statically typed language, which means that we specify our types up front. So why does our first example compile? Well, Rust has this thing called "type inference." If it can figure out what the type of something is, Rust @@ -416,18 +415,18 @@ doesn't require you to actually type it out. We can add the type if we want to, though. Types come after a colon (`:`): ```{rust} -let x: int = 5; +let x: i32 = 5; ``` If I asked you to read this out loud to the rest of the class, you'd say "`x` -is a binding with the type `int` and the value `five`." +is a binding with the type `i32` and the value `five`." In future examples, we may annotate the type in a comment. The examples will look like this: ```{rust} fn main() { - let x = 5i; // x: int + let x = 5; // x: i32 } ``` @@ -438,23 +437,23 @@ include them to help you understand what the types that Rust infers are. By default, bindings are **immutable**. This code will not compile: ```{ignore} -let x = 5i; -x = 10i; +let x = 5; +x = 10; ``` It will give you this error: ```text error: re-assignment of immutable variable `x` - x = 10i; + x = 10; ^~~~~~~ ``` If you want a binding to be mutable, you can use `mut`: ```{rust} -let mut x = 5i; // mut x: int -x = 10i; +let mut x = 5; // mut x: i32 +x = 10; ``` There is no single reason that bindings are immutable by default, but we can @@ -488,14 +487,14 @@ src/main.rs:2 let x; Giving it a type will compile, though: ```{rust} -let x: int; +let x: i32; ``` Let's try it out. Change your `src/main.rs` file to look like this: ```{rust} fn main() { - let x: int; + let x: i32; println!("Hello world!"); } @@ -507,7 +506,7 @@ but it will still print "Hello, world!": ```text Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default -src/main.rs:2 let x: int; +src/main.rs:2 let x: i32; ^ ``` @@ -517,7 +516,7 @@ do that. Change your program to look like this: ```{rust,ignore} fn main() { - let x: int; + let x: i32; println!("The value of x is: {}", x); } @@ -568,9 +567,9 @@ multiple paths can be taken. In the case of `if`, there is one choice that leads down two paths: ```rust -let x = 5i; +let x = 5; -if x == 5i { +if x == 5 { println!("x is five!"); } ``` @@ -582,9 +581,9 @@ the block is executed. If it's `false`, then it is not. If you want something to happen in the `false` case, use an `else`: ```{rust} -let x = 5i; +let x = 5; -if x == 5i { +if x == 5 { println!("x is five!"); } else { println!("x is not five :("); @@ -595,21 +594,21 @@ This is all pretty standard. However, you can also do this: ```{rust} -let x = 5i; +let x = 5; -let y = if x == 5i { - 10i +let y = if x == 5 { + 10 } else { - 15i -}; // y: int + 15 +}; // y: i32 ``` Which we can (and probably should) write like this: ```{rust} -let x = 5i; +let x = 5; -let y = if x == 5i { 10i } else { 15i }; // y: int +let y = if x == 5 { 10 } else { 15 }; // y: i32 ``` This reveals two interesting things about Rust: it is an expression-based @@ -641,15 +640,15 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The following will produce a compile-time error: ```{ignore} -let x = (let y = 5i); // expected identifier, found keyword `let` +let x = (let y = 5); // expected identifier, found keyword `let` ``` The compiler is telling us here that it was expecting to see the beginning of an expression, and a `let` can only begin a statement, not an expression. -Note that assigning to an already-bound variable (e.g. `y = 5i`) is still an +Note that assigning to an already-bound variable (e.g. `y = 5`) is still an expression, although its value is not particularly useful. Unlike C, where an -assignment evaluates to the assigned value (e.g. `5i` in the previous example), +assignment evaluates to the assigned value (e.g. `5` in the previous example), in Rust the value of an assignment is the unit type `()` (which we'll cover later). The second kind of statement in Rust is the **expression statement**. Its @@ -664,9 +663,9 @@ What is this exception that makes us say 'almost?' You saw it already, in this code: ```{rust} -let x = 5i; +let x = 5; -let y: int = if x == 5i { 10i } else { 15i }; +let y: i32 = if x == 5 { 10 } else { 15 }; ``` Note that I've added the type annotation to `y`, to specify explicitly that I @@ -675,20 +674,20 @@ want `y` to be an integer. This is not the same as this, which won't compile: ```{ignore} -let x = 5i; +let x = 5; -let y: int = if x == 5i { 10i; } else { 15i; }; +let y: i32 = if x == 5 { 10; } else { 15; }; ``` Note the semicolons after the 10 and 15. Rust will give us the following error: ```text -error: mismatched types: expected `int` but found `()` (expected int but found ()) +error: mismatched types: expected `i32` but found `()` (expected i32 but found ()) ``` We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a special type in Rust's type system. In Rust, `()` is _not_ a valid value for a -variable of type `int`. It's only a valid value for variables of the type `()`, +variable of type `i32`. It's only a valid value for variables of the type `()`, which aren't very useful. Remember how we said statements don't return a value? Well, that's the purpose of unit in this case. The semicolon turns any expression into a statement by throwing away its value and returning unit @@ -719,7 +718,7 @@ fn foo() { So, what about taking arguments? Here's a function that prints a number: ```{rust} -fn print_number(x: int) { +fn print_number(x: i32) { println!("x is: {}", x); } ``` @@ -731,7 +730,7 @@ fn main() { print_number(5); } -fn print_number(x: int) { +fn print_number(x: i32) { println!("x is: {}", x); } ``` @@ -746,7 +745,7 @@ fn main() { print_sum(5, 6); } -fn print_sum(x: int, y: int) { +fn print_sum(x: i32, y: i32) { println!("sum is: {}", x + y); } ``` @@ -779,7 +778,7 @@ sweet spot between full inference and no inference. What about returning a value? Here's a function that adds one to an integer: ```{rust} -fn add_one(x: int) -> int { +fn add_one(x: i32) -> i32 { x + 1 } ``` @@ -790,7 +789,7 @@ Rust functions return exactly one value, and you declare the type after an You'll note the lack of a semicolon here. If we added it in: ```{ignore} -fn add_one(x: int) -> int { +fn add_one(x: i32) -> i32 { x + 1; } ``` @@ -799,7 +798,7 @@ We would get an error: ```text error: not all control paths return a value -fn add_one(x: int) -> int { +fn add_one(x: i32) -> i32 { x + 1; } @@ -809,7 +808,7 @@ help: consider removing this semicolon: ``` Remember our earlier discussions about semicolons and `()`? Our function claims -to return an `int`, but with a semicolon, it would return `()` instead. Rust +to return an `i32`, but with a semicolon, it would return `()` instead. Rust realizes this probably isn't what we want, and suggests removing the semicolon. This is very much like our `if` statement before: the result of the block @@ -823,7 +822,7 @@ semicolon in a return position would cause a bug. But what about early returns? Rust does have a keyword for that, `return`: ```{rust} -fn foo(x: int) -> int { +fn foo(x: i32) -> i32 { if x < 5 { return x; } x + 1 @@ -834,7 +833,7 @@ Using a `return` as the last line of a function works, but is considered poor style: ```{rust} -fn foo(x: int) -> int { +fn foo(x: i32) -> i32 { if x < 5 { return x; } return x + 1; @@ -857,7 +856,7 @@ and **doc comment**s. ```{rust} // Line comments are anything after '//' and extend to the end of the line. -let x = 5i; // this is also a line comment. +let x = 5; // this is also a line comment. // If you have a long explanation for something, you can put line comments next // to each other. Put a space between the // and your comment so that it's @@ -904,19 +903,19 @@ The first compound data type we're going to talk about are called **tuple**s. Tuples are an ordered list of a fixed size. Like this: ```rust -let x = (1i, "hello"); +let x = (1, "hello"); ``` The parentheses and commas form this two-length tuple. Here's the same code, but with the type annotated: ```rust -let x: (int, &str) = (1, "hello"); +let x: (i32, &str) = (1, "hello"); ``` As you can see, the type of a tuple looks just like the tuple, but with each position having a type name rather than the value. Careful readers will also -note that tuples are heterogeneous: we have an `int` and a `&str` in this tuple. +note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. You haven't seen `&str` as a type before, and we'll discuss the details of strings later. In systems programming languages, strings are a bit more complex than in other languages. For now, just read `&str` as "a string slice," and @@ -926,7 +925,7 @@ You can access the fields in a tuple through a **destructuring let**. Here's an example: ```rust -let (x, y, z) = (1i, 2i, 3i); +let (x, y, z) = (1, 2, 3); println!("x is {}", x); ``` @@ -944,8 +943,8 @@ destructuring. You can assign one tuple into another, if they have the same arity and contained types. ```rust -let mut x = (1i, 2i); // x: (int, int) -let y = (2i, 3i); // y: (int, int) +let mut x = (1, 2); // x: (i32, i32) +let y = (2, 3); // y: (i32, i32) x = y; ``` @@ -954,8 +953,8 @@ You can also check for equality with `==`. Again, this will only compile if the tuples have the same type. ```rust -let x = (1i, 2i, 3i); -let y = (2i, 2i, 4i); +let x = (1, 2, 3); +let y = (2, 2, 4); if x == y { println!("yes"); @@ -969,16 +968,16 @@ This will print `no`, because some of the values aren't equal. One other use of tuples is to return multiple values from a function: ```rust -fn next_two(x: int) -> (int, int) { (x + 1i, x + 2i) } +fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) } fn main() { - let (x, y) = next_two(5i); + let (x, y) = next_two(5); println!("x, y = {}, {}", x, y); } ``` Even though Rust functions can only return one value, a tuple _is_ one value, -that happens to be made up of two. You can also see in this example how you +that happens to be made up of more than one value. You can also see in this example how you can destructure a pattern returned by a function, as well. Tuples are a very simple data structure, and so are not often what you want. @@ -992,12 +991,12 @@ difference: structs give each element that they contain a name, called a ```rust struct Point { - x: int, - y: int, + x: i32, + y: i32, } fn main() { - let origin = Point { x: 0i, y: 0i }; // origin: Point + let origin = Point { x: 0, y: 0 }; // origin: Point println!("The origin is at ({}, {})", origin.x, origin.y); } @@ -1019,12 +1018,12 @@ Use `mut` to make them mutable: ```{rust} struct Point { - x: int, - y: int, + x: i32, + y: i32, } fn main() { - let mut point = Point { x: 0i, y: 0i }; + let mut point = Point { x: 0, y: 0 }; point.x = 5; @@ -1042,15 +1041,15 @@ don't: ```{rust} -struct Color(int, int, int); -struct Point(int, int, int); +struct Color(i32, i32, i32); +struct Point(i32, i32, i32); ``` These two will not be equal, even if they have the same values: ```{rust} -# struct Color(int, int, int); -# struct Point(int, int, int); +# struct Color(i32, i32, i32); +# struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0); ``` @@ -1060,15 +1059,15 @@ It is almost always better to use a struct than a tuple struct. We would write ```{rust} struct Color { - red: int, - blue: int, - green: int, + red: i32, + blue: i32, + green: i32, } struct Point { - x: int, - y: int, - z: int, + x: i32, + y: i32, + z: i32, } ``` @@ -1080,7 +1079,7 @@ tuple struct with only one element. We call this a 'newtype,' because it lets you create a new type that's a synonym for another one: ```{rust} -struct Inches(int); +struct Inches(i32); let length = Inches(10); @@ -1117,15 +1116,15 @@ Here's an example of how to use `Ordering`: ```{rust} use std::cmp::Ordering; -fn cmp(a: int, b: int) -> Ordering { +fn cmp(a: i32, b: i32) -> Ordering { if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } } fn main() { - let x = 5i; - let y = 10i; + let x = 5; + let y = 10; let ordering = cmp(x, y); // ordering: Ordering @@ -1140,7 +1139,7 @@ fn main() { ``` There's a symbol here we haven't seen before: the double colon (`::`). -This is used to indicate a namesapce. In this case, `Ordering` lives in +This is used to indicate a namespace. In this case, `Ordering` lives in the `cmp` submodule of the `std` module. We'll talk more about modules later in the guide. For now, all you need to know is that you can `use` things from the standard library if you need them. @@ -1163,21 +1162,21 @@ This enum has two variants, one of which has a value: ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } ``` -This enum represents an `int` that we may or may not have. In the `Missing` +This enum represents an `i32` that we may or may not have. In the `Missing` case, we have no value, but in the `Value` case, we do. This enum is specific -to `int`s, though. We can make it usable by any type, but we haven't quite +to `i32`s, though. We can make it usable by any type, but we haven't quite gotten there yet! You can also have any number of values in an enum: ```{rust} enum OptionalColor { - Color(int, int, int), + Color(i32, i32, i32), Missing, } ``` @@ -1256,7 +1255,7 @@ Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` groupings with something more powerful. Check it out: ```{rust} -let x = 5i; +let x = 5; match x { 1 => println!("one"), @@ -1283,7 +1282,7 @@ error: non-exhaustive patterns: `_` not covered In other words, Rust is trying to tell us we forgot a value. Because `x` is an integer, Rust knows that it can have a number of different values – for example, -`6i`. Without the `_`, however, there is no arm that could match, and so Rust refuses +`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses to compile. `_` acts like a 'catch-all arm'. If none of the other arms match, the arm with `_` will, and since we have this catch-all arm, we now have an arm for every possible value of `x`, and so our program will compile successfully. @@ -1294,15 +1293,15 @@ section on enums? ```{rust} use std::cmp::Ordering; -fn cmp(a: int, b: int) -> Ordering { +fn cmp(a: i32, b: i32) -> Ordering { if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } } fn main() { - let x = 5i; - let y = 10i; + let x = 5; + let y = 10; let ordering = cmp(x, y); @@ -1321,15 +1320,15 @@ We can re-write this as a `match`: ```{rust} use std::cmp::Ordering; -fn cmp(a: int, b: int) -> Ordering { +fn cmp(a: i32, b: i32) -> Ordering { if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } } fn main() { - let x = 5i; - let y = 10i; + let x = 5; + let y = 10; match cmp(x, y) { Ordering::Less => println!("less"), @@ -1350,7 +1349,7 @@ make sure to cover all of our bases. ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } @@ -1372,7 +1371,7 @@ fn main() { That is how you can get and use the values contained in `enum`s. It can also allow us to handle errors or unexpected computations; for example, a -function that is not guaranteed to be able to compute a result (an `int` here) +function that is not guaranteed to be able to compute a result (an `i32` here) could return an `OptionalInt`, and we would handle that value with a `match`. As you can see, `enum` and `match` used together are quite useful! @@ -1383,15 +1382,15 @@ also implement the previous line like this: ```{rust} use std::cmp::Ordering; -fn cmp(a: int, b: int) -> Ordering { +fn cmp(a: i32, b: i32) -> Ordering { if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } } fn main() { - let x = 5i; - let y = 10i; + let x = 5; + let y = 10; println!("{}", match cmp(x, y) { Ordering::Less => "less", @@ -1423,8 +1422,8 @@ for (x = 0; x < 10; x++) { Instead, it looks like this: ```{rust} -for x in range(0i, 10i) { - println!("{}", x); // x: int +for x in range(0, 10) { + println!("{}", x); // x: i32 } ``` @@ -1528,7 +1527,7 @@ We now loop forever with `loop` and use `break` to break out early. iteration. This will only print the odd numbers: ```{rust} -for x in range(0i, 10i) { +for x in range(0, 10) { if x % 2 == 0 { continue; } println!("{}", x); @@ -1624,15 +1623,15 @@ things. The most basic is the **array**, a fixed-size list of elements of the same type. By default, arrays are immutable. ```{rust} -let a = [1i, 2i, 3i]; // a: [int; 3] -let mut m = [1i, 2i, 3i]; // mut m: [int; 3] +let a = [1, 2, 3]; // a: [i32; 3] +let mut m = [1, 2, 3]; // mut m: [i32; 3] ``` There's a shorthand for initializing each element of an array to the same -value. In this example, each element of `a` will be initialized to `0i`: +value. In this example, each element of `a` will be initialized to `0`: ```{rust} -let a = [0i; 20]; // a: [int; 20] +let a = [0; 20]; // a: [i32; 20] ``` Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we @@ -1643,7 +1642,7 @@ You can get the number of elements in an array `a` with `a.len()`, and use number in order: ```{rust} -let a = [1i, 2, 3]; // Only the first item needs a type suffix +let a = [1, 2, 3]; println!("a has {} elements", a.len()); for e in a.iter() { @@ -1672,7 +1671,7 @@ later). Vectors are to arrays what `String` is to `&str`. You can create them with the `vec!` macro: ```{rust} -let v = vec![1i, 2, 3]; // v: Vec +let v = vec![1, 2, 3]; // v: Vec ``` (Notice that unlike the `println!` macro we've used in the past, we use square @@ -1683,7 +1682,7 @@ You can get the length of, iterate over, and subscript vectors just like arrays. In addition, (mutable) vectors can grow automatically: ```{rust} -let mut nums = vec![1i, 2, 3]; // mut nums: Vec +let mut nums = vec![1, 2, 3]; // mut nums: Vec nums.push(4); @@ -1700,7 +1699,7 @@ Slices have a length, can be mutable or not, and in many ways behave like arrays: ```{rust} -let a = [0i, 1, 2, 3, 4]; +let a = [0, 1, 2, 3, 4]; let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3] for e in middle.iter() { @@ -1792,7 +1791,7 @@ Do you remember this code? ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } @@ -1824,7 +1823,7 @@ where there's no standard input. Because of this, `read_line` returns a type very similar to our `OptionalInt`: an `IoResult`. We haven't talked about `IoResult` yet because it is the **generic** form of our `OptionalInt`. Until then, you can think of it as being the same thing, just for any type – -not just `int`s. +not just `i32`s. Rust provides a method on these `IoResult`s called `ok()`, which does the same thing as our `match` statement but assumes that we have a valid value. @@ -2006,7 +2005,7 @@ use std::rand; fn main() { println!("Guess the number!"); - let secret_number = (rand::random() % 100i) + 1i; // secret_number: int + let secret_number = (rand::random() % 100) + 1; // secret_number: i32 println!("The secret number is: {}", secret_number); @@ -2038,7 +2037,7 @@ Let's try to compile this using `cargo build`: $ cargo build Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) src/main.rs:7:26: 7:34 error: the type of this value must be known in this context -src/main.rs:7 let secret_number = (rand::random() % 100i) + 1i; +src/main.rs:7 let secret_number = (rand::random() % 100) + 1; ^~~~~~~~ error: aborting due to previous error ``` @@ -2047,15 +2046,15 @@ It didn't work! Rust says "the type of this value must be known in this context." What's up with that? Well, as it turns out, `rand::random()` can generate many kinds of random values, not just integers. And in this case, Rust isn't sure what kind of value `random()` should generate. So we have to help -it. With number literals, we just add an `i` onto the end to tell Rust they're +it. With number literals, we can just add an `i32` onto the end to tell Rust they're integers, but that does not work with functions. There's a different syntax, and it looks like this: ```{rust,ignore} -rand::random::(); +rand::random::(); ``` -This says "please give me a random `int` value." We can change our code to use +This says "please give me a random `i32` value." We can change our code to use this hint: ```{rust,no_run} @@ -2065,7 +2064,7 @@ use std::rand; fn main() { println!("Guess the number!"); - let secret_number = (rand::random::() % 100i) + 1i; + let secret_number = (rand::random::() % 100) + 1; println!("The secret number is: {}", secret_number); @@ -2182,7 +2181,7 @@ fn main() { } } -fn cmp(a: int, b: int) -> Ordering { +fn cmp(a: i32, b: i32) -> Ordering { if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } @@ -2194,10 +2193,10 @@ If we try to compile, we'll get some errors: ```bash $ cargo build Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) -src/main.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String) +src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String) src/main.rs:20 match cmp(input, secret_number) { ^~~~~ -src/main.rs:20:22: 20:35 error: mismatched types: expected `int` but found `uint` (expected int but found uint) +src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint) src/main.rs:20 match cmp(input, secret_number) { ^~~~~~~~~~~~~ error: aborting due to 2 previous errors @@ -2906,7 +2905,7 @@ Here's a very basic test: ```{rust} #[test] fn is_one_equal_to_one() { - assert_eq!(1i, 1i); + assert_eq!(1, 1); } ``` @@ -3207,9 +3206,9 @@ to look like this: ```{rust,ignore} #[test] fn math_checks_out() { - let result = add_three_times_four(5i); + let result = add_three_times_four(5); - assert_eq!(32i, result); + assert_eq!(32, result); } ``` @@ -3219,7 +3218,7 @@ And try to run the test: $ cargo test Compiling testing v0.0.1 (file:///home/you/projects/testing) /home/you/projects/testing/tests/lib.rs:3:18: 3:38 error: unresolved name `add_three_times_four`. -/home/you/projects/testing/tests/lib.rs:3 let result = add_three_times_four(5i); +/home/you/projects/testing/tests/lib.rs:3 let result = add_three_times_four(5); ^~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error Build failed, waiting for other jobs to finish... @@ -3240,7 +3239,7 @@ and put this in it: ```{rust} # fn main() {} -pub fn add_three_times_four(x: int) -> int { +pub fn add_three_times_four(x: i32) -> i32 { (x + 3) * 4 } ``` @@ -3267,9 +3266,9 @@ use testing::add_three_times_four; #[test] fn math_checks_out() { - let result = add_three_times_four(5i); + let result = add_three_times_four(5); - assert_eq!(32i, result); + assert_eq!(32, result); } ``` @@ -3313,13 +3312,13 @@ some unit tests to test those. Change your `src/lib.rs` to look like this: ```{rust,ignore} -pub fn add_three_times_four(x: int) -> int { +pub fn add_three_times_four(x: i32) -> i32 { times_four(add_three(x)) } -fn add_three(x: int) -> int { x + 3 } +fn add_three(x: i32) -> i32 { x + 3 } -fn times_four(x: int) -> int { x * 4 } +fn times_four(x: i32) -> i32 { x * 4 } ``` If you run `cargo test`, you should get the same output: @@ -3363,16 +3362,16 @@ use testing::add_three; #[test] fn math_checks_out() { - let result = add_three_times_four(5i); + let result = add_three_times_four(5); - assert_eq!(32i, result); + assert_eq!(32, result); } #[test] fn test_add_three() { - let result = add_three(5i); + let result = add_three(5); - assert_eq!(8i, result); + assert_eq!(8, result); } ``` @@ -3389,13 +3388,13 @@ Right. It's private. So external, integration tests won't work. We need a unit test. Open up your `src/lib.rs` and add this: ```{rust,ignore} -pub fn add_three_times_four(x: int) -> int { +pub fn add_three_times_four(x: i32) -> i32 { times_four(add_three(x)) } -fn add_three(x: int) -> int { x + 3 } +fn add_three(x: i32) -> i32 { x + 3 } -fn times_four(x: int) -> int { x * 4 } +fn times_four(x: i32) -> i32 { x * 4 } #[cfg(test)] mod test { @@ -3404,16 +3403,16 @@ mod test { #[test] fn test_add_three() { - let result = add_three(5i); + let result = add_three(5); - assert_eq!(8i, result); + assert_eq!(8, result); } #[test] fn test_times_four() { - let result = times_four(5i); + let result = times_four(5); - assert_eq!(20i, result); + assert_eq!(20, result); } } ``` @@ -3495,7 +3494,7 @@ References are created using the ampersand (`&`). Here's a simple reference: ```{rust} -let x = 5i; +let x = 5; let y = &x; ``` @@ -3503,10 +3502,10 @@ let y = &x; rather than the reference itself) `y`, we use the asterisk (`*`): ```{rust} -let x = 5i; +let x = 5; let y = &x; -assert_eq!(5i, *y); +assert_eq!(5, *y); ``` Like any `let` binding, references are immutable by default. @@ -3514,7 +3513,7 @@ Like any `let` binding, references are immutable by default. You can declare that functions take a reference: ```{rust} -fn add_one(x: &int) -> int { *x + 1 } +fn add_one(x: &i32) -> i32 { *x + 1 } fn main() { assert_eq!(6, add_one(&5)); @@ -3529,7 +3528,7 @@ Because references are immutable, you can have multiple references that **alias** (point to the same place): ```{rust} -let x = 5i; +let x = 5; let y = &x; let z = &x; ``` @@ -3537,14 +3536,14 @@ let z = &x; We can make a mutable reference by using `&mut` instead of `&`: ```{rust} -let mut x = 5i; +let mut x = 5; let y = &mut x; ``` Note that `x` must also be mutable. If it isn't, like this: ```{rust,ignore} -let x = 5i; +let x = 5; let y = &mut x; ``` @@ -3570,7 +3569,7 @@ Rust will also prevent us from creating two mutable references that alias. This won't work: ```{rust,ignore} -let mut x = 5i; +let mut x = 5; let y = &mut x; let z = &mut x; ``` @@ -3586,7 +3585,7 @@ note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent ^ note: previous borrow ends here fn main() { - let mut x = 5i; + let mut x = 5; let y = &mut x; let z = &mut x; } @@ -3667,7 +3666,7 @@ all of Rust. Let's see this syntax in action: ```{rust} { - let x = 5i; // x is the owner of this integer, which is memory on the stack. + let x = 5; // x is the owner of this integer, which is memory on the stack. // other code here... @@ -3675,11 +3674,11 @@ all of Rust. Let's see this syntax in action: /// this function borrows an integer. It's given back automatically when the /// function returns. -fn foo(x: &int) -> &int { x } +fn foo(x: &i32) -> &i32 { x } { // x is the owner of the integer, which is memory on the stack. - let x = 5i; + let x = 5; // privilege 2: you may lend that resource to as many borrowers as you like let y = &x; @@ -3692,7 +3691,7 @@ fn foo(x: &int) -> &int { x } { // x is the owner of this integer, which is memory on the stack. - let mut x = 5i; + let mut x = 5; // privilege 3: you may lend that resource to a single borrower, mutably let y = &mut x; @@ -3718,7 +3717,7 @@ violation of the restrictions placed on owners who lend something out mutably. The code: ```{rust,ignore} -let mut x = 5i; +let mut x = 5; let y = &mut x; let z = &mut x; ``` @@ -3734,7 +3733,7 @@ note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent ^ note: previous borrow ends here fn main() { - let mut x = 5i; + let mut x = 5; let y = &mut x; let z = &mut x; } @@ -3767,7 +3766,7 @@ we can't change `x` until the borrow is over. ```text note: previous borrow ends here fn main() { - let mut x = 5i; + let mut x = 5; let y = &mut x; let z = &mut x; } @@ -3828,7 +3827,7 @@ an integer `5` and makes `x` a pointer to it: ```{rust} { - let x = box 5i; + let x = box 5; println!("{}", *x); // Prints 5 } ``` @@ -3844,7 +3843,7 @@ The Rust code above will do the same thing as the following C code: ```{c,ignore} { - int *x = (int *)malloc(sizeof(int)); + i32 *x = (i32 *)malloc(sizeof(i32)); if (!x) abort(); *x = 5; printf("%d\n", *x); @@ -3859,7 +3858,7 @@ Boxes are the sole owner of their contents, so you cannot take a mutable reference to them and then use the original box: ```{rust,ignore} -let mut x = box 5i; +let mut x = box 5; let y = &mut x; *x; // you might expect 5, but this is actually an error @@ -3880,7 +3879,7 @@ As long as `y` is borrowing the contents, we cannot use `x`. After `y` is done borrowing the value, we can use it again. This works fine: ```{rust} -let mut x = box 5i; +let mut x = box 5; { let y = &mut x; @@ -3915,7 +3914,7 @@ To create an `Rc` value, use `Rc::new()`. To create a second owner, use the ```{rust} use std::rc::Rc; -let x = Rc::new(5i); +let x = Rc::new(5); let y = x.clone(); println!("{} {}", *x, *y); // Prints 5 5 @@ -3944,7 +3943,7 @@ A quick refresher: you can match against literals directly, and `_` acts as an 'any' case: ```{rust} -let x = 1i; +let x = 1; match x { 1 => println!("one"), @@ -3957,7 +3956,7 @@ match x { You can match multiple patterns with `|`: ```{rust} -let x = 1i; +let x = 1; match x { 1 | 2 => println!("one or two"), @@ -3969,7 +3968,7 @@ match x { You can match a range of values with `...`: ```{rust} -let x = 1i; +let x = 1; match x { 1 ... 5 => println!("one through five"), @@ -3983,7 +3982,7 @@ If you're matching multiple things, via a `|` or a `...`, you can bind the value to a name with `@`: ```{rust} -let x = 1i; +let x = 1; match x { e @ 1 ... 5 => println!("got a range element {}", e), @@ -3996,14 +3995,14 @@ ignore the value and type in the variant: ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } -let x = OptionalInt::Value(5i); +let x = OptionalInt::Value(5); match x { - OptionalInt::Value(..) => println!("Got an int!"), + OptionalInt::Value(..) => println!("Got an i32!"), OptionalInt::Missing => println!("No such luck."), } ``` @@ -4012,15 +4011,15 @@ You can introduce **match guards** with `if`: ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } -let x = OptionalInt::Value(5i); +let x = OptionalInt::Value(5); match x { - OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"), - OptionalInt::Value(..) => println!("Got an int!"), + OptionalInt::Value(i) if i > 5 => println!("Got an i32 bigger than five!"), + OptionalInt::Value(..) => println!("Got an i32!"), OptionalInt::Missing => println!("No such luck."), } ``` @@ -4029,33 +4028,33 @@ If you're matching on a pointer, you can use the same syntax as you declared it with. First, `&`: ```{rust} -let x = &5i; +let x = &5; match x { &val => println!("Got a value: {}", val), } ``` -Here, the `val` inside the `match` has type `int`. In other words, the left-hand -side of the pattern destructures the value. If we have `&5i`, then in `&val`, `val` -would be `5i`. +Here, the `val` inside the `match` has type `i32`. In other words, the left-hand +side of the pattern destructures the value. If we have `&5`, then in `&val`, `val` +would be `5`. If you want to get a reference, use the `ref` keyword: ```{rust} -let x = 5i; +let x = 5; match x { ref r => println!("Got a reference to {}", r), } ``` -Here, the `r` inside the `match` has the type `&int`. In other words, the `ref` +Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` keyword _creates_ a reference, for use in the pattern. If you need a mutable reference, `ref mut` will work in the same way: ```{rust} -let mut x = 5i; +let mut x = 5; match x { ref mut mr => println!("Got a mutable reference to {}", mr), @@ -4067,11 +4066,11 @@ If you have a struct, you can destructure it inside of a pattern: ```{rust} # #![allow(non_shorthand_field_patterns)] struct Point { - x: int, - y: int, + x: i32, + y: i32, } -let origin = Point { x: 0i, y: 0i }; +let origin = Point { x: 0, y: 0 }; match origin { Point { x: x, y: y } => println!("({},{})", x, y), @@ -4083,11 +4082,11 @@ If we only care about some of the values, we don't have to give them all names: ```{rust} # #![allow(non_shorthand_field_patterns)] struct Point { - x: int, - y: int, + x: i32, + y: i32, } -let origin = Point { x: 0i, y: 0i }; +let origin = Point { x: 0, y: 0 }; match origin { Point { x: x, .. } => println!("x is {}", x), @@ -4099,11 +4098,11 @@ You can do this kind of match on any member, not just the first: ```{rust} # #![allow(non_shorthand_field_patterns)] struct Point { - x: int, - y: int, + x: i32, + y: i32, } -let origin = Point { x: 0i, y: 0i }; +let origin = Point { x: 0, y: 0 }; match origin { Point { y: y, .. } => println!("y is {}", y), @@ -4233,9 +4232,9 @@ arguments, really powerful things are possible. Let's make a closure: ```{rust} -let add_one = |x| { 1i + x }; +let add_one = |&: x| { 1 + x }; -println!("The sum of 5 plus 1 is {}.", add_one(5i)); +println!("The sum of 5 plus 1 is {}.", add_one(5)); ``` We create a closure using the `|...| { ... }` syntax, and then we create a @@ -4245,8 +4244,8 @@ binding name and two parentheses, just like we would for a named function. Let's compare syntax. The two are pretty close: ```{rust} -let add_one = |x: int| -> int { 1i + x }; -fn add_one (x: int) -> int { 1i + x } +let add_one = |&: x: i32| -> i32 { 1 + x }; +fn add_one (x: i32) -> i32 { 1 + x } ``` As you may have noticed, closures infer their argument and return types, so you @@ -4259,9 +4258,9 @@ this: ```{rust} fn main() { - let x = 5i; + let x: i32 = 5; - let printer = || { println!("x is: {}", x); }; + let printer = |&:| { println!("x is: {}", x); }; printer(); // prints "x is: 5" } @@ -4275,11 +4274,11 @@ defined. The closure borrows any variables it uses, so this will error: ```{rust,ignore} fn main() { - let mut x = 5i; + let mut x = 5; - let printer = || { println!("x is: {}", x); }; + let printer = |&:| { println!("x is: {}", x); }; - x = 6i; // error: cannot assign to `x` because it is borrowed + x = 6; // error: cannot assign to `x` because it is borrowed } ``` @@ -4299,67 +4298,67 @@ now. We'll talk about them more in the "Threads" section of the guide. Closures are most useful as an argument to another function. Here's an example: ```{rust} -fn twice(x: int, f: |int| -> int) -> int { +fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } fn main() { - let square = |x: int| { x * x }; + let square = |&: x: i32| { x * x }; - twice(5i, square); // evaluates to 50 + twice(5, square); // evaluates to 50 } ``` Let's break the example down, starting with `main`: ```{rust} -let square = |x: int| { x * x }; +let square = |&: x: i32| { x * x }; ``` We've seen this before. We make a closure that takes an integer, and returns its square. ```{rust} -# fn twice(x: int, f: |int| -> int) -> int { f(x) + f(x) } -# let square = |x: int| { x * x }; -twice(5i, square); // evaluates to 50 +# fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } +# let square = |&: x: i32| { x * x }; +twice(5, square); // evaluates to 50 ``` This line is more interesting. Here, we call our function, `twice`, and we pass it two arguments: an integer, `5`, and our closure, `square`. This is just like passing any other two variable bindings to a function, but if you've never worked with closures before, it can seem a little complex. Just think: "I'm -passing two variables: one is an int, and one is a function." +passing two variables: one is an i32, and one is a function." Next, let's look at how `twice` is defined: ```{rust,ignore} -fn twice(x: int, f: |int| -> int) -> int { +fn twice(x: i32, f: |i32| -> i32) -> i32 { ``` `twice` takes two arguments, `x` and `f`. That's why we called it with two -arguments. `x` is an `int`, we've done that a ton of times. `f` is a function, -though, and that function takes an `int` and returns an `int`. Notice -how the `|int| -> int` syntax looks a lot like our definition of `square` +arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function, +though, and that function takes an `i32` and returns an `i32`. Notice +how the `|i32| -> i32` syntax looks a lot like our definition of `square` above, if we added the return type in: ```{rust} -let square = |x: int| -> int { x * x }; -// |int| -> int +let square = |&: x: i32| -> i32 { x * x }; +// |i32| -> i32 ``` -This function takes an `int` and returns an `int`. +This function takes an `i32` and returns an `i32`. This is the most complicated function signature we've seen yet! Give it a read a few times until you can see how it works. It takes a teeny bit of practice, and then it's easy. -Finally, `twice` returns an `int` as well. +Finally, `twice` returns an `i32` as well. Okay, let's look at the body of `twice`: ```{rust} -fn twice(x: int, f: |int| -> int) -> int { +fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } ``` @@ -4377,12 +4376,12 @@ If we didn't want to give `square` a name, we could just define it inline. This example is the same as the previous one: ```{rust} -fn twice(x: int, f: |int| -> int) -> int { +fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } fn main() { - twice(5i, |x: int| { x * x }); // evaluates to 50 + twice(5, |x: i32| { x * x }); // evaluates to 50 } ``` @@ -4390,14 +4389,14 @@ A named function's name can be used wherever you'd use a closure. Another way of writing the previous example: ```{rust} -fn twice(x: int, f: |int| -> int) -> int { +fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } -fn square(x: int) -> int { x * x } +fn square(x: i32) -> i32 { x * x } fn main() { - twice(5i, square); // evaluates to 50 + twice(5, square); // evaluates to 50 } ``` @@ -4415,7 +4414,7 @@ Let's talk about loops. Remember Rust's `for` loop? Here's an example: ```{rust} -for x in range(0i, 10i) { +for x in range(0, 10) { println!("{}", x); } ``` @@ -4427,7 +4426,7 @@ call the `.next()` method on repeatedly, and it gives us a sequence of things. Like this: ```{rust} -let mut range = range(0i, 10i); +let mut range = range(0, 10); loop { match range.next() { @@ -4442,8 +4441,8 @@ loop { We make a mutable binding to the return value of `range`, which is our iterator. We then `loop`, with an inner `match`. This `match` is used on the result of `range.next()`, which gives us a reference to the next value of the iterator. -`next` returns an `Option`, in this case, which will be `Some(int)` when -we have a value and `None` once we run out. If we get `Some(int)`, we print it +`next` returns an `Option`, in this case, which will be `Some(i32)` when +we have a value and `None` once we run out. If we get `Some(i32)`, we print it out, and if we get `None`, we `break` out of the loop. This code sample is basically the same as our `for` loop version. The `for` @@ -4460,7 +4459,7 @@ primitive. For example, if you needed to iterate over the contents of a vector, you may be tempted to write this: ```{rust} -let nums = vec![1i, 2i, 3i]; +let nums = vec![1, 2, 3]; for i in range(0u, nums.len()) { println!("{}", nums[i]); @@ -4472,7 +4471,7 @@ vectors returns an iterator that iterates through a reference to each element of the vector in turn. So write this: ```{rust} -let nums = vec![1i, 2i, 3i]; +let nums = vec![1, 2, 3]; for num in nums.iter() { println!("{}", num); @@ -4489,12 +4488,12 @@ very common with iterators: we can ignore unnecessary bounds checks, but still know that we're safe. There's another detail here that's not 100% clear because of how `println!` -works. `num` is actually of type `&int`. That is, it's a reference to an `int`, -not an `int` itself. `println!` handles the dereferencing for us, so we don't +works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`, +not an `i32` itself. `println!` handles the dereferencing for us, so we don't see it. This code works fine too: ```{rust} -let nums = vec![1i, 2i, 3i]; +let nums = vec![1, 2, 3]; for num in nums.iter() { println!("{}", *num); @@ -4528,7 +4527,7 @@ The most common consumer is `collect()`. This code doesn't quite compile, but it shows the intention: ```{rust,ignore} -let one_to_one_hundred = range(1i, 101i).collect(); +let one_to_one_hundred = range(1, 101).collect(); ``` As you can see, we call `collect()` on our iterator. `collect()` takes @@ -4538,7 +4537,7 @@ type of things you want to collect, and so you need to let it know. Here's the version that does compile: ```{rust} -let one_to_one_hundred = range(1i, 101i).collect::>(); +let one_to_one_hundred = range(1, 101).collect::>(); ``` If you remember, the `::<>` syntax allows us to give a type hint, @@ -4548,7 +4547,7 @@ and so we tell it that we want a vector of integers. is one: ```{rust} -let greater_than_forty_two = range(0i, 100i) +let greater_than_forty_two = range(0, 100) .find(|x| *x > 42); match greater_than_forty_two { @@ -4565,8 +4564,8 @@ element, `find` returns an `Option` rather than the element itself. Another important consumer is `fold`. Here's what it looks like: ```{rust} -let sum = range(1i, 4i) - .fold(0i, |sum, x| sum + x); +let sum = range(1, 4) + .fold(0, |sum, x| sum + x); ``` `fold()` is a consumer that looks like this: @@ -4582,24 +4581,24 @@ in this iterator: | base | accumulator | element | closure result | |------|-------------|---------|----------------| -| 0i | 0i | 1i | 1i | -| 0i | 1i | 2i | 3i | -| 0i | 3i | 3i | 6i | +| 0 | 0 | 1 | 1 | +| 0 | 1 | 2 | 3 | +| 0 | 3 | 3 | 6 | We called `fold()` with these arguments: ```{rust} -# range(1i, 4i) -.fold(0i, |sum, x| sum + x); +# range(1, 4) +.fold(0, |sum, x| sum + x); ``` -So, `0i` is our base, `sum` is our accumulator, and `x` is our element. On the -first iteration, we set `sum` to `0i`, and `x` is the first element of `nums`, -`1i`. We then add `sum` and `x`, which gives us `0i + 1i = 1i`. On the second +So, `0` is our base, `sum` is our accumulator, and `x` is our element. On the +first iteration, we set `sum` to `0`, and `x` is the first element of `nums`, +`1`. We then add `sum` and `x`, which gives us `0 + 1 = 1`. On the second iteration, that value becomes our accumulator, `sum`, and the element is -the second element of the array, `2i`. `1i + 2i = 3i`, and so that becomes +the second element of the array, `2`. `1 + 2 = 3`, and so that becomes the value of the accumulator for the last iteration. On that iteration, -`x` is the last element, `3i`, and `3i + 3i = 6i`, which is our final +`x` is the last element, `3`, and `3 + 3 = 6`, which is our final result for our sum. `1 + 2 + 3 = 6`, and that's the result we got. Whew. `fold` can be a bit strange the first few times you see it, but once it @@ -4620,14 +4619,14 @@ This code, for example, does not actually generate the numbers `1-100`, and just creates a value that represents the sequence: ```{rust} -let nums = range(1i, 100i); +let nums = range(1, 100); ``` Since we didn't do anything with the range, it didn't generate the sequence. Let's add the consumer: ```{rust} -let nums = range(1i, 100i).collect::>(); +let nums = range(1, 100).collect::>(); ``` Now, `collect()` will require that `range()` give it some numbers, and so @@ -4638,7 +4637,7 @@ which you've used before. `iter()` can turn a vector into a simple iterator that gives you each element in turn: ```{rust} -let nums = [1i, 2i, 3i]; +let nums = [1, 2, 3]; for num in nums.iter() { println!("{}", num); @@ -4649,12 +4648,12 @@ These two basic iterators should serve you well. There are some more advanced iterators, including ones that are infinite. Like `count`: ```{rust} -std::iter::count(1i, 5i); +std::iter::count(1, 5); ``` This iterator counts up from one, adding five each time. It will give you a new integer every time, forever (well, technically, until it reaches the -maximum number representable by an `int`). But since iterators are lazy, +maximum number representable by an `i32`). But since iterators are lazy, that's okay! You probably don't want to use `collect()` on it, though... That's enough about iterators. Iterator adapters are the last concept @@ -4666,7 +4665,7 @@ we need to talk about with regards to iterators. Let's get to it! a new iterator. The simplest one is called `map`: ```{rust,ignore} -range(1i, 100i).map(|x| x + 1i); +range(1, 100).map(|x| x + 1); ``` `map` is called upon another iterator, and produces a new iterator where each @@ -4677,7 +4676,7 @@ compile the example, you'll get a warning: ```text warning: unused result which must be used: iterator adaptors are lazy and do nothing unless consumed, #[warn(unused_must_use)] on by default - range(1i, 100i).map(|x| x + 1i); + range(1, 100).map(|x| x + 1); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` @@ -4685,7 +4684,7 @@ Laziness strikes again! That closure will never execute. This example doesn't print any numbers: ```{rust,ignore} -range(1i, 100i).map(|x| println!("{}", x)); +range(1, 100).map(|x| println!("{}", x)); ``` If you are trying to execute a closure on an iterator for its side effects, @@ -4697,7 +4696,7 @@ has no side effect on the original iterator. Let's try it out with our infinite iterator from before, `count()`: ```{rust} -for i in std::iter::count(1i, 5i).take(5) { +for i in std::iter::count(1, 5).take(5) { println!("{}", i); } ``` @@ -4717,7 +4716,7 @@ returns `true` or `false`. The new iterator `filter()` produces only the elements that that closure returns `true` for: ```{rust} -for i in range(1i, 100i).filter(|&x| x % 2 == 0) { +for i in range(1, 100).filter(|&x| x % 2 == 0) { println!("{}", i); } ``` @@ -4732,11 +4731,11 @@ You can chain all three things together: start with an iterator, adapt it a few times, and then consume the result. Check it out: ```{rust} -range(1i, 1000i) +range(1, 1000) .filter(|&x| x % 2 == 0) .filter(|&x| x % 3 == 0) .take(5) - .collect::>(); + .collect::>(); ``` This will give you a vector containing `6`, `12`, `18`, `24`, and `30`. @@ -4755,7 +4754,7 @@ multiple types of arguments. For example, remember our `OptionalInt` type? ```{rust} enum OptionalInt { - Value(int), + Value(i32), Missing, } ``` @@ -4788,30 +4787,30 @@ The `` part, which you've seen a few times before, indicates that this is a generic data type. `T` is called a **type parameter**. When we create instances of `Option`, we need to provide a concrete type in place of the type parameter. For example, if we wanted something like our `OptionalInt`, we would -need to instantiate an `Option`. Inside the declaration of our enum, +need to instantiate an `Option`. Inside the declaration of our enum, wherever we see a `T`, we replace it with the type specified (or inferred by the the compiler). ```{rust} -let x: Option = Some(5i); +let x: Option = Some(5); ``` -In this particular `Option`, `T` has the value of `int`. On the right-hand side -of the binding, we do make a `Some(T)`, where `T` is `5i`. Since that's an -`int`, the two sides match, and Rust is happy. If they didn't match, we'd get an +In this particular `Option`, `T` has the value of `i32`. On the right-hand side +of the binding, we do make a `Some(T)`, where `T` is `5`. Since that's an +`i32`, the two sides match, and Rust is happy. If they didn't match, we'd get an error: ```{rust,ignore} -let x: Option = Some(5i); +let x: Option = Some(5); // error: mismatched types: expected `core::option::Option`, -// found `core::option::Option` (expected f64, found int) +// found `core::option::Option` (expected f64, found i32) ``` That doesn't mean we can't make `Option`s that hold an `f64`! They just have to match up: ```{rust} -let x: Option = Some(5i); +let x: Option = Some(5); let y: Option = Some(5.0f64); ``` @@ -5084,25 +5083,25 @@ As you can see, `print_area` is now generic, but also ensures that we have passed in the correct types. If we pass in an incorrect type: ```{rust,ignore} -print_area(5i); +print_area(5); ``` We get a compile-time error: ```text -error: failed to find an implementation of trait main::HasArea for int +error: failed to find an implementation of trait main::HasArea for i32 ``` So far, we've only added trait implementations to structs, but you can implement a trait for any type. So technically, we _could_ implement -`HasArea` for `int`: +`HasArea` for `i32`: ```{rust} trait HasArea { fn area(&self) -> f64; } -impl HasArea for int { +impl HasArea for i32 { fn area(&self) -> f64 { println!("this is silly"); @@ -5110,7 +5109,7 @@ impl HasArea for int { } } -5i.area(); +5.area(); ``` It is considered poor style to implement methods on such primitive types, even @@ -5166,7 +5165,7 @@ fn main() { ``` Requiring us to `use` traits whose methods we want means that even if someone -does something bad like add methods to `int`, it won't affect us, unless you +does something bad like add methods to `i32`, it won't affect us, unless you `use` that trait. The second condition allows us to `impl` built-in `trait`s for types we define, @@ -5174,9 +5173,9 @@ or allows us to `impl` our own `trait`s for built-in types, but restricts us from mixing and matching third party or built-in `impl`s with third party or built-in types. -We could `impl` the `HasArea` trait for `int`, because `HasArea` is in our +We could `impl` the `HasArea` trait for `i32`, because `HasArea` is in our crate. But if we tried to implement `Float`, a standard library `trait`, for -`int`, we could not, because neither the `trait` nor the `type` are in our +`i32`, we could not, because neither the `trait` nor the `type` are in our crate. ## Monomorphization @@ -5259,7 +5258,7 @@ touches. This implies that those variables are not usable from the parent thread after the child thread is spawned: ```{rust,ignore} -let mut x = vec![1i, 2i, 3i]; +let mut x = vec![1, 2, 3]; spawn(move || { println!("The value of x[0] is: {}", x[0]); @@ -5333,7 +5332,7 @@ use std::sync::Future; let mut delayed_value = Future::spawn(move || { // just return anything for examples' sake - 12345i + 12345 }); println!("value = {}", delayed_value.get()); ``` @@ -5401,7 +5400,7 @@ a function, but it would be worse. Why? Well, what macros allow you to do is write code that generates more code. So when we call `println!` like this: ```{rust} -let x = 5i; +let x = 5; println!("x is: {}", x); ``` @@ -5421,7 +5420,7 @@ called `print.rs`: ```{rust} fn main() { - let x = 5i; + let x = 5; println!("x is: {}", x); } ``` @@ -5439,7 +5438,7 @@ extern crate "native" as rt; #[prelude_import] use std::prelude::*; fn main() { - let x = 5i; + let x = 5; match (&x,) { (__arg0,) => { #[inline] @@ -5457,7 +5456,7 @@ fn main() { } ``` -Whew! This isn't too terrible. You can see that we still `let x = 5i`, +Whew! This isn't too terrible. You can see that we still `let x = 5`, but then things get a little bit hairy. Three more bindings get set: a static format string, an argument vector, and the arguments. We then invoke the `println_args` function with the generated arguments. diff --git a/src/doc/index.md b/src/doc/index.md index e54bf0eb242..7f22c1eeb85 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -58,7 +58,7 @@ a guide that can help you out: * [Strings](guide-strings.html) * [Pointers](guide-pointers.html) * [Crates and modules](guide-crates.html) -* [Threads and Communication](guide-threads.html) +* [Threads and Communication](guide-tasks.html) * [Error Handling](guide-error-handling.html) * [Foreign Function Interface](guide-ffi.html) * [Writing Unsafe and Low-Level Code](guide-unsafe.html) diff --git a/src/doc/reference.md b/src/doc/reference.md index d7930285260..016cf12985e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1259,8 +1259,8 @@ We call such functions "diverging" because they never return a value to the caller. Every control path in a diverging function must end with a `panic!()` or a call to another diverging function on every control path. The `!` annotation does *not* denote a type. Rather, the result type of a diverging function is a -special type called $\bot$ ("bottom") that unifies with any type. Rust has no -syntax for $\bot$. +special type called ⊥ ("bottom") that unifies with any type. Rust has no +syntax for ⊥. It might be necessary to declare a diverging function because as mentioned previously, the typechecker checks that every control path in a function ends @@ -1563,7 +1563,7 @@ functions](#generic-functions). trait Seq { fn len(&self) -> uint; fn elt_at(&self, n: uint) -> T; - fn iter(&self, |T|); + fn iter(&self, F) where F: Fn(T); } ``` @@ -3218,7 +3218,7 @@ In this example, we define a function `ten_times` that takes a higher-order function argument, and call it with a lambda expression as an argument. ``` -fn ten_times(f: |int|) { +fn ten_times(f: F) where F: Fn(int) { let mut i = 0; while i < 10 { f(i); @@ -3828,7 +3828,7 @@ fn add(x: int, y: int) -> int { let mut x = add(5,7); -type Binop<'a> = |int,int|: 'a -> int; +type Binop = fn(int, int) -> int; let bo: Binop = add; x = bo(5,7); ``` @@ -3852,14 +3852,14 @@ An example of creating and calling a closure: ```rust let captured_var = 10i; -let closure_no_args = || println!("captured_var={}", captured_var); +let closure_no_args = |&:| println!("captured_var={}", captured_var); -let closure_args = |arg: int| -> int { +let closure_args = |&: arg: int| -> int { println!("captured_var={}, arg={}", captured_var, arg); arg // Note lack of semicolon after 'arg' }; -fn call_closure(c1: ||, c2: |int| -> int) { +fn call_closure int>(c1: F, c2: G) { c1(); c2(2); } @@ -4316,73 +4316,28 @@ fine-grained control is desired over the output format of a Rust crate. *TODO*. -# Appendix: Influences and further references - -## Influences - -> The essential problem that must be solved in making a fault-tolerant -> software system is therefore that of fault-isolation. Different programmers -> will write different modules, some modules will be correct, others will have -> errors. We do not want the errors in one module to adversely affect the -> behaviour of a module which does not have any errors. -> -> — Joe Armstrong - -> In our approach, all data is private to some process, and processes can -> only communicate through communications channels. *Security*, as used -> in this paper, is the property which guarantees that processes in a system -> cannot affect each other except by explicit communication. -> -> When security is absent, nothing which can be proven about a single module -> in isolation can be guaranteed to hold when that module is embedded in a -> system [...] -> -> — Robert Strom and Shaula Yemini - -> Concurrent and applicative programming complement each other. The -> ability to send messages on channels provides I/O without side effects, -> while the avoidance of shared data helps keep concurrent processes from -> colliding. -> -> — Rob Pike - -Rust is not a particularly original language. It may however appear unusual by -contemporary standards, as its design elements are drawn from a number of -"historical" languages that have, with a few exceptions, fallen out of favour. -Five prominent lineages contribute the most, though their influences have come -and gone during the course of Rust's development: - -* The NIL (1981) and Hermes (1990) family. These languages were developed by - Robert Strom, Shaula Yemini, David Bacon and others in their group at IBM - Watson Research Center (Yorktown Heights, NY, USA). - -* The Erlang (1987) language, developed by Joe Armstrong, Robert Virding, Claes - Wikström, Mike Williams and others in their group at the Ericsson Computer - Science Laboratory (Älvsjö, Stockholm, Sweden) . - -* The Sather (1990) language, developed by Stephen Omohundro, Chu-Cheow Lim, - Heinz Schmidt and others in their group at The International Computer - Science Institute of the University of California, Berkeley (Berkeley, CA, - USA). - -* The Newsqueak (1988), Alef (1995), and Limbo (1996) family. These - languages were developed by Rob Pike, Phil Winterbottom, Sean Dorward and - others in their group at Bell Labs Computing Sciences Research Center - (Murray Hill, NJ, USA). - -* The Napier (1985) and Napier88 (1988) family. These languages were - developed by Malcolm Atkinson, Ron Morrison and others in their group at - the University of St. Andrews (St. Andrews, Fife, UK). - -Additional specific influences can be seen from the following languages: - -* The structural algebraic types and compilation manager of SML. -* The attribute and assembly systems of C#. -* The references and deterministic destructor system of C++. -* The memory region systems of the ML Kit and Cyclone. -* The typeclass system of Haskell. -* The lexical identifier rule of Python. -* The block syntax of Ruby. +# Appendix: Influences + +Rust is not a particularly original language, with design elements coming from +a wide range of sources. Some of these are listed below (including elements +that have since been removed): + +* SML, OCaml: algebraic datatypes, pattern matching, type inference, + semicolon statement separation +* C++: references, RAII, smart pointers, move semantics, monomorphisation, + memory model +* ML Kit, Cyclone: region based memory management +* Haskell (GHC): typeclasses, type families +* Newsqueak, Alef, Limbo: channels, concurrency +* Erlang: message passing, task failure, ~~linked task failure~~, + ~~lightweight concurrency~~ +* Swift: optional bindings +* Scheme: hygienic macros +* C#: attributes +* Ruby: ~~block syntax~~ +* NIL, Hermes: ~~typestate~~ +* [Unicode Annex #31](http://www.unicode.org/reports/tr31/): identifier and + pattern syntax [ffi]: guide-ffi.html [plugin]: guide-plugin.html diff --git a/src/doc/uptack.tex b/src/doc/uptack.tex new file mode 100644 index 00000000000..32158ea5496 --- /dev/null +++ b/src/doc/uptack.tex @@ -0,0 +1,2 @@ +\usepackage{newunicodechar} +\newunicodechar⊥{{$\bot$}} diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh index 85e15e36327..749d9eaa173 100755 --- a/src/etc/rustup.sh +++ b/src/etc/rustup.sh @@ -230,7 +230,7 @@ validate_opt() { } create_tmp_dir() { - local TMP_DIR=./rustup-tmp-install + local TMP_DIR=`pwd`/rustup-tmp-install rm -Rf "${TMP_DIR}" need_ok "failed to remove temporary installation directory" @@ -245,6 +245,21 @@ probe_need CFG_CURL curl probe_need CFG_TAR tar probe_need CFG_FILE file +probe CFG_SHA256SUM sha256sum +probe CFG_SHASUM shasum + +if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then + err "unable to find either sha256sum or shasum" +fi + +calculate_hash() { + if [ -n "$CFG_SHA256SUM" ]; then + ${CFG_SHA256SUM} $@ + else + ${CFG_SHASUM} -a 256 $@ + fi +} + CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/" CFG_SELF="$0" CFG_ARGS="$@" @@ -269,7 +284,8 @@ VAL_OPTIONS="" flag uninstall "only uninstall from the installation prefix" valopt prefix "" "set installation prefix" -opt cargo 1 "install cargo with rust" +valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" +flag save "save the downloaded nightlies to ~/.rustup" if [ $HELP -eq 1 ] then @@ -417,6 +433,13 @@ CFG_TMP_DIR=$(mktemp -d 2>/dev/null \ || mktemp -d -t 'rustup-tmp-install' 2>/dev/null \ || create_tmp_dir) +# If we're saving nightlies and we didn't specify which one, grab todays. +# Otherwise we'll use the latest version. +if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ]; +then + CFG_DATE=`date "+%Y-%m-%d"` +fi + RUST_URL="https://static.rust-lang.org/dist" RUST_PACKAGE_NAME=rust-nightly RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}" @@ -424,35 +447,84 @@ RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz" RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}" RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh" -CARGO_URL="https://static.rust-lang.org/cargo-dist" -CARGO_PACKAGE_NAME=cargo-nightly -CARGO_PACKAGE_NAME_AND_TRIPLE="${CARGO_PACKAGE_NAME}-${HOST_TRIPLE}" -CARGO_TARBALL_NAME="${CARGO_PACKAGE_NAME_AND_TRIPLE}.tar.gz" -CARGO_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${CARGO_PACKAGE_NAME_AND_TRIPLE}" -CARGO_LOCAL_INSTALL_SCRIPT="${CARGO_LOCAL_INSTALL_DIR}/install.sh" +# add a date suffix if we want a particular nighly. +if [ -n "${CFG_DATE}" ]; +then + RUST_URL="${RUST_URL}/${CFG_DATE}" +fi + +verify_hash() { + remote_sha256="$1" + local_file="$2" + + msg "Downloading ${remote_sha256}" + remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"` + if [ "$?" -ne 0 ]; then + rm -Rf "${CFG_TMP_DIR}" + err "Failed to download ${remote_url}" + fi + + msg "Verifying hash" + local_sha256=$(calculate_hash "${local_file}") + if [ "$?" -ne 0 ]; then + rm -Rf "${CFG_TMP_DIR}" + err "Failed to compute hash for ${local_tarball}" + fi + + # We only need the sha, not the filenames + remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '` + local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '` + + if [ "${remote_sha256}" != "${local_sha256}" ]; then + rm -Rf "${CFG_TMP_DIR}" + errmsg="invalid sha256.\n" + errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n" + errmsg="$errmsg ${local_sha256}\t${local_tarball}" + err "$errmsg" + fi +} -# Fetch the package. +# Fetch the package. Optionally caches the tarballs. download_package() { remote_tarball="$1" local_tarball="$2" + remote_sha256="${remote_tarball}.sha256" - msg "Downloading ${remote_tarball} to ${local_tarball}" + # Check if we've already downloaded this file. + if [ -e "${local_tarball}.tmp" ]; then + msg "Resuming ${remote_tarball} to ${local_tarball}" - "${CFG_CURL}" -f -o "${local_tarball}" "${remote_tarball}" - if [ $? -ne 0 ] - then - rm -Rf "${CFG_TMP_DIR}" - err "failed to download installer" + "${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}" + if [ $? -ne 0 ] + then + rm -Rf "${CFG_TMP_DIR}" + err "failed to download installer" + fi + + mv "${local_tarball}.tmp" "${local_tarball}" + elif [ ! -e "${local_tarball}" ]; then + msg "Downloading ${remote_tarball} to ${local_tarball}" + + "${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}" + if [ $? -ne 0 ] + then + rm -Rf "${CFG_TMP_DIR}" + err "failed to download installer" + fi + + mv "${local_tarball}.tmp" "${local_tarball}" fi + + verify_hash "${remote_sha256}" "${local_tarball}" } # Wrap all the commands needed to install a package. install_package() { - tarball_name="$1" + local_tarball="$1" install_script="$2" - msg "Extracting ${tarball_name}" - (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${tarball_name}") + msg "Extracting ${local_tarball}" + (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}") if [ $? -ne 0 ]; then rm -Rf "${CFG_TMP_DIR}" err "failed to unpack installer" @@ -479,29 +551,27 @@ install_packages() { mkdir -p "${CFG_TMP_DIR}" need_ok "failed to create create temporary installation directory" - RUST_LOCAL_TARBALL="${CFG_TMP_DIR}/${RUST_TARBALL_NAME}" - CARGO_LOCAL_TARBALL="${CFG_TMP_DIR}/${CARGO_TARBALL_NAME}" + # If we're saving our nightlies, put them in $HOME/.rustup. + if [ -n "${CFG_SAVE}" ] + then + RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}" + else + RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}" + fi + + mkdir -p "${RUST_DOWNLOAD_DIR}" + need_ok "failed to create create download directory" + + RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}" download_package \ "${RUST_URL}/${RUST_TARBALL_NAME}" \ "${RUST_LOCAL_TARBALL}" - if [ -z "${CFG_DISABLE_CARGO}" ]; then - download_package \ - "${CARGO_URL}/${CARGO_TARBALL_NAME}" \ - "${CARGO_LOCAL_TARBALL}" - fi - install_package \ - "${RUST_TARBALL_NAME}" \ + "${RUST_LOCAL_TARBALL}" \ "${RUST_LOCAL_INSTALL_SCRIPT}" - if [ -z "${CFG_DISABLE_CARGO}" ]; then - install_package \ - "${CARGO_TARBALL_NAME}" \ - "${CARGO_LOCAL_INSTALL_SCRIPT}" - fi - rm -Rf "${CFG_TMP_DIR}" need_ok "couldn't rm temporary installation directory" } diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 9e663eb0317..5588152a244 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -157,8 +157,8 @@ syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustE syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell -syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDeriving -syn region rustDeriving start="deriving(" end=")" contained contains=rustTrait +syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive +syn region rustDerive start="derive(" end=")" contained contains=rustTrait " Number literals syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(8\|16\|32\|64\)\=\)\=" @@ -263,7 +263,7 @@ hi def link rustMacro Macro hi def link rustType Type hi def link rustTodo Todo hi def link rustAttribute PreProc -hi def link rustDeriving PreProc +hi def link rustDerive PreProc hi def link rustStorage StorageClass hi def link rustObsoleteStorage Error hi def link rustLifetime Special @@ -275,7 +275,7 @@ hi def link rustBoxPlacementExpr rustKeyword " Other Suggestions: " hi rustAttribute ctermfg=cyan -" hi rustDeriving ctermfg=cyan +" hi rustDerive ctermfg=cyan " hi rustAssert ctermfg=yellow " hi rustPanic ctermfg=red " hi rustMacro ctermfg=magenta diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 88f02d6573e..080d34dbda5 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -35,7 +35,7 @@ //! use std::sync::Arc; //! use std::thread::Thread; //! -//! let five = Arc::new(5i); +//! let five = Arc::new(5); //! //! for i in range(0u, 10) { //! let five = five.clone(); @@ -52,7 +52,7 @@ //! use std::sync::{Arc, Mutex}; //! use std::thread::Thread; //! -//! let five = Arc::new(Mutex::new(5i)); +//! let five = Arc::new(Mutex::new(5)); //! //! for _ in range(0u, 10) { //! let five = five.clone(); @@ -154,7 +154,7 @@ impl Arc { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// ``` #[inline] #[stable] @@ -176,7 +176,7 @@ pub fn new(data: T) -> Arc { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// /// let weak_five = five.downgrade(); /// ``` @@ -220,7 +220,7 @@ impl Clone for Arc { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// /// five.clone(); /// ``` @@ -267,7 +267,7 @@ impl Arc { /// ``` /// use std::sync::Arc; /// - /// let mut five = Arc::new(5i); + /// let mut five = Arc::new(5); /// /// let mut_five = five.make_unique(); /// ``` @@ -303,14 +303,14 @@ impl Drop for Arc { /// use std::sync::Arc; /// /// { - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// /// // stuff /// /// drop(five); // explict drop /// } /// { - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// /// // stuff /// @@ -369,7 +369,7 @@ impl Weak { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// /// let weak_five = five.downgrade(); /// @@ -405,7 +405,7 @@ impl Clone for Weak { /// ``` /// use std::sync::Arc; /// - /// let weak_five = Arc::new(5i).downgrade(); + /// let weak_five = Arc::new(5).downgrade(); /// /// weak_five.clone(); /// ``` @@ -430,7 +430,7 @@ impl Drop for Weak { /// use std::sync::Arc; /// /// { - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// let weak_five = five.downgrade(); /// /// // stuff @@ -438,7 +438,7 @@ impl Drop for Weak { /// drop(weak_five); // explict drop /// } /// { - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// let weak_five = five.downgrade(); /// /// // stuff @@ -472,9 +472,9 @@ impl PartialEq for Arc { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five == Arc::new(5i); + /// five == Arc::new(5); /// ``` fn eq(&self, other: &Arc) -> bool { *(*self) == *(*other) } @@ -487,9 +487,9 @@ fn eq(&self, other: &Arc) -> bool { *(*self) == *(*other) } /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five != Arc::new(5i); + /// five != Arc::new(5); /// ``` fn ne(&self, other: &Arc) -> bool { *(*self) != *(*other) } } @@ -504,9 +504,9 @@ impl PartialOrd for Arc { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five.partial_cmp(&Arc::new(5i)); + /// five.partial_cmp(&Arc::new(5)); /// ``` fn partial_cmp(&self, other: &Arc) -> Option { (**self).partial_cmp(&**other) @@ -521,9 +521,9 @@ fn partial_cmp(&self, other: &Arc) -> Option { /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five < Arc::new(5i); + /// five < Arc::new(5); /// ``` fn lt(&self, other: &Arc) -> bool { *(*self) < *(*other) } @@ -536,9 +536,9 @@ fn lt(&self, other: &Arc) -> bool { *(*self) < *(*other) } /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five <= Arc::new(5i); + /// five <= Arc::new(5); /// ``` fn le(&self, other: &Arc) -> bool { *(*self) <= *(*other) } @@ -551,9 +551,9 @@ fn le(&self, other: &Arc) -> bool { *(*self) <= *(*other) } /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five > Arc::new(5i); + /// five > Arc::new(5); /// ``` fn gt(&self, other: &Arc) -> bool { *(*self) > *(*other) } @@ -566,9 +566,9 @@ fn gt(&self, other: &Arc) -> bool { *(*self) > *(*other) } /// ``` /// use std::sync::Arc; /// - /// let five = Arc::new(5i); + /// let five = Arc::new(5); /// - /// five >= Arc::new(5i); + /// five >= Arc::new(5); /// ``` fn ge(&self, other: &Arc) -> bool { *(*self) >= *(*other) } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 362f6c66b59..2c318181b09 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -12,7 +12,7 @@ #![stable] -use core::any::{Any, AnyRefExt}; +use core::any::Any; use core::clone::Clone; use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c4b455aff5c..d9239e93a07 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -187,7 +187,7 @@ impl Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// ``` #[stable] pub fn new(value: T) -> Rc { @@ -214,7 +214,7 @@ pub fn new(value: T) -> Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// /// let weak_five = five.downgrade(); /// ``` @@ -247,7 +247,7 @@ pub fn strong_count(this: &Rc) -> uint { this.strong() } /// use std::rc; /// use std::rc::Rc; /// -/// let five = Rc::new(5i); +/// let five = Rc::new(5); /// /// rc::is_unique(&five); /// ``` @@ -329,7 +329,7 @@ impl Rc { /// ``` /// use std::rc::Rc; /// - /// let mut five = Rc::new(5i); + /// let mut five = Rc::new(5); /// /// let mut_five = five.make_unique(); /// ``` @@ -378,14 +378,14 @@ impl Drop for Rc { /// use std::rc::Rc; /// /// { - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// /// // stuff /// /// drop(five); // explict drop /// } /// { - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// /// // stuff /// @@ -424,7 +424,7 @@ impl Clone for Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// /// five.clone(); /// ``` @@ -465,9 +465,9 @@ impl PartialEq for Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five == Rc::new(5i); + /// five == Rc::new(5); /// ``` #[inline(always)] fn eq(&self, other: &Rc) -> bool { **self == **other } @@ -481,9 +481,9 @@ fn eq(&self, other: &Rc) -> bool { **self == **other } /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five != Rc::new(5i); + /// five != Rc::new(5); /// ``` #[inline(always)] fn ne(&self, other: &Rc) -> bool { **self != **other } @@ -503,9 +503,9 @@ impl PartialOrd for Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five.partial_cmp(&Rc::new(5i)); + /// five.partial_cmp(&Rc::new(5)); /// ``` #[inline(always)] fn partial_cmp(&self, other: &Rc) -> Option { @@ -521,9 +521,9 @@ fn partial_cmp(&self, other: &Rc) -> Option { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five < Rc::new(5i); + /// five < Rc::new(5); /// ``` #[inline(always)] fn lt(&self, other: &Rc) -> bool { **self < **other } @@ -537,9 +537,9 @@ fn lt(&self, other: &Rc) -> bool { **self < **other } /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five <= Rc::new(5i); + /// five <= Rc::new(5); /// ``` #[inline(always)] fn le(&self, other: &Rc) -> bool { **self <= **other } @@ -553,9 +553,9 @@ fn le(&self, other: &Rc) -> bool { **self <= **other } /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five > Rc::new(5i); + /// five > Rc::new(5); /// ``` #[inline(always)] fn gt(&self, other: &Rc) -> bool { **self > **other } @@ -569,9 +569,9 @@ fn gt(&self, other: &Rc) -> bool { **self > **other } /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five >= Rc::new(5i); + /// five >= Rc::new(5); /// ``` #[inline(always)] fn ge(&self, other: &Rc) -> bool { **self >= **other } @@ -588,9 +588,9 @@ impl Ord for Rc { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// - /// five.partial_cmp(&Rc::new(5i)); + /// five.partial_cmp(&Rc::new(5)); /// ``` #[inline] fn cmp(&self, other: &Rc) -> Ordering { (**self).cmp(&**other) } @@ -639,7 +639,7 @@ impl Weak { /// ``` /// use std::rc::Rc; /// - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// /// let weak_five = five.downgrade(); /// @@ -668,7 +668,7 @@ impl Drop for Weak { /// use std::rc::Rc; /// /// { - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// let weak_five = five.downgrade(); /// /// // stuff @@ -676,7 +676,7 @@ impl Drop for Weak { /// drop(weak_five); // explict drop /// } /// { - /// let five = Rc::new(5i); + /// let five = Rc::new(5); /// let weak_five = five.downgrade(); /// /// // stuff @@ -710,7 +710,7 @@ impl Clone for Weak { /// ``` /// use std::rc::Rc; /// - /// let weak_five = Rc::new(5i).downgrade(); + /// let weak_five = Rc::new(5).downgrade(); /// /// weak_five.clone(); /// ``` diff --git a/src/libcollections/bench.rs b/src/libcollections/bench.rs index c7164b8199c..cd4f8d203df 100644 --- a/src/libcollections/bench.rs +++ b/src/libcollections/bench.rs @@ -11,7 +11,7 @@ use prelude::*; use std::rand; use std::rand::Rng; -use test::Bencher; +use test::{Bencher, black_box}; pub fn insert_rand_n(n: uint, map: &mut M, @@ -33,7 +33,8 @@ pub fn insert_rand_n(n: uint, let k = rng.gen::() % n; insert(map, k); remove(map, k); - }) + }); + black_box(map); } pub fn insert_seq_n(n: uint, @@ -55,7 +56,8 @@ pub fn insert_seq_n(n: uint, insert(map, i); remove(map, i); i = (i + 2) % n; - }) + }); + black_box(map); } pub fn find_rand_n(n: uint, @@ -82,7 +84,7 @@ pub fn find_rand_n(n: uint, b.iter(|| { let t = find(map, keys[i]); i = (i + 1) % n; - t + black_box(t); }) } @@ -104,6 +106,6 @@ pub fn find_seq_n(n: uint, b.iter(|| { let x = find(map, i); i = (i + 1) % n; - x + black_box(x); }) } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 4a550e5ce27..82002f16133 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -211,7 +211,7 @@ pub fn with_capacity(capacity: uint) -> BinaryHeap { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![9i, 1, 2, 7, 3, 2]); + /// let heap = BinaryHeap::from_vec(vec![9, 1, 2, 7, 3, 2]); /// ``` pub fn from_vec(vec: Vec) -> BinaryHeap { let mut heap = BinaryHeap { data: vec }; @@ -230,7 +230,7 @@ pub fn from_vec(vec: Vec) -> BinaryHeap { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]); + /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.iter() { @@ -250,7 +250,7 @@ pub fn iter(&self) -> Iter { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]); + /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.into_iter() { @@ -272,7 +272,7 @@ pub fn into_iter(self) -> IntoIter { /// let mut heap = BinaryHeap::new(); /// assert_eq!(heap.peek(), None); /// - /// heap.push(1i); + /// heap.push(1); /// heap.push(5); /// heap.push(2); /// assert_eq!(heap.peek(), Some(&5)); @@ -355,7 +355,7 @@ pub fn shrink_to_fit(&mut self) { /// /// ``` /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from_vec(vec![1i, 3]); + /// let mut heap = BinaryHeap::from_vec(vec![1, 3]); /// /// assert_eq!(heap.pop(), Some(3)); /// assert_eq!(heap.pop(), Some(1)); @@ -379,7 +379,7 @@ pub fn pop(&mut self) -> Option { /// ``` /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); - /// heap.push(3i); + /// heap.push(3); /// heap.push(5); /// heap.push(1); /// @@ -401,7 +401,7 @@ pub fn push(&mut self, item: T) { /// ``` /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); - /// heap.push(1i); + /// heap.push(1); /// heap.push(5); /// /// assert_eq!(heap.push_pop(3), 5); @@ -433,7 +433,7 @@ pub fn push_pop(&mut self, mut item: T) -> T { /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); /// - /// assert_eq!(heap.replace(1i), None); + /// assert_eq!(heap.replace(1), None); /// assert_eq!(heap.replace(3), Some(1)); /// assert_eq!(heap.len(), 1); /// assert_eq!(heap.peek(), Some(&3)); @@ -456,7 +456,7 @@ pub fn replace(&mut self, mut item: T) -> Option { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4, 5, 6, 7]); + /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4, 5, 6, 7]); /// let vec = heap.into_vec(); /// /// // Will print in some order @@ -474,12 +474,12 @@ pub fn into_vec(self) -> Vec { self.data } /// ``` /// use std::collections::BinaryHeap; /// - /// let mut heap = BinaryHeap::from_vec(vec![1i, 2, 4, 5, 7]); + /// let mut heap = BinaryHeap::from_vec(vec![1, 2, 4, 5, 7]); /// heap.push(6); /// heap.push(3); /// /// let vec = heap.into_sorted_vec(); - /// assert_eq!(vec, vec![1i, 2, 3, 4, 5, 6, 7]); + /// assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7]); /// ``` pub fn into_sorted_vec(mut self) -> Vec { let mut end = self.len(); diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 5e7089bb7ac..c092e000215 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -164,21 +164,6 @@ pub struct Bitv { nbits: uint } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) -impl Index for Bitv { - #[inline] - fn index(&self, i: &uint) -> &bool { - if self.get(*i).expect("index out of bounds") { - &TRUE - } else { - &FALSE - } - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot // FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) impl Index for Bitv { type Output = bool; diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 3a722178bc0..ea504530c4b 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -19,7 +19,7 @@ use core::prelude::*; -use core::borrow::BorrowFrom; +use core::borrow::{BorrowFrom, ToOwned}; use core::cmp::Ordering; use core::default::Default; use core::fmt::Show; @@ -128,20 +128,23 @@ pub struct Values<'a, K: 'a, V: 'a> { inner: Map<(&'a K, &'a V), &'a V, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> } +#[stable] /// A view into a single entry in a map, which may either be vacant or occupied. -pub enum Entry<'a, K:'a, V:'a> { +pub enum Entry<'a, Sized? Q:'a, K:'a, V:'a> { /// A vacant Entry - Vacant(VacantEntry<'a, K, V>), + Vacant(VacantEntry<'a, Q, K, V>), /// An occupied Entry Occupied(OccupiedEntry<'a, K, V>), } +#[stable] /// A vacant Entry. -pub struct VacantEntry<'a, K:'a, V:'a> { - key: K, +pub struct VacantEntry<'a, Sized? Q:'a, K:'a, V:'a> { + key: &'a Q, stack: stack::SearchStack<'a, K, V, node::handle::Edge, node::handle::Leaf>, } +#[stable] /// An occupied Entry. pub struct OccupiedEntry<'a, K:'a, V:'a> { stack: stack::SearchStack<'a, K, V, node::handle::KV, node::handle::LeafOrInternal>, @@ -874,18 +877,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl Index for BTreeMap - where Q: BorrowFrom + Ord -{ - fn index(&self, key: &Q) -> &V { - self.get(key).expect("no entry found for key") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl Index for BTreeMap where Q: BorrowFrom + Ord @@ -897,18 +888,6 @@ fn index(&self, key: &Q) -> &V { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl IndexMut for BTreeMap - where Q: BorrowFrom + Ord -{ - fn index_mut(&mut self, key: &Q) -> &mut V { - self.get_mut(key).expect("no entry found for key") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl IndexMut for BTreeMap where Q: BorrowFrom + Ord @@ -1132,40 +1111,56 @@ fn next_back(&mut self) -> Option<(&'a V)> { self.inner.next_back() } #[stable] impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {} +impl<'a, Sized? Q, K: Ord, V> Entry<'a, Q, K, V> { + #[unstable = "matches collection reform v2 specification, waiting for dust to settle"] + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> { + match self { + Occupied(entry) => Ok(entry.into_mut()), + Vacant(entry) => Err(entry), + } + } +} -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { +impl<'a, Sized? Q: ToOwned, K: Ord, V> VacantEntry<'a, Q, K, V> { + #[stable] /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. - pub fn set(self, value: V) -> &'a mut V { - self.stack.insert(self.key, value) + pub fn insert(self, value: V) -> &'a mut V { + self.stack.insert(self.key.to_owned(), value) } } impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { + #[stable] /// Gets a reference to the value in the entry. pub fn get(&self) -> &V { self.stack.peek() } + #[stable] /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut V { self.stack.peek_mut() } + #[stable] /// Converts the entry into a mutable reference to its value. pub fn into_mut(self) -> &'a mut V { self.stack.into_top() } + #[stable] /// Sets the value of the entry with the OccupiedEntry's key, /// and returns the entry's old value. - pub fn set(&mut self, mut value: V) -> V { + pub fn insert(&mut self, mut value: V) -> V { mem::swap(self.stack.peek_mut(), &mut value); value } + #[stable] /// Takes the value of the entry out of the map, and returns it. - pub fn take(self) -> V { + pub fn remove(self) -> V { self.stack.remove() } } @@ -1352,9 +1347,9 @@ impl BTreeMap { /// /// // count the number of occurrences of letters in the vec /// for x in vec!["a","b","a","c","a","b"].iter() { - /// match count.entry(*x) { + /// match count.entry(x) { /// Entry::Vacant(view) => { - /// view.set(1); + /// view.insert(1); /// }, /// Entry::Occupied(mut view) => { /// let v = view.get_mut(); @@ -1365,12 +1360,16 @@ impl BTreeMap { /// /// assert_eq!(count["a"], 3u); /// ``` - pub fn entry<'a>(&'a mut self, mut key: K) -> Entry<'a, K, V> { + /// The key must have the same ordering before or after `.to_owned()` is called. + #[stable] + pub fn entry<'a, Sized? Q>(&'a mut self, mut key: &'a Q) -> Entry<'a, Q, K, V> + where Q: Ord + ToOwned + { // same basic logic of `swap` and `pop`, blended together let mut stack = stack::PartialSearchStack::new(self); loop { let result = stack.with(move |pusher, node| { - return match Node::search(node, &key) { + return match Node::search(node, key) { Found(handle) => { // Perfect match Finished(Occupied(OccupiedEntry { @@ -1413,6 +1412,7 @@ pub fn entry<'a>(&'a mut self, mut key: K) -> Entry<'a, K, V> { #[cfg(test)] mod test { use prelude::*; + use std::borrow::{ToOwned, BorrowFrom}; use super::{BTreeMap, Occupied, Vacant}; @@ -1562,11 +1562,11 @@ fn test_entry(){ let mut map: BTreeMap = xs.iter().map(|&x| x).collect(); // Existing key (insert) - match map.entry(1) { + match map.entry(&1) { Vacant(_) => unreachable!(), Occupied(mut view) => { assert_eq!(view.get(), &10); - assert_eq!(view.set(100), 10); + assert_eq!(view.insert(100), 10); } } assert_eq!(map.get(&1).unwrap(), &100); @@ -1574,7 +1574,7 @@ fn test_entry(){ // Existing key (update) - match map.entry(2) { + match map.entry(&2) { Vacant(_) => unreachable!(), Occupied(mut view) => { let v = view.get_mut(); @@ -1585,10 +1585,10 @@ fn test_entry(){ assert_eq!(map.len(), 6); // Existing key (take) - match map.entry(3) { + match map.entry(&3) { Vacant(_) => unreachable!(), Occupied(view) => { - assert_eq!(view.take(), 30); + assert_eq!(view.remove(), 30); } } assert_eq!(map.get(&3), None); @@ -1596,10 +1596,10 @@ fn test_entry(){ // Inexistent key (insert) - match map.entry(10) { + match map.entry(&10) { Occupied(_) => unreachable!(), Vacant(view) => { - assert_eq!(*view.set(1000), 1000); + assert_eq!(*view.insert(1000), 1000); } } assert_eq!(map.get(&10).unwrap(), &1000); diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 0406edcdd32..80d01c07547 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -245,7 +245,7 @@ pub fn union<'a>(&'a self, other: &'a BTreeSet) -> Union<'a, T> { /// /// let mut v = BTreeSet::new(); /// assert_eq!(v.len(), 0); - /// v.insert(1i); + /// v.insert(1); /// assert_eq!(v.len(), 1); /// ``` #[stable] @@ -260,7 +260,7 @@ pub fn len(&self) -> uint { self.map.len() } /// /// let mut v = BTreeSet::new(); /// assert!(v.is_empty()); - /// v.insert(1i); + /// v.insert(1); /// assert!(!v.is_empty()); /// ``` #[stable] @@ -274,7 +274,7 @@ pub fn is_empty(&self) -> bool { self.len() == 0 } /// use std::collections::BTreeSet; /// /// let mut v = BTreeSet::new(); - /// v.insert(1i); + /// v.insert(1); /// v.clear(); /// assert!(v.is_empty()); /// ``` @@ -294,7 +294,7 @@ pub fn clear(&mut self) { /// ``` /// use std::collections::BTreeSet; /// - /// let set: BTreeSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let set: BTreeSet = [1, 2, 3].iter().map(|&x| x).collect(); /// assert_eq!(set.contains(&1), true); /// assert_eq!(set.contains(&4), false); /// ``` @@ -311,7 +311,7 @@ pub fn contains(&self, value: &Q) -> bool where Q: BorrowFrom + Ord /// ``` /// use std::collections::BTreeSet; /// - /// let a: BTreeSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let a: BTreeSet = [1, 2, 3].iter().map(|&x| x).collect(); /// let mut b: BTreeSet = BTreeSet::new(); /// /// assert_eq!(a.is_disjoint(&b), true); @@ -332,7 +332,7 @@ pub fn is_disjoint(&self, other: &BTreeSet) -> bool { /// ``` /// use std::collections::BTreeSet; /// - /// let sup: BTreeSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let sup: BTreeSet = [1, 2, 3].iter().map(|&x| x).collect(); /// let mut set: BTreeSet = BTreeSet::new(); /// /// assert_eq!(set.is_subset(&sup), true); @@ -374,7 +374,7 @@ pub fn is_subset(&self, other: &BTreeSet) -> bool { /// ``` /// use std::collections::BTreeSet; /// - /// let sub: BTreeSet = [1i, 2].iter().map(|&x| x).collect(); + /// let sub: BTreeSet = [1, 2].iter().map(|&x| x).collect(); /// let mut set: BTreeSet = BTreeSet::new(); /// /// assert_eq!(set.is_superset(&sub), false); @@ -401,8 +401,8 @@ pub fn is_superset(&self, other: &BTreeSet) -> bool { /// /// let mut set = BTreeSet::new(); /// - /// assert_eq!(set.insert(2i), true); - /// assert_eq!(set.insert(2i), false); + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); /// assert_eq!(set.len(), 1); /// ``` #[stable] @@ -424,7 +424,7 @@ pub fn insert(&mut self, value: T) -> bool { /// /// let mut set = BTreeSet::new(); /// - /// set.insert(2i); + /// set.insert(2); /// assert_eq!(set.remove(&2), true); /// assert_eq!(set.remove(&2), false); /// ``` diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index ca8e75ac43c..5aec9973c81 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -230,9 +230,9 @@ pub fn new() -> DList { /// /// let mut a = DList::new(); /// let mut b = DList::new(); - /// a.push_back(1i); + /// a.push_back(1); /// a.push_back(2); - /// b.push_back(3i); + /// b.push_back(3); /// b.push_back(4); /// /// a.append(b); @@ -375,7 +375,7 @@ pub fn pop_front(&mut self) -> Option { /// use std::collections::DList; /// /// let mut d = DList::new(); - /// d.push_back(1i); + /// d.push_back(1); /// d.push_back(3); /// assert_eq!(3, *d.back().unwrap()); /// ``` @@ -394,7 +394,7 @@ pub fn push_back(&mut self, elt: T) { /// /// let mut d = DList::new(); /// assert_eq!(d.pop_back(), None); - /// d.push_back(1i); + /// d.push_back(1); /// d.push_back(3); /// assert_eq!(d.pop_back(), Some(3)); /// ``` @@ -551,7 +551,7 @@ impl<'a, A> IterMut<'a, A> { /// } /// { /// let vec: Vec = list.into_iter().collect(); - /// assert_eq!(vec, vec![1i, 2, 3, 4]); + /// assert_eq!(vec, vec![1, 2, 3, 4]); /// } /// ``` #[inline] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 944b224fed8..db236795038 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -103,7 +103,6 @@ mod std { mod prelude { // from core. pub use core::borrow::IntoCow; - pub use core::char::Char; pub use core::clone::Clone; pub use core::cmp::{PartialEq, Eq, PartialOrd, Ord}; pub use core::cmp::Ordering::{Less, Equal, Greater}; @@ -127,7 +126,7 @@ mod prelude { // from other crates. pub use alloc::boxed::Box; - pub use unicode::char::UnicodeChar; + pub use unicode::char::CharExt; // from collections. pub use slice::SliceConcatExt; diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index e86c40bed21..8a83bf25e9b 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -17,7 +17,7 @@ use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::iter::{self, FromIterator, RandomAccessIterator}; +use core::iter::{self, repeat, FromIterator, RandomAccessIterator}; use core::kinds::marker; use core::mem; use core::num::{Int, UnsignedInt}; @@ -30,11 +30,8 @@ use alloc::heap; -static INITIAL_CAPACITY: uint = 8u; // 2^3 -static MINIMUM_CAPACITY: uint = 2u; - -// FIXME(conventions): implement shrink_to_fit. Awkward with the current design, but it should -// be scrapped anyway. Defer to rewrite? +static INITIAL_CAPACITY: uint = 7u; // 2^3 - 1 +static MINIMUM_CAPACITY: uint = 1u; // 2 - 1 /// `RingBuf` is a circular buffer, which can be used as a double-ended queue efficiently. #[stable] @@ -127,7 +124,20 @@ unsafe fn copy(&self, dst: uint, src: uint, len: uint) { self.cap); ptr::copy_memory( self.ptr.offset(dst as int), - self.ptr.offset(src as int) as *const T, + self.ptr.offset(src as int), + len); + } + + /// Copies a contiguous block of memory len long from src to dst + #[inline] + unsafe fn copy_nonoverlapping(&self, dst: uint, src: uint, len: uint) { + debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + ptr::copy_nonoverlapping_memory( + self.ptr.offset(dst as int), + self.ptr.offset(src as int), len); } } @@ -143,7 +153,8 @@ pub fn new() -> RingBuf { #[stable] pub fn with_capacity(n: uint) -> RingBuf { // +1 since the ringbuffer always leaves one space empty - let cap = cmp::max(n + 1, MINIMUM_CAPACITY).next_power_of_two(); + let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + assert!(cap > n, "capacity overflow"); let size = cap.checked_mul(mem::size_of::()) .expect("capacity overflow"); @@ -173,7 +184,7 @@ pub fn with_capacity(n: uint) -> RingBuf { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(3i); + /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); /// assert_eq!(buf.get(1).unwrap(), &4); @@ -196,7 +207,7 @@ pub fn get(&self, i: uint) -> Option<&T> { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(3i); + /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); /// match buf.get_mut(1) { @@ -230,7 +241,7 @@ pub fn get_mut(&mut self, i: uint) -> Option<&mut T> { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(3i); + /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); /// buf.swap(0, 2); @@ -346,23 +357,16 @@ pub fn reserve(&mut self, additional: uint) { // Nop } else if self.head < oldcap - self.tail { // B unsafe { - ptr::copy_nonoverlapping_memory( - self.ptr.offset(oldcap as int), - self.ptr as *const T, - self.head - ); + self.copy_nonoverlapping(oldcap, 0, self.head); } self.head += oldcap; debug_assert!(self.head > self.tail); } else { // C + let new_tail = count - (oldcap - self.tail); unsafe { - ptr::copy_nonoverlapping_memory( - self.ptr.offset((count - (oldcap - self.tail)) as int), - self.ptr.offset(self.tail as int) as *const T, - oldcap - self.tail - ); + self.copy_nonoverlapping(new_tail, self.tail, oldcap - self.tail); } - self.tail = count - (oldcap - self.tail); + self.tail = new_tail; debug_assert!(self.head < self.tail); } debug_assert!(self.head < self.cap); @@ -371,6 +375,116 @@ pub fn reserve(&mut self, additional: uint) { } } + /// Shrinks the capacity of the ringbuf as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator may still inform the + /// ringbuf that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::with_capacity(15); + /// buf.extend(range(0u, 4)); + /// assert_eq!(buf.capacity(), 15); + /// buf.shrink_to_fit(); + /// assert!(buf.capacity() >= 4); + /// ``` + pub fn shrink_to_fit(&mut self) { + // +1 since the ringbuffer always leaves one space empty + // len + 1 can't overflow for an existing, well-formed ringbuf. + let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + if target_cap < self.cap { + // There are three cases of interest: + // All elements are out of desired bounds + // Elements are contiguous, and head is out of desired bounds + // Elements are discontiguous, and tail is out of desired bounds + // + // At all other times, element positions are unaffected. + // + // Indicates that elements at the head should be moved. + let head_outside = self.head == 0 || self.head >= target_cap; + // Move elements from out of desired bounds (positions after target_cap) + if self.tail >= target_cap && head_outside { + // T H + // [. . . . . . . . o o o o o o o . ] + // T H + // [o o o o o o o . ] + unsafe { + self.copy_nonoverlapping(0, self.tail, self.len()); + } + self.head = self.len(); + self.tail = 0; + } else if self.tail != 0 && self.tail < target_cap && head_outside { + // T H + // [. . . o o o o o o o . . . . . . ] + // H T + // [o o . o o o o o ] + let len = self.wrap_index(self.head - target_cap); + unsafe { + self.copy_nonoverlapping(0, target_cap, len); + } + self.head = len; + debug_assert!(self.head < self.tail); + } else if self.tail >= target_cap { + // H T + // [o o o o o . . . . . . . . . o o ] + // H T + // [o o o o o . o o ] + debug_assert!(self.wrap_index(self.head - 1) < target_cap); + let len = self.cap - self.tail; + let new_tail = target_cap - len; + unsafe { + self.copy_nonoverlapping(new_tail, self.tail, len); + } + self.tail = new_tail; + debug_assert!(self.head < self.tail); + } + + if mem::size_of::() != 0 { + let old = self.cap * mem::size_of::(); + let new_size = target_cap * mem::size_of::(); + unsafe { + self.ptr = heap::reallocate(self.ptr as *mut u8, + old, + new_size, + mem::min_align_of::()) as *mut T; + if self.ptr.is_null() { ::alloc::oom() } + } + } + self.cap = target_cap; + debug_assert!(self.head < self.cap); + debug_assert!(self.tail < self.cap); + debug_assert!(self.cap.count_ones() == 1); + } + } + + /// Shorten a ringbuf, dropping excess elements from the back. + /// + /// If `len` is greater than the ringbuf's current length, this has no + /// effect. + /// + /// # Examples + /// + /// ``` + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// buf.push_back(5i); + /// buf.push_back(10i); + /// buf.push_back(15); + /// buf.truncate(1); + /// assert_eq!(buf.len(), 1); + /// assert_eq!(Some(&5), buf.get(0)); + /// ``` + #[unstable = "matches collection reform specification; waiting on panic semantics"] + pub fn truncate(&mut self, len: uint) { + for _ in range(len, self.len()) { + self.pop_back(); + } + } + /// Returns a front-to-back iterator. /// /// # Examples @@ -379,7 +493,7 @@ pub fn reserve(&mut self, additional: uint) { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(5i); + /// buf.push_back(5); /// buf.push_back(3); /// buf.push_back(4); /// let b: &[_] = &[&5, &3, &4]; @@ -402,7 +516,7 @@ pub fn iter(&self) -> Iter { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(5i); + /// buf.push_back(5); /// buf.push_back(3); /// buf.push_back(4); /// for num in buf.iter_mut() { @@ -481,7 +595,7 @@ pub fn as_mut_slices<'a>(&'a mut self) -> (&'a mut [T], &'a mut [T]) { /// /// let mut v = RingBuf::new(); /// assert_eq!(v.len(), 0); - /// v.push_back(1i); + /// v.push_back(1); /// assert_eq!(v.len(), 1); /// ``` #[stable] @@ -496,7 +610,7 @@ pub fn len(&self) -> uint { count(self.tail, self.head, self.cap) } /// /// let mut v = RingBuf::new(); /// assert!(v.is_empty()); - /// v.push_front(1i); + /// v.push_front(1); /// assert!(!v.is_empty()); /// ``` #[stable] @@ -511,7 +625,7 @@ pub fn is_empty(&self) -> bool { self.len() == 0 } /// use std::collections::RingBuf; /// /// let mut v = RingBuf::new(); - /// v.push_back(1i); + /// v.push_back(1); /// assert_eq!(v.drain().next(), Some(1)); /// assert!(v.is_empty()); /// ``` @@ -531,7 +645,7 @@ pub fn drain(&mut self) -> Drain { /// use std::collections::RingBuf; /// /// let mut v = RingBuf::new(); - /// v.push_back(1i); + /// v.push_back(1); /// v.clear(); /// assert!(v.is_empty()); /// ``` @@ -552,9 +666,9 @@ pub fn clear(&mut self) { /// let mut d = RingBuf::new(); /// assert_eq!(d.front(), None); /// - /// d.push_back(1i); - /// d.push_back(2i); - /// assert_eq!(d.front(), Some(&1i)); + /// d.push_back(1); + /// d.push_back(2); + /// assert_eq!(d.front(), Some(&1)); /// ``` #[stable] pub fn front(&self) -> Option<&T> { @@ -572,13 +686,13 @@ pub fn front(&self) -> Option<&T> { /// let mut d = RingBuf::new(); /// assert_eq!(d.front_mut(), None); /// - /// d.push_back(1i); - /// d.push_back(2i); + /// d.push_back(1); + /// d.push_back(2); /// match d.front_mut() { - /// Some(x) => *x = 9i, + /// Some(x) => *x = 9, /// None => (), /// } - /// assert_eq!(d.front(), Some(&9i)); + /// assert_eq!(d.front(), Some(&9)); /// ``` #[stable] pub fn front_mut(&mut self) -> Option<&mut T> { @@ -596,9 +710,9 @@ pub fn front_mut(&mut self) -> Option<&mut T> { /// let mut d = RingBuf::new(); /// assert_eq!(d.back(), None); /// - /// d.push_back(1i); - /// d.push_back(2i); - /// assert_eq!(d.back(), Some(&2i)); + /// d.push_back(1); + /// d.push_back(2); + /// assert_eq!(d.back(), Some(&2)); /// ``` #[stable] pub fn back(&self) -> Option<&T> { @@ -616,13 +730,13 @@ pub fn back(&self) -> Option<&T> { /// let mut d = RingBuf::new(); /// assert_eq!(d.back(), None); /// - /// d.push_back(1i); - /// d.push_back(2i); + /// d.push_back(1); + /// d.push_back(2); /// match d.back_mut() { - /// Some(x) => *x = 9i, + /// Some(x) => *x = 9, /// None => (), /// } - /// assert_eq!(d.back(), Some(&9i)); + /// assert_eq!(d.back(), Some(&9)); /// ``` #[stable] pub fn back_mut(&mut self) -> Option<&mut T> { @@ -639,11 +753,11 @@ pub fn back_mut(&mut self) -> Option<&mut T> { /// use std::collections::RingBuf; /// /// let mut d = RingBuf::new(); - /// d.push_back(1i); - /// d.push_back(2i); + /// d.push_back(1); + /// d.push_back(2); /// - /// assert_eq!(d.pop_front(), Some(1i)); - /// assert_eq!(d.pop_front(), Some(2i)); + /// assert_eq!(d.pop_front(), Some(1)); + /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); /// ``` #[stable] @@ -665,9 +779,9 @@ pub fn pop_front(&mut self) -> Option { /// use std::collections::RingBuf; /// /// let mut d = RingBuf::new(); - /// d.push_front(1i); - /// d.push_front(2i); - /// assert_eq!(d.front(), Some(&2i)); + /// d.push_front(1); + /// d.push_front(2); + /// assert_eq!(d.front(), Some(&2)); /// ``` #[stable] pub fn push_front(&mut self, t: T) { @@ -689,7 +803,7 @@ pub fn push_front(&mut self, t: T) { /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(1i); + /// buf.push_back(1); /// buf.push_back(3); /// assert_eq!(3, *buf.back().unwrap()); /// ``` @@ -715,7 +829,7 @@ pub fn push_back(&mut self, t: T) { /// /// let mut buf = RingBuf::new(); /// assert_eq!(buf.pop_back(), None); - /// buf.push_back(1i); + /// buf.push_back(1); /// buf.push_back(3); /// assert_eq!(buf.pop_back(), Some(3)); /// ``` @@ -735,6 +849,70 @@ fn is_contiguous(&self) -> bool { self.tail <= self.head } + /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the last + /// element. + /// + /// This does not preserve ordering, but is O(1). + /// + /// Returns `None` if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// assert_eq!(buf.swap_back_remove(0), None); + /// buf.push_back(5i); + /// buf.push_back(99); + /// buf.push_back(15); + /// buf.push_back(20); + /// buf.push_back(10); + /// assert_eq!(buf.swap_back_remove(1), Some(99)); + /// ``` + #[unstable = "the naming of this function may be altered"] + pub fn swap_back_remove(&mut self, index: uint) -> Option { + let length = self.len(); + if length > 0 && index < length - 1 { + self.swap(index, length - 1); + } else if index >= length { + return None; + } + self.pop_back() + } + + /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the first + /// element. + /// + /// This does not preserve ordering, but is O(1). + /// + /// Returns `None` if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// assert_eq!(buf.swap_front_remove(0), None); + /// buf.push_back(15i); + /// buf.push_back(5); + /// buf.push_back(10); + /// buf.push_back(99); + /// buf.push_back(20i); + /// assert_eq!(buf.swap_front_remove(3), Some(99)); + /// ``` + #[unstable = "the naming of this function may be altered"] + pub fn swap_front_remove(&mut self, index: uint) -> Option { + let length = self.len(); + if length > 0 && index < length && index != 0 { + self.swap(index, 0); + } else if index >= length { + return None; + } + self.pop_front() + } + /// Inserts an element at position `i` within the ringbuf. Whichever /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. @@ -743,12 +921,12 @@ fn is_contiguous(&self) -> bool { /// /// Panics if `i` is greater than ringbuf's length /// - /// # Example + /// # Examples /// ```rust /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(10i); + /// buf.push_back(10); /// buf.push_back(12); /// buf.insert(1,11); /// assert_eq!(Some(&11), buf.get(1)); @@ -945,14 +1123,14 @@ pub fn insert(&mut self, i: uint, t: T) { /// room, and all the affected elements will be moved to new positions. /// Returns `None` if `i` is out of bounds. /// - /// # Example + /// # Examples /// ```rust /// use std::collections::RingBuf; /// /// let mut buf = RingBuf::new(); - /// buf.push_back(5i); - /// buf.push_back(10i); - /// buf.push_back(12i); + /// buf.push_back(5); + /// buf.push_back(10); + /// buf.push_back(12); /// buf.push_back(15); /// buf.remove(2); /// assert_eq!(Some(&15), buf.get(2)); @@ -990,7 +1168,7 @@ pub fn remove(&mut self, i: uint) -> Option { let distance_to_tail = i; let distance_to_head = self.len() - i; - let contiguous = self.tail <= self.head; + let contiguous = self.is_contiguous(); match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { (true, true, _) => unsafe { @@ -1105,6 +1283,37 @@ pub fn remove(&mut self, i: uint) -> Option { } } +impl RingBuf { + /// Modifies the ringbuf in-place so that `len()` is equal to new_len, + /// either by removing excess elements or by appending copies of a value to the back. + /// + /// # Examples + /// + /// ``` + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// buf.push_back(5i); + /// buf.push_back(10i); + /// buf.push_back(15); + /// buf.resize(2, 0); + /// buf.resize(6, 20); + /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(buf.iter()) { + /// assert_eq!(a, b); + /// } + /// ``` + #[unstable = "matches collection reform specification; waiting on panic semantics"] + pub fn resize(&mut self, new_len: uint, value: T) { + let len = self.len(); + + if new_len > len { + self.extend(repeat(value).take(new_len - len)) + } else { + self.truncate(new_len); + } + } +} + /// Returns the index in the underlying buffer for a given logical element index. #[inline] fn wrap_index(index: uint, size: uint) -> uint { @@ -1360,17 +1569,6 @@ fn hash(&self, state: &mut S) { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl Index for RingBuf { - #[inline] - fn index<'a>(&'a self, i: &uint) -> &'a A { - self.get(*i).expect("Out of bounds access") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl Index for RingBuf { type Output = A; @@ -1381,17 +1579,6 @@ fn index<'a>(&'a self, i: &uint) -> &'a A { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl IndexMut for RingBuf { - #[inline] - fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut A { - self.get_mut(*i).expect("Out of bounds access") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl IndexMut for RingBuf { type Output = A; @@ -2292,6 +2479,50 @@ fn test_get_mut() { assert_eq!(ring.get_mut(2), None); } + #[test] + fn test_swap_front_back_remove() { + fn test(back: bool) { + // This test checks that every single combination of tail position and length is tested. + // Capacity 15 should be large enough to cover every case. + let mut tester = RingBuf::with_capacity(15); + let usable_cap = tester.capacity(); + let final_len = usable_cap / 2; + + for len in range(0, final_len) { + let expected = if back { + range(0, len).collect() + } else { + range(0, len).rev().collect() + }; + for tail_pos in range(0, usable_cap) { + tester.tail = tail_pos; + tester.head = tail_pos; + if back { + for i in range(0, len * 2) { + tester.push_front(i); + } + for i in range(0, len) { + assert_eq!(tester.swap_back_remove(i), Some(len * 2 - 1 - i)); + } + } else { + for i in range(0, len * 2) { + tester.push_back(i); + } + for i in range(0, len) { + let idx = tester.len() - 1 - i; + assert_eq!(tester.swap_front_remove(idx), Some(len * 2 - 1 - i)); + } + } + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); + assert_eq!(tester, expected); + } + } + } + test(true); + test(false); + } + #[test] fn test_insert() { // This test checks that every single combination of tail position, length, and @@ -2363,6 +2594,38 @@ fn test_remove() { } } + #[test] + fn test_shrink_to_fit() { + // This test checks that every single combination of head and tail position, + // is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = RingBuf::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + tester.reserve(63); + let max_cap = tester.capacity(); + + for len in range(0, cap + 1) { + // 0, 1, 2, .., len - 1 + let expected = iter::count(0, 1).take(len).collect(); + for tail_pos in range(0, max_cap + 1) { + tester.tail = tail_pos; + tester.head = tail_pos; + tester.reserve(63); + for i in range(0, len) { + tester.push_back(i); + } + tester.shrink_to_fit(); + assert!(tester.capacity() <= cap); + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); + assert_eq!(tester, expected); + } + } + } + #[test] fn test_front() { let mut ring = RingBuf::new(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 3602bfc10c3..8050c44f542 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -15,7 +15,7 @@ //! //! ```rust //! // slicing a Vec -//! let vec = vec!(1i, 2, 3); +//! let vec = vec!(1, 2, 3); //! let int_slice = vec.as_slice(); //! // coercing an array to a slice //! let str_slice: &[&str] = &["one", "two", "three"]; @@ -26,7 +26,7 @@ //! block of memory that a mutable slice points to: //! //! ```rust -//! let x: &mut[int] = &mut [1i, 2, 3]; +//! let x: &mut[int] = &mut [1, 2, 3]; //! x[1] = 7; //! assert_eq!(x[0], 1); //! assert_eq!(x[1], 7); @@ -54,9 +54,9 @@ //! ```rust //! #![feature(slicing_syntax)] //! fn main() { -//! let numbers = [0i, 1i, 2i]; +//! let numbers = [0, 1, 2]; //! let last_numbers = numbers[1..3]; -//! // last_numbers is now &[1i, 2i] +//! // last_numbers is now &[1, 2] //! } //! ``` //! @@ -76,7 +76,7 @@ //! type of the slice is `int`, the element type of the iterator is `&int`. //! //! ```rust -//! let numbers = [0i, 1i, 2i]; +//! let numbers = [0, 1, 2]; //! for &x in numbers.iter() { //! println!("{} is a number!", x); //! } @@ -89,40 +89,40 @@ use alloc::boxed::Box; use core::borrow::{BorrowFrom, BorrowFromMut, ToOwned}; -use core::clone::Clone; -use core::cmp::Ordering::{self, Greater, Less}; -use core::cmp::{self, Ord, PartialEq}; -use core::iter::{Iterator, IteratorExt}; -use core::iter::{range, range_step, MultiplicativeIterator}; +use core::cmp; +use core::iter::{range_step, MultiplicativeIterator}; use core::kinds::Sized; use core::mem::size_of; use core::mem; -use core::ops::{FnMut, SliceMut}; -use core::option::Option::{self, Some, None}; -use core::ptr::PtrExt; +use core::ops::{FnMut,SliceMut}; +use core::prelude::{Clone, Greater, Iterator, IteratorExt, Less, None, Option}; +use core::prelude::{Ord, Ordering, PtrExt, Some, range, IteratorCloneExt, Result}; use core::ptr; -use core::result::Result; use core::slice as core_slice; use self::Direction::*; use vec::Vec; pub use core::slice::{Chunks, AsSlice, Windows}; -pub use core::slice::{Iter, IterMut}; +pub use core::slice::{Iter, IterMut, PartialEqSliceExt}; pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split}; pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; pub use core::slice::{bytes, mut_ref_slice, ref_slice}; pub use core::slice::{from_raw_buf, from_raw_mut_buf}; +#[deprecated = "use Iter instead"] +pub type Items<'a, T:'a> = Iter<'a, T>; + +#[deprecated = "use IterMut instead"] +pub type MutItems<'a, T:'a> = IterMut<'a, T>; + //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods //////////////////////////////////////////////////////////////////////////////// /// Allocating extension methods for slices. #[unstable = "needs associated types, may merge with other traits"] -pub trait SliceExt for Sized? { - type Item; - +pub trait SliceExt for Sized? { /// Sorts the slice, in place, using `compare` to compare /// elements. /// @@ -132,7 +132,7 @@ pub trait SliceExt for Sized? { /// # Examples /// /// ```rust - /// let mut v = [5i, 4, 1, 3, 2]; + /// let mut v = [5, 4, 1, 3, 2]; /// v.sort_by(|a, b| a.cmp(b)); /// assert!(v == [1, 2, 3, 4, 5]); /// @@ -141,7 +141,7 @@ pub trait SliceExt for Sized? { /// assert!(v == [5, 4, 3, 2, 1]); /// ``` #[stable] - fn sort_by(&mut self, compare: F) where F: FnMut(&Self::Item, &Self::Item) -> Ordering; + fn sort_by(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering; /// Consumes `src` and moves as many elements as it can into `self` /// from the range [start,end). @@ -158,14 +158,14 @@ pub trait SliceExt for Sized? { /// # Examples /// /// ```rust - /// let mut a = [1i, 2, 3, 4, 5]; - /// let b = vec![6i, 7, 8]; + /// let mut a = [1, 2, 3, 4, 5]; + /// let b = vec![6, 7, 8]; /// let num_moved = a.move_from(b, 0, 3); /// assert_eq!(num_moved, 3); - /// assert!(a == [6i, 7, 8, 4, 5]); + /// assert!(a == [6, 7, 8, 4, 5]); /// ``` #[experimental = "uncertain about this API approach"] - fn move_from(&mut self, src: Vec, start: uint, end: uint) -> uint; + fn move_from(&mut self, src: Vec, start: uint, end: uint) -> uint; /// Returns a subslice spanning the interval [`start`, `end`). /// @@ -174,7 +174,7 @@ pub trait SliceExt for Sized? { /// /// Slicing with `start` equal to `end` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice(&self, start: uint, end: uint) -> &[Self::Item]; + fn slice(&self, start: uint, end: uint) -> &[T]; /// Returns a subslice from `start` to the end of the slice. /// @@ -182,7 +182,7 @@ pub trait SliceExt for Sized? { /// /// Slicing from `self.len()` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice_from(&self, start: uint) -> &[Self::Item]; + fn slice_from(&self, start: uint) -> &[T]; /// Returns a subslice from the start of the slice to `end`. /// @@ -190,7 +190,7 @@ pub trait SliceExt for Sized? { /// /// Slicing to `0` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice_to(&self, end: uint) -> &[Self::Item]; + fn slice_to(&self, end: uint) -> &[T]; /// Divides one slice into two at an index. /// @@ -200,32 +200,32 @@ pub trait SliceExt for Sized? { /// /// Panics if `mid > len`. #[stable] - fn split_at(&self, mid: uint) -> (&[Self::Item], &[Self::Item]); + fn split_at(&self, mid: uint) -> (&[T], &[T]); /// Returns an iterator over the slice #[stable] - fn iter(&self) -> Iter; + fn iter(&self) -> Iter; /// Returns an iterator over subslices separated by elements that match /// `pred`. The matched element is not contained in the subslices. #[stable] - fn split(&self, pred: F) -> Split - where F: FnMut(&Self::Item) -> bool; + fn split(&self, pred: F) -> Split + where F: FnMut(&T) -> bool; /// Returns an iterator over subslices separated by elements that match /// `pred`, limited to splitting at most `n` times. The matched element is /// not contained in the subslices. #[stable] - fn splitn(&self, n: uint, pred: F) -> SplitN - where F: FnMut(&Self::Item) -> bool; + fn splitn(&self, n: uint, pred: F) -> SplitN + where F: FnMut(&T) -> bool; /// Returns an iterator over subslices separated by elements that match /// `pred` limited to splitting at most `n` times. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. #[stable] - fn rsplitn(&self, n: uint, pred: F) -> RSplitN - where F: FnMut(&Self::Item) -> bool; + fn rsplitn(&self, n: uint, pred: F) -> RSplitN + where F: FnMut(&T) -> bool; /// Returns an iterator over all contiguous windows of length /// `size`. The windows overlap. If the slice is shorter than @@ -241,13 +241,13 @@ fn rsplitn(&self, n: uint, pred: F) -> RSplitN /// `[3,4]`): /// /// ```rust - /// let v = &[1i, 2, 3, 4]; + /// let v = &[1, 2, 3, 4]; /// for win in v.windows(2) { /// println!("{}", win); /// } /// ``` #[stable] - fn windows(&self, size: uint) -> Windows; + fn windows(&self, size: uint) -> Windows; /// Returns an iterator over `size` elements of the slice at a /// time. The chunks do not overlap. If `size` does not divide the @@ -264,39 +264,49 @@ fn rsplitn(&self, n: uint, pred: F) -> RSplitN /// `[3,4]`, `[5]`): /// /// ```rust - /// let v = &[1i, 2, 3, 4, 5]; + /// let v = &[1, 2, 3, 4, 5]; /// for win in v.chunks(2) { /// println!("{}", win); /// } /// ``` #[stable] - fn chunks(&self, size: uint) -> Chunks; + fn chunks(&self, size: uint) -> Chunks; /// Returns the element of a slice at the given index, or `None` if the /// index is out of bounds. #[stable] - fn get(&self, index: uint) -> Option<&Self::Item>; + fn get(&self, index: uint) -> Option<&T>; /// Returns the first element of a slice, or `None` if it is empty. #[stable] - fn first(&self) -> Option<&Self::Item>; + fn first(&self) -> Option<&T>; + + /// Deprecated: renamed to `first`. + #[deprecated = "renamed to `first`"] + fn head(&self) -> Option<&T> { self.first() } /// Returns all but the first element of a slice. #[experimental = "likely to be renamed"] - fn tail(&self) -> &[Self::Item]; + fn tail(&self) -> &[T]; /// Returns all but the last element of a slice. #[experimental = "likely to be renamed"] - fn init(&self) -> &[Self::Item]; + fn init(&self) -> &[T]; /// Returns the last element of a slice, or `None` if it is empty. #[stable] - fn last(&self) -> Option<&Self::Item>; + fn last(&self) -> Option<&T>; /// Returns a pointer to the element at the given index, without doing /// bounds checking. #[stable] - unsafe fn get_unchecked(&self, index: uint) -> &Self::Item; + unsafe fn get_unchecked(&self, index: uint) -> &T; + + /// Deprecated: renamed to `get_unchecked`. + #[deprecated = "renamed to get_unchecked"] + unsafe fn unsafe_get(&self, index: uint) -> &T { + self.get_unchecked(index) + } /// Returns an unsafe pointer to the slice's buffer /// @@ -306,7 +316,7 @@ fn rsplitn(&self, n: uint, pred: F) -> RSplitN /// Modifying the slice may cause its buffer to be reallocated, which /// would also make any pointers to it invalid. #[stable] - fn as_ptr(&self) -> *const Self::Item; + fn as_ptr(&self) -> *const T; /// Binary search a sorted slice with a comparator function. /// @@ -327,7 +337,7 @@ fn rsplitn(&self, n: uint, pred: F) -> RSplitN /// found; the fourth could match any position in `[1,4]`. /// /// ```rust - /// let s = [0i, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// let s = s.as_slice(); /// /// let seek = 13; @@ -342,14 +352,14 @@ fn rsplitn(&self, n: uint, pred: F) -> RSplitN /// ``` #[stable] fn binary_search_by(&self, f: F) -> Result where - F: FnMut(&Self::Item) -> Ordering; + F: FnMut(&T) -> Ordering; /// Return the number of elements in the slice /// /// # Example /// /// ``` - /// let a = [1i, 2, 3]; + /// let a = [1, 2, 3]; /// assert_eq!(a.len(), 3); /// ``` #[stable] @@ -360,7 +370,7 @@ fn binary_search_by(&self, f: F) -> Result where /// # Example /// /// ``` - /// let a = [1i, 2, 3]; + /// let a = [1, 2, 3]; /// assert!(!a.is_empty()); /// ``` #[inline] @@ -369,12 +379,12 @@ fn is_empty(&self) -> bool { self.len() == 0 } /// Returns a mutable reference to the element at the given index, /// or `None` if the index is out of bounds #[stable] - fn get_mut(&mut self, index: uint) -> Option<&mut Self::Item>; + fn get_mut(&mut self, index: uint) -> Option<&mut T>; /// Work with `self` as a mut slice. /// Primarily intended for getting a &mut [T] from a [T; N]. #[stable] - fn as_mut_slice(&mut self) -> &mut [Self::Item]; + fn as_mut_slice(&mut self) -> &mut [T]; /// Returns a mutable subslice spanning the interval [`start`, `end`). /// @@ -383,7 +393,7 @@ fn is_empty(&self) -> bool { self.len() == 0 } /// /// Slicing with `start` equal to `end` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice_mut(&mut self, start: uint, end: uint) -> &mut [Self::Item]; + fn slice_mut(&mut self, start: uint, end: uint) -> &mut [T]; /// Returns a mutable subslice from `start` to the end of the slice. /// @@ -391,7 +401,7 @@ fn is_empty(&self) -> bool { self.len() == 0 } /// /// Slicing from `self.len()` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice_from_mut(&mut self, start: uint) -> &mut [Self::Item]; + fn slice_from_mut(&mut self, start: uint) -> &mut [T]; /// Returns a mutable subslice from the start of the slice to `end`. /// @@ -399,48 +409,54 @@ fn is_empty(&self) -> bool { self.len() == 0 } /// /// Slicing to `0` yields an empty slice. #[experimental = "will be replaced by slice syntax"] - fn slice_to_mut(&mut self, end: uint) -> &mut [Self::Item]; + fn slice_to_mut(&mut self, end: uint) -> &mut [T]; /// Returns an iterator that allows modifying each value #[stable] - fn iter_mut(&mut self) -> IterMut; + fn iter_mut(&mut self) -> IterMut; /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty #[stable] - fn first_mut(&mut self) -> Option<&mut Self::Item>; + fn first_mut(&mut self) -> Option<&mut T>; + + /// Depreated: renamed to `first_mut`. + #[deprecated = "renamed to first_mut"] + fn head_mut(&mut self) -> Option<&mut T> { + self.first_mut() + } /// Returns all but the first element of a mutable slice #[experimental = "likely to be renamed or removed"] - fn tail_mut(&mut self) -> &mut [Self::Item]; + fn tail_mut(&mut self) -> &mut [T]; /// Returns all but the last element of a mutable slice #[experimental = "likely to be renamed or removed"] - fn init_mut(&mut self) -> &mut [Self::Item]; + fn init_mut(&mut self) -> &mut [T]; /// Returns a mutable pointer to the last item in the slice. #[stable] - fn last_mut(&mut self) -> Option<&mut Self::Item>; + fn last_mut(&mut self) -> Option<&mut T>; /// Returns an iterator over mutable subslices separated by elements that /// match `pred`. The matched element is not contained in the subslices. #[stable] - fn split_mut(&mut self, pred: F) -> SplitMut - where F: FnMut(&Self::Item) -> bool; + fn split_mut(&mut self, pred: F) -> SplitMut + where F: FnMut(&T) -> bool; /// Returns an iterator over subslices separated by elements that match /// `pred`, limited to splitting at most `n` times. The matched element is /// not contained in the subslices. #[stable] - fn splitn_mut(&mut self, n: uint, pred: F) -> SplitNMut - where F: FnMut(&Self::Item) -> bool; + fn splitn_mut(&mut self, n: uint, pred: F) -> SplitNMut + where F: FnMut(&T) -> bool; /// Returns an iterator over subslices separated by elements that match /// `pred` limited to splitting at most `n` times. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. #[stable] - fn rsplitn_mut(&mut self, n: uint, pred: F) -> RSplitNMut - where F: FnMut(&Self::Item) -> bool; + fn rsplitn_mut(&mut self, n: uint, pred: F) -> RSplitNMut + where F: FnMut(&T) -> bool; /// Returns an iterator over `chunk_size` elements of the slice at a time. /// The chunks are mutable and do not overlap. If `chunk_size` does @@ -451,7 +467,7 @@ fn rsplitn_mut(&mut self, n: uint, pred: F) -> RSplitNMut /// /// Panics if `chunk_size` is 0. #[stable] - fn chunks_mut(&mut self, chunk_size: uint) -> ChunksMut; + fn chunks_mut(&mut self, chunk_size: uint) -> ChunksMut; /// Swaps two elements in a slice. /// @@ -487,45 +503,51 @@ fn rsplitn_mut(&mut self, n: uint, pred: F) -> RSplitNMut /// # Example /// /// ```rust - /// let mut v = [1i, 2, 3, 4, 5, 6]; + /// let mut v = [1, 2, 3, 4, 5, 6]; /// /// // scoped to restrict the lifetime of the borrows /// { /// let (left, right) = v.split_at_mut(0); /// assert!(left == []); - /// assert!(right == [1i, 2, 3, 4, 5, 6]); + /// assert!(right == [1, 2, 3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at_mut(2); - /// assert!(left == [1i, 2]); - /// assert!(right == [3i, 4, 5, 6]); + /// assert!(left == [1, 2]); + /// assert!(right == [3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at_mut(6); - /// assert!(left == [1i, 2, 3, 4, 5, 6]); + /// assert!(left == [1, 2, 3, 4, 5, 6]); /// assert!(right == []); /// } /// ``` #[stable] - fn split_at_mut(&mut self, mid: uint) -> (&mut [Self::Item], &mut [Self::Item]); + fn split_at_mut(&mut self, mid: uint) -> (&mut [T], &mut [T]); /// Reverse the order of elements in a slice, in place. /// /// # Example /// /// ```rust - /// let mut v = [1i, 2, 3]; + /// let mut v = [1, 2, 3]; /// v.reverse(); - /// assert!(v == [3i, 2, 1]); + /// assert!(v == [3, 2, 1]); /// ``` #[stable] fn reverse(&mut self); /// Returns an unsafe mutable pointer to the element in index #[stable] - unsafe fn get_unchecked_mut(&mut self, index: uint) -> &mut Self::Item; + unsafe fn get_unchecked_mut(&mut self, index: uint) -> &mut T; + + /// Deprecated: renamed to `get_unchecked_mut`. + #[deprecated = "renamed to get_unchecked_mut"] + unsafe fn unchecked_mut(&mut self, index: uint) -> &mut T { + self.get_unchecked_mut(index) + } /// Return an unsafe mutable pointer to the slice's buffer. /// @@ -536,173 +558,11 @@ fn rsplitn_mut(&mut self, n: uint, pred: F) -> RSplitNMut /// would also make any pointers to it invalid. #[inline] #[stable] - fn as_mut_ptr(&mut self) -> *mut Self::Item; - - /// Copies `self` into a new `Vec`. - #[stable] - fn to_vec(&self) -> Vec where Self::Item: Clone; - - /// Creates an iterator that yields every possible permutation of the - /// vector in succession. - /// - /// # Examples - /// - /// ```rust - /// let v = [1i, 2, 3]; - /// let mut perms = v.permutations(); - /// - /// for p in perms { - /// println!("{}", p); - /// } - /// ``` - /// - /// Iterating through permutations one by one. - /// - /// ```rust - /// let v = [1i, 2, 3]; - /// let mut perms = v.permutations(); - /// - /// assert_eq!(Some(vec![1i, 2, 3]), perms.next()); - /// assert_eq!(Some(vec![1i, 3, 2]), perms.next()); - /// assert_eq!(Some(vec![3i, 1, 2]), perms.next()); - /// ``` - #[unstable] - fn permutations(&self) -> Permutations where Self::Item: Clone; - - /// Copies as many elements from `src` as it can into `self` (the - /// shorter of `self.len()` and `src.len()`). Returns the number - /// of elements copied. - /// - /// # Example - /// - /// ```rust - /// let mut dst = [0i, 0, 0]; - /// let src = [1i, 2]; - /// - /// assert!(dst.clone_from_slice(&src) == 2); - /// assert!(dst == [1, 2, 0]); - /// - /// let src2 = [3i, 4, 5, 6]; - /// assert!(dst.clone_from_slice(&src2) == 3); - /// assert!(dst == [3i, 4, 5]); - /// ``` - #[experimental] - fn clone_from_slice(&mut self, &[Self::Item]) -> uint where Self::Item: Clone; - - /// Sorts the slice, in place. - /// - /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. - /// - /// # Examples - /// - /// ```rust - /// let mut v = [-5i, 4, 1, -3, 2]; - /// - /// v.sort(); - /// assert!(v == [-5i, -3, 1, 2, 4]); - /// ``` - #[stable] - fn sort(&mut self) where Self::Item: Ord; - - /// Binary search a sorted slice for a given element. - /// - /// If the value is found then `Ok` is returned, containing the - /// index of the matching element; if the value is not found then - /// `Err` is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. - /// - /// # Example - /// - /// Looks up a series of four elements. The first is found, with a - /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1,4]`. - /// - /// ```rust - /// let s = [0i, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; - /// let s = s.as_slice(); - /// - /// assert_eq!(s.binary_search(&13), Ok(9)); - /// assert_eq!(s.binary_search(&4), Err(7)); - /// assert_eq!(s.binary_search(&100), Err(13)); - /// let r = s.binary_search(&1); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable] - fn binary_search(&self, x: &Self::Item) -> Result where Self::Item: Ord; - - /// Deprecated: use `binary_search` instead. - #[deprecated = "use binary_search instead"] - fn binary_search_elem(&self, x: &Self::Item) -> Result where Self::Item: Ord { - self.binary_search(x) - } - - /// Mutates the slice to the next lexicographic permutation. - /// - /// Returns `true` if successful and `false` if the slice is at the - /// last-ordered permutation. - /// - /// # Example - /// - /// ```rust - /// let v: &mut [_] = &mut [0i, 1, 2]; - /// v.next_permutation(); - /// let b: &mut [_] = &mut [0i, 2, 1]; - /// assert!(v == b); - /// v.next_permutation(); - /// let b: &mut [_] = &mut [1i, 0, 2]; - /// assert!(v == b); - /// ``` - #[unstable = "uncertain if this merits inclusion in std"] - fn next_permutation(&mut self) -> bool where Self::Item: Ord; - - /// Mutates the slice to the previous lexicographic permutation. - /// - /// Returns `true` if successful and `false` if the slice is at the - /// first-ordered permutation. - /// - /// # Example - /// - /// ```rust - /// let v: &mut [_] = &mut [1i, 0, 2]; - /// v.prev_permutation(); - /// let b: &mut [_] = &mut [0i, 2, 1]; - /// assert!(v == b); - /// v.prev_permutation(); - /// let b: &mut [_] = &mut [0i, 1, 2]; - /// assert!(v == b); - /// ``` - #[unstable = "uncertain if this merits inclusion in std"] - fn prev_permutation(&mut self) -> bool where Self::Item: Ord; - - /// Find the first index containing a matching value. - #[experimental] - fn position_elem(&self, t: &Self::Item) -> Option where Self::Item: PartialEq; - - /// Find the last index containing a matching value. - #[experimental] - fn rposition_elem(&self, t: &Self::Item) -> Option where Self::Item: PartialEq; - - /// Return true if the slice contains an element with the given value. - #[stable] - fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq; - - /// Returns true if `needle` is a prefix of the slice. - #[stable] - fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - /// Returns true if `needle` is a suffix of the slice. - #[stable] - fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - /// Convert `self` into a vector without clones or allocation. - #[experimental] - fn into_vec(self: Box) -> Vec; + fn as_mut_ptr(&mut self) -> *mut T; } #[unstable = "trait is unstable"] -impl SliceExt for [T] { - type Item = T; - +impl SliceExt for [T] { #[inline] fn sort_by(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering { merge_sort(self, compare) @@ -917,76 +777,229 @@ unsafe fn get_unchecked_mut<'a>(&'a mut self, index: uint) -> &'a mut T { fn as_mut_ptr(&mut self) -> *mut T { core_slice::SliceExt::as_mut_ptr(self) } +} + +//////////////////////////////////////////////////////////////////////////////// +// Extension traits for slices over specifc kinds of data +//////////////////////////////////////////////////////////////////////////////// + +/// Extension methods for boxed slices. +#[experimental = "likely to merge into SliceExt if it survives"] +pub trait BoxedSliceExt { + /// Convert `self` into a vector without clones or allocation. + #[experimental] + fn into_vec(self) -> Vec; +} + +#[experimental = "trait is experimental"] +impl BoxedSliceExt for Box<[T]> { + fn into_vec(mut self) -> Vec { + unsafe { + let xs = Vec::from_raw_parts(self.as_mut_ptr(), self.len(), self.len()); + mem::forget(self); + xs + } + } +} + +/// Allocating extension methods for slices containing `Clone` elements. +#[unstable = "likely to be merged into SliceExt"] +pub trait CloneSliceExt for Sized? { + /// Copies `self` into a new `Vec`. + #[stable] + fn to_vec(&self) -> Vec; + + /// Deprecated: use `iter().cloned().partition(f)` instead. + #[deprecated = "use iter().cloned().partition(f) instead"] + fn partitioned(&self, f: F) -> (Vec, Vec) where F: FnMut(&T) -> bool; + /// Creates an iterator that yields every possible permutation of the + /// vector in succession. + /// + /// # Examples + /// + /// ```rust + /// let v = [1, 2, 3]; + /// let mut perms = v.permutations(); + /// + /// for p in perms { + /// println!("{}", p); + /// } + /// ``` + /// + /// Iterating through permutations one by one. + /// + /// ```rust + /// let v = [1, 2, 3]; + /// let mut perms = v.permutations(); + /// + /// assert_eq!(Some(vec![1, 2, 3]), perms.next()); + /// assert_eq!(Some(vec![1, 3, 2]), perms.next()); + /// assert_eq!(Some(vec![3, 1, 2]), perms.next()); + /// ``` + #[unstable] + fn permutations(&self) -> Permutations; + + /// Copies as many elements from `src` as it can into `self` (the + /// shorter of `self.len()` and `src.len()`). Returns the number + /// of elements copied. + /// + /// # Example + /// + /// ```rust + /// let mut dst = [0, 0, 0]; + /// let src = [1, 2]; + /// + /// assert!(dst.clone_from_slice(&src) == 2); + /// assert!(dst == [1, 2, 0]); + /// + /// let src2 = [3, 4, 5, 6]; + /// assert!(dst.clone_from_slice(&src2) == 3); + /// assert!(dst == [3, 4, 5]); + /// ``` + #[experimental] + fn clone_from_slice(&mut self, &[T]) -> uint; +} + + +#[unstable = "trait is unstable"] +impl CloneSliceExt for [T] { /// Returns a copy of `v`. #[inline] - fn to_vec(&self) -> Vec where T: Clone { + fn to_vec(&self) -> Vec { let mut vector = Vec::with_capacity(self.len()); vector.push_all(self); vector } + + #[inline] + fn partitioned(&self, f: F) -> (Vec, Vec) where F: FnMut(&T) -> bool { + self.iter().cloned().partition(f) + } + /// Returns an iterator over all permutations of a vector. - fn permutations(&self) -> Permutations where T: Clone { + fn permutations(&self) -> Permutations { Permutations{ swaps: ElementSwaps::new(self.len()), v: self.to_vec(), } } - fn clone_from_slice(&mut self, src: &[T]) -> uint where T: Clone { - core_slice::SliceExt::clone_from_slice(self, src) - } - - #[inline] - fn sort(&mut self) where T: Ord { - self.sort_by(|a, b| a.cmp(b)) + fn clone_from_slice(&mut self, src: &[T]) -> uint { + core_slice::CloneSliceExt::clone_from_slice(self, src) } +} - fn binary_search(&self, x: &T) -> Result where T: Ord { - core_slice::SliceExt::binary_search(self, x) - } +/// Allocating extension methods for slices on Ord values. +#[unstable = "likely to merge with SliceExt"] +pub trait OrdSliceExt for Sized? { + /// Sorts the slice, in place. + /// + /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. + /// + /// # Examples + /// + /// ```rust + /// let mut v = [-5, 4, 1, -3, 2]; + /// + /// v.sort(); + /// assert!(v == [-5, -3, 1, 2, 4]); + /// ``` + #[stable] + fn sort(&mut self); - fn next_permutation(&mut self) -> bool where T: Ord { - core_slice::SliceExt::next_permutation(self) - } + /// Binary search a sorted slice for a given element. + /// + /// If the value is found then `Ok` is returned, containing the + /// index of the matching element; if the value is not found then + /// `Err` is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Example + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1,4]`. + /// + /// ```rust + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let s = s.as_slice(); + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable] + fn binary_search(&self, x: &T) -> Result; - fn prev_permutation(&mut self) -> bool where T: Ord { - core_slice::SliceExt::prev_permutation(self) + /// Deprecated: use `binary_search` instead. + #[deprecated = "use binary_search instead"] + fn binary_search_elem(&self, x: &T) -> Result { + self.binary_search(x) } - fn position_elem(&self, t: &T) -> Option where T: PartialEq { - core_slice::SliceExt::position_elem(self, t) - } + /// Mutates the slice to the next lexicographic permutation. + /// + /// Returns `true` if successful and `false` if the slice is at the + /// last-ordered permutation. + /// + /// # Example + /// + /// ```rust + /// let v: &mut [_] = &mut [0, 1, 2]; + /// v.next_permutation(); + /// let b: &mut [_] = &mut [0, 2, 1]; + /// assert!(v == b); + /// v.next_permutation(); + /// let b: &mut [_] = &mut [1, 0, 2]; + /// assert!(v == b); + /// ``` + #[unstable = "uncertain if this merits inclusion in std"] + fn next_permutation(&mut self) -> bool; - fn rposition_elem(&self, t: &T) -> Option where T: PartialEq { - core_slice::SliceExt::rposition_elem(self, t) - } + /// Mutates the slice to the previous lexicographic permutation. + /// + /// Returns `true` if successful and `false` if the slice is at the + /// first-ordered permutation. + /// + /// # Example + /// + /// ```rust + /// let v: &mut [_] = &mut [1, 0, 2]; + /// v.prev_permutation(); + /// let b: &mut [_] = &mut [0, 2, 1]; + /// assert!(v == b); + /// v.prev_permutation(); + /// let b: &mut [_] = &mut [0, 1, 2]; + /// assert!(v == b); + /// ``` + #[unstable = "uncertain if this merits inclusion in std"] + fn prev_permutation(&mut self) -> bool; +} - fn contains(&self, x: &T) -> bool where T: PartialEq { - core_slice::SliceExt::contains(self, x) +#[unstable = "trait is unstable"] +impl OrdSliceExt for [T] { + #[inline] + fn sort(&mut self) { + self.sort_by(|a, b| a.cmp(b)) } - fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - core_slice::SliceExt::starts_with(self, needle) + fn binary_search(&self, x: &T) -> Result { + core_slice::OrdSliceExt::binary_search(self, x) } - fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - core_slice::SliceExt::ends_with(self, needle) + fn next_permutation(&mut self) -> bool { + core_slice::OrdSliceExt::next_permutation(self) } - fn into_vec(mut self: Box) -> Vec { - unsafe { - let xs = Vec::from_raw_parts(self.as_mut_ptr(), self.len(), self.len()); - mem::forget(self); - xs - } + fn prev_permutation(&mut self) -> bool { + core_slice::OrdSliceExt::prev_permutation(self) } } -//////////////////////////////////////////////////////////////////////////////// -// Extension traits for slices over specifc kinds of data -//////////////////////////////////////////////////////////////////////////////// #[unstable = "U should be an associated type"] /// An extension trait for concatenating slices pub trait SliceConcatExt for Sized? { @@ -994,10 +1007,20 @@ pub trait SliceConcatExt for Sized? { #[stable] fn concat(&self) -> U; + #[deprecated = "renamed to concat"] + fn concat_vec(&self) -> U { + self.concat() + } + /// Flattens a slice of `T` into a single value `U`, placing a /// given seperator between each. #[stable] fn connect(&self, sep: &T) -> U; + + #[deprecated = "renamed to connect"] + fn connect_vec(&self, sep: &T) -> U { + self.connect(sep) + } } impl> SliceConcatExt> for [V] { @@ -1033,7 +1056,7 @@ fn connect(&self, sep: &T) -> Vec { /// The last generated swap is always (0, 1), and it returns the /// sequence to its initial order. #[experimental] -#[derive(Clone)] +#[deriving(Clone)] pub struct ElementSwaps { sdir: Vec, /// If `true`, emit the last swap that returns the sequence to initial @@ -1080,19 +1103,17 @@ fn to_owned(&self) -> Vec { self.to_vec() } // Iterators //////////////////////////////////////////////////////////////////////////////// -#[derive(Copy, Clone)] +#[deriving(Copy, Clone)] enum Direction { Pos, Neg } /// An `Index` and `Direction` together. -#[derive(Copy, Clone)] +#[deriving(Copy, Clone)] struct SizeDirection { size: uint, dir: Direction, } -impl Iterator for ElementSwaps { - type Item = (uint, uint); - +impl Iterator<(uint, uint)> for ElementSwaps { #[inline] fn next(&mut self) -> Option<(uint, uint)> { fn new_pos(i: uint, s: Direction) -> uint { @@ -1159,9 +1180,7 @@ pub struct Permutations { } #[unstable = "trait is unstable"] -impl Iterator for Permutations { - type Item = Vec; - +impl Iterator> for Permutations { #[inline] fn next(&mut self) -> Option> { match self.swaps.next() { @@ -1388,12 +1407,21 @@ unsafe fn step(ptr: &mut *mut T) -> *mut T { } } +/// Deprecated, unsafe operations +#[deprecated] +pub mod raw { + pub use core::slice::raw::{buf_as_slice, mut_buf_as_slice}; + pub use core::slice::raw::{shift_ptr, pop_ptr}; +} + #[cfg(test)] mod tests { + use std::boxed::Box; use prelude::{Some, None, range, Vec, ToString, Clone, Greater, Less, Equal}; - use prelude::{SliceExt, Iterator, IteratorExt}; - use prelude::AsSlice; + use prelude::{SliceExt, Iterator, IteratorExt, DoubleEndedIteratorExt}; + use prelude::{OrdSliceExt, CloneSliceExt, PartialEqSliceExt, AsSlice}; use prelude::{RandomAccessIterator, Ord, SliceConcatExt}; + use core::cell::Cell; use core::default::Default; use core::mem; use std::rand::{Rng, thread_rng}; @@ -1407,7 +1435,7 @@ fn is_odd(n: &uint) -> bool { *n % 2u == 1u } #[test] fn test_from_fn() { // Test on-stack from_fn. - let mut v = range(0, 3).map(square).collect::>(); + let mut v = Vec::from_fn(3u, square); { let v = v.as_slice(); assert_eq!(v.len(), 3u); @@ -1417,7 +1445,7 @@ fn test_from_fn() { } // Test on-heap from_fn. - v = range(0, 5).map(square).collect::>(); + v = Vec::from_fn(5u, square); { let v = v.as_slice(); assert_eq!(v.len(), 5u); @@ -1432,7 +1460,7 @@ fn test_from_fn() { #[test] fn test_from_elem() { // Test on-stack from_elem. - let mut v = vec![10u, 10u]; + let mut v = Vec::from_elem(2u, 10u); { let v = v.as_slice(); assert_eq!(v.len(), 2u); @@ -1441,7 +1469,7 @@ fn test_from_elem() { } // Test on-heap from_elem. - v = vec![20u, 20u, 20u, 20u, 20u, 20u]; + v = Vec::from_elem(6u, 20u); { let v = v.as_slice(); assert_eq!(v[0], 20u); @@ -1483,23 +1511,23 @@ fn test_get() { } #[test] - fn test_first() { + fn test_head() { let mut a = vec![]; - assert_eq!(a.as_slice().first(), None); + assert_eq!(a.as_slice().head(), None); a = vec![11i]; - assert_eq!(a.as_slice().first().unwrap(), &11); + assert_eq!(a.as_slice().head().unwrap(), &11); a = vec![11i, 12]; - assert_eq!(a.as_slice().first().unwrap(), &11); + assert_eq!(a.as_slice().head().unwrap(), &11); } #[test] - fn test_first_mut() { + fn test_head_mut() { let mut a = vec![]; - assert_eq!(a.first_mut(), None); + assert_eq!(a.head_mut(), None); a = vec![11i]; - assert_eq!(*a.first_mut().unwrap(), 11); + assert_eq!(*a.head_mut().unwrap(), 11); a = vec![11i, 12]; - assert_eq!(*a.first_mut().unwrap(), 11); + assert_eq!(*a.head_mut().unwrap(), 11); } #[test] @@ -1703,6 +1731,42 @@ fn test_push() { assert_eq!(v.as_slice()[1], 2); } + #[test] + fn test_grow() { + // Test on-stack grow(). + let mut v = vec![]; + v.grow(2u, 1i); + { + let v = v.as_slice(); + assert_eq!(v.len(), 2u); + assert_eq!(v[0], 1); + assert_eq!(v[1], 1); + } + + // Test on-heap grow(). + v.grow(3u, 2i); + { + let v = v.as_slice(); + assert_eq!(v.len(), 5u); + assert_eq!(v[0], 1); + assert_eq!(v[1], 1); + assert_eq!(v[2], 2); + assert_eq!(v[3], 2); + assert_eq!(v[4], 2); + } + } + + #[test] + fn test_grow_fn() { + let mut v = vec![]; + v.grow_fn(3u, square); + let v = v.as_slice(); + assert_eq!(v.len(), 3u); + assert_eq!(v[0], 0u); + assert_eq!(v[1], 1u); + assert_eq!(v[2], 4u); + } + #[test] fn test_truncate() { let mut v = vec![box 6i,box 5,box 4]; @@ -2035,6 +2099,22 @@ fn test_sort_stability() { } } + #[test] + fn test_partition() { + assert_eq!((vec![]).partition(|x: &int| *x < 3), (vec![], vec![])); + assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 4), (vec![1, 2, 3], vec![])); + assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 2), (vec![1], vec![2, 3])); + assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 0), (vec![], vec![1, 2, 3])); + } + + #[test] + fn test_partitioned() { + assert_eq!(([]).partitioned(|x: &int| *x < 3), (vec![], vec![])); + assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 4), (vec![1, 2, 3], vec![])); + assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 2), (vec![1], vec![2, 3])); + assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 0), (vec![], vec![1, 2, 3])); + } + #[test] fn test_concat() { let v: [Vec; 0] = []; @@ -2052,14 +2132,14 @@ fn test_concat() { #[test] fn test_connect() { let v: [Vec; 0] = []; - assert_eq!(v.connect(&0), vec![]); - assert_eq!([vec![1i], vec![2i, 3]].connect(&0), vec![1, 0, 2, 3]); - assert_eq!([vec![1i], vec![2i], vec![3i]].connect(&0), vec![1, 0, 2, 0, 3]); + assert_eq!(v.connect_vec(&0), vec![]); + assert_eq!([vec![1i], vec![2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]); + assert_eq!([vec![1i], vec![2i], vec![3i]].connect_vec(&0), vec![1, 0, 2, 0, 3]); let v: [&[int]; 2] = [&[1], &[2, 3]]; - assert_eq!(v.connect(&0), vec![1, 0, 2, 3]); + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]); let v: [&[int]; 3] = [&[1], &[2], &[3]]; - assert_eq!(v.connect(&0), vec![1, 0, 2, 0, 3]); + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]); } #[test] @@ -2132,6 +2212,55 @@ fn test_slice_2() { assert_eq!(v[1], 3); } + + #[test] + #[should_fail] + fn test_from_fn_fail() { + Vec::from_fn(100, |v| { + if v == 50 { panic!() } + box 0i + }); + } + + #[test] + #[should_fail] + fn test_from_elem_fail() { + + struct S { + f: Cell, + boxes: (Box, Rc) + } + + impl Clone for S { + fn clone(&self) -> S { + self.f.set(self.f.get() + 1); + if self.f.get() == 10 { panic!() } + S { + f: self.f.clone(), + boxes: self.boxes.clone(), + } + } + } + + let s = S { + f: Cell::new(0), + boxes: (box 0, Rc::new(0)), + }; + let _ = Vec::from_elem(100, s); + } + + #[test] + #[should_fail] + fn test_grow_fn_fail() { + let mut v = vec![]; + v.grow_fn(100, |i| { + if i == 50 { + panic!() + } + (box 0i, Rc::new(0i)) + }) + } + #[test] #[should_fail] fn test_permute_fail() { @@ -2549,7 +2678,7 @@ fn test_mut_split_at() { assert!(values == [2, 3, 5, 6, 7]); } - #[derive(Clone, PartialEq)] + #[deriving(Clone, PartialEq)] struct Foo; #[test] @@ -2720,7 +2849,6 @@ mod bench { use prelude::*; use core::mem; use core::ptr; - use core::iter::repeat; use std::rand::{weak_rng, Rng}; use test::{Bencher, black_box}; @@ -2728,7 +2856,7 @@ mod bench { fn iterator(b: &mut Bencher) { // peculiar numbers to stop LLVM from optimising the summation // out. - let v = range(0u, 100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect::>(); + let v = Vec::from_fn(100, |i| i ^ (i << 1) ^ (i >> 1)); b.iter(|| { let mut sum = 0; @@ -2742,7 +2870,7 @@ fn iterator(b: &mut Bencher) { #[bench] fn mut_iterator(b: &mut Bencher) { - let mut v = repeat(0i).take(100).collect::>(); + let mut v = Vec::from_elem(100, 0i); b.iter(|| { let mut i = 0i; @@ -2756,7 +2884,7 @@ fn mut_iterator(b: &mut Bencher) { #[bench] fn concat(b: &mut Bencher) { let xss: Vec> = - range(0, 100u).map(|i| range(0, i).collect()).collect(); + Vec::from_fn(100, |i| range(0u, i).collect()); b.iter(|| { xss.as_slice().concat(); }); @@ -2765,9 +2893,9 @@ fn concat(b: &mut Bencher) { #[bench] fn connect(b: &mut Bencher) { let xss: Vec> = - range(0, 100u).map(|i| range(0, i).collect()).collect(); + Vec::from_fn(100, |i| range(0u, i).collect()); b.iter(|| { - xss.as_slice().connect(&0) + xss.as_slice().connect_vec(&0) }); } @@ -2782,7 +2910,7 @@ fn push(b: &mut Bencher) { #[bench] fn starts_with_same_vector(b: &mut Bencher) { - let vec: Vec = range(0, 100).collect(); + let vec: Vec = Vec::from_fn(100, |i| i); b.iter(|| { vec.as_slice().starts_with(vec.as_slice()) }) @@ -2798,8 +2926,8 @@ fn starts_with_single_element(b: &mut Bencher) { #[bench] fn starts_with_diff_one_element_at_end(b: &mut Bencher) { - let vec: Vec = range(0, 100).collect(); - let mut match_vec: Vec = range(0, 99).collect(); + let vec: Vec = Vec::from_fn(100, |i| i); + let mut match_vec: Vec = Vec::from_fn(99, |i| i); match_vec.push(0); b.iter(|| { vec.as_slice().starts_with(match_vec.as_slice()) @@ -2808,7 +2936,7 @@ fn starts_with_diff_one_element_at_end(b: &mut Bencher) { #[bench] fn ends_with_same_vector(b: &mut Bencher) { - let vec: Vec = range(0, 100).collect(); + let vec: Vec = Vec::from_fn(100, |i| i); b.iter(|| { vec.as_slice().ends_with(vec.as_slice()) }) @@ -2824,8 +2952,8 @@ fn ends_with_single_element(b: &mut Bencher) { #[bench] fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) { - let vec: Vec = range(0, 100).collect(); - let mut match_vec: Vec = range(0, 100).collect(); + let vec: Vec = Vec::from_fn(100, |i| i); + let mut match_vec: Vec = Vec::from_fn(100, |i| i); match_vec.as_mut_slice()[0] = 200; b.iter(|| { vec.as_slice().starts_with(match_vec.as_slice()) @@ -2834,7 +2962,7 @@ fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) { #[bench] fn contains_last_element(b: &mut Bencher) { - let vec: Vec = range(0, 100).collect(); + let vec: Vec = Vec::from_fn(100, |i| i); b.iter(|| { vec.contains(&99u) }) @@ -2843,7 +2971,7 @@ fn contains_last_element(b: &mut Bencher) { #[bench] fn zero_1kb_from_elem(b: &mut Bencher) { b.iter(|| { - repeat(0u8).take(1024).collect::>() + Vec::from_elem(1024, 0u8) }); } @@ -2891,24 +3019,24 @@ fn zero_1kb_mut_iter(b: &mut Bencher) { fn random_inserts(b: &mut Bencher) { let mut rng = weak_rng(); b.iter(|| { - let mut v = repeat((0u, 0u)).take(30).collect::>(); - for _ in range(0u, 100) { - let l = v.len(); - v.insert(rng.gen::() % (l + 1), - (1, 1)); - } - }) + let mut v = Vec::from_elem(30, (0u, 0u)); + for _ in range(0u, 100) { + let l = v.len(); + v.insert(rng.gen::() % (l + 1), + (1, 1)); + } + }) } #[bench] fn random_removes(b: &mut Bencher) { let mut rng = weak_rng(); b.iter(|| { - let mut v = repeat((0u, 0u)).take(130).collect::>(); - for _ in range(0u, 100) { - let l = v.len(); - v.remove(rng.gen::() % l); - } - }) + let mut v = Vec::from_elem(130, (0u, 0u)); + for _ in range(0u, 100) { + let l = v.len(); + v.remove(rng.gen::() % l); + } + }) } #[bench] @@ -2943,7 +3071,7 @@ fn sort_random_large(b: &mut Bencher) { #[bench] fn sort_sorted(b: &mut Bencher) { - let mut v = range(0u, 10000).collect::>(); + let mut v = Vec::from_fn(10000, |i| i); b.iter(|| { v.sort(); }); @@ -2987,7 +3115,7 @@ fn sort_big_random_large(b: &mut Bencher) { #[bench] fn sort_big_sorted(b: &mut Bencher) { - let mut v = range(0, 10000u).map(|i| (i, i, i, i)).collect::>(); + let mut v = Vec::from_fn(10000u, |i| (i, i, i, i)); b.iter(|| { v.sort(); }); diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ed6a957d2ac..ecf17820d2d 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -55,7 +55,7 @@ use self::DecompositionType::*; use core::borrow::{BorrowFrom, ToOwned}; -use core::char::Char; +use core::char::CharExt; use core::clone::Clone; use core::iter::AdditiveIterator; use core::iter::{range, Iterator, IteratorExt}; diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e7451331908..11e6c48cfdb 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -320,30 +320,6 @@ pub unsafe fn from_raw_parts(buf: *mut u8, length: uint, capacity: uint) -> Stri } } - /// Creates a `String` from a null-terminated `*const u8` buffer. - /// - /// This function is unsafe because we dereference memory until we find the - /// NUL character, which is not guaranteed to be present. Additionally, the - /// slice is not checked to see whether it contains valid UTF-8 - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf(buf: *const u8) -> String { - String::from_str(str::from_c_str(buf as *const i8)) - } - - /// Creates a `String` from a `*const u8` buffer of the given length. - /// - /// This function is unsafe because it blindly assumes the validity of the - /// pointer `buf` for `len` bytes of memory. This function will copy the - /// memory from `buf` into a new allocation (owned by the returned - /// `String`). - /// - /// This function is also unsafe because it does not validate that the - /// buffer is valid UTF-8 encoded data. - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String { - String::from_utf8_unchecked(Vec::from_raw_buf(buf, len)) - } - /// Converts a vector of bytes to a new `String` without checking if /// it contains valid UTF-8. This is unsafe because it assumes that /// the UTF-8-ness of the vector has already been validated. @@ -1126,24 +1102,6 @@ fn test_from_utf16_lossy() { String::from_str("\u{FFFD}𐒋\u{FFFD}")); } - #[test] - fn test_from_buf_len() { - unsafe { - let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0]; - assert_eq!(String::from_raw_buf_len(a.as_ptr(), 3), String::from_str("AAA")); - } - } - - #[test] - fn test_from_buf() { - unsafe { - let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; - let b = a.as_ptr(); - let c = String::from_raw_buf(b); - assert_eq!(c, String::from_str("AAAAAAA")); - } - } - #[test] fn test_push_bytes() { let mut s = String::from_str("ABC"); diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index b8f97799c97..e0ed8e27e99 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -25,13 +25,13 @@ //! ``` //! let ys: Vec = vec![]; //! -//! let zs = vec![1i32, 2, 3, 4, 5]; +//! let zs = vec![1, 2, 3, 4, 5]; //! ``` //! //! Push: //! //! ``` -//! let mut xs = vec![1i32, 2]; +//! let mut xs = vec![1, 2]; //! //! xs.push(3); //! ``` @@ -39,7 +39,7 @@ //! And pop: //! //! ``` -//! let mut xs = vec![1i32, 2]; +//! let mut xs = vec![1, 2]; //! //! let two = xs.pop(); //! ``` @@ -71,8 +71,8 @@ /// /// ``` /// let mut vec = Vec::new(); -/// vec.push(1i); -/// vec.push(2i); +/// vec.push(1); +/// vec.push(2); /// /// assert_eq!(vec.len(), 2); /// assert_eq!(vec[0], 1); @@ -80,7 +80,7 @@ /// assert_eq!(vec.pop(), Some(2)); /// assert_eq!(vec.len(), 1); /// -/// vec[0] = 7i; +/// vec[0] = 7; /// assert_eq!(vec[0], 7); /// /// vec.push_all(&[1, 2, 3]); @@ -88,13 +88,13 @@ /// for x in vec.iter() { /// println!("{}", x); /// } -/// assert_eq!(vec, vec![7i, 1, 2, 3]); +/// assert_eq!(vec, vec![7, 1, 2, 3]); /// ``` /// /// The `vec!` macro is provided to make initialization more convenient: /// /// ``` -/// let mut vec = vec![1i, 2i, 3i]; +/// let mut vec = vec![1, 2, 3]; /// vec.push(4); /// assert_eq!(vec, vec![1, 2, 3, 4]); /// ``` @@ -104,9 +104,9 @@ /// ``` /// let mut stack = Vec::new(); /// -/// stack.push(1i); -/// stack.push(2i); -/// stack.push(3i); +/// stack.push(1); +/// stack.push(2); +/// stack.push(3); /// /// loop { /// let top = match stack.pop() { @@ -218,7 +218,7 @@ pub fn with_capacity(capacity: uint) -> Vec { /// use std::mem; /// /// fn main() { - /// let mut v = vec![1i, 2, 3]; + /// let mut v = vec![1, 2, 3]; /// /// // Pull out the various important pieces of information about `v` /// let p = v.as_mut_ptr(); @@ -237,7 +237,7 @@ pub fn with_capacity(capacity: uint) -> Vec { /// /// // Put everything back together into a Vec /// let rebuilt = Vec::from_raw_parts(p, len, cap); - /// assert_eq!(rebuilt, vec![4i, 5i, 6i]); + /// assert_eq!(rebuilt, vec![4, 5, 6]); /// } /// } /// ``` @@ -392,7 +392,7 @@ pub fn into_boxed_slice(mut self) -> Box<[T]> { /// # Examples /// /// ``` - /// let mut vec = vec![1i, 2, 3, 4]; + /// let mut vec = vec![1, 2, 3, 4]; /// vec.truncate(2); /// assert_eq!(vec, vec![1, 2]); /// ``` @@ -416,7 +416,7 @@ pub fn truncate(&mut self, len: uint) { /// ``` /// fn foo(slice: &mut [int]) {} /// - /// let mut vec = vec![1i, 2]; + /// let mut vec = vec![1, 2]; /// foo(vec.as_mut_slice()); /// ``` #[inline] @@ -519,7 +519,7 @@ pub fn swap_remove(&mut self, index: uint) -> T { /// # Examples /// /// ``` - /// let mut vec = vec![1i, 2, 3]; + /// let mut vec = vec![1, 2, 3]; /// vec.insert(1, 4); /// assert_eq!(vec, vec![1, 4, 2, 3]); /// vec.insert(4, 5); @@ -557,7 +557,7 @@ pub fn insert(&mut self, index: uint, element: T) { /// # Examples /// /// ``` - /// let mut v = vec![1i, 2, 3]; + /// let mut v = vec![1, 2, 3]; /// assert_eq!(v.remove(1), 2); /// assert_eq!(v, vec![1, 3]); /// ``` @@ -591,7 +591,7 @@ pub fn remove(&mut self, index: uint) -> T { /// # Examples /// /// ``` - /// let mut vec = vec![1i, 2, 3, 4]; + /// let mut vec = vec![1, 2, 3, 4]; /// vec.retain(|&x| x%2 == 0); /// assert_eq!(vec, vec![2, 4]); /// ``` @@ -624,7 +624,7 @@ pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool { /// # Examples /// /// ```rust - /// let mut vec = vec!(1i, 2); + /// let mut vec = vec!(1, 2); /// vec.push(3); /// assert_eq!(vec, vec!(1, 2, 3)); /// ``` @@ -662,7 +662,7 @@ pub fn push(&mut self, value: T) { /// # Examples /// /// ```rust - /// let mut vec = vec![1i, 2, 3]; + /// let mut vec = vec![1, 2, 3]; /// assert_eq!(vec.pop(), Some(3)); /// assert_eq!(vec, vec![1, 2]); /// ``` @@ -716,7 +716,7 @@ pub fn drain<'a>(&'a mut self) -> Drain<'a, T> { /// # Examples /// /// ``` - /// let mut v = vec![1i, 2, 3]; + /// let mut v = vec![1, 2, 3]; /// /// v.clear(); /// @@ -733,7 +733,7 @@ pub fn clear(&mut self) { /// # Examples /// /// ``` - /// let a = vec![1i, 2, 3]; + /// let a = vec![1, 2, 3]; /// assert_eq!(a.len(), 3); /// ``` #[inline] @@ -748,7 +748,7 @@ pub fn len(&self) -> uint { self.len } /// let mut v = Vec::new(); /// assert!(v.is_empty()); /// - /// v.push(1i); + /// v.push(1); /// assert!(!v.is_empty()); /// ``` #[stable] @@ -965,7 +965,7 @@ impl Vec { /// vec.resize(3, "world"); /// assert_eq!(vec, vec!["hello", "world", "world"]); /// - /// let mut vec = vec![1i, 2, 3, 4]; + /// let mut vec = vec![1, 2, 3, 4]; /// vec.resize(2, 0); /// assert_eq!(vec, vec![1, 2]); /// ``` @@ -988,8 +988,8 @@ pub fn resize(&mut self, new_len: uint, value: T) { /// # Examples /// /// ``` - /// let mut vec = vec![1i]; - /// vec.push_all(&[2i, 3, 4]); + /// let mut vec = vec![1]; + /// vec.push_all(&[2, 3, 4]); /// assert_eq!(vec, vec![1, 2, 3, 4]); /// ``` #[inline] @@ -1021,11 +1021,11 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec = vec![1i, 2, 2, 3, 2]; + /// let mut vec = vec![1, 2, 2, 3, 2]; /// /// vec.dedup(); /// - /// assert_eq!(vec, vec![1i, 2, 3, 2]); + /// assert_eq!(vec, vec![1, 2, 3, 2]); /// ``` #[stable] pub fn dedup(&mut self) { @@ -1190,17 +1190,6 @@ fn hash(&self, state: &mut S) { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[experimental = "waiting on Index stability"] -impl Index for Vec { - #[inline] - fn index<'a>(&'a self, index: &uint) -> &'a T { - &self.as_slice()[*index] - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[experimental = "waiting on Index stability"] impl Index for Vec { type Output = T; @@ -1211,16 +1200,6 @@ fn index<'a>(&'a self, index: &uint) -> &'a T { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IndexMut for Vec { - #[inline] - fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T { - &mut self.as_mut_slice()[*index] - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl IndexMut for Vec { type Output = T; @@ -1399,7 +1378,7 @@ impl AsSlice for Vec { /// ``` /// fn foo(slice: &[int]) {} /// - /// let vec = vec![1i, 2]; + /// let vec = vec![1, 2]; /// foo(vec.as_slice()); /// ``` #[inline] diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index ab6c6b7ca55..cc757b65623 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -517,17 +517,6 @@ fn extend>(&mut self, mut iter: Iter) { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl Index for VecMap { - #[inline] - fn index<'a>(&'a self, i: &uint) -> &'a V { - self.get(i).expect("key not present") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl Index for VecMap { type Output = V; @@ -537,17 +526,6 @@ fn index<'a>(&'a self, i: &uint) -> &'a V { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl IndexMut for VecMap { - #[inline] - fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut V { - self.get_mut(i).expect("key not present") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl IndexMut for VecMap { type Output = V; diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 75feb4d8828..33cb335d756 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -35,7 +35,7 @@ //! //! ```rust //! use std::fmt::Show; -//! use std::any::{Any, AnyRefExt}; +//! use std::any::Any; //! //! // Logger function for any type that implements Show. //! fn log(value: &T) { @@ -102,24 +102,11 @@ fn get_type_id(&self) -> TypeId { TypeId::of::() } // Implemented as three extension traits so that the methods can be generic. /////////////////////////////////////////////////////////////////////////////// -/// Extension methods for a referenced `Any` trait object -#[unstable = "this trait will not be necessary once DST lands, it will be a \ - part of `impl Any`"] -pub trait AnyRefExt<'a> { +impl Any { /// Returns true if the boxed type is the same as `T` #[stable] - fn is(self) -> bool; - - /// Returns some reference to the boxed value if it is of type `T`, or - /// `None` if it isn't. - #[unstable = "naming conventions around acquiring references may change"] - fn downcast_ref(self) -> Option<&'a T>; -} - -#[stable] -impl<'a> AnyRefExt<'a> for &'a Any { #[inline] - fn is(self) -> bool { + pub fn is(&self) -> bool { // Get TypeId of the type this function is instantiated with let t = TypeId::of::(); @@ -130,8 +117,11 @@ fn is(self) -> bool { t == boxed } + /// Returns some reference to the boxed value if it is of type `T`, or + /// `None` if it isn't. + #[unstable = "naming conventions around acquiring references may change"] #[inline] - fn downcast_ref(self) -> Option<&'a T> { + pub fn downcast_ref<'a, T: 'static>(&'a self) -> Option<&'a T> { if self.is::() { unsafe { // Get the raw representation of the trait object @@ -144,22 +134,12 @@ fn downcast_ref(self) -> Option<&'a T> { None } } -} -/// Extension methods for a mutable referenced `Any` trait object -#[unstable = "this trait will not be necessary once DST lands, it will be a \ - part of `impl Any`"] -pub trait AnyMutRefExt<'a> { /// Returns some mutable reference to the boxed value if it is of type `T`, or /// `None` if it isn't. #[unstable = "naming conventions around acquiring references may change"] - fn downcast_mut(self) -> Option<&'a mut T>; -} - -#[stable] -impl<'a> AnyMutRefExt<'a> for &'a mut Any { #[inline] - fn downcast_mut(self) -> Option<&'a mut T> { + pub fn downcast_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> { if self.is::() { unsafe { // Get the raw representation of the trait object diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 0ac0dc396cc..ebc01ae14fc 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -793,7 +793,7 @@ impl AtomicPtr { /// ``` /// use std::sync::atomic::AtomicPtr; /// - /// let ptr = &mut 5i; + /// let ptr = &mut 5; /// let atomic_ptr = AtomicPtr::new(ptr); /// ``` #[inline] @@ -815,7 +815,7 @@ pub fn new(p: *mut T) -> AtomicPtr { /// ``` /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let ptr = &mut 5i; + /// let ptr = &mut 5; /// let some_ptr = AtomicPtr::new(ptr); /// /// let value = some_ptr.load(Ordering::Relaxed); @@ -837,10 +837,10 @@ pub fn load(&self, order: Ordering) -> *mut T { /// ``` /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let ptr = &mut 5i; + /// let ptr = &mut 5; /// let some_ptr = AtomicPtr::new(ptr); /// - /// let other_ptr = &mut 10i; + /// let other_ptr = &mut 10; /// /// some_ptr.store(other_ptr, Ordering::Relaxed); /// ``` @@ -863,10 +863,10 @@ pub fn store(&self, ptr: *mut T, order: Ordering) { /// ``` /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let ptr = &mut 5i; + /// let ptr = &mut 5; /// let some_ptr = AtomicPtr::new(ptr); /// - /// let other_ptr = &mut 10i; + /// let other_ptr = &mut 10; /// /// let value = some_ptr.swap(other_ptr, Ordering::Relaxed); /// ``` @@ -888,11 +888,11 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { /// ``` /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let ptr = &mut 5i; + /// let ptr = &mut 5; /// let some_ptr = AtomicPtr::new(ptr); /// - /// let other_ptr = &mut 10i; - /// let another_ptr = &mut 10i; + /// let other_ptr = &mut 10; + /// let another_ptr = &mut 10; /// /// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed); /// ``` diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 3423e76ea64..291b7f2ece4 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -69,7 +69,7 @@ /// Converts from `u32` to a `char` #[inline] -#[unstable = "pending decisions about costructors for primitives"] +#[stable] pub fn from_u32(i: u32) -> Option { // catch out-of-bounds and surrogates if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { @@ -92,7 +92,7 @@ pub fn from_u32(i: u32) -> Option { /// Panics if given an `radix` > 36. /// #[inline] -#[unstable = "pending decisions about costructors for primitives"] +#[unstable = "pending integer conventions"] pub fn from_digit(num: uint, radix: uint) -> Option { if radix > 36 { panic!("from_digit: radix is too high (maximum 36)"); @@ -111,8 +111,8 @@ pub fn from_digit(num: uint, radix: uint) -> Option { } /// Basic `char` manipulations. -#[experimental = "trait organization may change"] -pub trait Char { +#[stable] +pub trait CharExt { /// Checks if a `char` parses as a numeric digit in the given radix. /// /// Compared to `is_numeric()`, this function only recognizes the characters @@ -126,7 +126,7 @@ pub trait Char { /// # Panics /// /// Panics if given a radix > 36. - #[unstable = "pending error conventions"] + #[unstable = "pending integer conventions"] fn is_digit(self, radix: uint) -> bool; /// Converts a character to the corresponding digit. @@ -140,7 +140,7 @@ pub trait Char { /// # Panics /// /// Panics if given a radix outside the range [0..36]. - #[unstable = "pending error conventions, trait organization"] + #[unstable = "pending integer conventions"] fn to_digit(self, radix: uint) -> Option; /// Returns an iterator that yields the hexadecimal Unicode escape @@ -149,7 +149,7 @@ pub trait Char { /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` /// where `NNNN` is the shortest hexadecimal representation of the code /// point. - #[unstable = "pending error conventions, trait organization"] + #[stable] fn escape_unicode(self) -> EscapeUnicode; /// Returns an iterator that yields the 'default' ASCII and @@ -164,17 +164,17 @@ pub trait Char { /// escaped. /// * Any other chars in the range [0x20,0x7e] are not escaped. /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. - #[unstable = "pending error conventions, trait organization"] + #[stable] fn escape_default(self) -> EscapeDefault; /// Returns the amount of bytes this character would need if encoded in /// UTF-8. - #[unstable = "pending trait organization"] + #[stable] fn len_utf8(self) -> uint; /// Returns the amount of bytes this character would need if encoded in /// UTF-16. - #[unstable = "pending trait organization"] + #[stable] fn len_utf16(self) -> uint; /// Encodes this character as UTF-8 into the provided byte buffer, @@ -182,29 +182,26 @@ pub trait Char { /// /// If the buffer is not large enough, nothing will be written into it /// and a `None` will be returned. - #[unstable = "pending trait organization"] - fn encode_utf8(&self, dst: &mut [u8]) -> Option; + #[stable] + fn encode_utf8(self, dst: &mut [u8]) -> Option; /// Encodes this character as UTF-16 into the provided `u16` buffer, /// and then returns the number of `u16`s written. /// /// If the buffer is not large enough, nothing will be written into it /// and a `None` will be returned. - #[unstable = "pending trait organization"] - fn encode_utf16(&self, dst: &mut [u16]) -> Option; + #[stable] + fn encode_utf16(self, dst: &mut [u16]) -> Option; } -#[experimental = "trait is experimental"] -impl Char for char { - #[unstable = "pending trait organization"] +#[stable] +impl CharExt for char { + #[unstable = "pending integer conventions"] fn is_digit(self, radix: uint) -> bool { - match self.to_digit(radix) { - Some(_) => true, - None => false, - } + self.to_digit(radix).is_some() } - #[unstable = "pending trait organization"] + #[unstable = "pending integer conventions"] fn to_digit(self, radix: uint) -> Option { if radix > 36 { panic!("to_digit: radix is too high (maximum 36)"); @@ -219,12 +216,12 @@ fn to_digit(self, radix: uint) -> Option { else { None } } - #[unstable = "pending error conventions, trait organization"] + #[stable] fn escape_unicode(self) -> EscapeUnicode { EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash } } - #[unstable = "pending error conventions, trait organization"] + #[stable] fn escape_default(self) -> EscapeDefault { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), @@ -240,7 +237,7 @@ fn escape_default(self) -> EscapeDefault { } #[inline] - #[unstable = "pending trait organization"] + #[stable] fn len_utf8(self) -> uint { let code = self as u32; match () { @@ -252,17 +249,17 @@ fn len_utf8(self) -> uint { } #[inline] - #[unstable = "pending trait organization"] + #[stable] fn len_utf16(self) -> uint { let ch = self as u32; if (ch & 0xFFFF_u32) == ch { 1 } else { 2 } } #[inline] - #[unstable = "pending error conventions, trait organization"] - fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> Option { + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf8(self, dst: &mut [u8]) -> Option { // Marked #[inline] to allow llvm optimizing it away - let code = *self as u32; + let code = self as u32; if code < MAX_ONE_B && dst.len() >= 1 { dst[0] = code as u8; Some(1) @@ -287,10 +284,10 @@ fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> Option { } #[inline] - #[unstable = "pending error conventions, trait organization"] - fn encode_utf16(&self, dst: &mut [u16]) -> Option { + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf16(self, dst: &mut [u16]) -> Option { // Marked #[inline] to allow llvm optimizing it away - let mut ch = *self as u32; + let mut ch = self as u32; if (ch & 0xFFFF_u32) == ch && dst.len() >= 1 { // The BMP falls through (assuming non-surrogate, as it should) dst[0] = ch as u16; @@ -310,6 +307,7 @@ fn encode_utf16(&self, dst: &mut [u16]) -> Option { /// An iterator over the characters that represent a `char`, as escaped by /// Rust's unicode escaping rules. #[derive(Clone)] +#[stable] pub struct EscapeUnicode { c: char, state: EscapeUnicodeState @@ -325,6 +323,7 @@ enum EscapeUnicodeState { Done, } +#[stable] impl Iterator for EscapeUnicode { type Item = char; @@ -370,6 +369,7 @@ fn next(&mut self) -> Option { /// An iterator over the characters that represent a `char`, escaped /// for maximum portability. #[derive(Clone)] +#[stable] pub struct EscapeDefault { state: EscapeDefaultState } @@ -382,6 +382,7 @@ enum EscapeDefaultState { Unicode(EscapeUnicode), } +#[stable] impl Iterator for EscapeDefault { type Item = char; diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 9e62226220c..f63242b4f85 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -15,7 +15,7 @@ pub use self::SignFormat::*; use char; -use char::Char; +use char::CharExt; use fmt; use iter::{IteratorExt, range}; use num::{cast, Float, ToPrimitive}; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f49f87ff329..102836f8d30 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -388,7 +388,7 @@ pub fn pad_integral(&mut self, prefix: &str, buf: &str) -> Result { - use char::Char; + use char::CharExt; use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad}; let mut width = buf.len(); @@ -504,7 +504,7 @@ pub fn pad(&mut self, s: &str) -> Result { fn with_padding(&mut self, padding: uint, default: rt::Alignment, f: F) -> Result where F: FnOnce(&mut Formatter) -> Result, { - use char::Char; + use char::CharExt; let align = match self.align { rt::AlignUnknown => default, _ => self.align @@ -613,7 +613,7 @@ fn fmt(&self, f: &mut Formatter) -> Result { impl Show for char { fn fmt(&self, f: &mut Formatter) -> Result { - use char::Char; + use char::CharExt; let mut utf8 = [0u8; 4]; let amt = self.encode_utf8(&mut utf8).unwrap_or(0); diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index e0724fc2da5..c9646bb3d35 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -145,7 +145,7 @@ fn digit(&self, x: u8) -> u8 { /// /// ``` /// use std::fmt::radix; -/// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string()); +/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string()); /// ``` #[unstable = "may be renamed or move to a different module"] pub fn radix(x: T, base: u8) -> RadixFmt { diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 62bfa381c44..e7e32cec177 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -33,7 +33,7 @@ //! translated to the `loop` below. //! //! ```rust -//! let values = vec![1i, 2, 3]; +//! let values = vec![1, 2, 3]; //! //! // "Syntactical sugar" taking advantage of an iterator //! for &x in values.iter() { @@ -118,8 +118,8 @@ pub trait IteratorExt: Iterator + Sized { /// # Example /// /// ```rust - /// let a = [0i]; - /// let b = [1i]; + /// let a = [0]; + /// let b = [1]; /// let mut it = a.iter().chain(b.iter()); /// assert_eq!(it.next().unwrap(), &0); /// assert_eq!(it.next().unwrap(), &1); @@ -141,10 +141,10 @@ fn chain(self, other: U) -> Chain where /// # Example /// /// ```rust - /// let a = [0i]; - /// let b = [1i]; + /// let a = [0]; + /// let b = [1]; /// let mut it = a.iter().zip(b.iter()); - /// let (x0, x1) = (0i, 1i); + /// let (x0, x1) = (0, 1); /// assert_eq!(it.next().unwrap(), (&x0, &x1)); /// assert!(it.next().is_none()); /// ``` @@ -162,7 +162,7 @@ fn zip(self, other: U) -> Zip where /// # Example /// /// ```rust - /// let a = [1i, 2]; + /// let a = [1, 2]; /// let mut it = a.iter().map(|&x| 2 * x); /// assert_eq!(it.next().unwrap(), 2); /// assert_eq!(it.next().unwrap(), 4); @@ -183,7 +183,7 @@ fn map(self, f: F) -> Map< ::Item, B, Self, F> where /// # Example /// /// ```rust - /// let a = [1i, 2]; + /// let a = [1, 2]; /// let mut it = a.iter().filter(|&x| *x > 1); /// assert_eq!(it.next().unwrap(), &2); /// assert!(it.next().is_none()); @@ -203,7 +203,7 @@ fn filter

(self, predicate: P) -> Filter< ::Item, Self, P> w /// # Example /// /// ```rust - /// let a = [1i, 2]; + /// let a = [1, 2]; /// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None}); /// assert_eq!(it.next().unwrap(), 4); /// assert!(it.next().is_none()); @@ -222,9 +222,9 @@ fn filter_map(self, f: F) -> FilterMap< ::Item, B, Self, /// # Example /// /// ```rust - /// let a = [100i, 200]; + /// let a = [100, 200]; /// let mut it = a.iter().enumerate(); - /// let (x100, x200) = (100i, 200i); + /// let (x100, x200) = (100, 200); /// assert_eq!(it.next().unwrap(), (0, &x100)); /// assert_eq!(it.next().unwrap(), (1, &x200)); /// assert!(it.next().is_none()); @@ -241,7 +241,7 @@ fn enumerate(self) -> Enumerate { /// # Example /// /// ```rust - /// let xs = [100i, 200, 300]; + /// let xs = [100, 200, 300]; /// let mut it = xs.iter().map(|x| *x).peekable(); /// assert_eq!(*it.peek().unwrap(), 100); /// assert_eq!(it.next().unwrap(), 100); @@ -265,7 +265,7 @@ fn peekable(self) -> Peekable< ::Item, Self> { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 2, 1]; + /// let a = [1, 2, 3, 2, 1]; /// let mut it = a.iter().skip_while(|&a| *a < 3); /// assert_eq!(it.next().unwrap(), &3); /// assert_eq!(it.next().unwrap(), &2); @@ -287,7 +287,7 @@ fn skip_while

(self, predicate: P) -> SkipWhile< ::Item, Sel /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 2, 1]; + /// let a = [1, 2, 3, 2, 1]; /// let mut it = a.iter().take_while(|&a| *a < 3); /// assert_eq!(it.next().unwrap(), &1); /// assert_eq!(it.next().unwrap(), &2); @@ -307,7 +307,7 @@ fn take_while

(self, predicate: P) -> TakeWhile< ::Item, Sel /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().skip(3); /// assert_eq!(it.next().unwrap(), &4); /// assert_eq!(it.next().unwrap(), &5); @@ -325,7 +325,7 @@ fn skip(self, n: uint) -> Skip { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().take(3); /// assert_eq!(it.next().unwrap(), &1); /// assert_eq!(it.next().unwrap(), &2); @@ -346,7 +346,7 @@ fn take(self, n: uint) -> Take { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().scan(1, |fac, &x| { /// *fac = *fac * x; /// Some(*fac) @@ -419,9 +419,9 @@ fn flat_map(self, f: F) -> FlatMap< ::Item, B, Self, /// } /// sum /// } - /// let x = vec![1i,2,3,7,8,9]; + /// let x = vec![1,2,3,7,8,9]; /// assert_eq!(process(x.into_iter()), 6); - /// let x = vec![1i,2,3]; + /// let x = vec![1,2,3]; /// assert_eq!(process(x.into_iter()), 1006); /// ``` #[inline] @@ -482,7 +482,7 @@ fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let b: Vec = a.iter().map(|&x| x).collect(); /// assert!(a.as_slice() == b.as_slice()); /// ``` @@ -498,7 +498,7 @@ fn collect::Item>>(self) -> B { /// do not. /// /// ``` - /// let vec = vec![1i, 2i, 3i, 4i]; + /// let vec = vec![1, 2, 3, 4]; /// let (even, odd): (Vec, Vec) = vec.into_iter().partition(|&n| n % 2 == 0); /// assert_eq!(even, vec![2, 4]); /// assert_eq!(odd, vec![1, 3]); @@ -528,7 +528,7 @@ fn partition(mut self, mut f: F) -> (B, B) where /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert!(it.nth(2).unwrap() == &3); /// assert!(it.nth(2) == None); @@ -549,7 +549,7 @@ fn nth(&mut self, mut n: uint) -> Option< ::Item> { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().last().unwrap() == &5); /// ``` #[inline] @@ -566,7 +566,7 @@ fn last(mut self) -> Option< ::Item> { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().fold(0, |a, &b| a + b) == 15); /// ``` #[inline] @@ -586,7 +586,7 @@ fn fold(mut self, init: B, mut f: F) -> B where /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert!(it.count() == 5); /// ``` @@ -601,7 +601,7 @@ fn count(self) -> uint { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().all(|x| *x > 0)); /// assert!(!a.iter().all(|x| *x > 2)); /// ``` @@ -618,7 +618,7 @@ fn all(mut self, mut f: F) -> bool where F: FnMut(::Item) - /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert!(it.any(|x| *x == 3)); /// assert!(!it.any(|x| *x == 3)); @@ -668,7 +668,7 @@ fn position

"));
+        try!(write!(fmt, "
"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt, "{0:1$}\n", i, cols));
+            try!(write!(fmt, "{0:1$}\n", i, cols));
         }
         try!(write!(fmt, "
")); try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None))); diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 9d4f341a30e..a5a48254141 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -157,6 +157,7 @@ nav.sub { left: 0; top: 0; min-height: 100%; + z-index: -1; } .content, nav { max-width: 960px; } @@ -217,10 +218,18 @@ nav.sub { overflow: auto; padding-left: 0; } -.content pre.line-numbers { float: left; border: none; } -.line-numbers span { color: #c67e2d; } +.content pre.line-numbers { + float: left; + border: none; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers span { color: #c67e2d; cursor: pointer; } .line-numbers .line-highlighted { - background-color: #f6fdb0; + background-color: #f6fdb0 !important; } .content .highlighted { @@ -470,6 +479,7 @@ h1 .stability { .summary.Unmarked { background-color: #BBBBBB; } :target { background: #FDFFD3; } +.line-numbers :target { background-color: transparent; } /* Code highlighting */ pre.rust .kw { color: #8959A8; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 978af31cdc6..2d575c226c5 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -50,7 +50,7 @@ resizeShortBlocks(); $(window).on('resize', resizeShortBlocks); - function highlightSourceLines() { + function highlightSourceLines(ev) { var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { from = parseInt(match[1], 10); @@ -59,14 +59,14 @@ if ($('#' + from).length === 0) { return; } - $('#' + from)[0].scrollIntoView(); + if (ev === null) $('#' + from)[0].scrollIntoView(); $('.line-numbers span').removeClass('line-highlighted'); for (i = from; i <= to; ++i) { $('#' + i).addClass('line-highlighted'); } } } - highlightSourceLines(); + highlightSourceLines(null); $(window).on('hashchange', highlightSourceLines); $(document).on('keyup', function(e) { @@ -778,4 +778,35 @@ $("#main > .docblock").before(wrapper); }); + $('pre.line-numbers').on('click', 'span', function() { + var prev_id = 0; + + function set_fragment(name) { + if (history.replaceState) { + history.replaceState(null, null, '#' + name); + $(window).trigger('hashchange'); + } else { + location.replace('#' + name); + } + } + + return function(ev) { + var cur_id = parseInt(ev.target.id); + + if (ev.shiftKey && prev_id) { + if (prev_id > cur_id) { + var tmp = prev_id; + prev_id = cur_id; + cur_id = tmp; + } + + set_fragment(prev_id + '-' + cur_id); + } else { + prev_id = cur_id; + + set_fragment(cur_id); + } + }; + }()); + }()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 125bc21d79d..106fe452f46 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -38,7 +38,6 @@ use std::cell::RefCell; use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::io::File; use std::io; use std::rc::Rc; @@ -321,10 +320,9 @@ fn parse_externs(matches: &getopts::Matches) -> Result { return Err("--extern value must be of the format `foo=bar`".to_string()); } }; - let locs = match externs.entry(name.to_string()) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let name = name.to_string(); + let locs = externs.entry(&name).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); locs.push(location.to_string()); } Ok(externs) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e71711aa8d6..c98ec97ab87 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -337,9 +337,10 @@ pub fn visit_item(&mut self, item: &ast::Item, }; om.traits.push(t); }, - ast::ItemImpl(unsafety, ref gen, ref tr, ref ty, ref items) => { + ast::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => { let i = Impl { unsafety: unsafety, + polarity: polarity, generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index f2d79b13346..7ba329c518e 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -19,11 +19,9 @@ use collections::enum_set::{EnumSet, CLike}; impl< - E, - S: Encoder, - T: Encodable -> Encodable for DList { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -33,8 +31,8 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } -impl,T:Decodable> Decodable for DList { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for DList { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut list = DList::new(); for i in range(0u, len) { @@ -45,12 +43,8 @@ fn decode(d: &mut D) -> Result, E> { } } -impl< - E, - S: Encoder, - T: Encodable -> Encodable for RingBuf { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -60,8 +54,8 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } -impl,T:Decodable> Decodable for RingBuf { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RingBuf { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut deque: RingBuf = RingBuf::new(); for i in range(0u, len) { @@ -73,12 +67,10 @@ fn decode(d: &mut D) -> Result, E> { } impl< - E, - S: Encoder, - K: Encodable + PartialEq + Ord, - V: Encodable + PartialEq -> Encodable for BTreeMap { - fn encode(&self, e: &mut S) -> Result<(), E> { + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -92,12 +84,10 @@ fn encode(&self, e: &mut S) -> Result<(), E> { } impl< - E, - D: Decoder, - K: Decodable + PartialEq + Ord, - V: Decodable + PartialEq -> Decodable for BTreeMap { - fn decode(d: &mut D) -> Result, E> { + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = BTreeMap::new(); for i in range(0u, len) { @@ -111,11 +101,9 @@ fn decode(d: &mut D) -> Result, E> { } impl< - E, - S: Encoder, - T: Encodable + PartialEq + Ord -> Encodable for BTreeSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -128,11 +116,9 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } impl< - E, - D: Decoder, - T: Decodable + PartialEq + Ord -> Decodable for BTreeSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = BTreeSet::new(); for i in range(0u, len) { @@ -144,11 +130,9 @@ fn decode(d: &mut D) -> Result, E> { } impl< - E, - S: Encoder, - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let mut bits = 0; for item in self.iter() { bits |= item.to_uint(); @@ -158,11 +142,9 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } impl< - E, - D: Decoder, - T: Decodable + CLike -> Decodable for EnumSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, D::Error> { let bits = try!(d.read_uint()); let mut set = EnumSet::new(); for bit in range(0, uint::BITS) { @@ -175,14 +157,12 @@ fn decode(d: &mut D) -> Result, E> { } impl< - E, - S: Encoder, - K: Encodable + Hash + Eq, - V: Encodable, + K: Encodable + Hash + Eq, + V: Encodable, X, H: Hasher -> Encodable for HashMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -196,14 +176,12 @@ fn encode(&self, e: &mut S) -> Result<(), E> { } impl< - E, - D: Decoder, - K: Decodable + Hash + Eq, - V: Decodable, + K: Decodable + Hash + Eq, + V: Decodable, S, H: Hasher + Default -> Decodable for HashMap { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let hasher = Default::default(); let mut map = HashMap::with_capacity_and_hasher(len, hasher); @@ -218,13 +196,11 @@ fn decode(d: &mut D) -> Result, E> { } impl< - E, - S: Encoder, - T: Encodable + Hash + Eq, + T: Encodable + Hash + Eq, X, H: Hasher -> Encodable for HashSet { - fn encode(&self, s: &mut S) -> Result<(), E> { +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -237,13 +213,11 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } impl< - E, - D: Decoder, - T: Decodable + Hash + Eq, + T: Decodable + Hash + Eq, S, H: Hasher + Default -> Decodable for HashSet { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); for i in range(0u, len) { @@ -254,12 +228,8 @@ fn decode(d: &mut D) -> Result, E> { } } -impl< - E, - S: Encoder, - V: Encodable -> Encodable for VecMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { try!(e.emit_map_elt_key(i, |e| key.encode(e))); @@ -270,12 +240,8 @@ fn encode(&self, e: &mut S) -> Result<(), E> { } } -impl< - E, - D: Decoder, - V: Decodable -> Decodable for VecMap { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for VecMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = VecMap::new(); for i in range(0u, len) { diff --git a/src/libserialize/collection_impls_stage0.rs b/src/libserialize/collection_impls_stage0.rs new file mode 100644 index 00000000000..f2d79b13346 --- /dev/null +++ b/src/libserialize/collection_impls_stage0.rs @@ -0,0 +1,289 @@ +// Copyright 2014 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 serialization for structures found in libcollections + +use std::uint; +use std::default::Default; +use std::hash::{Hash, Hasher}; + +use {Decodable, Encodable, Decoder, Encoder}; +use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; +use collections::enum_set::{EnumSet, CLike}; + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for DList { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut list = DList::new(); + for i in range(0u, len) { + list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(list) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for RingBuf { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut deque: RingBuf = RingBuf::new(); + for i in range(0u, len) { + deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(deque) + }) + } +} + +impl< + E, + S: Encoder, + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = BTreeMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = BTreeSet::new(); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + let mut bits = 0; + for item in self.iter() { + bits |= item.to_uint(); + } + s.emit_uint(bits) + } +} + +impl< + E, + D: Decoder, + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, E> { + let bits = try!(d.read_uint()); + let mut set = EnumSet::new(); + for bit in range(0, uint::BITS) { + if bits & (1 << bit) != 0 { + set.insert(CLike::from_uint(1 << bit)); + } + } + Ok(set) + } +} + +impl< + E, + S: Encoder, + K: Encodable + Hash + Eq, + V: Encodable, + X, + H: Hasher +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + Hash + Eq, + V: Decodable, + S, + H: Hasher + Default +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let hasher = Default::default(); + let mut map = HashMap::with_capacity_and_hasher(len, hasher); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + Hash + Eq, + X, + H: Hasher +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + Hash + Eq, + S, + H: Hasher + Default +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + V: Encodable +> Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + for (i, (key, val)) in self.iter().enumerate() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + V: Decodable +> Decodable for VecMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = VecMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index e31d8157332..bd4cb1884a6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -300,7 +300,7 @@ pub fn error_str(error: ErrorCode) -> &'static str { } /// Shortcut function to decode a JSON `&str` into an object -pub fn decode>(s: &str) -> DecodeResult { +pub fn decode(s: &str) -> DecodeResult { let json = match from_str(s) { Ok(x) => x, Err(e) => return Err(ParseError(e)) @@ -311,9 +311,7 @@ pub fn decode>(s: &str) -> DecodeResult } /// Shortcut function to encode a `T` into a JSON `String` -pub fn encode(object: &T) -> string::String - where T: for<'a> Encodable, fmt::Error> -{ +pub fn encode(object: &T) -> string::String { let mut s = String::new(); { let mut encoder = Encoder::new(&mut s); @@ -444,7 +442,9 @@ pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { } } -impl<'a> ::Encoder for Encoder<'a> { +impl<'a> ::Encoder for Encoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -664,7 +664,9 @@ pub fn set_indent(&mut self, indent: uint) { } } -impl<'a> ::Encoder for PrettyEncoder<'a> { +impl<'a> ::Encoder for PrettyEncoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -909,8 +911,8 @@ fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where } } -impl, S> Encodable for Json { - fn encode(&self, e: &mut E) -> Result<(), S> { +impl Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { match *self { Json::I64(v) => v.encode(e), Json::U64(v) => v.encode(e), @@ -1123,15 +1125,6 @@ pub fn as_null(&self) -> Option<()> { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a> ops::Index<&'a str, Json> for Json { - fn index(&self, idx: & &str) -> &Json { - self.find(*idx).unwrap() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl<'a> ops::Index<&'a str> for Json { type Output = Json; @@ -1140,18 +1133,6 @@ fn index(&self, idx: & &str) -> &Json { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl ops::Index for Json { - fn index<'a>(&'a self, idx: &uint) -> &'a Json { - match self { - &Json::Array(ref v) => v.index(idx), - _ => panic!("can only index Json with uint if it is an array") - } - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl ops::Index for Json { type Output = Json; @@ -2062,7 +2043,9 @@ fn $name(&mut self) -> DecodeResult<$ty> { } } -impl ::Decoder for Decoder { +impl ::Decoder for Decoder { + type Error = DecoderError; + fn read_nil(&mut self) -> DecodeResult<()> { expect!(self.pop(), Null) } @@ -2474,9 +2457,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } -impl<'a, T> fmt::Show for AsJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -2493,9 +2474,7 @@ pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> { } } -impl<'a, T> fmt::Show for AsPrettyJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsPrettyJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -3155,8 +3134,7 @@ enum DecodeEnum { A(f64), B(string::String) } - fn check_err>(to_parse: &'static str, - expected: DecoderError) { + fn check_err(to_parse: &'static str, expected: DecoderError) { let res: DecodeResult = match from_str(to_parse) { Err(e) => Err(ParseError(e)), Ok(json) => Decodable::decode(&mut Decoder::new(json)) diff --git a/src/libserialize/json_stage0.rs b/src/libserialize/json_stage0.rs new file mode 100644 index 00000000000..9932f8d0306 --- /dev/null +++ b/src/libserialize/json_stage0.rs @@ -0,0 +1,3862 @@ +// Copyright 2012-2014 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 JSON serialization library +// Copyright (c) 2011 Google Inc. + +#![forbid(non_camel_case_types)] +#![allow(missing_docs)] + +//! JSON parsing and serialization +//! +//! # What is JSON? +//! +//! JSON (JavaScript Object Notation) is a way to write data in Javascript. +//! Like XML, it allows to encode structured data in a text format that can be easily read by humans +//! Its simple syntax and native compatibility with JavaScript have made it a widely used format. +//! +//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details): +//! +//! * `Boolean`: equivalent to rust's `bool` +//! * `Number`: equivalent to rust's `f64` +//! * `String`: equivalent to rust's `String` +//! * `Array`: equivalent to rust's `Vec`, but also allowing objects of different types in the +//! same array +//! * `Object`: equivalent to rust's `BTreeMap` +//! * `Null` +//! +//! An object is a series of string keys mapping to values, in `"key": value` format. +//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }). +//! A simple JSON document encoding a person, his/her age, address and phone numbers could look like +//! +//! ```ignore +//! { +//! "FirstName": "John", +//! "LastName": "Doe", +//! "Age": 43, +//! "Address": { +//! "Street": "Downing Street 10", +//! "City": "London", +//! "Country": "Great Britain" +//! }, +//! "PhoneNumbers": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! } +//! ``` +//! +//! # Rust Type-based Encoding and Decoding +//! +//! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via +//! the serialization API. +//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait. +//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait. +//! The Rust compiler provides an annotation to automatically generate the code for these traits: +//! `#[derive(RustcDecodable, RustcEncodable)]` +//! +//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects. +//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value. +//! A `json::Json` value can be encoded as a string or buffer using the functions described above. +//! You can also use the `json::Encoder` object, which implements the `Encoder` trait. +//! +//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory. +//! +//! # Examples of use +//! +//! ## Using Autoserialization +//! +//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the +//! serialization API, using the derived serialization code. +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json; +//! +//! // Automatically generate `Decodable` and `Encodable` trait implementations +//! #[derive(RustcDecodable, RustcEncodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! fn main() { +//! let object = TestStruct { +//! data_int: 1, +//! data_str: "homura".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! +//! // Serialize using `json::encode` +//! let encoded = json::encode(&object); +//! +//! // Deserialize using `json::decode` +//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap(); +//! } +//! ``` +//! +//! ## Using the `ToJson` trait +//! +//! The examples above use the `ToJson` trait to generate the JSON string, which is required +//! for custom mappings. +//! +//! ### Simple example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json::{mod, ToJson, Json}; +//! +//! // A custom data structure +//! struct ComplexNum { +//! a: f64, +//! b: f64, +//! } +//! +//! // JSON value representation +//! impl ToJson for ComplexNum { +//! fn to_json(&self) -> Json { +//! Json::String(format!("{}+{}i", self.a, self.b)) +//! } +//! } +//! +//! // Only generate `RustcEncodable` trait implementation +//! #[derive(Encodable)] +//! pub struct ComplexNumRecord { +//! uid: u8, +//! dsc: String, +//! val: Json, +//! } +//! +//! fn main() { +//! let num = ComplexNum { a: 0.0001, b: 12.539 }; +//! let data: String = json::encode(&ComplexNumRecord{ +//! uid: 1, +//! dsc: "test".to_string(), +//! val: num.to_json(), +//! }); +//! println!("data: {}", data); +//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"}; +//! } +//! ``` +//! +//! ### Verbose example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use std::collections::BTreeMap; +//! use serialize::json::{mod, Json, ToJson}; +//! +//! // Only generate `Decodable` trait implementation +//! #[derive(Decodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! // Specify encoding method manually +//! impl ToJson for TestStruct { +//! fn to_json(&self) -> Json { +//! let mut d = BTreeMap::new(); +//! // All standard types implement `to_json()`, so use it +//! d.insert("data_int".to_string(), self.data_int.to_json()); +//! d.insert("data_str".to_string(), self.data_str.to_json()); +//! d.insert("data_vector".to_string(), self.data_vector.to_json()); +//! Json::Object(d) +//! } +//! } +//! +//! fn main() { +//! // Serialize using `ToJson` +//! let input_data = TestStruct { +//! data_int: 1, +//! data_str: "madoka".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! let json_obj: Json = input_data.to_json(); +//! let json_str: String = json_obj.to_string(); +//! +//! // Deserialize like before +//! let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap(); +//! } +//! ``` + +use self::JsonEvent::*; +use self::StackElement::*; +use self::ErrorCode::*; +use self::ParserError::*; +use self::DecoderError::*; +use self::ParserState::*; +use self::InternalStackElement::*; + +use std; +use std::collections::{HashMap, BTreeMap}; +use std::{char, f64, fmt, io, num, str}; +use std::mem::{swap, transmute}; +use std::num::{Float, Int}; +use std::num::FpCategory as Fp; +use std::str::FromStr; +use std::string; +use std::ops; +use unicode::str as unicode_str; +use unicode::str::Utf16Item; + +use Encodable; + +/// Represents a json value +#[derive(Clone, PartialEq, PartialOrd)] +pub enum Json { + I64(i64), + U64(u64), + F64(f64), + String(string::String), + Boolean(bool), + Array(self::Array), + Object(self::Object), + Null, +} + +pub type Array = Vec; +pub type Object = BTreeMap; + +pub struct PrettyJson<'a> { inner: &'a Json } + +pub struct AsJson<'a, T: 'a> { inner: &'a T } +pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option } + +/// The errors that can arise while parsing a JSON stream. +#[derive(Clone, Copy, PartialEq)] +pub enum ErrorCode { + InvalidSyntax, + InvalidNumber, + EOFWhileParsingObject, + EOFWhileParsingArray, + EOFWhileParsingValue, + EOFWhileParsingString, + KeyMustBeAString, + ExpectedColon, + TrailingCharacters, + TrailingComma, + InvalidEscape, + InvalidUnicodeCodePoint, + LoneLeadingSurrogateInHexEscape, + UnexpectedEndOfHexEscape, + UnrecognizedHex, + NotFourDigit, + NotUtf8, +} + +#[derive(Clone, Copy, PartialEq, Show)] +pub enum ParserError { + /// msg, line, col + SyntaxError(ErrorCode, uint, uint), + IoError(io::IoErrorKind, &'static str), +} + +// Builder and Parser have the same errors. +pub type BuilderError = ParserError; + +#[derive(Clone, PartialEq, Show)] +pub enum DecoderError { + ParseError(ParserError), + ExpectedError(string::String, string::String), + MissingFieldError(string::String), + UnknownVariantError(string::String), + ApplicationError(string::String) +} + +/// Returns a readable error string for a given error code. +pub fn error_str(error: ErrorCode) -> &'static str { + match error { + InvalidSyntax => "invalid syntax", + InvalidNumber => "invalid number", + EOFWhileParsingObject => "EOF While parsing object", + EOFWhileParsingArray => "EOF While parsing array", + EOFWhileParsingValue => "EOF While parsing value", + EOFWhileParsingString => "EOF While parsing string", + KeyMustBeAString => "key must be a string", + ExpectedColon => "expected `:`", + TrailingCharacters => "trailing characters", + TrailingComma => "trailing comma", + InvalidEscape => "invalid escape", + UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)", + NotFourDigit => "invalid \\u{ esc}ape (not four digits)", + NotUtf8 => "contents not utf-8", + InvalidUnicodeCodePoint => "invalid Unicode code point", + LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape", + UnexpectedEndOfHexEscape => "unexpected end of hex escape", + } +} + +/// Shortcut function to decode a JSON `&str` into an object +pub fn decode>(s: &str) -> DecodeResult { + let json = match from_str(s) { + Ok(x) => x, + Err(e) => return Err(ParseError(e)) + }; + + let mut decoder = Decoder::new(json); + ::Decodable::decode(&mut decoder) +} + +/// Shortcut function to encode a `T` into a JSON `String` +pub fn encode(object: &T) -> string::String + where T: for<'a> Encodable, fmt::Error> +{ + let mut s = String::new(); + { + let mut encoder = Encoder::new(&mut s); + let _ = object.encode(&mut encoder); + } + s +} + +impl fmt::Show for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error_str(*self).fmt(f) + } +} + +fn io_error_to_error(io: io::IoError) -> ParserError { + IoError(io.kind, io.desc) +} + +impl std::error::Error for DecoderError { + fn description(&self) -> &str { "decoder error" } + fn detail(&self) -> Option { Some(self.to_string()) } +} + +pub type EncodeResult = fmt::Result; +pub type DecodeResult = Result; + +fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result { + try!(wr.write_str("\"")); + + let mut start = 0; + + for (i, byte) in v.bytes().enumerate() { + let escaped = match byte { + b'"' => "\\\"", + b'\\' => "\\\\", + b'\x00' => "\\u0000", + b'\x01' => "\\u0001", + b'\x02' => "\\u0002", + b'\x03' => "\\u0003", + b'\x04' => "\\u0004", + b'\x05' => "\\u0005", + b'\x06' => "\\u0006", + b'\x07' => "\\u0007", + b'\x08' => "\\b", + b'\t' => "\\t", + b'\n' => "\\n", + b'\x0b' => "\\u000b", + b'\x0c' => "\\f", + b'\r' => "\\r", + b'\x0e' => "\\u000e", + b'\x0f' => "\\u000f", + b'\x10' => "\\u0010", + b'\x11' => "\\u0011", + b'\x12' => "\\u0012", + b'\x13' => "\\u0013", + b'\x14' => "\\u0014", + b'\x15' => "\\u0015", + b'\x16' => "\\u0016", + b'\x17' => "\\u0017", + b'\x18' => "\\u0018", + b'\x19' => "\\u0019", + b'\x1a' => "\\u001a", + b'\x1b' => "\\u001b", + b'\x1c' => "\\u001c", + b'\x1d' => "\\u001d", + b'\x1e' => "\\u001e", + b'\x1f' => "\\u001f", + b'\x7f' => "\\u007f", + _ => { continue; } + }; + + if start < i { + try!(wr.write_str(v[start..i])); + } + + try!(wr.write_str(escaped)); + + start = i + 1; + } + + if start != v.len() { + try!(wr.write_str(v[start..])); + } + + wr.write_str("\"") +} + +fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result { + let mut buf = [0; 4]; + let n = v.encode_utf8(&mut buf).unwrap(); + let buf = unsafe { str::from_utf8_unchecked(buf[0..n]) }; + escape_str(writer, buf) +} + +fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result { + const BUF: &'static str = " "; + + while n >= BUF.len() { + try!(wr.write_str(BUF)); + n -= BUF.len(); + } + + if n > 0 { + wr.write_str(BUF[..n]) + } else { + Ok(()) + } +} + +fn fmt_number_or_null(v: f64) -> string::String { + match v.classify() { + Fp::Nan | Fp::Infinite => string::String::from_str("null"), + _ if v.fract() != 0f64 => f64::to_str_digits(v, 6u), + _ => f64::to_str_digits(v, 6u) + ".0", + } +} + +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { + writer: &'a mut (fmt::Writer+'a), +} + +impl<'a> Encoder<'a> { + /// Creates a new JSON encoder whose output will be written to the writer + /// specified. + pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { + Encoder { writer: writer } + } +} + +impl<'a> ::Encoder for Encoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + // enums are encoded as strings or objects + // Bunny => "Bunny" + // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\"variant\":")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\"fields\":[")); + try!(f(self)); + write!(self.writer, "]}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")); } + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ":")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "[")); + try!(f(self)); + write!(self.writer, "]") + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")) } + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = Encoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ":")); + f(self) + } +} + +/// Another encoder for JSON, but prints out human-readable JSON instead of +/// compact data +pub struct PrettyEncoder<'a> { + writer: &'a mut (fmt::Writer+'a), + curr_indent: uint, + indent: uint, +} + +impl<'a> PrettyEncoder<'a> { + /// Creates a new encoder whose output will be written to the specified writer + pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { + PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, } + } + + /// Set the number of spaces to indent for each level. + /// This is safe to set during encoding. + pub fn set_indent(&mut self, indent: uint) { + // self.indent very well could be 0 so we need to use checked division. + let level = self.curr_indent.checked_div(self.indent).unwrap_or(0); + self.indent = indent; + self.curr_indent = level * self.indent; + } +} + +impl<'a> ::Encoder for PrettyEncoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) + -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\n")); + self.curr_indent += self.indent; + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"variant\": ")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"fields\": [\n")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "]\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + + fn emit_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ": ")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "[]") + } else { + try!(write!(self.writer, "[")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "]") + } + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = PrettyEncoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ": ")); + f(self) + } +} + +impl, S> Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), S> { + match *self { + Json::I64(v) => v.encode(e), + Json::U64(v) => v.encode(e), + Json::F64(v) => v.encode(e), + Json::String(ref v) => v.encode(e), + Json::Boolean(v) => v.encode(e), + Json::Array(ref v) => v.encode(e), + Json::Object(ref v) => v.encode(e), + Json::Null => e.emit_nil(), + } + } +} + +/// Create an `AsJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_json(t: &T) -> AsJson { + AsJson { inner: t } +} + +/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_pretty_json(t: &T) -> AsPrettyJson { + AsPrettyJson { inner: t, indent: None } +} + +impl Json { + /// Borrow this json object as a pretty object to generate a pretty + /// representation for it via `Show`. + pub fn pretty(&self) -> PrettyJson { + PrettyJson { inner: self } + } + + /// If the Json value is an Object, returns the value associated with the provided key. + /// Otherwise, returns None. + pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{ + match self { + &Json::Object(ref map) => map.get(key), + _ => None + } + } + + /// Attempts to get a nested Json Object for each key in `keys`. + /// If any key is found not to exist, find_path will return None. + /// Otherwise, it will return the Json value associated with the final key. + pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{ + let mut target = self; + for key in keys.iter() { + match target.find(*key) { + Some(t) => { target = t; }, + None => return None + } + } + Some(target) + } + + /// If the Json value is an Object, performs a depth-first search until + /// a value associated with the provided key is found. If no value is found + /// or the Json value is not an Object, returns None. + pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> { + match self { + &Json::Object(ref map) => { + match map.get(key) { + Some(json_value) => Some(json_value), + None => { + for (_, v) in map.iter() { + match v.search(key) { + x if x.is_some() => return x, + _ => () + } + } + None + } + } + }, + _ => None + } + } + + /// Returns true if the Json value is an Object. Returns false otherwise. + pub fn is_object<'a>(&'a self) -> bool { + self.as_object().is_some() + } + + /// If the Json value is an Object, returns the associated BTreeMap. + /// Returns None otherwise. + pub fn as_object<'a>(&'a self) -> Option<&'a Object> { + match self { + &Json::Object(ref map) => Some(map), + _ => None + } + } + + /// Returns true if the Json value is an Array. Returns false otherwise. + pub fn is_array<'a>(&'a self) -> bool { + self.as_array().is_some() + } + + /// If the Json value is an Array, returns the associated vector. + /// Returns None otherwise. + pub fn as_array<'a>(&'a self) -> Option<&'a Array> { + match self { + &Json::Array(ref array) => Some(&*array), + _ => None + } + } + + /// Returns true if the Json value is a String. Returns false otherwise. + pub fn is_string<'a>(&'a self) -> bool { + self.as_string().is_some() + } + + /// If the Json value is a String, returns the associated str. + /// Returns None otherwise. + pub fn as_string<'a>(&'a self) -> Option<&'a str> { + match *self { + Json::String(ref s) => Some(s[]), + _ => None + } + } + + /// Returns true if the Json value is a Number. Returns false otherwise. + pub fn is_number(&self) -> bool { + match *self { + Json::I64(_) | Json::U64(_) | Json::F64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a i64. Returns false otherwise. + pub fn is_i64(&self) -> bool { + match *self { + Json::I64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a u64. Returns false otherwise. + pub fn is_u64(&self) -> bool { + match *self { + Json::U64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a f64. Returns false otherwise. + pub fn is_f64(&self) -> bool { + match *self { + Json::F64(_) => true, + _ => false, + } + } + + /// If the Json value is a number, return or cast it to a i64. + /// Returns None otherwise. + pub fn as_i64(&self) -> Option { + match *self { + Json::I64(n) => Some(n), + Json::U64(n) => num::cast(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a u64. + /// Returns None otherwise. + pub fn as_u64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => Some(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a f64. + /// Returns None otherwise. + pub fn as_f64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => num::cast(n), + Json::F64(n) => Some(n), + _ => None + } + } + + /// Returns true if the Json value is a Boolean. Returns false otherwise. + pub fn is_boolean(&self) -> bool { + self.as_boolean().is_some() + } + + /// If the Json value is a Boolean, returns the associated bool. + /// Returns None otherwise. + pub fn as_boolean(&self) -> Option { + match self { + &Json::Boolean(b) => Some(b), + _ => None + } + } + + /// Returns true if the Json value is a Null. Returns false otherwise. + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the Json value is a Null, returns (). + /// Returns None otherwise. + pub fn as_null(&self) -> Option<()> { + match self { + &Json::Null => Some(()), + _ => None + } + } +} + +impl<'a> ops::Index<&'a str> for Json { + type Output = Json; + + fn index(&self, idx: & &str) -> &Json { + self.find(*idx).unwrap() + } +} + +impl ops::Index for Json { + type Output = Json; + + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &Json::Array(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is an array") + } + } +} + +/// The output of the streaming parser. +#[derive(PartialEq, Clone, Show)] +pub enum JsonEvent { + ObjectStart, + ObjectEnd, + ArrayStart, + ArrayEnd, + BooleanValue(bool), + I64Value(i64), + U64Value(u64), + F64Value(f64), + StringValue(string::String), + NullValue, + Error(ParserError), +} + +#[derive(PartialEq, Show)] +enum ParserState { + // Parse a value in an array, true means first element. + ParseArray(bool), + // Parse ',' or ']' after an element in an array. + ParseArrayComma, + // Parse a key:value in an object, true means first element. + ParseObject(bool), + // Parse ',' or ']' after an element in an object. + ParseObjectComma, + // Initial state. + ParseStart, + // Expecting the stream to end. + ParseBeforeFinish, + // Parsing can't continue. + ParseFinished, +} + +/// A Stack represents the current position of the parser in the logical +/// structure of the JSON stream. +/// For example foo.bar[3].x +pub struct Stack { + stack: Vec, + str_buffer: Vec, +} + +/// StackElements compose a Stack. +/// For example, Key("foo"), Key("bar"), Index(3) and Key("x") are the +/// StackElements compositing the stack that represents foo.bar[3].x +#[derive(PartialEq, Clone, Show)] +pub enum StackElement<'l> { + Index(u32), + Key(&'l str), +} + +// Internally, Key elements are stored as indices in a buffer to avoid +// allocating a string for every member of an object. +#[derive(PartialEq, Clone, Show)] +enum InternalStackElement { + InternalIndex(u32), + InternalKey(u16, u16), // start, size +} + +impl Stack { + pub fn new() -> Stack { + Stack { stack: Vec::new(), str_buffer: Vec::new() } + } + + /// Returns The number of elements in the Stack. + pub fn len(&self) -> uint { self.stack.len() } + + /// Returns true if the stack is empty. + pub fn is_empty(&self) -> bool { self.stack.is_empty() } + + /// Provides access to the StackElement at a given index. + /// lower indices are at the bottom of the stack while higher indices are + /// at the top. + pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> { + match self.stack[idx] { + InternalIndex(i) => Index(i), + InternalKey(start, size) => { + Key(str::from_utf8( + self.str_buffer[start as uint .. start as uint + size as uint]).unwrap()) + } + } + } + + /// Compares this stack with an array of StackElements. + pub fn is_equal_to(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() != rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the bottom-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn starts_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the top-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn ends_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + let offset = self.stack.len() - rhs.len(); + for i in range(0, rhs.len()) { + if self.get(i + offset) != rhs[i] { return false; } + } + return true; + } + + /// Returns the top-most element (if any). + pub fn top<'l>(&'l self) -> Option> { + return match self.stack.last() { + None => None, + Some(&InternalIndex(i)) => Some(Index(i)), + Some(&InternalKey(start, size)) => { + Some(Key(str::from_utf8( + self.str_buffer[start as uint .. (start+size) as uint] + ).unwrap())) + } + } + } + + // Used by Parser to insert Key elements at the top of the stack. + fn push_key(&mut self, key: string::String) { + self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16)); + for c in key.as_bytes().iter() { + self.str_buffer.push(*c); + } + } + + // Used by Parser to insert Index elements at the top of the stack. + fn push_index(&mut self, index: u32) { + self.stack.push(InternalIndex(index)); + } + + // Used by Parser to remove the top-most element of the stack. + fn pop(&mut self) { + assert!(!self.is_empty()); + match *self.stack.last().unwrap() { + InternalKey(_, sz) => { + let new_size = self.str_buffer.len() - sz as uint; + self.str_buffer.truncate(new_size); + } + InternalIndex(_) => {} + } + self.stack.pop(); + } + + // Used by Parser to test whether the top-most element is an index. + fn last_is_index(&self) -> bool { + if self.is_empty() { return false; } + return match *self.stack.last().unwrap() { + InternalIndex(_) => true, + _ => false, + } + } + + // Used by Parser to increment the index of the top-most element. + fn bump_index(&mut self) { + let len = self.stack.len(); + let idx = match *self.stack.last().unwrap() { + InternalIndex(i) => { i + 1 } + _ => { panic!(); } + }; + self.stack[len - 1] = InternalIndex(idx); + } +} + +/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming +/// an iterator of char. +pub struct Parser { + rdr: T, + ch: Option, + line: uint, + col: uint, + // We maintain a stack representing where we are in the logical structure + // of the JSON stream. + stack: Stack, + // A state machine is kept to make it possible to interrupt and resume parsing. + state: ParserState, +} + +impl> Iterator for Parser { + type Item = JsonEvent; + + fn next(&mut self) -> Option { + if self.state == ParseFinished { + return None; + } + + if self.state == ParseBeforeFinish { + self.parse_whitespace(); + // Make sure there is no trailing characters. + if self.eof() { + self.state = ParseFinished; + return None; + } else { + return Some(self.error_event(TrailingCharacters)); + } + } + + return Some(self.parse()); + } +} + +impl> Parser { + /// Creates the JSON parser. + pub fn new(rdr: T) -> Parser { + let mut p = Parser { + rdr: rdr, + ch: Some('\x00'), + line: 1, + col: 0, + stack: Stack::new(), + state: ParseStart, + }; + p.bump(); + return p; + } + + /// Provides access to the current position in the logical structure of the + /// JSON stream. + pub fn stack<'l>(&'l self) -> &'l Stack { + return &self.stack; + } + + fn eof(&self) -> bool { self.ch.is_none() } + fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') } + fn bump(&mut self) { + self.ch = self.rdr.next(); + + if self.ch_is('\n') { + self.line += 1u; + self.col = 1u; + } else { + self.col += 1u; + } + } + + fn next_char(&mut self) -> Option { + self.bump(); + self.ch + } + fn ch_is(&self, c: char) -> bool { + self.ch == Some(c) + } + + fn error(&self, reason: ErrorCode) -> Result { + Err(SyntaxError(reason, self.line, self.col)) + } + + fn parse_whitespace(&mut self) { + while self.ch_is(' ') || + self.ch_is('\n') || + self.ch_is('\t') || + self.ch_is('\r') { self.bump(); } + } + + fn parse_number(&mut self) -> JsonEvent { + let mut neg = false; + + if self.ch_is('-') { + self.bump(); + neg = true; + } + + let res = match self.parse_u64() { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + + if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') { + let mut res = res as f64; + + if self.ch_is('.') { + res = match self.parse_decimal(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if self.ch_is('e') || self.ch_is('E') { + res = match self.parse_exponent(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if neg { + res *= -1.0; + } + + F64Value(res) + } else { + if neg { + let res = -(res as i64); + + // Make sure we didn't underflow. + if res > 0 { + Error(SyntaxError(InvalidNumber, self.line, self.col)) + } else { + I64Value(res) + } + } else { + U64Value(res) + } + } + } + + fn parse_u64(&mut self) -> Result { + let mut accum = 0; + let last_accum = 0; // necessary to detect overflow. + + match self.ch_or_null() { + '0' => { + self.bump(); + + // A leading '0' must be the only digit before the decimal point. + match self.ch_or_null() { + '0' ... '9' => return self.error(InvalidNumber), + _ => () + } + }, + '1' ... '9' => { + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + accum *= 10; + accum += (c as u64) - ('0' as u64); + + // Detect overflow by comparing to the last value. + if accum <= last_accum { return self.error(InvalidNumber); } + + self.bump(); + } + _ => break, + } + } + } + _ => return self.error(InvalidNumber), + } + + Ok(accum) + } + + fn parse_decimal(&mut self, mut res: f64) -> Result { + self.bump(); + + // Make sure a digit follows the decimal place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + + let mut dec = 1.0; + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + dec /= 10.0; + res += (((c as int) - ('0' as int)) as f64) * dec; + self.bump(); + } + _ => break, + } + } + + Ok(res) + } + + fn parse_exponent(&mut self, mut res: f64) -> Result { + self.bump(); + + let mut exp = 0u; + let mut neg_exp = false; + + if self.ch_is('+') { + self.bump(); + } else if self.ch_is('-') { + self.bump(); + neg_exp = true; + } + + // Make sure a digit follows the exponent place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + exp *= 10; + exp += (c as uint) - ('0' as uint); + + self.bump(); + } + _ => break + } + } + + let exp = 10_f64.powi(exp as i32); + if neg_exp { + res /= exp; + } else { + res *= exp; + } + + Ok(res) + } + + fn decode_hex_escape(&mut self) -> Result { + let mut i = 0u; + let mut n = 0u16; + while i < 4 && !self.eof() { + self.bump(); + n = match self.ch_or_null() { + c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)), + 'a' | 'A' => n * 16 + 10, + 'b' | 'B' => n * 16 + 11, + 'c' | 'C' => n * 16 + 12, + 'd' | 'D' => n * 16 + 13, + 'e' | 'E' => n * 16 + 14, + 'f' | 'F' => n * 16 + 15, + _ => return self.error(InvalidEscape) + }; + + i += 1u; + } + + // Error out if we didn't parse 4 digits. + if i != 4 { + return self.error(InvalidEscape); + } + + Ok(n) + } + + fn parse_str(&mut self) -> Result { + let mut escape = false; + let mut res = string::String::new(); + + loop { + self.bump(); + if self.eof() { + return self.error(EOFWhileParsingString); + } + + if escape { + match self.ch_or_null() { + '"' => res.push('"'), + '\\' => res.push('\\'), + '/' => res.push('/'), + 'b' => res.push('\x08'), + 'f' => res.push('\x0c'), + 'n' => res.push('\n'), + 'r' => res.push('\r'), + 't' => res.push('\t'), + 'u' => match try!(self.decode_hex_escape()) { + 0xDC00 ... 0xDFFF => { + return self.error(LoneLeadingSurrogateInHexEscape) + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800 ... 0xDBFF => { + match (self.next_char(), self.next_char()) { + (Some('\\'), Some('u')) => (), + _ => return self.error(UnexpectedEndOfHexEscape), + } + + let buf = [n1, try!(self.decode_hex_escape())]; + match unicode_str::utf16_items(&buf).next() { + Some(Utf16Item::ScalarValue(c)) => res.push(c), + _ => return self.error(LoneLeadingSurrogateInHexEscape), + } + } + + n => match char::from_u32(n as u32) { + Some(c) => res.push(c), + None => return self.error(InvalidUnicodeCodePoint), + }, + }, + _ => return self.error(InvalidEscape), + } + escape = false; + } else if self.ch_is('\\') { + escape = true; + } else { + match self.ch { + Some('"') => { + self.bump(); + return Ok(res); + }, + Some(c) => res.push(c), + None => unreachable!() + } + } + } + } + + // Invoked at each iteration, consumes the stream until it has enough + // information to return a JsonEvent. + // Manages an internal state so that parsing can be interrupted and resumed. + // Also keeps track of the position in the logical structure of the json + // stream int the form of a stack that can be queried by the user using the + // stack() method. + fn parse(&mut self) -> JsonEvent { + loop { + // The only paths where the loop can spin a new iteration + // are in the cases ParseArrayComma and ParseObjectComma if ',' + // is parsed. In these cases the state is set to (respectively) + // ParseArray(false) and ParseObject(false), which always return, + // so there is no risk of getting stuck in an infinite loop. + // All other paths return before the end of the loop's iteration. + self.parse_whitespace(); + + match self.state { + ParseStart => { + return self.parse_start(); + } + ParseArray(first) => { + return self.parse_array(first); + } + ParseArrayComma => { + match self.parse_array_comma_or_end() { + Some(evt) => { return evt; } + None => {} + } + } + ParseObject(first) => { + return self.parse_object(first); + } + ParseObjectComma => { + self.stack.pop(); + if self.ch_is(',') { + self.state = ParseObject(false); + self.bump(); + } else { + return self.parse_object_end(); + } + } + _ => { + return self.error_event(InvalidSyntax); + } + } + } + } + + fn parse_start(&mut self) -> JsonEvent { + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseBeforeFinish, + }; + return val; + } + + fn parse_array(&mut self, first: bool) -> JsonEvent { + if self.ch_is(']') { + if !first { + self.error_event(InvalidSyntax) + } else { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ArrayEnd + } + } else { + if first { + self.stack.push_index(0); + } + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseArrayComma, + }; + val + } + } + + fn parse_array_comma_or_end(&mut self) -> Option { + if self.ch_is(',') { + self.stack.bump_index(); + self.state = ParseArray(false); + self.bump(); + None + } else if self.ch_is(']') { + self.stack.pop(); + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + Some(ArrayEnd) + } else if self.eof() { + Some(self.error_event(EOFWhileParsingArray)) + } else { + Some(self.error_event(InvalidSyntax)) + } + } + + fn parse_object(&mut self, first: bool) -> JsonEvent { + if self.ch_is('}') { + if !first { + if self.stack.is_empty() { + return self.error_event(TrailingComma); + } else { + self.stack.pop(); + } + } + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + return ObjectEnd; + } + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } + if !self.ch_is('"') { + return self.error_event(KeyMustBeAString); + } + let s = match self.parse_str() { + Ok(s) => s, + Err(e) => { + self.state = ParseFinished; + return Error(e); + } + }; + self.parse_whitespace(); + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } else if self.ch_or_null() != ':' { + return self.error_event(ExpectedColon); + } + self.stack.push_key(s); + self.bump(); + self.parse_whitespace(); + + let val = self.parse_value(); + + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseObjectComma, + }; + return val; + } + + fn parse_object_end(&mut self) -> JsonEvent { + if self.ch_is('}') { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ObjectEnd + } else if self.eof() { + self.error_event(EOFWhileParsingObject) + } else { + self.error_event(InvalidSyntax) + } + } + + fn parse_value(&mut self) -> JsonEvent { + if self.eof() { return self.error_event(EOFWhileParsingValue); } + match self.ch_or_null() { + 'n' => { self.parse_ident("ull", NullValue) } + 't' => { self.parse_ident("rue", BooleanValue(true)) } + 'f' => { self.parse_ident("alse", BooleanValue(false)) } + '0' ... '9' | '-' => self.parse_number(), + '"' => match self.parse_str() { + Ok(s) => StringValue(s), + Err(e) => Error(e), + }, + '[' => { + self.bump(); + ArrayStart + } + '{' => { + self.bump(); + ObjectStart + } + _ => { self.error_event(InvalidSyntax) } + } + } + + fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent { + if ident.chars().all(|c| Some(c) == self.next_char()) { + self.bump(); + value + } else { + Error(SyntaxError(InvalidSyntax, self.line, self.col)) + } + } + + fn error_event(&mut self, reason: ErrorCode) -> JsonEvent { + self.state = ParseFinished; + Error(SyntaxError(reason, self.line, self.col)) + } +} + +/// A Builder consumes a json::Parser to create a generic Json structure. +pub struct Builder { + parser: Parser, + token: Option, +} + +impl> Builder { + /// Create a JSON Builder. + pub fn new(src: T) -> Builder { + Builder { parser: Parser::new(src), token: None, } + } + + // Decode a Json value from a Parser. + pub fn build(&mut self) -> Result { + self.bump(); + let result = self.build_value(); + self.bump(); + match self.token { + None => {} + Some(Error(e)) => { return Err(e); } + ref tok => { panic!("unexpected token {}", tok.clone()); } + } + result + } + + fn bump(&mut self) { + self.token = self.parser.next(); + } + + fn build_value(&mut self) -> Result { + return match self.token { + Some(NullValue) => Ok(Json::Null), + Some(I64Value(n)) => Ok(Json::I64(n)), + Some(U64Value(n)) => Ok(Json::U64(n)), + Some(F64Value(n)) => Ok(Json::F64(n)), + Some(BooleanValue(b)) => Ok(Json::Boolean(b)), + Some(StringValue(ref mut s)) => { + let mut temp = string::String::new(); + swap(s, &mut temp); + Ok(Json::String(temp)) + } + Some(Error(e)) => Err(e), + Some(ArrayStart) => self.build_array(), + Some(ObjectStart) => self.build_object(), + Some(ObjectEnd) => self.parser.error(InvalidSyntax), + Some(ArrayEnd) => self.parser.error(InvalidSyntax), + None => self.parser.error(EOFWhileParsingValue), + } + } + + fn build_array(&mut self) -> Result { + self.bump(); + let mut values = Vec::new(); + + loop { + if self.token == Some(ArrayEnd) { + return Ok(Json::Array(values.into_iter().collect())); + } + match self.build_value() { + Ok(v) => values.push(v), + Err(e) => { return Err(e) } + } + self.bump(); + } + } + + fn build_object(&mut self) -> Result { + self.bump(); + + let mut values = BTreeMap::new(); + + loop { + match self.token { + Some(ObjectEnd) => { return Ok(Json::Object(values)); } + Some(Error(e)) => { return Err(e); } + None => { break; } + _ => {} + } + let key = match self.parser.stack().top() { + Some(Key(k)) => { k.to_string() } + _ => { panic!("invalid state"); } + }; + match self.build_value() { + Ok(value) => { values.insert(key, value); } + Err(e) => { return Err(e); } + } + self.bump(); + } + return self.parser.error(EOFWhileParsingObject); + } +} + +/// Decodes a json value from an `&mut io::Reader` +pub fn from_reader(rdr: &mut io::Reader) -> Result { + let contents = match rdr.read_to_end() { + Ok(c) => c, + Err(e) => return Err(io_error_to_error(e)) + }; + let s = match str::from_utf8(contents.as_slice()).ok() { + Some(s) => s, + _ => return Err(SyntaxError(NotUtf8, 0, 0)) + }; + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// Decodes a json value from a string +pub fn from_str(s: &str) -> Result { + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// A structure to decode JSON to values in rust. +pub struct Decoder { + stack: Vec, +} + +impl Decoder { + /// Creates a new decoder instance for decoding the specified JSON value. + pub fn new(json: Json) -> Decoder { + Decoder { stack: vec![json] } + } +} + +impl Decoder { + fn pop(&mut self) -> Json { + self.stack.pop().unwrap() + } +} + +macro_rules! expect { + ($e:expr, Null) => ({ + match $e { + Json::Null => Ok(()), + other => Err(ExpectedError("Null".to_string(), + format!("{}", other))) + } + }); + ($e:expr, $t:ident) => ({ + match $e { + Json::$t(v) => Ok(v), + other => { + Err(ExpectedError(stringify!($t).to_string(), + format!("{}", other))) + } + } + }) +} + +macro_rules! read_primitive { + ($name:ident, $ty:ty) => { + fn $name(&mut self) -> DecodeResult<$ty> { + match self.pop() { + Json::I64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::U64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + Json::String(s) => match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + }, + value => Err(ExpectedError("Number".to_string(), format!("{}", value))), + } + } + } +} + +impl ::Decoder for Decoder { + fn read_nil(&mut self) -> DecodeResult<()> { + expect!(self.pop(), Null) + } + + read_primitive! { read_uint, uint } + read_primitive! { read_u8, u8 } + read_primitive! { read_u16, u16 } + read_primitive! { read_u32, u32 } + read_primitive! { read_u64, u64 } + read_primitive! { read_int, int } + read_primitive! { read_i8, i8 } + read_primitive! { read_i16, i16 } + read_primitive! { read_i32, i32 } + read_primitive! { read_i64, i64 } + + fn read_f32(&mut self) -> DecodeResult { self.read_f64().map(|x| x as f32) } + + fn read_f64(&mut self) -> DecodeResult { + match self.pop() { + Json::I64(f) => Ok(f as f64), + Json::U64(f) => Ok(f as f64), + Json::F64(f) => Ok(f), + Json::String(s) => { + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + } + }, + Json::Null => Ok(f64::NAN), + value => Err(ExpectedError("Number".to_string(), format!("{}", value))) + } + } + + fn read_bool(&mut self) -> DecodeResult { + expect!(self.pop(), Boolean) + } + + fn read_char(&mut self) -> DecodeResult { + let s = try!(self.read_str()); + { + let mut it = s.chars(); + match (it.next(), it.next()) { + // exactly one character + (Some(c), None) => return Ok(c), + _ => () + } + } + Err(ExpectedError("single character string".to_string(), format!("{}", s))) + } + + fn read_str(&mut self) -> DecodeResult { + expect!(self.pop(), String) + } + + fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_variant(&mut self, names: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + let name = match self.pop() { + Json::String(s) => s, + Json::Object(mut o) => { + let n = match o.remove(&"variant".to_string()) { + Some(Json::String(s)) => s, + Some(val) => { + return Err(ExpectedError("String".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("variant".to_string())) + } + }; + match o.remove(&"fields".to_string()) { + Some(Json::Array(l)) => { + for field in l.into_iter().rev() { + self.stack.push(field); + } + }, + Some(val) => { + return Err(ExpectedError("Array".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("fields".to_string())) + } + } + n + } + json => { + return Err(ExpectedError("String or Object".to_string(), format!("{}", json))) + } + }; + let idx = match names.iter().position(|n| *n == name[]) { + Some(idx) => idx, + None => return Err(UnknownVariantError(name)) + }; + f(self, idx) + } + + fn read_enum_variant_arg(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodeResult where + F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + self.read_enum_variant(names, f) + } + + + fn read_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_enum_variant_arg(idx, f) + } + + fn read_struct(&mut self, _name: &str, _len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let value = try!(f(self)); + self.pop(); + Ok(value) + } + + fn read_struct_field(&mut self, + name: &str, + _idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let mut obj = try!(expect!(self.pop(), Object)); + + let value = match obj.remove(&name.to_string()) { + None => { + // Add a Null and try to parse it as an Option<_> + // to get None as a default value. + self.stack.push(Json::Null); + match f(self) { + Ok(x) => x, + Err(_) => return Err(MissingFieldError(name.to_string())), + } + }, + Some(json) => { + self.stack.push(json); + try!(f(self)) + } + }; + self.stack.push(Json::Object(obj)); + Ok(value) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + _name: &str, + len: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder, bool) -> DecodeResult, + { + match self.pop() { + Json::Null => f(self, false), + value => { self.stack.push(value); f(self, true) } + } + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let array = try!(expect!(self.pop(), Array)); + let len = array.len(); + for v in array.into_iter().rev() { + self.stack.push(v); + } + f(self, len) + } + + fn read_seq_elt(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let obj = try!(expect!(self.pop(), Object)); + let len = obj.len(); + for (key, value) in obj.into_iter() { + self.stack.push(value); + self.stack.push(Json::String(key)); + } + f(self, len) + } + + fn read_map_elt_key(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map_elt_val(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn error(&mut self, err: &str) -> DecoderError { + ApplicationError(err.to_string()) + } +} + +/// A trait for converting values to JSON +pub trait ToJson for Sized? { + /// Converts the value of `self` to an instance of JSON + fn to_json(&self) -> Json; +} + +macro_rules! to_json_impl_i64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::I64(*self as i64) } + })+ + ) +} + +to_json_impl_i64! { int, i8, i16, i32, i64 } + +macro_rules! to_json_impl_u64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::U64(*self as u64) } + })+ + ) +} + +to_json_impl_u64! { uint, u8, u16, u32, u64 } + +impl ToJson for Json { + fn to_json(&self) -> Json { self.clone() } +} + +impl ToJson for f32 { + fn to_json(&self) -> Json { (*self as f64).to_json() } +} + +impl ToJson for f64 { + fn to_json(&self) -> Json { + match self.classify() { + Fp::Nan | Fp::Infinite => Json::Null, + _ => Json::F64(*self) + } + } +} + +impl ToJson for () { + fn to_json(&self) -> Json { Json::Null } +} + +impl ToJson for bool { + fn to_json(&self) -> Json { Json::Boolean(*self) } +} + +impl ToJson for str { + fn to_json(&self) -> Json { Json::String(self.to_string()) } +} + +impl ToJson for string::String { + fn to_json(&self) -> Json { Json::String((*self).clone()) } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< + $( $tyvar : ToJson ),* + > ToJson for ( $( $tyvar ),* , ) { + + #[inline] + #[allow(non_snake_case)] + fn to_json(&self) -> Json { + match *self { + ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*]) + } + } + } + } +} + +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +impl ToJson for [A] { + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for Vec
{ + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for BTreeMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for HashMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for Option { + fn to_json(&self) -> Json { + match *self { + None => Json::Null, + Some(ref value) => value.to_json() + } + } +} + +struct FormatShim<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, +} + +impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.inner.write_str(s) + } +} + +impl fmt::Show for Json { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.encode(&mut encoder) + } +} + +impl<'a> fmt::Show for PrettyJson<'a> { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> fmt::Show for AsJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> AsPrettyJson<'a, T> { + /// Set the indentation level for the emitted JSON + pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> { + self.indent = Some(indent); + self + } +} + +impl<'a, T> fmt::Show for AsPrettyJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + match self.indent { + Some(n) => encoder.set_indent(n), + None => {} + } + self.inner.encode(&mut encoder) + } +} + +impl FromStr for Json { + fn from_str(s: &str) -> Option { + from_str(s).ok() + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::Animal::*; + use self::DecodeEnum::*; + use self::test::Bencher; + use {Encodable, Decodable}; + use super::Json::*; + use super::ErrorCode::*; + use super::ParserError::*; + use super::DecoderError::*; + use super::JsonEvent::*; + use super::StackElement::*; + use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, + StackElement, Stack, Decoder}; + use std::{i64, u64, f32, f64}; + use std::collections::BTreeMap; + use std::num::Float; + use std::string; + + #[derive(RustcDecodable, Eq, PartialEq, Show)] + struct OptionData { + opt: Option, + } + + #[test] + fn test_decode_option_none() { + let s ="{}"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: None }); + } + + #[test] + fn test_decode_option_some() { + let s = "{ \"opt\": 10 }"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: Some(10u) }); + } + + #[test] + fn test_decode_option_malformed() { + check_err::("{ \"opt\": [] }", + ExpectedError("Number".to_string(), "[]".to_string())); + check_err::("{ \"opt\": false }", + ExpectedError("Number".to_string(), "false".to_string())); + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + enum Animal { + Dog, + Frog(string::String, int) + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Inner { + a: (), + b: uint, + c: Vec, + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Outer { + inner: Vec, + } + + fn mk_object(items: &[(string::String, Json)]) -> Json { + let mut d = BTreeMap::new(); + + for item in items.iter() { + match *item { + (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); }, + } + }; + + Object(d) + } + + #[test] + fn test_from_str_trait() { + let s = "null"; + assert!(s.parse::().unwrap() == s.parse().unwrap()); + } + + #[test] + fn test_write_null() { + assert_eq!(Null.to_string(), "null"); + assert_eq!(Null.pretty().to_string(), "null"); + } + + #[test] + fn test_write_i64() { + assert_eq!(U64(0).to_string(), "0"); + assert_eq!(U64(0).pretty().to_string(), "0"); + + assert_eq!(U64(1234).to_string(), "1234"); + assert_eq!(U64(1234).pretty().to_string(), "1234"); + + assert_eq!(I64(-5678).to_string(), "-5678"); + assert_eq!(I64(-5678).pretty().to_string(), "-5678"); + + assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000"); + assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000"); + } + + #[test] + fn test_write_f64() { + assert_eq!(F64(3.0).to_string(), "3.0"); + assert_eq!(F64(3.0).pretty().to_string(), "3.0"); + + assert_eq!(F64(3.1).to_string(), "3.1"); + assert_eq!(F64(3.1).pretty().to_string(), "3.1"); + + assert_eq!(F64(-1.5).to_string(), "-1.5"); + assert_eq!(F64(-1.5).pretty().to_string(), "-1.5"); + + assert_eq!(F64(0.5).to_string(), "0.5"); + assert_eq!(F64(0.5).pretty().to_string(), "0.5"); + + assert_eq!(F64(f64::NAN).to_string(), "null"); + assert_eq!(F64(f64::NAN).pretty().to_string(), "null"); + + assert_eq!(F64(f64::INFINITY).to_string(), "null"); + assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null"); + + assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null"); + assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null"); + } + + #[test] + fn test_write_str() { + assert_eq!(String("".to_string()).to_string(), "\"\""); + assert_eq!(String("".to_string()).pretty().to_string(), "\"\""); + + assert_eq!(String("homura".to_string()).to_string(), "\"homura\""); + assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\""); + } + + #[test] + fn test_write_bool() { + assert_eq!(Boolean(true).to_string(), "true"); + assert_eq!(Boolean(true).pretty().to_string(), "true"); + + assert_eq!(Boolean(false).to_string(), "false"); + assert_eq!(Boolean(false).pretty().to_string(), "false"); + } + + #[test] + fn test_write_array() { + assert_eq!(Array(vec![]).to_string(), "[]"); + assert_eq!(Array(vec![]).pretty().to_string(), "[]"); + + assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]"); + assert_eq!( + Array(vec![Boolean(true)]).pretty().to_string(), + "\ + [\n \ + true\n\ + ]" + ); + + let long_test_array = Array(vec![ + Boolean(false), + Null, + Array(vec![String("foo\nbar".to_string()), F64(3.5)])]); + + assert_eq!(long_test_array.to_string(), + "[false,null,[\"foo\\nbar\",3.5]]"); + assert_eq!( + long_test_array.pretty().to_string(), + "\ + [\n \ + false,\n \ + null,\n \ + [\n \ + \"foo\\nbar\",\n \ + 3.5\n \ + ]\n\ + ]" + ); + } + + #[test] + fn test_write_object() { + assert_eq!(mk_object(&[]).to_string(), "{}"); + assert_eq!(mk_object(&[]).pretty().to_string(), "{}"); + + assert_eq!( + mk_object(&[ + ("a".to_string(), Boolean(true)) + ]).to_string(), + "{\"a\":true}" + ); + assert_eq!( + mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(), + "\ + {\n \ + \"a\": true\n\ + }" + ); + + let complex_obj = mk_object(&[ + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + assert_eq!( + complex_obj.to_string(), + "{\ + \"b\":[\ + {\"c\":\"\\f\\r\"},\ + {\"d\":\"\"}\ + ]\ + }" + ); + assert_eq!( + complex_obj.pretty().to_string(), + "\ + {\n \ + \"b\": [\n \ + {\n \ + \"c\": \"\\f\\r\"\n \ + },\n \ + {\n \ + \"d\": \"\"\n \ + }\n \ + ]\n\ + }" + ); + + let a = mk_object(&[ + ("a".to_string(), Boolean(true)), + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + // We can't compare the strings directly because the object fields be + // printed in a different order. + assert_eq!(a.clone(), a.to_string().parse().unwrap()); + assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap()); + } + + #[test] + fn test_write_enum() { + let animal = Dog; + assert_eq!( + format!("{}", super::as_json(&animal)), + "\"Dog\"" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "\"Dog\"" + ); + + let animal = Frog("Henry".to_string(), 349); + assert_eq!( + format!("{}", super::as_json(&animal)), + "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "{\n \ + \"variant\": \"Frog\",\n \ + \"fields\": [\n \ + \"Henry\",\n \ + 349\n \ + ]\n\ + }" + ); + } + + macro_rules! check_encoder_for_simple { + ($value:expr, $expected:expr) => ({ + let s = format!("{}", super::as_json(&$value)); + assert_eq!(s, $expected); + + let s = format!("{}", super::as_pretty_json(&$value)); + assert_eq!(s, $expected); + }) + } + + #[test] + fn test_write_some() { + check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\""); + } + + #[test] + fn test_write_none() { + check_encoder_for_simple!(None::, "null"); + } + + #[test] + fn test_write_char() { + check_encoder_for_simple!('a', "\"a\""); + check_encoder_for_simple!('\t', "\"\\t\""); + check_encoder_for_simple!('\u{0000}', "\"\\u0000\""); + check_encoder_for_simple!('\u{001b}', "\"\\u001b\""); + check_encoder_for_simple!('\u{007f}', "\"\\u007f\""); + check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\""); + check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\""); + check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\""); + } + + #[test] + fn test_trailing_characters() { + assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + } + + #[test] + fn test_read_identifiers() { + assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3))); + + assert_eq!(from_str("null"), Ok(Null)); + assert_eq!(from_str("true"), Ok(Boolean(true))); + assert_eq!(from_str("false"), Ok(Boolean(false))); + assert_eq!(from_str(" null "), Ok(Null)); + assert_eq!(from_str(" true "), Ok(Boolean(true))); + assert_eq!(from_str(" false "), Ok(Boolean(false))); + } + + #[test] + fn test_decode_identifiers() { + let v: () = super::decode("null").unwrap(); + assert_eq!(v, ()); + + let v: bool = super::decode("true").unwrap(); + assert_eq!(v, true); + + let v: bool = super::decode("false").unwrap(); + assert_eq!(v, false); + } + + #[test] + fn test_read_number() { + assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4))); + + assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20))); + assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21))); + + assert_eq!(from_str("3"), Ok(U64(3))); + assert_eq!(from_str("3.1"), Ok(F64(3.1))); + assert_eq!(from_str("-1.2"), Ok(F64(-1.2))); + assert_eq!(from_str("0.4"), Ok(F64(0.4))); + assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5))); + assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15))); + assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01))); + assert_eq!(from_str(" 3 "), Ok(U64(3))); + + assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN))); + assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64))); + assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX))); + } + + #[test] + fn test_decode_numbers() { + let v: f64 = super::decode("3").unwrap(); + assert_eq!(v, 3.0); + + let v: f64 = super::decode("3.1").unwrap(); + assert_eq!(v, 3.1); + + let v: f64 = super::decode("-1.2").unwrap(); + assert_eq!(v, -1.2); + + let v: f64 = super::decode("0.4").unwrap(); + assert_eq!(v, 0.4); + + let v: f64 = super::decode("0.4e5").unwrap(); + assert_eq!(v, 0.4e5); + + let v: f64 = super::decode("0.4e15").unwrap(); + assert_eq!(v, 0.4e15); + + let v: f64 = super::decode("0.4e-01").unwrap(); + assert_eq!(v, 0.4e-01); + + let v: u64 = super::decode("0").unwrap(); + assert_eq!(v, 0); + + let v: u64 = super::decode("18446744073709551615").unwrap(); + assert_eq!(v, u64::MAX); + + let v: i64 = super::decode("-9223372036854775808").unwrap(); + assert_eq!(v, i64::MIN); + + let v: i64 = super::decode("9223372036854775807").unwrap(); + assert_eq!(v, i64::MAX); + + let res: DecodeResult = super::decode("765.25252"); + assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25252".to_string()))); + } + + #[test] + fn test_read_str() { + assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2))); + assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5))); + + assert_eq!(from_str("\"\""), Ok(String("".to_string()))); + assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string()))); + assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string()))); + assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string()))); + assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string()))); + assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string()))); + assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string()))); + assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string()))); + } + + #[test] + fn test_decode_str() { + let s = [("\"\"", ""), + ("\"foo\"", "foo"), + ("\"\\\"\"", "\""), + ("\"\\b\"", "\x08"), + ("\"\\n\"", "\n"), + ("\"\\r\"", "\r"), + ("\"\\t\"", "\t"), + ("\"\\u12ab\"", "\u{12ab}"), + ("\"\\uAB12\"", "\u{AB12}")]; + + for &(i, o) in s.iter() { + let v: string::String = super::decode(i).unwrap(); + assert_eq!(v, o); + } + } + + #[test] + fn test_read_array() { + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + assert_eq!(from_str("[]"), Ok(Array(vec![]))); + assert_eq!(from_str("[ ]"), Ok(Array(vec![]))); + assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)]))); + assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)]))); + assert_eq!(from_str("[null]"), Ok(Array(vec![Null]))); + assert_eq!(from_str("[3, 1]"), + Ok(Array(vec![U64(3), U64(1)]))); + assert_eq!(from_str("\n[3, 2]\n"), + Ok(Array(vec![U64(3), U64(2)]))); + assert_eq!(from_str("[2, [4, 1]]"), + Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])]))); + } + + #[test] + fn test_decode_array() { + let v: Vec<()> = super::decode("[]").unwrap(); + assert_eq!(v, vec![]); + + let v: Vec<()> = super::decode("[null]").unwrap(); + assert_eq!(v, vec![()]); + + let v: Vec = super::decode("[true]").unwrap(); + assert_eq!(v, vec![true]); + + let v: Vec = super::decode("[3, 1]").unwrap(); + assert_eq!(v, vec![3, 1]); + + let v: Vec> = super::decode("[[3], [1, 2]]").unwrap(); + assert_eq!(v, vec![vec![3], vec![1, 2]]); + } + + #[test] + fn test_decode_tuple() { + let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap(); + assert_eq!(t, (1u, 2, 3)); + + let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap(); + assert_eq!(t, (1u, "two".to_string())); + } + + #[test] + fn test_decode_tuple_malformed_types() { + assert!(super::decode::<(uint, string::String)>("[1, 2]").is_err()); + } + + #[test] + fn test_decode_tuple_malformed_length() { + assert!(super::decode::<(uint, uint)>("[1, 2, 3]").is_err()); + } + + #[test] + fn test_read_object() { + assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2))); + assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8))); + + assert_eq!(from_str("{}").unwrap(), mk_object(&[])); + assert_eq!(from_str("{\"a\": 3}").unwrap(), + mk_object(&[("a".to_string(), U64(3))])); + + assert_eq!(from_str( + "{ \"a\": null, \"b\" : true }").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str( + "{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![Boolean(true)])) + ])); + assert_eq!(from_str( + "{\ + \"a\": 1.0, \ + \"b\": [\ + true,\ + \"foo\\nbar\", \ + { \"c\": {\"d\": null} } \ + ]\ + }").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![ + Boolean(true), + String("foo\nbar".to_string()), + mk_object(&[ + ("c".to_string(), mk_object(&[("d".to_string(), Null)])) + ]) + ])) + ])); + } + + #[test] + fn test_decode_struct() { + let s = "{ + \"inner\": [ + { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + ] + }"; + + let v: Outer = super::decode(s).unwrap(); + assert_eq!( + v, + Outer { + inner: vec![ + Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] } + ] + } + ); + } + + #[derive(RustcDecodable)] + struct FloatStruct { + f: f64, + a: Vec + } + #[test] + fn test_decode_struct_with_nan() { + let s = "{\"f\":null,\"a\":[null,123]}"; + let obj: FloatStruct = super::decode(s).unwrap(); + assert!(obj.f.is_nan()); + assert!(obj.a[0].is_nan()); + assert_eq!(obj.a[1], 123f64); + } + + #[test] + fn test_decode_option() { + let value: Option = super::decode("null").unwrap(); + assert_eq!(value, None); + + let value: Option = super::decode("\"jodhpurs\"").unwrap(); + assert_eq!(value, Some("jodhpurs".to_string())); + } + + #[test] + fn test_decode_enum() { + let value: Animal = super::decode("\"Dog\"").unwrap(); + assert_eq!(value, Dog); + + let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"; + let value: Animal = super::decode(s).unwrap(); + assert_eq!(value, Frog("Henry".to_string(), 349)); + } + + #[test] + fn test_decode_map() { + let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\ + \"fields\":[\"Henry\", 349]}}"; + let mut map: BTreeMap = super::decode(s).unwrap(); + + assert_eq!(map.remove(&"a".to_string()), Some(Dog)); + assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349))); + } + + #[test] + fn test_multiline_errors() { + assert_eq!(from_str("{\n \"foo\":\n \"bar\""), + Err(SyntaxError(EOFWhileParsingObject, 3u, 8u))); + } + + #[derive(RustcDecodable)] + #[allow(dead_code)] + struct DecodeStruct { + x: f64, + y: bool, + z: string::String, + w: Vec + } + #[derive(RustcDecodable)] + enum DecodeEnum { + A(f64), + B(string::String) + } + fn check_err>(to_parse: &'static str, + expected: DecoderError) { + let res: DecodeResult = match from_str(to_parse) { + Err(e) => Err(ParseError(e)), + Ok(json) => Decodable::decode(&mut Decoder::new(json)) + }; + match res { + Ok(_) => panic!("`{}` parsed & decoded ok, expecting error `{}`", + to_parse, expected), + Err(ParseError(e)) => panic!("`{}` is not valid json: {}", + to_parse, e), + Err(e) => { + assert_eq!(e, expected); + } + } + } + #[test] + fn test_decode_errors_struct() { + check_err::("[]", ExpectedError("Object".to_string(), "[]".to_string())); + check_err::("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}", + ExpectedError("Number".to_string(), "true".to_string())); + check_err::("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}", + ExpectedError("Boolean".to_string(), "[]".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}", + ExpectedError("String".to_string(), "{}".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\"}", + MissingFieldError("w".to_string())); + } + #[test] + fn test_decode_errors_enum() { + check_err::("{}", + MissingFieldError("variant".to_string())); + check_err::("{\"variant\": 1}", + ExpectedError("String".to_string(), "1".to_string())); + check_err::("{\"variant\": \"A\"}", + MissingFieldError("fields".to_string())); + check_err::("{\"variant\": \"A\", \"fields\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"variant\": \"C\", \"fields\": []}", + UnknownVariantError("C".to_string())); + } + + #[test] + fn test_find(){ + let json_value = from_str("{\"dog\" : \"cat\"}").unwrap(); + let found_str = json_value.find("dog"); + assert!(found_str.unwrap().as_string().unwrap() == "cat"); + } + + #[test] + fn test_find_path(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.find_path(&["dog", "cat", "mouse"]); + assert!(found_str.unwrap().as_string().unwrap() == "cheese"); + } + + #[test] + fn test_search(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.search("mouse").and_then(|j| j.as_string()); + assert!(found_str.unwrap() == "cheese"); + } + + #[test] + fn test_index(){ + let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap(); + let ref array = json_value["animals"]; + assert_eq!(array[0].as_string().unwrap(), "dog"); + assert_eq!(array[1].as_string().unwrap(), "cat"); + assert_eq!(array[2].as_string().unwrap(), "mouse"); + } + + #[test] + fn test_is_object(){ + let json_value = from_str("{}").unwrap(); + assert!(json_value.is_object()); + } + + #[test] + fn test_as_object(){ + let json_value = from_str("{}").unwrap(); + let json_object = json_value.as_object(); + assert!(json_object.is_some()); + } + + #[test] + fn test_is_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + assert!(json_value.is_array()); + } + + #[test] + fn test_as_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + let json_array = json_value.as_array(); + let expected_length = 3; + assert!(json_array.is_some() && json_array.unwrap().len() == expected_length); + } + + #[test] + fn test_is_string(){ + let json_value = from_str("\"dog\"").unwrap(); + assert!(json_value.is_string()); + } + + #[test] + fn test_as_string(){ + let json_value = from_str("\"dog\"").unwrap(); + let json_str = json_value.as_string(); + let expected_str = "dog"; + assert_eq!(json_str, Some(expected_str)); + } + + #[test] + fn test_is_number(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_number()); + } + + #[test] + fn test_is_i64(){ + let json_value = from_str("-12").unwrap(); + assert!(json_value.is_i64()); + + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_i64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_i64()); + } + + #[test] + fn test_is_u64(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_u64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_u64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_u64()); + } + + #[test] + fn test_is_f64(){ + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("12.0").unwrap(); + assert!(json_value.is_f64()); + + let json_value = from_str("-12.0").unwrap(); + assert!(json_value.is_f64()); + } + + #[test] + fn test_as_i64(){ + let json_value = from_str("-12").unwrap(); + let json_num = json_value.as_i64(); + assert_eq!(json_num, Some(-12)); + } + + #[test] + fn test_as_u64(){ + let json_value = from_str("12").unwrap(); + let json_num = json_value.as_u64(); + assert_eq!(json_num, Some(12)); + } + + #[test] + fn test_as_f64(){ + let json_value = from_str("12.0").unwrap(); + let json_num = json_value.as_f64(); + assert_eq!(json_num, Some(12f64)); + } + + #[test] + fn test_is_boolean(){ + let json_value = from_str("false").unwrap(); + assert!(json_value.is_boolean()); + } + + #[test] + fn test_as_boolean(){ + let json_value = from_str("false").unwrap(); + let json_bool = json_value.as_boolean(); + let expected_bool = false; + assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool); + } + + #[test] + fn test_is_null(){ + let json_value = from_str("null").unwrap(); + assert!(json_value.is_null()); + } + + #[test] + fn test_as_null(){ + let json_value = from_str("null").unwrap(); + let json_null = json_value.as_null(); + let expected_null = (); + assert!(json_null.is_some() && json_null.unwrap() == expected_null); + } + + #[test] + fn test_encode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencoder_indent_level_param() { + use std::str::from_utf8; + use std::collections::BTreeMap; + + let mut tree = BTreeMap::new(); + + tree.insert("hello".to_string(), String("guten tag".to_string())); + tree.insert("goodbye".to_string(), String("sayonara".to_string())); + + let json = Array( + // The following layout below should look a lot like + // the pretty-printed JSON (indent * x) + vec! + ( // 0x + String("greetings".to_string()), // 1x + Object(tree), // 1x + 2x + 2x + 1x + ) // 0x + // End JSON array (7 lines) + ); + + // Helper function for counting indents + fn indents(source: &str) -> uint { + let trimmed = source.trim_left_matches(' '); + source.len() - trimmed.len() + } + + // Test up to 4 spaces of indents (more?) + for i in range(0, 4u) { + let mut writer = Vec::new(); + write!(&mut writer, "{}", + super::as_pretty_json(&json).indent(i)).unwrap(); + + let printed = from_utf8(writer[]).unwrap(); + + // Check for indents at each line + let lines: Vec<&str> = printed.lines().collect(); + assert_eq!(lines.len(), 7); // JSON should be 7 lines + + assert_eq!(indents(lines[0]), 0 * i); // [ + assert_eq!(indents(lines[1]), 1 * i); // "greetings", + assert_eq!(indents(lines[2]), 1 * i); // { + assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag", + assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara" + assert_eq!(indents(lines[5]), 1 * i); // }, + assert_eq!(indents(lines[6]), 0 * i); // ] + + // Finally, test that the pretty-printed JSON is valid + from_str(printed).ok().expect("Pretty-printed JSON is invalid!"); + } + } + + #[test] + fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"1\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let _hm: HashMap = Decodable::decode(&mut decoder).unwrap(); + } + + #[test] + fn test_hashmap_with_numeric_key_will_error_with_string_keys() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"a\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let result: Result, DecoderError> = Decodable::decode(&mut decoder); + assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string()))); + } + + fn assert_stream_equal(src: &str, + expected: Vec<(JsonEvent, Vec)>) { + let mut parser = Parser::new(src.chars()); + let mut i = 0; + loop { + let evt = match parser.next() { + Some(e) => e, + None => { break; } + }; + let (ref expected_evt, ref expected_stack) = expected[i]; + if !parser.stack().is_equal_to(expected_stack.as_slice()) { + panic!("Parser stack is not equal to {}", expected_stack); + } + assert_eq!(&evt, expected_evt); + i+=1; + } + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_streaming_parser() { + assert_stream_equal( + r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#, + vec![ + (ObjectStart, vec![]), + (StringValue("bar".to_string()), vec![Key("foo")]), + (ArrayStart, vec![Key("array")]), + (U64Value(0), vec![Key("array"), Index(0)]), + (U64Value(1), vec![Key("array"), Index(1)]), + (U64Value(2), vec![Key("array"), Index(2)]), + (U64Value(3), vec![Key("array"), Index(3)]), + (U64Value(4), vec![Key("array"), Index(4)]), + (U64Value(5), vec![Key("array"), Index(5)]), + (ArrayEnd, vec![Key("array")]), + (ArrayStart, vec![Key("idents")]), + (NullValue, vec![Key("idents"), Index(0)]), + (BooleanValue(true), vec![Key("idents"), Index(1)]), + (BooleanValue(false), vec![Key("idents"), Index(2)]), + (ArrayEnd, vec![Key("idents")]), + (ObjectEnd, vec![]), + ] + ); + } + fn last_event(src: &str) -> JsonEvent { + let mut parser = Parser::new(src.chars()); + let mut evt = NullValue; + loop { + evt = match parser.next() { + Some(e) => e, + None => return evt, + } + } + } + + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_object_streaming() { + assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8))); + assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8))); + + assert_stream_equal( + "{}", + vec![(ObjectStart, vec![]), (ObjectEnd, vec![])] + ); + assert_stream_equal( + "{\"a\": 3}", + vec![ + (ObjectStart, vec![]), + (U64Value(3), vec![Key("a")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{ \"a\": null, \"b\" : true }", + vec![ + (ObjectStart, vec![]), + (NullValue, vec![Key("a")]), + (BooleanValue(true), vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{\"a\" : 1.0 ,\"b\": [ true ]}", + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true),vec![Key("b"), Index(0)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#, + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true), vec![Key("b"), Index(0)]), + (StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]), + (ObjectStart, vec![Key("b"), Index(2)]), + (ObjectStart, vec![Key("b"), Index(2), Key("c")]), + (NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]), + (ObjectEnd, vec![Key("b"), Index(2), Key("c")]), + (ObjectEnd, vec![Key("b"), Index(2)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_array_streaming() { + assert_stream_equal( + "[]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ ]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[true]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(true), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ false ]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(false), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[null]", + vec![ + (ArrayStart, vec![]), + (NullValue, vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[3, 1]", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(1), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "\n[3, 2]\n", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(2), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[2, [4, 1]]", + vec![ + (ArrayStart, vec![]), + (U64Value(2), vec![Index(0)]), + (ArrayStart, vec![Index(1)]), + (U64Value(4), vec![Index(1), Index(0)]), + (U64Value(1), vec![Index(1), Index(1)]), + (ArrayEnd, vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + + assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2))); + + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + } + #[test] + fn test_trailing_characters_streaming() { + assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + } + #[test] + fn test_read_identifiers_streaming() { + assert_eq!(Parser::new("null".chars()).next(), Some(NullValue)); + assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true))); + assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false))); + + assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3))); + } + + #[test] + fn test_stack() { + let mut stack = Stack::new(); + + assert!(stack.is_empty()); + assert!(stack.len() == 0); + assert!(!stack.last_is_index()); + + stack.push_index(0); + stack.bump_index(); + + assert!(stack.len() == 1); + assert!(stack.is_equal_to(&[Index(1)])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1)])); + assert!(stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + + stack.push_key("foo".to_string()); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + + stack.push_key("bar".to_string()); + + assert!(stack.len() == 3); + assert!(stack.is_equal_to(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Key("bar")])); + assert!(stack.ends_with(&[Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + assert!(stack.get(2) == Key("bar")); + + stack.pop(); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + } + + #[test] + fn test_to_json() { + use std::collections::{HashMap,BTreeMap}; + use super::ToJson; + + let array2 = Array(vec!(U64(1), U64(2))); + let array3 = Array(vec!(U64(1), U64(2), U64(3))); + let object = { + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), U64(1)); + tree_map.insert("b".to_string(), U64(2)); + Object(tree_map) + }; + + assert_eq!(array2.to_json(), array2); + assert_eq!(object.to_json(), object); + assert_eq!(3_i.to_json(), I64(3)); + assert_eq!(4_i8.to_json(), I64(4)); + assert_eq!(5_i16.to_json(), I64(5)); + assert_eq!(6_i32.to_json(), I64(6)); + assert_eq!(7_i64.to_json(), I64(7)); + assert_eq!(8_u.to_json(), U64(8)); + assert_eq!(9_u8.to_json(), U64(9)); + assert_eq!(10_u16.to_json(), U64(10)); + assert_eq!(11_u32.to_json(), U64(11)); + assert_eq!(12_u64.to_json(), U64(12)); + assert_eq!(13.0_f32.to_json(), F64(13.0_f64)); + assert_eq!(14.0_f64.to_json(), F64(14.0_f64)); + assert_eq!(().to_json(), Null); + assert_eq!(f32::INFINITY.to_json(), Null); + assert_eq!(f64::NAN.to_json(), Null); + assert_eq!(true.to_json(), Boolean(true)); + assert_eq!(false.to_json(), Boolean(false)); + assert_eq!("abc".to_json(), String("abc".to_string())); + assert_eq!("abc".to_string().to_json(), String("abc".to_string())); + assert_eq!((1u, 2u).to_json(), array2); + assert_eq!((1u, 2u, 3u).to_json(), array3); + assert_eq!([1u, 2].to_json(), array2); + assert_eq!((&[1u, 2, 3]).to_json(), array3); + assert_eq!((vec![1u, 2]).to_json(), array2); + assert_eq!(vec!(1u, 2, 3).to_json(), array3); + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), 1u); + tree_map.insert("b".to_string(), 2); + assert_eq!(tree_map.to_json(), object); + let mut hash_map = HashMap::new(); + hash_map.insert("a".to_string(), 1u); + hash_map.insert("b".to_string(), 2); + assert_eq!(hash_map.to_json(), object); + assert_eq!(Some(15i).to_json(), I64(15)); + assert_eq!(Some(15u).to_json(), U64(15)); + assert_eq!(None::.to_json(), Null); + } + + #[bench] + fn bench_streaming_small(b: &mut Bencher) { + b.iter( || { + let mut parser = Parser::new( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#.chars() + ); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_small(b: &mut Bencher) { + b.iter( || { + let _ = from_str(r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#); + }); + } + + fn big_json() -> string::String { + let mut src = "[\n".to_string(); + for _ in range(0i, 500) { + src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ + [1,2,3]},"#); + } + src.push_str("{}]"); + return src; + } + + #[bench] + fn bench_streaming_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { + let mut parser = Parser::new(src.chars()); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { let _ = from_str(src.as_slice()); }); + } +} diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 1ec6a2af309..8ad2013f936 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -40,11 +40,25 @@ pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, DecoderHelpers, EncoderHelpers}; +#[cfg(stage0)] +#[path = "serialize_stage0.rs"] mod serialize; +#[cfg(not(stage0))] +mod serialize; + +#[cfg(stage0)] +#[path = "collection_impls_stage0.rs"] +mod collection_impls; +#[cfg(not(stage0))] mod collection_impls; pub mod base64; pub mod hex; + +#[cfg(stage0)] +#[path = "json_stage0.rs"] +pub mod json; +#[cfg(not(stage0))] pub mod json; mod rustc_serialize { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 558f9e603e1..0646ee1758f 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -19,406 +19,424 @@ use std::cell::{Cell, RefCell}; use std::sync::Arc; -pub trait Encoder { +pub trait Encoder { + type Error; + // Primitive types: - fn emit_nil(&mut self) -> Result<(), E>; - fn emit_uint(&mut self, v: uint) -> Result<(), E>; - fn emit_u64(&mut self, v: u64) -> Result<(), E>; - fn emit_u32(&mut self, v: u32) -> Result<(), E>; - fn emit_u16(&mut self, v: u16) -> Result<(), E>; - fn emit_u8(&mut self, v: u8) -> Result<(), E>; - fn emit_int(&mut self, v: int) -> Result<(), E>; - fn emit_i64(&mut self, v: i64) -> Result<(), E>; - fn emit_i32(&mut self, v: i32) -> Result<(), E>; - fn emit_i16(&mut self, v: i16) -> Result<(), E>; - fn emit_i8(&mut self, v: i8) -> Result<(), E>; - fn emit_bool(&mut self, v: bool) -> Result<(), E>; - fn emit_f64(&mut self, v: f64) -> Result<(), E>; - fn emit_f32(&mut self, v: f32) -> Result<(), E>; - fn emit_char(&mut self, v: char) -> Result<(), E>; - fn emit_str(&mut self, v: &str) -> Result<(), E>; + fn emit_nil(&mut self) -> Result<(), Self::Error>; + fn emit_uint(&mut self, v: uint) -> Result<(), Self::Error>; + fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; + fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; + fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; + fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; + fn emit_int(&mut self, v: int) -> Result<(), Self::Error>; + fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; + fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; + fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; + fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>; + fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>; + fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>; + fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>; + fn emit_char(&mut self, v: char) -> Result<(), Self::Error>; + fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>; // Compound types: - fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant_field(&mut self, f_name: &str, f_idx: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_option_none(&mut self) -> Result<(), Self::Error>; + fn emit_option_some(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnMut(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; +} - fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; +pub trait Decoder { + type Error; - // Specialized types: - fn emit_option(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_option_none(&mut self) -> Result<(), E>; - fn emit_option_some(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnMut(&mut Self) -> Result<(), E>; - fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; -} - -pub trait Decoder { // Primitive types: - fn read_nil(&mut self) -> Result<(), E>; - fn read_uint(&mut self) -> Result; - fn read_u64(&mut self) -> Result; - fn read_u32(&mut self) -> Result; - fn read_u16(&mut self) -> Result; - fn read_u8(&mut self) -> Result; - fn read_int(&mut self) -> Result; - fn read_i64(&mut self) -> Result; - fn read_i32(&mut self) -> Result; - fn read_i16(&mut self) -> Result; - fn read_i8(&mut self) -> Result; - fn read_bool(&mut self) -> Result; - fn read_f64(&mut self) -> Result; - fn read_f32(&mut self) -> Result; - fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_nil(&mut self) -> Result<(), Self::Error>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; - fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; + fn read_enum(&mut self, name: &str, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; fn read_enum_struct_variant_field(&mut self, &f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; - fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; fn read_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple(&mut self, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Specialized types: - fn read_option(&mut self, f: F) -> Result where - F: FnMut(&mut Self, bool) -> Result; - - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_map(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_option(&mut self, f: F) -> Result + where F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Failure - fn error(&mut self, err: &str) -> E; + fn error(&mut self, err: &str) -> Self::Error; } -pub trait Encodable, E> for Sized? { - fn encode(&self, s: &mut S) -> Result<(), E>; +pub trait Encodable for Sized? { + fn encode(&self, s: &mut S) -> Result<(), S::Error>; } -pub trait Decodable, E> { - fn decode(d: &mut D) -> Result; +pub trait Decodable { + fn decode(d: &mut D) -> Result; } -impl> Encodable for uint { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_uint(*self) } } -impl> Decodable for uint { - fn decode(d: &mut D) -> Result { +impl Decodable for uint { + fn decode(d: &mut D) -> Result { d.read_uint() } } -impl> Encodable for u8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u8(*self) } } -impl> Decodable for u8 { - fn decode(d: &mut D) -> Result { +impl Decodable for u8 { + fn decode(d: &mut D) -> Result { d.read_u8() } } -impl> Encodable for u16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u16(*self) } } -impl> Decodable for u16 { - fn decode(d: &mut D) -> Result { +impl Decodable for u16 { + fn decode(d: &mut D) -> Result { d.read_u16() } } -impl> Encodable for u32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(*self) } } -impl> Decodable for u32 { - fn decode(d: &mut D) -> Result { +impl Decodable for u32 { + fn decode(d: &mut D) -> Result { d.read_u32() } } -impl> Encodable for u64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u64(*self) } } -impl> Decodable for u64 { - fn decode(d: &mut D) -> Result { +impl Decodable for u64 { + fn decode(d: &mut D) -> Result { d.read_u64() } } -impl> Encodable for int { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_int(*self) } } -impl> Decodable for int { - fn decode(d: &mut D) -> Result { +impl Decodable for int { + fn decode(d: &mut D) -> Result { d.read_int() } } -impl> Encodable for i8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i8(*self) } } -impl> Decodable for i8 { - fn decode(d: &mut D) -> Result { +impl Decodable for i8 { + fn decode(d: &mut D) -> Result { d.read_i8() } } -impl> Encodable for i16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i16(*self) } } -impl> Decodable for i16 { - fn decode(d: &mut D) -> Result { +impl Decodable for i16 { + fn decode(d: &mut D) -> Result { d.read_i16() } } -impl> Encodable for i32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i32(*self) } } -impl> Decodable for i32 { - fn decode(d: &mut D) -> Result { +impl Decodable for i32 { + fn decode(d: &mut D) -> Result { d.read_i32() } } -impl> Encodable for i64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i64(*self) } } -impl> Decodable for i64 { - fn decode(d: &mut D) -> Result { +impl Decodable for i64 { + fn decode(d: &mut D) -> Result { d.read_i64() } } -impl> Encodable for str { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self) } } -impl> Encodable for String { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self[]) } } -impl> Decodable for String { - fn decode(d: &mut D) -> Result { +impl Decodable for String { + fn decode(d: &mut D) -> Result { d.read_str() } } -impl> Encodable for f32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f32(*self) } } -impl> Decodable for f32 { - fn decode(d: &mut D) -> Result { +impl Decodable for f32 { + fn decode(d: &mut D) -> Result { d.read_f32() } } -impl> Encodable for f64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f64(*self) } } -impl> Decodable for f64 { - fn decode(d: &mut D) -> Result { +impl Decodable for f64 { + fn decode(d: &mut D) -> Result { d.read_f64() } } -impl> Encodable for bool { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_bool(*self) } } -impl> Decodable for bool { - fn decode(d: &mut D) -> Result { +impl Decodable for bool { + fn decode(d: &mut D) -> Result { d.read_bool() } } -impl> Encodable for char { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_char(*self) } } -impl> Decodable for char { - fn decode(d: &mut D) -> Result { +impl Decodable for char { + fn decode(d: &mut D) -> Result { d.read_char() } } -impl> Encodable for () { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_nil() } } -impl> Decodable for () { - fn decode(d: &mut D) -> Result<(), E> { +impl Decodable for () { + fn decode(d: &mut D) -> Result<(), D::Error> { d.read_nil() } } -impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl<'a, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, Sized? T: Encodable> Encodable for Box { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, T: Decodable> Decodable for Box { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, D::Error> { Ok(box try!(Decodable::decode(d))) } } -impl, T: Decodable> Decodable for Box<[T]> { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, D::Error> { let v: Vec = try!(Decodable::decode(d)); Ok(v.into_boxed_slice()) } } -impl,T:Encodable> Encodable for Rc { +impl Encodable for Rc { #[inline] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable> Decodable for Rc { +impl Decodable for Rc { #[inline] - fn decode(d: &mut D) -> Result, E> { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Rc::new(try!(Decodable::decode(d)))) } } -impl,T:Encodable> Encodable for [T] { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -428,8 +446,8 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } -impl,T:Encodable> Encodable for Vec { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -439,8 +457,8 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } -impl,T:Decodable> Decodable for Vec { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Vec { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); for i in range(0, len) { @@ -451,8 +469,8 @@ fn decode(d: &mut D) -> Result, E> { } } -impl,T:Encodable> Encodable for Option { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_option(|s| { match *self { None => s.emit_option_none(), @@ -462,8 +480,8 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } -impl,T:Decodable> Decodable for Option { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Option { + fn decode(d: &mut D) -> Result, D::Error> { d.read_option(|d, b| { if b { Ok(Some(try!(Decodable::decode(d)))) @@ -487,22 +505,23 @@ macro_rules! count_idents { macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( - impl,$($name:Decodable),*> Decodable for ($($name,)*) { + impl<$($name:Decodable),*> Decodable for ($($name,)*) { #[allow(non_snake_case)] - fn decode(d: &mut D) -> Result<($($name,)*), E> { + fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { let len: uint = count_idents!($($name),*); d.read_tuple(len, |d| { let mut i = 0; - let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, + |d| -> Result<$name,D::Error> { Decodable::decode(d) })),)*); return Ok(ret); }) } } - impl,$($name:Encodable),*> Encodable for ($($name,)*) { + impl<$($name:Encodable),*> Encodable for ($($name,)*) { #[allow(non_snake_case)] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let ($(ref $name,)*) = *self; let mut n = 0; $(let $name = $name; n += 1;)* @@ -519,40 +538,40 @@ fn encode(&self, s: &mut S) -> Result<(), E> { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl> Encodable for path::posix::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::posix::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::posix::Path::new(bytes)) } } -impl> Encodable for path::windows::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::windows::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::windows::Path::new(bytes)) } } -impl, T: Encodable + Copy> Encodable for Cell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.get().encode(s) } } -impl, T: Decodable + Copy> Decodable for Cell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Cell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Cell::new(try!(Decodable::decode(d)))) } } @@ -562,26 +581,26 @@ fn decode(d: &mut D) -> Result, E> { // `encoder.error("attempting to Encode borrowed RefCell")` // from `encode` when `try_borrow` returns `None`. -impl, T: Encodable> Encodable for RefCell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.borrow().encode(s) } } -impl, T: Decodable> Decodable for RefCell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RefCell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(RefCell::new(try!(Decodable::decode(d)))) } } -impl, T:Encodable> Encodable for Arc { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable+Send+Sync> Decodable for Arc { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Arc { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Arc::new(try!(Decodable::decode(d)))) } } @@ -589,14 +608,15 @@ fn decode(d: &mut D) -> Result, E> { // ___________________________________________________________________________ // Helper routines -pub trait EncoderHelpers { - fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where - F: FnMut(&mut Self, &T) -> Result<(), E>; +pub trait EncoderHelpers: Encoder { + fn emit_from_vec(&mut self, v: &[T], f: F) + -> Result<(), ::Error> + where F: FnMut(&mut Self, &T) -> Result<(), ::Error>; } -impl> EncoderHelpers for S { - fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where - F: FnMut(&mut S, &T) -> Result<(), E>, +impl EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where + F: FnMut(&mut S, &T) -> Result<(), S::Error>, { self.emit_seq(v.len(), |this| { for (i, e) in v.iter().enumerate() { @@ -609,14 +629,15 @@ fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where } } -pub trait DecoderHelpers { - fn read_to_vec(&mut self, f: F) -> Result, E> where - F: FnMut(&mut Self) -> Result; +pub trait DecoderHelpers: Decoder { + fn read_to_vec(&mut self, f: F) + -> Result, ::Error> where + F: FnMut(&mut Self) -> Result::Error>; } -impl> DecoderHelpers for D { - fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: - FnMut(&mut D) -> Result, +impl DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, D::Error> where F: + FnMut(&mut D) -> Result, { self.read_seq(|this, len| { let mut v = Vec::with_capacity(len); diff --git a/src/libserialize/serialize_stage0.rs b/src/libserialize/serialize_stage0.rs new file mode 100644 index 00000000000..558f9e603e1 --- /dev/null +++ b/src/libserialize/serialize_stage0.rs @@ -0,0 +1,629 @@ +// Copyright 2012-2014 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. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +use std::path; +use std::rc::Rc; +use std::cell::{Cell, RefCell}; +use std::sync::Arc; + +pub trait Encoder { + // Primitive types: + fn emit_nil(&mut self) -> Result<(), E>; + fn emit_uint(&mut self, v: uint) -> Result<(), E>; + fn emit_u64(&mut self, v: u64) -> Result<(), E>; + fn emit_u32(&mut self, v: u32) -> Result<(), E>; + fn emit_u16(&mut self, v: u16) -> Result<(), E>; + fn emit_u8(&mut self, v: u8) -> Result<(), E>; + fn emit_int(&mut self, v: int) -> Result<(), E>; + fn emit_i64(&mut self, v: i64) -> Result<(), E>; + fn emit_i32(&mut self, v: i32) -> Result<(), E>; + fn emit_i16(&mut self, v: i16) -> Result<(), E>; + fn emit_i8(&mut self, v: i8) -> Result<(), E>; + fn emit_bool(&mut self, v: bool) -> Result<(), E>; + fn emit_f64(&mut self, v: f64) -> Result<(), E>; + fn emit_f32(&mut self, v: f32) -> Result<(), E>; + fn emit_char(&mut self, v: char) -> Result<(), E>; + fn emit_str(&mut self, v: &str) -> Result<(), E>; + + // Compound types: + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_struct_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_option_none(&mut self) -> Result<(), E>; + fn emit_option_some(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnMut(&mut Self) -> Result<(), E>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; +} + +pub trait Decoder { + // Primitive types: + fn read_nil(&mut self) -> Result<(), E>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Specialized types: + fn read_option(&mut self, f: F) -> Result where + F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Failure + fn error(&mut self, err: &str) -> E; +} + +pub trait Encodable, E> for Sized? { + fn encode(&self, s: &mut S) -> Result<(), E>; +} + +pub trait Decodable, E> { + fn decode(d: &mut D) -> Result; +} + +impl> Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_uint(*self) + } +} + +impl> Decodable for uint { + fn decode(d: &mut D) -> Result { + d.read_uint() + } +} + +impl> Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u8(*self) + } +} + +impl> Decodable for u8 { + fn decode(d: &mut D) -> Result { + d.read_u8() + } +} + +impl> Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u16(*self) + } +} + +impl> Decodable for u16 { + fn decode(d: &mut D) -> Result { + d.read_u16() + } +} + +impl> Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u32(*self) + } +} + +impl> Decodable for u32 { + fn decode(d: &mut D) -> Result { + d.read_u32() + } +} + +impl> Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u64(*self) + } +} + +impl> Decodable for u64 { + fn decode(d: &mut D) -> Result { + d.read_u64() + } +} + +impl> Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_int(*self) + } +} + +impl> Decodable for int { + fn decode(d: &mut D) -> Result { + d.read_int() + } +} + +impl> Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i8(*self) + } +} + +impl> Decodable for i8 { + fn decode(d: &mut D) -> Result { + d.read_i8() + } +} + +impl> Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i16(*self) + } +} + +impl> Decodable for i16 { + fn decode(d: &mut D) -> Result { + d.read_i16() + } +} + +impl> Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i32(*self) + } +} + +impl> Decodable for i32 { + fn decode(d: &mut D) -> Result { + d.read_i32() + } +} + +impl> Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i64(*self) + } +} + +impl> Decodable for i64 { + fn decode(d: &mut D) -> Result { + d.read_i64() + } +} + +impl> Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self) + } +} + +impl> Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self[]) + } +} + +impl> Decodable for String { + fn decode(d: &mut D) -> Result { + d.read_str() + } +} + +impl> Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f32(*self) + } +} + +impl> Decodable for f32 { + fn decode(d: &mut D) -> Result { + d.read_f32() + } +} + +impl> Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f64(*self) + } +} + +impl> Decodable for f64 { + fn decode(d: &mut D) -> Result { + d.read_f64() + } +} + +impl> Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_bool(*self) + } +} + +impl> Decodable for bool { + fn decode(d: &mut D) -> Result { + d.read_bool() + } +} + +impl> Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_char(*self) + } +} + +impl> Decodable for char { + fn decode(d: &mut D) -> Result { + d.read_char() + } +} + +impl> Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_nil() + } +} + +impl> Decodable for () { + fn decode(d: &mut D) -> Result<(), E> { + d.read_nil() + } +} + +impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, Sized? T: Encodable> Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, E> { + Ok(box try!(Decodable::decode(d))) + } +} + +impl, T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, E> { + let v: Vec = try!(Decodable::decode(d)); + Ok(v.into_boxed_slice()) + } +} + +impl,T:Encodable> Encodable for Rc { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable> Decodable for Rc { + #[inline] + fn decode(d: &mut D) -> Result, E> { + Ok(Rc::new(try!(Decodable::decode(d)))) + } +} + +impl,T:Encodable> Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Encodable> Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for Vec { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(v) + }) + } +} + +impl,T:Encodable> Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_option(|s| { + match *self { + None => s.emit_option_none(), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), + } + }) + } +} + +impl,T:Decodable> Decodable for Option { + fn decode(d: &mut D) -> Result, E> { + d.read_option(|d, b| { + if b { + Ok(Some(try!(Decodable::decode(d)))) + } else { + Ok(None) + } + }) + } +} + +macro_rules! peel { + ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* }) +} + +/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3 +macro_rules! count_idents { + () => { 0u }; + ($_i:ident $(, $rest:ident)*) => { 1 + count_idents!($($rest),*) } +} + +macro_rules! tuple { + () => (); + ( $($name:ident,)+ ) => ( + impl,$($name:Decodable),*> Decodable for ($($name,)*) { + #[allow(non_snake_case)] + fn decode(d: &mut D) -> Result<($($name,)*), E> { + let len: uint = count_idents!($($name),*); + d.read_tuple(len, |d| { + let mut i = 0; + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + Decodable::decode(d) + })),)*); + return Ok(ret); + }) + } + } + impl,$($name:Encodable),*> Encodable for ($($name,)*) { + #[allow(non_snake_case)] + fn encode(&self, s: &mut S) -> Result<(), E> { + let ($(ref $name,)*) = *self; + let mut n = 0; + $(let $name = $name; n += 1;)* + s.emit_tuple(n, |s| { + let mut i = 0; + $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)* + Ok(()) + }) + } + } + peel! { $($name,)* } + ) +} + +tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } + +impl> Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::posix::Path::new(bytes)) + } +} + +impl> Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::windows::Path::new(bytes)) + } +} + +impl, T: Encodable + Copy> Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.get().encode(s) + } +} + +impl, T: Decodable + Copy> Decodable for Cell { + fn decode(d: &mut D) -> Result, E> { + Ok(Cell::new(try!(Decodable::decode(d)))) + } +} + +// FIXME: #15036 +// Should use `try_borrow`, returning a +// `encoder.error("attempting to Encode borrowed RefCell")` +// from `encode` when `try_borrow` returns `None`. + +impl, T: Encodable> Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.borrow().encode(s) + } +} + +impl, T: Decodable> Decodable for RefCell { + fn decode(d: &mut D) -> Result, E> { + Ok(RefCell::new(try!(Decodable::decode(d)))) + } +} + +impl, T:Encodable> Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable+Send+Sync> Decodable for Arc { + fn decode(d: &mut D) -> Result, E> { + Ok(Arc::new(try!(Decodable::decode(d)))) + } +} + +// ___________________________________________________________________________ +// Helper routines + +pub trait EncoderHelpers { + fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where + F: FnMut(&mut Self, &T) -> Result<(), E>; +} + +impl> EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where + F: FnMut(&mut S, &T) -> Result<(), E>, + { + self.emit_seq(v.len(), |this| { + for (i, e) in v.iter().enumerate() { + try!(this.emit_seq_elt(i, |this| { + f(this, e) + })); + } + Ok(()) + }) + } +} + +pub trait DecoderHelpers { + fn read_to_vec(&mut self, f: F) -> Result, E> where + F: FnMut(&mut Self) -> Result; +} + +impl> DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: + FnMut(&mut D) -> Result, + { + self.read_seq(|this, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(this.read_seq_elt(i, |this| f(this)))); + } + Ok(v) + }) + } +} diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs deleted file mode 100644 index 9c96a9cac78..00000000000 --- a/src/libstd/c_str.rs +++ /dev/null @@ -1,857 +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. - -//! C-string manipulation and management -//! -//! This modules provides the basic methods for creating and manipulating -//! null-terminated strings for use with FFI calls (back to C). Most C APIs require -//! that the string being passed to them is null-terminated, and by default rust's -//! string types are *not* null terminated. -//! -//! The other problem with translating Rust strings to C strings is that Rust -//! strings can validly contain a null-byte in the middle of the string (0 is a -//! valid Unicode codepoint). This means that not all Rust strings can actually be -//! translated to C strings. -//! -//! # Creation of a C string -//! -//! A C string is managed through the `CString` type defined in this module. It -//! "owns" the internal buffer of characters and will automatically deallocate the -//! buffer when the string is dropped. The `ToCStr` trait is implemented for `&str` -//! and `&[u8]`, but the conversions can fail due to some of the limitations -//! explained above. -//! -//! This also means that currently whenever a C string is created, an allocation -//! must be performed to place the data elsewhere (the lifetime of the C string is -//! not tied to the lifetime of the original string/data buffer). If C strings are -//! heavily used in applications, then caching may be advisable to prevent -//! unnecessary amounts of allocations. -//! -//! Be carefull to remember that the memory is managed by C allocator API and not -//! by Rust allocator API. -//! That means that the CString pointers should be freed with C allocator API -//! if you intend to do that on your own, as the behaviour if you free them with -//! Rust's allocator API is not well defined -//! -//! An example of creating and using a C string would be: -//! -//! ```rust -//! extern crate libc; -//! -//! use std::c_str::ToCStr; -//! -//! extern { -//! fn puts(s: *const libc::c_char); -//! } -//! -//! fn main() { -//! let my_string = "Hello, world!"; -//! -//! // Allocate the C string with an explicit local that owns the string. The -//! // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope. -//! let my_c_string = my_string.to_c_str(); -//! unsafe { -//! puts(my_c_string.as_ptr()); -//! } -//! -//! // Don't save/return the pointer to the C string, the `c_buffer` will be -//! // deallocated when this block returns! -//! my_string.with_c_str(|c_buffer| { -//! unsafe { puts(c_buffer); } -//! }); -//! } -//! ``` - -use core::prelude::*; -use libc; - -use cmp::Ordering; -use fmt; -use hash; -use mem; -use ptr; -use slice::{self, IntSliceExt}; -use str; -use string::String; -use core::kinds::marker; - -/// The representation of a C String. -/// -/// This structure wraps a `*libc::c_char`, and will automatically free the -/// memory it is pointing to when it goes out of scope. -#[allow(missing_copy_implementations)] -pub struct CString { - buf: *const libc::c_char, - owns_buffer_: bool, -} - -unsafe impl Send for CString { } -unsafe impl Sync for CString { } - -impl Clone for CString { - /// Clone this CString into a new, uniquely owned CString. For safety - /// reasons, this is always a deep clone with the memory allocated - /// with C's allocator API, rather than the usual shallow clone. - fn clone(&self) -> CString { - let len = self.len() + 1; - let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char; - if buf.is_null() { ::alloc::oom() } - unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); } - CString { buf: buf as *const libc::c_char, owns_buffer_: true } - } -} - -impl PartialEq for CString { - fn eq(&self, other: &CString) -> bool { - // Check if the two strings share the same buffer - if self.buf as uint == other.buf as uint { - true - } else { - unsafe { - libc::strcmp(self.buf, other.buf) == 0 - } - } - } -} - -impl PartialOrd for CString { - #[inline] - fn partial_cmp(&self, other: &CString) -> Option { - self.as_bytes().partial_cmp(other.as_bytes()) - } -} - -impl Eq for CString {} - -impl hash::Hash for CString { - #[inline] - fn hash(&self, state: &mut S) { - self.as_bytes().hash(state) - } -} - -impl CString { - /// Create a C String from a pointer, with memory managed by C's allocator - /// API, so avoid calling it with a pointer to memory managed by Rust's - /// allocator API, as the behaviour would not be well defined. - /// - ///# Panics - /// - /// Panics if `buf` is null - pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString { - assert!(!buf.is_null()); - CString { buf: buf, owns_buffer_: owns_buffer } - } - - /// Return a pointer to the NUL-terminated string data. - /// - /// `.as_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let x = foo.to_c_str(); - /// let p = x.as_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_ptr(); - /// ``` - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let c_str = "foo bar".to_c_str(); - /// unsafe { - /// libc::puts(c_str.as_ptr()); - /// } - /// } - /// ``` - pub fn as_ptr(&self) -> *const libc::c_char { - self.buf - } - - /// Return a mutable pointer to the NUL-terminated string data. - /// - /// `.as_mut_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let mut x = foo.to_c_str(); - /// let p = x.as_mut_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_mut_ptr(); - /// ``` - pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - self.buf as *mut _ - } - - /// Returns whether or not the `CString` owns the buffer. - pub fn owns_buffer(&self) -> bool { - self.owns_buffer_ - } - - /// Converts the CString into a `&[u8]` without copying. - /// Includes the terminating NUL byte. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned() - } - } - - /// Converts the CString into a `&[u8]` without copying. - /// Does not include the terminating NUL byte. - #[inline] - pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len()).as_unsigned() - } - } - - /// Converts the CString into a `&str` without copying. - /// Returns None if the CString is not UTF-8. - #[inline] - pub fn as_str<'a>(&'a self) -> Option<&'a str> { - let buf = self.as_bytes_no_nul(); - str::from_utf8(buf).ok() - } - - /// Return a CString iterator. - pub fn iter<'a>(&'a self) -> CChars<'a> { - CChars { - ptr: self.buf, - marker: marker::ContravariantLifetime, - } - } - - /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper. - /// - /// Any ownership of the buffer by the `CString` wrapper is - /// forgotten, meaning that the backing allocation of this - /// `CString` is not automatically freed if it owns the - /// allocation. In this case, a user of `.unwrap()` should ensure - /// the allocation is freed, to avoid leaking memory. You should - /// use libc's memory allocator in this case. - /// - /// Prefer `.as_ptr()` when just retrieving a pointer to the - /// string data, as that does not relinquish ownership. - pub unsafe fn into_inner(mut self) -> *const libc::c_char { - self.owns_buffer_ = false; - self.buf - } - - /// Return the number of bytes in the CString (not including the NUL - /// terminator). - #[inline] - pub fn len(&self) -> uint { - unsafe { libc::strlen(self.buf) as uint } - } - - /// Returns if there are no bytes in this string - #[inline] - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl Drop for CString { - fn drop(&mut self) { - if self.owns_buffer_ { - unsafe { - libc::free(self.buf as *mut libc::c_void) - } - } - } -} - -impl fmt::Show for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - String::from_utf8_lossy(self.as_bytes_no_nul()).fmt(f) - } -} - -/// A generic trait for converting a value to a CString. -pub trait ToCStr for Sized? { - /// Copy the receiver into a CString. - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - fn to_c_str(&self) -> CString; - - /// Unsafe variant of `to_c_str()` that doesn't check for nulls. - unsafe fn to_c_str_unchecked(&self) -> CString; - - /// Work with a temporary CString constructed from the receiver. - /// The provided `*libc::c_char` will be freed immediately upon return. - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let s = "PATH".with_c_str(|path| unsafe { - /// libc::getenv(path) - /// }); - /// } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str(); - f(c_str.as_ptr()) - } - - /// Unsafe variant of `with_c_str()` that doesn't check for nulls. - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str_unchecked(); - f(c_str.as_ptr()) - } -} - -impl ToCStr for str { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -impl ToCStr for String { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -// The length of the stack allocated buffer for `vec.with_c_str()` -const BUF_LEN: uint = 128; - -impl ToCStr for [u8] { - fn to_c_str(&self) -> CString { - let mut cs = unsafe { self.to_c_str_unchecked() }; - check_for_null(self, cs.as_mut_ptr()); - cs - } - - unsafe fn to_c_str_unchecked(&self) -> CString { - let self_len = self.len(); - let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8; - if buf.is_null() { ::alloc::oom() } - - ptr::copy_memory(buf, self.as_ptr(), self_len); - *buf.offset(self_len as int) = 0; - - CString::new(buf as *const libc::c_char, true) - } - - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - unsafe { with_c_str(self, true, f) } - } - - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - with_c_str(self, false, f) - } -} - -impl<'a, Sized? T: ToCStr> ToCStr for &'a T { - #[inline] - fn to_c_str(&self) -> CString { - (**self).to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - (**self).to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str_unchecked(f) - } -} - -// Unsafe function that handles possibly copying the &[u8] into a stack array. -unsafe fn with_c_str(v: &[u8], checked: bool, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, -{ - let c_str = if v.len() < BUF_LEN { - let mut buf: [u8; BUF_LEN] = mem::uninitialized(); - slice::bytes::copy_memory(&mut buf, v); - buf[v.len()] = 0; - - let buf = buf.as_mut_ptr(); - if checked { - check_for_null(v, buf as *mut libc::c_char); - } - - return f(buf as *const libc::c_char) - } else if checked { - v.to_c_str() - } else { - v.to_c_str_unchecked() - }; - - f(c_str.as_ptr()) -} - -#[inline] -fn check_for_null(v: &[u8], buf: *mut libc::c_char) { - for i in range(0, v.len()) { - unsafe { - let p = buf.offset(i as int); - assert!(*p != 0); - } - } -} - -/// External iterator for a CString's bytes. -/// -/// Use with the `std::iter` module. -#[allow(raw_pointer_deriving)] -#[derive(Clone)] -pub struct CChars<'a> { - ptr: *const libc::c_char, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a> Iterator for CChars<'a> { - type Item = libc::c_char; - - fn next(&mut self) -> Option { - let ch = unsafe { *self.ptr }; - if ch == 0 { - None - } else { - self.ptr = unsafe { self.ptr.offset(1) }; - Some(ch) - } - } -} - -/// Parses a C "multistring", eg windows env values or -/// the req->ptr result in a uv_fs_readdir() call. -/// -/// Optionally, a `count` can be passed in, limiting the -/// parsing to only being done `count`-times. -/// -/// The specified closure is invoked with each string that -/// is found, and the number of strings found is returned. -pub unsafe fn from_c_multistring(buf: *const libc::c_char, - count: Option, - mut f: F) - -> uint where - F: FnMut(&CString), -{ - - let mut curr_ptr: uint = buf as uint; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while ((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char { - let cstr = CString::new(curr_ptr as *const libc::c_char, false); - f(&cstr); - curr_ptr += cstr.len() + 1; - ctr += 1; - } - return ctr; -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use super::*; - use ptr; - use thread::Thread; - use libc; - - #[test] - fn test_str_multistring_parsing() { - unsafe { - let input = b"zero\0one\0\0"; - let ptr = input.as_ptr(); - let expected = ["zero", "one"]; - let mut it = expected.iter(); - let result = from_c_multistring(ptr as *const libc::c_char, None, |c| { - let cbytes = c.as_bytes_no_nul(); - assert_eq!(cbytes, it.next().unwrap().as_bytes()); - }); - assert_eq!(result, 2); - assert!(it.next().is_none()); - } - } - - #[test] - fn test_str_to_c_str() { - let c_str = "".to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = "hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - } - - #[test] - fn test_vec_to_c_str() { - let b: &[u8] = &[]; - let c_str = b.to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = b"hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - - let c_str = b"foo\xFF".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'f' as libc::c_char); - assert_eq!(*buf.offset(1), 'o' as libc::c_char); - assert_eq!(*buf.offset(2), 'o' as libc::c_char); - assert_eq!(*buf.offset(3), 0xffu8 as libc::c_char); - assert_eq!(*buf.offset(4), 0); - } - } - - #[test] - fn test_unwrap() { - let c_str = "hello".to_c_str(); - unsafe { libc::free(c_str.into_inner() as *mut libc::c_void) } - } - - #[test] - fn test_as_ptr() { - let c_str = "hello".to_c_str(); - let len = unsafe { libc::strlen(c_str.as_ptr()) }; - assert_eq!(len, 5); - } - - #[test] - fn test_iterator() { - let c_str = "".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), None); - - let c_str = "hello".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), Some('h' as libc::c_char)); - assert_eq!(iter.next(), Some('e' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('o' as libc::c_char)); - assert_eq!(iter.next(), None); - } - - #[test] - fn test_to_c_str_fail() { - assert!(Thread::spawn(move|| { "he\x00llo".to_c_str() }).join().is_err()); - } - - #[test] - fn test_to_c_str_unchecked() { - unsafe { - let c_string = "he\x00llo".to_c_str_unchecked(); - let buf = c_string.as_ptr(); - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 0); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'l' as libc::c_char); - assert_eq!(*buf.offset(5), 'o' as libc::c_char); - assert_eq!(*buf.offset(6), 0); - } - } - - #[test] - fn test_as_bytes() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes(), b"hello\0"); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_bytes(), b"\0"); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes(), b"foo\xFF\0"); - } - - #[test] - fn test_as_bytes_no_nul() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"hello"); - let c_str = "".to_c_str(); - let exp: &[u8] = &[]; - assert_eq!(c_str.as_bytes_no_nul(), exp); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); - } - - #[test] - fn test_as_str() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_str(), Some("hello")); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_str(), Some("")); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_str(), None); - } - - #[test] - #[should_fail] - fn test_new_fail() { - let _c_str = unsafe { CString::new(ptr::null(), false) }; - } - - #[test] - fn test_clone() { - let a = "hello".to_c_str(); - let b = a.clone(); - assert!(a == b); - } - - #[test] - fn test_clone_noleak() { - fn foo(f: F) where F: FnOnce(&CString) { - let s = "test".to_string(); - let c = s.to_c_str(); - // give the closure a non-owned CString - let mut c_ = unsafe { CString::new(c.as_ptr(), false) }; - f(&c_); - // muck with the buffer for later printing - unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char } - } - - let mut c_: Option = None; - foo(|c| { - c_ = Some(c.clone()); - c.clone(); - // force a copy, reading the memory - c.as_bytes().to_vec(); - }); - let c_ = c_.unwrap(); - // force a copy, reading the memory - c_.as_bytes().to_vec(); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - use prelude::v1::*; - use self::test::Bencher; - use libc; - use c_str::ToCStr; - - #[inline] - fn check(s: &str, c_str: *const libc::c_char) { - let s_buf = s.as_ptr(); - for i in range(0, s.len()) { - unsafe { - assert_eq!( - *s_buf.offset(i as int) as libc::c_char, - *c_str.offset(i as int)); - } - } - } - - static S_SHORT: &'static str = "Mary"; - static S_MEDIUM: &'static str = "Mary had a little lamb"; - static S_LONG: &'static str = "\ - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb"; - - fn bench_to_string(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = s.to_c_str(); - check(s, c_str.as_ptr()); - }) - } - - #[bench] - fn bench_to_c_str_short(b: &mut Bencher) { - bench_to_string(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_medium(b: &mut Bencher) { - bench_to_string(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_long(b: &mut Bencher) { - bench_to_string(b, S_LONG) - } - - fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = unsafe { s.to_c_str_unchecked() }; - check(s, c_str.as_ptr()) - }) - } - - #[bench] - fn bench_to_c_str_unchecked_short(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_unchecked_medium(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_unchecked_long(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_LONG) - } - - fn bench_with_c_str(b: &mut Bencher, s: &str) { - b.iter(|| { - s.with_c_str(|c_str_buf| check(s, c_str_buf)) - }) - } - - #[bench] - fn bench_with_c_str_short(b: &mut Bencher) { - bench_with_c_str(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_medium(b: &mut Bencher) { - bench_with_c_str(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_long(b: &mut Bencher) { - bench_with_c_str(b, S_LONG) - } - - fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - unsafe { - s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf)) - } - }) - } - - #[bench] - fn bench_with_c_str_unchecked_short(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_unchecked_medium(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_unchecked_long(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_LONG) - } -} diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs deleted file mode 100644 index 4a20208f31a..00000000000 --- a/src/libstd/c_vec.rs +++ /dev/null @@ -1,232 +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. - -//! Library to interface with chunks of memory allocated in C. -//! -//! It is often desirable to safely interface with memory allocated from C, -//! encapsulating the unsafety into allocation and destruction time. Indeed, -//! allocating memory externally is currently the only way to give Rust shared -//! mut state with C programs that keep their own references; vectors are -//! unsuitable because they could be reallocated or moved at any time, and -//! importing C memory into a vector takes a one-time snapshot of the memory. -//! -//! This module simplifies the usage of such external blocks of memory. Memory -//! is encapsulated into an opaque object after creation; the lifecycle of the -//! memory can be optionally managed by Rust, if an appropriate destructor -//! closure is provided. Safety is ensured by bounds-checking accesses, which -//! are marshalled through get and set functions. -//! -//! There are three unsafe functions: the two constructors, and the -//! unwrap method. The constructors are unsafe for the -//! obvious reason (they act on a pointer that cannot be checked inside the -//! method), but `unwrap()` is somewhat more subtle in its unsafety. -//! It returns the contained pointer, but at the same time destroys the CVec -//! without running its destructor. This can be used to pass memory back to -//! C, but care must be taken that the ownership of underlying resources are -//! handled correctly, i.e. that allocated memory is eventually freed -//! if necessary. - -#![experimental] - -use kinds::Send; -use mem; -use ops::{Drop, FnOnce}; -use option::Option; -use option::Option::{Some, None}; -use ptr::PtrExt; -use ptr; -use raw; -use slice::AsSlice; -use thunk::{Thunk}; - -/// The type representing a foreign chunk of memory -pub struct CVec { - base: *mut T, - len: uint, - dtor: Option, -} - -#[unsafe_destructor] -impl Drop for CVec { - fn drop(&mut self) { - match self.dtor.take() { - None => (), - Some(f) => f.invoke(()) - } - } -} - -impl CVec { - /// Create a `CVec` from a raw pointer to a buffer with a given length. - /// - /// Panics if the given pointer is null. The returned vector will not attempt - /// to deallocate the vector when dropped. - /// - /// # Arguments - /// - /// * base - A raw pointer to a buffer - /// * len - The number of elements in the buffer - pub unsafe fn new(base: *mut T, len: uint) -> CVec { - assert!(base != ptr::null_mut()); - CVec { - base: base, - len: len, - dtor: None, - } - } - - /// Create a `CVec` from a foreign buffer, with a given length, - /// and a function to run upon destruction. - /// - /// Panics if the given pointer is null. - /// - /// # Arguments - /// - /// * base - A foreign pointer to a buffer - /// * len - The number of elements in the buffer - /// * dtor - A fn to run when the value is destructed, useful - /// for freeing the buffer, etc. - pub unsafe fn new_with_dtor(base: *mut T, - len: uint, - dtor: F) - -> CVec - where F : FnOnce(), F : Send - { - assert!(base != ptr::null_mut()); - let dtor: Thunk = Thunk::new(dtor); - CVec { - base: base, - len: len, - dtor: Some(dtor) - } - } - - /// View the stored data as a mutable slice. - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } - - /// Retrieves an element at a given index, returning `None` if the requested - /// index is greater than the length of the vector. - pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> { - if ofs < self.len { - Some(unsafe { &*self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Retrieves a mutable element at a given index, returning `None` if the - /// requested index is greater than the length of the vector. - pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> { - if ofs < self.len { - Some(unsafe { &mut *self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Unwrap the pointer without running the destructor - /// - /// This method retrieves the underlying pointer, and in the process - /// destroys the CVec but without running the destructor. A use case - /// would be transferring ownership of the buffer to a C function, as - /// in this case you would not want to run the destructor. - /// - /// Note that if you want to access the underlying pointer without - /// cancelling the destructor, you can simply call `transmute` on the return - /// value of `get(0)`. - pub unsafe fn into_inner(mut self) -> *mut T { - self.dtor = None; - self.base - } - - /// Returns the number of items in this vector. - pub fn len(&self) -> uint { self.len } - - /// Returns whether this vector is empty. - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl AsSlice for CVec { - /// View the stored data as a slice. - fn as_slice<'a>(&'a self) -> &'a [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use super::CVec; - use libc; - use ptr; - - fn malloc(n: uint) -> CVec { - unsafe { - let mem = ptr::Unique(libc::malloc(n as libc::size_t)); - if mem.0.is_null() { ::alloc::oom() } - - CVec::new_with_dtor(mem.0 as *mut u8, - n, - move|| { libc::free(mem.0 as *mut libc::c_void); }) - } - } - - #[test] - fn test_basic() { - let mut cv = malloc(16); - - *cv.get_mut(3).unwrap() = 8; - *cv.get_mut(4).unwrap() = 9; - assert_eq!(*cv.get(3).unwrap(), 8); - assert_eq!(*cv.get(4).unwrap(), 9); - assert_eq!(cv.len(), 16); - } - - #[test] - #[should_fail] - fn test_panic_at_null() { - unsafe { - CVec::new(ptr::null_mut::(), 9); - } - } - - #[test] - fn test_overrun_get() { - let cv = malloc(16); - - assert!(cv.get(17).is_none()); - } - - #[test] - fn test_overrun_set() { - let mut cv = malloc(16); - - assert!(cv.get_mut(17).is_none()); - } - - #[test] - fn test_unwrap() { - unsafe { - let cv = CVec::new_with_dtor(1 as *mut int, - 0, - move|:| panic!("Don't run this destructor!")); - let p = cv.into_inner(); - assert_eq!(p, 1 as *mut int); - } - } - -} diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 651f31b205d..c35be86420d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -14,7 +14,7 @@ use self::SearchResult::*; use self::VacantEntryState::*; -use borrow::BorrowFrom; +use borrow::{BorrowFrom, ToOwned}; use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; @@ -920,12 +920,16 @@ fn last_two((_, b, c): (A, B, C)) -> (B, C) { (b, c) } } } - /// Gets the given key's corresponding entry in the map for in-place manipulation - pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { + #[stable] + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// Regardless of whether or not `to_owned()` has been called, the key must hash the same way. + pub fn entry<'a, Sized? Q>(&'a mut self, key: &'a Q) -> Entry<'a, Q, K, V> + where Q: Eq + Hash + ToOwned + { // Gotta resize now. self.reserve(1); - let hash = self.make_hash(&key); + let hash = self.make_hash(key); search_entry_hashed(&mut self.table, hash, key) } @@ -1138,8 +1142,10 @@ pub fn remove(&mut self, k: &Q) -> Option } } -fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHash, k: K) - -> Entry<'a, K, V> { +fn search_entry_hashed<'a, K, V, Sized? Q>(table: &'a mut RawTable, hash: SafeHash, k: &'a Q) + -> Entry<'a, Q, K, V> + where Q: Eq + ToOwned +{ // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = table.size(); let mut probe = Bucket::new(table, hash); @@ -1161,7 +1167,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHas // hash matches? if bucket.hash() == hash { // key matches? - if k == *bucket.read().0 { + if *k == *BorrowFrom::borrow_from(bucket.read().0) { return Occupied(OccupiedEntry{ elem: bucket, }); @@ -1220,19 +1226,6 @@ fn default() -> HashMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap - where Q: BorrowFrom + Hash + Eq -{ - #[inline] - fn index<'a>(&'a self, index: &Q) -> &'a V { - self.get(index).expect("no entry found for key") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap where Q: BorrowFrom + Hash + Eq @@ -1245,19 +1238,6 @@ fn index<'a>(&'a self, index: &Q) -> &'a V { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -#[stable] -impl + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap - where Q: BorrowFrom + Hash + Eq -{ - #[inline] - fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { - self.get_mut(index).expect("no entry found for key") - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot #[stable] impl + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap where Q: BorrowFrom + Hash + Eq @@ -1343,24 +1323,27 @@ pub struct Drain<'a, K: 'a, V: 'a> { > } +#[stable] /// A view into a single occupied location in a HashMap -pub struct OccupiedEntry<'a, K:'a, V:'a> { +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { elem: FullBucket>, } +#[stable] /// A view into a single empty location in a HashMap -pub struct VacantEntry<'a, K:'a, V:'a> { +pub struct VacantEntry<'a, Sized? Q: 'a, K: 'a, V: 'a> { hash: SafeHash, - key: K, - elem: VacantEntryState>, + key: &'a Q, + elem: VacantEntryState>, } +#[stable] /// A view into a single location in a map, which may be vacant or occupied -pub enum Entry<'a, K:'a, V:'a> { +pub enum Entry<'a, Sized? Q: 'a, K: 'a, V: 'a> { /// An occupied Entry Occupied(OccupiedEntry<'a, K, V>), /// A vacant Entry - Vacant(VacantEntry<'a, K, V>), + Vacant(VacantEntry<'a, Q, K, V>), } /// Possible states of a VacantEntry @@ -1426,46 +1409,63 @@ fn size_hint(&self) -> (uint, Option) { } } +impl<'a, Sized? Q, K, V> Entry<'a, Q, K, V> { + #[unstable = "matches collection reform v2 specification, waiting for dust to settle"] + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> { + match self { + Occupied(entry) => Ok(entry.into_mut()), + Vacant(entry) => Err(entry), + } + } +} + impl<'a, K, V> OccupiedEntry<'a, K, V> { + #[stable] /// Gets a reference to the value in the entry pub fn get(&self) -> &V { self.elem.read().1 } + #[stable] /// Gets a mutable reference to the value in the entry pub fn get_mut(&mut self) -> &mut V { self.elem.read_mut().1 } + #[stable] /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut V { self.elem.into_mut_refs().1 } + #[stable] /// Sets the value of the entry, and returns the entry's old value - pub fn set(&mut self, mut value: V) -> V { + pub fn insert(&mut self, mut value: V) -> V { let old_value = self.get_mut(); mem::swap(&mut value, old_value); value } + #[stable] /// Takes the value out of the entry, and returns it - pub fn take(self) -> V { + pub fn remove(self) -> V { pop_internal(self.elem).1 } } -impl<'a, K, V> VacantEntry<'a, K, V> { +impl<'a, Sized? Q: 'a + ToOwned, K: 'a, V: 'a> VacantEntry<'a, Q, K, V> { + #[stable] /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it - pub fn set(self, value: V) -> &'a mut V { + pub fn insert(self, value: V) -> &'a mut V { match self.elem { NeqElem(bucket, ib) => { - robin_hood(bucket, ib, self.hash, self.key, value) + robin_hood(bucket, ib, self.hash, self.key.to_owned(), value) } NoElem(bucket) => { - bucket.put(self.hash, self.key, value).into_mut_refs().1 + bucket.put(self.hash, self.key.to_owned(), value).into_mut_refs().1 } } } @@ -1497,6 +1497,8 @@ mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; use iter::{range_inclusive, range_step_inclusive, repeat}; + use borrow::ToOwned; + use hash; use cell::RefCell; use rand::{weak_rng, Rng}; @@ -2090,11 +2092,11 @@ fn test_entry(){ let mut map: HashMap = xs.iter().map(|&x| x).collect(); // Existing key (insert) - match map.entry(1) { + match map.entry(&1) { Vacant(_) => unreachable!(), Occupied(mut view) => { assert_eq!(view.get(), &10); - assert_eq!(view.set(100), 10); + assert_eq!(view.insert(100), 10); } } assert_eq!(map.get(&1).unwrap(), &100); @@ -2102,7 +2104,7 @@ fn test_entry(){ // Existing key (update) - match map.entry(2) { + match map.entry(&2) { Vacant(_) => unreachable!(), Occupied(mut view) => { let v = view.get_mut(); @@ -2114,10 +2116,10 @@ fn test_entry(){ assert_eq!(map.len(), 6); // Existing key (take) - match map.entry(3) { + match map.entry(&3) { Vacant(_) => unreachable!(), Occupied(view) => { - assert_eq!(view.take(), 30); + assert_eq!(view.remove(), 30); } } assert_eq!(map.get(&3), None); @@ -2125,10 +2127,10 @@ fn test_entry(){ // Inexistent key (insert) - match map.entry(10) { + match map.entry(&10) { Occupied(_) => unreachable!(), Vacant(view) => { - assert_eq!(*view.set(1000), 1000); + assert_eq!(*view.insert(1000), 1000); } } assert_eq!(map.get(&10).unwrap(), &1000); @@ -2156,11 +2158,11 @@ fn check(m: &HashMap) { for i in range(0u, 1000) { let x = rng.gen_range(-10, 10); - match m.entry(x) { + match m.entry(&x) { Vacant(_) => {}, Occupied(e) => { println!("{}: remove {}", i, x); - e.take(); + e.remove(); }, } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b1824db93aa..7877e783ed6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -164,7 +164,7 @@ pub fn with_hasher(hasher: H) -> HashSet { /// /// let h = SipHasher::new(); /// let mut set = HashSet::with_capacity_and_hasher(10u, h); - /// set.insert(1i); + /// set.insert(1); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] @@ -283,8 +283,8 @@ fn first((a, _): (A, B)) -> A { a } /// /// ``` /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4, 2, 3, 4].iter().map(|&x| x).collect(); /// /// // Can be seen as `a - b`. /// for x in a.difference(&b) { @@ -292,12 +292,12 @@ fn first((a, _): (A, B)) -> A { a } /// } /// /// let diff: HashSet = a.difference(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [1i].iter().map(|&x| x).collect()); + /// assert_eq!(diff, [1].iter().map(|&x| x).collect()); /// /// // Note that difference is not symmetric, /// // and `b - a` means something else: /// let diff: HashSet = b.difference(&a).map(|&x| x).collect(); - /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); + /// assert_eq!(diff, [4].iter().map(|&x| x).collect()); /// ``` #[stable] pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, H> { @@ -313,8 +313,8 @@ pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, H /// /// ``` /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4, 2, 3, 4].iter().map(|&x| x).collect(); /// /// // Print 1, 4 in arbitrary order. /// for x in a.symmetric_difference(&b) { @@ -325,7 +325,7 @@ pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, H /// let diff2: HashSet = b.symmetric_difference(&a).map(|&x| x).collect(); /// /// assert_eq!(diff1, diff2); - /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); + /// assert_eq!(diff1, [1, 4].iter().map(|&x| x).collect()); /// ``` #[stable] pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) @@ -339,8 +339,8 @@ pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) /// /// ``` /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4, 2, 3, 4].iter().map(|&x| x).collect(); /// /// // Print 2, 3 in arbitrary order. /// for x in a.intersection(&b) { @@ -348,7 +348,7 @@ pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) /// } /// /// let diff: HashSet = a.intersection(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); + /// assert_eq!(diff, [2, 3].iter().map(|&x| x).collect()); /// ``` #[stable] pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, H> { @@ -364,8 +364,8 @@ pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, /// /// ``` /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4, 2, 3, 4].iter().map(|&x| x).collect(); /// /// // Print 1, 2, 3, 4 in arbitrary order. /// for x in a.union(&b) { @@ -373,7 +373,7 @@ pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, /// } /// /// let diff: HashSet = a.union(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); + /// assert_eq!(diff, [1, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[stable] pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, H> { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 7c87094805d..ab91beb4f9b 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -139,13 +139,11 @@ pub fn inspect(&self) -> u64 { self.hash } /// This function wraps up `hash_keyed` to be the only way outside this /// module to generate a SafeHash. pub fn make_hash, S, H: Hasher>(hasher: &H, t: &T) -> SafeHash { - match hasher.hash(t) { - // This constant is exceedingly likely to hash to the same - // bucket, but it won't be counted as empty! Just so we can maintain - // our precious uniform distribution of initial indexes. - EMPTY_BUCKET => SafeHash { hash: 0x8000_0000_0000_0000 }, - h => SafeHash { hash: h }, - } + // We need to avoid 0u64 in order to prevent collisions with + // EMPTY_HASH. We can maintain our precious uniform distribution + // of initial indexes by unconditionally setting the MSB, + // effectively reducing 64-bits hashes to 63 bits. + SafeHash { hash: 0x8000_0000_0000_0000 | hasher.hash(t) } } // `replace` casts a `*u64` to a `*SafeHash`. Since we statically diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 4be83bfc664..c0445fb5aea 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -226,7 +226,7 @@ //! the key has been seen or not. Normally, this would require a `find` followed by an //! `insert`, effectively duplicating the search effort on each insertion. //! -//! When a user calls `map.entry(key)`, the map will search for the key and then yield +//! When a user calls `map.entry(&key)`, the map will search for the key and then yield //! a variant of the `Entry` enum. //! //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the @@ -255,8 +255,8 @@ //! let message = "she sells sea shells by the sea shore"; //! //! for c in message.chars() { -//! match count.entry(c) { -//! Vacant(entry) => { entry.set(1u); }, +//! match count.entry(&c) { +//! Vacant(entry) => { entry.insert(1u); }, //! Occupied(mut entry) => *entry.get_mut() += 1, //! } //! } @@ -290,8 +290,8 @@ //! for id in orders.into_iter() { //! // If this is the first time we've seen this customer, initialize them //! // with no blood alcohol. Otherwise, just retrieve them. -//! let person = match blood_alcohol.entry(id) { -//! Vacant(entry) => entry.set(Person{id: id, blood_alcohol: 0.0}), +//! let person = match blood_alcohol.entry(&id) { +//! Vacant(entry) => entry.insert(Person{id: id, blood_alcohol: 0.0}), //! Occupied(entry) => entry.into_mut(), //! }; //! diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index de3d75ffb32..66cb1f2c948 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; use mem; use os; use str; @@ -51,13 +51,11 @@ impl DynamicLibrary { /// Lazily open a dynamic library. When passed None it gives a /// handle to the calling process - pub fn open(filename: Option) - -> Result { + pub fn open(filename: Option<&Path>) -> Result { unsafe { - let mut filename = filename; let maybe_library = dl::check_for_errors_in(|| { - match filename.take() { - Some(name) => dl::open_external(name), + match filename { + Some(name) => dl::open_external(name.as_vec()), None => dl::open_internal() } }); @@ -131,9 +129,8 @@ pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { // T but that feature is still unimplemented let maybe_symbol_value = dl::check_for_errors_in(|| { - symbol.with_c_str(|raw_string| { - dl::symbol(self.handle, raw_string) - }) + let raw_string = CString::from_slice(symbol.as_bytes()); + dl::symbol(self.handle, raw_string.as_ptr()) }); // The value must not be constructed if there is an error so @@ -157,7 +154,7 @@ mod test { fn test_loading_cosine() { // The math library does not need to be loaded since it is already // statically linked in - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let libm = match DynamicLibrary::open(none) { Err(error) => panic!("Could not load self as module: {}", error), Ok(libm) => libm @@ -202,17 +199,17 @@ fn test_errors_do_not_crash() { target_os = "freebsd", target_os = "dragonfly"))] pub mod dl { - use self::Rtld::*; - + pub use self::Rtld::*; use prelude::v1::*; - use c_str::{CString, ToCStr}; + + use ffi::{self, CString}; + use str; use libc; use ptr; - pub unsafe fn open_external(filename: T) -> *mut u8 { - filename.with_c_str(|raw_name| { - dlopen(raw_name, Lazy as libc::c_int) as *mut u8 - }) + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { + let s = CString::from_slice(filename); + dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8 } pub unsafe fn open_internal() -> *mut u8 { @@ -236,8 +233,8 @@ pub fn check_for_errors_in(f: F) -> Result where let ret = if ptr::null() == last_error { Ok(result) } else { - Err(String::from_str(CString::new(last_error, false).as_str() - .unwrap())) + let s = ffi::c_str_to_bytes(&last_error); + Err(str::from_utf8(s).unwrap().to_string()) }; ret @@ -273,7 +270,6 @@ fn dlsym(handle: *mut libc::c_void, #[cfg(target_os = "windows")] pub mod dl { - use c_str::ToCStr; use iter::IteratorExt; use libc; use ops::FnOnce; @@ -287,10 +283,9 @@ pub mod dl { use string::String; use vec::Vec; - pub unsafe fn open_external(filename: T) -> *mut u8 { + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { // Windows expects Unicode data - let filename_cstr = filename.to_c_str(); - let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap(); + let filename_str = str::from_utf8(filename).unwrap(); let mut filename_str: Vec = filename_str.utf16_units().collect(); filename_str.push(0); LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8 diff --git a/src/libstd/failure.rs b/src/libstd/failure.rs index d3bcdbf1a53..e48137047b0 100644 --- a/src/libstd/failure.rs +++ b/src/libstd/failure.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use any::{Any, AnyRefExt}; +use any::Any; use cell::RefCell; use io::IoResult; use rt::{backtrace, unwind}; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs new file mode 100644 index 00000000000..bef2344d9e8 --- /dev/null +++ b/src/libstd/ffi/c_str.rs @@ -0,0 +1,218 @@ +// 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 fmt; +use iter::IteratorExt; +use libc; +use mem; +use ops::Deref; +use slice::{self, SliceExt, AsSlice}; +use string::String; +use vec::Vec; + +/// A type representing a C-compatible string +/// +/// This type serves the primary purpose of being able to generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. After +/// being created, a `CString` predominately inherits all of its methods from +/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying +/// array is represented as an array of `libc::c_char` as opposed to `u8`. A +/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from +/// a `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi::CString; +/// use libc; +/// +/// extern { +/// fn my_printer(s: *const libc::c_char); +/// } +/// +/// let to_print = "Hello, world!"; +/// let c_to_print = CString::from_slice(to_print.as_bytes()); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct CString { + inner: Vec, +} + +impl CString { + /// Create a new C-compatible string from a byte slice. + /// + /// This method will copy the data of the slice provided into a new + /// allocation, ensuring that there is a trailing 0 byte. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the slice + /// provided. + pub fn from_slice(v: &[u8]) -> CString { + CString::from_vec(v.to_vec()) + } + + /// Create a C-compatible string from a byte vector. + /// + /// This method will consume ownership of the provided vector, appending a 0 + /// byte to the end after verifying that there are no interior 0 bytes. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the vector + /// provided. + pub fn from_vec(v: Vec) -> CString { + assert!(!v.iter().any(|&x| x == 0)); + unsafe { CString::from_vec_unchecked(v) } + } + + /// Create a C-compatibel string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to `from_vec` except that no runtime assertion + /// is made that `v` contains no 0 bytes. + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.push(0); + CString { inner: mem::transmute(v) } + } + + /// Create a view into this C string which includes the trailing nul + /// terminator at the end of the string. + pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() } + + /// Similar to the `as_slice` method, but returns a `u8` slice instead of a + /// `libc::c_char` slice. + pub fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice()) } + } + + /// Equivalend to `as_slice_with_nul` except that the type returned is a + /// `u8` slice instead of a `libc::c_char` slice. + pub fn as_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice_with_nul()) } + } +} + +impl Deref for CString { + type Target = [libc::c_char]; + + fn deref(&self) -> &[libc::c_char] { + self.inner.slice_to(self.inner.len() - 1) + } +} + +impl fmt::Show for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + String::from_utf8_lossy(self.as_bytes()).fmt(f) + } +} + +/// Interpret a C string as a byte slice. +/// +/// This function will calculate the length of the C string provided, and it +/// will then return a corresponding slice for the contents of the C string not +/// including the nul terminator. +/// +/// This function will tie the lifetime of the returned slice to the lifetime of +/// the pointer provided. This is done to help prevent the slice from escaping +/// the lifetime of the pointer itself. If a longer lifetime is needed, then +/// `mem::copy_lifetime` should be used. +/// +/// This function is unsafe because there is no guarantee of the validity of the +/// pointer `raw` or a guarantee that a nul terminator will be found. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi; +/// use std::str; +/// use libc; +/// +/// extern { +/// fn my_string() -> *const libc::c_char; +/// } +/// +/// unsafe { +/// let to_print = my_string(); +/// let slice = ffi::c_str_to_bytes(&to_print); +/// println!("string returned: {}", str::from_utf8(slice).unwrap()); +/// } +/// # } +/// ``` +pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw); + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +/// Interpret a C string as a byte slice with the nul terminator. +/// +/// This function is identical to `from_raw_buf` except that the returned slice +/// will include the nul terminator of the string. +pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw) + 1; + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use super::*; + use libc; + use mem; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const libc::c_char; + unsafe { + assert_eq!(c_str_to_bytes(&ptr), b"123"); + assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::from_slice(b"1234"); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + unsafe { + assert_eq!(s.as_slice(), + mem::transmute::<_, &[libc::c_char]>(b"1234")); + assert_eq!(s.as_slice_with_nul(), + mem::transmute::<_, &[libc::c_char]>(b"1234\0")); + } + } + + #[should_fail] #[test] + fn build_with_zero1() { CString::from_slice(b"\0"); } + #[should_fail] #[test] + fn build_with_zero2() { CString::from_vec(vec![0]); } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } +} diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs new file mode 100644 index 00000000000..cc86f804e3e --- /dev/null +++ b/src/libstd/ffi/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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. + +//! Utilities related to FFI bindings. + +#![unstable = "module just underwent fairly large reorganization and the dust \ + still needs to settle"] + +pub use self::c_str::CString; +pub use self::c_str::c_str_to_bytes; +pub use self::c_str::c_str_to_bytes_with_nul; + +mod c_str; diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 5cb79d41db9..4691c06c1de 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -518,14 +518,16 @@ pub fn rmdir(path: &Path) -> IoResult<()> { /// use std::io; /// /// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> { +/// fn visit_dirs(dir: &Path, cb: &mut F) -> io::IoResult<()> where +/// F: FnMut(&Path), +/// { /// if dir.is_dir() { /// let contents = try!(fs::readdir(dir)); /// for entry in contents.iter() { /// if entry.is_dir() { -/// try!(visit_dirs(entry, |p| cb(p))); +/// try!(visit_dirs(entry, cb)); /// } else { -/// cb(entry); +/// (*cb)(entry); /// } /// } /// Ok(()) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index ae401a04a96..3fa0b5645c5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -225,7 +225,7 @@ pub use self::FileAccess::*; pub use self::IoErrorKind::*; -use char::Char; +use char::CharExt; use clone::Clone; use default::Default; use error::{FromError, Error}; @@ -248,7 +248,6 @@ use string::String; use uint; use unicode; -use unicode::char::UnicodeChar; use vec::Vec; // Reexports diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs index 52b589b5f24..d398b61fe64 100644 --- a/src/libstd/io/net/ip.rs +++ b/src/libstd/io/net/ip.rs @@ -17,11 +17,12 @@ pub use self::IpAddr::*; +use boxed::Box; use fmt; use io::{self, IoResult, IoError}; use io::net; use iter::{Iterator, IteratorExt}; -use ops::FnOnce; +use ops::{FnOnce, FnMut}; use option::Option; use option::Option::{None, Some}; use result::Result::{Ok, Err}; @@ -120,10 +121,10 @@ fn read_till_eof(&mut self, cb: F) -> Option where } // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [|&mut Parser| -> Option]) + fn read_or(&mut self, parsers: &mut [Box Option>]) -> Option { for pf in parsers.iter_mut() { - match self.read_atomically(|p: &mut Parser| (*pf)(p)) { + match self.read_atomically(|p: &mut Parser| pf.call_mut((p,))) { Some(r) => return Some(r), None => {} } @@ -320,22 +321,22 @@ fn read_ipv6_addr(&mut self) -> Option { } fn read_ip_addr(&mut self) -> Option { - let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr(); - let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr(); - self.read_or(&mut [ipv4_addr, ipv6_addr]) + let ipv4_addr = |&mut: p: &mut Parser| p.read_ipv4_addr(); + let ipv6_addr = |&mut: p: &mut Parser| p.read_ipv6_addr(); + self.read_or(&mut [box ipv4_addr, box ipv6_addr]) } fn read_socket_addr(&mut self) -> Option { let ip_addr = |&: p: &mut Parser| { - let ipv4_p = |p: &mut Parser| p.read_ip_addr(); - let ipv6_p = |p: &mut Parser| { + let ipv4_p = |&mut: p: &mut Parser| p.read_ip_addr(); + let ipv6_p = |&mut: p: &mut Parser| { let open_br = |&: p: &mut Parser| p.read_given_char('['); let ip_addr = |&: p: &mut Parser| p.read_ipv6_addr(); let clos_br = |&: p: &mut Parser| p.read_given_char(']'); p.read_seq_3::(open_br, ip_addr, clos_br) .map(|t| match t { (_, ip, _) => ip }) }; - p.read_or(&mut [ipv4_p, ipv6_p]) + p.read_or(&mut [box ipv4_p, box ipv6_p]) }; let colon = |&: p: &mut Parser| p.read_given_char(':'); let port = |&: p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16); diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index daefdd28b30..738c70412f7 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -22,7 +22,8 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; +use path::BytesContainer; use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; use sys::pipe::UnixAcceptor as UnixAcceptorImp; use sys::pipe::UnixListener as UnixListenerImp; @@ -53,8 +54,9 @@ impl UnixStream { /// let mut stream = UnixStream::connect(&server); /// stream.write(&[1, 2, 3]); /// ``` - pub fn connect(path: &P) -> IoResult { - UnixStreamImp::connect(&path.to_c_str(), None) + pub fn connect(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, None) .map(|inner| UnixStream { inner: inner }) } @@ -67,13 +69,15 @@ pub fn connect(path: &P) -> IoResult { /// If a `timeout` with zero or negative duration is specified then /// the function returns `Err`, with the error kind set to `TimedOut`. #[experimental = "the timeout argument is likely to change types"] - pub fn connect_timeout(path: &P, - timeout: Duration) -> IoResult { + pub fn connect_timeout

(path: P, timeout: Duration) + -> IoResult + where P: BytesContainer { if timeout <= Duration::milliseconds(0) { return Err(standard_error(TimedOut)); } - UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64)) + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) .map(|inner| UnixStream { inner: inner }) } @@ -177,8 +181,9 @@ impl UnixListener { /// } /// # } /// ``` - pub fn bind(path: &P) -> IoResult { - UnixListenerImp::bind(&path.to_c_str()) + pub fn bind(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixListenerImp::bind(&path) .map(|inner| UnixListener { inner: inner }) } } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 5886c9cc3e2..ea232ad0c3f 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -18,8 +18,8 @@ use prelude::v1::*; -use c_str::{CString, ToCStr}; use collections::HashMap; +use ffi::CString; use fmt; use hash::Hash; use io::pipe::{PipeStream, PipePair}; @@ -35,6 +35,7 @@ use thread::Thread; #[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to /// SIGTERM on unix platforms. @@ -109,11 +110,11 @@ pub struct Process { impl Hash for EnvKey { fn hash(&self, state: &mut SipState) { let &EnvKey(ref x) = self; - match x.as_str() { - Some(s) => for ch in s.chars() { + match str::from_utf8(x.as_bytes()) { + Ok(s) => for ch in s.chars() { (ch as u8 as char).to_lowercase().hash(state); }, - None => x.hash(state) + Err(..) => x.hash(state) } } } @@ -123,8 +124,8 @@ impl PartialEq for EnvKey { fn eq(&self, other: &EnvKey) -> bool { let &EnvKey(ref x) = self; let &EnvKey(ref y) = other; - match (x.as_str(), y.as_str()) { - (Some(xs), Some(ys)) => { + match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { + (Ok(xs), Ok(ys)) => { if xs.len() != ys.len() { return false } else { @@ -185,10 +186,10 @@ pub struct Command { } // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an +// we cannot usefully take BytesContainer arguments by reference (without forcing an // additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by +// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by BytesContainer should be passed by // reference. (Here: {new, arg, args, env}.) impl Command { @@ -203,9 +204,9 @@ impl Command { /// /// Builder methods are provided to change these defaults and /// otherwise configure the process. - pub fn new(program: T) -> Command { + pub fn new(program: T) -> Command { Command { - program: program.to_c_str(), + program: CString::from_slice(program.container_as_bytes()), args: Vec::new(), env: None, cwd: None, @@ -219,27 +220,29 @@ pub fn new(program: T) -> Command { } /// Add an argument to pass to the program. - pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(arg.to_c_str()); + pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { + self.args.push(CString::from_slice(arg.container_as_bytes())); self } /// Add multiple arguments to pass to the program. - pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| arg.to_c_str()));; + pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { + self.args.extend(args.iter().map(|arg| { + CString::from_slice(arg.container_as_bytes()) + })); self } // Get a mutable borrow of the environment variable map for this `Command`. - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { + fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { match self.env { Some(ref mut map) => map, None => { // if the env is currently just inheriting from the parent's, // materialize the parent's env into a hashtable. - self.env = Some(os::env_as_bytes().into_iter() - .map(|(k, v)| (EnvKey(k.to_c_str()), - v.to_c_str())) - .collect()); + self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { + (EnvKey(CString::from_slice(k.as_slice())), + CString::from_slice(v.as_slice())) + }).collect()); self.env.as_mut().unwrap() } } @@ -249,15 +252,20 @@ fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { /// /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, /// and case-sensitive on all other platforms. - pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U) - -> &'a mut Command { - self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str()); + pub fn env<'a, T, U>(&'a mut self, key: T, val: U) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + let val = CString::from_slice(val.container_as_bytes()); + self.get_env_map().insert(key, val); self } /// Removes an environment variable mapping. - pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { - self.get_env_map().remove(&EnvKey(key.to_c_str())); + pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command + where T: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + self.get_env_map().remove(&key); self } @@ -265,16 +273,19 @@ pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { /// /// If the given slice contains multiple instances of an environment /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command { - self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str())) - .collect()); + pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)]) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + self.env = Some(env.iter().map(|&(ref k, ref v)| { + (EnvKey(CString::from_slice(k.container_as_bytes())), + CString::from_slice(v.container_as_bytes())) + }).collect()); self } /// Set the working directory for the child process. pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(dir.to_c_str()); + self.cwd = Some(CString::from_slice(dir.as_vec())); self } @@ -389,9 +400,9 @@ impl fmt::Show for Command { /// non-utf8 data is lossily converted using the utf8 replacement /// character. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes_no_nul()))); + try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes()))); for arg in self.args.iter() { - try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes_no_nul()))); + try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes()))); } Ok(()) } @@ -1208,13 +1219,13 @@ fn dont_close_fd_on_command_spawn() { #[test] #[cfg(windows)] fn env_map_keys_ci() { - use c_str::ToCStr; + use ffi::CString; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); cmd.env("Path", "bar"); let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey("PATH".to_c_str())); - assert!(val.unwrap() == &"bar".to_c_str()); + let val = env.get(&EnvKey(CString::from_slice(b"PATH"))); + assert!(val.unwrap() == &CString::from_slice(b"bar")); } } diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs index 45e0dd4e8e5..394686be814 100644 --- a/src/libstd/io/tempfile.rs +++ b/src/libstd/io/tempfile.rs @@ -10,16 +10,18 @@ //! Temporary files and directories -use io::{fs, IoResult}; +use io::{fs, IoError, IoErrorKind, IoResult}; use io; -use libc; +use iter::{IteratorExt, range}; use ops::Drop; use option::Option; use option::Option::{None, Some}; use os; use path::{Path, GenericPath}; +use rand::{Rng, thread_rng}; use result::Result::{Ok, Err}; -use sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering}; +use str::StrExt; +use string::String; /// A wrapper for a path to temporary directory implementing automatic /// scope-based deletion. @@ -31,7 +33,7 @@ /// /// { /// // create a temporary directory -/// let tmpdir = match TempDir::new("mysuffix") { +/// let tmpdir = match TempDir::new("myprefix") { /// Ok(dir) => dir, /// Err(e) => panic!("couldn't create temporary directory: {}", e) /// }; @@ -46,7 +48,7 @@ /// } /// { /// // create a temporary directory, this time using a custom path -/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "mysuffix") { +/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "myprefix") { /// Ok(dir) => dir, /// Err(e) => panic!("couldn't create temporary directory: {}", e) /// }; @@ -61,7 +63,7 @@ /// } /// { /// // create a temporary directory -/// let tmpdir = match TempDir::new("mysuffix") { +/// let tmpdir = match TempDir::new("myprefix") { /// Ok(dir) => dir, /// Err(e) => panic!("couldn't create temporary directory: {}", e) /// }; @@ -78,47 +80,59 @@ pub struct TempDir { disarmed: bool } +// How many times should we (re)try finding an unused random name? It should be +// enough that an attacker will run out of luck before we run out of patience. +const NUM_RETRIES: u32 = 1 << 31; +// How many characters should we include in a random file name? It needs to +// be enough to dissuade an attacker from trying to preemptively create names +// of that length, but not so huge that we unnecessarily drain the random number +// generator of entropy. +const NUM_RAND_CHARS: uint = 12; + impl TempDir { /// Attempts to make a temporary directory inside of `tmpdir` whose name - /// will have the suffix `suffix`. The directory will be automatically + /// will have the prefix `prefix`. The directory will be automatically /// deleted once the returned wrapper is destroyed. /// /// If no directory can be created, `Err` is returned. - pub fn new_in(tmpdir: &Path, suffix: &str) -> IoResult { + pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult { if !tmpdir.is_absolute() { let abs_tmpdir = try!(os::make_absolute(tmpdir)); - return TempDir::new_in(&abs_tmpdir, suffix); + return TempDir::new_in(&abs_tmpdir, prefix); } - static CNT: AtomicUint = ATOMIC_UINT_INIT; - - let mut attempts = 0u; - loop { - let filename = - format!("rs-{}-{}-{}", - unsafe { libc::getpid() }, - CNT.fetch_add(1, Ordering::SeqCst), - suffix); - let p = tmpdir.join(filename); - match fs::mkdir(&p, io::USER_RWX) { - Err(error) => { - if attempts >= 1000 { - return Err(error) - } - attempts += 1; - } - Ok(()) => return Ok(TempDir { path: Some(p), disarmed: false }) + let mut rng = thread_rng(); + for _ in range(0, NUM_RETRIES) { + let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect(); + let leaf = if prefix.len() > 0 { + format!("{}.{}", prefix, suffix) + } else { + // If we're given an empty string for a prefix, then creating a + // directory starting with "." would lead to it being + // semi-invisible on some systems. + suffix + }; + let path = tmpdir.join(leaf); + match fs::mkdir(&path, io::USER_RWX) { + Ok(_) => return Ok(TempDir { path: Some(path), disarmed: false }), + Err(IoError{kind:IoErrorKind::PathAlreadyExists,..}) => (), + Err(e) => return Err(e) } } + + return Err(IoError{ + kind: IoErrorKind::PathAlreadyExists, + desc:"Exhausted", + detail: None}); } /// Attempts to make a temporary directory inside of `os::tmpdir()` whose - /// name will have the suffix `suffix`. The directory will be automatically + /// name will have the prefix `prefix`. The directory will be automatically /// deleted once the returned wrapper is destroyed. /// /// If no directory can be created, `Err` is returned. - pub fn new(suffix: &str) -> IoResult { - TempDir::new_in(&os::tmpdir(), suffix) + pub fn new(prefix: &str) -> IoResult { + TempDir::new_in(&os::tmpdir(), prefix) } /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 608ad9882b9..2d3a4639379 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -208,10 +208,10 @@ /* Runtime and platform support */ -pub mod thread_local; -pub mod c_str; -pub mod c_vec; +pub mod thread_local; // first for macros + pub mod dynamic_lib; +pub mod ffi; pub mod fmt; pub mod io; pub mod os; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 63fd3209cc0..fb2d23b01b4 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -33,7 +33,7 @@ /// # #![allow(unreachable_code)] /// panic!(); /// panic!("this is a terrible mistake!"); -/// panic!(4i); // panic with the value of 4 to be collected elsewhere +/// panic!(4); // panic with the value of 4 to be collected elsewhere /// panic!("this is a {} {message}", "fancy", message = "message"); /// ``` #[macro_export] @@ -74,7 +74,7 @@ macro_rules! panic { /// // assert with a custom message /// # let x = true; /// assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; +/// # let a = 3; let b = 27; /// assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[macro_export] @@ -99,8 +99,8 @@ macro_rules! assert { /// # Example /// /// ``` -/// let a = 3i; -/// let b = 1i + 2i; +/// let a = 3; +/// let b = 1 + 2; /// assert_eq!(a, b); /// ``` #[macro_export] @@ -141,7 +141,7 @@ macro_rules! assert_eq { /// // assert with a custom message /// # let x = true; /// debug_assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; +/// # let a = 3; let b = 27; /// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[macro_export] @@ -162,8 +162,8 @@ macro_rules! debug_assert { /// # Example /// /// ``` -/// let a = 3i; -/// let b = 1i + 2i; +/// let a = 3; +/// let b = 1 + 2; /// debug_assert_eq!(a, b); /// ``` #[macro_export] @@ -238,7 +238,7 @@ macro_rules! unimplemented { /// ``` /// format!("test"); /// format!("hello {}", "world!"); -/// format!("x = {}, y = {y}", 10i, y = 30i); +/// format!("x = {}, y = {y}", 10, y = 30); /// ``` #[macro_export] #[stable] @@ -338,7 +338,7 @@ macro_rules! vec { /// let (tx1, rx1) = channel(); /// let (tx2, rx2) = channel(); /// # fn long_running_task() {} -/// # fn calculate_the_answer() -> int { 42i } +/// # fn calculate_the_answer() -> int { 42 } /// /// Thread::spawn(move|| { long_running_task(); tx1.send(()) }).detach(); /// Thread::spawn(move|| { tx2.send(calculate_the_answer()) }).detach(); @@ -507,7 +507,7 @@ macro_rules! concat_idents { /// # Example /// /// ``` - /// let s = concat!("test", 10i, 'b', true); + /// let s = concat!("test", 10, 'b', true); /// assert_eq!(s, "test10btrue"); /// ``` #[macro_export] diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 20dd70f0faa..67fe599ecd6 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -16,7 +16,7 @@ use self::SignificantDigits::*; use self::SignFormat::*; -use char::{self, Char}; +use char::{self, CharExt}; use num::{self, Int, Float, ToPrimitive}; use num::FpCategory as Fp; use ops::FnMut; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index be8f82349c2..300ceec4b45 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -57,12 +57,10 @@ use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering}; use vec::Vec; -#[cfg(unix)] use c_str::ToCStr; +#[cfg(unix)] use ffi::{self, CString}; -#[cfg(unix)] -pub use sys::ext as unix; -#[cfg(windows)] -pub use sys::ext as windows; +#[cfg(unix)] pub use sys::ext as unix; +#[cfg(windows)] pub use sys::ext as windows; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -196,15 +194,14 @@ pub fn getenv(n: &str) -> Option { /// /// Panics if `n` has any interior NULs. pub fn getenv_as_bytes(n: &str) -> Option> { - use c_str::CString; - unsafe { with_env_lock(|| { - let s = n.with_c_str(|buf| libc::getenv(buf)); + let s = CString::from_slice(n.as_bytes()); + let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(CString::new(s as *const libc::c_char, false).as_bytes_no_nul().to_vec()) + Some(ffi::c_str_to_bytes(&s).to_vec()) } }) } @@ -253,13 +250,12 @@ pub fn setenv(n: &str, v: T) { fn _setenv(n: &str, v: &[u8]) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - v.with_c_str(|vbuf| { - if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 { - panic!(IoError::last_error()); - } - }) - }) + let k = CString::from_slice(n.as_bytes()); + let v = CString::from_slice(v); + if libc::funcs::posix01::unistd::setenv(k.as_ptr(), + v.as_ptr(), 1) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -289,11 +285,10 @@ pub fn unsetenv(n: &str) { fn _unsetenv(n: &str) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 { - panic!(IoError::last_error()); - } - }) + let nbuf = CString::from_slice(n.as_bytes()); + if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -618,11 +613,10 @@ pub fn get_exit_status() -> int { #[cfg(target_os = "macos")] unsafe fn load_argc_and_argv(argc: int, argv: *const *const c_char) -> Vec> { - use c_str::CString; use iter::range; range(0, argc as uint).map(|i| { - CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } @@ -652,7 +646,6 @@ fn real_args_as_bytes() -> Vec> { // res #[cfg(target_os = "ios")] fn real_args_as_bytes() -> Vec> { - use c_str::CString; use iter::range; use mem; diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index bf9ffbffe7d..2f014872402 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -62,7 +62,7 @@ #![experimental] use core::kinds::Sized; -use c_str::CString; +use ffi::CString; use clone::Clone; use fmt; use iter::IteratorExt; @@ -892,7 +892,7 @@ fn container_as_bytes(&self) -> &[u8] { impl BytesContainer for CString { #[inline] fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_bytes_no_nul() + self.as_bytes() } } @@ -913,21 +913,3 @@ fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) } fn contains_nul(v: &T) -> bool { v.container_as_bytes().iter().any(|&x| x == 0) } - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use c_str::ToCStr; - use path::{WindowsPath, PosixPath}; - - #[test] - fn test_cstring() { - let input = "/foo/bar/baz"; - let path: PosixPath = PosixPath::new(input.to_c_str()); - assert_eq!(path.as_vec(), input.as_bytes()); - - let input = r"\foo\bar\baz"; - let path: WindowsPath = WindowsPath::new(input.to_c_str()); - assert_eq!(path.as_str().unwrap(), input); - } -} diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index ae82e201cb8..013212b2705 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -10,19 +10,16 @@ //! POSIX file path handling -use c_str::{CString, ToCStr}; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; -use option::Option; -use option::Option::{None, Some}; use kinds::Sized; -use str::{FromStr, Str}; -use str; -use slice::{Split, AsSlice, SliceConcatExt, SliceExt}; +use option::Option::{self, Some, None}; +use slice::{AsSlice, Split, SliceExt, SliceConcatExt}; +use str::{self, FromStr, StrExt}; use vec::Vec; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; @@ -86,26 +83,6 @@ fn from_str(s: &str) -> Option { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index aae8d6cadef..05129a7ab9d 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -15,20 +15,18 @@ use self::PathPrefix::*; use ascii::AsciiExt; -use c_str::{CString, ToCStr}; +use char::CharExt; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map, repeat}; use mem; -use option::Option; -use option::Option::{Some, None}; +use option::Option::{self, Some, None}; use slice::{SliceExt, SliceConcatExt}; use str::{SplitTerminator, FromStr, StrExt}; use string::{String, ToString}; -use unicode::char::UnicodeChar; use vec::Vec; use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; @@ -112,26 +110,6 @@ fn from_str(s: &str) -> Option { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[cfg(not(test))] #[inline] diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index a122cb81b8c..f6bdcd53dff 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -22,7 +22,7 @@ // Reexported types and traits #[stable] #[doc(no_inline)] pub use boxed::Box; -#[stable] #[doc(no_inline)] pub use char::{Char, UnicodeChar}; +#[stable] #[doc(no_inline)] pub use char::CharExt; #[stable] #[doc(no_inline)] pub use clone::Clone; #[stable] #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable] #[doc(no_inline)] pub use iter::CloneIteratorExt; diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index aa28c8266d1..cadaae5de5c 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -245,7 +245,7 @@ /// The standard RNG. This is designed to be efficient on the current /// platform. -#[derive(Copy)] +#[deriving(Copy, Clone)] pub struct StdRng { rng: IsaacWordRng, } @@ -322,6 +322,7 @@ fn reseed(&mut self, rng: &mut StdRng) { type ThreadRngInner = reseeding::ReseedingRng; /// The thread-local RNG. +#[deriving(Clone)] pub struct ThreadRng { rng: Rc>, } diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 4734a39c835..86abacb9365 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -46,8 +46,9 @@ pub fn clone() -> Option>> { imp::clone() } mod imp { use prelude::v1::*; + use libc; use mem; - use slice; + use ffi; use sync::{StaticMutex, MUTEX_INIT}; @@ -95,13 +96,9 @@ fn get_global_ptr() -> *mut Option>>> { } unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec> { + let argv = argv as *const *const libc::c_char; range(0, argc as uint).map(|i| { - let arg = *argv.offset(i as int); - let mut len = 0u; - while *arg.offset(len as int) != 0 { - len += 1u; - } - slice::from_raw_buf(&arg, len).to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 578239c9cc4..bb0b6fe804b 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -15,7 +15,7 @@ use prelude::v1::*; use os; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; pub use sys::backtrace::write; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index a48a8edd82f..71169386c18 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -67,7 +67,7 @@ use intrinsics; use libc::c_void; use mem; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::{Once, ONCE_INIT}; use rt::libunwind as uw; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 883a01fa318..bc01ce926f8 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -19,7 +19,7 @@ use os; use slice; use str; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; /// Dynamically inquire about whether we're running under V. /// You should usually not use this unless your test definitely diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index de1724cbc4e..338cadafff7 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -8,7 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Multi-producer, single-consumer communication primitives threads +//! Communication primitives for concurrent tasks +//! +//! Rust makes it very difficult to share data among tasks to prevent race +//! conditions and to improve parallelism, but there is often a need for +//! communication between concurrent tasks. The primitives defined in this +//! module are the building blocks for synchronization in rust. //! //! This module provides message-based communication over channels, concretely //! defined among three types: @@ -18,10 +23,12 @@ //! * `Receiver` //! //! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both -//! senders are clone-able (multi-producer) such that many threads can send -//! simultaneously to one receiver (single-consumer). These channels are +//! senders are clone-able such that many tasks can send simultaneously to one +//! receiver. These channels are *task blocking*, not *thread blocking*. This +//! means that if one task is blocked on a channel, other tasks can continue to +//! make progress. //! -//! These channels come in two flavors: +//! Rust channels come in one of two flavors: //! //! 1. An asynchronous, infinitely buffered channel. The `channel()` function //! will return a `(Sender, Receiver)` tuple where all sends will be @@ -36,39 +43,36 @@ //! "rendezvous" channel where each sender atomically hands off a message to //! a receiver. //! -//! ## Disconnection +//! ## Panic Propagation //! -//! The send and receive operations on channels will all return a `Result` -//! indicating whether the operation succeeded or not. An unsuccessful operation -//! is normally indicative of the other half of a channel having "hung up" by -//! being dropped in its corresponding thread. +//! In addition to being a core primitive for communicating in rust, channels +//! are the points at which panics are propagated among tasks. Whenever the one +//! half of channel is closed, the other half will have its next operation +//! `panic!`. The purpose of this is to allow propagation of panics among tasks +//! that are linked to one another via channels. //! -//! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so `Err` will be returned. Many applications will -//! continue to `unwrap()` the results returned from this module, instigating a -//! propagation of failure among threads if one unexpectedly dies. +//! There are methods on both of senders and receivers to perform their +//! respective operations without panicking, however. //! -//! # Examples +//! # Example //! //! Simple usage: //! //! ``` //! use std::thread::Thread; -//! use std::sync::mpsc::channel; //! //! // Create a simple streaming channel //! let (tx, rx) = channel(); //! Thread::spawn(move|| { -//! tx.send(10i).unwrap(); +//! tx.send(10); //! }).detach(); -//! assert_eq!(rx.recv().unwrap(), 10i); +//! assert_eq!(rx.recv(), 10); //! ``` //! //! Shared usage: //! //! ``` //! use std::thread::Thread; -//! use std::sync::mpsc::channel; //! //! // Create a shared channel that can be sent along from many threads //! // where tx is the sending half (tx for transmission), and rx is the receiving @@ -77,40 +81,37 @@ //! for i in range(0i, 10i) { //! let tx = tx.clone(); //! Thread::spawn(move|| { -//! tx.send(i).unwrap(); +//! tx.send(i); //! }).detach() //! } //! //! for _ in range(0i, 10i) { -//! let j = rx.recv().unwrap(); +//! let j = rx.recv(); //! assert!(0 <= j && j < 10); //! } //! ``` //! //! Propagating panics: //! -//! ``` -//! use std::sync::mpsc::channel; -//! -//! // The call to recv() will return an error because the channel has already -//! // hung up (or been deallocated) +//! ```should_fail +//! // The call to recv() will panic!() because the channel has already hung +//! // up (or been deallocated) //! let (tx, rx) = channel::(); //! drop(tx); -//! assert!(rx.recv().is_err()); +//! rx.recv(); //! ``` //! //! Synchronous channels: //! //! ``` //! use std::thread::Thread; -//! use std::sync::mpsc::sync_channel; //! //! let (tx, rx) = sync_channel::(0); //! Thread::spawn(move|| { //! // This will wait for the parent task to start receiving -//! tx.send(53).unwrap(); +//! tx.send(53); //! }).detach(); -//! rx.recv().unwrap(); +//! rx.recv(); //! ``` //! //! Reading from a channel with a timeout requires to use a Timer together @@ -119,7 +120,6 @@ //! after 10 seconds no matter what: //! //! ```no_run -//! use std::sync::mpsc::channel; //! use std::io::timer::Timer; //! use std::time::Duration; //! @@ -129,8 +129,8 @@ //! //! loop { //! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { +//! val = rx.recv() => println!("Received {}", val), +//! () = timeout.recv() => { //! println!("timed out, total time was more than 10 seconds"); //! break; //! } @@ -143,7 +143,6 @@ //! has been inactive for 5 seconds: //! //! ```no_run -//! use std::sync::mpsc::channel; //! use std::io::timer::Timer; //! use std::time::Duration; //! @@ -154,8 +153,8 @@ //! let timeout = timer.oneshot(Duration::seconds(5)); //! //! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { +//! val = rx.recv() => println!("Received {}", val), +//! () = timeout.recv() => { //! println!("timed out, no message received in 5 seconds"); //! break; //! } @@ -313,19 +312,38 @@ // And now that you've seen all the races that I found and attempted to fix, // here's the code for you to find some more! -use prelude::v1::*; +use core::prelude::*; -use sync::Arc; -use fmt; -use kinds::marker; -use mem; -use cell::UnsafeCell; +pub use self::TryRecvError::*; +pub use self::TrySendError::*; + +use alloc::arc::Arc; +use core::kinds; +use core::kinds::marker; +use core::mem; +use core::cell::UnsafeCell; pub use self::select::{Select, Handle}; use self::select::StartResult; use self::select::StartResult::*; use self::blocking::SignalToken; +macro_rules! test { + { fn $name:ident() $b:block $(#[$a:meta])*} => ( + mod $name { + #![allow(unused_imports)] + + use super::*; + use comm::*; + use thread::Thread; + use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option}; + use prelude::{Vec, Buffer, from_str, Clone}; + + $(#[$a])* #[test] fn f() { $b } + } + ) +} + mod blocking; mod oneshot; mod select; @@ -337,7 +355,7 @@ /// The receiving-half of Rust's channel type. This half can only be owned by /// one task -#[stable] +#[unstable] pub struct Receiver { inner: UnsafeCell>, } @@ -349,14 +367,14 @@ unsafe impl Send for Receiver { } /// An iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. -#[stable] -pub struct Iter<'a, T:'a> { +#[unstable] +pub struct Messages<'a, T:'a> { rx: &'a Receiver } /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. -#[stable] +#[unstable] pub struct Sender { inner: UnsafeCell>, } @@ -367,50 +385,30 @@ unsafe impl Send for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. -#[stable] +#[unstable = "this type may be renamed, but it will always exist"] pub struct SyncSender { inner: Arc>>, // can't share in an arc _marker: marker::NoSync, } -/// An error returned from the `send` function on channels. -/// -/// A `send` operation can only fail if the receiving end of a channel is -/// disconnected, implying that the data could never be received. The error -/// contains the data being sent as a payload so it can be recovered. -#[derive(PartialEq, Eq)] -#[stable] -pub struct SendError(pub T); - -/// An error returned from the `recv` function on a `Receiver`. -/// -/// The `recv` operation can only fail if the sending half of a channel is -/// disconnected, implying that no further messages will ever be received. -#[derive(PartialEq, Eq, Clone, Copy)] -#[stable] -pub struct RecvError; - /// This enumeration is the list of the possible reasons that try_recv could not /// return data when called. -#[derive(PartialEq, Clone, Copy)] -#[stable] +#[deriving(PartialEq, Clone, Copy, Show)] +#[experimental = "this is likely to be removed in changing try_recv()"] pub enum TryRecvError { /// This channel is currently empty, but the sender(s) have not yet /// disconnected, so data may yet become available. - #[stable] Empty, - /// This channel's sending half has become disconnected, and there will /// never be any more data received on this channel - #[stable] Disconnected, } /// This enumeration is the list of the possible error outcomes for the /// `SyncSender::try_send` method. -#[derive(PartialEq, Clone)] -#[stable] +#[deriving(PartialEq, Clone, Show)] +#[experimental = "this is likely to be removed in changing try_send()"] pub enum TrySendError { /// The data could not be sent on the channel because it would require that /// the callee block to send the data. @@ -418,13 +416,10 @@ pub enum TrySendError { /// If this is a buffered channel, then the buffer is full at this time. If /// this is not a buffered channel, then there is no receiver available to /// acquire the data. - #[stable] Full(T), - /// This channel's receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. - #[stable] - Disconnected(T), + RecvDisconnected(T), } enum Flavor { @@ -463,7 +458,6 @@ fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { /// # Example /// /// ``` -/// use std::sync::mpsc::channel; /// use std::thread::Thread; /// /// // tx is is the sending half (tx for transmission), and rx is the receiving @@ -473,15 +467,15 @@ fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { /// // Spawn off an expensive computation /// Thread::spawn(move|| { /// # fn expensive_computation() {} -/// tx.send(expensive_computation()).unwrap(); +/// tx.send(expensive_computation()); /// }).detach(); /// /// // Do some useful work for awhile /// /// // Let's see what that answer was -/// println!("{}", rx.recv().unwrap()); +/// println!("{}", rx.recv()); /// ``` -#[stable] +#[unstable] pub fn channel() -> (Sender, Receiver) { let a = Arc::new(RacyCell::new(oneshot::Packet::new())); (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) @@ -505,23 +499,23 @@ pub fn channel() -> (Sender, Receiver) { /// # Example /// /// ``` -/// use std::sync::mpsc::sync_channel; /// use std::thread::Thread; /// /// let (tx, rx) = sync_channel(1); /// /// // this returns immediately -/// tx.send(1i).unwrap(); +/// tx.send(1); /// /// Thread::spawn(move|| { /// // this will block until the previous message has been received -/// tx.send(2i).unwrap(); +/// tx.send(2); /// }).detach(); /// -/// assert_eq!(rx.recv().unwrap(), 1i); -/// assert_eq!(rx.recv().unwrap(), 2i); +/// assert_eq!(rx.recv(), 1); +/// assert_eq!(rx.recv(), 2); /// ``` -#[stable] +#[unstable = "this function may be renamed to more accurately reflect the type \ + of channel that is is creating"] pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { let a = Arc::new(RacyCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) @@ -538,6 +532,33 @@ fn new(inner: Flavor) -> Sender { } } + /// Sends a value along this channel to be received by the corresponding + /// receiver. + /// + /// Rust channels are infinitely buffered so this method will never block. + /// + /// # Panics + /// + /// This function will panic if the other end of the channel has hung up. + /// This means that if the corresponding receiver has fallen out of scope, + /// this function will trigger a panic message saying that a message is + /// being sent on a closed channel. + /// + /// Note that if this function does *not* panic, it does not mean that the + /// data will be successfully received. All sends are placed into a queue, + /// so it is possible for a send to succeed (the other end is alive), but + /// then the other end could immediately disconnect. + /// + /// The purpose of this functionality is to propagate panics among tasks. + /// If a panic is not desired, then consider using the `send_opt` method + #[experimental = "this function is being considered candidate for removal \ + to adhere to the general guidelines of rust"] + pub fn send(&self, t: T) { + if self.send_opt(t).is_err() { + panic!("sending on a closed channel"); + } + } + /// Attempts to send a value on this channel, returning it back if it could /// not be sent. /// @@ -549,34 +570,37 @@ fn new(inner: Flavor) -> Sender { /// will be received. It is possible for the corresponding receiver to /// hang up immediately after this function returns `Ok`. /// - /// This method will never block the current thread. + /// Like `send`, this method will never block. + /// + /// # Panics + /// + /// This method will never panic, it will return the message back to the + /// caller if the other end is disconnected /// /// # Example /// /// ``` - /// use std::sync::mpsc::channel; - /// /// let (tx, rx) = channel(); /// /// // This send is always successful - /// tx.send(1i).unwrap(); + /// assert_eq!(tx.send_opt(1), Ok(())); /// /// // This send will fail because the receiver is gone /// drop(rx); - /// assert_eq!(tx.send(1i).err().unwrap().0, 1); + /// assert_eq!(tx.send_opt(1), Err(1)); /// ``` - pub fn send(&self, t: T) -> Result<(), SendError> { + #[unstable = "this function may be renamed to send() in the future"] + pub fn send_opt(&self, t: T) -> Result<(), T> { let (new_inner, ret) = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { unsafe { let p = p.get(); if !(*p).sent() { - return (*p).send(t).map_err(SendError); + return (*p).send(t); } else { let a = Arc::new(RacyCell::new(stream::Packet::new())); - let rx = Receiver::new(Flavor::Stream(a.clone())); - match (*p).upgrade(rx) { + match (*p).upgrade(Receiver::new(Flavor::Stream(a.clone()))) { oneshot::UpSuccess => { let ret = (*a.get()).send(t); (a, ret) @@ -594,12 +618,8 @@ pub fn send(&self, t: T) -> Result<(), SendError> { } } } - Flavor::Stream(ref p) => return unsafe { - (*p.get()).send(t).map_err(SendError) - }, - Flavor::Shared(ref p) => return unsafe { - (*p.get()).send(t).map_err(SendError) - }, + Flavor::Stream(ref p) => return unsafe { (*p.get()).send(t) }, + Flavor::Shared(ref p) => return unsafe { (*p.get()).send(t) }, Flavor::Sync(..) => unreachable!(), }; @@ -607,7 +627,7 @@ pub fn send(&self, t: T) -> Result<(), SendError> { let tmp = Sender::new(Flavor::Stream(new_inner)); mem::swap(self.inner_mut(), tmp.inner_mut()); } - ret.map_err(SendError) + return ret; } } @@ -619,8 +639,7 @@ fn clone(&self) -> Sender { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - let rx = Receiver::new(Flavor::Shared(a.clone())); - match (*p.get()).upgrade(rx) { + match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { oneshot::UpSuccess | oneshot::UpDisconnected => (a, None, guard), oneshot::UpWoke(task) => (a, Some(task), guard) @@ -631,8 +650,7 @@ fn clone(&self) -> Sender { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - let rx = Receiver::new(Flavor::Shared(a.clone())); - match (*p.get()).upgrade(rx) { + match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { stream::UpSuccess | stream::UpDisconnected => (a, None, guard), stream::UpWoke(task) => (a, Some(task), guard), @@ -683,29 +701,59 @@ fn new(inner: Arc>>) -> SyncSender { /// available or a receiver is available to hand off the message to. /// /// Note that a successful send does *not* guarantee that the receiver will - /// ever see the data if there is a buffer on this channel. Items may be + /// ever see the data if there is a buffer on this channel. Messages may be /// enqueued in the internal buffer for the receiver to receive at a later /// time. If the buffer size is 0, however, it can be guaranteed that the /// receiver has indeed received the data if this function returns success. /// - /// This function will never panic, but it may return `Err` if the - /// `Receiver` has disconnected and is no longer able to receive - /// information. - #[stable] - pub fn send(&self, t: T) -> Result<(), SendError> { - unsafe { (*self.inner.get()).send(t).map_err(SendError) } + /// # Panics + /// + /// Similarly to `Sender::send`, this function will panic if the + /// corresponding `Receiver` for this channel has disconnected. This + /// behavior is used to propagate panics among tasks. + /// + /// If a panic is not desired, you can achieve the same semantics with the + /// `SyncSender::send_opt` method which will not panic if the receiver + /// disconnects. + #[experimental = "this function is being considered candidate for removal \ + to adhere to the general guidelines of rust"] + pub fn send(&self, t: T) { + if self.send_opt(t).is_err() { + panic!("sending on a closed channel"); + } + } + + /// Send a value on a channel, returning it back if the receiver + /// disconnected + /// + /// This method will *block* to send the value `t` on the channel, but if + /// the value could not be sent due to the receiver disconnecting, the value + /// is returned back to the callee. This function is similar to `try_send`, + /// except that it will block if the channel is currently full. + /// + /// # Panics + /// + /// This function cannot panic. + #[unstable = "this function may be renamed to send() in the future"] + pub fn send_opt(&self, t: T) -> Result<(), T> { + unsafe { (*self.inner.get()).send(t) } } /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send` by returning immediately if the + /// This method differs from `send_opt` by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send`, this function has two failure cases + /// data. Compared with `send_opt`, this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// /// See `SyncSender::send` for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. - #[stable] + /// + /// # Panics + /// + /// This function cannot panic + #[unstable = "the return type of this function is candidate for \ + modification"] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { unsafe { (*self.inner.get()).try_send(t) } } @@ -735,6 +783,34 @@ fn new(inner: Flavor) -> Receiver { Receiver { inner: UnsafeCell::new(inner) } } + /// Blocks waiting for a value on this receiver + /// + /// This function will block if necessary to wait for a corresponding send + /// on the channel from its paired `Sender` structure. This receiver will + /// be woken up when data is ready, and the data will be returned. + /// + /// # Panics + /// + /// Similar to channels, this method will trigger a task panic if the + /// other end of the channel has hung up (been deallocated). The purpose of + /// this is to propagate panics among tasks. + /// + /// If a panic is not desired, then there are two options: + /// + /// * If blocking is still desired, the `recv_opt` method will return `None` + /// when the other end hangs up + /// + /// * If blocking is not desired, then the `try_recv` method will attempt to + /// peek at a value on this receiver. + #[experimental = "this function is being considered candidate for removal \ + to adhere to the general guidelines of rust"] + pub fn recv(&self) -> T { + match self.recv_opt() { + Ok(t) => t, + Err(()) => panic!("receiving on a closed channel"), + } + } + /// Attempts to return a pending value on this receiver without blocking /// /// This method will never block the caller in order to wait for data to @@ -743,46 +819,42 @@ fn new(inner: Flavor) -> Receiver { /// /// This is useful for a flavor of "optimistic check" before deciding to /// block on a receiver. - #[stable] + /// + /// # Panics + /// + /// This function cannot panic. + #[unstable = "the return type of this function may be altered"] pub fn try_recv(&self) -> Result { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(oneshot::Empty) => return Err(TryRecvError::Empty), - Err(oneshot::Disconnected) => { - return Err(TryRecvError::Disconnected) - } + Err(oneshot::Empty) => return Err(Empty), + Err(oneshot::Disconnected) => return Err(Disconnected), Err(oneshot::Upgraded(rx)) => rx, } } Flavor::Stream(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(stream::Empty) => return Err(TryRecvError::Empty), - Err(stream::Disconnected) => { - return Err(TryRecvError::Disconnected) - } + Err(stream::Empty) => return Err(Empty), + Err(stream::Disconnected) => return Err(Disconnected), Err(stream::Upgraded(rx)) => rx, } } Flavor::Shared(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(shared::Empty) => return Err(TryRecvError::Empty), - Err(shared::Disconnected) => { - return Err(TryRecvError::Disconnected) - } + Err(shared::Empty) => return Err(Empty), + Err(shared::Disconnected) => return Err(Disconnected), } } Flavor::Sync(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(sync::Empty) => return Err(TryRecvError::Empty), - Err(sync::Disconnected) => { - return Err(TryRecvError::Disconnected) - } + Err(sync::Empty) => return Err(Empty), + Err(sync::Disconnected) => return Err(Disconnected), } } }; @@ -793,26 +865,27 @@ pub fn try_recv(&self) -> Result { } } - /// Attempt to wait for a value on this receiver, returning an error if the + /// Attempt to wait for a value on this receiver, but does not panic if the /// corresponding channel has hung up. /// - /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and - /// return that message. + /// This implementation of iterators for ports will always block if there is + /// not data available on the receiver, but it will not panic in the case + /// that the channel has been deallocated. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to - /// indicate that no more messages can ever be received on this channel. - #[stable] - pub fn recv(&self) -> Result { + /// In other words, this function has the same semantics as the `recv` + /// method except for the panic aspect. + /// + /// If the channel has hung up, then `Err` is returned. Otherwise `Ok` of + /// the value found on the receiver is returned. + #[unstable = "this function may be renamed to recv()"] + pub fn recv_opt(&self) -> Result { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(oneshot::Empty) => return unreachable!(), - Err(oneshot::Disconnected) => return Err(RecvError), + Err(oneshot::Disconnected) => return Err(()), Err(oneshot::Upgraded(rx)) => rx, } } @@ -820,7 +893,7 @@ pub fn recv(&self) -> Result { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(stream::Empty) => return unreachable!(), - Err(stream::Disconnected) => return Err(RecvError), + Err(stream::Disconnected) => return Err(()), Err(stream::Upgraded(rx)) => rx, } } @@ -828,12 +901,10 @@ pub fn recv(&self) -> Result { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(shared::Empty) => return unreachable!(), - Err(shared::Disconnected) => return Err(RecvError), + Err(shared::Disconnected) => return Err(()), } } - Flavor::Sync(ref p) => return unsafe { - (*p.get()).recv().map_err(|()| RecvError) - } + Flavor::Sync(ref p) => return unsafe { (*p.get()).recv() } }; unsafe { mem::swap(self.inner_mut(), new_port.inner_mut()); @@ -843,9 +914,9 @@ pub fn recv(&self) -> Result { /// Returns an iterator that will block waiting for messages, but never /// `panic!`. It will return `None` when the channel has hung up. - #[stable] - pub fn iter(&self) -> Iter { - Iter { rx: self } + #[unstable] + pub fn iter<'a>(&'a self) -> Messages<'a, T> { + Messages { rx: self } } } @@ -936,10 +1007,8 @@ fn abort_selection(&self) -> bool { } #[unstable] -impl<'a, T: Send> Iterator for Iter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { self.rx.recv().ok() } +impl<'a, T: Send> Iterator for Messages<'a, T> { + fn next(&mut self) -> Option { self.rx.recv_opt().ok() } } #[unsafe_destructor] @@ -972,425 +1041,368 @@ unsafe fn get(&self) -> *mut T { unsafe impl Send for RacyCell { } -unsafe impl Sync for RacyCell { } // Oh dear - -impl fmt::Show for SendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "sending on a closed channel".fmt(f) - } -} - -impl fmt::Show for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TrySendError::Full(..) => { - "sending on a full channel".fmt(f) - } - TrySendError::Disconnected(..) => { - "sending on a closed channel".fmt(f) - } - } - } -} - -impl fmt::Show for RecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "receiving on a closed channel".fmt(f) - } -} +unsafe impl kinds::Sync for RacyCell { } // Oh dear -impl fmt::Show for TryRecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TryRecvError::Empty => { - "receiving on an empty channel".fmt(f) - } - TryRecvError::Disconnected => { - "receiving on a closed channel".fmt(f) - } - } - } -} #[cfg(test)] mod test { - use prelude::v1::*; - - use os; use super::*; - use thread::Thread; + use prelude::{spawn, range, Some, None, from_str, Clone, Str}; + use os; pub fn stress_factor() -> uint { match os::getenv("RUST_TEST_STRESS") { - Some(val) => val.parse().unwrap(), + Some(val) => from_str::(val.as_slice()).unwrap(), None => 1, } } - #[test] - fn smoke() { + test! { fn smoke() { let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } + tx.send(1); + assert_eq!(rx.recv(), 1); + } } - #[test] - fn drop_full() { + test! { fn drop_full() { let (tx, _rx) = channel(); - tx.send(box 1i).unwrap(); - } + tx.send(box 1i); + } } - #[test] - fn drop_full_shared() { + test! { fn drop_full_shared() { let (tx, _rx) = channel(); drop(tx.clone()); drop(tx.clone()); - tx.send(box 1i).unwrap(); - } + tx.send(box 1i); + } } - #[test] - fn smoke_shared() { + test! { fn smoke_shared() { let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); + tx.send(1); + assert_eq!(rx.recv(), 1); let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } + tx.send(1); + assert_eq!(rx.recv(), 1); + } } - #[test] - fn smoke_threads() { + test! { fn smoke_threads() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { - tx.send(1).unwrap(); + spawn(move|| { + tx.send(1); }); - assert_eq!(rx.recv().unwrap(), 1); - } + assert_eq!(rx.recv(), 1); + } } - #[test] - fn smoke_port_gone() { + test! { fn smoke_port_gone() { let (tx, rx) = channel::(); drop(rx); - assert!(tx.send(1).is_err()); - } + tx.send(1); + } #[should_fail] } - #[test] - fn smoke_shared_port_gone() { + test! { fn smoke_shared_port_gone() { let (tx, rx) = channel::(); drop(rx); - assert!(tx.send(1).is_err()) - } + tx.send(1); + } #[should_fail] } - #[test] - fn smoke_shared_port_gone2() { + test! { fn smoke_shared_port_gone2() { let (tx, rx) = channel::(); drop(rx); let tx2 = tx.clone(); drop(tx); - assert!(tx2.send(1).is_err()); - } + tx2.send(1); + } #[should_fail] } - #[test] - fn port_gone_concurrent() { + test! { fn port_gone_concurrent() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); + spawn(move|| { + rx.recv(); }); - while tx.send(1).is_ok() {} - } + loop { tx.send(1) } + } #[should_fail] } - #[test] - fn port_gone_concurrent_shared() { + test! { fn port_gone_concurrent_shared() { let (tx, rx) = channel::(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); + spawn(move|| { + rx.recv(); }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } + loop { + tx.send(1); + tx2.send(1); + } + } #[should_fail] } - #[test] - fn smoke_chan_gone() { + test! { fn smoke_chan_gone() { let (tx, rx) = channel::(); drop(tx); - assert!(rx.recv().is_err()); - } + rx.recv(); + } #[should_fail] } - #[test] - fn smoke_chan_gone_shared() { + test! { fn smoke_chan_gone_shared() { let (tx, rx) = channel::<()>(); let tx2 = tx.clone(); drop(tx); drop(tx2); - assert!(rx.recv().is_err()); - } + rx.recv(); + } #[should_fail] } - #[test] - fn chan_gone_concurrent() { + test! { fn chan_gone_concurrent() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { - tx.send(1).unwrap(); - tx.send(1).unwrap(); + spawn(move|| { + tx.send(1); + tx.send(1); }); - while rx.recv().is_ok() {} - } + loop { rx.recv(); } + } #[should_fail] } - #[test] - fn stress() { + test! { fn stress() { let (tx, rx) = channel::(); - let t = Thread::spawn(move|| { - for _ in range(0u, 10000) { tx.send(1i).unwrap(); } + spawn(move|| { + for _ in range(0u, 10000) { tx.send(1i); } }); for _ in range(0u, 10000) { - assert_eq!(rx.recv().unwrap(), 1); + assert_eq!(rx.recv(), 1); } - t.join().ok().unwrap(); - } + } } - #[test] - fn stress_shared() { + test! { fn stress_shared() { static AMT: uint = 10000; static NTHREADS: uint = 8; let (tx, rx) = channel::(); + let (dtx, drx) = channel::<()>(); - let t = Thread::spawn(move|| { + spawn(move|| { for _ in range(0, AMT * NTHREADS) { - assert_eq!(rx.recv().unwrap(), 1); + assert_eq!(rx.recv(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } + dtx.send(()); }); for _ in range(0, NTHREADS) { let tx = tx.clone(); - Thread::spawn(move|| { - for _ in range(0, AMT) { tx.send(1).unwrap(); } - }).detach(); + spawn(move|| { + for _ in range(0, AMT) { tx.send(1); } + }); } drop(tx); - t.join().ok().unwrap(); - } + drx.recv(); + } } #[test] fn send_from_outside_runtime() { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::(); - let t1 = Thread::spawn(move|| { - tx1.send(()).unwrap(); + let (tx3, rx3) = channel::<()>(); + let tx4 = tx3.clone(); + spawn(move|| { + tx1.send(()); for _ in range(0i, 40) { - assert_eq!(rx2.recv().unwrap(), 1); + assert_eq!(rx2.recv(), 1); } + tx3.send(()); }); - rx1.recv().unwrap(); - let t2 = Thread::spawn(move|| { + rx1.recv(); + spawn(move|| { for _ in range(0i, 40) { - tx2.send(1).unwrap(); + tx2.send(1); } + tx4.send(()); }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + rx3.recv(); + rx3.recv(); } #[test] fn recv_from_outside_runtime() { let (tx, rx) = channel::(); - let t = Thread::spawn(move|| { + let (dtx, drx) = channel(); + spawn(move|| { for _ in range(0i, 40) { - assert_eq!(rx.recv().unwrap(), 1); + assert_eq!(rx.recv(), 1); } + dtx.send(()); }); for _ in range(0u, 40) { - tx.send(1).unwrap(); + tx.send(1); } - t.join().ok().unwrap(); + drx.recv(); } #[test] fn no_runtime() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); - let t1 = Thread::spawn(move|| { - assert_eq!(rx1.recv().unwrap(), 1); - tx2.send(2).unwrap(); + let (tx3, rx3) = channel::<()>(); + let tx4 = tx3.clone(); + spawn(move|| { + assert_eq!(rx1.recv(), 1); + tx2.send(2); + tx4.send(()); }); - let t2 = Thread::spawn(move|| { - tx1.send(1).unwrap(); - assert_eq!(rx2.recv().unwrap(), 2); + spawn(move|| { + tx1.send(1); + assert_eq!(rx2.recv(), 2); + tx3.send(()); }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + rx3.recv(); + rx3.recv(); } - #[test] - fn oneshot_single_thread_close_port_first() { + test! { fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = channel::(); drop(rx); - } + } } - #[test] - fn oneshot_single_thread_close_chan_first() { + test! { fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = channel::(); drop(tx); - } + } } - #[test] - fn oneshot_single_thread_send_port_close() { + test! { fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = channel::>(); drop(rx); - assert!(tx.send(box 0).is_err()); - } + tx.send(box 0); + } #[should_fail] } - #[test] - fn oneshot_single_thread_recv_chan_close() { + test! { fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic let res = Thread::spawn(move|| { let (tx, rx) = channel::(); drop(tx); - rx.recv().unwrap(); + rx.recv(); }).join(); // What is our res? assert!(res.is_err()); - } + } } - #[test] - fn oneshot_single_thread_send_then_recv() { + test! { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = channel::>(); - tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); - } + tx.send(box 10); + assert!(rx.recv() == box 10); + } } - #[test] - fn oneshot_single_thread_try_send_open() { + test! { fn oneshot_single_thread_try_send_open() { let (tx, rx) = channel::(); - assert!(tx.send(10).is_ok()); - assert!(rx.recv().unwrap() == 10); - } + assert!(tx.send_opt(10).is_ok()); + assert!(rx.recv() == 10); + } } - #[test] - fn oneshot_single_thread_try_send_closed() { + test! { fn oneshot_single_thread_try_send_closed() { let (tx, rx) = channel::(); drop(rx); - assert!(tx.send(10).is_err()); - } + assert!(tx.send_opt(10).is_err()); + } } - #[test] - fn oneshot_single_thread_try_recv_open() { + test! { fn oneshot_single_thread_try_recv_open() { let (tx, rx) = channel::(); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } + tx.send(10); + assert!(rx.recv_opt() == Ok(10)); + } } - #[test] - fn oneshot_single_thread_try_recv_closed() { + test! { fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = channel::(); drop(tx); - assert!(rx.recv().is_err()); - } + assert!(rx.recv_opt() == Err(())); + } } - #[test] - fn oneshot_single_thread_peek_data() { + test! { fn oneshot_single_thread_peek_data() { let (tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Err(Empty)); + tx.send(10); assert_eq!(rx.try_recv(), Ok(10)); - } + } } - #[test] - fn oneshot_single_thread_peek_close() { + test! { fn oneshot_single_thread_peek_close() { let (tx, rx) = channel::(); drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } + assert_eq!(rx.try_recv(), Err(Disconnected)); + assert_eq!(rx.try_recv(), Err(Disconnected)); + } } - #[test] - fn oneshot_single_thread_peek_open() { + test! { fn oneshot_single_thread_peek_open() { let (_tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } + assert_eq!(rx.try_recv(), Err(Empty)); + } } - #[test] - fn oneshot_multi_task_recv_then_send() { + test! { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::>(); - let _t = Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + spawn(move|| { + assert!(rx.recv() == box 10); }); - tx.send(box 10).unwrap(); - } + tx.send(box 10); + } } - #[test] - fn oneshot_multi_task_recv_then_close() { + test! { fn oneshot_multi_task_recv_then_close() { let (tx, rx) = channel::>(); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(tx); }); let res = Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(rx.recv() == box 10); }).join(); assert!(res.is_err()); - } + } } - #[test] - fn oneshot_multi_thread_close_stress() { + test! { fn oneshot_multi_thread_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(rx); }); drop(tx); } - } + } } - #[test] - fn oneshot_multi_thread_send_close_stress() { + test! { fn oneshot_multi_thread_send_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(rx); }); let _ = Thread::spawn(move|| { - tx.send(1).unwrap(); + tx.send(1); }).join(); } - } + } } - #[test] - fn oneshot_multi_thread_recv_close_stress() { + test! { fn oneshot_multi_thread_recv_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::(); - Thread::spawn(move|| { + spawn(move|| { let res = Thread::spawn(move|| { - rx.recv().unwrap(); + rx.recv(); }).join(); assert!(res.is_err()); - }).detach(); - let _t = Thread::spawn(move|| { - Thread::spawn(move|| { + }); + spawn(move|| { + spawn(move|| { drop(tx); - }).detach(); + }); }); } - } + } } - #[test] - fn oneshot_multi_thread_send_recv_stress() { + test! { fn oneshot_multi_thread_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { - tx.send(box 10i).unwrap(); + spawn(move|| { + tx.send(box 10i); + }); + spawn(move|| { + assert!(rx.recv() == box 10i); }); - assert!(rx.recv().unwrap() == box 10i); } - } + } } - #[test] - fn stream_send_recv_stress() { + test! { fn stream_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel(); @@ -1400,73 +1412,69 @@ fn stream_send_recv_stress() { fn send(tx: Sender>, i: int) { if i == 10 { return } - Thread::spawn(move|| { - tx.send(box i).unwrap(); + spawn(move|| { + tx.send(box i); send(tx, i + 1); - }).detach(); + }); } fn recv(rx: Receiver>, i: int) { if i == 10 { return } - Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + spawn(move|| { + assert!(rx.recv() == box i); recv(rx, i + 1); - }).detach(); + }); } } - } + } } - #[test] - fn recv_a_lot() { + test! { fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); - for _ in range(0i, 10000) { tx.send(()).unwrap(); } - for _ in range(0i, 10000) { rx.recv().unwrap(); } - } + for _ in range(0i, 10000) { tx.send(()); } + for _ in range(0i, 10000) { rx.recv(); } + } } - #[test] - fn shared_chan_stress() { + test! { fn shared_chan_stress() { let (tx, rx) = channel(); let total = stress_factor() + 100; for _ in range(0, total) { let tx = tx.clone(); - Thread::spawn(move|| { - tx.send(()).unwrap(); - }).detach(); + spawn(move|| { + tx.send(()); + }); } for _ in range(0, total) { - rx.recv().unwrap(); + rx.recv(); } - } + } } - #[test] - fn test_nested_recv_iter() { + test! { fn test_nested_recv_iter() { let (tx, rx) = channel::(); let (total_tx, total_rx) = channel::(); - let _t = Thread::spawn(move|| { + spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; } - total_tx.send(acc).unwrap(); + total_tx.send(acc); }); - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); + tx.send(3); + tx.send(1); + tx.send(2); drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } + assert_eq!(total_rx.recv(), 6); + } } - #[test] - fn test_recv_iter_break() { + test! { fn test_recv_iter_break() { let (tx, rx) = channel::(); let (count_tx, count_rx) = channel(); - let _t = Thread::spawn(move|| { + spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1475,51 +1483,49 @@ fn test_recv_iter_break() { count += x; } } - count_tx.send(count).unwrap(); + count_tx.send(count); }); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.send(2); + tx.send(2); + tx.send(2); + tx.send(2); + let _ = tx.send_opt(2); drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } + assert_eq!(count_rx.recv(), 4); + } } - #[test] - fn try_recv_states() { + test! { fn try_recv_states() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); + spawn(move|| { + rx2.recv(); + tx1.send(1); + tx3.send(()); + rx2.recv(); drop(tx1); - tx3.send(()).unwrap(); + tx3.send(()); }); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(Empty)); + tx2.send(()); + rx3.recv(); assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } + assert_eq!(rx1.try_recv(), Err(Empty)); + tx2.send(()); + rx3.recv(); + assert_eq!(rx1.try_recv(), Err(Disconnected)); + } } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { + test! { fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); // wait on a oneshot + spawn(move|| { + rx.recv(); // wait on a oneshot drop(rx); // destroy a shared - tx2.send(()).unwrap(); + tx2.send(()); }); // make sure the other task has gone to sleep for _ in range(0u, 5000) { Thread::yield_now(); } @@ -1527,334 +1533,303 @@ fn destroy_upgraded_shared_port_when_sender_still_active() { // upgrade to a shared chan and send a message let t = tx.clone(); drop(tx); - t.send(()).unwrap(); + t.send(()); // wait for the child task to exit before we exit - rx2.recv().unwrap(); - } + rx2.recv(); + }} } #[cfg(test)] mod sync_tests { - use prelude::v1::*; - + use prelude::*; use os; - use thread::Thread; - use super::*; pub fn stress_factor() -> uint { match os::getenv("RUST_TEST_STRESS") { - Some(val) => val.parse().unwrap(), + Some(val) => from_str::(val.as_slice()).unwrap(), None => 1, } } - #[test] - fn smoke() { + test! { fn smoke() { let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } + tx.send(1); + assert_eq!(rx.recv(), 1); + } } - #[test] - fn drop_full() { + test! { fn drop_full() { let (tx, _rx) = sync_channel(1); - tx.send(box 1i).unwrap(); - } + tx.send(box 1i); + } } - #[test] - fn smoke_shared() { + test! { fn smoke_shared() { let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); + tx.send(1); + assert_eq!(rx.recv(), 1); let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } + tx.send(1); + assert_eq!(rx.recv(), 1); + } } - #[test] - fn smoke_threads() { + test! { fn smoke_threads() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { - tx.send(1).unwrap(); + spawn(move|| { + tx.send(1); }); - assert_eq!(rx.recv().unwrap(), 1); - } + assert_eq!(rx.recv(), 1); + } } - #[test] - fn smoke_port_gone() { + test! { fn smoke_port_gone() { let (tx, rx) = sync_channel::(0); drop(rx); - assert!(tx.send(1).is_err()); - } + tx.send(1); + } #[should_fail] } - #[test] - fn smoke_shared_port_gone2() { + test! { fn smoke_shared_port_gone2() { let (tx, rx) = sync_channel::(0); drop(rx); let tx2 = tx.clone(); drop(tx); - assert!(tx2.send(1).is_err()); - } + tx2.send(1); + } #[should_fail] } - #[test] - fn port_gone_concurrent() { + test! { fn port_gone_concurrent() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); + spawn(move|| { + rx.recv(); }); - while tx.send(1).is_ok() {} - } + loop { tx.send(1) } + } #[should_fail] } - #[test] - fn port_gone_concurrent_shared() { + test! { fn port_gone_concurrent_shared() { let (tx, rx) = sync_channel::(0); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); + spawn(move|| { + rx.recv(); }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } + loop { + tx.send(1); + tx2.send(1); + } + } #[should_fail] } - #[test] - fn smoke_chan_gone() { + test! { fn smoke_chan_gone() { let (tx, rx) = sync_channel::(0); drop(tx); - assert!(rx.recv().is_err()); - } + rx.recv(); + } #[should_fail] } - #[test] - fn smoke_chan_gone_shared() { + test! { fn smoke_chan_gone_shared() { let (tx, rx) = sync_channel::<()>(0); let tx2 = tx.clone(); drop(tx); drop(tx2); - assert!(rx.recv().is_err()); - } + rx.recv(); + } #[should_fail] } - #[test] - fn chan_gone_concurrent() { + test! { fn chan_gone_concurrent() { let (tx, rx) = sync_channel::(0); - Thread::spawn(move|| { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }).detach(); - while rx.recv().is_ok() {} - } + spawn(move|| { + tx.send(1); + tx.send(1); + }); + loop { rx.recv(); } + } #[should_fail] } - #[test] - fn stress() { + test! { fn stress() { let (tx, rx) = sync_channel::(0); - Thread::spawn(move|| { - for _ in range(0u, 10000) { tx.send(1).unwrap(); } - }).detach(); + spawn(move|| { + for _ in range(0u, 10000) { tx.send(1); } + }); for _ in range(0u, 10000) { - assert_eq!(rx.recv().unwrap(), 1); + assert_eq!(rx.recv(), 1); } - } + } } - #[test] - fn stress_shared() { + test! { fn stress_shared() { static AMT: uint = 1000; static NTHREADS: uint = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); - Thread::spawn(move|| { + spawn(move|| { for _ in range(0, AMT * NTHREADS) { - assert_eq!(rx.recv().unwrap(), 1); + assert_eq!(rx.recv(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } - dtx.send(()).unwrap(); - }).detach(); + dtx.send(()); + }); for _ in range(0, NTHREADS) { let tx = tx.clone(); - Thread::spawn(move|| { - for _ in range(0, AMT) { tx.send(1).unwrap(); } - }).detach(); + spawn(move|| { + for _ in range(0, AMT) { tx.send(1); } + }); } drop(tx); - drx.recv().unwrap(); - } + drx.recv(); + } } - #[test] - fn oneshot_single_thread_close_port_first() { + test! { fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = sync_channel::(0); drop(rx); - } + } } - #[test] - fn oneshot_single_thread_close_chan_first() { + test! { fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = sync_channel::(0); drop(tx); - } + } } - #[test] - fn oneshot_single_thread_send_port_close() { + test! { fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = sync_channel::>(0); drop(rx); - assert!(tx.send(box 0).is_err()); - } + tx.send(box 0); + } #[should_fail] } - #[test] - fn oneshot_single_thread_recv_chan_close() { + test! { fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic let res = Thread::spawn(move|| { let (tx, rx) = sync_channel::(0); drop(tx); - rx.recv().unwrap(); + rx.recv(); }).join(); // What is our res? assert!(res.is_err()); - } + } } - #[test] - fn oneshot_single_thread_send_then_recv() { + test! { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = sync_channel::>(1); - tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); - } + tx.send(box 10); + assert!(rx.recv() == box 10); + } } - #[test] - fn oneshot_single_thread_try_send_open() { + test! { fn oneshot_single_thread_try_send_open() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.try_send(10), Ok(())); - assert!(rx.recv().unwrap() == 10); - } + assert!(rx.recv() == 10); + } } - #[test] - fn oneshot_single_thread_try_send_closed() { + test! { fn oneshot_single_thread_try_send_closed() { let (tx, rx) = sync_channel::(0); drop(rx); - assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); - } + assert_eq!(tx.try_send(10), Err(RecvDisconnected(10))); + } } - #[test] - fn oneshot_single_thread_try_send_closed2() { + test! { fn oneshot_single_thread_try_send_closed2() { let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); - } + assert_eq!(tx.try_send(10), Err(Full(10))); + } } - #[test] - fn oneshot_single_thread_try_recv_open() { + test! { fn oneshot_single_thread_try_recv_open() { let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } + tx.send(10); + assert!(rx.recv_opt() == Ok(10)); + } } - #[test] - fn oneshot_single_thread_try_recv_closed() { + test! { fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = sync_channel::(0); drop(tx); - assert!(rx.recv().is_err()); - } + assert!(rx.recv_opt() == Err(())); + } } - #[test] - fn oneshot_single_thread_peek_data() { + test! { fn oneshot_single_thread_peek_data() { let (tx, rx) = sync_channel::(1); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Err(Empty)); + tx.send(10); assert_eq!(rx.try_recv(), Ok(10)); - } + } } - #[test] - fn oneshot_single_thread_peek_close() { + test! { fn oneshot_single_thread_peek_close() { let (tx, rx) = sync_channel::(0); drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } + assert_eq!(rx.try_recv(), Err(Disconnected)); + assert_eq!(rx.try_recv(), Err(Disconnected)); + } } - #[test] - fn oneshot_single_thread_peek_open() { + test! { fn oneshot_single_thread_peek_open() { let (_tx, rx) = sync_channel::(0); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } + assert_eq!(rx.try_recv(), Err(Empty)); + } } - #[test] - fn oneshot_multi_task_recv_then_send() { + test! { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + spawn(move|| { + assert!(rx.recv() == box 10); }); - tx.send(box 10).unwrap(); - } + tx.send(box 10); + } } - #[test] - fn oneshot_multi_task_recv_then_close() { + test! { fn oneshot_multi_task_recv_then_close() { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(tx); }); let res = Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(rx.recv() == box 10); }).join(); assert!(res.is_err()); - } + } } - #[test] - fn oneshot_multi_thread_close_stress() { + test! { fn oneshot_multi_thread_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(rx); }); drop(tx); } - } + } } - #[test] - fn oneshot_multi_thread_send_close_stress() { + test! { fn oneshot_multi_thread_send_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + spawn(move|| { drop(rx); }); let _ = Thread::spawn(move || { - tx.send(1).unwrap(); + tx.send(1); }).join(); } - } + } } - #[test] - fn oneshot_multi_thread_recv_close_stress() { + test! { fn oneshot_multi_thread_recv_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + spawn(move|| { let res = Thread::spawn(move|| { - rx.recv().unwrap(); + rx.recv(); }).join(); assert!(res.is_err()); }); - let _t = Thread::spawn(move|| { - Thread::spawn(move|| { + spawn(move|| { + spawn(move|| { drop(tx); - }).detach(); + }); }); } - } + } } - #[test] - fn oneshot_multi_thread_send_recv_stress() { + test! { fn oneshot_multi_thread_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { - tx.send(box 10i).unwrap(); + spawn(move|| { + tx.send(box 10i); + }); + spawn(move|| { + assert!(rx.recv() == box 10i); }); - assert!(rx.recv().unwrap() == box 10i); } - } + } } - #[test] - fn stream_send_recv_stress() { + test! { fn stream_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::>(0); @@ -1864,73 +1839,69 @@ fn stream_send_recv_stress() { fn send(tx: SyncSender>, i: int) { if i == 10 { return } - Thread::spawn(move|| { - tx.send(box i).unwrap(); + spawn(move|| { + tx.send(box i); send(tx, i + 1); - }).detach(); + }); } fn recv(rx: Receiver>, i: int) { if i == 10 { return } - Thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + spawn(move|| { + assert!(rx.recv() == box i); recv(rx, i + 1); - }).detach(); + }); } } - } + } } - #[test] - fn recv_a_lot() { + test! { fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = sync_channel(10000); - for _ in range(0u, 10000) { tx.send(()).unwrap(); } - for _ in range(0u, 10000) { rx.recv().unwrap(); } - } + for _ in range(0u, 10000) { tx.send(()); } + for _ in range(0u, 10000) { rx.recv(); } + } } - #[test] - fn shared_chan_stress() { + test! { fn shared_chan_stress() { let (tx, rx) = sync_channel(0); let total = stress_factor() + 100; for _ in range(0, total) { let tx = tx.clone(); - Thread::spawn(move|| { - tx.send(()).unwrap(); - }).detach(); + spawn(move|| { + tx.send(()); + }); } for _ in range(0, total) { - rx.recv().unwrap(); + rx.recv(); } - } + } } - #[test] - fn test_nested_recv_iter() { + test! { fn test_nested_recv_iter() { let (tx, rx) = sync_channel::(0); let (total_tx, total_rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; } - total_tx.send(acc).unwrap(); + total_tx.send(acc); }); - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); + tx.send(3); + tx.send(1); + tx.send(2); drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } + assert_eq!(total_rx.recv(), 6); + } } - #[test] - fn test_recv_iter_break() { + test! { fn test_recv_iter_break() { let (tx, rx) = sync_channel::(0); let (count_tx, count_rx) = sync_channel(0); - let _t = Thread::spawn(move|| { + spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1939,51 +1910,49 @@ fn test_recv_iter_break() { count += x; } } - count_tx.send(count).unwrap(); + count_tx.send(count); }); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); + tx.send(2); + tx.send(2); + tx.send(2); let _ = tx.try_send(2); drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } + assert_eq!(count_rx.recv(), 4); + } } - #[test] - fn try_recv_states() { + test! { fn try_recv_states() { let (tx1, rx1) = sync_channel::(1); let (tx2, rx2) = sync_channel::<()>(1); let (tx3, rx3) = sync_channel::<()>(1); - let _t = Thread::spawn(move|| { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); + spawn(move|| { + rx2.recv(); + tx1.send(1); + tx3.send(()); + rx2.recv(); drop(tx1); - tx3.send(()).unwrap(); + tx3.send(()); }); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(Empty)); + tx2.send(()); + rx3.recv(); assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } + assert_eq!(rx1.try_recv(), Err(Empty)); + tx2.send(()); + rx3.recv(); + assert_eq!(rx1.try_recv(), Err(Disconnected)); + } } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { + test! { fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = sync_channel::<()>(0); let (tx2, rx2) = sync_channel::<()>(0); - let _t = Thread::spawn(move|| { - rx.recv().unwrap(); // wait on a oneshot + spawn(move|| { + rx.recv(); // wait on a oneshot drop(rx); // destroy a shared - tx2.send(()).unwrap(); + tx2.send(()); }); // make sure the other task has gone to sleep for _ in range(0u, 5000) { Thread::yield_now(); } @@ -1991,91 +1960,92 @@ fn destroy_upgraded_shared_port_when_sender_still_active() { // upgrade to a shared chan and send a message let t = tx.clone(); drop(tx); - t.send(()).unwrap(); + t.send(()); // wait for the child task to exit before we exit - rx2.recv().unwrap(); - } + rx2.recv(); + } } - #[test] - fn send1() { + test! { fn send_opt1() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { rx.recv().unwrap(); }); - assert_eq!(tx.send(1), Ok(())); - } + spawn(move|| { rx.recv(); }); + assert_eq!(tx.send_opt(1), Ok(())); + } } - #[test] - fn send2() { + test! { fn send_opt2() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { drop(rx); }); - assert!(tx.send(1).is_err()); - } + spawn(move|| { drop(rx); }); + assert_eq!(tx.send_opt(1), Err(1)); + } } - #[test] - fn send3() { + test! { fn send_opt3() { let (tx, rx) = sync_channel::(1); - assert_eq!(tx.send(1), Ok(())); - let _t =Thread::spawn(move|| { drop(rx); }); - assert!(tx.send(1).is_err()); - } + assert_eq!(tx.send_opt(1), Ok(())); + spawn(move|| { drop(rx); }); + assert_eq!(tx.send_opt(1), Err(1)); + } } - #[test] - fn send4() { + test! { fn send_opt4() { let (tx, rx) = sync_channel::(0); let tx2 = tx.clone(); let (done, donerx) = channel(); let done2 = done.clone(); - let _t = Thread::spawn(move|| { - assert!(tx.send(1).is_err()); - done.send(()).unwrap(); + spawn(move|| { + assert_eq!(tx.send_opt(1), Err(1)); + done.send(()); }); - let _t = Thread::spawn(move|| { - assert!(tx2.send(2).is_err()); - done2.send(()).unwrap(); + spawn(move|| { + assert_eq!(tx2.send_opt(2), Err(2)); + done2.send(()); }); drop(rx); - donerx.recv().unwrap(); - donerx.recv().unwrap(); - } + donerx.recv(); + donerx.recv(); + } } - #[test] - fn try_send1() { + test! { fn try_send1() { let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } + assert_eq!(tx.try_send(1), Err(Full(1))); + } } - #[test] - fn try_send2() { + test! { fn try_send2() { let (tx, _rx) = sync_channel::(1); assert_eq!(tx.try_send(1), Ok(())); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } + assert_eq!(tx.try_send(1), Err(Full(1))); + } } - #[test] - fn try_send3() { + test! { fn try_send3() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.try_send(1), Ok(())); drop(rx); - assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); - } + assert_eq!(tx.try_send(1), Err(RecvDisconnected(1))); + } } - #[test] - fn issue_15761() { + test! { fn try_send4() { + let (tx, rx) = sync_channel::(0); + spawn(move|| { + for _ in range(0u, 1000) { Thread::yield_now(); } + assert_eq!(tx.try_send(1), Ok(())); + }); + assert_eq!(rx.recv(), 1); + } #[ignore(reason = "flaky on libnative")] } + + test! { fn issue_15761() { fn repro() { let (tx1, rx1) = sync_channel::<()>(3); let (tx2, rx2) = sync_channel::<()>(3); - let _t = Thread::spawn(move|| { - rx1.recv().unwrap(); + spawn(move|| { + rx1.recv(); tx2.try_send(()).unwrap(); }); tx1.try_send(()).unwrap(); - rx2.recv().unwrap(); + rx2.recv(); } for _ in range(0u, 100) { repro() } - } + } } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index b2367ff8352..bd98b09d779 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -41,7 +41,7 @@ /// ``` /// use std::sync::RWLock; /// -/// let lock = RWLock::new(5i); +/// let lock = RWLock::new(5); /// /// // many reader locks can be held at once /// { diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a441e55a732..a31dcc9884f 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -14,7 +14,7 @@ use io::{self, IoError, IoResult}; use prelude::v1::*; use sys::{last_error, retry}; -use c_str::CString; +use ffi::CString; use num::Int; use path::BytesContainer; use collections; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 3f67b284f68..4cf891ac498 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,15 +12,16 @@ use self::SocketStatus::*; use self::InAddr::*; -use c_str::ToCStr; +use ffi::CString; +use ffi; use io::net::addrinfo; use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult, IoError}; use libc::{self, c_char, c_int}; -use c_str::CString; use mem; use num::Int; use ptr::{self, null, null_mut}; +use str; use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; @@ -234,9 +235,9 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| x.to_c_str()); + let c_host = host.map(|x| CString::from_slice(x.as_bytes())); let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| x.to_c_str()); + let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -324,7 +325,8 @@ pub fn get_address_name(addr: IpAddr) -> Result { } unsafe { - Ok(CString::new(hostbuf.as_ptr(), false).as_str().unwrap().to_string()) + Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) + .unwrap().to_string()) } } diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5b261ea6b9e..ca268a8f27f 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,13 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. -use c_str::CString; -use io::{IoResult, Writer}; +use prelude::v1::*; + +use ffi; +use io::IoResult; use libc; use mem; -use option::Option::{self, Some, None}; -use result::Result::{Ok, Err}; +use str; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -105,9 +106,7 @@ #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Writer) -> IoResult<()> { - use iter::{IteratorExt, range}; use result; - use slice::SliceExt; extern { fn backtrace(buf: *mut *mut libc::c_void, @@ -234,19 +233,15 @@ fn dladdr(addr: *const libc::c_void, output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - CString::new(info.dli_sname, false) + ffi::c_str_to_bytes(&info.dli_sname) })) } } #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API @@ -368,15 +363,15 @@ unsafe fn init_state() -> *mut backtrace_state { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { CString::new(data, false) })) + output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) } } // Finally, after all that work above, we can emit a symbol. fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void, - s: Option) -> IoResult<()> { + s: Option<&[u8]>) -> IoResult<()> { try!(write!(w, " {:2}: {:2$} - ", idx, addr, HEX_WIDTH)); - match s.as_ref().and_then(|c| c.as_str()) { + match s.and_then(|s| str::from_utf8(s).ok()) { Some(string) => try!(demangle(w, string)), None => try!(write!(w, "")), } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index b49ace8e2f8..1ad775517bb 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use c_str::{CString, ToCStr}; +use ffi::{self, CString}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, FileStat, SeekStyle}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -150,6 +150,10 @@ fn drop(&mut self) { } } +fn cstr(path: &Path) -> CString { + CString::from_slice(path.as_vec()) +} + pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { let flags = match fm { Open => 0, @@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { libc::S_IRUSR | libc::S_IWUSR), }; - let path = path.to_c_str(); + let path = cstr(path); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -173,7 +177,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -182,7 +186,6 @@ pub fn readdir(p: &Path) -> IoResult> { use libc::{opendir, readdir_r, closedir}; fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; let root = Path::new(root); dirs.into_iter().filter(|path| { @@ -199,7 +202,7 @@ fn prune(root: &CString, dirs: Vec) -> Vec { let mut buf = Vec::::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = p.to_c_str(); + let p = CString::from_slice(p.as_vec()); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -207,10 +210,9 @@ fn prune(root: &CString, dirs: Vec) -> Vec { let mut entry_ptr = 0 as *mut dirent_t; while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } - let cstr = unsafe { - CString::new(rust_list_dir_val(entry_ptr), false) - }; - paths.push(Path::new(cstr)); + paths.push(unsafe { + Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); Ok(prune(&p, paths)) @@ -220,39 +222,39 @@ fn prune(root: &CString, dirs: Vec) -> Vec { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = old.to_c_str(); - let new = new.to_c_str(); + let old = cstr(old); + let new = cstr(new); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })) } pub fn readlink(p: &Path) -> IoResult { - let c_path = p.to_c_str(); + let c_path = cstr(p); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -273,14 +275,14 @@ pub fn readlink(p: &Path) -> IoResult { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -328,7 +330,7 @@ fn gen(_stat: &libc::stat) -> u64 { 0 } } pub fn stat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -337,7 +339,7 @@ pub fn stat(p: &Path) -> IoResult { } pub fn lstat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -346,7 +348,7 @@ pub fn lstat(p: &Path) -> IoResult { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index ea0d230e8b2..6a408aa60f0 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -15,12 +15,14 @@ #![allow(unused_unsafe)] #![allow(unused_mut)] -extern crate libc; - -use num; -use num::{Int, SignedInt}; use prelude::v1::*; + +use ffi; use io::{self, IoResult, IoError}; +use libc; +use num::{Int, SignedInt}; +use num; +use str; use sys_common::mkerr_libc; macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( @@ -78,11 +80,10 @@ pub fn last_net_error() -> IoError { } pub fn last_gai_error(s: libc::c_int) -> IoError { - use c_str::CString; let mut err = decode_error(s); err.detail = Some(unsafe { - CString::new(gai_strerror(s), false).as_str().unwrap().to_string() + str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 181b8fdd0f8..175c4e2e353 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -12,18 +12,18 @@ use prelude::v1::*; -use c_str::ToCStr; use error::{FromError, Error}; +use ffi::{self, CString}; use fmt; use io::{IoError, IoResult}; use libc::{self, c_int, c_char, c_void}; +use os::TMPBUF_SZ; use os; use path::{BytesContainer}; use ptr; +use str; use sys::fs::FileDesc; -use os::TMPBUF_SZ; - const BUF_BYTES : uint = 2048u; /// Returns the platform-specific value of errno @@ -108,7 +108,8 @@ fn __xpg_strerror_r(errnum: c_int, panic!("strerror_r failure"); } - String::from_raw_buf(p as *const u8) + let p = p as *const _; + str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() } } @@ -122,21 +123,17 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { } pub fn getcwd() -> IoResult { - use c_str::CString; - let mut buf = [0 as c_char; BUF_BYTES]; unsafe { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(CString::new(buf.as_ptr(), false))) + Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) } } } pub unsafe fn get_env_pairs() -> Vec> { - use c_str::CString; - extern { fn rust_env_pairs() -> *const *const c_char; } @@ -147,8 +144,7 @@ pub unsafe fn get_env_pairs() -> Vec> { } let mut result = Vec::new(); while *environ != 0 as *const _ { - let env_pair = - CString::new(*environ, false).as_bytes_no_nul().to_vec(); + let env_pair = ffi::c_str_to_bytes(&*environ).to_vec(); result.push(env_pair); environ = environ.offset(1); } @@ -234,14 +230,13 @@ pub fn load_self() -> Option> { } pub fn chdir(p: &Path) -> IoResult<()> { - p.with_c_str(|buf| { - unsafe { - match libc::chdir(buf) == (0 as c_int) { - true => Ok(()), - false => Err(IoError::last_error()), - } + let p = CString::from_slice(p.as_vec()); + unsafe { + match libc::chdir(p.as_ptr()) == (0 as c_int) { + true => Ok(()), + false => Err(IoError::last_error()), } - }) + } } pub fn page_size() -> uint { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 9063fbc2ba9..158a1ce2204 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -10,8 +10,8 @@ use prelude::v1::*; +use ffi::CString; use libc; -use c_str::CString; use mem; use sync::{Arc, Mutex}; use sync::atomic::{AtomicBool, Ordering}; @@ -48,7 +48,7 @@ fn addr_to_sockaddr_un(addr: &CString, } s.sun_family = libc::AF_UNIX as libc::sa_family_t; for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) { - *slot = value; + *slot = *value; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index b73919fe2a2..5bc6b0c703b 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,8 +11,8 @@ use prelude::v1::*; use self::Req::*; -use c_str::{CString, ToCStr}; use collections; +use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{self, IoResult, IoError, EndOfFile}; @@ -101,7 +101,7 @@ unsafe fn set_cloexec(fd: c_int) { // We may use this in the child, so perform allocations before the // fork - let devnull = "/dev/null".to_c_str(); + let devnull = b"/dev/null\0"; set_cloexec(output.fd()); @@ -204,7 +204,7 @@ fn fail(output: &mut FileDesc) -> ! { } else { libc::O_RDWR }; - libc::open(devnull.as_ptr(), flags, 0) + libc::open(devnull.as_ptr() as *const _, flags, 0) } Some(obj) => { let fd = obj.as_inner().fd(); diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 11f29232a92..62f3242a206 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -54,7 +54,7 @@ use mem; use os; use ptr; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; use sys::c; use sys::fs::FileDesc; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 319a458087b..4ccecfd1f5f 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -21,7 +21,8 @@ /// copy of that function in my mingw install (maybe it was broken?). Instead, /// this takes the route of using StackWalk64 in order to walk the stack. -use c_str::CString; +use dynamic_lib::DynamicLibrary; +use ffi; use intrinsics; use io::{IoResult, Writer}; use libc; @@ -30,10 +31,9 @@ use option::Option::{Some, None}; use path::Path; use result::Result::{Ok, Err}; -use sync::{StaticMutex, MUTEX_INIT}; use slice::SliceExt; -use str::StrExt; -use dynamic_lib::DynamicLibrary; +use str::{self, StrExt}; +use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -357,11 +357,11 @@ macro_rules! sym{ ($e:expr, $t:ident) => (unsafe { if ret == libc::TRUE { try!(write!(w, " - ")); - let cstr = unsafe { CString::new(info.Name.as_ptr(), false) }; - let bytes = cstr.as_bytes(); - match cstr.as_str() { - Some(s) => try!(demangle(w, s)), - None => try!(w.write(bytes[..bytes.len()-1])), + let ptr = info.Name.as_ptr() as *const libc::c_char; + let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + match str::from_utf8(bytes) { + Ok(s) => try!(demangle(w, s)), + Err(..) => try!(w.write(bytes[..bytes.len()-1])), } } try!(w.write(&['\n' as u8])); diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 1ee57434fb9..945c2e8e7d1 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -133,7 +133,7 @@ pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::v1::*; - use c_str::ToCStr; + use ffi::CString; extern "system" { fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -147,14 +147,13 @@ pub mod compat { unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { let mut module: Vec = module.utf16_units().collect(); module.push(0); - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module.as_ptr()); - let func: uint = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, if func == 0 { - fallback - } else { - func - }) + let symbol = CString::from_slice(symbol.as_bytes()); + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr())); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func }) } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 9a942300656..f8c75335b35 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -13,7 +13,6 @@ use alloc::arc::Arc; use libc::{self, c_int}; -use c_str::CString; use mem; use sys::os::fill_utf16_buf_and_decode; use path; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 9057515cad2..9996909f2f5 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -87,16 +87,21 @@ use prelude::v1::*; use libc; -use c_str::CString; +use ffi::CString; +use io::{self, IoError, IoResult}; use mem; use ptr; -use sync::{Arc, Mutex}; +use str; use sync::atomic::{AtomicBool, Ordering}; -use io::{self, IoError, IoResult}; +use sync::{Arc, Mutex}; use sys_common::{self, eof}; -use super::{c, os, timer, to_utf16, decode_error_detailed}; +use super::{c, os, timer, decode_error_detailed}; + +fn to_utf16(c: &CString) -> IoResult> { + super::to_utf16(str::from_utf8(c.as_bytes()).ok()) +} struct Event(libc::HANDLE); @@ -270,7 +275,7 @@ fn try_connect(p: *const u16) -> Option { } pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr.as_str())); + let addr = try!(to_utf16(addr)); let start = timer::now(); loop { match UnixStream::try_connect(addr.as_ptr()) { @@ -571,7 +576,7 @@ pub fn bind(addr: &CString) -> IoResult { // Although we technically don't need the pipe until much later, we // create the initial handle up front to test the validity of the name // and such. - let addr_v = try!(to_utf16(addr.as_str())); + let addr_v = try!(to_utf16(addr)); let ret = unsafe { pipe(addr_v.as_ptr(), true) }; if ret == libc::INVALID_HANDLE_VALUE { Err(super::last_error()) @@ -661,7 +666,7 @@ pub fn accept(&mut self) -> IoResult { // proceed in accepting new clients in the future if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) } - let name = try!(to_utf16(self.listener.name.as_str())); + let name = try!(to_utf16(&self.listener.name)); // Once we've got a "server handle", we need to wait for a client to // connect. The ConnectNamedPipe function will block this thread until @@ -753,7 +758,7 @@ pub fn handle(&self) -> libc::HANDLE { impl Clone for UnixAcceptor { fn clone(&self) -> UnixAcceptor { - let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); + let name = to_utf16(&self.listener.name).ok().unwrap(); UnixAcceptor { inner: self.inner.clone(), event: Event::new(true, false).ok().unwrap(), diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 81e8f974a12..9b3f2ca0373 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,27 +10,26 @@ use prelude::v1::*; +use collections; +use ffi::CString; +use hash::Hash; +use io::fs::PathExtensions; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::{IoResult, IoError}; +use io; use libc::{pid_t, c_void, c_int}; use libc; -use c_str::{CString, ToCStr}; -use io; use mem; use os; -use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; use path::BytesContainer; -use hash::Hash; -use io::{IoResult, IoError}; - +use ptr; +use str; +use sys::fs::FileDesc; use sys::fs; use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; use sys_common::{AsInner, mkerr_libc, timeout}; -use io::fs::PathExtensions; - pub use sys_common::ProcessConfig; /// A value representing a child process. @@ -142,10 +141,10 @@ pub fn spawn(cfg: &C, in_fd: Option

, // Split the value and test each path to see if the // program exists. for path in os::split_paths(v.container_as_bytes()).into_iter() { - let path = path.join(cfg.program().as_bytes_no_nul()) + let path = path.join(cfg.program().as_bytes()) .with_extension(os::consts::EXE_EXTENSION); if path.exists() { - return Some(path.to_c_str()) + return Some(CString::from_slice(path.as_vec())) } } break @@ -363,11 +362,11 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA fn make_command_line(prog: &CString, args: &[CString]) -> String { let mut cmd = String::new(); - append_arg(&mut cmd, prog.as_str() + append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() .expect("expected program name to be utf-8 encoded")); for arg in args.iter() { cmd.push(' '); - append_arg(&mut cmd, arg.as_str() + append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() .expect("expected argument to be utf-8 encoded")); } return cmd; @@ -449,7 +448,7 @@ fn with_dirp(d: Option<&CString>, cb: F) -> T where { match d { Some(dir) => { - let dir_str = dir.as_str() + let dir_str = str::from_utf8(dir.as_bytes()).ok() .expect("expected workingdirectory to be utf-8 encoded"); let mut dir_str: Vec = dir_str.utf16_units().collect(); dir_str.push(0); diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 1d6f49b04a3..63112327415 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -435,7 +435,7 @@ fn drop(&mut self) { mod test { use prelude::v1::*; - use any::{Any, AnyRefExt}; + use any::Any; use sync::mpsc::{channel, Sender}; use boxed::BoxAny; use result; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 01f66f3bbd0..e779821342a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -182,18 +182,34 @@ pub fn ident(&self) -> Ident { /// A mark represents a unique id associated with a macro expansion pub type Mrk = u32; +#[cfg(stage0)] impl, E> Encodable for Ident { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(token::get_ident(*self).get()) } } +#[cfg(not(stage0))] +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(token::get_ident(*self).get()) + } +} + +#[cfg(stage0)] impl, E> Decodable for Ident { fn decode(d: &mut D) -> Result { Ok(str_to_ident(try!(d.read_str())[])) } } +#[cfg(not(stage0))] +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(str_to_ident(try!(d.read_str())[])) + } +} + /// Function name (not all functions have names) pub type FnIdent = Option; @@ -989,7 +1005,7 @@ pub fn suffix_len(&self) -> uint { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)] pub enum Lit_ { LitStr(InternedString, StrStyle), - LitBinary(Rc >), + LitBinary(Rc>), LitByte(u8), LitChar(char), LitInt(u64, LitIntType), @@ -1204,8 +1220,6 @@ pub enum Ty_ { TyPtr(MutTy), /// A reference (`&'a T` or `&'a mut T`) TyRptr(Option, MutTy), - /// A closure (e.g. `|uint| -> bool`) - TyClosure(P), /// A bare function (e.g. `fn(uint) -> bool`) TyBareFn(P), /// A tuple (`(A, B, C, D,...)`) @@ -1299,6 +1313,24 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub enum ImplPolarity { + /// impl Trait for Type + Positive, + /// impl !Trait for Type + Negative, +} + +impl fmt::Show for ImplPolarity { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ImplPolarity::Positive => "positive".fmt(f), + ImplPolarity::Negative => "negative".fmt(f), + } + } +} + + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)] pub enum FunctionRetTy { /// Functions with return type ! that always @@ -1587,6 +1619,7 @@ pub enum Item_ { TyParamBounds, Vec), ItemImpl(Unsafety, + ImplPolarity, Generics, Option, // (optional) trait this impl implements P, // self @@ -1667,27 +1700,7 @@ mod test { // are ASTs encodable? #[test] fn check_asts_encodable() { - use std::io; - let e = Crate { - module: Mod { - inner: Span { - lo: BytePos(11), - hi: BytePos(19), - expn_id: NO_EXPANSION, - }, - view_items: Vec::new(), - items: Vec::new(), - }, - attrs: Vec::new(), - config: Vec::new(), - span: Span { - lo: BytePos(10), - hi: BytePos(20), - expn_id: NO_EXPANSION, - }, - exported_macros: Vec::new(), - }; - // doesn't matter which encoder we use.... - let _f = &e as &serialize::Encodable; + fn assert_encodable() {} + assert_encodable::(); } } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index c5dbd194e3e..cf09e2777f7 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -755,7 +755,7 @@ fn visit_item(&mut self, i: &'ast Item) { let parent = self.parent; self.parent = i.id; match i.node { - ItemImpl(_, _, _, _, ref impl_items) => { + ItemImpl(_, _, _, _, _, ref impl_items) => { for impl_item in impl_items.iter() { match *impl_item { MethodImplItem(ref m) => { @@ -859,9 +859,6 @@ fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, fn visit_ty(&mut self, ty: &'ast Ty) { match ty.node { - TyClosure(ref fd) => { - self.visit_fn_decl(&*fd.decl); - } TyBareFn(ref fd) => { self.visit_fn_decl(&*fd.decl); } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2c7bbcb6faf..a49f2614cd7 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -120,6 +120,7 @@ fn ne(&self, other: &Span) -> bool { !(*self).eq(other) } impl Eq for Span {} +#[cfg(stage0)] impl, E> Encodable for Span { /* Note #1972 -- spans are encoded but not decoded */ fn encode(&self, s: &mut S) -> Result<(), E> { @@ -127,12 +128,28 @@ fn encode(&self, s: &mut S) -> Result<(), E> { } } +#[cfg(not(stage0))] +impl Encodable for Span { + /* Note #1972 -- spans are encoded but not decoded */ + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_nil() + } +} + +#[cfg(stage0)] impl, E> Decodable for Span { fn decode(_d: &mut D) -> Result { Ok(DUMMY_SP) } } +#[cfg(not(stage0))] +impl Decodable for Span { + fn decode(_d: &mut D) -> Result { + Ok(DUMMY_SP) + } +} + pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { respan(mk_sp(lo, hi), t) } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 94a3784291d..3f91831a5df 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -133,11 +133,11 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ F: FnMut(&[ast::Attribute]) -> bool { let item = match item { - ast::ItemImpl(u, a, b, c, impl_items) => { + ast::ItemImpl(u, o, a, b, c, impl_items) => { let impl_items = impl_items.into_iter() .filter(|ii| impl_item_in_cfg(cx, ii)) .collect(); - ast::ItemImpl(u, a, b, c, impl_items) + ast::ItemImpl(u, o, a, b, c, impl_items) } ast::ItemTrait(u, a, b, methods) => { let methods = methods.into_iter() diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index eedec6f37c8..3c74a9f4431 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, args: Vec::new(), ret_ty: Self, attributes: attrs, - combine_substructure: combine_substructure(|c, s, sub| { + combine_substructure: combine_substructure(box |c, s, sub| { cs_clone("Clone", c, s, sub) }), } diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 7a67fab820d..84d30a99004 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -40,7 +40,7 @@ fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { cx.expr_binary(span, ast::BiAnd, subexpr, eq) }, cx.expr_bool(span, true), - |cx, span, _, _| cx.expr_bool(span, false), + box |cx, span, _, _| cx.expr_bool(span, false), cx, span, substr) } fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { @@ -57,7 +57,7 @@ fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { cx.expr_binary(span, ast::BiOr, subexpr, eq) }, cx.expr_bool(span, false), - |cx, span, _, _| cx.expr_bool(span, true), + box |cx, span, _, _| cx.expr_bool(span, true), cx, span, substr) } @@ -72,7 +72,7 @@ macro_rules! md ( args: vec!(borrowed_self()), ret_ty: Literal(Path::new(vec!("bool"))), attributes: attrs, - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { $f(a, b, c) }) } diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index c02416bfbea..f9c8d95b308 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -38,7 +38,7 @@ macro_rules! md ( args: vec!(borrowed_self()), ret_ty: Literal(Path::new(vec!("bool"))), attributes: attrs, - combine_substructure: combine_substructure(|cx, span, substr| { + combine_substructure: combine_substructure(box |cx, span, substr| { cs_op($op, $equal, cx, span, substr) }) } @@ -61,7 +61,7 @@ macro_rules! md ( args: vec![borrowed_self()], ret_ty: ret_ty, attributes: attrs, - combine_substructure: combine_substructure(|cx, span, substr| { + combine_substructure: combine_substructure(box |cx, span, substr| { cs_partial_cmp(cx, span, substr) }) }; @@ -174,7 +174,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, cx.expr_block(cx.block(span, vec!(assign), Some(if_))) }, equals_expr.clone(), - |cx, span, (self_args, tag_tuple), _non_self_args| { + box |cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`") } else { @@ -222,7 +222,7 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, cx.expr_binary(span, ast::BiOr, cmp, and) }, cx.expr_bool(span, equal), - |cx, span, (self_args, tag_tuple), _non_self_args| { + box |cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`") } else { diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs index 2b986bea122..cdb36ede65d 100644 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -32,7 +32,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< let block = cx.block(span, stmts, None); cx.expr_block(block) }, - |cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"), + box |cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"), cx, span, substr) @@ -57,7 +57,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< args: vec!(), ret_ty: nil_ty(), attributes: attrs, - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { cs_total_eq_assert(a, b, c) }) } diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 65a4c569b44..10ecc86bda5 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -41,7 +41,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt, args: vec!(borrowed_self()), ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))), attributes: attrs, - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { cs_cmp(a, b, c) }), } @@ -130,7 +130,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, cx.expr_block(cx.block(span, vec!(assign), Some(if_))) }, cx.expr_path(equals_path.clone()), - |cx, span, (self_args, tag_tuple), _non_self_args| { + box |cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`") } else { diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 882136cb862..8094f0d3de8 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -52,29 +52,31 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, - vec!(box Literal(Path::new_local("__D")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "decode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__D", vec!(Path::new_( + vec!(krate, "Decoder"), None, + vec!(), true)))) + }, explicit_self: None, args: vec!(Ptr(box Literal(Path::new_local("__D")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), None, - vec!(box Self, - box Literal(Path::new_local("__E"))), true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Self, box Literal(Path::new_( + vec!["__D", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { decodable_substructure(a, b, c, krate) }), }) diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 49bcb26a4c2..047c4fef3c4 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, args: Vec::new(), ret_ty: Self, attributes: attrs, - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { default_substructure(a, b, c) }) }) diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index b2c929123d5..0fceb0fbfda 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -128,31 +128,31 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, - vec!(box Literal(Path::new_local("__S")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "encode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__S", vec!(Path::new_( + vec!(krate, "Encoder"), None, + vec!(), true)))) + }, explicit_self: borrowed_explicit_self(), args: vec!(Ptr(box Literal(Path::new_local("__S")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), - None, - vec!(box Tuple(Vec::new()), - box Literal(Path::new_local("__E"))), - true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Tuple(Vec::new()), box Literal(Path::new_( + vec!["__S", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { encodable_substructure(a, b, c) }), }) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 8863de8757b..1fb8189c63c 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -312,7 +312,7 @@ pub enum SubstructureFields<'a> { /// Combine the values of all the fields together. The last argument is /// all the fields of all the structures. pub type CombineSubstructureFunc<'a> = - |&mut ExtCtxt, Span, &Substructure|: 'a -> P; + Box P + 'a>; /// Deal with non-matching enum variants. The tuple is a list of /// identifiers (one for each `Self` argument, which could be any of the @@ -320,11 +320,7 @@ pub enum SubstructureFields<'a> { /// holding the variant index value for each of the `Self` arguments. The /// last argument is all the non-`Self` args of the method being derived. pub type EnumNonMatchCollapsedFunc<'a> = - |&mut ExtCtxt, - Span, - (&[Ident], &[Ident]), - &[P]|: 'a - -> P; + Box]) -> P + 'a>; pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) -> RefCell> { @@ -488,6 +484,7 @@ fn create_derived_impl(&self, ident, a, ast::ItemImpl(ast::Unsafety::Normal, + ast::ImplPolarity::Positive, trait_generics, opt_trait_ref, self_type, @@ -605,7 +602,7 @@ fn call_substructure_method(&self, }; let mut f = self.combine_substructure.borrow_mut(); let f: &mut CombineSubstructureFunc = &mut *f; - (*f)(cx, trait_.span, &substructure) + f.call_mut((cx, trait_.span, &substructure)) } fn get_ret_ty(&self, @@ -1340,7 +1337,7 @@ fn create_enum_variant_pattern(&self, pub fn cs_fold(use_foldl: bool, mut f: F, base: P, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, + mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) @@ -1368,8 +1365,8 @@ pub fn cs_fold(use_foldl: bool, } }, EnumNonMatchingCollapsed(ref all_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (all_args[], tuple), - substructure.nonself_args), + enum_nonmatch_f.call_mut((cx, trait_span, (all_args[], tuple), + substructure.nonself_args)), StaticEnum(..) | StaticStruct(..) => { cx.span_bug(trait_span, "static function in `derive`") } @@ -1386,7 +1383,7 @@ pub fn cs_fold(use_foldl: bool, /// ``` #[inline] pub fn cs_same_method(f: F, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, + mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) @@ -1408,8 +1405,8 @@ pub fn cs_same_method(f: F, f(cx, trait_span, called) }, EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (all_self_args[], tuple), - substructure.nonself_args), + enum_nonmatch_f.call_mut((cx, trait_span, (all_self_args[], tuple), + substructure.nonself_args)), StaticEnum(..) | StaticStruct(..) => { cx.span_bug(trait_span, "static function in `derive`") } diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 9ff42d85cfb..b9acde4bf6b 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -55,7 +55,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, args: vec!(Ptr(box Literal(args), Borrowed(None, MutMutable))), ret_ty: nil_ty(), attributes: attrs, - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { hash_substructure(a, b, c) }) } diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 8abd846373a..d36bb2cd1c2 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -46,7 +46,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, true)), // #[inline] liable to cause code-bloat attributes: attrs.clone(), - combine_substructure: combine_substructure(|c, s, sub| { + combine_substructure: combine_substructure(box |c, s, sub| { cs_from("i64", c, s, sub) }), }, @@ -62,7 +62,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, true)), // #[inline] liable to cause code-bloat attributes: attrs, - combine_substructure: combine_substructure(|c, s, sub| { + combine_substructure: combine_substructure(box |c, s, sub| { cs_from("u64", c, s, sub) }), }) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 1ddf5b2a5c3..5517019f804 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -45,7 +45,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, ), ret_ty: Self, attributes: Vec::new(), - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { rand_substructure(a, b, c) }) } diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index 0513c75cf57..eceac4e9a83 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -46,7 +46,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, args: vec!(fmtr), ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))), attributes: Vec::new(), - combine_substructure: combine_substructure(|a, b, c| { + combine_substructure: combine_substructure(box |a, b, c| { show_substructure(a, b, c) }) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e65ecc19ea1..b3f30dd4581 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1111,7 +1111,7 @@ fn fold_pat(&mut self, pat: P) -> P { fn fold_item(&mut self, item: P) -> SmallVector> { let prev_type = self.current_impl_type.clone(); - if let ast::Item_::ItemImpl(_, _, _, ref ty, _) = item.node { + if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node { self.current_impl_type = Some(ty.clone()); } diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index bac82494f28..4075b208f78 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -21,7 +21,6 @@ use std::cell::RefCell; use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; /// The SCTable contains a table of SyntaxContext_'s. It /// represents a flattened tree structure, to avoid having @@ -67,10 +66,9 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext { /// Extend a syntax context with a given mark and sctable (explicit memoization) fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext { let key = (ctxt, m); - * match table.mark_memo.borrow_mut().entry(key) { - Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))), - Occupied(entry) => entry.into_mut(), - } + * table.mark_memo.borrow_mut().entry(&key).get().unwrap_or_else( + |vacant_entry| + vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))) } /// Extend a syntax context with a given rename @@ -86,10 +84,9 @@ fn apply_rename_internal(id: Ident, table: &SCTable) -> SyntaxContext { let key = (ctxt, id, to); - * match table.rename_memo.borrow_mut().entry(key) { - Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))), - Occupied(entry) => entry.into_mut(), - } + * table.rename_memo.borrow_mut().entry(&key).get().unwrap_or_else( + |vacant_entry| + vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))) } /// Apply a list of renamings to a context diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 69e473055e8..1438d152554 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -219,9 +219,9 @@ fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc], } } &TtToken(sp, MatchNt(bind_name, _, _, _)) => { - match ret_val.entry(bind_name) { + match ret_val.entry(&bind_name) { Vacant(spot) => { - spot.set(res[*idx].clone()); + spot.insert(res[*idx].clone()); *idx += 1; } Occupied(..) => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f75873ac1c0..cb6277069e1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -84,6 +84,9 @@ // A way to temporarily opt out of the new orphan rules. This will *never* be accepted. ("old_orphan_check", Deprecated), + // OIBIT specific features + ("optin_builtin_traits", Active), + // These are used to test this portion of the compiler, they don't actually // mean anything ("test_accepted_feature", Accepted), @@ -291,7 +294,17 @@ fn visit_item(&mut self, i: &ast::Item) { } } - ast::ItemImpl(_, _, _, _, ref items) => { + ast::ItemImpl(_, polarity, _, _, _, ref items) => { + match polarity { + ast::ImplPolarity::Negative => { + self.gate_feature("optin_builtin_traits", + i.span, + "negative trait bounds are not yet fully implemented; \ + use marker types for now"); + }, + _ => {} + } + if attr::contains_name(i.attrs[], "unsafe_destructor") { self.gate_feature("unsafe_destructor", @@ -351,12 +364,6 @@ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { } fn visit_ty(&mut self, t: &ast::Ty) { - if let ast::TyClosure(ref closure) = t.node { - // this used to be blocked by a feature gate, but it should just - // be plain impossible right now - assert!(closure.onceness != ast::Once); - } - visit::walk_ty(self, t); } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3d3068f6868..396b0033b81 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -414,17 +414,6 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyRptr(region, mt) => { TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) } - TyClosure(f) => { - TyClosure(f.map(|ClosureTy {unsafety, onceness, bounds, decl, lifetimes}| { - ClosureTy { - unsafety: unsafety, - onceness: onceness, - bounds: fld.fold_bounds(bounds), - decl: fld.fold_fn_decl(decl), - lifetimes: fld.fold_lifetime_defs(lifetimes) - } - })) - } TyBareFn(f) => { TyBareFn(f.map(|BareFnTy {lifetimes, unsafety, abi, decl}| BareFnTy { lifetimes: fld.fold_lifetime_defs(lifetimes), @@ -1014,7 +1003,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { let struct_def = folder.fold_struct_def(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } - ItemImpl(unsafety, generics, ifce, ty, impl_items) => { + ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => { let mut new_impl_items = Vec::new(); for impl_item in impl_items.iter() { match *impl_item { @@ -1037,6 +1026,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { } }; ItemImpl(unsafety, + polarity, folder.fold_generics(generics), ifce, folder.fold_ty(ty), @@ -1166,7 +1156,7 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span} let node = folder.fold_item_underscore(node); let ident = match node { // The node may have changed, recompute the "pretty" impl name. - ItemImpl(_, _, ref maybe_trait, ref ty, _) => { + ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => { ast_util::impl_pretty_name(maybe_trait, &**ty) } _ => ident diff --git a/src/libsyntax/owned_slice.rs b/src/libsyntax/owned_slice.rs index b87e2c6abbc..2a27431a086 100644 --- a/src/libsyntax/owned_slice.rs +++ b/src/libsyntax/owned_slice.rs @@ -82,12 +82,21 @@ fn from_iter>(iter: I) -> OwnedSlice { } } +#[cfg(stage0)] impl, T: Encodable, E> Encodable for OwnedSlice { fn encode(&self, s: &mut S) -> Result<(), E> { self.as_slice().encode(s) } } +#[cfg(not(stage0))] +impl Encodable for OwnedSlice { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.as_slice().encode(s) + } +} + +#[cfg(stage0)] impl, T: Decodable, E> Decodable for OwnedSlice { fn decode(d: &mut D) -> Result, E> { Ok(OwnedSlice::from_vec(match Decodable::decode(d) { @@ -96,3 +105,13 @@ fn decode(d: &mut D) -> Result, E> { })) } } + +#[cfg(not(stage0))] +impl Decodable for OwnedSlice { + fn decode(d: &mut D) -> Result, D::Error> { + Ok(OwnedSlice::from_vec(match Decodable::decode(d) { + Ok(t) => t, + Err(e) => return Err(e) + })) + } +} diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index e1e456f880e..75b2c17b81b 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -34,6 +34,7 @@ pub enum ObsoleteSyntax { ObsoleteExternCrateRenaming, ObsoleteProcType, ObsoleteProcExpr, + ObsoleteClosureType, } pub trait ParserObsoleteMethods { @@ -94,6 +95,10 @@ fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { ObsoleteExternCrateRenaming => ( "`extern crate foo = bar` syntax", "write `extern crate bar as foo` instead" + ), + ObsoleteClosureType => ( + "`|uint| -> bool` closure type syntax", + "use unboxed closures instead, no type annotation needed" ) }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 37ac86a3324..8e4a385923a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -14,7 +14,7 @@ use self::ItemOrViewItem::*; use abi; -use ast::{AssociatedType, BareFnTy, ClosureTy}; +use ast::{AssociatedType, BareFnTy}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{ProvidedMethod, Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; @@ -30,7 +30,6 @@ use ast::{ExprMethodCall, ExprParen, ExprPath}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; -use ast::{Many}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; @@ -55,7 +54,7 @@ use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; -use ast::{TypeField, TyFixedLengthVec, TyClosure, TyBareFn}; +use ast::{TypeField, TyFixedLengthVec, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; @@ -1227,38 +1226,29 @@ pub fn parse_ty_closure(&mut self, lifetime_defs: Vec) -> Ty_ */ - let unsafety = self.parse_unsafety(); + let ty_closure_span = self.last_span; - let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); + // To be helpful, parse the closure type as ever + let _ = self.parse_unsafety(); - let inputs = if self.eat(&token::OrOr) { - Vec::new() - } else { + let _ = self.parse_legacy_lifetime_defs(lifetime_defs); + + if !self.eat(&token::OrOr) { self.expect_or(); - let inputs = self.parse_seq_to_before_or( + let _ = self.parse_seq_to_before_or( &token::Comma, |p| p.parse_arg_general(false)); self.expect_or(); - inputs - }; + } - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); + let _ = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); - let output = self.parse_ret_ty(); - let decl = P(FnDecl { - inputs: inputs, - output: output, - variadic: false - }); + let _ = self.parse_ret_ty(); - TyClosure(P(ClosureTy { - unsafety: unsafety, - onceness: Many, - bounds: bounds, - decl: decl, - lifetimes: lifetime_defs, - })) + self.obsolete(ty_closure_span, ObsoleteClosureType); + + TyInfer } pub fn parse_unsafety(&mut self) -> Unsafety { @@ -2976,14 +2966,17 @@ pub fn parse_more_binops(&mut self, lhs: P, min_prec: uint) -> P { /// actually, this seems to be the main entry point for /// parsing an arbitrary expression. pub fn parse_assign_expr(&mut self) -> P { - let lo = self.span.lo; let lhs = self.parse_binops(); + self.parse_assign_expr_with(lhs) + } + + pub fn parse_assign_expr_with(&mut self, lhs: P) -> P { let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; match self.token { token::Eq => { self.bump(); let rhs = self.parse_expr_res(restrictions); - self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs)) + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)) } token::BinOpEq(op) => { self.bump(); @@ -3001,8 +2994,9 @@ pub fn parse_assign_expr(&mut self) -> P { token::Shr => BiShr }; let rhs_span = rhs.span; + let span = lhs.span; let assign_op = self.mk_assign_op(aop, lhs, rhs); - self.mk_expr(lo, rhs_span.hi, assign_op) + self.mk_expr(span.lo, rhs_span.hi, assign_op) } _ => { lhs @@ -3896,8 +3890,9 @@ fn parse_block_tail_(&mut self, lo: BytePos, s: BlockCheckMode, let e = self.mk_mac_expr(span.lo, span.hi, macro.and_then(|m| m.node)); - let e = - self.parse_dot_or_call_expr_with(e); + let e = self.parse_dot_or_call_expr_with(e); + let e = self.parse_more_binops(e, 0); + let e = self.parse_assign_expr_with(e); self.handle_expression_like_statement( e, ast::DUMMY_NODE_ID, @@ -4801,6 +4796,13 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo { // allow this to be parsed as a trait. let could_be_trait = self.token != token::OpenDelim(token::Paren); + let neg_span = self.span; + let polarity = if self.eat(&token::Not) { + ast::ImplPolarity::Negative + } else { + ast::ImplPolarity::Positive + }; + // Parse the trait. let mut ty = self.parse_ty_sum(); @@ -4823,6 +4825,14 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo { ty = self.parse_ty_sum(); opt_trait_ref } else { + match polarity { + ast::ImplPolarity::Negative => { + // This is a negated type implementation + // `impl !MyType {}`, which is not allowed. + self.span_err(neg_span, "inherent implementation can't be negated"); + }, + _ => {} + } None }; @@ -4832,7 +4842,7 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo { let ident = ast_util::impl_pretty_name(&opt_trait, &*ty); (ident, - ItemImpl(unsafety, generics, opt_trait, ty, impl_items), + ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items), Some(attrs)) } @@ -4875,67 +4885,116 @@ fn parse_item_struct(&mut self) -> ItemInfo { self.span_err(ty.span, "`virtual` structs have been removed from the language"); } - self.parse_where_clause(&mut generics); + // There is a special case worth noting here, as reported in issue #17904. + // If we are parsing a tuple struct it is the case that the where clause + // should follow the field list. Like so: + // + // struct Foo(T) where T: Copy; + // + // If we are parsing a normal record-style struct it is the case + // that the where clause comes before the body, and after the generics. + // So if we look ahead and see a brace or a where-clause we begin + // parsing a record style struct. + // + // Otherwise if we look ahead and see a paren we parse a tuple-style + // struct. + + let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(&mut generics); + if self.eat(&token::Semi) { + // If we see a: `struct Foo where T: Copy;` style decl. + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + } else { + // If we see: `struct Foo where T: Copy { ... }` + (self.parse_record_struct_body(&class_name), None) + } + // No `where` so: `struct Foo;` + } else if self.eat(&token::Semi) { + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + // Record-style struct definition + } else if self.token == token::OpenDelim(token::Brace) { + let fields = self.parse_record_struct_body(&class_name); + (fields, None) + // Tuple-style struct definition with optional where-clause. + } else { + let fields = self.parse_tuple_struct_body(&class_name, &mut generics); + (fields, Some(ast::DUMMY_NODE_ID)) + }; - let mut fields: Vec; - let is_tuple_like; + (class_name, + ItemStruct(P(ast::StructDef { + fields: fields, + ctor_id: ctor_id, + }), generics), + None) + } + pub fn parse_record_struct_body(&mut self, class_name: &ast::Ident) -> Vec { + let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { - // It's a record-like struct. - is_tuple_like = false; - fields = Vec::new(); while self.token != token::CloseDelim(token::Brace) { fields.push(self.parse_struct_decl_field(true)); } + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } + self.bump(); - } else if self.check(&token::OpenDelim(token::Paren)) { - // It's a tuple-like struct. - is_tuple_like = true; - fields = self.parse_unspanned_seq( + } else { + let token_str = self.this_token_to_string(); + self.fatal(format!("expected `where`, or `{}` after struct \ + name, found `{}`", "{", + token_str)[]); + } + + fields + } + + pub fn parse_tuple_struct_body(&mut self, + class_name: &ast::Ident, + generics: &mut ast::Generics) + -> Vec { + // This is the case where we find `struct Foo(T) where T: Copy;` + if self.check(&token::OpenDelim(token::Paren)) { + let fields = self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), |p| { - let attrs = p.parse_outer_attributes(); - let lo = p.span.lo; - let struct_field_ = ast::StructField_ { - kind: UnnamedField(p.parse_visibility()), - id: ast::DUMMY_NODE_ID, - ty: p.parse_ty_sum(), - attrs: attrs, - }; - spanned(lo, p.span.hi, struct_field_) - }); + let attrs = p.parse_outer_attributes(); + let lo = p.span.lo; + let struct_field_ = ast::StructField_ { + kind: UnnamedField(p.parse_visibility()), + id: ast::DUMMY_NODE_ID, + ty: p.parse_ty_sum(), + attrs: attrs, + }; + spanned(lo, p.span.hi, struct_field_) + }); + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } + + self.parse_where_clause(generics); self.expect(&token::Semi); - } else if self.eat(&token::Semi) { - // It's a unit-like struct. - is_tuple_like = true; - fields = Vec::new(); + fields + // This is the case where we just see struct Foo where T: Copy; + } else if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(generics); + self.expect(&token::Semi); + Vec::new() + // This case is where we see: `struct Foo;` } else { let token_str = self.this_token_to_string(); - self.fatal(format!("expected `{}`, `(`, or `;` after struct \ - name, found `{}`", "{", - token_str)[]) + self.fatal(format!("expected `where`, `{}`, `(`, or `;` after struct \ + name, found `{}`", "{", token_str)[]); } - - let _ = ast::DUMMY_NODE_ID; // FIXME: Workaround for crazy bug. - let new_id = ast::DUMMY_NODE_ID; - (class_name, - ItemStruct(P(ast::StructDef { - fields: fields, - ctor_id: if is_tuple_like { Some(new_id) } else { None }, - }), generics), - None) } /// Parse a structure field declaration diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4bfcc94a083..b7e89b32b70 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -653,6 +653,7 @@ fn ne(&self, other: &InternedString) -> bool { } } +#[cfg(stage0)] impl, E> Decodable for InternedString { fn decode(d: &mut D) -> Result { Ok(get_name(get_ident_interner().intern( @@ -660,12 +661,28 @@ fn decode(d: &mut D) -> Result { } } +#[cfg(not(stage0))] +impl Decodable for InternedString { + fn decode(d: &mut D) -> Result { + Ok(get_name(get_ident_interner().intern( + try!(d.read_str())[]))) + } +} + +#[cfg(stage0)] impl, E> Encodable for InternedString { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(self.string[]) } } +#[cfg(not(stage0))] +impl Encodable for InternedString { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string[]) + } +} + /// Returns the string contents of a name, using the task-local interner. #[inline] pub fn get_name(name: ast::Name) -> InternedString { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9702c79719c..effd6e8218d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -714,25 +714,6 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> { Some(&generics), None)); } - ast::TyClosure(ref f) => { - let generics = ast::Generics { - lifetimes: f.lifetimes.clone(), - ty_params: OwnedSlice::empty(), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, - }; - try!(self.print_ty_fn(None, - Some('&'), - f.unsafety, - f.onceness, - &*f.decl, - None, - &f.bounds, - Some(&generics), - None)); - } ast::TyPath(ref path, _) => { try!(self.print_path(path, false)); } @@ -917,6 +898,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { } ast::ItemImpl(unsafety, + polarity, ref generics, ref opt_trait, ref ty, @@ -931,6 +913,13 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { try!(space(&mut self.s)); } + match polarity { + ast::ImplPolarity::Negative => { + try!(word(&mut self.s, "!")); + }, + _ => {} + } + match opt_trait { &Some(ref t) => { try!(self.print_trait_ref(t)); @@ -1067,7 +1056,6 @@ pub fn print_struct(&mut self, span: codemap::Span) -> IoResult<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); - try!(self.print_where_clause(generics)); if ast_util::struct_def_is_tuple_like(struct_def) { if !struct_def.fields.is_empty() { try!(self.popen()); @@ -1086,10 +1074,12 @@ pub fn print_struct(&mut self, )); try!(self.pclose()); } + try!(self.print_where_clause(generics)); try!(word(&mut self.s, ";")); try!(self.end()); self.end() // close the outer-box } else { + try!(self.print_where_clause(generics)); try!(self.nbsp()); try!(self.bopen()); try!(self.hardbreak_if_not_bol()); diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 6eee1d903ea..13eda7bb88f 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -111,14 +111,30 @@ fn hash(&self, state: &mut S) { } } +#[cfg(stage0)] impl, T: 'static + Decodable> Decodable for P { fn decode(d: &mut D) -> Result, E> { Decodable::decode(d).map(P) } } +#[cfg(not(stage0))] +impl Decodable for P { + fn decode(d: &mut D) -> Result, D::Error> { + Decodable::decode(d).map(P) + } +} + +#[cfg(stage0)] impl, T: Encodable> Encodable for P { fn encode(&self, s: &mut S) -> Result<(), E> { (**self).encode(s) } } + +#[cfg(not(stage0))] +impl Encodable for P { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 354ba854b10..51d655ec0f2 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -13,27 +13,73 @@ //! This module shows spans for all expressions in the crate //! to help with compiler debugging. +use std::str::FromStr; + use ast; use diagnostic; use visit; use visit::Visitor; +enum Mode { + Expression, + Pattern, + Type, +} + +impl FromStr for Mode { + fn from_str(s: &str) -> Option { + let mode = match s { + "expr" => Mode::Expression, + "pat" => Mode::Pattern, + "ty" => Mode::Type, + _ => return None + }; + Some(mode) + } +} + struct ShowSpanVisitor<'a> { span_diagnostic: &'a diagnostic::SpanHandler, + mode: Mode, } impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { - self.span_diagnostic.span_note(e.span, "expression"); + if let Mode::Expression = self.mode { + self.span_diagnostic.span_note(e.span, "expression"); + } visit::walk_expr(self, e); } + fn visit_pat(&mut self, p: &ast::Pat) { + if let Mode::Pattern = self.mode { + self.span_diagnostic.span_note(p.span, "pattern"); + } + visit::walk_pat(self, p); + } + + fn visit_ty(&mut self, t: &ast::Ty) { + if let Mode::Type = self.mode { + self.span_diagnostic.span_note(t.span, "type"); + } + visit::walk_ty(self, t); + } + fn visit_mac(&mut self, macro: &ast::Mac) { visit::walk_mac(self, macro); } } -pub fn run(span_diagnostic: &diagnostic::SpanHandler, krate: &ast::Crate) { - let mut v = ShowSpanVisitor { span_diagnostic: span_diagnostic }; +pub fn run(span_diagnostic: &diagnostic::SpanHandler, + mode: &str, + krate: &ast::Crate) { + let mode = match mode.parse() { + Some(mode) => mode, + None => return + }; + let mut v = ShowSpanVisitor { + span_diagnostic: span_diagnostic, + mode: mode, + }; visit::walk_crate(&mut v, krate); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ec6b2cfa5c3..737f1b73b32 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -297,7 +297,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_generics(type_parameters); walk_enum_def(visitor, enum_definition, type_parameters) } - ItemImpl(_, + ItemImpl(_, _, ref type_parameters, ref trait_reference, ref typ, @@ -404,14 +404,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(&**tuple_element_type) } } - TyClosure(ref function_declaration) => { - for argument in function_declaration.decl.inputs.iter() { - visitor.visit_ty(&*argument.ty) - } - walk_fn_ret_ty(visitor, &function_declaration.decl.output); - walk_ty_param_bounds_helper(visitor, &function_declaration.bounds); - walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes); - } TyBareFn(ref function_declaration) => { for argument in function_declaration.decl.inputs.iter() { visitor.visit_ty(&*argument.ty) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 4bac20dd67c..3fb2211eff2 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -58,7 +58,7 @@ use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; -use std::any::{Any, AnyRefExt}; +use std::any::Any; use std::cmp; use std::collections::BTreeMap; use std::f64; diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 35af0e763d7..7e7f36f6e83 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -438,12 +438,14 @@ pub fn write_boxplot( /// Returns a HashMap with the number of occurrences of every element in the /// sequence that the iterator exposes. -pub fn freq_count, U: Eq+Hash>(mut iter: T) -> hash_map::HashMap { +pub fn freq_count(mut iter: T) -> hash_map::HashMap + where T: Iterator, U: Eq + Clone + Hash +{ let mut map: hash_map::HashMap = hash_map::HashMap::new(); for elem in iter { - match map.entry(elem) { + match map.entry(&elem) { Occupied(mut entry) => { *entry.get_mut() += 1; }, - Vacant(entry) => { entry.set(1); }, + Vacant(entry) => { entry.insert(1); }, } } map diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 72e9ce2bcaf..a3884d0c86e 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -44,9 +44,9 @@ // re-export char so that std et al see it correctly /// Character manipulation (`char` type, Unicode Scalar Value) /// -/// This module provides the `Char` and `UnicodeChar` traits, as well as their -/// implementation for the primitive `char` type, in order to allow basic character -/// manipulation. +/// This module provides the `CharExt` trait, as well as its +/// implementation for the primitive `char` type, in order to allow +/// basic character manipulation. /// /// A `char` actually represents a /// *[Unicode Scalar Value](http://www.unicode.org/glossary/#unicode_scalar_value)*, @@ -58,16 +58,14 @@ /// however the converse is not always true due to the above range limits /// and, as such, should be performed via the `from_u32` function.. pub mod char { - pub use core::char::{MAX, from_u32}; - pub use core::char::{from_digit}; - pub use core::char::Char; + pub use core::char::{MAX, from_u32, from_digit}; pub use normalize::{decompose_canonical, decompose_compatible, compose}; pub use tables::normalization::canonical_combining_class; pub use tables::UNICODE_VERSION; - pub use u_char::UnicodeChar; + pub use u_char::CharExt; } pub mod str { diff --git a/src/libunicode/tables.rs b/src/libunicode/tables.rs index e3550810010..c755ea93184 100644 --- a/src/libunicode/tables.rs +++ b/src/libunicode/tables.rs @@ -13,7 +13,7 @@ #![allow(missing_docs, non_upper_case_globals, non_snake_case)] /// The version of [Unicode](http://www.unicode.org/) -/// that the `UnicodeChar` and `UnicodeStrPrelude` traits are based on. +/// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on. pub const UNICODE_VERSION: (uint, uint, uint) = (7, 0, 0); fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { diff --git a/src/libunicode/u_char.rs b/src/libunicode/u_char.rs index 9c356801604..5693c222de1 100644 --- a/src/libunicode/u_char.rs +++ b/src/libunicode/u_char.rs @@ -8,19 +8,102 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unicode-intensive `char` methods. +//! Unicode-intensive `char` methods along with the `core` methods. //! //! These methods implement functionality for `char` that requires knowledge of //! Unicode definitions, including normalization, categorization, and display information. +use core::char; +use core::char::CharExt as C; use core::option::Option; use tables::{derived_property, property, general_category, conversions, charwidth}; -/// Useful functions for Unicode characters. -#[experimental = "pending prelude organization"] -pub trait UnicodeChar { +/// Functionality for manipulating `char`. +#[stable] +pub trait CharExt { + /// Checks if a `char` parses as a numeric digit in the given radix. + /// + /// Compared to `is_numeric()`, this function only recognizes the characters + /// `0-9`, `a-z` and `A-Z`. + /// + /// # Return value + /// + /// Returns `true` if `c` is a valid digit under `radix`, and `false` + /// otherwise. + /// + /// # Panics + /// + /// Panics if given a radix > 36. + #[unstable = "pending integer conventions"] + fn is_digit(self, radix: uint) -> bool; + + /// Converts a character to the corresponding digit. + /// + /// # Return value + /// + /// If `c` is between '0' and '9', the corresponding value between 0 and + /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns + /// none if the character does not refer to a digit in the given radix. + /// + /// # Panics + /// + /// Panics if given a radix outside the range [0..36]. + #[unstable = "pending integer conventions"] + fn to_digit(self, radix: uint) -> Option; + + /// Returns an iterator that yields the hexadecimal Unicode escape + /// of a character, as `char`s. + /// + /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` + /// where `NNNN` is the shortest hexadecimal representation of the code + /// point. + #[stable] + fn escape_unicode(self) -> char::EscapeUnicode; + + /// Returns an iterator that yields the 'default' ASCII and + /// C++11-like literal escape of a character, as `char`s. + /// + /// The default is chosen with a bias toward producing literals that are + /// legal in a variety of languages, including C++11 and similar C-family + /// languages. The exact rules are: + /// + /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. + /// * Single-quote, double-quote and backslash chars are backslash- + /// escaped. + /// * Any other chars in the range [0x20,0x7e] are not escaped. + /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. + #[stable] + fn escape_default(self) -> char::EscapeDefault; + + /// Returns the amount of bytes this character would need if encoded in + /// UTF-8. + #[stable] + fn len_utf8(self) -> uint; + + /// Returns the amount of bytes this character would need if encoded in + /// UTF-16. + #[stable] + fn len_utf16(self) -> uint; + + /// Encodes this character as UTF-8 into the provided byte buffer, + /// and then returns the number of bytes written. + /// + /// If the buffer is not large enough, nothing will be written into it + /// and a `None` will be returned. + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf8(self, dst: &mut [u8]) -> Option; + + /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// and then returns the number of `u16`s written. + /// + /// If the buffer is not large enough, nothing will be written into it + /// and a `None` will be returned. + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf16(self, dst: &mut [u16]) -> Option; + /// Returns whether the specified character is considered a Unicode /// alphabetic code point. + #[stable] fn is_alphabetic(self) -> bool; /// Returns whether the specified character satisfies the 'XID_Start' @@ -29,6 +112,7 @@ pub trait UnicodeChar { /// 'XID_Start' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), /// mostly similar to ID_Start but modified for closure under NFKx. + #[experimental = "mainly needed for compiler internals"] fn is_xid_start(self) -> bool; /// Returns whether the specified `char` satisfies the 'XID_Continue' @@ -37,38 +121,45 @@ pub trait UnicodeChar { /// 'XID_Continue' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + #[experimental = "mainly needed for compiler internals"] fn is_xid_continue(self) -> bool; /// Indicates whether a character is in lowercase. /// /// This is defined according to the terms of the Unicode Derived Core /// Property `Lowercase`. + #[stable] fn is_lowercase(self) -> bool; /// Indicates whether a character is in uppercase. /// /// This is defined according to the terms of the Unicode Derived Core /// Property `Uppercase`. + #[stable] fn is_uppercase(self) -> bool; /// Indicates whether a character is whitespace. /// /// Whitespace is defined in terms of the Unicode Property `White_Space`. + #[stable] fn is_whitespace(self) -> bool; /// Indicates whether a character is alphanumeric. /// /// Alphanumericness is defined in terms of the Unicode General Categories /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + #[stable] fn is_alphanumeric(self) -> bool; /// Indicates whether a character is a control code point. /// /// Control code points are defined in terms of the Unicode General /// Category `Cc`. + #[stable] fn is_control(self) -> bool; /// Indicates whether the character is numeric (Nd, Nl, or No). + #[stable] fn is_numeric(self) -> bool; /// Converts a character to its lowercase equivalent. @@ -80,6 +171,7 @@ pub trait UnicodeChar { /// /// Returns the lowercase equivalent of the character, or the character /// itself if no conversion is possible. + #[experimental = "pending case transformation decisions"] fn to_lowercase(self) -> char; /// Converts a character to its uppercase equivalent. @@ -102,6 +194,7 @@ pub trait UnicodeChar { /// [`SpecialCasing`.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt /// /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992 + #[experimental = "pending case transformation decisions"] fn to_uppercase(self) -> char; /// Returns this character's displayed width in columns, or `None` if it is a @@ -117,8 +210,26 @@ pub trait UnicodeChar { fn width(self, is_cjk: bool) -> Option; } -#[experimental = "pending prelude organization"] -impl UnicodeChar for char { +#[stable] +impl CharExt for char { + #[unstable = "pending integer conventions"] + fn is_digit(self, radix: uint) -> bool { C::is_digit(self, radix) } + #[unstable = "pending integer conventions"] + fn to_digit(self, radix: uint) -> Option { C::to_digit(self, radix) } + #[stable] + fn escape_unicode(self) -> char::EscapeUnicode { C::escape_unicode(self) } + #[stable] + fn escape_default(self) -> char::EscapeDefault { C::escape_default(self) } + #[stable] + fn len_utf8(self) -> uint { C::len_utf8(self) } + #[stable] + fn len_utf16(self) -> uint { C::len_utf16(self) } + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf8(self, dst: &mut [u8]) -> Option { C::encode_utf8(self, dst) } + #[unstable = "pending decision about Iterator/Writer/Reader"] + fn encode_utf16(self, dst: &mut [u16]) -> Option { C::encode_utf16(self, dst) } + + #[stable] fn is_alphabetic(self) -> bool { match self { 'a' ... 'z' | 'A' ... 'Z' => true, @@ -127,10 +238,13 @@ fn is_alphabetic(self) -> bool { } } + #[experimental = "mainly needed for compiler internals"] fn is_xid_start(self) -> bool { derived_property::XID_Start(self) } + #[experimental = "mainly needed for compiler internals"] fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) } + #[stable] fn is_lowercase(self) -> bool { match self { 'a' ... 'z' => true, @@ -139,6 +253,7 @@ fn is_lowercase(self) -> bool { } } + #[stable] fn is_uppercase(self) -> bool { match self { 'A' ... 'Z' => true, @@ -147,6 +262,7 @@ fn is_uppercase(self) -> bool { } } + #[stable] fn is_whitespace(self) -> bool { match self { ' ' | '\x09' ... '\x0d' => true, @@ -155,12 +271,15 @@ fn is_whitespace(self) -> bool { } } + #[stable] fn is_alphanumeric(self) -> bool { self.is_alphabetic() || self.is_numeric() } + #[stable] fn is_control(self) -> bool { general_category::Cc(self) } + #[stable] fn is_numeric(self) -> bool { match self { '0' ... '9' => true, @@ -169,8 +288,10 @@ fn is_numeric(self) -> bool { } } + #[experimental = "pending case transformation decisions"] fn to_lowercase(self) -> char { conversions::to_lower(self) } + #[experimental = "pending case transformation decisions"] fn to_uppercase(self) -> char { conversions::to_upper(self) } #[experimental = "needs expert opinion. is_cjk flag stands out as ugly"] diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 1b0c4171134..90949437774 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -13,7 +13,7 @@ //! Unicode-intensive string manipulations. //! //! This module provides functionality to `str` that requires the Unicode methods provided by the -//! UnicodeChar trait. +//! unicode parts of the CharExt trait. use self::GraphemeState::*; use core::prelude::*; @@ -26,7 +26,7 @@ use core::slice; use core::str::Split; -use u_char::UnicodeChar; +use u_char::CharExt as UCharExt; // conflicts with core::prelude::CharExt use tables::grapheme::GraphemeCat; /// An iterator over the words of a string, separated by a sequence of whitespace @@ -529,7 +529,7 @@ fn next(&mut self) -> Option { let mut buf = [0u16; 2]; self.chars.next().map(|ch| { - let n = ch.encode_utf16(buf.as_mut_slice()).unwrap_or(0); + let n = CharExt::encode_utf16(ch, buf.as_mut_slice()).unwrap_or(0); if n == 2 { self.extra = buf[1]; } buf[0] }) diff --git a/src/llvm b/src/llvm index ec1fdb3b9d3..b820135911e 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit ec1fdb3b9d3b1fb9e1dae97a65dd3a13db9bfb23 +Subproject commit b820135911e17c7a46b901db56baa48e5155bf46 diff --git a/src/rust-installer b/src/rust-installer index 3a37981744a..b5ac4cd4432 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit 3a37981744a5af2433fed551f742465c78c9af7f +Subproject commit b5ac4cd44321da10dfd70f070dbc9094ca3f92ff diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index c1ad6754ca1..2ac855681f2 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2015-01-03 +2015-01-05 diff --git a/src/snapshots.txt b/src/snapshots.txt index c72fd7978f8..5c21a8a8abf 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,12 @@ +S 2015-01-04 b2085d9 + freebsd-x86_64 50ccb6bf9c0645d0746a5167493a39b2be40c2d4 + linux-i386 b880b98d832c9a049b8ef6a50df50061e363de5a + linux-x86_64 82a09c162474b69d2d1e4e8399086f3f0f4e31c3 + macos-i386 569055bb10d96ab25f78ecf2c80ffbccd5e69b8d + macos-x86_64 cff1f9ebd63dae6890359b7d353bd9486d8ecdfc + winnt-i386 553790fe493413287a19d17a42bf7225d3e2272d + winnt-x86_64 bab0d13960afb7ccdd6bf11452de1b9c457cc3e9 + S 2015-01-02 c894171 freebsd-x86_64 ea8bcf75eada3539f5cbab51708eecf40d436b77 linux-i386 646ae265721e3cbe19404aae4fea4ffa1f1d90cf diff --git a/src/test/auxiliary/cci_impl_lib.rs b/src/test/auxiliary/cci_impl_lib.rs index 40a9a52061f..3b1857f9ccb 100644 --- a/src/test/auxiliary/cci_impl_lib.rs +++ b/src/test/auxiliary/cci_impl_lib.rs @@ -11,12 +11,12 @@ #![crate_name="cci_impl_lib"] pub trait uint_helpers { - fn to(&self, v: uint, f: |uint|); + fn to(&self, v: uint, f: F) where F: FnMut(uint); } impl uint_helpers for uint { #[inline] - fn to(&self, v: uint, f: |uint|) { + fn to(&self, v: uint, mut f: F) where F: FnMut(uint) { let mut i = *self; while i < v { f(i); diff --git a/src/test/auxiliary/cci_iter_lib.rs b/src/test/auxiliary/cci_iter_lib.rs index 84ade3572f9..3ba068df058 100644 --- a/src/test/auxiliary/cci_iter_lib.rs +++ b/src/test/auxiliary/cci_iter_lib.rs @@ -11,7 +11,7 @@ #![crate_name="cci_iter_lib"] #[inline] -pub fn iter(v: &[T], f: |&T|) { +pub fn iter(v: &[T], mut f: F) where F: FnMut(&T) { let mut i = 0u; let n = v.len(); while i < n { diff --git a/src/test/auxiliary/cci_no_inline_lib.rs b/src/test/auxiliary/cci_no_inline_lib.rs index 67f55cca1e1..474925d8838 100644 --- a/src/test/auxiliary/cci_no_inline_lib.rs +++ b/src/test/auxiliary/cci_no_inline_lib.rs @@ -12,7 +12,7 @@ // same as cci_iter_lib, more-or-less, but not marked inline -pub fn iter(v: Vec , f: |uint|) { +pub fn iter(v: Vec , mut f: F) where F: FnMut(uint) { let mut i = 0u; let n = v.len(); while i < n { diff --git a/src/test/auxiliary/iss.rs b/src/test/auxiliary/iss.rs index 37edcdf7628..690d5783c4b 100644 --- a/src/test/auxiliary/iss.rs +++ b/src/test/auxiliary/iss.rs @@ -12,12 +12,12 @@ // part of issue-6919.rs -pub struct C<'a> { - pub k: ||: 'a, +pub struct C where K: FnOnce() { + pub k: K, } fn no_op() { } -pub const D : C<'static> = C { - k: no_op +pub const D : C = C { + k: no_op as fn() }; diff --git a/src/test/auxiliary/issue13507.rs b/src/test/auxiliary/issue13507.rs index 961dad00091..c2820a8d4ae 100644 --- a/src/test/auxiliary/issue13507.rs +++ b/src/test/auxiliary/issue13507.rs @@ -21,7 +21,6 @@ pub fn type_ids() -> Vec { ids.push(TypeId::of::()); ids.push(TypeId::of::()); ids.push(TypeId::of::()); - ids.push(TypeId::of::()); ids.push(TypeId::of::<&'static FooTrait>()); ids.push(TypeId::of::()); ids.push(TypeId::of::()); @@ -68,9 +67,6 @@ pub enum FooEnum { // Skipping ty_bare_fn (how do you get a bare function type, rather than proc or closure?) - // Tests ty_closure (does not test all types of closures) - pub type FooClosure = |arg: u8|: 'static -> u8; - // Tests ty_trait pub trait FooTrait { fn foo_method(&self) -> uint; diff --git a/src/test/auxiliary/linkage-visibility.rs b/src/test/auxiliary/linkage-visibility.rs index 0b4bea49fa2..6cd94ee5602 100644 --- a/src/test/auxiliary/linkage-visibility.rs +++ b/src/test/auxiliary/linkage-visibility.rs @@ -27,7 +27,7 @@ fn bar() { } fn baz() { } pub fn test() { - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let lib = DynamicLibrary::open(none).unwrap(); unsafe { assert!(lib.symbol::("foo").is_ok()); diff --git a/src/test/auxiliary/logging_right_crate.rs b/src/test/auxiliary/logging_right_crate.rs index fad70a91798..399dfb9fa9a 100644 --- a/src/test/auxiliary/logging_right_crate.rs +++ b/src/test/auxiliary/logging_right_crate.rs @@ -13,5 +13,5 @@ pub fn foo() { fn death() -> int { panic!() } - debug!("{}", (||{ death() })()); + debug!("{}", (|&:|{ death() })()); } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 491d910f351..1dcac9fe074 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -61,12 +61,14 @@ fn contains(&self, k: &uint) -> bool { self.contains(k) } impl Results { pub fn bench_int, - R: rand::Rng>( + R:rand::Rng, + F:FnMut() -> T>( &mut self, rng: &mut R, num_keys: uint, rand_cap: uint, - f: || -> T) { { + mut f: F) { + { let mut set = f(); timed(&mut self.sequential_ints, || { for i in range(0u, num_keys) { @@ -103,11 +105,12 @@ pub fn bench_int, } pub fn bench_str, - R:rand::Rng>( + R:rand::Rng, + F:FnMut() -> T>( &mut self, rng: &mut R, num_keys: uint, - f: || -> T) { + mut f: F) { { let mut set = f(); timed(&mut self.sequential_strings, || { diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs index a3f1bc74b44..adf773a2f25 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -20,7 +20,6 @@ use std::sync::mpsc::channel; use std::os; use std::thread::Thread; -use std::uint; // This is a simple bench that creates M pairs of tasks. These // tasks ping-pong back and forth over a pair of streams. This is a @@ -31,24 +30,24 @@ fn ping_pong_bench(n: uint, m: uint) { // Create pairs of tasks that pingpong back and forth. fn run_pair(n: uint) { - // Create a stream A->B - let (atx, arx) = channel::<()>(); - // Create a stream B->A - let (btx, brx) = channel::<()>(); + // Create a channel: A->B + let (atx, arx) = channel(); + // Create a channel: B->A + let (btx, brx) = channel(); Thread::spawn(move|| { let (tx, rx) = (atx, brx); for _ in range(0, n) { - tx.send(()); - rx.recv(); + tx.send(()).unwrap(); + rx.recv().unwrap(); } }).detach(); Thread::spawn(move|| { let (tx, rx) = (btx, arx); for _ in range(0, n) { - rx.recv(); - tx.send(()); + rx.recv().unwrap(); + tx.send(()).unwrap(); } }).detach(); } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 8c0ec667332..e6ef6a8c8c9 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -94,7 +94,9 @@ fn update_freq(mm: &mut HashMap , uint>, key: &[u8]) { // given a Vec, for each window call a function // i.e., for "hello" and windows of size four, // run it("hell") and it("ello"), then return "llo" -fn windows_with_carry(bb: &[u8], nn: uint, it: |window: &[u8]|) -> Vec { +fn windows_with_carry(bb: &[u8], nn: uint, mut it: F) -> Vec where + F: FnMut(&[u8]), +{ let mut ii = 0u; let len = bb.len(); diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index 438775d8ba0..cdc7617fec8 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -53,14 +53,14 @@ // returns an infinite iterator of repeated applications of f to x, // i.e. [x, f(x), f(f(x)), ...], as haskell iterate function. -fn iterate<'a, T>(x: T, f: |&T|: 'a -> T) -> Iterate<'a, T> { +fn iterate(x: T, f: F) -> Iterate where F: FnMut(&T) -> T { Iterate {f: f, next: x} } -struct Iterate<'a, T> { - f: |&T|: 'a -> T, +struct Iterate where F: FnMut(&T) -> T { + f: F, next: T } -impl<'a, T> Iterator for Iterate<'a, T> { +impl Iterator for Iterate where F: FnMut(&T) -> T { type Item = T; fn next(&mut self) -> Option { diff --git a/src/test/compile-fail/access-mode-in-closures.rs b/src/test/compile-fail/access-mode-in-closures.rs index e1696f0e63e..f15157d126e 100644 --- a/src/test/compile-fail/access-mode-in-closures.rs +++ b/src/test/compile-fail/access-mode-in-closures.rs @@ -11,7 +11,7 @@ struct sty(Vec ); -fn unpack(_unpack: |v: &sty| -> Vec ) {} +fn unpack(_unpack: F) where F: FnOnce(&sty) -> Vec {} fn main() { let _foo = unpack(|s| { diff --git a/src/test/compile-fail/assign-to-method.rs b/src/test/compile-fail/assign-to-method.rs index 453d7ffdad5..f14668192f8 100644 --- a/src/test/compile-fail/assign-to-method.rs +++ b/src/test/compile-fail/assign-to-method.rs @@ -27,5 +27,5 @@ fn cat(in_x : uint, in_y : int) -> cat { fn main() { let nyan : cat = cat(52u, 99); - nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method + nyan.speak = |&:| println!("meow"); //~ ERROR attempted to take value of method } diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs new file mode 100644 index 00000000000..6555aa32027 --- /dev/null +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -0,0 +1,47 @@ +// Copyright 2014 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 equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Box { + type Color; + + fn mail(&self) { } +} + +pub trait BoxCar : Box + Vehicle { +} + +fn dent(c: C, color: C::Color) { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` + //~| NOTE could derive from `Vehicle` + //~| NOTE could derive from `Box` +} + +fn dent_object(c: BoxCar) { + //~^ ERROR ambiguous associated type +} + +fn paint(c: C, d: C::Color) { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` + //~| NOTE could derive from `Vehicle` + //~| NOTE could derive from `Box` +} + +pub fn main() { } diff --git a/src/test/compile-fail/associated-type-projection-from-supertrait.rs b/src/test/compile-fail/associated-type-projection-from-supertrait.rs new file mode 100644 index 00000000000..01f9bd3541f --- /dev/null +++ b/src/test/compile-fail/associated-type-projection-from-supertrait.rs @@ -0,0 +1,56 @@ +// Copyright 2014 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 equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Car : Vehicle { + fn honk(&self) { } + fn chip_paint(&self, c: Self::Color) { } +} + +/////////////////////////////////////////////////////////////////////////// + +struct Black; +struct ModelT; +impl Vehicle for ModelT { type Color = Black; } +impl Car for ModelT { } + +/////////////////////////////////////////////////////////////////////////// + +struct Blue; +struct ModelU; +impl Vehicle for ModelU { type Color = Blue; } +impl Car for ModelU { } + +/////////////////////////////////////////////////////////////////////////// + +fn dent(c: C, color: C::Color) { c.chip_paint(color) } +fn a() { dent(ModelT, Black); } +fn b() { dent(ModelT, Blue); } //~ ERROR type mismatch +fn c() { dent(ModelU, Black); } //~ ERROR type mismatch +fn d() { dent(ModelU, Blue); } + +/////////////////////////////////////////////////////////////////////////// + +fn e() { ModelT.chip_paint(Black); } +fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types +fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types +fn h() { ModelU.chip_paint(Blue); } + +pub fn main() { } diff --git a/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs new file mode 100644 index 00000000000..a362529bee8 --- /dev/null +++ b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs @@ -0,0 +1,53 @@ +// Copyright 2014 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 equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Car : Vehicle { + fn honk(&self) { } +} + +/////////////////////////////////////////////////////////////////////////// + +struct Black; +struct ModelT; +impl Vehicle for ModelT { type Color = Black; } +impl Car for ModelT { } + +/////////////////////////////////////////////////////////////////////////// + +struct Blue; +struct ModelU; +impl Vehicle for ModelU { type Color = Blue; } +impl Car for ModelU { } + +/////////////////////////////////////////////////////////////////////////// + +fn black_car>(c: C) { +} + +fn blue_car>(c: C) { +} + +fn a() { black_car(ModelT); } +fn b() { blue_car(ModelT); } //~ ERROR type mismatch +fn c() { black_car(ModelU); } //~ ERROR type mismatch +fn d() { blue_car(ModelU); } + +pub fn main() { } diff --git a/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs b/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs new file mode 100644 index 00000000000..8afd86195ff --- /dev/null +++ b/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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 report an error if the trait ref in an qualified type +// uses invalid type arguments. + +#![feature(associated_types)] + +trait Foo { + type Bar; + fn get_bar(&self) -> Self::Bar; +} + +fn f>(t: &T) { + let u: >::Bar = t.get_bar(); + //~^ ERROR the trait `Foo` is not implemented for the type `T` +} + +fn main() { } diff --git a/src/test/compile-fail/associated-types-issue-17359.rs b/src/test/compile-fail/associated-types-issue-17359.rs new file mode 100644 index 00000000000..764b79c4cc6 --- /dev/null +++ b/src/test/compile-fail/associated-types-issue-17359.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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 do not ICE when an impl is missing an associated type (and that we report +// a useful error, of course). + +#![feature(associated_types)] + +trait Trait { + type Type; +} + +impl Trait for int {} //~ ERROR missing: `Type` + +fn main() {} + diff --git a/src/test/compile-fail/block-coerce-no-2.rs b/src/test/compile-fail/block-coerce-no-2.rs deleted file mode 100644 index e268b0e93fd..00000000000 --- a/src/test/compile-fail/block-coerce-no-2.rs +++ /dev/null @@ -1,23 +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. - -// Make sure that fn-to-block coercion isn't incorrectly lifted over -// other tycons. - -fn main() { - fn f(f: fn(fn(fn()))) { - } - - fn g(f: fn(||)) { - } - - f(g); - //~^ ERROR mismatched types: expected `fn(fn(fn()))` -} diff --git a/src/test/compile-fail/block-coerce-no.rs b/src/test/compile-fail/block-coerce-no.rs deleted file mode 100644 index 76af956a26f..00000000000 --- a/src/test/compile-fail/block-coerce-no.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. - -// Make sure that fn-to-block coercion isn't incorrectly lifted over -// other tycons. - -fn coerce(b: ||) -> extern fn() { - fn lol(f: extern fn(v: ||) -> extern fn(), - g: ||) -> extern fn() { return f(g); } - fn fn_id(f: extern fn()) -> extern fn() { return f } - return lol(fn_id, b); - //~^ ERROR mismatched types -} - -fn main() { - let i = 8i; - let f = coerce(|| println!("{}", i) ); - f(); -} diff --git a/src/test/compile-fail/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck-assign-comp-idx.rs index e14911d3508..a6801a6a51a 100644 --- a/src/test/compile-fail/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck-assign-comp-idx.rs @@ -24,7 +24,7 @@ fn a() { println!("{}", *q); } -fn borrow(_x: &[int], _f: ||) {} +fn borrow(_x: &[int], _f: F) where F: FnOnce() {} fn b() { // here we alias the mutable vector into an imm slice and try to diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs index 1b4e5891f94..2804b8c48a7 100644 --- a/src/test/compile-fail/borrowck-autoref-3261.rs +++ b/src/test/compile-fail/borrowck-autoref-3261.rs @@ -13,7 +13,7 @@ enum Either { Left(T), Right(U) } struct X(Either<(uint,uint), fn()>); impl X { - pub fn with(&self, blk: |x: &Either<(uint,uint), fn()>|) { + pub fn with(&self, blk: F) where F: FnOnce(&Either<(uint, uint), fn()>) { let X(ref e) = *self; blk(e) } @@ -25,7 +25,7 @@ fn main() { |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time match opt { &Either::Right(ref f) => { - x = X(Either::Left((0,0))); + x = X(Either::Left((0, 0))); (*f)() }, _ => panic!() diff --git a/src/test/compile-fail/borrowck-block-unint.rs b/src/test/compile-fail/borrowck-block-unint.rs index a37717ed5d9..e519e57d178 100644 --- a/src/test/compile-fail/borrowck-block-unint.rs +++ b/src/test/compile-fail/borrowck-block-unint.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn force(f: ||) { f(); } +fn force(f: F) where F: FnOnce() { f(); } fn main() { let x: int; force(|| { //~ ERROR capture of possibly uninitialized variable: `x` diff --git a/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs b/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs index 002ae5a7d28..6dbdff9441d 100644 --- a/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs @@ -10,53 +10,54 @@ // Ensure that invoking a closure counts as a unique immutable borrow +#![feature(unboxed_closures)] -type Fn<'a> = ||:'a; +type Fn<'a> = Box; struct Test<'a> { - f: ||: 'a + f: Box } -fn call(f: |Fn|) { - f(|| { - //~^ ERROR: closure requires unique access to `f` but it is already borrowed - f(|| {}) +fn call(mut f: F) where F: FnMut(Fn) { + f(box || { + //~^ ERROR: cannot borrow `f` as mutable more than once + f(box || {}) }); } fn test1() { - call(|a| { - a(); + call(|mut a| { + a.call_mut(()); }); } -fn test2(f: &||) { - (*f)(); //~ ERROR: closure invocation in a `&` reference +fn test2(f: &F) where F: FnMut() { + (*f)(); //~ ERROR: cannot borrow immutable dereference of `&`-pointer `*f` as mutable } -fn test3(f: &mut ||) { +fn test3(f: &mut F) where F: FnMut() { (*f)(); } fn test4(f: &Test) { - (f.f)() //~ ERROR: closure invocation in a `&` reference + f.f.call_mut(()) //~ ERROR: cannot borrow immutable dereference of `Box` `*f.f` as mutable } fn test5(f: &mut Test) { - (f.f)() + f.f.call_mut(()) } fn test6() { - let f = || {}; - (|| { + let mut f = |&mut:| {}; + (|&mut:| { f(); })(); } fn test7() { - fn foo(_: |g: |int|, b: int|) {} - let f = |g: |int|, b: int| {}; - f(|a| { //~ ERROR: cannot borrow `f` as immutable because previous closure + fn foo(_: F) where F: FnMut(Box, int) {} + let mut f = |&mut: g: Box, b: int| {}; + f(box |a| { //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable foo(f); //~ ERROR: cannot move out of captured outer variable }, 3); } diff --git a/src/test/compile-fail/borrowck-closures-mut-and-imm.rs b/src/test/compile-fail/borrowck-closures-mut-and-imm.rs index 886026e45d9..47a47d04432 100644 --- a/src/test/compile-fail/borrowck-closures-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck-closures-mut-and-imm.rs @@ -22,37 +22,37 @@ fn set(x: &mut int) { fn a() { let mut x = 3i; - let c1 = || x = 4; - let c2 = || x * 5; //~ ERROR cannot borrow `x` + let c1 = |&mut:| x = 4; + let c2 = |&mut:| x * 5; //~ ERROR cannot borrow `x` } fn b() { let mut x = 3i; - let c1 = || set(&mut x); - let c2 = || get(&x); //~ ERROR cannot borrow `x` + let c1 = |&mut:| set(&mut x); + let c2 = |&mut:| get(&x); //~ ERROR cannot borrow `x` } fn c() { let mut x = 3i; - let c1 = || set(&mut x); - let c2 = || x * 5; //~ ERROR cannot borrow `x` + let c1 = |&mut:| set(&mut x); + let c2 = |&mut:| x * 5; //~ ERROR cannot borrow `x` } fn d() { let mut x = 3i; - let c2 = || x * 5; + let c2 = |&mut:| x * 5; x = 5; //~ ERROR cannot assign } fn e() { let mut x = 3i; - let c1 = || get(&x); + let c1 = |&mut:| get(&x); x = 5; //~ ERROR cannot assign } fn f() { let mut x = box 3i; - let c1 = || get(&*x); + let c1 = |&mut:| get(&*x); *x = 5; //~ ERROR cannot assign } @@ -62,7 +62,7 @@ struct Foo { } let mut x = box Foo { f: box 3 }; - let c1 = || get(&*x.f); + let c1 = |&mut:| get(&*x.f); *x.f = 5; //~ ERROR cannot assign to `*x.f` } @@ -72,8 +72,8 @@ struct Foo { } let mut x = box Foo { f: box 3 }; - let c1 = || get(&*x.f); - let c2 = || *x.f = 5; //~ ERROR cannot borrow `x` as mutable + let c1 = |&mut:| get(&*x.f); + let c2 = |&mut:| *x.f = 5; //~ ERROR cannot borrow `x` as mutable } fn main() { diff --git a/src/test/compile-fail/borrowck-closures-mut-of-imm.rs b/src/test/compile-fail/borrowck-closures-mut-of-imm.rs index 8163df5e967..30e1421ba26 100644 --- a/src/test/compile-fail/borrowck-closures-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck-closures-mut-of-imm.rs @@ -20,9 +20,9 @@ fn set(x: &mut int) { } fn a(x: &int) { - let c1 = || set(&mut *x); + let c1 = |&mut:| set(&mut *x); //~^ ERROR cannot borrow - let c2 = || set(&mut *x); + let c2 = |&mut:| set(&mut *x); //~^ ERROR cannot borrow //~| ERROR closure requires unique access } diff --git a/src/test/compile-fail/borrowck-closures-two-mut.rs b/src/test/compile-fail/borrowck-closures-two-mut.rs index 6d382854d49..0f284b53849 100644 --- a/src/test/compile-fail/borrowck-closures-two-mut.rs +++ b/src/test/compile-fail/borrowck-closures-two-mut.rs @@ -15,8 +15,8 @@ fn a() { let mut x = 3i; - let c1 = || x = 4; - let c2 = || x = 5; //~ ERROR cannot borrow `x` as mutable more than once + let c1 = |&mut:| x = 4; + let c2 = |&mut:| x = 5; //~ ERROR cannot borrow `x` as mutable more than once } fn set(x: &mut int) { @@ -25,20 +25,20 @@ fn set(x: &mut int) { fn b() { let mut x = 3i; - let c1 = || set(&mut x); - let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once + let c1 = |&mut:| set(&mut x); + let c2 = |&mut:| set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once } fn c() { let mut x = 3i; - let c1 = || x = 5; - let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once + let c1 = |&mut:| x = 5; + let c2 = |&mut:| set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once } fn d() { let mut x = 3i; - let c1 = || x = 5; - let c2 = || { let _y = || set(&mut x); }; // (nested closure) + let c1 = |&mut:| x = 5; + let c2 = |&mut:| { let _y = |&mut:| set(&mut x); }; // (nested closure) //~^ ERROR cannot borrow `x` as mutable more than once } @@ -48,8 +48,8 @@ struct Foo { } let mut x = box Foo { f: box 3 }; - let c1 = || set(&mut *x.f); - let c2 = || set(&mut *x.f); + let c1 = |&mut:| set(&mut *x.f); + let c2 = |&mut:| set(&mut *x.f); //~^ ERROR cannot borrow `x` as mutable more than once } diff --git a/src/test/compile-fail/borrowck-closures-unique-imm.rs b/src/test/compile-fail/borrowck-closures-unique-imm.rs index dfe5de09c50..a9cc9e967f6 100644 --- a/src/test/compile-fail/borrowck-closures-unique-imm.rs +++ b/src/test/compile-fail/borrowck-closures-unique-imm.rs @@ -16,7 +16,7 @@ pub fn main() { let mut this = &mut Foo { x: 1, }; - let r = || { + let mut r = |&mut:| { let p = &this.x; &mut this.x; //~ ERROR cannot borrow }; diff --git a/src/test/compile-fail/borrowck-closures-unique.rs b/src/test/compile-fail/borrowck-closures-unique.rs index febc84ccd44..9a772cc49b8 100644 --- a/src/test/compile-fail/borrowck-closures-unique.rs +++ b/src/test/compile-fail/borrowck-closures-unique.rs @@ -23,27 +23,27 @@ fn set(x: &mut int) -> int { } fn a(x: &mut int) { - let c1 = || get(x); - let c2 = || get(x); + let c1 = |&mut:| get(x); + let c2 = |&mut:| get(x); } fn b(x: &mut int) { - let c1 = || get(x); - let c2 = || set(x); //~ ERROR closure requires unique access to `x` + let c1 = |&mut:| get(x); + let c2 = |&mut:| set(x); //~ ERROR closure requires unique access to `x` } fn c(x: &mut int) { - let c1 = || get(x); - let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x` + let c1 = |&mut:| get(x); + let c2 = |&mut:| { get(x); set(x); }; //~ ERROR closure requires unique access to `x` } fn d(x: &mut int) { - let c1 = || set(x); - let c2 = || set(x); //~ ERROR closure requires unique access to `x` + let c1 = |&mut:| set(x); + let c2 = |&mut:| set(x); //~ ERROR closure requires unique access to `x` } fn e(x: &mut int) { - let c1: || = || x = panic!(); //~ ERROR closure cannot assign to immutable local variable + let c1 = |&mut:| x = panic!(); //~ ERROR closure cannot assign to immutable local variable } fn main() { diff --git a/src/test/compile-fail/borrowck-closures-use-after-free.rs b/src/test/compile-fail/borrowck-closures-use-after-free.rs index 735d9ece9b1..23c90fcf574 100644 --- a/src/test/compile-fail/borrowck-closures-use-after-free.rs +++ b/src/test/compile-fail/borrowck-closures-use-after-free.rs @@ -25,7 +25,7 @@ fn drop(&mut self) { fn main() { let mut ptr = box Foo { x: 0 }; - let test = |foo: &Foo| { + let mut test = |&mut: foo: &Foo| { ptr = box Foo { x: ptr.x + 1 }; }; test(&*ptr); //~ ERROR cannot borrow `*ptr` diff --git a/src/test/compile-fail/borrowck-init-in-called-fn-expr.rs b/src/test/compile-fail/borrowck-init-in-called-fn-expr.rs index d759a5738bd..5496a9dd4b3 100644 --- a/src/test/compile-fail/borrowck-init-in-called-fn-expr.rs +++ b/src/test/compile-fail/borrowck-init-in-called-fn-expr.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let j: || -> int = || { + let j = |&:| -> int { let i: int; i //~ ERROR use of possibly uninitialized variable: `i` }; diff --git a/src/test/compile-fail/borrowck-init-in-fn-expr.rs b/src/test/compile-fail/borrowck-init-in-fn-expr.rs index 07e2ff08466..33c284c71b3 100644 --- a/src/test/compile-fail/borrowck-init-in-fn-expr.rs +++ b/src/test/compile-fail/borrowck-init-in-fn-expr.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let f: || -> int = || { + let f = |&:| -> int { let i: int; i //~ ERROR use of possibly uninitialized variable: `i` }; diff --git a/src/test/compile-fail/borrowck-insert-during-each.rs b/src/test/compile-fail/borrowck-insert-during-each.rs index a84a025d8a8..0428ee83065 100644 --- a/src/test/compile-fail/borrowck-insert-during-each.rs +++ b/src/test/compile-fail/borrowck-insert-during-each.rs @@ -16,7 +16,7 @@ struct Foo { } impl Foo { - pub fn foo(&mut self, fun: |&int|) { + pub fn foo(&mut self, mut fun: F) where F: FnMut(&int) { for f in self.n.iter() { fun(f); } diff --git a/src/test/compile-fail/borrowck-lend-flow-if.rs b/src/test/compile-fail/borrowck-lend-flow-if.rs index 8a7ecde700a..f798d170f96 100644 --- a/src/test/compile-fail/borrowck-lend-flow-if.rs +++ b/src/test/compile-fail/borrowck-lend-flow-if.rs @@ -18,7 +18,7 @@ fn borrow(_v: &int) {} fn borrow_mut(_v: &mut int) {} fn cond() -> bool { panic!() } -fn for_func(_f: || -> bool) { panic!() } +fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { diff --git a/src/test/compile-fail/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck-lend-flow-loop.rs index 6adcfad33f4..ff038b545d5 100644 --- a/src/test/compile-fail/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck-lend-flow-loop.rs @@ -112,7 +112,9 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { } } -fn loop_break_pops_scopes<'r>(_v: &'r mut [uint], f: |&'r mut uint| -> bool) { +fn loop_break_pops_scopes<'r, F>(_v: &'r mut [uint], mut f: F) where + F: FnMut(&'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. @@ -128,7 +130,7 @@ fn loop_break_pops_scopes<'r>(_v: &'r mut [uint], f: |&'r mut uint| -> bool) { } } -fn loop_loop_pops_scopes<'r>(_v: &'r mut [uint], f: |&'r mut uint| -> bool) { +fn loop_loop_pops_scopes<'r, F>(_v: &'r mut [uint], mut f: F) where F: FnMut(&'r mut uint) -> bool { // Similar to `loop_break_pops_scopes` but for the `loop` keyword while cond() { diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index de8c7d9def4..85fc7fb87b3 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -18,7 +18,7 @@ fn borrow(_v: &int) {} fn borrow_mut(_v: &mut int) {} fn cond() -> bool { panic!() } -fn for_func(_f: || -> bool) { panic!() } +fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { 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 9bd2d48b29a..5c282495cc2 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs @@ -10,7 +10,7 @@ use std::thread::Thread; -fn borrow(v: &int, f: |x: &int|) { +fn borrow(v: &int, f: F) where F: FnOnce(&int) { f(v); } 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 bfa890ada9f..b6a71fcd446 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn borrow(v: &int, f: |x: &int|) { +fn borrow(v: &int, f: F) where F: FnOnce(&int) { f(v); } diff --git a/src/test/compile-fail/borrowck-loan-rcvr.rs b/src/test/compile-fail/borrowck-loan-rcvr.rs index d678fd48f21..0ada3db47a4 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr.rs @@ -13,14 +13,14 @@ struct point { x: int, y: int } trait methods { fn impurem(&self); - fn blockm(&self, f: ||); + fn blockm(&self, f: F) where F: FnOnce(); } impl methods for point { fn impurem(&self) { } - fn blockm(&self, f: ||) { f() } + fn blockm(&self, f: F) where F: FnOnce() { f() } } fn a() { diff --git a/src/test/compile-fail/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck-loan-vec-content.rs index 200d208d140..7849475ec67 100644 --- a/src/test/compile-fail/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck-loan-vec-content.rs @@ -12,7 +12,7 @@ // (locally rooted) mutable, unique vector, and that we then prevent // modifications to the contents. -fn takes_imm_elt(_v: &int, f: ||) { +fn takes_imm_elt(_v: &int, f: F) where F: FnOnce() { f(); } diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index 9c9641bccfa..35f0751aa78 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -10,7 +10,7 @@ pub fn main() { let bar = box 3; - let _g = || { + let _g = |&mut:| { let _h = move |:| -> int { *bar }; //~ ERROR cannot move out of captured outer variable }; } diff --git a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs index c7b573562e3..c5d23925a89 100644 --- a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs +++ b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn with(f: |&String|) {} +fn with(f: F) where F: FnOnce(&String) {} fn arg_item(&_x: &String) {} //~^ ERROR cannot move out of dereference of `&`-pointer diff --git a/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs index 82189c6b7c1..0a47353683c 100644 --- a/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs +++ b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs @@ -32,7 +32,7 @@ fn foo() { fn bar() { // Original borrow ends at end of closure - || { + |&:| { let mut x = 1u; let y = &mut x; let z = &mut x; //~ ERROR cannot borrow diff --git a/src/test/compile-fail/break-outside-loop.rs b/src/test/compile-fail/break-outside-loop.rs index d72398a6ac5..1f257b8a5cb 100644 --- a/src/test/compile-fail/break-outside-loop.rs +++ b/src/test/compile-fail/break-outside-loop.rs @@ -14,7 +14,7 @@ struct Foo { fn cond() -> bool { true } -fn foo(_: ||) {} +fn foo(_: F) where F: FnOnce() {} fn main() { let pth = break; //~ ERROR: `break` outside of loop diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs index 1ff9dc9dac4..a02d6b7f517 100644 --- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct X { - field: ||:'static + Send, +struct X where F: FnOnce() + 'static + Send { + field: F, } -fn foo(blk: ||:'static) -> X { - return X { field: blk }; //~ ERROR expected bounds `Send` +fn foo(blk: F) -> X where F: FnOnce() + 'static { + //~^ ERROR the trait `core::kinds::Send` is not implemented for the type + return X { field: blk }; } fn main() { diff --git a/src/test/compile-fail/closure-bounds-not-builtin.rs b/src/test/compile-fail/closure-bounds-not-builtin.rs deleted file mode 100644 index 6b25e4be2d9..00000000000 --- a/src/test/compile-fail/closure-bounds-not-builtin.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -trait Foo {} - -fn take(f: ||:Foo) { - //~^ ERROR only the builtin traits can be used as closure or object bounds -} - -fn main() {} diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs index 6769740294b..d27529bad43 100644 --- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn bar(blk: ||:'static) { +fn bar(blk: F) where F: FnOnce() + 'static { } fn foo(x: &()) { bar(|| { //~ ERROR cannot infer an appropriate lifetime let _ = x; - //~^ ERROR captured variable `x` does not outlive }) } diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index 5bd9f20dd83..509fffc5c9a 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -9,19 +9,19 @@ // except according to those terms. -fn take_any(_: ||) { +fn take_any(_: F) where F: FnOnce() { } -fn take_const_owned(_: ||:Sync+Send) { +fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { } -fn give_any(f: ||) { +fn give_any(f: F) where F: FnOnce() { take_any(f); } -fn give_owned(f: ||:Send) { +fn give_owned(f: F) where F: FnOnce() + Send { take_any(f); - take_const_owned(f); //~ ERROR expected bounds `Send+Sync`, found bounds `Send` + take_const_owned(f); //~ ERROR the trait `core::kinds::Sync` is not implemented for the type } fn main() {} diff --git a/src/test/compile-fail/closure-reform-bad.rs b/src/test/compile-fail/closure-reform-bad.rs index 1e1889c7339..ef01c96adde 100644 --- a/src/test/compile-fail/closure-reform-bad.rs +++ b/src/test/compile-fail/closure-reform-bad.rs @@ -17,7 +17,7 @@ fn call_bare(f: fn(&str)) { fn main() { let string = "world!"; - let f: |&str| = |s| println!("{}{}", s, string); + let f = |&: s: &str| println!("{}{}", s, string); call_bare(f) //~ ERROR mismatched types } diff --git a/src/test/compile-fail/closure-that-fails.rs b/src/test/compile-fail/closure-that-fails.rs deleted file mode 100644 index 7a1ebed0a82..00000000000 --- a/src/test/compile-fail/closure-that-fails.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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 foo(f: || -> !) {} - -fn main() { - // Type inference didn't use to be able to handle this: - foo(|| panic!()); - foo(|| -> ! panic!()); - foo(|| 22i); //~ ERROR computation may converge in a function marked as diverging - foo(|| -> ! 22i); //~ ERROR computation may converge in a function marked as diverging - let x = || -> ! 1i; //~ ERROR computation may converge in a function marked as diverging -} diff --git a/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs b/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs deleted file mode 100644 index 52f4c4749e2..00000000000 --- a/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 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 coercions from fn item types are ok, but not fn pointer -// types to closures/procs are not allowed. - -fn foo() {} - -fn fn_item_type() { - let f = foo; - - let f_closure: || = f; -} - -fn fn_pointer_type() { - let f = foo as fn(); - let f_closure: || = f; - //~^ ERROR: mismatched types -} - -fn main() { } diff --git a/src/test/compile-fail/dead-code-closure-bang.rs b/src/test/compile-fail/dead-code-closure-bang.rs index 0aa3c40fa5f..46f5f41d728 100644 --- a/src/test/compile-fail/dead-code-closure-bang.rs +++ b/src/test/compile-fail/dead-code-closure-bang.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-test FIXME(#20574) + #![deny(unreachable_code)] fn main() { - let x: || -> ! = || panic!(); + let x = |:| panic!(); x(); std::io::println("Foo bar"); //~ ERROR: unreachable statement } diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index 6b01b83db21..d7586af291e 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -11,8 +11,10 @@ extern fn f() { } +fn is_fn(_: F) where F: Fn() {} + fn main() { // extern functions are extern "C" fn let _x: extern "C" fn() = f; // OK - let _x: || = f; //~ ERROR mismatched types + is_fn(f); //~ ERROR the trait `core::ops::Fn()` is not implemented for the type `extern "C" fn() } diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs index 2277f7080af..039628b6752 100644 --- a/src/test/compile-fail/fn-variance-1.rs +++ b/src/test/compile-fail/fn-variance-1.rs @@ -12,7 +12,7 @@ fn takes_imm(x: &int) { } fn takes_mut(x: &mut int) { } -fn apply(t: T, f: |T|) { +fn apply(t: T, f: F) where F: FnOnce(T) { f(t) } diff --git a/src/test/compile-fail/immut-function-arguments.rs b/src/test/compile-fail/immut-function-arguments.rs index 71328acdd70..827e648cca8 100644 --- a/src/test/compile-fail/immut-function-arguments.rs +++ b/src/test/compile-fail/immut-function-arguments.rs @@ -14,7 +14,7 @@ fn f(y: Box) { } fn g() { - let _frob: |Box| = |q| { *q = 2; }; //~ ERROR cannot assign + let _frob = |&: q: Box| { *q = 2; }; //~ ERROR cannot assign } diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 924132c6de2..dec4fc3b8f5 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -9,7 +9,7 @@ // except according to those terms. fn test<'x>(x: &'x int) { - drop::< for<'z>|&'z int| -> &'z int >(|z| { + drop:: FnMut(&'z int) -> &'z int>>(box |z| { x //~^ ERROR cannot infer an appropriate lifetime }); diff --git a/src/test/compile-fail/issue-11192.rs b/src/test/compile-fail/issue-11192.rs index 18a00d15eaf..f496c1e1227 100644 --- a/src/test/compile-fail/issue-11192.rs +++ b/src/test/compile-fail/issue-11192.rs @@ -20,7 +20,7 @@ fn drop(&mut self) { fn main() { let mut ptr = box Foo { x: 0 }; - let test = |foo: &Foo| { + let mut test = |&mut: foo: &Foo| { println!("access {}", foo.x); ptr = box Foo { x: ptr.x + 1 }; println!("access {}", foo.x); diff --git a/src/test/compile-fail/issue-11873.rs b/src/test/compile-fail/issue-11873.rs index e1acab4008a..89667937531 100644 --- a/src/test/compile-fail/issue-11873.rs +++ b/src/test/compile-fail/issue-11873.rs @@ -10,7 +10,7 @@ fn main() { let mut v = vec!(1i); - let f = || v.push(2i); + let mut f = |&mut:| v.push(2i); let _w = v; //~ ERROR: cannot move out of `v` f(); diff --git a/src/test/compile-fail/issue-14182.rs b/src/test/compile-fail/issue-14182.rs index 24256e31118..5033576a234 100644 --- a/src/test/compile-fail/issue-14182.rs +++ b/src/test/compile-fail/issue-14182.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-test FIXME(japari) remove test + struct Foo { f: for <'b> |&'b int|: 'b -> &'b int //~ ERROR use of undeclared lifetime name `'b` diff --git a/src/test/compile-fail/issue-16939.rs b/src/test/compile-fail/issue-16939.rs index 7ec3fef5c87..9d2212b69ce 100644 --- a/src/test/compile-fail/issue-16939.rs +++ b/src/test/compile-fail/issue-16939.rs @@ -14,7 +14,7 @@ // wrong arity. fn _foo (f: F) { - |t| f(t); //~ ERROR E0057 + |&: t| f(t); //~ ERROR E0057 } fn main() {} diff --git a/src/test/compile-fail/issue-17636.rs b/src/test/compile-fail/issue-17636.rs deleted file mode 100644 index ad2ebff59bc..00000000000 --- a/src/test/compile-fail/issue-17636.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -trait MyItem {} -impl MyItem for T {} - -pub fn build_archive<'a, I: MyItem<&'a (|&uint|:'a)>>(files: I) {} - -fn main() { - build_archive(&(|_| { })); -//~^ ERROR not implemented -} diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index ab396edddf4..970b14c7eb7 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -12,7 +12,7 @@ // and rejected. fn main() { - (|| box *[0u].as_slice())(); + (|&:| box *[0u].as_slice())(); //~^ ERROR cannot move out of dereference //~^^ ERROR cannot move a value of type [uint] } diff --git a/src/test/compile-fail/issue-17904.rs b/src/test/compile-fail/issue-17904.rs new file mode 100644 index 00000000000..96ba712bbae --- /dev/null +++ b/src/test/compile-fail/issue-17904.rs @@ -0,0 +1,17 @@ +// Copyright 2014 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 Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. +struct Baz where U: Eq(U) -> R; // Notice this parses as well. +struct Baz(U) where U: Eq; // This rightfully signals no error as well. +struct Foo where T: Copy, (T); //~ ERROR unexpected token in `where` clause +struct Bar { x: T } where T: Copy //~ ERROR expected item, found `where` + +fn main() {} diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 1608d2137fc..f87a0d774fa 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Obj<'a> { - closure: ||: 'a -> u32 +struct Obj where F: FnMut() -> u32 { + closure: F, } fn main() { let o = Obj { closure: || 42 }; - o.closure(); //~ ERROR type `Obj<'_>` does not implement any method in scope named `closure` + o.closure(); //~ ERROR does not implement any method in scope named `closure` //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field } diff --git a/src/test/compile-fail/issue-18345.rs b/src/test/compile-fail/issue-18345.rs deleted file mode 100644 index e93acb3f064..00000000000 --- a/src/test/compile-fail/issue-18345.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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. - -type Step<'s, R, T> = |R, T|: 's -> R; -type Transducer<'t, R, T, U> = |Step<'t, R, U>|: 't -> Step<'t, R, T>; - -fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> { - |step| |r, x| - step(r, f(x)) - //~^ ERROR the type of this value must be known in this context -} - -fn main() {} diff --git a/src/test/compile-fail/issue-18783.rs b/src/test/compile-fail/issue-18783.rs index 8097d93ca07..3a0fbddf818 100644 --- a/src/test/compile-fail/issue-18783.rs +++ b/src/test/compile-fail/issue-18783.rs @@ -13,8 +13,8 @@ fn main() { let c = RefCell::new(vec![]); let mut y = 1u; - c.push(|| y = 0); - c.push(|| y = 0); + c.push(box || y = 0); + c.push(box || y = 0); //~^ ERROR cannot borrow `y` as mutable more than once at a time } @@ -22,16 +22,16 @@ fn ufcs() { let c = RefCell::new(vec![]); let mut y = 1u; - Push::push(&c, || y = 0); - Push::push(&c, || y = 0); + Push::push(&c, box || y = 0); + Push::push(&c, box || y = 0); } trait Push<'c> { - fn push<'f: 'c>(&self, push: ||:'f -> ()); + fn push<'f: 'c>(&self, push: Box); } -impl<'c> Push<'c> for RefCell> { - fn push<'f: 'c>(&self, fun: ||:'f -> ()) { +impl<'c> Push<'c> for RefCell>> { + fn push<'f: 'c>(&self, fun: Box) { self.borrow_mut().push(fun) } } diff --git a/src/test/compile-fail/issue-19009.rs b/src/test/compile-fail/issue-19009.rs deleted file mode 100644 index aa7c4c3060b..00000000000 --- a/src/test/compile-fail/issue-19009.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 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. - -#![feature(lang_items)] -#![no_std] -#![crate_type="rlib"] -#[lang="sized"] pub trait Sized for Sized? {} - -fn ice(f: for <'s> || - :'s //~ ERROR use of undeclared lifetime name `'s` -) {} -fn main() { ice(||{}) } diff --git a/src/test/compile-fail/issue-19141.rs b/src/test/compile-fail/issue-19141.rs deleted file mode 100644 index 545e3f8acb1..00000000000 --- a/src/test/compile-fail/issue-19141.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2014 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 n = 0u; - - let f = move || n += 1; //~error boxed closures can't capture by value -} diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 4069ea6b997..7794c34a04b 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -12,7 +12,7 @@ fn akemi(homura: Homura) { let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method - madoka.clone(); //~ ERROR the type of this value must be known + madoka.clone(); } fn main() { } diff --git a/src/test/compile-fail/issue-20193.rs b/src/test/compile-fail/issue-20193.rs deleted file mode 100644 index e5d8d332719..00000000000 --- a/src/test/compile-fail/issue-20193.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 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 foo(t: &mut int){ - println!("{}", t); -} - -fn main() { - let test = 10; - - let h = move || { //~error boxed closures can't capture by value - let mut r = &mut test.clone(); - foo(r); - }; - - h(); -} diff --git a/src/test/compile-fail/issue-20228-1.rs b/src/test/compile-fail/issue-20228-1.rs deleted file mode 100644 index 3ff4557ae80..00000000000 --- a/src/test/compile-fail/issue-20228-1.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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; - -impl S { - fn foo(&self) { - let _ = move || { self }; //~error boxed closures can't capture by value - } -} - -fn main() { -} diff --git a/src/test/compile-fail/issue-20228-2.rs b/src/test/compile-fail/issue-20228-2.rs deleted file mode 100644 index 5fec4268bf7..00000000000 --- a/src/test/compile-fail/issue-20228-2.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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; - -impl S { - fn foo(&self) { - let _ = move || { self.foo() }; //~error boxed closures can't capture by value - } -} - -fn main() { -} diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index b688cafb674..691660f8971 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -9,17 +9,17 @@ // except according to those terms. trait vec_monad { - fn bind(&self, f: |A| -> Vec ); + fn bind(&self, f: F) where F: FnMut(A) -> Vec; } impl vec_monad for Vec { - fn bind(&self, f: |A| -> Vec ) { + fn bind(&self, mut f: F) where F: FnMut(A) -> Vec { let mut r = panic!(); for elt in self.iter() { r = r + f(*elt); } //~^ ERROR the type of this value must be known } } fn main() { - ["hi"].bind(|x| [x] ); + ["hi"].bind(|&mut: x| [x] ); //~^ ERROR type `[&str; 1]` does not implement any method in scope named `bind` } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index 0f7cc2cb72b..c67d6b1ce8f 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -11,7 +11,7 @@ fn main() { let needlesArr: Vec = vec!('a', 'f'); - needlesArr.iter().fold(|x, y| { + needlesArr.iter().fold(|&: x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied // diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 38f28bd79df..86ab9be77fc 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -9,8 +9,9 @@ // except according to those terms. trait A { - fn a(&self) { - || self.b() //~ ERROR type `&Self` does not implement any method in scope named `b` - } + fn a(&self) { + |&:| self.b() //~ ERROR type `&Self` does not implement any method in scope named `b` + //~^ ERROR expected (), found closure + } } fn main() {} diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index eadd16348b2..d4f9ea5b276 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + fn id(t: T) -> T { t } -fn f<'r, T>(v: &'r T) -> ||: 'r -> T { - id(|| *v) //~ ERROR cannot infer +fn f<'r, T>(v: &'r T) -> Box T + 'r> { + id(box |&mut:| *v) //~ ERROR cannot infer } fn main() { let v = &5i; - println!("{}", f(v)()); + println!("{}", f(v).call_mut(())); } diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs deleted file mode 100644 index 5063a78e383..00000000000 --- a/src/test/compile-fail/issue-4523.rs +++ /dev/null @@ -1,17 +0,0 @@ -// 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 foopy() {} - -static f: ||: 'static = foopy; - -fn main () { - f(); //~ ERROR closure invocation in a static location -} diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs index 18af9736ed9..fef414ce978 100644 --- a/src/test/compile-fail/issue-5216.rs +++ b/src/test/compile-fail/issue-5216.rs @@ -9,12 +9,12 @@ // except according to those terms. fn f() { } -struct S(||); //~ ERROR explicit lifetime bound required +struct S(Box); //~ ERROR explicit lifetime bound required pub static C: S = S(f); fn g() { } -type T = ||; //~ ERROR explicit lifetime bound required +type T = Box; //~ ERROR explicit lifetime bound required pub static D: T = g; fn main() {} diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 88b08655caa..1691688fd84 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -11,6 +11,6 @@ // Regression test for issue #5239 fn main() { - let x: |int| -> int = |ref x| { x += 1; }; + let x = |&: ref x: int| -> int { x += 1; }; //~^ ERROR binary assignment operation `+=` cannot be applied to type `&int` } diff --git a/src/test/compile-fail/issue-6801.rs b/src/test/compile-fail/issue-6801.rs index 5925f686939..433ae3bf89e 100644 --- a/src/test/compile-fail/issue-6801.rs +++ b/src/test/compile-fail/issue-6801.rs @@ -17,13 +17,13 @@ fn twice(x: Box) -> uint { *x * 2 } -fn invoke(f: || -> uint) { +fn invoke(f: F) where F: FnOnce() -> uint { f(); } fn main() { let x : Box = box 9; - let sq : || -> uint = || { *x * *x }; + let sq = |:| { *x * *x }; twice(x); //~ ERROR: cannot move out of invoke(sq); diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index 0e978a09edd..897afb1c102 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -25,7 +25,7 @@ fn new(s: &str) -> CrateId { pub fn remove_package_from_database() { let mut lines_to_use: Vec<&CrateId> = Vec::new(); - let push_id = |installed_id: &CrateId| { + let push_id = |&mut: installed_id: &CrateId| { lines_to_use.push(installed_id); //~^ ERROR cannot infer an appropriate lifetime for automatic coercion due to // conflicting requirements @@ -38,7 +38,7 @@ pub fn remove_package_from_database() { } -pub fn list_database(f: |&CrateId|) { +pub fn list_database(mut f: F) where F: FnMut(&CrateId) { let stuff = ["foo", "bar"]; for l in stuff.iter() { diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 8868c7f8256..b5725249812 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -57,9 +57,6 @@ fn test<'a,T,U:Copy>(_: &'a int) { // mutable object types are not ok assert_copy::<&'a mut (Dummy+Copy)>(); //~ ERROR `core::kinds::Copy` is not implemented - // closures are like an `&mut` object - assert_copy::<||>(); //~ ERROR `core::kinds::Copy` is not implemented - // unsafe ptrs are ok assert_copy::<*const int>(); assert_copy::<*const &'a mut int>(); diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index f5740992af4..d66fd0d77d6 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -11,7 +11,6 @@ // Test that Copy bounds inherited by trait are checked. use std::any::Any; -use std::any::AnyRefExt; trait Foo : Copy { } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index 3b67e98f42c..c300096caf1 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -27,14 +27,9 @@ fn box_object_with_no_bound_not_ok<'a>() { assert_send::>(); //~ ERROR the trait `core::kinds::Send` is not implemented } -fn closure_with_no_bound_not_ok<'a>() { - assert_send::<||:'static>(); //~ ERROR the trait `core::kinds::Send` is not implemented -} - fn object_with_send_bound_ok() { assert_send::<&'static (Dummy+Send)>(); assert_send::>(); - assert_send::<||:Send>; } fn main() { } diff --git a/src/test/compile-fail/lint-raw-ptr-derive.rs b/src/test/compile-fail/lint-raw-ptr-derive.rs new file mode 100644 index 00000000000..3198e782df8 --- /dev/null +++ b/src/test/compile-fail/lint-raw-ptr-derive.rs @@ -0,0 +1,34 @@ +// 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. + +#![allow(dead_code)] +#![deny(raw_pointer_derive)] + +#[derive(Clone)] +struct Foo { + x: *const int //~ ERROR use of `#[derive]` with a raw pointer +} + +#[derive(Clone)] +struct Bar(*mut int); //~ ERROR use of `#[derive]` with a raw pointer + +#[derive(Clone)] +enum Baz { + A(*const int), //~ ERROR use of `#[derive]` with a raw pointer + B { x: *mut int } //~ ERROR use of `#[derive]` with a raw pointer +} + +#[derive(Clone)] +struct Buzz { + x: (*const int, //~ ERROR use of `#[derive]` with a raw pointer + *const uint) //~ ERROR use of `#[derive]` with a raw pointer +} + +fn main() {} diff --git a/src/test/compile-fail/lint-raw-ptr-deriving.rs b/src/test/compile-fail/lint-raw-ptr-deriving.rs deleted file mode 100644 index 6fe8862d77e..00000000000 --- a/src/test/compile-fail/lint-raw-ptr-deriving.rs +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -#![allow(dead_code)] -#![deny(raw_pointer_deriving)] - -#[derive(Clone)] -struct Foo { - x: *const int //~ ERROR use of `#[derive]` with a raw pointer -} - -#[derive(Clone)] -struct Bar(*mut int); //~ ERROR use of `#[derive]` with a raw pointer - -#[derive(Clone)] -enum Baz { - A(*const int), //~ ERROR use of `#[derive]` with a raw pointer - B { x: *mut int } //~ ERROR use of `#[derive]` with a raw pointer -} - -#[derive(Clone)] -struct Buzz { - x: (*const int, //~ ERROR use of `#[derive]` with a raw pointer - *const uint) //~ ERROR use of `#[derive]` with a raw pointer -} - -fn main() {} diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index 29b4686198b..7513e1bc21a 100644 --- a/src/test/compile-fail/lint-unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs @@ -35,7 +35,7 @@ fn main() { _ => {} } - let x = |mut y: int| 10i; //~ ERROR: variable does not need to be mutable + let x = |&: mut y: int| 10i; //~ ERROR: variable does not need to be mutable fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable // positive cases @@ -65,7 +65,7 @@ fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable _ => {} } - let x = |mut y: int| y = 32i; + let x = |&mut: mut y: int| y = 32i; fn nothing(mut foo: int) { foo = 37i; } // leading underscore should avoid the warning, just like the @@ -73,7 +73,7 @@ fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable let mut _allowed = 1i; } -fn callback(f: ||) {} +fn callback(f: F) where F: FnOnce() {} // make sure the lint attribute can be turned off #[allow(unused_mut)] diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/compile-fail/lint-unused-unsafe.rs index df3feefa881..5c8e73e6747 100644 --- a/src/test/compile-fail/lint-unused-unsafe.rs +++ b/src/test/compile-fail/lint-unused-unsafe.rs @@ -20,7 +20,7 @@ mod foo { } } -fn callback(_f: || -> T) -> T { panic!() } +fn callback(_f: F) -> T where F: FnOnce() -> T { panic!() } unsafe fn unsf() {} fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block diff --git a/src/test/compile-fail/liveness-closure-require-ret.rs b/src/test/compile-fail/liveness-closure-require-ret.rs index 6466310eb4d..82de02f0981 100644 --- a/src/test/compile-fail/liveness-closure-require-ret.rs +++ b/src/test/compile-fail/liveness-closure-require-ret.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn force(f: || -> int) -> int { f() } +fn force(f: F) -> int where F: FnOnce() -> int { f() } fn main() { println!("{}", force(|| {})); } //~ ERROR mismatched types 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 ee57377943d..14af49dfc49 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 @@ -20,7 +20,7 @@ enum E { Baz } -fn f(s: &S, g: |&S|) { +fn f(s: &S, g: G) where G: FnOnce(&S) { g(s) } 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 f9614574abd..ab762332ee4 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 @@ -14,5 +14,5 @@ fn test(_x: Box) {} fn main() { let i = box 3; - let _f = || test(i); //~ ERROR cannot move out + let _f = |&:| test(i); //~ ERROR cannot move out } diff --git a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs index 2a73b769895..9053f97e8a7 100644 --- a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs @@ -12,11 +12,13 @@ // bound must be noncopyable. For details see // http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ +#![feature(unboxed_closures)] + struct R<'a> { // This struct is needed to create the // otherwise infinite type of a fn that // accepts itself as argument: - c: |&mut R, bool|: 'a + c: Box } fn innocent_looking_victim() { @@ -28,7 +30,7 @@ fn innocent_looking_victim() { match x { Some(ref msg) => { (f.c)(f, true); - //~^ ERROR: cannot borrow `*f` as mutable because + //~^ ERROR: cannot borrow `*f` as mutable more than once at a time println!("{}", msg); }, None => panic!("oops"), @@ -37,8 +39,8 @@ fn innocent_looking_victim() { }) } -fn conspirator(f: |&mut R, bool|) { - let mut r = R {c: f}; +fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { + let mut r = R {c: box f}; f(&mut r, false) //~ ERROR use of moved value } diff --git a/src/test/compile-fail/pptypedef.rs b/src/test/compile-fail/pptypedef.rs index 4de56e32f56..ebda4e9103d 100644 --- a/src/test/compile-fail/pptypedef.rs +++ b/src/test/compile-fail/pptypedef.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn let_in(x: T, f: |T|) {} +fn let_in(x: T, f: F) where F: FnOnce(T) {} fn main() { let_in(3u, |i| { assert!(i == 3i); }); 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 954d4b23e30..575e9864a92 100644 --- a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs +++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let f = |3: int| println!("hello"); + let f = |&: 3: int| println!("hello"); //~^ ERROR refutable pattern in function argument: `_` not covered f(4); } diff --git a/src/test/compile-fail/region-bound-on-closure-outlives-call.rs b/src/test/compile-fail/region-bound-on-closure-outlives-call.rs index 13ab7acaf48..9e8281faf2f 100644 --- a/src/test/compile-fail/region-bound-on-closure-outlives-call.rs +++ b/src/test/compile-fail/region-bound-on-closure-outlives-call.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn call_rec(f: |uint| -> uint) -> uint { - (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` +fn call_rec(mut f: F) -> uint where F: FnMut(uint) -> uint { + (|&mut: x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` } fn main() {} diff --git a/src/test/compile-fail/regionck-closure-lifetimes.rs b/src/test/compile-fail/regionck-closure-lifetimes.rs deleted file mode 100644 index bb895a318ff..00000000000 --- a/src/test/compile-fail/regionck-closure-lifetimes.rs +++ /dev/null @@ -1,60 +0,0 @@ -// 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 env<'a>(blk: |p: ||: 'a|) { - // Test that the closure here cannot be assigned - // the lifetime `'a`, which outlives the current - // block. - - let mut state = 0i; - let statep = &mut state; - blk(|| *statep = 1i); //~ ERROR captured variable `statep` does not outlive -} - -fn no_env_no_for<'a>(blk: |p: |||: 'a) { - // Test that a closure with no free variables CAN - // outlive the block in which it is created. - - blk(|| ()) -} - -fn repeating_loop() { - // Test that the closure cannot be created within `loop` loop and - // called without, even though the state that it closes over is - // external to the loop. - - let closure; - let state = 0i; - - loop { - closure = || state; //~ ERROR cannot infer - break; - } - - closure(); -} - -fn repeating_while() { - // Test that the closure cannot be created within `while` loop and - // called without, even though the state that it closes over is - // external to the loop. - - let closure; - let state = 0i; - - while true { - closure = || state; //~ ERROR cannot infer - break; - } - - closure(); -} - -fn main() {} diff --git a/src/test/compile-fail/regions-addr-of-upvar-self.rs b/src/test/compile-fail/regions-addr-of-upvar-self.rs index 7a146c043c8..fb60d8f7b27 100644 --- a/src/test/compile-fail/regions-addr-of-upvar-self.rs +++ b/src/test/compile-fail/regions-addr-of-upvar-self.rs @@ -16,7 +16,7 @@ struct dog { impl dog { pub fn chase_cat(&mut self) { - let _f = || { + let _f = |&:| { let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer *p = 3u; }; diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index e15cb25295a..0628bbb8bb0 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -69,11 +69,6 @@ fn object_with_send_bound_not_ok<'a>() { //~^ ERROR declared lifetime bound not satisfied } -fn closure_with_lifetime_not_ok<'a>() { - assert_send::<||:'a>(); - //~^ ERROR not implemented -} - // unsafe pointers are ok unless they point at unsendable things struct UniqueUnsafePtr(Unique<*const int>); diff --git a/src/test/compile-fail/regions-close-associated-type-into-object.rs b/src/test/compile-fail/regions-close-associated-type-into-object.rs new file mode 100644 index 00000000000..84664078d56 --- /dev/null +++ b/src/test/compile-fail/regions-close-associated-type-into-object.rs @@ -0,0 +1,83 @@ +// Copyright 2014 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. + +#![feature(associated_types)] + +trait X {} + +trait Iter { + type Item: X; + + fn into_item(self) -> Self::Item; + fn as_item(&self) -> &Self::Item; +} + +fn bad1(v: T) -> Box +{ + let item = v.into_item(); + box item //~ ERROR associated type `::Item` may not live long enough +} + +fn bad2(v: T) -> Box + where Box : X +{ + let item = box v.into_item(); + box item //~ ERROR associated type `::Item` may not live long enough +} + +fn bad3<'a, T: Iter>(v: T) -> Box +{ + let item = v.into_item(); + box item //~ ERROR associated type `::Item` may not live long enough +} + +fn bad4<'a, T: Iter>(v: T) -> Box + where Box : X +{ + let item = box v.into_item(); + box item //~ ERROR associated type `::Item` may not live long enough +} + +fn ok1<'a, T: Iter>(v: T) -> Box + where T::Item : 'a +{ + let item = v.into_item(); + box item // OK, T::Item : 'a is declared +} + +fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box + where T::Item : Clone +{ + let item = Clone::clone(w); + box item // OK, T::Item : 'a is implied +} + +fn ok3<'a, T: Iter>(v: &'a T) -> Box + where T::Item : Clone + 'a +{ + let item = Clone::clone(v.as_item()); + box item // OK, T::Item : 'a was declared +} + +fn meh1<'a, T: Iter>(v: &'a T) -> Box + where T::Item : Clone +{ + // This case is kind of interesting. It's the same as `ok3` but + // without the explicit declaration. In principle, it seems like + // we ought to be able to infer that `T::Item : 'a` because we + // invoked `v.as_self()` which yielded a value of type `&'a + // T::Item`. But we're not that smart at present. + + let item = Clone::clone(v.as_item()); + box item //~ ERROR associated type `::Item` may not live +} + +fn main() {} + diff --git a/src/test/compile-fail/regions-close-param-into-object.rs b/src/test/compile-fail/regions-close-param-into-object.rs new file mode 100644 index 00000000000..3e91d090c31 --- /dev/null +++ b/src/test/compile-fail/regions-close-param-into-object.rs @@ -0,0 +1,39 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +trait X {} + +fn p1(v: T) -> Box + where T : X +{ + box v //~ ERROR parameter type `T` may not live long enough +} + +fn p2(v: Box) -> Box + where Box : X +{ + box v //~ ERROR parameter type `T` may not live long enough +} + +fn p3<'a,T>(v: T) -> Box + where T : X +{ + box v //~ ERROR parameter type `T` may not live long enough +} + +fn p4<'a,T>(v: Box) -> Box + where Box : X +{ + box v //~ ERROR parameter type `T` may not live long enough +} + +fn main() {} + diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index b15f0405d23..1774c9fada9 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -27,14 +27,14 @@ fn compute(x: &ast) -> uint { } } -fn map_nums<'a,'b>(x: &ast, f: |uint| -> uint) -> &'a ast<'b> { +fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(uint) -> uint { match *x { ast::num(x) => { - return &ast::num(f(x)); //~ ERROR borrowed value does not live long enough + return &ast::num((*f)(x)); //~ ERROR borrowed value does not live long enough } ast::add(x, y) => { - let m_x = map_nums(x, |z| f(z)); - let m_y = map_nums(y, |z| f(z)); + let m_x = map_nums(x, f); + let m_y = map_nums(y, f); return &ast::add(m_x, m_y); //~ ERROR borrowed value does not live long enough } } diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs index 66103eb9588..547accbf086 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn with_int(f: |x: &int|) { +fn with_int(f: F) where F: FnOnce(&int) { let x = 3; f(&x); } diff --git a/src/test/compile-fail/regions-escape-bound-fn.rs b/src/test/compile-fail/regions-escape-bound-fn.rs index fee84cf9656..6d67bd80650 100644 --- a/src/test/compile-fail/regions-escape-bound-fn.rs +++ b/src/test/compile-fail/regions-escape-bound-fn.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn with_int(f: |x: &int|) { +fn with_int(f: F) where F: FnOnce(&int) { let x = 3; f(&x); } diff --git a/src/test/compile-fail/regions-escape-method.rs b/src/test/compile-fail/regions-escape-method.rs index f92c264784a..e3771cfebba 100644 --- a/src/test/compile-fail/regions-escape-method.rs +++ b/src/test/compile-fail/regions-escape-method.rs @@ -16,7 +16,7 @@ struct S; impl S { - fn f(&self, _: |&i32| -> B) { + fn f(&self, _: F) where F: FnOnce(&i32) -> B { } } 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 adc960b069d..873d4cea039 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 @@ -20,7 +20,7 @@ fn get(self) -> int { } } -fn with(f: |x: &int| -> R) -> int { +fn with(f: F) -> int where F: FnOnce(&int) -> R { f(&3).get() } diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs deleted file mode 100644 index 91a6ff789ea..00000000000 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ /dev/null @@ -1,45 +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. - -fn of<'a,T>() -> |T|:'a { panic!(); } -fn subtype(x: |T|) { panic!(); } - -fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) { - // Here, x, y, and z are free. Other letters - // are bound. Note that the arrangement - // subtype::(of::()) will typecheck - // iff T1 <: T2. - - subtype::< for<'a>|&'a T|>( - of::< for<'a>|&'a T|>()); - - subtype::< for<'a>|&'a T|>( - of::< for<'b>|&'b T|>()); - - subtype::< for<'b>|&'b T|>( - of::<|&'x T|>()); - - subtype::<|&'x T|>( - of::< for<'b>|&'b T|>()); //~ ERROR mismatched types - - subtype::< for<'a,'b>|&'a T, &'b T|>( - of::< for<'a>|&'a T, &'a T|>()); - - subtype::< for<'a>|&'a T, &'a T|>( - of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types - - subtype::< for<'a,'b>|&'a T, &'b T|>( - of::<|&'x T, &'y T|>()); - - subtype::<|&'x T, &'y T|>( - of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types -} - -fn main() {} diff --git a/src/test/compile-fail/regions-fns.rs b/src/test/compile-fail/regions-fns.rs deleted file mode 100644 index 854584ec535..00000000000 --- a/src/test/compile-fail/regions-fns.rs +++ /dev/null @@ -1,21 +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. - -// Before fn subtyping was properly implemented, -// we reported errors in this case: - -fn not_ok<'b>(a: &uint, b: &'b uint) { - let mut g: |x: &uint| = |x: &'b uint| {}; - //~^ ERROR mismatched types - g(a); -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-free-region-ordering-callee.rs b/src/test/compile-fail/regions-free-region-ordering-callee.rs index 435d10a0a29..6e59a29b8cf 100644 --- a/src/test/compile-fail/regions-free-region-ordering-callee.rs +++ b/src/test/compile-fail/regions-free-region-ordering-callee.rs @@ -30,7 +30,7 @@ fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint { panic!(); } -fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: |&'a &'b uint|) { +fn ordering4<'a, 'b, F>(a: &'a uint, b: &'b uint, x: F) where F: FnOnce(&'a &'b uint) { // Do not infer ordering from closure argument types. let z: Option<&'a &'b uint> = None; //~^ ERROR reference has a longer lifetime than the data it references diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs deleted file mode 100644 index 76bbe71cf75..00000000000 --- a/src/test/compile-fail/regions-freevar.rs +++ /dev/null @@ -1,18 +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. - -fn wants_static_fn(_x: ||: 'static) {} - -fn main() { - let i = 3i; - wants_static_fn(|| { - println!("i={}", i); //~ ERROR captured variable `i` does not outlive - }) -} diff --git a/src/test/compile-fail/regions-infer-at-fn-not-param.rs b/src/test/compile-fail/regions-infer-at-fn-not-param.rs index 8af341e3ace..0c250e38258 100644 --- a/src/test/compile-fail/regions-infer-at-fn-not-param.rs +++ b/src/test/compile-fail/regions-infer-at-fn-not-param.rs @@ -9,15 +9,15 @@ // except according to those terms. struct parameterized1<'a> { - g: ||: 'a + g: Box } struct not_parameterized1 { - g: ||: 'static + g: Box } struct not_parameterized2 { - g: ||: 'static + g: Box } fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p } 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 cf1fa2cfc4c..c8edd936bf2 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 @@ -11,7 +11,10 @@ fn borrow(x: &T) -> &T {x} -fn foo(cond: || -> bool, make_box: || -> Box) { +fn foo(mut cond: C, mut make_box: M) where + C: FnMut() -> bool, + M: FnMut() -> Box, +{ let mut y: ∫ loop { let x = make_box(); diff --git a/src/test/compile-fail/regions-infer-call-3.rs b/src/test/compile-fail/regions-infer-call-3.rs index 66f958c7893..ac41f2a5b3e 100644 --- a/src/test/compile-fail/regions-infer-call-3.rs +++ b/src/test/compile-fail/regions-infer-call-3.rs @@ -10,7 +10,7 @@ fn select<'r>(x: &'r int, y: &'r int) -> &'r int { x } -fn with(f: |x: &int| -> T) -> T { +fn with(f: F) -> T where F: FnOnce(&int) -> T { f(&20) } diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs index 33573cae0f6..190e444fe7e 100644 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs +++ b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs @@ -10,7 +10,7 @@ struct invariant<'a> { - f: |x: &mut &'a int|: 'static + f: Box, } fn to_same_lifetime<'r>(bi: invariant<'r>) { diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs index 66dcb5fdebd..71d0c988c5e 100644 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs +++ b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs @@ -10,7 +10,7 @@ struct invariant<'a> { - f: ||: 'static -> &mut &'a int + f: Box FnOnce() -> &'b mut &'a int + 'static>, } fn to_same_lifetime<'r>(bi: invariant<'r>) { diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index b84f13ec37f..323ebc3c20b 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -14,12 +14,12 @@ struct direct<'a> { struct indirect1 { // Here the lifetime parameter of direct is bound by the fn() - g: |direct|: 'static + g: Box } struct indirect2<'a> { // But here it is set to 'a - g: |direct<'a>|: 'static + g: Box) + 'static> } fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types diff --git a/src/test/compile-fail/regions-name-undeclared.rs b/src/test/compile-fail/regions-name-undeclared.rs index ffd1501075e..b9c721159f2 100644 --- a/src/test/compile-fail/regions-name-undeclared.rs +++ b/src/test/compile-fail/regions-name-undeclared.rs @@ -43,19 +43,16 @@ fn f(a: &'a int) { } //~ ERROR undeclared lifetime // &'a CAN be declared on functions and used then: fn g<'a>(a: &'a int) { } // OK - fn h(a: for<'a>|&'a int|) { } // OK - - // But not in the bound of a closure, it's not in scope *there* - fn i(a: for<'a>|&int|:'a) { } //~ ERROR undeclared lifetime + fn h(a: Box FnOnce(&'a int)>) { } // OK } // Test nesting of lifetimes in fn type declarations fn fn_types(a: &'a int, //~ ERROR undeclared lifetime - b: for<'a>|a: &'a int, - b: &'b int, //~ ERROR undeclared lifetime - c: for<'b>|a: &'a int, - b: &'b int|, - d: &'b int|, //~ ERROR undeclared lifetime + b: Box FnOnce(&'a int, + &'b int, //~ ERROR undeclared lifetime + Box FnOnce(&'a int, + &'b int)>, + &'b int)>, //~ ERROR undeclared lifetime c: &'a int) //~ ERROR undeclared lifetime { } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index a08cf226389..b7fe893a1f5 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn ignore(_f: for<'z>|&'z int| -> &'z int) {} +fn ignore(_f: F) where F: for<'z> FnOnce(&'z int) -> &'z int {} fn nested() { let y = 3; diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index f4654367970..5d8ef718ef0 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -14,13 +14,13 @@ fn nested<'x>(x: &'x int) { let y = 3; let mut ay = &y; - ignore::< for<'z>|&'z int|>(|z| { + ignore:: FnMut(&'z int)>>(box |z| { ay = x; //~ ERROR cannot infer ay = &y; ay = z; }); - ignore::< for<'z>|&'z int| -> &'z int>(|z| { + ignore::< Box FnMut(&'z int) -> &'z int>>(box |z| { if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return ay; } return z; diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs new file mode 100644 index 00000000000..3f722c9433b --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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 assert_send(_t: T) {} + +fn main() { + let line = String::new(); + match [line.as_slice()] { //~ ERROR `line` does not live long enough + [ word ] => { assert_send(word); } + } +} diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19997.rs b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs new file mode 100644 index 00000000000..da839d72172 --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs @@ -0,0 +1,20 @@ +// Copyright 2014 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 a0 = 0u8; + let f = 1u8; + let mut a1 = &a0; + match (&a1,) { + (&ref b0,) => { + a1 = &f; //~ ERROR cannot assign + } + } +} diff --git a/src/test/compile-fail/regions-ref-in-fn-arg.rs b/src/test/compile-fail/regions-ref-in-fn-arg.rs index 47fca8bb8df..f9eecb60c6a 100644 --- a/src/test/compile-fail/regions-ref-in-fn-arg.rs +++ b/src/test/compile-fail/regions-ref-in-fn-arg.rs @@ -13,7 +13,7 @@ fn arg_item(box ref x: Box) -> &'static int { x //~^ ERROR borrowed value does not live long enough } -fn with(f: |Box| -> R) -> R { f(box 3) } +fn with(f: F) -> R where F: FnOnce(Box) -> R { f(box 3) } fn arg_closure() -> &'static int { with(|box ref x| x) //~ ERROR borrowed value does not live long enough diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 997775efa84..bd14d31217e 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -12,7 +12,7 @@ // some point regions-ret-borrowed reported an error but this file did // not, due to special hardcoding around the anonymous region. -fn with(f: for<'a>|x: &'a int| -> R) -> R { +fn with(f: F) -> R where F: for<'a> FnOnce(&'a int) -> R { f(&3) } diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index 465f4410fbb..4dfd4f1709a 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -15,7 +15,7 @@ // used to successfully compile because we failed to account for the // fact that fn(x: &int) rebound the region &. -fn with(f: |x: &int| -> R) -> R { +fn with(f: F) -> R where F: FnOnce(&int) -> R { f(&3) } diff --git a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs index aedaced5794..d7b2a45cc63 100644 --- a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs +++ b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs @@ -20,11 +20,4 @@ fn main() { let x = f(); let y = f(); } - // Boxed closure case - { - let mut x = 0u; - let f = || &mut x; //~ ERROR cannot infer - let x = f(); - let y = f(); - } } diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index 7ffc6a75cff..991040bc62f 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -8,18 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + struct closure_box<'a> { - cl: ||: 'a + cl: Box, } -fn box_it<'r>(x: ||: 'r) -> closure_box<'r> { +fn box_it<'r>(x: Box) -> closure_box<'r> { closure_box {cl: x} } fn main() { let cl_box = { - let mut i = 3; - box_it(|| i += 1) //~ ERROR cannot infer + let mut i = 3i; + box_it(box || i += 1) //~ ERROR cannot infer }; - (cl_box.cl)(); + cl_box.cl.call_mut(()); } diff --git a/src/test/compile-fail/syntax-trait-polarity-feature-gate.rs b/src/test/compile-fail/syntax-trait-polarity-feature-gate.rs new file mode 100644 index 00000000000..e6dc712137f --- /dev/null +++ b/src/test/compile-fail/syntax-trait-polarity-feature-gate.rs @@ -0,0 +1,20 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::kinds::Send; + +struct TestType; + +trait TestTrait {} + +unsafe impl !Send for TestType {} +//~^ ERROR negative trait bounds + +fn main() {} diff --git a/src/test/compile-fail/syntax-trait-polarity.rs b/src/test/compile-fail/syntax-trait-polarity.rs new file mode 100644 index 00000000000..3c84bc26298 --- /dev/null +++ b/src/test/compile-fail/syntax-trait-polarity.rs @@ -0,0 +1,33 @@ +// Copyright 2014 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. + +#![feature(optin_builtin_traits)] + +use std::kinds::Send; + +struct TestType; + +impl !TestType {} +//~^ ERROR inherent implementation can't be negated + +trait TestTrait {} + +unsafe impl !Send for TestType {} +impl !TestTrait for TestType {} + +struct TestType2; + +impl !TestType2 {} +//~^ ERROR inherent implementation can't be negated + +unsafe impl !Send for TestType2 {} +impl !TestTrait for TestType2 {} + +fn main() {} diff --git a/src/test/compile-fail/type-arg-out-of-scope.rs b/src/test/compile-fail/type-arg-out-of-scope.rs index ac2f9d0379f..3249794e5c8 100644 --- a/src/test/compile-fail/type-arg-out-of-scope.rs +++ b/src/test/compile-fail/type-arg-out-of-scope.rs @@ -10,6 +10,6 @@ // error-pattern:can't use type parameters from outer function; try using fn foo(x: T) { - fn bar(f: |T| -> T) { } + fn bar(f: Box T>) { } } fn main() { foo(1); } diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs index b3528f7abe7..61f13172832 100644 --- a/src/test/compile-fail/unboxed-closures-type-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs @@ -14,6 +14,6 @@ pub fn main() { let mut f = |&mut: x: int, y: int| -> int { x + y }; - let z = f.call_mut((1u, 2)); //~ ERROR type mismatch + let z = f(1u, 2); //~ ERROR mismatched types println!("{}", z); } diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs index a96bde7cca4..85b33f73bbc 100644 --- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -13,7 +13,7 @@ use std::ops::FnMut; fn call_it>(y: int, mut f: F) -> int { - f.call_mut((2, y)) + f(2, y) } pub fn main() { diff --git a/src/test/compile-fail/unsized.rs b/src/test/compile-fail/unsized.rs index 43db4dfd395..92dbea0424b 100644 --- a/src/test/compile-fail/unsized.rs +++ b/src/test/compile-fail/unsized.rs @@ -10,7 +10,7 @@ // Test syntax checks for `type` keyword. -struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name, found `for` +struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for` pub fn main() { } diff --git a/src/test/compile-fail/variance-trait-matching-2.rs b/src/test/compile-fail/variance-trait-matching-2.rs deleted file mode 100644 index cae7a4cefad..00000000000 --- a/src/test/compile-fail/variance-trait-matching-2.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 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 crate serialize; - -use std::fmt; -use serialize::{Encodable, Encoder}; - -pub fn buffer_encode<'a, - T:Encodable,fmt::Error>>( - to_encode_object: &T) - -> String { - let mut m = String::new(); - { - let mut encoder = - serialize::json::Encoder::new(&mut m); - //~^ ERROR `m` does not live long enough - to_encode_object.encode(&mut encoder); - } - m -} - -fn main() {} diff --git a/src/test/debuginfo/closure-in-generic-function.rs b/src/test/debuginfo/closure-in-generic-function.rs index 84366ae7114..e3cb190c3f2 100644 --- a/src/test/debuginfo/closure-in-generic-function.rs +++ b/src/test/debuginfo/closure-in-generic-function.rs @@ -50,7 +50,7 @@ fn some_generic_fun(a: T1, b: T2) -> (T2, T1) { - let closure = |x, y| { + let closure = |&: x, y| { zzz(); // #break (y, x) }; diff --git a/src/test/debuginfo/lexical-scope-in-parameterless-closure.rs b/src/test/debuginfo/lexical-scope-in-parameterless-closure.rs index b451f61d05e..b2617c57742 100644 --- a/src/test/debuginfo/lexical-scope-in-parameterless-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-parameterless-closure.rs @@ -18,7 +18,7 @@ // Nothing to do here really, just make sure it compiles. See issue #8513. fn main() { - let _ = ||(); + let _ = |&:|(); let _ = range(1u,3).map(|_| 5i); } diff --git a/src/test/debuginfo/lexical-scope-in-stack-closure.rs b/src/test/debuginfo/lexical-scope-in-stack-closure.rs index d6e3a43eea0..f2d09221669 100644 --- a/src/test/debuginfo/lexical-scope-in-stack-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-stack-closure.rs @@ -79,7 +79,7 @@ fn main() { zzz(); // #break sentinel(); - let stack_closure: |int| = |x| { + let closure = |&: x: int| { zzz(); // #break sentinel(); @@ -97,7 +97,7 @@ fn main() { zzz(); // #break sentinel(); - stack_closure(1000); + closure(1000); zzz(); // #break sentinel(); diff --git a/src/test/debuginfo/multi-byte-chars.rs b/src/test/debuginfo/multi-byte-chars.rs index dd0d86bf742..cb7e26327c3 100644 --- a/src/test/debuginfo/multi-byte-chars.rs +++ b/src/test/debuginfo/multi-byte-chars.rs @@ -24,5 +24,5 @@ struct C { θ: u8 } fn main() { let x = C { θ: 0 }; - (|c: C| c.θ )(x); + (|&: c: C| c.θ )(x); } diff --git a/src/test/debuginfo/recursive-enum.rs b/src/test/debuginfo/recursive-enum.rs index 93348e7b53e..73a68893e93 100644 --- a/src/test/debuginfo/recursive-enum.rs +++ b/src/test/debuginfo/recursive-enum.rs @@ -25,11 +25,9 @@ pub struct Window<'a> { } struct WindowCallbacks<'a> { - pos_callback: Option>, + pos_callback: Option>, } -pub type WindowPosCallback<'a> = |&Window, i32, i32|: 'a; - fn main() { let x = WindowCallbacks { pos_callback: None }; } diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index ddcbfdcceee..aac5824af00 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -167,11 +167,11 @@ // CLOSURES -// gdb-command:whatis stack_closure1 -// gdb-check:type = struct (&mut|int|, uint) +// gdb-command:whatis closure1 +// gdb-check:type = struct (closure, uint) -// gdb-command:whatis stack_closure2 -// gdb-check:type = struct (&mut|i8, f32| -> f32, uint) +// gdb-command:whatis closure2 +// gdb-check:type = struct (closure, uint) #![omit_gdb_pretty_printer_section] @@ -321,8 +321,8 @@ fn main() { // how that maps to rustc's internal representation of these forms. // Once closures have reached their 1.0 form, the tests below should // probably be expanded. - let stack_closure1 = (|x:int| {}, 0u); - let stack_closure2 = (|x:i8, y: f32| { (x as f32) + y }, 0u); + let closure1 = (|&: x:int| {}, 0u); + let closure2 = (|&: x:i8, y: f32| { (x as f32) + y }, 0u); zzz(); // #break } diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index 99d67c60516..3a7fbb9a3a1 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -100,10 +100,10 @@ fn main() { let struct_ref = &a_struct; let owned = box 6; - let closure = || { + let mut closure = |&mut:| { let closure_local = 8; - let nested_closure = || { + let mut nested_closure = |&mut:| { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned + closure_local; }; diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index f474e8d1317..a743adae51e 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -94,20 +94,20 @@ fn main() { let owned = box 6; { - let closure = || { + let mut first_closure = |&mut:| { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned; }; - closure(); + first_closure(); } { - let mut unboxed_closure = |&mut:| { + let mut second_closure = |&mut:| { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned; }; - unboxed_closure(); + second_closure(); } } diff --git a/src/test/pretty/closure-reform-pretty.rs b/src/test/pretty/closure-reform-pretty.rs index 328d4245eb6..094e3ce9156 100644 --- a/src/test/pretty/closure-reform-pretty.rs +++ b/src/test/pretty/closure-reform-pretty.rs @@ -15,9 +15,9 @@ fn call_it(f: Box String>) { } -fn call_this(f: |&str|: Send) { } +fn call_this(f: F) where F: Fn(&str) + Send { } -fn call_that(f: <'a>|&'a int, &'a int| -> int) { } +fn call_that(f: F) where F: for<'a>Fn(&'a int, &'a int) -> int { } fn call_extern(f: fn() -> int) { } diff --git a/src/test/pretty/disamb-stmt-expr.rs b/src/test/pretty/disamb-stmt-expr.rs index 78658a4c121..0c4cd103b82 100644 --- a/src/test/pretty/disamb-stmt-expr.rs +++ b/src/test/pretty/disamb-stmt-expr.rs @@ -14,7 +14,7 @@ // preserved. They are needed to disambiguate `{return n+1}; - 0` from // `({return n+1}-0)`. -fn id(f: || -> int) -> int { f() } +fn id(f: F) -> int where F: Fn() -> int { f() } fn wsucc(_n: int) -> int { id(|| { 1 }) - 0 } fn main() { } diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs index cd7a5b29a8a..e0066053f3c 100644 --- a/src/test/pretty/do1.rs +++ b/src/test/pretty/do1.rs @@ -10,6 +10,6 @@ // pp-exact -fn f(f: |int|) { f(10) } +fn f(f: F) where F: Fn(int) { f(10) } fn main() { f(|i| { assert!(i == 10) }) } diff --git a/src/test/pretty/fn-types.rs b/src/test/pretty/fn-types.rs index 1313af2df3d..31efb0c9ab1 100644 --- a/src/test/pretty/fn-types.rs +++ b/src/test/pretty/fn-types.rs @@ -11,5 +11,5 @@ // pp-exact fn from_foreign_fn(_x: fn()) { } -fn from_stack_closure(_x: ||) { } +fn from_stack_closure(_x: F) where F: Fn() { } fn main() { } diff --git a/src/test/pretty/trait-polarity.rs b/src/test/pretty/trait-polarity.rs new file mode 100644 index 00000000000..47c36ac7a40 --- /dev/null +++ b/src/test/pretty/trait-polarity.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +#![feature(optin_builtin_traits)] + +// pp-exact + +trait UnsafeTrait { + fn foo(&self); +} + +impl !UnsafeTrait for int { + fn foo(&self) { } +} + +pub fn main() { } diff --git a/src/test/run-make/static-unwinding/lib.rs b/src/test/run-make/static-unwinding/lib.rs index 5e75e1cd1cb..c3fa1a68e16 100644 --- a/src/test/run-make/static-unwinding/lib.rs +++ b/src/test/run-make/static-unwinding/lib.rs @@ -19,7 +19,7 @@ fn drop(&mut self) { } } -pub fn callback(f: ||) { +pub fn callback(f: F) where F: FnOnce() { let _a = A; f(); } diff --git a/src/test/run-pass/argument-passing.rs b/src/test/run-pass/argument-passing.rs index 75e197923c6..dfce3115290 100644 --- a/src/test/run-pass/argument-passing.rs +++ b/src/test/run-pass/argument-passing.rs @@ -20,7 +20,7 @@ fn f1(a: &mut X, b: &mut int, c: int) -> int { return r; } -fn f2(a: int, f: |int|) -> int { f(1); return a; } +fn f2(a: int, f: F) -> int where F: FnOnce(int) { f(1); return a; } pub fn main() { let mut a = X {x: 1}; diff --git a/src/test/run-pass/associated-type-doubleendediterator-object.rs b/src/test/run-pass/associated-type-doubleendediterator-object.rs new file mode 100644 index 00000000000..429027cbf30 --- /dev/null +++ b/src/test/run-pass/associated-type-doubleendediterator-object.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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 pairwise_sub(mut t: Box>) -> int { + let mut result = 0; + loop { + let front = t.next(); + let back = t.next_back(); + match (front, back) { + (Some(f), Some(b)) => { result += b - f; } + _ => { return result; } + } + } +} + +fn main() { + let v = vec!(1, 2, 3, 4, 5, 6); + let r = pairwise_sub(box v.into_iter()); + assert_eq!(r, 9); +} diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs new file mode 100644 index 00000000000..f8258466a7d --- /dev/null +++ b/src/test/run-pass/associated-types-iterator-binding.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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 pairwise_sub>(mut t: T) -> int { + let mut result = 0; + loop { + let front = t.next(); + let back = t.next_back(); + match (front, back) { + (Some(f), Some(b)) => { result += b - f; } + _ => { return result; } + } + } +} + +fn main() { + let v = vec!(1, 2, 3, 4, 5, 6); + let r =pairwise_sub(v.into_iter()); + assert_eq!(r, 9); +} diff --git a/src/test/run-pass/autobind.rs b/src/test/run-pass/autobind.rs index f5766ae1e53..ed471ed0079 100644 --- a/src/test/run-pass/autobind.rs +++ b/src/test/run-pass/autobind.rs @@ -11,11 +11,11 @@ fn f(x: Vec) -> T { return x.into_iter().next().unwrap(); } -fn g(act: |Vec | -> int) -> int { return act(vec!(1, 2, 3)); } +fn g(act: F) -> int where F: FnOnce(Vec) -> int { return act(vec!(1, 2, 3)); } pub fn main() { assert_eq!(g(f), 1); - let f1: |Vec| -> String = f; + let f1 = f; assert_eq!(f1(vec!["x".to_string(), "y".to_string(), "z".to_string()]), "x".to_string()); } diff --git a/src/test/run-pass/block-arg-call-as.rs b/src/test/run-pass/block-arg-call-as.rs index b4e36629651..6c54f33fbe6 100644 --- a/src/test/run-pass/block-arg-call-as.rs +++ b/src/test/run-pass/block-arg-call-as.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn asBlock(f: || -> uint) -> uint { +fn asBlock(f: F) -> uint where F: FnOnce() -> uint { return f(); } diff --git a/src/test/run-pass/block-explicit-types.rs b/src/test/run-pass/block-explicit-types.rs index 63051d71271..54b650d762b 100644 --- a/src/test/run-pass/block-explicit-types.rs +++ b/src/test/run-pass/block-explicit-types.rs @@ -9,6 +9,6 @@ // except according to those terms. pub fn main() { - fn as_buf(s: String, f: |String| -> T) -> T { f(s) } + fn as_buf(s: String, f: F) -> T where F: FnOnce(String) -> T { f(s) } as_buf("foo".to_string(), |foo: String| -> () println!("{}", foo) ); } diff --git a/src/test/run-pass/block-fn-coerce.rs b/src/test/run-pass/block-fn-coerce.rs index bbb30e9578e..fe52b1a693c 100644 --- a/src/test/run-pass/block-fn-coerce.rs +++ b/src/test/run-pass/block-fn-coerce.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn force(f: || -> int) -> int { return f(); } +fn force(f: F) -> int where F: FnOnce() -> int { return f(); } + pub fn main() { fn f() -> int { return 7; } assert_eq!(force(f), 7); - let g = {||force(f)}; + let g = {|&:|force(f)}; assert_eq!(g(), 7); } diff --git a/src/test/run-pass/block-iter-1.rs b/src/test/run-pass/block-iter-1.rs index ce20c3024d6..972bde5f29a 100644 --- a/src/test/run-pass/block-iter-1.rs +++ b/src/test/run-pass/block-iter-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn iter_vec(v: Vec , f: |&T|) { for x in v.iter() { f(x); } } +fn iter_vec(v: Vec , mut f: F) where F: FnMut(&T) { for x in v.iter() { f(x); } } pub fn main() { let v = vec!(1i, 2, 3, 4, 5, 6, 7); diff --git a/src/test/run-pass/block-iter-2.rs b/src/test/run-pass/block-iter-2.rs index 7bb9d0ddf99..1032fb486a1 100644 --- a/src/test/run-pass/block-iter-2.rs +++ b/src/test/run-pass/block-iter-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn iter_vec(v: Vec , f: |&T|) { for x in v.iter() { f(x); } } +fn iter_vec(v: Vec, mut f: F) where F: FnMut(&T) { for x in v.iter() { f(x); } } pub fn main() { let v = vec!(1i, 2, 3, 4, 5); diff --git a/src/test/run-pass/borrowck-borrow-from-expr-block.rs b/src/test/run-pass/borrowck-borrow-from-expr-block.rs index 8c4995e7100..038f9e5c9ab 100644 --- a/src/test/run-pass/borrowck-borrow-from-expr-block.rs +++ b/src/test/run-pass/borrowck-borrow-from-expr-block.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn borrow(x: &int, f: |x: &int|) { +fn borrow(x: &int, f: F) where F: FnOnce(&int) { f(x) } diff --git a/src/test/run-pass/borrowck-closures-two-imm.rs b/src/test/run-pass/borrowck-closures-two-imm.rs index 3bd12b03041..33e4294366f 100644 --- a/src/test/run-pass/borrowck-closures-two-imm.rs +++ b/src/test/run-pass/borrowck-closures-two-imm.rs @@ -15,10 +15,10 @@ // the closures are in scope. Issue #6801. fn a() -> int { - let mut x = 3; + let mut x = 3i; x += 1; - let c1 = || x * 4; - let c2 = || x * 5; + let c1 = |&:| x * 4; + let c2 = |&:| x * 5; c1() * c2() * x } @@ -29,16 +29,16 @@ fn get(x: &int) -> int { fn b() -> int { let mut x = 3; x += 1; - let c1 = || get(&x); - let c2 = || get(&x); + let c1 = |&:| get(&x); + let c2 = |&:| get(&x); c1() * c2() * x } fn c() -> int { let mut x = 3; x += 1; - let c1 = || x * 5; - let c2 = || get(&x); + let c1 = |&:| x * 5; + let c2 = |&:| get(&x); c1() * c2() * x } diff --git a/src/test/run-pass/borrowck-mut-uniq.rs b/src/test/run-pass/borrowck-mut-uniq.rs index 176c7277efd..dac8945b6e8 100644 --- a/src/test/run-pass/borrowck-mut-uniq.rs +++ b/src/test/run-pass/borrowck-mut-uniq.rs @@ -21,7 +21,7 @@ fn add_int(x: &mut Ints, v: int) { swap(&mut values, &mut x.values); } -fn iter_ints(x: &Ints, f: |x: &int| -> bool) -> bool { +fn iter_ints(x: &Ints, mut f: F) -> bool where F: FnMut(&int) -> bool { let l = x.values.len(); range(0u, l).all(|i| f(&x.values[i])) } diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index c95cf0bfdee..22c322b86c9 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -12,7 +12,7 @@ extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, c_long, c_longlong}; @@ -24,11 +24,13 @@ mod mlibc { } fn atol(s: String) -> int { - s.as_slice().with_c_str(|x| unsafe { mlibc::atol(x) as int }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atol(c.as_ptr()) as int } } fn atoll(s: String) -> i64 { - s.as_slice().with_c_str(|x| unsafe { mlibc::atoll(x) as i64 }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atoll(c.as_ptr()) as i64 } } pub fn main() { diff --git a/src/test/run-pass/call-closure-from-overloaded-op.rs b/src/test/run-pass/call-closure-from-overloaded-op.rs index 432d022c69b..29fcdf504de 100644 --- a/src/test/run-pass/call-closure-from-overloaded-op.rs +++ b/src/test/run-pass/call-closure-from-overloaded-op.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - fn foo() -> int { 22 } pub fn main() { diff --git a/src/test/run-pass/capture-clauses-boxed-closures.rs b/src/test/run-pass/capture-clauses-boxed-closures.rs index d24b9332917..6e8ed4fd5a1 100644 --- a/src/test/run-pass/capture-clauses-boxed-closures.rs +++ b/src/test/run-pass/capture-clauses-boxed-closures.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn each(x: &[T], f: |&T|) { +fn each(x: &[T], mut f: F) where F: FnMut(&T) { for val in x.iter() { f(val) } diff --git a/src/test/run-pass/closure-inference.rs b/src/test/run-pass/closure-inference.rs index 410b7416546..893003dd997 100644 --- a/src/test/run-pass/closure-inference.rs +++ b/src/test/run-pass/closure-inference.rs @@ -11,9 +11,9 @@ fn foo(i: int) -> int { i + 1 } -fn apply(f: |A| -> A, v: A) -> A { f(v) } +fn apply(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) } pub fn main() { - let f = {|i| foo(i)}; + let f = {|: i| foo(i)}; assert_eq!(apply(f, 2), 3); } diff --git a/src/test/run-pass/closure-inference2.rs b/src/test/run-pass/closure-inference2.rs index 6666b8e3cfa..03b10b881f7 100644 --- a/src/test/run-pass/closure-inference2.rs +++ b/src/test/run-pass/closure-inference2.rs @@ -11,7 +11,7 @@ // Test a rather underspecified example: pub fn main() { - let f = {|i| i}; + let f = {|&: i| i}; assert_eq!(f(2i), 2i); assert_eq!(f(5i), 5i); } diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index 03d9511b41c..a2e7d7bd7e3 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -22,25 +22,14 @@ fn call_it(f: F) println!("{}", f("Fred".to_string())) } -fn call_a_thunk(f: ||) { +fn call_a_thunk(f: F) where F: FnOnce() { f(); } -fn call_this(f: |&str|:Send) { +fn call_this(f: F) where F: FnOnce(&str) + Send { f("Hello!"); } -fn call_that(f: <'a>|&'a int, &'a int| -> int) { - let (ten, forty_two) = (10, 42); - println!("Your lucky number is {}", f(&ten, &forty_two)); -} - -fn call_cramped(f:||->uint,g:<'a>||->&'a uint) { - let number = f(); - let other_number = *g(); - println!("Ticket {} wins an all-expenses-paid trip to Mountain View", number + other_number); -} - fn call_bare(f: fn(&str)) { f("Hello world!") } @@ -71,16 +60,6 @@ pub fn main() { call_this(|s| println!("{}", s)); - call_that(|x, y| *x + *y); - - let z = 100; - call_that(|x, y| *x + *y - z); - - call_cramped(|| 1, || unsafe { - static a: uint = 100; - mem::transmute(&a) - }); - // External functions call_bare(println); diff --git a/src/test/run-pass/closure-return-bang.rs b/src/test/run-pass/closure-return-bang.rs deleted file mode 100644 index 9b4033ae0d7..00000000000 --- a/src/test/run-pass/closure-return-bang.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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. - -#![allow(dead_code)] - -fn f(x: || -> !) -> ! { - x(); -} - -fn main() { - let x: || -> ! = || panic!(); - let _y: || -> ! = || x(); -} diff --git a/src/test/run-pass/closure-syntax.rs b/src/test/run-pass/closure-syntax.rs deleted file mode 100644 index 4caa234ac7a..00000000000 --- a/src/test/run-pass/closure-syntax.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2014 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. - -#![allow(dead_code)] -#![feature(unboxed_closures)] - -// compile-flags:-g - -fn foo() {} - -trait Bar3 {} -impl<'b> Bar3 for <'a>|&'a int|: 'b + Send -> &'a int {} - -struct Foo<'a> { - a: ||: 'a, - b: ||: 'static, - c: <'b>||: 'a, - d: ||: 'a + Sync, - e: <'b>|int|: 'a + Sync -> &'b f32, -} - -fn f<'a>(a: &'a int, f: <'b>|&'b int| -> &'b int) -> &'a int { - f(a) -} - -fn g<'a>(a: &'a int) -> &'a int { - a -} - -struct A; - -impl A { - fn foo(&self) {} -} - -fn bar<'b>() { - foo::<||>(); - foo::<|| -> ()>(); - foo::<||:>(); - foo::<||:'b>(); - foo::<||:'b + Sync>(); - foo::<||:Sync>(); - foo::< <'a>|int, f32, &'a int|:'b + Sync -> &'a int>(); - - foo::<<'a>||>(); - - // issue #11209 - let _: ||: 'b; // for comparison - let _: <'a> ||; - - let _: Option<||:'b>; - let _: Option<<'a>||>; - let _: Option< <'a>||>; - - // issue #11210 - let _: ||: 'static; - - let a = A; - a.foo::<<'a>||>(); - - // issue #13490 - let _ = || -> ! loop {}; - - // issue #17021 - let c = box |&:| {}; -} - -struct B; -impl<'b> B<<'a>||: 'b> {} - -pub fn main() { -} diff --git a/src/test/run-pass/coerce-to-closure-and-proc.rs b/src/test/run-pass/coerce-to-closure-and-proc.rs deleted file mode 100644 index 413717d9226..00000000000 --- a/src/test/run-pass/coerce-to-closure-and-proc.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 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. - -#![feature(unboxed_closures)] - -fn id(x: T) -> T { - x -} - -#[derive(PartialEq, Show)] -struct Foo(T); - -#[derive(PartialEq, Show)] -enum Bar { - Baz(T) -} - -pub fn main() { - let f: |int| -> int = id; - assert_eq!(f(5), 5); - - let f: |int| -> Foo = Foo; - assert_eq!(f(5), Foo(5)); - - let f: |int| -> Bar = Bar::Baz; - assert_eq!(f(5), Bar::Baz(5)); - - let f: |int| -> Option = Some; - assert_eq!(f(5), Some(5)); -} diff --git a/src/test/run-pass/const-fn-val.rs b/src/test/run-pass/const-fn-val.rs index 57e37aaf393..8394c53cba5 100644 --- a/src/test/run-pass/const-fn-val.rs +++ b/src/test/run-pass/const-fn-val.rs @@ -12,9 +12,9 @@ fn foo() -> int { return 0xca7f000d; } -struct Bar<'a> { f: ||: 'a -> int } +struct Bar where F: FnMut() -> int { f: F } -static mut b : Bar<'static> = Bar { f: foo }; +static mut b : Bar int> = Bar { f: foo as fn() -> int}; pub fn main() { unsafe { assert_eq!((b.f)(), 0xca7f000d); } diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs new file mode 100644 index 00000000000..25c1464adfa --- /dev/null +++ b/src/test/run-pass/const-polymorphic-paths.rs @@ -0,0 +1,84 @@ +// Copyright 2014 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. + +#![feature(macro_rules)] + +use std::collections::Bitv; +use std::default::Default; +use std::iter::FromIterator; +use std::option::IntoIter as OptionIter; +use std::rand::Rand; +use std::rand::XorShiftRng as DummyRng; +// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods. +use std::vec::Vec; + +#[derive(PartialEq, Eq)] +struct Newt(T); + +fn id(x: T) -> T { x } +fn eq(a: T, b: T) -> bool { a == b } +fn u8_as_i8(x: u8) -> i8 { x as i8 } +fn odd(x: uint) -> bool { x % 2 == 1 } +fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } + +macro_rules! tests { + ($($expr:expr: $ty:ty /($($test:expr),*);)+) => (pub fn main() {$({ + const C: $ty = $expr; + static S: $ty = $expr; + assert!(eq(C($($test),*), $expr($($test),*))); + assert!(eq(S($($test),*), $expr($($test),*))); + assert!(eq(C($($test),*), S($($test),*))); + })+}) +} + +tests! { + // Free function. + id: fn(int) -> int /(5); + id::: fn(int) -> int /(5); + + // Enum variant constructor. + Some: fn(int) -> Option /(5); + Some::: fn(int) -> Option /(5); + + // Tuple struct constructor. + Newt: fn(int) -> Newt /(5); + Newt::: fn(int) -> Newt /(5); + + // Inherent static methods. + Vec::new: fn() -> Vec<()> /(); + Vec::<()>::new: fn() -> Vec<()> /(); + Vec::with_capacity: fn(uint) -> Vec<()> /(5); + Vec::<()>::with_capacity: fn(uint) -> Vec<()> /(5); + Bitv::from_fn: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd); + Bitv::from_fn:: bool>: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd); + + // Inherent non-static method. + Vec::map_in_place: fn(Vec, fn(u8) -> i8) -> Vec + /(vec![b'f', b'o', b'o'], u8_as_i8); + Vec::map_in_place:: i8>: fn(Vec, fn(u8) -> i8) -> Vec + /(vec![b'f', b'o', b'o'], u8_as_i8); + // FIXME these break with "type parameter might not appear here pointing at ``. + // Vec::::map_in_place: fn(Vec, fn(u8) -> i8) -> Vec + // /(vec![b'f', b'o', b'o'], u8_as_i8); + // Vec::::map_in_place:: i8>: fn(Vec, fn(u8) -> i8) -> Vec + // /(vec![b'f', b'o', b'o'], u8_as_i8); + + // Trait static methods. + // FIXME qualified path expressions aka UFCS i.e. ::method. + Default::default: fn() -> int /(); + Rand::rand: fn(&mut DummyRng) -> int /(&mut dummy_rng()); + Rand::rand::: fn(&mut DummyRng) -> int /(&mut dummy_rng()); + + // Trait non-static methods. + Clone::clone: fn(&int) -> int /(&5); + FromIterator::from_iter: fn(OptionIter) -> Vec /(Some(5).into_iter()); + FromIterator::from_iter::>: fn(OptionIter) -> Vec + /(Some(5).into_iter()); +} diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 5e028d3774f..1a84236793b 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::{str, string}; -use std::c_str::ToCStr; const A: [u8; 2] = ['h' as u8, 'i' as u8]; const B: &'static [u8; 2] = &A; @@ -23,8 +22,5 @@ pub fn main() { assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); - - let bar = str::from_utf8_unchecked(&A).to_c_str(); - assert_eq!(bar.as_str(), "hi".to_c_str().as_str()); } } diff --git a/src/test/run-pass/const-vec-of-fns.rs b/src/test/run-pass/const-vec-of-fns.rs index 86cac14b443..f21f7d1903c 100644 --- a/src/test/run-pass/const-vec-of-fns.rs +++ b/src/test/run-pass/const-vec-of-fns.rs @@ -17,8 +17,8 @@ fn f() { } static bare_fns: &'static [fn()] = &[f, f]; -struct S<'a>(||:'a); -static mut closures: &'static mut [S<'static>] = &mut [S(f), S(f)]; +struct S(F); +static mut closures: &'static mut [S] = &mut [S(f as fn()), S(f as fn())]; pub fn main() { unsafe { diff --git a/src/test/run-pass/empty-tag.rs b/src/test/run-pass/empty-tag.rs index 58eb4ce2f7a..d9201746440 100644 --- a/src/test/run-pass/empty-tag.rs +++ b/src/test/run-pass/empty-tag.rs @@ -25,6 +25,6 @@ fn wrapper3(i: chan) { } pub fn main() { - let wrapped = {||wrapper3(chan::chan_t)}; + let wrapped = {|&:|wrapper3(chan::chan_t)}; wrapped(); } diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 34ff0b3821c..797c26556aa 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -19,9 +19,6 @@ trait Trait {} fn main() { - // Closures - || - assert_eq!(size_of::<||>(), size_of::>()); - // Functions assert_eq!(size_of::(), size_of::>()); assert_eq!(size_of::(), size_of::>()); diff --git a/src/test/run-pass/expr-block-fn.rs b/src/test/run-pass/expr-block-fn.rs index 3a6cd61fa09..ed246e2cb7d 100644 --- a/src/test/run-pass/expr-block-fn.rs +++ b/src/test/run-pass/expr-block-fn.rs @@ -11,9 +11,8 @@ fn test_fn() { - type t = ||: 'static -> int; fn ten() -> int { return 10; } - let rs: t = ten; + let rs = ten; assert!((rs() == 10)); } diff --git a/src/test/run-pass/expr-block-generic-unique1.rs b/src/test/run-pass/expr-block-generic-unique1.rs index ec5013122ac..5c1039fe433 100644 --- a/src/test/run-pass/expr-block-generic-unique1.rs +++ b/src/test/run-pass/expr-block-generic-unique1.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -type compare<'a, T> = |Box, Box|: 'a -> bool; - -fn test_generic(expected: Box, eq: compare) { +fn test_generic(expected: Box, eq: F) where T: Clone, F: FnOnce(Box, Box) -> bool { let actual: Box = { expected.clone() }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_box() { @@ -22,7 +19,7 @@ fn compare_box(b1: Box, b2: Box) -> bool { println!("{}", *b2); return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(box true, compare_box); } pub fn main() { test_box(); } diff --git a/src/test/run-pass/expr-block-generic-unique2.rs b/src/test/run-pass/expr-block-generic-unique2.rs index 48e27dc449c..3d736cca6d5 100644 --- a/src/test/run-pass/expr-block-generic-unique2.rs +++ b/src/test/run-pass/expr-block-generic-unique2.rs @@ -8,17 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -type compare<'a, T> = |T, T|: 'a -> bool; - -fn test_generic(expected: T, eq: compare) { +fn test_generic(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_vec() { fn compare_vec(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::>(box 1, compare_vec); + test_generic::, _>(box 1, compare_vec); } pub fn main() { test_vec(); } diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs index f1363c42961..91b847d47cb 100644 --- a/src/test/run-pass/expr-block-generic.rs +++ b/src/test/run-pass/expr-block-generic.rs @@ -8,19 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - -// Tests for standalone blocks as expressions with dynamic type sizes -type compare<'a, T> = |T, T|: 'a -> bool; - -fn test_generic(expected: T, eq: compare) { +fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_bool() { fn compare_bool(b1: bool, b2: bool) -> bool { return b1 == b2; } - test_generic::(true, compare_bool); + test_generic::(true, compare_bool); } #[derive(Clone)] @@ -33,7 +28,7 @@ fn test_rec() { fn compare_rec(t1: Pair, t2: Pair) -> bool { t1.a == t2.a && t1.b == t2.b } - test_generic::(Pair {a: 1, b: 2}, compare_rec); + test_generic::(Pair {a: 1, b: 2}, compare_rec); } pub fn main() { test_bool(); test_rec(); } diff --git a/src/test/run-pass/expr-if-generic.rs b/src/test/run-pass/expr-if-generic.rs index d9300d0bc33..fb2a120e6f4 100644 --- a/src/test/run-pass/expr-if-generic.rs +++ b/src/test/run-pass/expr-if-generic.rs @@ -8,18 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -// Tests for if as expressions with dynamic type sizes -type compare = |T, T|: 'static -> bool; - -fn test_generic(expected: T, not_expected: T, eq: compare) { +fn test_generic(expected: T, not_expected: T, eq: F) where + T: Clone, + F: FnOnce(T, T) -> bool, +{ let actual: T = if true { expected.clone() } else { not_expected }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_bool() { fn compare_bool(b1: bool, b2: bool) -> bool { return b1 == b2; } - test_generic::(true, false, compare_bool); + test_generic::(true, false, compare_bool); } #[derive(Clone)] @@ -32,7 +31,7 @@ fn test_rec() { fn compare_rec(t1: Pair, t2: Pair) -> bool { t1.a == t2.a && t1.b == t2.b } - test_generic::(Pair{a: 1, b: 2}, Pair{a: 2, b: 3}, compare_rec); + test_generic::(Pair{a: 1, b: 2}, Pair{a: 2, b: 3}, compare_rec); } pub fn main() { test_bool(); test_rec(); } diff --git a/src/test/run-pass/expr-match-generic-unique1.rs b/src/test/run-pass/expr-match-generic-unique1.rs index aed4024b5bc..5fc9a502ca8 100644 --- a/src/test/run-pass/expr-match-generic-unique1.rs +++ b/src/test/run-pass/expr-match-generic-unique1.rs @@ -8,22 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -type compare = |Box, Box|: 'static -> bool; - -fn test_generic(expected: Box, eq: compare) { +fn test_generic(expected: Box, eq: F) where F: FnOnce(Box, Box) -> bool { let actual: Box = match true { true => { expected.clone() }, _ => panic!("wat") }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_box() { fn compare_box(b1: Box, b2: Box) -> bool { return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(box true, compare_box); } pub fn main() { test_box(); } diff --git a/src/test/run-pass/expr-match-generic-unique2.rs b/src/test/run-pass/expr-match-generic-unique2.rs index 89adef378f1..e608f9c46c7 100644 --- a/src/test/run-pass/expr-match-generic-unique2.rs +++ b/src/test/run-pass/expr-match-generic-unique2.rs @@ -8,20 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -type compare<'a, T> = |T, T|: 'a -> bool; - -fn test_generic(expected: T, eq: compare) { +fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = match true { true => expected.clone(), _ => panic!("wat") }; - assert!((eq(expected, actual))); + assert!(eq(expected, actual)); } fn test_vec() { fn compare_box(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::>(box 1, compare_box); + test_generic::, _>(box 1, compare_box); } pub fn main() { test_vec(); } diff --git a/src/test/run-pass/fn-bare-coerce-to-block.rs b/src/test/run-pass/fn-bare-coerce-to-block.rs index 1231a49dcd3..09508b9b136 100644 --- a/src/test/run-pass/fn-bare-coerce-to-block.rs +++ b/src/test/run-pass/fn-bare-coerce-to-block.rs @@ -10,7 +10,7 @@ fn bare() {} -fn likes_block(f: ||) { f() } +fn likes_block(f: F) where F: FnOnce() { f() } pub fn main() { likes_block(bare); diff --git a/src/test/run-pass/fn-coerce-field.rs b/src/test/run-pass/fn-coerce-field.rs index 6b7490ba673..bf6926050ba 100644 --- a/src/test/run-pass/fn-coerce-field.rs +++ b/src/test/run-pass/fn-coerce-field.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct r<'a> { - field: ||: 'a, +struct r where F: FnOnce() { + field: F, } pub fn main() { fn f() {} - let _i: r = r {field: f}; + let _i: r = r {field: f as fn()}; } diff --git a/src/test/run-pass/fn-pattern-expected-type.rs b/src/test/run-pass/fn-pattern-expected-type.rs index fb75abc6ea0..24bf1f94d88 100644 --- a/src/test/run-pass/fn-pattern-expected-type.rs +++ b/src/test/run-pass/fn-pattern-expected-type.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let f: |(int,int)| = |(x, y)| { + let f = |&: (x, y): (int, int)| { assert_eq!(x, 1); assert_eq!(y, 2); }; diff --git a/src/test/run-pass/fn-type-infer.rs b/src/test/run-pass/fn-type-infer.rs index 80d3527736f..ae22ff5cce0 100644 --- a/src/test/run-pass/fn-type-infer.rs +++ b/src/test/run-pass/fn-type-infer.rs @@ -12,7 +12,7 @@ pub fn main() { // We should be able to type infer inside of ||s. - let _f = || { + let _f = |&:| { let i = 10i; }; } diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs index 2a54f22ee66..f6466994955 100644 --- a/src/test/run-pass/foreach-nested.rs +++ b/src/test/run-pass/foreach-nested.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn two(it: |int|) { it(0); it(1); } +fn two(mut it: F) where F: FnMut(int) { it(0); it(1); } pub fn main() { let mut a: Vec = vec!(-1, -1, -1, -1); diff --git a/src/test/run-pass/foreach-put-structured.rs b/src/test/run-pass/foreach-put-structured.rs index 7a728e18a29..029dddb7a21 100644 --- a/src/test/run-pass/foreach-put-structured.rs +++ b/src/test/run-pass/foreach-put-structured.rs @@ -10,7 +10,7 @@ -fn pairs(it: |(int, int)|) { +fn pairs(mut it: F) where F: FnMut((int, int)) { let mut i: int = 0; let mut j: int = 0; while i < 10 { it((i, j)); i += 1; j += i; } diff --git a/src/test/run-pass/foreach-simple-outer-slot.rs b/src/test/run-pass/foreach-simple-outer-slot.rs index bb726773bb5..9ccb2dd56cf 100644 --- a/src/test/run-pass/foreach-simple-outer-slot.rs +++ b/src/test/run-pass/foreach-simple-outer-slot.rs @@ -19,7 +19,7 @@ pub fn main() { assert_eq!(sum, 45); } -fn first_ten(it: |int|) { +fn first_ten(mut it: F) where F: FnMut(int) { let mut i: int = 0; while i < 10 { println!("first_ten"); it(i); i = i + 1; } } diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 8a75fdd685d..dff1a1eaa04 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -11,7 +11,7 @@ // ignore-fast doesn't like extern crate extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; @@ -24,11 +24,10 @@ mod mlibc { fn strlen(str: String) -> uint { // C string is terminated with a zero - str.as_slice().with_c_str(|buf| { - unsafe { - mlibc::my_strlen(buf) as uint - } - }) + let s = CString::from_slice(str.as_bytes()); + unsafe { + mlibc::my_strlen(s.as_ptr()) as uint + } } pub fn main() { diff --git a/src/test/run-pass/fun-call-variants.rs b/src/test/run-pass/fun-call-variants.rs index 479f4f8387f..3955bedb168 100644 --- a/src/test/run-pass/fun-call-variants.rs +++ b/src/test/run-pass/fun-call-variants.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn ho(f: |int| -> int) -> int { let n: int = f(3); return n; } +fn ho(f: F) -> int where F: FnOnce(int) -> int { let n: int = f(3); return n; } fn direct(x: int) -> int { return x + 1; } diff --git a/src/test/run-pass/generic-static-methods.rs b/src/test/run-pass/generic-static-methods.rs index 032db16c617..f992847e4e9 100644 --- a/src/test/run-pass/generic-static-methods.rs +++ b/src/test/run-pass/generic-static-methods.rs @@ -10,11 +10,11 @@ trait vec_utils { - fn map_(x: &Self, f: |&T| -> U) -> Vec ; + fn map_(x: &Self, f: F) -> Vec where F: FnMut(&T) -> U; } impl vec_utils for Vec { - fn map_(x: &Vec , f: |&T| -> U) -> Vec { + fn map_(x: &Vec , mut f: F) -> Vec where F: FnMut(&T) -> U { let mut r = Vec::new(); for elt in x.iter() { r.push(f(elt)); diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 7fd8ca1fd8a..3bcce538871 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -9,13 +9,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + /** A somewhat reduced test case to expose some Valgrind issues. This originally came from the word-count benchmark. */ -pub fn map(filename: String, emit: map_reduce::putter) { +pub fn map(filename: String, mut emit: map_reduce::putter) { emit(filename, "1".to_string()); } @@ -25,7 +27,7 @@ mod map_reduce { use std::str; use std::thread::Thread; - pub type putter<'a> = |String, String|: 'a; + pub type putter<'a> = Box; pub type mapper = extern fn(String, putter); @@ -58,7 +60,7 @@ fn emit(im: &mut HashMap, } let ctrl_clone = ctrl.clone(); - ::map(input, |a,b| emit(&mut intermediates, ctrl.clone(), a, b) ); + ::map(input, box |a,b| emit(&mut intermediates, ctrl.clone(), a, b) ); ctrl_clone.send(ctrl_proto::mapper_done).unwrap(); } diff --git a/src/test/run-pass/hrtb-debruijn-object-types-in-closures.rs b/src/test/run-pass/hrtb-debruijn-object-types-in-closures.rs index 5bdfa3cafd7..9e857a33245 100644 --- a/src/test/run-pass/hrtb-debruijn-object-types-in-closures.rs +++ b/src/test/run-pass/hrtb-debruijn-object-types-in-closures.rs @@ -13,8 +13,7 @@ fn method(&self, data: &'tcx int) -> &'tcx int { data } fn dummy(&self) { } } -fn g(_: |&Typer|) { -} +fn g(_: F) where F: FnOnce(&Typer) {} fn h() { g(|typer| typer.dummy()) diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs index 53749f09f74..41b7c0fae07 100644 --- a/src/test/run-pass/hrtb-parse.rs +++ b/src/test/run-pass/hrtb-parse.rs @@ -40,8 +40,5 @@ fn foo21(t: for<'a> unsafe fn(int) -> int) { } fn foo22(t: for<'a> extern "C" fn(int) -> int) { } fn foo23(t: for<'a> unsafe extern "C" fn(int) -> int) { } -fn foo30(t: for<'a> |int| -> int) { } -fn foo31(t: for<'a> unsafe |int| -> int) { } - fn main() { } diff --git a/src/test/run-pass/hrtb-trait-object-passed-to-closure.rs b/src/test/run-pass/hrtb-trait-object-passed-to-closure.rs index 076b9c7684e..c90c3643d4e 100644 --- a/src/test/run-pass/hrtb-trait-object-passed-to-closure.rs +++ b/src/test/run-pass/hrtb-trait-object-passed-to-closure.rs @@ -23,7 +23,7 @@ struct NoAnn<'ast> { impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { } -fn foo<'ast> (f: Option<&'ast uint>, g: |&PrinterSupport|) { +fn foo<'ast, G>(f: Option<&'ast uint>, g: G) where G: FnOnce(&PrinterSupport) { let annotation = NoAnn { f: f }; g(&annotation) } diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 24deb7c2e4b..d0d8a8589a4 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -40,16 +40,10 @@ enum WireProtocol { // ... } -fn encode_json< - T: for<'a> Encodable, - fmt::Error>>(val: &T, - wr: &mut SeekableMemWriter) { +fn encode_json(val: &T, wr: &mut SeekableMemWriter) { write!(wr, "{}", json::as_json(val)); } -fn encode_rbml<'a, - T: Encodable, - io::IoError>>(val: &T, - wr: &'a mut SeekableMemWriter) { +fn encode_rbml(val: &T, wr: &mut SeekableMemWriter) { let mut encoder = writer::Encoder::new(wr); val.encode(&mut encoder); } diff --git a/src/test/run-pass/issue-13434.rs b/src/test/run-pass/issue-13434.rs index e223feede02..e5fd17e2dfe 100644 --- a/src/test/run-pass/issue-13434.rs +++ b/src/test/run-pass/issue-13434.rs @@ -15,7 +15,7 @@ trait Repro { fn repro(self, s: MyStruct) -> String; } -impl Repro for |MyStruct|:'static -> String { +impl Repro for F where F: FnOnce(MyStruct) -> String { fn repro(self, s: MyStruct) -> String { self(s) } @@ -26,5 +26,5 @@ fn do_stuff(r: R) -> String { } pub fn main() { - assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{}", s))); + assert_eq!("MyStruct".to_string(), do_stuff(|: s: MyStruct| format!("{}", s))); } diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 626381c334d..4d150e7a68e 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -24,7 +24,6 @@ pub fn type_ids() -> Vec { ids.push(TypeId::of::()); ids.push(TypeId::of::()); ids.push(TypeId::of::()); - ids.push(TypeId::of::()); ids.push(TypeId::of::<&'static testtypes::FooTrait>()); ids.push(TypeId::of::()); ids.push(TypeId::of::()); diff --git a/src/test/run-pass/issue-13808.rs b/src/test/run-pass/issue-13808.rs index e20090adcf6..c0652b946db 100644 --- a/src/test/run-pass/issue-13808.rs +++ b/src/test/run-pass/issue-13808.rs @@ -9,12 +9,12 @@ // except according to those terms. struct Foo<'a> { - listener: ||: 'a + listener: Box, } impl<'a> Foo<'a> { - fn new(listener: ||: 'a) -> Foo<'a> { - Foo { listener: listener } + fn new(listener: F) -> Foo<'a> where F: FnMut() + 'a { + Foo { listener: box listener } } } diff --git a/src/test/run-pass/issue-1460.rs b/src/test/run-pass/issue-1460.rs index 8176262abd9..2091a5437c2 100644 --- a/src/test/run-pass/issue-1460.rs +++ b/src/test/run-pass/issue-1460.rs @@ -10,5 +10,5 @@ pub fn main() { - {|i| if 1i == i { }}; + {|&: i| if 1i == i { }}; } diff --git a/src/test/run-pass/issue-14919.rs b/src/test/run-pass/issue-14919.rs index d66bbe9187a..d5590e99f2c 100644 --- a/src/test/run-pass/issue-14919.rs +++ b/src/test/run-pass/issue-14919.rs @@ -16,7 +16,7 @@ trait Matcher { struct CharPredMatcher<'a, 'b> { str: &'a str, - pred: |char|:'b -> bool + pred: Box bool + 'b>, } impl<'a, 'b> Matcher for CharPredMatcher<'a, 'b> { @@ -29,11 +29,11 @@ trait IntoMatcher<'a, T> { fn into_matcher(self, &'a str) -> T; } -impl<'a, 'b> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for |char|:'b -> bool { +impl<'a, 'b, F> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for F where F: FnMut(char) -> bool + 'b { fn into_matcher(self, s: &'a str) -> CharPredMatcher<'a, 'b> { CharPredMatcher { str: s, - pred: self + pred: box self, } } } @@ -57,6 +57,6 @@ fn match_indices<'a, M, T: IntoMatcher<'a, M>>(s: &'a str, from: T) -> MatchIndi fn main() { let s = "abcbdef"; - match_indices(s, |c: char| c == 'b') + match_indices(s, |&mut: c: char| c == 'b') .collect::>(); } diff --git a/src/test/run-pass/issue-1516.rs b/src/test/run-pass/issue-1516.rs deleted file mode 100644 index 3c5af9ca032..00000000000 --- a/src/test/run-pass/issue-1516.rs +++ /dev/null @@ -1,13 +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. - -pub fn main() { - let early_error: |&str|: 'static -> ! = |_msg| { panic!() }; -} diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass/issue-15924.rs index 1ab8deda383..db9f1cc9df7 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass/issue-15924.rs @@ -21,7 +21,7 @@ struct Foo { } #[unsafe_destructor] -impl Encodable, fmt::Error>> Drop for Foo { +impl Drop for Foo { fn drop(&mut self) { json::encode(&self.v); } diff --git a/src/test/run-pass/issue-16256.rs b/src/test/run-pass/issue-16256.rs index 48ea3a93296..e7422e233a6 100644 --- a/src/test/run-pass/issue-16256.rs +++ b/src/test/run-pass/issue-16256.rs @@ -10,5 +10,5 @@ fn main() { let mut buf = Vec::new(); - |c: u8| buf.push(c); + |&mut: c: u8| buf.push(c); } diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index f36594cb401..1febf337429 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -20,8 +20,8 @@ impl<'a, I, O: 'a> Parser<'a, I, O> { fn compose(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> { Parser { parse: box move |&mut: x: I| { - match (*self.parse).call_mut((x,)) { - Ok(r) => (*rhs.parse).call_mut((r,)), + match (self.parse)(x) { + Ok(r) => (rhs.parse)(r), Err(e) => Err(e) } } diff --git a/src/test/run-pass/issue-17904.rs b/src/test/run-pass/issue-17904.rs new file mode 100644 index 00000000000..3ce347d67e3 --- /dev/null +++ b/src/test/run-pass/issue-17904.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo where T: Copy; +struct Bar(T) where T: Copy; +struct Bleh(T, U) where T: Copy, U: Sized; +struct Baz where T: Copy { + field: T +} + +fn main() {} diff --git a/src/test/run-pass/issue-2074.rs b/src/test/run-pass/issue-2074.rs index ebcaf97c5f7..120ada96c15 100644 --- a/src/test/run-pass/issue-2074.rs +++ b/src/test/run-pass/issue-2074.rs @@ -11,11 +11,11 @@ #![allow(non_camel_case_types)] pub fn main() { - let one: || -> uint = || { + let one = |&:| { enum r { a }; r::a as uint }; - let two: || -> uint = || { + let two = |&:| { enum r { a }; r::a as uint }; diff --git a/src/test/run-pass/issue-2487-a.rs b/src/test/run-pass/issue-2487-a.rs index d8c12d8511c..aa61d52b2a3 100644 --- a/src/test/run-pass/issue-2487-a.rs +++ b/src/test/run-pass/issue-2487-a.rs @@ -29,7 +29,7 @@ fn socket() -> socket { } } -fn closure(f: ||) { f() } +fn closure(f: F) where F: FnOnce() { f() } fn setsockopt_bytes(_sock: int) { } diff --git a/src/test/run-pass/issue-3052.rs b/src/test/run-pass/issue-3052.rs index 00e6b5ca8fe..72cf2219bb6 100644 --- a/src/test/run-pass/issue-3052.rs +++ b/src/test/run-pass/issue-3052.rs @@ -9,10 +9,10 @@ // except according to those terms. -type Connection = |Vec|: 'static; +type Connection = Box) + 'static>; fn f() -> Option { - let mock_connection: Connection = |_| {}; + let mock_connection: Connection = box |&mut: _| {}; Some(mock_connection) } diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index 651315ea641..528870d0334 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -27,7 +27,7 @@ fn tester() }; let path = path::Path::new("blah"); - assert!(loader.call_mut((&path,)).is_ok()); + assert!(loader(&path).is_ok()); } pub fn main() {} diff --git a/src/test/run-pass/issue-3429.rs b/src/test/run-pass/issue-3429.rs index cce90f8a2cd..60c53450004 100644 --- a/src/test/run-pass/issue-3429.rs +++ b/src/test/run-pass/issue-3429.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let x = 1; - let y: || -> int = || x; + let x = 1u; + let y = |&:| x; let _z = y(); } diff --git a/src/test/run-pass/issue-3874.rs b/src/test/run-pass/issue-3874.rs index c616c09c70e..9226bebd2dc 100644 --- a/src/test/run-pass/issue-3874.rs +++ b/src/test/run-pass/issue-3874.rs @@ -10,7 +10,7 @@ enum PureCounter { PureCounterVariant(uint) } -fn each(thing: PureCounter, blk: |v: &uint|) { +fn each(thing: PureCounter, blk: F) where F: FnOnce(&uint) { let PureCounter::PureCounterVariant(ref x) = thing; blk(x); } diff --git a/src/test/run-pass/issue-3904.rs b/src/test/run-pass/issue-3904.rs index 81a7d073c4c..e917ecc745f 100644 --- a/src/test/run-pass/issue-3904.rs +++ b/src/test/run-pass/issue-3904.rs @@ -8,21 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type ErrPrinter<'a> = |&str, &str|: 'a; - fn example_err(prog: &str, arg: &str) { println!("{}: {}", prog, arg) } -fn exit(print: ErrPrinter, prog: &str, arg: &str) { +fn exit(print: F, prog: &str, arg: &str) where F: FnOnce(&str, &str) { print(prog, arg); } -struct X<'a> { - err: ErrPrinter<'a> +struct X where F: FnOnce(&str, &str) { + err: F, } -impl<'a> X<'a> { +impl X where F: FnOnce(&str, &str) { pub fn boom(self) { exit(self.err, "prog", "arg"); } diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index e5cc8414f06..220332f6354 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -13,7 +13,7 @@ use serialize::{json, Decodable}; -trait JD : Decodable { } +trait JD : Decodable {} fn exec() { let doc = json::from_str("").unwrap(); diff --git a/src/test/run-pass/issue-5239-2.rs b/src/test/run-pass/issue-5239-2.rs index 863acc5c0c3..69255c57681 100644 --- a/src/test/run-pass/issue-5239-2.rs +++ b/src/test/run-pass/issue-5239-2.rs @@ -11,7 +11,7 @@ // Regression test for issue #5239 pub fn main() { - let _f: |int| -> int = |ref x: int| { *x }; + let _f = |&: ref x: int| { *x }; let foo = 10; assert!(_f(foo) == 10); } diff --git a/src/test/run-pass/issue-6153.rs b/src/test/run-pass/issue-6153.rs index fa784e17b10..b2b64e62c39 100644 --- a/src/test/run-pass/issue-6153.rs +++ b/src/test/run-pass/issue-6153.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn swap(f: |Vec | -> Vec ) -> Vec { +fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { let x = vec!(1, 2, 3); f(x) } diff --git a/src/test/run-pass/issue-6157.rs b/src/test/run-pass/issue-6157.rs index 23e70085504..07c7c6888e1 100644 --- a/src/test/run-pass/issue-6157.rs +++ b/src/test/run-pass/issue-6157.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub trait OpInt<'a> { fn call(&mut self, int, int) -> int; } +pub trait OpInt { fn call(&mut self, int, int) -> int; } -impl<'a> OpInt<'a> for |int, int|: 'a -> int { +impl OpInt for F where F: FnMut(int, int) -> int { fn call(&mut self, a:int, b:int) -> int { (*self)(a, b) } @@ -21,7 +21,7 @@ fn squarei<'a>(x: int, op: &'a mut OpInt) -> int { op.call(x, x) } fn muli(x:int, y:int) -> int { x * y } pub fn main() { - let mut f = |x,y| muli(x,y); + let mut f = |&mut: x, y| muli(x, y); { let g = &mut f; let h = g as &mut OpInt; diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs index 99ab83ec620..72bdd1af746 100644 --- a/src/test/run-pass/issue-868.rs +++ b/src/test/run-pass/issue-868.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(g: || -> T) -> T { g() } +fn f(g: F) -> T where F: FnOnce() -> T { g() } pub fn main() { let _x = f( | | { 10i }); @@ -20,5 +20,5 @@ pub fn main() { let _: () = f(| | { }); // empty block with no type info should compile too let _ = f(||{}); - let _ = (||{}); + let _ = (|&:|{}); } diff --git a/src/test/run-pass/issue-9129.rs b/src/test/run-pass/issue-9129.rs index a6746f45206..3ca060f45a5 100644 --- a/src/test/run-pass/issue-9129.rs +++ b/src/test/run-pass/issue-9129.rs @@ -29,7 +29,7 @@ fn Ident_new() -> Ident { pub fn light_fuse(fld: Box) { int3!(); - let f = || { + let f = |&:| { int3!(); fld.boom(Ident_new()); // *** 1 }; diff --git a/src/test/run-pass/iter-range.rs b/src/test/run-pass/iter-range.rs index 794c4f4016e..29ac563878b 100644 --- a/src/test/run-pass/iter-range.rs +++ b/src/test/run-pass/iter-range.rs @@ -10,7 +10,7 @@ -fn range_(a: int, b: int, it: |int|) { +fn range_(a: int, b: int, mut it: F) where F: FnMut(int) { assert!((a < b)); let mut i: int = a; while i < b { it(i); i += 1; } diff --git a/src/test/run-pass/lambda-infer-unresolved.rs b/src/test/run-pass/lambda-infer-unresolved.rs index 190d2501584..b33e6512b18 100644 --- a/src/test/run-pass/lambda-infer-unresolved.rs +++ b/src/test/run-pass/lambda-infer-unresolved.rs @@ -16,7 +16,7 @@ struct Refs { refs: Vec , n: int } pub fn main() { let mut e = Refs{refs: vec!(), n: 0}; - let _f: || = || println!("{}", e.n); + let _f = |&:| println!("{}", e.n); let x: &[int] = e.refs.as_slice(); assert_eq!(x.len(), 0); } diff --git a/src/test/run-pass/last-use-in-block.rs b/src/test/run-pass/last-use-in-block.rs index c0dcf9e6094..8ef5df5d696 100644 --- a/src/test/run-pass/last-use-in-block.rs +++ b/src/test/run-pass/last-use-in-block.rs @@ -10,7 +10,7 @@ // Issue #1818 -fn lp(s: String, f: |String| -> T) -> T { +fn lp(s: String, mut f: F) -> T where F: FnMut(String) -> T { while false { let r = f(s); return (r); @@ -18,8 +18,8 @@ fn lp(s: String, f: |String| -> T) -> T { panic!(); } -fn apply(s: String, f: |String| -> T) -> T { - fn g(s: String, f: |String| -> T) -> T {f(s)} +fn apply(s: String, mut f: F) -> T where F: FnMut(String) -> T { + fn g(s: String, mut f: F) -> T where F: FnMut(String) -> T {f(s)} g(s, |v| { let r = f(v); r }) } diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index c9ea520576a..6615bb6368f 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -10,16 +10,17 @@ // Make sure #1399 stays fixed +#![feature(unboxed_closures)] struct A { a: Box } -fn foo() -> ||: 'static -> int { +fn foo() -> Box int + 'static> { let k = box 22i; let _u = A {a: k.clone()}; - let result: ||: 'static -> int = || 22; - result + let result = |&mut:| 22; + box result } pub fn main() { - assert_eq!(foo()(), 22); + assert_eq!(foo().call_mut(()), 22); } diff --git a/src/test/run-pass/last-use-is-capture.rs b/src/test/run-pass/last-use-is-capture.rs index 6d5624e2b58..206d4db3db4 100644 --- a/src/test/run-pass/last-use-is-capture.rs +++ b/src/test/run-pass/last-use-is-capture.rs @@ -13,7 +13,7 @@ struct A { a: Box } pub fn main() { - fn invoke(f: ||) { f(); } + fn invoke(f: F) where F: FnOnce() { f(); } let k = box 22i; let _u = A {a: k.clone()}; invoke(|| println!("{}", k.clone()) ) diff --git a/src/test/run-pass/match-phi.rs b/src/test/run-pass/match-phi.rs index c5f39bc1a53..2a0a2b20887 100644 --- a/src/test/run-pass/match-phi.rs +++ b/src/test/run-pass/match-phi.rs @@ -13,7 +13,7 @@ enum thing { a, b, c, } -fn foo(it: |int|) { it(10); } +fn foo(it: F) where F: FnOnce(int) { it(10); } pub fn main() { let mut x = true; diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index 4f9e573ccff..acd8078b1f4 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -11,11 +11,11 @@ trait vec_monad { - fn bind(&self, f: |&A| -> Vec ) -> Vec ; + fn bind(&self, f: F ) -> Vec where F: FnMut(&A) -> Vec ; } impl vec_monad for Vec { - fn bind(&self, f: |&A| -> Vec ) -> Vec { + fn bind(&self, mut f: F) -> Vec where F: FnMut(&A) -> Vec { let mut r = Vec::new(); for elt in self.iter() { r.extend(f(elt).into_iter()); @@ -25,11 +25,11 @@ fn bind(&self, f: |&A| -> Vec ) -> Vec { } trait option_monad { - fn bind(&self, f: |&A| -> Option) -> Option; + fn bind(&self, f: F) -> Option where F: FnOnce(&A) -> Option; } impl option_monad for Option { - fn bind(&self, f: |&A| -> Option) -> Option { + fn bind(&self, f: F) -> Option where F: FnOnce(&A) -> Option { match *self { Some(ref a) => { f(a) } None => { None } diff --git a/src/test/run-pass/move-nullary-fn.rs b/src/test/run-pass/move-nullary-fn.rs index 4b613e9beaa..b7cd3003e75 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 f2(_thing: F) where F: FnOnce() { } -fn f(thing: ||) { +fn f(thing: F) where F: FnOnce() { f2(thing); } diff --git a/src/test/run-pass/mut-function-arguments.rs b/src/test/run-pass/mut-function-arguments.rs index 39441227f60..f8072851913 100644 --- a/src/test/run-pass/mut-function-arguments.rs +++ b/src/test/run-pass/mut-function-arguments.rs @@ -15,7 +15,7 @@ fn f(mut y: Box) { } fn g() { - let frob: |Box| = |mut q| { *q = 2; assert!(*q == 2); }; + let frob = |&: mut q: Box| { *q = 2; assert!(*q == 2); }; let w = box 37; frob(w); diff --git a/src/test/run-pass/mut-in-ident-patterns.rs b/src/test/run-pass/mut-in-ident-patterns.rs index 139122b7b81..ad9161f9bd4 100644 --- a/src/test/run-pass/mut-in-ident-patterns.rs +++ b/src/test/run-pass/mut-in-ident-patterns.rs @@ -75,6 +75,6 @@ struct A { x = 30; assert_eq!(x, 30); - (|A { x: mut t }: A| { t = t+1; t })(A { x: 34 }); + (|&: A { x: mut t }: A| { t = t+1; t })(A { x: 34 }); } diff --git a/src/test/run-pass/newlambdas.rs b/src/test/run-pass/newlambdas.rs index 043136fdad9..01875288aef 100644 --- a/src/test/run-pass/newlambdas.rs +++ b/src/test/run-pass/newlambdas.rs @@ -10,9 +10,9 @@ // Tests for the new |args| expr lambda syntax -fn f(i: int, f: |int| -> int) -> int { f(i) } +fn f(i: int, f: F) -> int where F: FnOnce(int) -> int { f(i) } -fn g(_g: ||) { } +fn g(_g: G) where G: FnOnce() { } pub fn main() { assert_eq!(f(10, |a| a), 10); diff --git a/src/test/run-pass/non-legacy-modes.rs b/src/test/run-pass/non-legacy-modes.rs index 8262432db60..e422cb80321 100644 --- a/src/test/run-pass/non-legacy-modes.rs +++ b/src/test/run-pass/non-legacy-modes.rs @@ -12,7 +12,7 @@ struct X { repr: int } -fn apply(x: T, f: |T|) { +fn apply(x: T, f: F) where F: FnOnce(T) { f(x); } diff --git a/src/test/run-pass/object-one-type-two-traits.rs b/src/test/run-pass/object-one-type-two-traits.rs index f8bc0929bfa..4964b3f6728 100644 --- a/src/test/run-pass/object-one-type-two-traits.rs +++ b/src/test/run-pass/object-one-type-two-traits.rs @@ -12,7 +12,6 @@ // traits. use std::any::Any; -use std::any::AnyRefExt; trait Wrap { fn get(&self) -> int; diff --git a/src/test/run-pass/overloaded-calls-object-one-arg.rs b/src/test/run-pass/overloaded-calls-object-one-arg.rs new file mode 100644 index 00000000000..25b63cd14c4 --- /dev/null +++ b/src/test/run-pass/overloaded-calls-object-one-arg.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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 calls to closure arguments where the closure takes 1 argument. +// This is a bit tricky due to rust-call ABI. + +fn foo(f: &mut FnMut(int) -> int) -> int { + f(22) +} + +fn main() { + let z = foo(&mut |x| x *100); + assert_eq!(z, 2200); +} diff --git a/src/test/run-pass/overloaded-calls-object-two-args.rs b/src/test/run-pass/overloaded-calls-object-two-args.rs new file mode 100644 index 00000000000..026ebc30840 --- /dev/null +++ b/src/test/run-pass/overloaded-calls-object-two-args.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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 calls to closure arguments where the closure takes 2 arguments. +// This is a bit tricky due to rust-call ABI. + +fn foo(f: &mut FnMut(int, int) -> int) -> int { + f(1, 2) +} + +fn main() { + let z = foo(&mut |x, y| x * 10 + y); + assert_eq!(z, 12); +} diff --git a/src/test/run-pass/overloaded-calls-object-zero-args.rs b/src/test/run-pass/overloaded-calls-object-zero-args.rs new file mode 100644 index 00000000000..b38f8213b4a --- /dev/null +++ b/src/test/run-pass/overloaded-calls-object-zero-args.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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 calls to closure arguments where the closure takes 0 arguments. +// This is a bit tricky due to rust-call ABI. + +fn foo(f: &mut FnMut() -> int) -> int { + f() +} + +fn main() { + let z = foo(&mut || 22); + assert_eq!(z, 22); +} diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index b0a40f74ff9..bb5b88d3674 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -50,7 +50,7 @@ fn main() { x: 3, y: 3, }; - let ans = s.call_mut((3,)); + let ans = s(3); assert_eq!(ans, 27); let s = S2 { @@ -64,7 +64,7 @@ fn main() { x: 3, y: 3, }; - let ans = s.call_once((3, 1)); + let ans = s(3, 1); assert_eq!(ans, 27); } diff --git a/src/test/run-pass/parse-complex-macro-invoc-op.rs b/src/test/run-pass/parse-complex-macro-invoc-op.rs new file mode 100644 index 00000000000..e9ec624c13e --- /dev/null +++ b/src/test/run-pass/parse-complex-macro-invoc-op.rs @@ -0,0 +1,43 @@ +// Copyright 2014 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 parsing binary operators after macro invocations. + +#![feature(macro_rules)] + +macro_rules! id { + ($e: expr) => { $e } +} + +fn foo() { + id!(1i) + 1; + id![1i] - 1; + id!(1i) * 1; + id![1i] / 1; + id!(1i) % 1; + + id!(1i) & 1; + id![1i] | 1; + id!(1i) ^ 1; + + let mut x = 1i; + id![x] = 2; + id!(x) += 1; + + id!(1f64).clone(); + + id!([1i, 2, 3])[1]; + id![drop](1i); + + id!(true) && true; + id![true] || true; +} + +fn main() {} diff --git a/src/test/run-pass/pattern-in-closure.rs b/src/test/run-pass/pattern-in-closure.rs index e4f1df2d637..c718b948f8d 100644 --- a/src/test/run-pass/pattern-in-closure.rs +++ b/src/test/run-pass/pattern-in-closure.rs @@ -14,8 +14,8 @@ struct Foo { } pub fn main() { - let f = |(x, _): (int, int)| println!("{}", x + 1); - let g = |Foo { x: x, y: _y }: Foo| println!("{}", x + 1); + let f = |&: (x, _): (int, int)| println!("{}", x + 1); + let g = |&: Foo { x: x, y: _y }: Foo| println!("{}", x + 1); f((2, 3)); g(Foo { x: 1, y: 2 }); } diff --git a/src/test/run-pass/purity-infer.rs b/src/test/run-pass/purity-infer.rs index 3bceefb8318..c5588a29cb5 100644 --- a/src/test/run-pass/purity-infer.rs +++ b/src/test/run-pass/purity-infer.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn something(f: ||) { f(); } +fn something(f: F) where F: FnOnce() { f(); } pub fn main() { something(|| println!("hi!") ); } diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index b4523ce41ce..a7724e68310 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + struct closure_box<'a> { - cl: ||: 'a, + cl: Box, } -fn box_it(x: ||) -> closure_box { +fn box_it<'a>(x: Box) -> closure_box<'a> { closure_box {cl: x} } @@ -20,9 +22,9 @@ pub fn main() { let mut i = 3i; assert_eq!(i, 3); { - let cl = || i += 1; - let cl_box = box_it(cl); - (cl_box.cl)(); + let cl = |&mut:| i += 1; + let mut cl_box = box_it(box cl); + cl_box.cl.call_mut(()); } assert_eq!(i, 4); } diff --git a/src/test/run-pass/regions-dependent-autofn.rs b/src/test/run-pass/regions-dependent-autofn.rs index 311fd1bcdf2..e7dc5e99c2b 100644 --- a/src/test/run-pass/regions-dependent-autofn.rs +++ b/src/test/run-pass/regions-dependent-autofn.rs @@ -11,9 +11,9 @@ // Test lifetimes are linked properly when we autoslice a vector. // Issue #3148. -fn subslice(v: ||) -> || { v } +fn subslice(v: F) -> F where F: FnOnce() { v } -fn both(v: ||) -> || { +fn both(v: F) -> F where F: FnOnce() { subslice(subslice(v)) } diff --git a/src/test/run-pass/regions-fn-subtyping-2.rs b/src/test/run-pass/regions-fn-subtyping-2.rs index 9d2a959eae1..70c90ee05b3 100644 --- a/src/test/run-pass/regions-fn-subtyping-2.rs +++ b/src/test/run-pass/regions-fn-subtyping-2.rs @@ -13,13 +13,13 @@ // 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: <'a>|x: &'a int, g: |y: &'a int||) { +fn has_same_region(f: Box FnMut(&'a int, Box)>) { // `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: <'b>|x: &'b int, g: |y: &'b int||) { +fn wants_same_region(_f: Box FnMut(&'b int, Box)>) { } pub fn main() { diff --git a/src/test/run-pass/regions-fn-subtyping.rs b/src/test/run-pass/regions-fn-subtyping.rs index 705a0e12852..e9f774150dc 100644 --- a/src/test/run-pass/regions-fn-subtyping.rs +++ b/src/test/run-pass/regions-fn-subtyping.rs @@ -14,21 +14,21 @@ #![allow(unused_variable)] // Should pass region checking. -fn ok(f: |x: &uint|) { +fn ok(f: Box) { // Here, g is a function that can accept a uint pointer with // lifetime r, and f is a function that can accept a uint pointer // with any lifetime. The assignment g = f should be OK (i.e., // f's type should be a subtype of g's type), because f can be // used in any context that expects g's type. But this currently // fails. - let mut g: <'r>|y: &'r uint| = |x| { }; + let mut g: Box FnMut(&'r uint)> = box |x| { }; g = f; } // This version is the same as above, except that here, g's type is // inferred. -fn ok_inferred(f: |x: &uint|) { - let mut g: <'r>|x: &'r uint| = |_| {}; +fn ok_inferred(f: Box) { + let mut g: Box FnMut(&'r uint)> = box |_| {}; g = f; } diff --git a/src/test/run-pass/regions-infer-call-2.rs b/src/test/run-pass/regions-infer-call-2.rs index 3350c3b65d0..cfb6c858563 100644 --- a/src/test/run-pass/regions-infer-call-2.rs +++ b/src/test/run-pass/regions-infer-call-2.rs @@ -10,7 +10,7 @@ fn takes_two(x: &int, y: &int) -> int { *x + *y } -fn with(f: |x: &int| -> T) -> T { +fn with(f: F) -> T where F: FnOnce(&int) -> T { f(&20) } diff --git a/src/test/run-pass/regions-lifetime-nonfree-late-bound.rs b/src/test/run-pass/regions-lifetime-nonfree-late-bound.rs index 77ecb077fef..c796566b79d 100644 --- a/src/test/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/src/test/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -24,15 +24,15 @@ pub fn main() { fn explicit() { - fn test(_x: Option<|f: <'a> |g: &'a int||>) {} - test(Some(|_f: <'a> |g: &'a int|| {})); + fn test(_x: Option>) where F: FnMut(Box FnMut(&'a int)>) {} + test(Some(box |&mut: _f: Box FnMut(&'a int)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option<|f: |g: & int||>) {} - test(Some(|_f: |g: & int|| {})); + fn test(_x: Option>) where F: FnMut(Box< FnMut(& int)>) {} + test(Some(box |&mut: _f: Box< FnMut(& int)>| {})); } explicit(); diff --git a/src/test/run-pass/regions-link-fn-args.rs b/src/test/run-pass/regions-link-fn-args.rs index 2823622bdf6..8822d388039 100644 --- a/src/test/run-pass/regions-link-fn-args.rs +++ b/src/test/run-pass/regions-link-fn-args.rs @@ -13,7 +13,7 @@ #![allow(dead_code)] -fn with<'a>(_: |&'a Vec| -> &'a Vec) { } +fn with<'a, F>(_: F) where F: FnOnce(&'a Vec) -> &'a Vec { } fn foo() { with(|&ref ints| ints); diff --git a/src/test/run-pass/regions-params.rs b/src/test/run-pass/regions-params.rs index c0e821b8d38..0042d3a765b 100644 --- a/src/test/run-pass/regions-params.rs +++ b/src/test/run-pass/regions-params.rs @@ -11,7 +11,7 @@ fn region_identity(x: &uint) -> &uint { x } -fn apply(t: T, f: |T| -> T) -> T { f(t) } +fn apply(t: T, f: F) -> T where F: FnOnce(T) -> T { f(t) } fn parameterized(x: &uint) -> uint { let z = apply(x, ({|y| diff --git a/src/test/run-pass/regions-reassign-let-bound-pointer.rs b/src/test/run-pass/regions-reassign-let-bound-pointer.rs new file mode 100644 index 00000000000..ecf79de6222 --- /dev/null +++ b/src/test/run-pass/regions-reassign-let-bound-pointer.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + let mut z = x; + z = &a; +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-reassign-match-bound-pointer.rs b/src/test/run-pass/regions-reassign-match-bound-pointer.rs new file mode 100644 index 00000000000..18312b17339 --- /dev/null +++ b/src/test/run-pass/regions-reassign-match-bound-pointer.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + match x { + mut z => { + z = &a; + } + } +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs new file mode 100644 index 00000000000..aa0ed023da3 --- /dev/null +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -0,0 +1,65 @@ +// Copyright 2014 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 this fairly specialized, but also reasonable, pattern +// typechecks. The pattern involves regions bound in closures that +// wind up related to inference variables. +// +// NB. Changes to the region implementatiosn have broken this pattern +// a few times, but it happens to be used in the compiler so those +// changes were caught. However, those uses in the compiler could +// easily get changed or refactored away in the future. + +struct Ctxt<'tcx> { + x: &'tcx Vec +} + +struct Foo<'a,'tcx:'a> { + cx: &'a Ctxt<'tcx>, +} + +impl<'a,'tcx> Foo<'a,'tcx> { + fn bother(&mut self) -> int { + self.elaborate_bounds(|this| { + // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, + // where `'f0` and `'f1` are fresh, free regions that + // result from the bound regions on the closure, and `'2` + // is a region inference variable created by the call. Due + // to the constraints on the type, we find that `'_2 : 'f1 + // + 'f2` must hold (and can be assumed by the callee). + // Region inference has to do some clever stuff to avoid + // inferring `'_2` to be `'static` in this case, because + // it is created outside the closure but then related to + // regions bound by the closure itself. See the + // `region_inference.rs` file (and the `givens` field, in + // particular) for more details. + this.foo() + }) + } + + fn foo(&mut self) -> int { + 22 + } + + fn elaborate_bounds( + &mut self, + mk_cand: for<'b>|this: &mut Foo<'b, 'tcx>| -> int) + -> int + { + mk_cand(self) + } +} + +fn main() { + let v = vec!(); + let cx = Ctxt { x: &v }; + let mut foo = Foo { cx: &cx }; + assert_eq!(foo.bother(), 22); // just so the code is not dead, basically +} diff --git a/src/test/run-pass/regions-static-closure.rs b/src/test/run-pass/regions-static-closure.rs index f1d2adcaf94..0f36dc04575 100644 --- a/src/test/run-pass/regions-static-closure.rs +++ b/src/test/run-pass/regions-static-closure.rs @@ -8,19 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + struct closure_box<'a> { - cl: ||: 'a, + cl: Box, } -fn box_it(x: ||) -> closure_box { +fn box_it<'a>(x: Box) -> closure_box<'a> { closure_box {cl: x} } -fn call_static_closure(cl: closure_box<'static>) { - (cl.cl)(); +fn call_static_closure(mut cl: closure_box<'static>) { + cl.cl.call_mut(()) } pub fn main() { - let cl_box = box_it(|| println!("Hello, world!")); + let cl_box = box_it(box |&mut:| println!("Hello, world!")); call_static_closure(cl_box); } diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index c7aa405b513..d610bf09edb 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -13,8 +13,8 @@ extern crate libc; +use std::ffi::CString; use std::io::TempDir; -use std::c_str::ToCStr; use std::io::fs::PathExtensions; use std::io::fs; use std::io; @@ -31,20 +31,17 @@ fn rename_directory() { let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ - let ostream = test_file.with_c_str(|fromp| { - "w+b".with_c_str(|modebuf| { - libc::fopen(fromp, modebuf) - }) - }); + let fromp = CString::from_slice(test_file.as_vec()); + let modebuf = CString::from_slice(b"w+b"); + let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr()); assert!((ostream as uint != 0u)); let s = "hello".to_string(); - "hello".with_c_str(|buf| { - let write_len = libc::fwrite(buf as *const libc::c_void, - 1u as libc::size_t, - (s.len() + 1u) as libc::size_t, - ostream); - assert_eq!(write_len, (s.len() + 1) as libc::size_t) - }); + let buf = CString::from_slice(b"hello"); + let write_len = libc::fwrite(buf.as_ptr() as *mut _, + 1u as libc::size_t, + (s.len() + 1u) as libc::size_t, + ostream); + assert_eq!(write_len, (s.len() + 1) as libc::size_t); assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(&["quux", "blat"]); diff --git a/src/test/run-pass/return-from-closure.rs b/src/test/run-pass/return-from-closure.rs index b905ebf52fc..899dc8ddbe9 100644 --- a/src/test/run-pass/return-from-closure.rs +++ b/src/test/run-pass/return-from-closure.rs @@ -13,7 +13,7 @@ static mut calls: uint = 0; fn surrounding() { - let return_works = |n: int| { + let return_works = |&: n: int| { unsafe { calls += 1 } if n >= 0 { return; } diff --git a/src/test/run-pass/sendfn-is-a-block.rs b/src/test/run-pass/sendfn-is-a-block.rs index 3f94c7c8e54..c70ed9a3d74 100644 --- a/src/test/run-pass/sendfn-is-a-block.rs +++ b/src/test/run-pass/sendfn-is-a-block.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn test(f: |uint| -> uint) -> uint { +fn test(f: F) -> uint where F: FnOnce(uint) -> uint { return f(22u); } diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index ff6e0e4bbc9..74c0663971e 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -26,14 +26,14 @@ impl plus for String { fn plus(&self) -> int { 200 } } trait uint_utils { fn str(&self) -> String; - fn multi(&self, f: |uint|); + fn multi(&self, f: F) where F: FnMut(uint); } impl uint_utils for uint { fn str(&self) -> String { self.to_string() } - fn multi(&self, f: |uint|) { + fn multi(&self, mut f: F) where F: FnMut(uint) { let mut c = 0u; while c < *self { f(c); c += 1u; } } @@ -41,14 +41,14 @@ fn multi(&self, f: |uint|) { trait vec_utils { fn length_(&self, ) -> uint; - fn iter_(&self, f: |&T|); - fn map_(&self, f: |&T| -> U) -> Vec ; + fn iter_(&self, f: F) where F: FnMut(&T); + fn map_(&self, f: F) -> Vec where F: FnMut(&T) -> U; } impl vec_utils for Vec { fn length_(&self) -> uint { self.len() } - fn iter_(&self, f: |&T|) { for x in self.iter() { f(x); } } - fn map_(&self, f: |&T| -> U) -> Vec { + fn iter_(&self, mut f: F) where F: FnMut(&T) { for x in self.iter() { f(x); } } + fn map_(&self, mut f: F) -> Vec where F: FnMut(&T) -> U { let mut r = Vec::new(); for elt in self.iter() { r.push(f(elt)); @@ -64,7 +64,7 @@ pub fn main() { assert_eq!((vec!(1i)).length_().str(), "1".to_string()); let vect = vec!(3i, 4).map_(|a| *a + 4); assert_eq!(vect[0], 7); - let vect = (vec!(3i, 4)).map_::(|a| *a as uint + 4u); + let vect = (vec!(3i, 4)).map_::(|a| *a as uint + 4u); assert_eq!(vect[0], 7u); let mut x = 0u; 10u.multi(|_n| x += 2u ); diff --git a/src/test/run-pass/struct-partial-move-1.rs b/src/test/run-pass/struct-partial-move-1.rs index 8cc4cd142be..043ca121b1b 100644 --- a/src/test/run-pass/struct-partial-move-1.rs +++ b/src/test/run-pass/struct-partial-move-1.rs @@ -16,7 +16,7 @@ struct S { val: int } impl S { fn new(v: int) -> S { S { val: v } } } impl Drop for S { fn drop(&mut self) { } } -pub fn f((b1, b2): (T, T), f: |T| -> T) -> Partial { +pub fn f((b1, b2): (T, T), mut f: F) -> Partial where F: FnMut(T) -> T { let p = Partial { x: b1, y: b2 }; // Move of `p` is legal even though we are also moving `p.y`; the diff --git a/src/test/run-pass/struct-partial-move-2.rs b/src/test/run-pass/struct-partial-move-2.rs index aafe9e632b1..6327e03e528 100644 --- a/src/test/run-pass/struct-partial-move-2.rs +++ b/src/test/run-pass/struct-partial-move-2.rs @@ -18,7 +18,7 @@ impl Drop for S { fn drop(&mut self) { } } pub type Two = (Partial, Partial); -pub fn f((b1, b2): (T, T), (b3, b4): (T, T), f: |T| -> T) -> Two { +pub fn f((b1, b2): (T, T), (b3, b4): (T, T), mut f: F) -> Two where F: FnMut(T) -> T { let p = Partial { x: b1, y: b2 }; let q = Partial { x: b3, y: b4 }; diff --git a/src/test/run-pass/syntax-trait-polarity.rs b/src/test/run-pass/syntax-trait-polarity.rs new file mode 100644 index 00000000000..021cfedf06f --- /dev/null +++ b/src/test/run-pass/syntax-trait-polarity.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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. + +#![feature(optin_builtin_traits)] + +use std::kinds::Send; + +struct TestType; + +impl TestType {} + +trait TestTrait {} + +unsafe impl !Send for TestType {} +impl !TestTrait for TestType {} + +struct TestType2; + +impl TestType2 {} + +unsafe impl !Send for TestType2 {} +impl !TestTrait for TestType2 {} + +fn main() {} diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 8fda8a95169..bf108ecd676 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -29,7 +29,7 @@ fn test_tempdir() { let path = { let p = TempDir::new_in(&Path::new("."), "foobar").unwrap(); let p = p.path(); - assert!(p.as_vec().ends_with(b"foobar")); + assert!(p.as_str().unwrap().contains("foobar")); p.clone() }; assert!(!path.exists()); @@ -189,7 +189,7 @@ pub fn dont_double_panic() { assert!(r.is_err()); } -fn in_tmpdir(f: ||) { +fn in_tmpdir(f: F) where F: FnOnce() { let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir"); assert!(os::change_dir(tmpdir.path()).is_ok()); diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index c8abfcaa721..bc397bb6319 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -11,12 +11,16 @@ // Tests that a heterogeneous list of existential types can be put inside an Arc // and shared between tasks as long as all types fulfill Send. +// ignore-pretty + +#![feature(unboxed_closures)] + use std::sync::Arc; use std::sync::mpsc::channel; use std::thread::Thread; trait Pet { - fn name(&self, blk: |&str|); + fn name(&self, blk: Box); fn num_legs(&self) -> uint; fn of_good_pedigree(&self) -> bool; } @@ -38,19 +42,19 @@ struct Goldfyshe { } impl Pet for Catte { - fn name(&self, blk: |&str|) { blk(self.name.as_slice()) } + fn name(&self, mut blk: Box) { blk(self.name.as_slice()) } fn num_legs(&self) -> uint { 4 } fn of_good_pedigree(&self) -> bool { self.num_whiskers >= 4 } } impl Pet for Dogge { - fn name(&self, blk: |&str|) { blk(self.name.as_slice()) } + fn name(&self, mut blk: Box) { blk(self.name.as_slice()) } fn num_legs(&self) -> uint { 4 } fn of_good_pedigree(&self) -> bool { self.bark_decibels < 70 || self.tricks_known > 20 } } impl Pet for Goldfyshe { - fn name(&self, blk: |&str|) { blk(self.name.as_slice()) } + fn name(&self, mut blk: Box) { blk(self.name.as_slice()) } fn num_legs(&self) -> uint { 0 } fn of_good_pedigree(&self) -> bool { self.swim_speed >= 500 } } @@ -98,7 +102,7 @@ fn check_legs(arc: Arc>>) { } fn check_names(arc: Arc>>) { for pet in arc.iter() { - pet.name(|name| { + pet.name(box |name| { assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8); }) } diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index eeda6e2c88b..d4c1b688b47 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -24,10 +24,10 @@ fn to_string_(&self) -> String { "()".to_string() } } trait map { - fn map(&self, f: |&T| -> U) -> Vec ; + fn map(&self, f: F) -> Vec where F: FnMut(&T) -> U; } impl map for Vec { - fn map(&self, f: |&T| -> U) -> Vec { + fn map(&self, mut f: F) -> Vec where F: FnMut(&T) -> U { let mut r = Vec::new(); for i in self.iter() { r.push(f(i)); diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index efda7771403..7287d149f51 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -34,24 +34,6 @@ fn main() { let f = TypeId::of:: fn(&'a int) -> &'a int)>(); assert!(e != f); } - // Stack closures - { - let a = TypeId::of::<|&'static int, &'static int|>(); - let b = TypeId::of:: |&'static int, &'a int|>(); - let c = TypeId::of:: |&'a int, &'b int|>(); - let d = TypeId::of:: |&'b int, &'a int|>(); - assert!(a != b); - assert!(a != c); - assert!(a != d); - assert!(b != c); - assert!(b != d); - assert_eq!(c, d); - - // Make sure De Bruijn indices are handled correctly - let e = TypeId::of:: |(|&'a int| -> &'a int)|>(); - let f = TypeId::of::<|for<'a> |&'a int| -> &'a int|>(); - assert!(e != f); - } // Boxed unboxed closures { let a = TypeId::of::>(); diff --git a/src/test/run-pass/type-params-in-for-each.rs b/src/test/run-pass/type-params-in-for-each.rs index 5bf1a72dc6b..24cc5fab8ed 100644 --- a/src/test/run-pass/type-params-in-for-each.rs +++ b/src/test/run-pass/type-params-in-for-each.rs @@ -14,7 +14,7 @@ struct S { b: uint, } -fn range_(lo: uint, hi: uint, it: |uint|) { +fn range_(lo: uint, hi: uint, mut it: F) where F: FnMut(uint) { let mut lo_ = lo; while lo_ < hi { it(lo_); lo_ += 1u; } } diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs index ab3faa16f94..60e59400e1a 100644 --- a/src/test/run-pass/unboxed-closures-boxed.rs +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -19,7 +19,7 @@ fn make_adder(x: int) -> Box+'static> { pub fn main() { let mut adder = make_adder(3); - let z = adder.call_mut((2,)); + let z = adder(2); println!("{}", z); assert_eq!(z, 5); } diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs new file mode 100644 index 00000000000..0303954ce2a --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -0,0 +1,28 @@ +// 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 the call operator autoderefs when calling a bounded type parameter. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_with_2(x: &fn(int) -> int) -> int +{ + x(2) // look ma, no `*` +} + +fn subtract_22(x: int) -> int { x - 22 } + +pub fn main() { + let subtract_22: fn(int) -> int = subtract_22; + let z = call_with_2(&subtract_22); + assert_eq!(z, -20); +} diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs new file mode 100644 index 00000000000..305f496e668 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -0,0 +1,26 @@ +// 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 the call operator autoderefs when calling a bounded type parameter. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_with_2(x: &mut F) -> int + where F : FnMut(int) -> int +{ + x(2) // look ma, no `*` +} + +pub fn main() { + let z = call_with_2(&mut |x| x - 22); + assert_eq!(z, -20); +} diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs new file mode 100644 index 00000000000..8909f4e261f --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -0,0 +1,27 @@ +// 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 the call operator autoderefs when calling to an object type. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn make_adder(x: int) -> Boxint + 'static> { + box move |y| { x + y } +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder(2); + println!("{}", z); + assert_eq!(z, 5); +} + diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index 58657c2b718..a25f5e265e8 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -18,15 +18,15 @@ fn square(x: int) -> int { x * x } fn call_itint>(f: &F, x: int) -> int { - f.call((x,)) + f(x) } fn call_it_mutint>(f: &mut F, x: int) -> int { - f.call_mut((x,)) + f(x) } fn call_it_onceint>(f: F, x: int) -> int { - f.call_once((x,)) + f(x) } fn main() { diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 77d41ae1907..8af0547e5e5 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -25,15 +25,15 @@ extern "rust-call" fn call(&self, (x,): (int,)) -> int { } fn call_itint>(f: &F, x: int) -> int { - f.call((x,)) + f(x) } fn call_it_mutint>(f: &mut F, x: int) -> int { - f.call_mut((x,)) + f(x) } fn call_it_onceint>(f: F, x: int) -> int { - f.call_once((x,)) + f(x) } fn main() { diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index 02395624cd1..068080e256d 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -25,11 +25,11 @@ extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { } fn call_it_mutint>(f: &mut F, x: int) -> int { - f.call_mut((x,)) + f(x) } fn call_it_onceint>(f: F, x: int) -> int { - f.call_once((x,)) + f(x) } fn main() { diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs index 9d1d81fe259..0edeeb8d198 100644 --- a/src/test/run-pass/unboxed-closures-generic.rs +++ b/src/test/run-pass/unboxed-closures-generic.rs @@ -13,7 +13,7 @@ use std::ops::FnMut; fn call_it>(y: int, mut f: F) -> int { - f.call_mut((2, y)) + f(2, y) } pub fn main() { diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs index 3a750dadb91..88c9ceae4a1 100644 --- a/src/test/run-pass/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures-manual-impl.rs @@ -22,11 +22,11 @@ extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { } fn call_itint>(mut f: F, x: int) -> int { - f.call_mut((x,)) + 3 + f(x) + 3 } fn call_box(f: &mut FnMut(int) -> int, x: int) -> int { - f.call_mut((x,)) + 3 + f(x) + 3 } fn main() { diff --git a/src/test/run-pass/unboxed-closures-prelude.rs b/src/test/run-pass/unboxed-closures-prelude.rs index e31ef169e16..d1bd7e908c8 100644 --- a/src/test/run-pass/unboxed-closures-prelude.rs +++ b/src/test/run-pass/unboxed-closures-prelude.rs @@ -17,12 +17,12 @@ fn main() { task.call((0i, )); let mut task: Box int> = box |&mut: x| x; - task.call_mut((0i, )); + task(0i); call(|:x| x, 22); } fn call int>(f: F, x: int) -> int { - f.call_once((x,)) + f(x) } diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs index f11096ba5ff..c473db4586f 100644 --- a/src/test/run-pass/unboxed-closures-simple.rs +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -14,6 +14,6 @@ pub fn main() { let mut f = |&mut: x: int, y: int| -> int { x + y }; - let z = f.call_mut((1, 2)); + let z = f(1, 2); assert_eq!(z, 3); } diff --git a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs index beab82e804b..780a1e6cdf0 100644 --- a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs +++ b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs @@ -12,6 +12,6 @@ fn main() { let onetime = |: x| x; - onetime.call_once((0i,)); + onetime(0i); } diff --git a/src/test/run-pass/unnamed_argument_mode.rs b/src/test/run-pass/unnamed_argument_mode.rs index 3a5e0dd8ae3..d22a6652e16 100644 --- a/src/test/run-pass/unnamed_argument_mode.rs +++ b/src/test/run-pass/unnamed_argument_mode.rs @@ -13,7 +13,7 @@ fn good(_a: &int) { // unnamed argument &int is now parse x: &int -fn called(_f: |&int|) { +fn called(_f: F) where F: FnOnce(&int) { } pub fn main() { diff --git a/src/test/run-pass/unused-move-capture.rs b/src/test/run-pass/unused-move-capture.rs index ba48ae1c0ce..bd20a174d1e 100644 --- a/src/test/run-pass/unused-move-capture.rs +++ b/src/test/run-pass/unused-move-capture.rs @@ -10,6 +10,6 @@ pub fn main() { let _x = box 1i; - let lam_move: || = || {}; + let lam_move = |&:| {}; lam_move(); } diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index ec320c1f8a3..9600a242ca1 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -10,7 +10,7 @@ extern crate libc; -use std::c_str::{CString, ToCStr}; +use std::ffi::{self, CString}; use libc::{c_char, c_int}; // ignore-fast doesn't like extern crate @@ -19,43 +19,38 @@ fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; } -unsafe fn check(expected: &str, f: |*mut c_char| -> T) { +unsafe fn check(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T { let mut x = [0 as c_char; 50]; f(&mut x[0] as *mut c_char); - let res = CString::new(&x[0], false); - assert_eq!(expected, res.as_str().unwrap()); + assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr())); } pub fn main() { unsafe { // Call with just the named parameter - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| sprintf(s, c)); - }); + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); // Make a function pointer - let x: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; + let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; // A function that takes a function pointer - unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) { - // Call with just the named parameter via fn pointer - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| p(s, c)); - }); + unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) { + // Call with just the named parameter + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - p(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); } diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index cc2061c3cf3..57660183333 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -10,10 +10,13 @@ #![feature(advanced_slice_patterns)] -fn foldl(values: &[T], - initial: U, - function: |partial: U, element: &T| -> U) - -> U { +fn foldl(values: &[T], + initial: U, + mut function: F) + -> U where + U: Clone, + F: FnMut(U, &T) -> U, +{ match values { [ref head, tail..] => foldl(tail, function(initial, head), function), @@ -21,10 +24,13 @@ fn foldl(values: &[T], } } -fn foldr(values: &[T], - initial: U, - function: |element: &T, partial: U| -> U) - -> U { +fn foldr(values: &[T], + initial: U, + mut function: F) + -> U where + U: Clone, + F: FnMut(&T, U) -> U, +{ match values { [head.., ref tail] => foldr(head, function(tail, initial), function), diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index f73800b89db..c8ed1a26105 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -26,7 +26,7 @@ fn the(x: &Cell) { return while !x.get() { x.set(true); }; } let i = &Cell::new(false); - let dont = {||the(i)}; + let dont = {|&:|the(i)}; dont(); assert!((i.get())); } diff --git a/src/test/run-pass/wf-bound-region-in-object-type.rs b/src/test/run-pass/wf-bound-region-in-object-type.rs new file mode 100644 index 00000000000..256b199d729 --- /dev/null +++ b/src/test/run-pass/wf-bound-region-in-object-type.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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 the `wf` checker properly handles bound regions in object +// types. Compiling this code used to trigger an ICE. + +pub struct Context<'tcx> { + vec: &'tcx Vec +} + +pub type Cmd<'a> = &'a int; + +pub type DecodeInlinedItem<'a> = + Box FnMut(Cmd, &Context<'tcx>) -> Result<&'tcx int, ()> + 'a>; + +fn foo(d: DecodeInlinedItem) { +} + +fn main() { }

(&mut self, mut predicate: P) -> Option where /// ```rust /// use core::num::SignedInt; /// - /// let xs = [-3i, 0, 1, 5, -10]; + /// let xs = [-3, 0, 1, 5, -10]; /// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); /// ``` #[inline] @@ -697,7 +697,7 @@ fn max_by(self, mut f: F) -> Option< ::Item> where /// ```rust /// use core::num::SignedInt; /// - /// let xs = [-3i, 0, 1, 5, -10]; + /// let xs = [-3, 0, 1, 5, -10]; /// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); /// ``` #[inline] @@ -950,7 +950,7 @@ pub trait AdditiveIterator { /// ```rust /// use std::iter::AdditiveIterator; /// - /// let a = [1i, 2, 3, 4, 5]; + /// let a: [i32] = [1, 2, 3, 4, 5]; /// let mut it = a.iter().map(|&x| x); /// assert!(it.sum() == 15); /// ``` @@ -1033,7 +1033,7 @@ pub trait IteratorOrdExt { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().max().unwrap() == &5); /// ``` fn max(self) -> Option; @@ -1043,7 +1043,7 @@ pub trait IteratorOrdExt { /// # Example /// /// ```rust - /// let a = [1i, 2, 3, 4, 5]; + /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().min().unwrap() == &1); /// ``` fn min(self) -> Option; @@ -1069,16 +1069,16 @@ pub trait IteratorOrdExt { /// let v: [int; 0] = []; /// assert_eq!(v.iter().min_max(), NoElements); /// - /// let v = [1i]; + /// let v = [1]; /// assert!(v.iter().min_max() == OneElement(&1)); /// - /// let v = [1i, 2, 3, 4, 5]; + /// let v = [1, 2, 3, 4, 5]; /// assert!(v.iter().min_max() == MinMax(&1, &5)); /// - /// let v = [1i, 2, 3, 4, 5, 6]; + /// let v = [1, 2, 3, 4, 5, 6]; /// assert!(v.iter().min_max() == MinMax(&1, &6)); /// - /// let v = [1i, 1, 1, 1]; + /// let v = [1, 1, 1, 1]; /// assert!(v.iter().min_max() == MinMax(&1, &1)); /// ``` fn min_max(self) -> MinMaxResult; @@ -1179,10 +1179,10 @@ impl MinMaxResult { /// let r: MinMaxResult = NoElements; /// assert_eq!(r.into_option(), None); /// - /// let r = OneElement(1i); + /// let r = OneElement(1); /// assert_eq!(r.into_option(), Some((1,1))); /// - /// let r = MinMax(1i,2i); + /// let r = MinMax(1, 2); /// assert_eq!(r.into_option(), Some((1,2))); /// ``` pub fn into_option(self) -> Option<(T,T)> { @@ -1261,7 +1261,7 @@ pub trait CloneIteratorExt { /// ```rust /// use std::iter::{CloneIteratorExt, count}; /// - /// let a = count(1i,1i).take(1); + /// let a = count(1, 1).take(1); /// let mut cy = a.cycle(); /// assert_eq!(cy.next(), Some(1)); /// assert_eq!(cy.next(), Some(1)); @@ -2726,10 +2726,10 @@ pub trait Step: Ord { /// Change self to the previous object. fn step_back(&mut self); /// The steps_between two step objects. - /// a should always be less than b, so the result should never be negative. + /// start should always be less than end, so the result should never be negative. /// Return None if it is not possible to calculate steps_between without /// overflow. - fn steps_between(a: &Self, b: &Self) -> Option; + fn steps_between(start: &Self, end: &Self) -> Option; } macro_rules! step_impl { @@ -2741,9 +2741,9 @@ impl Step for $t { #[inline] fn step_back(&mut self) { *self -= 1; } #[inline] - fn steps_between(a: &$t, b: &$t) -> Option { - debug_assert!(a < b); - Some((*a - *b) as uint) + fn steps_between(start: &$t, end: &$t) -> Option { + debug_assert!(end >= start); + Some((*end - *start) as uint) } } )*) @@ -2758,7 +2758,7 @@ impl Step for $t { #[inline] fn step_back(&mut self) { *self -= 1; } #[inline] - fn steps_between(_a: &$t, _b: &$t) -> Option { + fn steps_between(_start: &$t, _end: &$t) -> Option { None } } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 2620928acc1..9cf3433e1ab 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -187,13 +187,13 @@ pub unsafe fn uninitialized() -> T { /// ``` /// use std::mem; /// -/// let x = &mut 5i; -/// let y = &mut 42i; +/// let x = &mut 5; +/// let y = &mut 42; /// /// mem::swap(x, y); /// -/// assert_eq!(42i, *x); -/// assert_eq!(5i, *y); +/// assert_eq!(42, *x); +/// assert_eq!(5, *y); /// ``` #[inline] #[stable] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6c3b153c000..485d320cf5c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,7 +15,7 @@ #![stable] #![allow(missing_docs)] -use char::Char; +use char::CharExt; use clone::Clone; use cmp::{PartialEq, Eq}; use cmp::{PartialOrd, Ord}; @@ -336,7 +336,7 @@ fn saturating_sub(self, other: Self) -> Self { /// ```rust /// use std::num::Int; /// - /// assert_eq!(2i.pow(4), 16); + /// assert_eq!(2.pow(4), 16); /// ``` #[inline] fn pow(self, mut exp: uint) -> Self { diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 2a7df5db5c9..17e4c5f8215 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -717,15 +717,6 @@ fn shr(self, other: uint) -> $t { self >> other } shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 } -// NOTE(stage0) remove trait after a snapshot -#[cfg(stage0)] -#[allow(missing_docs)] -#[lang="index"] -pub trait Index for Sized? { - /// The method for the indexing (`Foo[Bar]`) operation - fn index<'a>(&'a self, index: &Index) -> &'a Result; -} - /// The `Index` trait is used to specify the functionality of indexing operations /// like `arr[idx]` when used in an immutable context. /// @@ -755,7 +746,6 @@ pub trait Index for Sized? { /// Foo[Foo]; /// } /// ``` -#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index"] pub trait Index for Sized? { type Sized? Output; @@ -764,15 +754,6 @@ pub trait Index for Sized? { fn index<'a>(&'a self, index: &Index) -> &'a Self::Output; } -// NOTE(stage0) remove trait after a snapshot -#[cfg(stage0)] -#[allow(missing_docs)] -#[lang="index_mut"] -pub trait IndexMut for Sized? { - /// The method for the indexing (`Foo[Bar]`) operation - fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result; -} - /// The `IndexMut` trait is used to specify the functionality of indexing /// operations like `arr[idx]`, when used in a mutable context. /// @@ -802,7 +783,6 @@ pub trait IndexMut for Sized? { /// &mut Foo[Foo]; /// } /// ``` -#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index_mut"] pub trait IndexMut for Sized? { type Sized? Output; @@ -943,7 +923,7 @@ fn next(&mut self) -> Option { #[inline] fn size_hint(&self) -> (uint, Option) { - if let Some(hint) = Step::steps_between(&self.end, &self.start) { + if let Some(hint) = Step::steps_between(&self.start, &self.end) { (hint, Some(hint)) } else { (0, None) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index a9a1857ec97..9e55a3aa8c4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -470,10 +470,10 @@ pub fn map_or_else U, F: FnOnce(T) -> U>(self, def: D, f: F) - /// /// ``` /// let x = Some("foo"); - /// assert_eq!(x.ok_or(0i), Ok("foo")); + /// assert_eq!(x.ok_or(0), Ok("foo")); /// /// let x: Option<&str> = None; - /// assert_eq!(x.ok_or(0i), Err(0i)); + /// assert_eq!(x.ok_or(0), Err(0)); /// ``` #[inline] #[experimental] @@ -491,10 +491,10 @@ pub fn ok_or(self, err: E) -> Result { /// /// ``` /// let x = Some("foo"); - /// assert_eq!(x.ok_or_else(|| 0i), Ok("foo")); + /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); /// /// let x: Option<&str> = None; - /// assert_eq!(x.ok_or_else(|| 0i), Err(0i)); + /// assert_eq!(x.ok_or_else(|| 0), Err(0)); /// ``` #[inline] #[experimental] @@ -728,8 +728,8 @@ impl Option { /// let good_year = good_year_from_input.parse().unwrap_or_default(); /// let bad_year = bad_year_from_input.parse().unwrap_or_default(); /// - /// assert_eq!(1909i, good_year); - /// assert_eq!(0i, bad_year); + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); /// ``` #[inline] #[stable] diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 64f13a8f123..d4aca1bb73c 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -38,7 +38,7 @@ // Reexported types and traits -pub use char::Char; +pub use char::CharExt; pub use clone::Clone; pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; pub use iter::{Extend, IteratorExt}; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index f17a775cf42..7aed16173e9 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -531,17 +531,6 @@ fn clone_from_slice(&mut self, src: &[T]) -> uint where T: Clone { } } -// NOTE(stage0) remove impl after a snapshot -#[cfg(stage0)] -impl ops::Index for [T] { - fn index(&self, &index: &uint) -> &T { - assert!(index < self.len()); - - unsafe { mem::transmute(self.repr().data.offset(index as int)) } - } -} - -#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot impl ops::Index for [T] { type Output = T; @@ -552,17 +541,6 @@ fn index(&self, &index: &uint) -> &T { } } -// NOTE(stage0) remove impl after a snapshot -#[cfg(stage0)] -impl ops::IndexMut for [T] { - fn index_mut(&mut self, &index: &uint) -> &mut T { - assert!(index < self.len()); - - unsafe { mem::transmute(self.repr().data.offset(index as int)) } - } -} - -#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot impl ops::IndexMut for [T] { type Output = T; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da..8fdd66f83ce 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -190,7 +190,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { /// # Panics /// /// This function will panic if the string pointed to by `s` is not valid UTF-8. -#[unstable = "may change location based on the outcome of the c_str module"] +#[deprecated = "use std::ffi::c_str_to_bytes + str::from_utf8"] pub unsafe fn from_c_str(s: *const i8) -> &'static str { let s = s as *const u8; let mut len = 0u; diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index e6608eee3dd..b6fc6457fce 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -30,7 +30,6 @@ mod ops; mod option; mod ptr; -mod raw; mod result; mod slice; mod str; diff --git a/src/libcoretest/option.rs b/src/libcoretest/option.rs index 86fc25c9d91..4a459992098 100644 --- a/src/libcoretest/option.rs +++ b/src/libcoretest/option.rs @@ -220,6 +220,7 @@ fn test_ord() { assert!(big > None); } +/* FIXME(#20575) #[test] fn test_collect() { let v: Option> = range(0i, 0).map(|_| Some(0i)).collect(); @@ -234,12 +235,14 @@ fn test_collect() { assert!(v == None); // test that it does not take more elements than it needs - let mut functions = [|| Some(()), || None, || panic!()]; + let mut functions: [Box Option<()>>; 3] = + [box || Some(()), box || None, box || panic!()]; let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); assert!(v == None); } +*/ #[test] fn test_cloned() { diff --git a/src/libcoretest/raw.rs b/src/libcoretest/raw.rs deleted file mode 100644 index f2c23c7c773..00000000000 --- a/src/libcoretest/raw.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 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::raw::*; -use core::mem; - -#[test] -fn synthesize_closure() { - unsafe { - let x = 10; - let f: |int| -> int = |y| x + y; - - assert_eq!(f(20), 30); - - let original_closure: Closure = mem::transmute(f); - - let actual_function_pointer = original_closure.code; - let environment = original_closure.env; - - let new_closure = Closure { - code: actual_function_pointer, - env: environment - }; - - let new_f: |int| -> int = mem::transmute(new_closure); - assert_eq!(new_f(20), 30); - } -} diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index 415cd4e7dcf..52ea14dd05d 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -67,6 +67,7 @@ pub fn test_impl_map_err() { assert!(Err::(1).map_err(|x| x + 1) == Err(2)); } +/* FIXME(#20575) #[test] fn test_collect() { let v: Result, ()> = range(0i, 0).map(|_| Ok::(0)).collect(); @@ -81,11 +82,13 @@ fn test_collect() { assert!(v == Err(2)); // test that it does not take more elements than it needs - let mut functions = [|| Ok(()), || Err(1i), || panic!()]; + let mut functions: [Box Result<(), int>>; 3] = + [box || Ok(()), box || Err(1i), box || panic!()]; let v: Result, int> = functions.iter_mut().map(|f| (*f)()).collect(); assert!(v == Err(1)); } +*/ #[test] pub fn test_fmt_default() { diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index aa1550ae5b8..a0c9da3ae6d 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -21,15 +21,34 @@ #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(phase, unboxed_closures)] +#![feature(phase, unboxed_closures, associated_types)] #[cfg(test)] #[phase(plugin, link)] extern crate log; extern crate libc; use libc::{c_void, size_t, c_int}; -use std::c_vec::CVec; +use std::ops::Deref; use std::ptr::Unique; +use std::slice; + +pub struct Bytes { + ptr: Unique, + len: uint, +} + +impl Deref for Bytes { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_mut_buf(&self.ptr.0, self.len) } + } +} + +impl Drop for Bytes { + fn drop(&mut self) { + unsafe { libc::free(self.ptr.0 as *mut _); } + } +} #[link(name = "miniz", kind = "static")] extern { @@ -52,7 +71,7 @@ fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, @@ -60,8 +79,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -69,16 +88,16 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Option> { +pub fn deflate_bytes(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM) } /// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -86,8 +105,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -95,12 +114,12 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Option> { +pub fn inflate_bytes(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, 0) } /// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index f151102f286..e3bcf70e8c8 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -168,10 +168,10 @@ //! dot::Id::new(format!("N{}", n)).unwrap() //! } //! fn node_label<'b>(&'b self, n: &Nd) -> dot::LabelText<'b> { -//! dot::LabelStr(self.nodes[*n].as_slice().into_cow()) +//! dot::LabelText::LabelStr(self.nodes[*n].as_slice().into_cow()) //! } //! fn edge_label<'b>(&'b self, _: &Ed) -> dot::LabelText<'b> { -//! dot::LabelStr("⊆".into_cow()) +//! dot::LabelText::LabelStr("⊆".into_cow()) //! } //! } //! @@ -225,10 +225,10 @@ //! } //! fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> { //! let &(i, _) = n; -//! dot::LabelStr(self.nodes[i].as_slice().into_cow()) +//! dot::LabelText::LabelStr(self.nodes[i].as_slice().into_cow()) //! } //! fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> { -//! dot::LabelStr("⊆".into_cow()) +//! dot::LabelText::LabelStr("⊆".into_cow()) //! } //! } //! @@ -274,7 +274,7 @@ #![feature(globs, slicing_syntax)] #![feature(unboxed_closures)] -pub use self::LabelText::*; +use self::LabelText::*; use std::borrow::IntoCow; use std::io; @@ -586,8 +586,8 @@ fn indent(w: &mut W) -> io::IoResult<()> { #[cfg(test)] mod tests { use self::NodeLabels::*; - use super::{Id, LabelText, LabelStr, EscStr, Labeller}; - use super::{Nodes, Edges, GraphWalk, render}; + use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; + use super::LabelText::{mod, LabelStr, EscStr}; use std::io::IoResult; use std::borrow::IntoCow; use std::iter::repeat; diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs index 233d1c049f4..f41a4a8b901 100644 --- a/src/liblog/macros.rs +++ b/src/liblog/macros.rs @@ -125,7 +125,7 @@ macro_rules! warn { /// #[phase(plugin, link)] extern crate log; /// /// fn main() { -/// let ret = 3i; +/// let ret = 3; /// info!("this function is about to return: {}", ret); /// } /// ``` @@ -152,7 +152,7 @@ macro_rules! info { /// #[phase(plugin, link)] extern crate log; /// /// fn main() { -/// debug!("x = {x}, y = {y}", x=10i, y=20i); +/// debug!("x = {x}, y = {y}", x=10, y=20); /// } /// ``` /// diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index 71ce882e98c..ce055a84d3f 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -12,7 +12,6 @@ use core::prelude::*; use core::num::Int; - use {Rng, SeedableRng, Rand}; const KEY_WORDS : uint = 8; // 8 words for the 256-bit key @@ -28,8 +27,7 @@ /// /// [1]: D. J. Bernstein, [*ChaCha, a variant of /// Salsa20*](http://cr.yp.to/chacha.html) - -#[derive(Copy)] +#[deriving(Copy, Clone)] pub struct ChaChaRng { buffer: [u32; STATE_WORDS], // Internal buffer of output state: [u32; STATE_WORDS], // Initial state @@ -283,5 +281,15 @@ fn test_rng_true_values() { 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4)); } + + #[test] + fn test_rng_clone() { + let seed : &[_] = &[0u32, ..8]; + let mut rng: ChaChaRng = SeedableRng::from_seed(seed); + let mut clone = rng.clone(); + for _ in range(0u, 16) { + assert_eq!(rng.next_u64(), clone.next_u64()); + } + } } diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 53ae242c5e2..03b56963ba9 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -179,6 +179,13 @@ macro_rules! rngstepn( } } +// Cannot be derived because [u32; 256] does not implement Clone +impl Clone for IsaacRng { + fn clone(&self) -> IsaacRng { + *self + } +} + impl Rng for IsaacRng { #[inline] fn next_u32(&mut self) -> u32 { @@ -415,6 +422,13 @@ macro_rules! rngstepn( } } +// Cannot be derived because [u32; 256] does not implement Clone +impl Clone for Isaac64Rng { + fn clone(&self) -> Isaac64Rng { + *self + } +} + impl Rng for Isaac64Rng { // FIXME #7771: having next_u32 like this should be unnecessary #[inline] @@ -485,6 +499,7 @@ fn rand(other: &mut R) -> Isaac64Rng { } } + #[cfg(test)] mod test { use std::prelude::v1::*; @@ -594,4 +609,14 @@ fn test_rng_64_true_values() { 596345674630742204, 9947027391921273664, 11788097613744130851, 10391409374914919106)); } + + #[test] + fn test_rng_clone() { + let seed: &[_] = &[1, 23, 456, 7890, 12345]; + let mut rng: Isaac64Rng = SeedableRng::from_seed(seed); + let mut clone = rng.clone(); + for _ in range(0u, 16) { + assert_eq!(rng.next_u64(), clone.next_u64()); + } + } } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 18f508e816f..f538e0ade05 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -269,7 +269,7 @@ fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { /// ``` /// use std::rand::{thread_rng, Rng}; /// - /// let choices = [1i, 2, 4, 8, 16, 32]; + /// let choices = [1, 2, 4, 8, 16, 32]; /// let mut rng = thread_rng(); /// println!("{}", rng.choose(&choices)); /// # // replace with slicing syntax when it's stable! @@ -291,7 +291,7 @@ fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { /// use std::rand::{thread_rng, Rng}; /// /// let mut rng = thread_rng(); - /// let mut y = [1i, 2, 3]; + /// let mut y = [1, 2, 3]; /// rng.shuffle(&mut y); /// println!("{}", y.as_slice()); /// rng.shuffle(&mut y); @@ -385,6 +385,7 @@ pub trait SeedableRng: Rng { /// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of /// Statistical Software*. Vol. 8 (Issue 14). #[allow(missing_copy_implementations)] +#[deriving(Clone)] pub struct XorShiftRng { x: u32, y: u32, @@ -392,17 +393,6 @@ pub struct XorShiftRng { w: u32, } -impl Clone for XorShiftRng { - fn clone(&self) -> XorShiftRng { - XorShiftRng { - x: self.x, - y: self.y, - z: self.z, - w: self.w, - } - } -} - impl XorShiftRng { /// Creates a new XorShiftRng instance which is not seeded. /// @@ -507,6 +497,7 @@ fn rand(rng: &mut R) -> XorShiftRng { #[cfg(not(test))] mod std { pub use core::{option, fmt}; // panic!() + pub use core::clone; // derive Clone pub use core::kinds; } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index f7d5bfcd117..3acedac111d 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -25,7 +25,7 @@ html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] #![feature(macro_rules, phase, slicing_syntax, globs)] -#![feature(unboxed_closures)] +#![feature(unboxed_closures, associated_types)] #![allow(missing_docs)] extern crate serialize; @@ -417,6 +417,7 @@ pub fn read_opaque(&mut self, op: F) -> DecodeResult where } } + #[cfg(stage0)] impl<'doc> serialize::Decoder for Decoder<'doc> { fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } @@ -671,6 +672,263 @@ fn error(&mut self, err: &str) -> Error { ApplicationError(err.to_string()) } } + + #[cfg(not(stage0))] + impl<'doc> serialize::Decoder for Decoder<'doc> { + type Error = Error; + fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } + + fn read_u64(&mut self) -> DecodeResult { Ok(doc_as_u64(try!(self.next_doc(EsU64)))) } + fn read_u32(&mut self) -> DecodeResult { Ok(doc_as_u32(try!(self.next_doc(EsU32)))) } + fn read_u16(&mut self) -> DecodeResult { Ok(doc_as_u16(try!(self.next_doc(EsU16)))) } + fn read_u8 (&mut self) -> DecodeResult { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) } + fn read_uint(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsUint))); + if v > (::std::uint::MAX as u64) { + Err(IntTooBig(v as uint)) + } else { + Ok(v as uint) + } + } + + fn read_i64(&mut self) -> DecodeResult { + Ok(doc_as_u64(try!(self.next_doc(EsI64))) as i64) + } + fn read_i32(&mut self) -> DecodeResult { + Ok(doc_as_u32(try!(self.next_doc(EsI32))) as i32) + } + fn read_i16(&mut self) -> DecodeResult { + Ok(doc_as_u16(try!(self.next_doc(EsI16))) as i16) + } + fn read_i8 (&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsI8 ))) as i8) + } + fn read_int(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64; + if v > (int::MAX as i64) || v < (int::MIN as i64) { + debug!("FIXME \\#6122: Removing this makes this function miscompile"); + Err(IntTooBig(v as uint)) + } else { + Ok(v as int) + } + } + + fn read_bool(&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsBool))) != 0) + } + + fn read_f64(&mut self) -> DecodeResult { + let bits = doc_as_u64(try!(self.next_doc(EsF64))); + Ok(unsafe { transmute(bits) }) + } + fn read_f32(&mut self) -> DecodeResult { + let bits = doc_as_u32(try!(self.next_doc(EsF32))); + Ok(unsafe { transmute(bits) }) + } + fn read_char(&mut self) -> DecodeResult { + Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap()) + } + fn read_str(&mut self) -> DecodeResult { + Ok(try!(self.next_doc(EsStr)).as_str()) + } + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum({})", name); + try!(self._check_label(name)); + + let doc = try!(self.next_doc(EsEnum)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_variant_arg(idx={})", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_struct_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); + f(self) + } + + fn read_struct(&mut self, name: &str, _: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct(name={})", name); + f(self) + } + + fn read_struct_field(&mut self, name: &str, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct_field(name={}, idx={})", name, idx); + try!(self._check_label(name)); + f(self) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple()"); + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(Expected(format!("Expected tuple of length `{}`, \ + found tuple of length `{}`", tuple_len, len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_arg(idx={})", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, name: &str, len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct(name={})", name); + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct_arg(idx={})", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult, + { + debug!("read_option()"); + self.read_enum("Option", move |this| { + this.read_enum_variant(&["None", "Some"], move |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => { + Err(Expected(format!("Expected None or Some"))) + } + } + }) + }) + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_seq()"); + self.push_doc(EsVec, move |d| { + let len = try!(d._next_uint(EsVecLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_seq_elt(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_seq_elt(idx={})", idx); + self.push_doc(EsVecElt, f) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_map()"); + self.push_doc(EsMap, move |d| { + let len = try!(d._next_uint(EsMapLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_map_elt_key(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_key(idx={})", idx); + self.push_doc(EsMapKey, f) + } + + fn read_map_elt_val(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_val(idx={})", idx); + self.push_doc(EsMapVal, f) + } + + fn error(&mut self, err: &str) -> Error { + ApplicationError(err.to_string()) + } + } } pub mod writer { @@ -872,7 +1130,212 @@ pub fn emit_opaque(&mut self, f: F) -> EncodeResult where } } + #[cfg(stage0)] impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + + fn emit_nil(&mut self) -> EncodeResult { + Ok(()) + } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { + self.wr_tagged_u64(EsUint as uint, v as u64) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { + self.wr_tagged_u64(EsU64 as uint, v) + } + fn emit_u32(&mut self, v: u32) -> EncodeResult { + self.wr_tagged_u32(EsU32 as uint, v) + } + fn emit_u16(&mut self, v: u16) -> EncodeResult { + self.wr_tagged_u16(EsU16 as uint, v) + } + fn emit_u8(&mut self, v: u8) -> EncodeResult { + self.wr_tagged_u8(EsU8 as uint, v) + } + + fn emit_int(&mut self, v: int) -> EncodeResult { + self.wr_tagged_i64(EsInt as uint, v as i64) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { + self.wr_tagged_i64(EsI64 as uint, v) + } + fn emit_i32(&mut self, v: i32) -> EncodeResult { + self.wr_tagged_i32(EsI32 as uint, v) + } + fn emit_i16(&mut self, v: i16) -> EncodeResult { + self.wr_tagged_i16(EsI16 as uint, v) + } + fn emit_i8(&mut self, v: i8) -> EncodeResult { + self.wr_tagged_i8(EsI8 as uint, v) + } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u64(EsF64 as uint, bits) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u32(EsF32 as uint, bits) + } + fn emit_char(&mut self, v: char) -> EncodeResult { + self.wr_tagged_u32(EsChar as uint, v as u32) + } + + fn emit_str(&mut self, v: &str) -> EncodeResult { + self.wr_tagged_str(EsStr as uint, v) + } + + fn emit_enum(&mut self, name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + try!(self.start_tag(EsEnum as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_tagged_uint(EsEnumVid, v_id)); + try!(self.start_tag(EsEnumBody as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant_arg(&mut self, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_struct_field(&mut self, name: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum("Option", f) + } + fn emit_option_none(&mut self) -> EncodeResult { + self.emit_enum_variant("None", 0, 0, |_| Ok(())) + } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVec as uint)); + try!(self._emit_tagged_uint(EsVecLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_seq_elt(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVecElt as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMap as uint)); + try!(self._emit_tagged_uint(EsMapLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_key(&mut self, _idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMapKey as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self.start_tag(EsMapVal as uint)); + try!(f(self)); + self.end_tag() + } + } + #[cfg(not(stage0))] + impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + type Error = io::IoError; + fn emit_nil(&mut self) -> EncodeResult { Ok(()) } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 8f03f882128..1a145746a28 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -494,11 +494,7 @@ fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'a, 'tcx>, let mut n_uniq = 0i; ty::fold_ty(cx.tcx, ty, |t| { match t.sty { - ty::ty_uniq(_) | - ty::ty_closure(box ty::ClosureTy { - store: ty::UniqTraitStore, - .. - }) => { + ty::ty_uniq(_) => { n_uniq += 1; } @@ -550,20 +546,20 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { } declare_lint! { - RAW_POINTER_DERIVING, + RAW_POINTER_DERIVE, Warn, "uses of #[derive] with raw pointers are rarely correct" } -struct RawPtrDerivingVisitor<'a, 'tcx: 'a> { +struct RawPtrDeriveVisitor<'a, 'tcx: 'a> { cx: &'a Context<'a, 'tcx> } -impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { static MSG: &'static str = "use of `#[derive]` with a raw pointer"; if let ast::TyPtr(..) = ty.node { - self.cx.span_lint(RAW_POINTER_DERIVING, ty.span, MSG); + self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG); } visit::walk_ty(self, ty); } @@ -572,21 +568,21 @@ fn visit_expr(&mut self, _: &ast::Expr) {} fn visit_block(&mut self, _: &ast::Block) {} } -pub struct RawPointerDeriving { +pub struct RawPointerDerive { checked_raw_pointers: NodeSet, } -impl RawPointerDeriving { - pub fn new() -> RawPointerDeriving { - RawPointerDeriving { +impl RawPointerDerive { + pub fn new() -> RawPointerDerive { + RawPointerDerive { checked_raw_pointers: NodeSet::new(), } } } -impl LintPass for RawPointerDeriving { +impl LintPass for RawPointerDerive { fn get_lints(&self) -> LintArray { - lint_array!(RAW_POINTER_DERIVING) + lint_array!(RAW_POINTER_DERIVE) } fn check_item(&mut self, cx: &Context, item: &ast::Item) { @@ -611,7 +607,7 @@ fn check_item(&mut self, cx: &Context, item: &ast::Item) { if !self.checked_raw_pointers.insert(item.id) { return } match item.node { ast::ItemStruct(..) | ast::ItemEnum(..) => { - let mut visitor = RawPtrDerivingVisitor { cx: cx }; + let mut visitor = RawPtrDeriveVisitor { cx: cx }; visit::walk_item(&mut visitor, &*item); } _ => {} @@ -1329,8 +1325,8 @@ fn check_unused_mut_pat(&self, cx: &Context, pats: &[P]) { let ident = path1.node; if let ast::BindByValue(ast::MutMutable) = mode { if !token::get_ident(ident).get().starts_with("_") { - match mutables.entry(ident.name.uint()) { - Vacant(entry) => { entry.set(vec![id]); }, + match mutables.entry(&ident.name.uint()) { + Vacant(entry) => { entry.insert(vec![id]); }, Occupied(mut entry) => { entry.get_mut().push(id); }, } } @@ -1762,7 +1758,7 @@ fn check_item(&mut self, cx: &Context, item: &ast::Item) { } } } - ast::ItemImpl(_, _, Some(ref t), _, _) => { + ast::ItemImpl(_, _, _, Some(ref t), _, _) => { let id = ty::trait_ref_to_def_id(cx.tcx, t); self.lint(cx, id, t.path.span); } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 69e5b4889c2..521e5e305bc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -208,7 +208,7 @@ macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => ( add_builtin_with_new!(sess, TypeLimits, - RawPointerDeriving, + RawPointerDerive, MissingDoc, ); @@ -247,6 +247,7 @@ macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => ( self.register_renamed("unknown_crate_type", "unknown_crate_types"); self.register_renamed("variant_size_difference", "variant_size_differences"); self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes"); + self.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index cc21243b81d..ca7c65c8e2b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -259,3 +259,5 @@ pub struct LinkMeta { pub const tag_associated_type_names: uint = 0xb2; pub const tag_associated_type_name: uint = 0xb3; + +pub const tag_polarity: uint = 0xb4; diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 5dac2bafaec..b0cf322b068 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -87,8 +87,8 @@ fn dump_crates(cstore: &CStore) { fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) { let mut map = FnvHashMap::new(); cstore.iter_crate_data(|cnum, data| { - match map.entry(data.name()) { - Vacant(entry) => { entry.set(vec![cnum]); }, + match map.entry(&data.name()) { + Vacant(entry) => { entry.insert(vec![cnum]); }, Occupied(mut entry) => { entry.get_mut().push(cnum); }, } }); diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 2f4acaca4de..ec0b80c3a53 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -23,8 +23,8 @@ use util::nodemap::{FnvHashMap, NodeMap}; use std::cell::RefCell; -use std::c_vec::CVec; use std::rc::Rc; +use flate::Bytes; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::IdentInterner; @@ -36,7 +36,7 @@ pub type cnum_map = FnvHashMap; pub enum MetadataBlob { - MetadataVec(CVec), + MetadataVec(Bytes), MetadataArchive(loader::ArchiveMetadata), } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 97f5228f033..ac8dfc16759 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -662,27 +662,27 @@ pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec { item_path(lookup_item(id, cdata.data())) } -pub type DecodeInlinedItem<'a> = for<'tcx> |cdata: Cmd, - tcx: &ty::ctxt<'tcx>, - path: Vec, - par_doc: rbml::Doc|: 'a - -> Result<&'tcx ast::InlinedItem, - Vec>; +pub type DecodeInlinedItem<'a> = + Box FnMut(Cmd, + &ty::ctxt<'tcx>, + Vec, + rbml::Doc) + -> Result<&'tcx ast::InlinedItem, Vec> + 'a>; pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId, - decode_inlined_item: DecodeInlinedItem) + mut decode_inlined_item: DecodeInlinedItem) -> csearch::found_ast<'tcx> { debug!("Looking up item: {}", id); let item_doc = lookup_item(id, cdata.data()); let path = item_path(item_doc).init().to_vec(); - match decode_inlined_item(cdata, tcx, path, item_doc) { + match decode_inlined_item.call_mut((cdata, tcx, path, item_doc)) { Ok(ii) => csearch::found(ii), Err(path) => { match item_parent_item(item_doc) { Some(did) => { let did = translate_def_id(cdata, did); let parent_item = lookup_item(did.node, cdata.data()); - match decode_inlined_item(cdata, tcx, path, parent_item) { + match decode_inlined_item.call_mut((cdata, tcx, path, parent_item)) { Ok(ii) => csearch::found_parent(did, ii), Err(_) => csearch::not_found } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 75b9a18063e..14ab471a4b8 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -59,9 +59,8 @@ pub enum InlinedItemRef<'a> { pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>; -pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext, - rbml_w: &mut Encoder, - ii: InlinedItemRef|: 'a; +pub type EncodeInlinedItem<'a> = + Box; pub struct EncodeParams<'a, 'tcx: 'a> { pub diag: &'a SpanHandler, @@ -953,7 +952,7 @@ fn encode_inlined_item(ecx: &EncodeContext, ii: InlinedItemRef) { let mut eii = ecx.encode_inlined_item.borrow_mut(); let eii: &mut EncodeInlinedItem = &mut *eii; - (*eii)(ecx, rbml_w, ii) + eii.call_mut((ecx, rbml_w, ii)) } const FN_FAMILY: char = 'f'; @@ -1207,7 +1206,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &Encoder, None => {} } } - ast::ItemImpl(unsafety, _, ref opt_trait, ref ty, ref ast_items) => { + ast::ItemImpl(unsafety, polarity, _, ref opt_trait, ref ty, ref ast_items) => { // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. let impl_items = tcx.impl_items.borrow(); @@ -1221,6 +1220,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &Encoder, encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, item.attrs[]); encode_unsafety(rbml_w, unsafety); + encode_polarity(rbml_w, polarity); match ty.node { ast::TyPath(ref path, _) if path.segments.len() == 1 => { let ident = path.segments.last().unwrap().identifier; @@ -1704,6 +1704,14 @@ fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[ast::Name]) { rbml_w.end_tag(); } +fn encode_polarity(rbml_w: &mut Encoder, polarity: ast::ImplPolarity) { + let byte: u8 = match polarity { + ast::ImplPolarity::Positive => 0, + ast::ImplPolarity::Negative => 1, + }; + rbml_w.wr_tagged_u8(tag_polarity, byte); +} + fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec { // Pull the cnums and name,vers,hash out of cstore @@ -1885,7 +1893,7 @@ struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { - if let ast::ItemImpl(_, _, Some(ref trait_ref), _, _) = item.node { + if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node { let def_map = &self.ecx.tcx.def_map; let trait_def = def_map.borrow()[trait_ref.ref_id].clone(); let def_id = trait_def.def_id(); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 5f554eb9c1e..7c0645b4ca2 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -226,9 +226,8 @@ use syntax::diagnostic::SpanHandler; use util::fs; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cmp; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::io::fs::PathExtensions; use std::io; @@ -400,10 +399,9 @@ fn find_library_crate(&mut self) -> Option { }; info!("lib candidate: {}", path.display()); - let slot = match candidates.entry(hash.to_string()) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.set((HashSet::new(), HashSet::new())), - }; + let hash_str = hash.to_string(); + let slot = candidates.entry(&hash_str).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert((HashSet::new(), HashSet::new()))); let (ref mut rlibs, ref mut dylibs) = *slot; if rlib { rlibs.insert(fs::realpath(path).unwrap()); @@ -722,9 +720,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result Result = - |source: DefIdSource, ast::DefId|: 'a -> ast::DefId; +// type conv_did = impl FnMut(DefIdSource, ast::DefId) -> ast::DefId; pub struct PState<'a, 'tcx: 'a> { data: &'a [u8], @@ -145,70 +144,88 @@ fn data_log_string(data: &[u8], pos: uint) -> String { buf } -pub fn parse_ty_closure_data<'tcx>(data: &[u8], - crate_num: ast::CrateNum, - pos: uint, - tcx: &ty::ctxt<'tcx>, - conv: conv_did) - -> ty::ClosureTy<'tcx> { +pub fn parse_ty_closure_data<'tcx, F>(data: &[u8], + crate_num: ast::CrateNum, + pos: uint, + tcx: &ty::ctxt<'tcx>, + conv: F) + -> ty::ClosureTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_closure_ty(&mut st, conv) } -pub fn parse_ty_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint, - tcx: &ty::ctxt<'tcx>, conv: conv_did) -> Ty<'tcx> { +pub fn parse_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, + tcx: &ty::ctxt<'tcx>, conv: F) -> Ty<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ debug!("parse_ty_data {}", data_log_string(data, pos)); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_ty(&mut st, conv) } -pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, - conv: conv_did) -> ty::Region { +pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, + conv: F) -> ty::Region where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ debug!("parse_region_data {}", data_log_string(data, pos)); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_region(&mut st, conv) } -pub fn parse_bare_fn_ty_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint, - tcx: &ty::ctxt<'tcx>, conv: conv_did) - -> ty::BareFnTy<'tcx> { +pub fn parse_bare_fn_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, + tcx: &ty::ctxt<'tcx>, conv: F) + -> ty::BareFnTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos)); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_bare_fn_ty(&mut st, conv) } -pub fn parse_trait_ref_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint, - tcx: &ty::ctxt<'tcx>, conv: conv_did) - -> Rc> { +pub fn parse_trait_ref_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, + tcx: &ty::ctxt<'tcx>, conv: F) + -> Rc> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ debug!("parse_trait_ref_data {}", data_log_string(data, pos)); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_trait_ref(&mut st, conv) } -pub fn parse_substs_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint, - tcx: &ty::ctxt<'tcx>, conv: conv_did) -> subst::Substs<'tcx> { +pub fn parse_substs_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, + tcx: &ty::ctxt<'tcx>, conv: F) -> subst::Substs<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ debug!("parse_substs_data {}", data_log_string(data, pos)); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_substs(&mut st, conv) } -pub fn parse_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, - pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did) - -> ty::ParamBounds<'tcx> { +pub fn parse_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt<'tcx>, conv: F) + -> ty::ParamBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_bounds(&mut st, conv) } -pub fn parse_existential_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, - pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did) - -> ty::ExistentialBounds<'tcx> { +pub fn parse_existential_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt<'tcx>, conv: F) + -> ty::ExistentialBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_existential_bounds(&mut st, conv) } -pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum, - pos: uint, tcx: &ty::ctxt, conv: conv_did) - -> ty::BuiltinBounds { +pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt, conv: F) + -> ty::BuiltinBounds where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_builtin_bounds(&mut st, conv) } @@ -226,10 +243,12 @@ fn parse_size(st: &mut PState) -> Option { } } -fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore { +fn parse_trait_store_(st: &mut PState, conv: &mut F) -> ty::TraitStore where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ match next(st) { '~' => ty::UniqTraitStore, - '&' => ty::RegionTraitStore(parse_region(st, conv), parse_mutability(st)), + '&' => ty::RegionTraitStore(parse_region_(st, conv), parse_mutability(st)), c => { st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'", c)[]) @@ -253,31 +272,44 @@ fn parse_vec_per_param_space<'a, 'tcx, T, F>(st: &mut PState<'a, 'tcx>, r } -fn parse_substs<'a, 'tcx>(st: &mut PState<'a, 'tcx>, - conv: conv_did) -> subst::Substs<'tcx> { +fn parse_substs<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + mut conv: F) -> subst::Substs<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_substs_(st, &mut conv) +} + +fn parse_substs_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + conv: &mut F) -> subst::Substs<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let regions = - parse_region_substs(st, |x,y| conv(x,y)); + parse_region_substs_(st, conv); let types = - parse_vec_per_param_space(st, |st| parse_ty(st, |x,y| conv(x,y))); + parse_vec_per_param_space(st, |st| parse_ty_(st, conv)); subst::Substs { types: types, regions: regions } } -fn parse_region_substs(st: &mut PState, conv: conv_did) -> subst::RegionSubsts { +fn parse_region_substs_(st: &mut PState, conv: &mut F) -> subst::RegionSubsts where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ match next(st) { 'e' => subst::ErasedRegions, 'n' => { subst::NonerasedRegions( parse_vec_per_param_space( - st, |st| parse_region(st, |x,y| conv(x,y)))) + st, |st| parse_region_(st, conv))) } _ => panic!("parse_bound_region: bad input") } } -fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::BoundRegion { +fn parse_bound_region_(st: &mut PState, conv: &mut F) -> ty::BoundRegion where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ match next(st) { 'a' => { let id = parse_u32(st); @@ -285,7 +317,7 @@ fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::BoundRegion { ty::BrAnon(id) } '[' => { - let def = parse_def(st, RegionParameter, |x,y| conv(x,y)); + let def = parse_def_(st, RegionParameter, conv); let ident = token::str_to_ident(parse_str(st, ']')[]); ty::BrNamed(def, ident.name) } @@ -299,13 +331,21 @@ fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::BoundRegion { } } -fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { +fn parse_region(st: &mut PState, mut conv: F) -> ty::Region where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_region_(st, &mut conv) +} + +fn parse_region_(st: &mut PState, conv: &mut F) -> ty::Region where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ match next(st) { 'b' => { assert_eq!(next(st), '['); let id = ty::DebruijnIndex::new(parse_u32(st)); assert_eq!(next(st), '|'); - let br = parse_bound_region(st, |x,y| conv(x,y)); + let br = parse_bound_region_(st, conv); assert_eq!(next(st), ']'); ty::ReLateBound(id, br) } @@ -324,7 +364,7 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { assert_eq!(next(st), '['); let scope = parse_scope(st); assert_eq!(next(st), '|'); - let br = parse_bound_region(st, |x,y| conv(x,y)); + let br = parse_bound_region_(st, conv); assert_eq!(next(st), ']'); ty::ReFree(ty::FreeRegion { scope: scope, bound_region: br}) @@ -375,14 +415,31 @@ fn parse_str(st: &mut PState, term: char) -> String { result } -fn parse_trait_ref<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) - -> Rc> { - let def = parse_def(st, NominalType, |x,y| conv(x,y)); - let substs = st.tcx.mk_substs(parse_substs(st, |x,y| conv(x,y))); +fn parse_trait_ref<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F) + -> Rc> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_trait_ref_(st, &mut conv) +} + +fn parse_trait_ref_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) + -> Rc> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + let def = parse_def_(st, NominalType, conv); + let substs = st.tcx.mk_substs(parse_substs_(st, conv)); Rc::new(ty::TraitRef {def_id: def, substs: substs}) } -fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { +fn parse_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F) -> Ty<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_ty_(st, &mut conv) +} + +fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let tcx = st.tcx; match next(st) { 'b' => return tcx.types.bool, @@ -406,15 +463,15 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { 'c' => return tcx.types.char, 't' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, |x,y| conv(x,y)); - let substs = parse_substs(st, |x,y| conv(x,y)); + let def = parse_def_(st, NominalType, conv); + let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs)); } 'x' => { assert_eq!(next(st), '['); - let trait_ref = ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))); - let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); + let trait_ref = ty::Binder(parse_trait_ref_(st, conv)); + let bounds = parse_existential_bounds_(st, conv); assert_eq!(next(st), ']'); return ty::mk_trait(tcx, trait_ref, bounds); } @@ -427,15 +484,15 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { let name = token::intern(parse_str(st, ']')[]); return ty::mk_param(tcx, space, index, name); } - '~' => return ty::mk_uniq(tcx, parse_ty(st, |x,y| conv(x,y))), - '*' => return ty::mk_ptr(tcx, parse_mt(st, |x,y| conv(x,y))), + '~' => return ty::mk_uniq(tcx, parse_ty_(st, conv)), + '*' => return ty::mk_ptr(tcx, parse_mt_(st, conv)), '&' => { - let r = parse_region(st, |x,y| conv(x,y)); - let mt = parse_mt(st, |x,y| conv(x,y)); + let r = parse_region_(st, conv); + let mt = parse_mt_(st, conv); return ty::mk_rptr(tcx, tcx.mk_region(r), mt); } 'V' => { - let t = parse_ty(st, |x,y| conv(x,y)); + let t = parse_ty_(st, conv); let sz = parse_size(st); return ty::mk_vec(tcx, t, sz); } @@ -445,21 +502,18 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { 'T' => { assert_eq!(next(st), '['); let mut params = Vec::new(); - while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } + while peek(st) != ']' { params.push(parse_ty_(st, conv)); } st.pos = st.pos + 1u; return ty::mk_tup(tcx, params); } - 'f' => { - return ty::mk_closure(tcx, parse_closure_ty(st, |x,y| conv(x,y))); - } 'F' => { - let def_id = parse_def(st, NominalType, |x,y| conv(x,y)); + let def_id = parse_def_(st, NominalType, conv); return ty::mk_bare_fn(tcx, Some(def_id), - tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y)))); + tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); } 'G' => { return ty::mk_bare_fn(tcx, None, - tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y)))); + tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); } '#' => { let pos = parse_hex(st); @@ -478,34 +532,34 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { pos: pos, .. *st }; - let tt = parse_ty(&mut ps, |x,y| conv(x,y)); + let tt = parse_ty_(&mut ps, conv); tcx.rcache.borrow_mut().insert(key, tt); return tt; } '\"' => { - let _ = parse_def(st, TypeWithId, |x,y| conv(x,y)); - let inner = parse_ty(st, |x,y| conv(x,y)); + let _ = parse_def_(st, TypeWithId, conv); + let inner = parse_ty_(st, conv); inner } 'a' => { assert_eq!(next(st), '['); - let did = parse_def(st, NominalType, |x,y| conv(x,y)); - let substs = parse_substs(st, |x,y| conv(x,y)); + let did = parse_def_(st, NominalType, conv); + let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); return ty::mk_struct(st.tcx, did, st.tcx.mk_substs(substs)); } 'k' => { assert_eq!(next(st), '['); - let did = parse_def(st, UnboxedClosureSource, |x,y| conv(x,y)); - let region = parse_region(st, |x,y| conv(x,y)); - let substs = parse_substs(st, |x,y| conv(x,y)); + let did = parse_def_(st, UnboxedClosureSource, conv); + let region = parse_region_(st, conv); + let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); return ty::mk_unboxed_closure(st.tcx, did, st.tcx.mk_region(region), st.tcx.mk_substs(substs)); } 'P' => { assert_eq!(next(st), '['); - let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); + let trait_ref = parse_trait_ref_(st, conv); let name = token::intern(parse_str(st, ']').as_slice()); return ty::mk_projection(tcx, trait_ref, name); } @@ -523,14 +577,17 @@ fn parse_mutability(st: &mut PState) -> ast::Mutability { } } -fn parse_mt<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::mt<'tcx> { +fn parse_mt_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> ty::mt<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let m = parse_mutability(st); - ty::mt { ty: parse_ty(st, |x,y| conv(x,y)), mutbl: m } + ty::mt { ty: parse_ty_(st, conv), mutbl: m } } -fn parse_def(st: &mut PState, source: DefIdSource, - conv: conv_did) -> ast::DefId { - return conv(source, scan(st, |c| { c == '|' }, parse_def_id)); +fn parse_def_(st: &mut PState, source: DefIdSource, conv: &mut F) -> ast::DefId where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + return (*conv)(source, scan(st, |c| { c == '|' }, parse_def_id)); } fn parse_uint(st: &mut PState) -> uint { @@ -592,13 +649,22 @@ fn parse_onceness(c: char) -> ast::Onceness { } } -fn parse_closure_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, - conv: conv_did) -> ty::ClosureTy<'tcx> { +fn parse_closure_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + mut conv: F) -> ty::ClosureTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_closure_ty_(st, &mut conv) +} + +fn parse_closure_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + conv: &mut F) -> ty::ClosureTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let unsafety = parse_unsafety(next(st)); let onceness = parse_onceness(next(st)); - let store = parse_trait_store(st, |x,y| conv(x,y)); - let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); - let sig = parse_sig(st, |x,y| conv(x,y)); + let store = parse_trait_store_(st, conv); + let bounds = parse_existential_bounds_(st, conv); + let sig = parse_sig_(st, conv); let abi = parse_abi_set(st); ty::ClosureTy { unsafety: unsafety, @@ -610,11 +676,20 @@ fn parse_closure_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, } } -fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, - conv: conv_did) -> ty::BareFnTy<'tcx> { +fn parse_bare_fn_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + mut conv: F) -> ty::BareFnTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_bare_fn_ty_(st, &mut conv) +} + +fn parse_bare_fn_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, + conv: &mut F) -> ty::BareFnTy<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let unsafety = parse_unsafety(next(st)); let abi = parse_abi_set(st); - let sig = parse_sig(st, |x,y| conv(x,y)); + let sig = parse_sig_(st, conv); ty::BareFnTy { unsafety: unsafety, abi: abi, @@ -622,11 +697,13 @@ fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, } } -fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnSig<'tcx> { +fn parse_sig_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> ty::PolyFnSig<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ assert_eq!(next(st), '['); let mut inputs = Vec::new(); while peek(st) != ']' { - inputs.push(parse_ty(st, |x,y| conv(x,y))); + inputs.push(parse_ty_(st, conv)); } st.pos += 1u; // eat the ']' let variadic = match next(st) { @@ -639,7 +716,7 @@ fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnS st.pos += 1u; ty::FnDiverging } - _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y))) + _ => ty::FnConverging(parse_ty_(st, conv)) }; ty::Binder(ty::FnSig {inputs: inputs, output: output, @@ -672,66 +749,87 @@ pub fn parse_def_id(buf: &[u8]) -> ast::DefId { ast::DefId { krate: crate_num, node: def_num } } -pub fn parse_predicate_data<'tcx>(data: &[u8], - start: uint, - crate_num: ast::CrateNum, - tcx: &ty::ctxt<'tcx>, - conv: conv_did) - -> ty::Predicate<'tcx> +pub fn parse_predicate_data<'tcx, F>(data: &[u8], + start: uint, + crate_num: ast::CrateNum, + tcx: &ty::ctxt<'tcx>, + conv: F) + -> ty::Predicate<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { let mut st = parse_state_from_data(data, crate_num, start, tcx); parse_predicate(&mut st, conv) } -pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, - conv: conv_did) - -> ty::Predicate<'tcx> +pub fn parse_predicate<'a,'tcx, F>(st: &mut PState<'a, 'tcx>, + mut conv: F) + -> ty::Predicate<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_predicate_(st, &mut conv) +} + +fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>, + conv: &mut F) + -> ty::Predicate<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { match next(st) { - 't' => ty::Binder(parse_trait_ref(st, conv)).as_predicate(), - 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)), - parse_ty(st, |x,y| conv(x,y)))).as_predicate(), - 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y)))).as_predicate(), - 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y)))).as_predicate(), - 'p' => ty::Binder(parse_projection_predicate(st, conv)).as_predicate(), + 't' => ty::Binder(parse_trait_ref_(st, conv)).as_predicate(), + 'e' => ty::Binder(ty::EquatePredicate(parse_ty_(st, conv), + parse_ty_(st, conv))).as_predicate(), + 'r' => ty::Binder(ty::OutlivesPredicate(parse_region_(st, conv), + parse_region_(st, conv))).as_predicate(), + 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv), + parse_region_(st, conv))).as_predicate(), + 'p' => ty::Binder(parse_projection_predicate_(st, conv)).as_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } -fn parse_projection_predicate<'a,'tcx>( +fn parse_projection_predicate_<'a,'tcx, F>( st: &mut PState<'a, 'tcx>, - conv: conv_did) - -> ty::ProjectionPredicate<'tcx> + conv: &mut F, +) -> ty::ProjectionPredicate<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { - trait_ref: parse_trait_ref(st, |x,y| conv(x,y)), + trait_ref: parse_trait_ref_(st, conv), item_name: token::str_to_ident(parse_str(st, '|').as_slice()).name, }, - ty: parse_ty(st, |x,y| conv(x,y)), + ty: parse_ty_(st, conv), } } -pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint, - crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>, - conv: conv_did) -> ty::TypeParameterDef<'tcx> +pub fn parse_type_param_def_data<'tcx, F>(data: &[u8], start: uint, + crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>, + conv: F) -> ty::TypeParameterDef<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { let mut st = parse_state_from_data(data, crate_num, start, tcx); parse_type_param_def(&mut st, conv) } -fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) - -> ty::TypeParameterDef<'tcx> { +fn parse_type_param_def<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F) + -> ty::TypeParameterDef<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_type_param_def_(st, &mut conv) +} + +fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) + -> ty::TypeParameterDef<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let name = parse_name(st, ':'); - let def_id = parse_def(st, NominalType, |x,y| conv(x,y)); + let def_id = parse_def_(st, NominalType, conv); let space = parse_param_space(st); assert_eq!(next(st), '|'); let index = parse_u32(st); assert_eq!(next(st), '|'); - let bounds = parse_bounds(st, |x,y| conv(x,y)); - let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))); + let bounds = parse_bounds_(st, conv); + let default = parse_opt(st, |st| parse_ty_(st, conv)); ty::TypeParameterDef { name: name, @@ -743,12 +841,21 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) } } -fn parse_existential_bounds<'a,'tcx>(st: &mut PState<'a,'tcx>, - conv: conv_did) - -> ty::ExistentialBounds<'tcx> +fn parse_existential_bounds<'a,'tcx, F>(st: &mut PState<'a,'tcx>, + mut conv: F) + -> ty::ExistentialBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_existential_bounds_(st, &mut conv) +} + +fn parse_existential_bounds_<'a,'tcx, F>(st: &mut PState<'a,'tcx>, + conv: &mut F) + -> ty::ExistentialBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { let ty::ParamBounds { trait_bounds, mut region_bounds, builtin_bounds, projection_bounds } = - parse_bounds(st, conv); + parse_bounds_(st, conv); assert_eq!(region_bounds.len(), 1); assert_eq!(trait_bounds.len(), 0); let region_bound = region_bounds.pop().unwrap(); @@ -757,7 +864,15 @@ fn parse_existential_bounds<'a,'tcx>(st: &mut PState<'a,'tcx>, projection_bounds: projection_bounds }; } -fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds { +fn parse_builtin_bounds(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_builtin_bounds_(st, &mut _conv) +} + +fn parse_builtin_bounds_(st: &mut PState, _conv: &mut F) -> ty::BuiltinBounds where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ let mut builtin_bounds = ty::empty_builtin_bounds(); loop { @@ -784,9 +899,18 @@ fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds { } } -fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) - -> ty::ParamBounds<'tcx> { - let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y)); +fn parse_bounds<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F) + -> ty::ParamBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + parse_bounds_(st, &mut conv) +} + +fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) + -> ty::ParamBounds<'tcx> where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + let builtin_bounds = parse_builtin_bounds_(st, conv); let mut param_bounds = ty::ParamBounds { region_bounds: Vec::new(), @@ -798,15 +922,15 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) match next(st) { 'R' => { param_bounds.region_bounds.push( - parse_region(st, |x, y| conv (x, y))); + parse_region_(st, conv)); } 'I' => { param_bounds.trait_bounds.push( - ty::Binder(parse_trait_ref(st, |x,y| conv(x,y)))); + ty::Binder(parse_trait_ref_(st, conv))); } 'P' => { param_bounds.projection_bounds.push( - ty::Binder(parse_projection_predicate(st, |x,y| conv(x,y)))); + ty::Binder(parse_projection_predicate_(st, conv))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 5f0f51ce903..0042209aced 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -119,10 +119,6 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t ty::ty_str => { mywrite!(w, "v"); } - ty::ty_closure(ref f) => { - mywrite!(w, "f"); - enc_closure_ty(w, cx, &**f); - } ty::ty_bare_fn(Some(def_id), f) => { mywrite!(w, "F"); mywrite!(w, "{}|", (cx.ds)(def_id)); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e4d407d66a2..93a19a01f66 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -263,18 +263,27 @@ trait def_id_encoder_helpers { fn emit_def_id(&mut self, did: ast::DefId); } +#[cfg(stage0)] impl, E> def_id_encoder_helpers for S { fn emit_def_id(&mut self, did: ast::DefId) { did.encode(self).ok().unwrap() } } +#[cfg(not(stage0))] +impl def_id_encoder_helpers for S { + fn emit_def_id(&mut self, did: ast::DefId) { + did.encode(self).ok().unwrap() + } +} + trait def_id_decoder_helpers { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId; fn read_def_id_nodcx(&mut self, cdata: &cstore::crate_metadata) -> ast::DefId; } +#[cfg(stage0)] impl, E> def_id_decoder_helpers for D { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { let did: ast::DefId = Decodable::decode(self).ok().unwrap(); @@ -288,6 +297,20 @@ fn read_def_id_nodcx(&mut self, } } +#[cfg(not(stage0))] +impl def_id_decoder_helpers for D { + fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + did.tr(dcx) + } + + fn read_def_id_nodcx(&mut self, + cdata: &cstore::crate_metadata) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + decoder::translate_def_id(cdata, did) + } +} + // ______________________________________________________________________ // Encoding and decoding the AST itself // @@ -1008,13 +1031,6 @@ fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, self.emit_enum("AutoAdjustment", |this| { match *adj { - ty::AdjustAddEnv(def_id, store) => { - this.emit_enum_variant("AdjustAddEnv", 0, 2, |this| { - this.emit_enum_variant_arg(0, |this| def_id.encode(this)); - this.emit_enum_variant_arg(1, |this| store.encode(this)) - }) - } - ty::AdjustReifyFnPointer(def_id) => { this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| { this.emit_enum_variant_arg(0, |this| def_id.encode(this)) @@ -1655,14 +1671,6 @@ fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) let variants = ["AutoAddEnv", "AutoDerefRef"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { - 0 => { - let def_id: ast::DefId = - this.read_def_id(dcx); - let store: ty::TraitStore = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - ty::AdjustAddEnv(def_id, store.tr(dcx)) - } 1 => { let def_id: ast::DefId = this.read_def_id(dcx); diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index ff5175ffdcf..de81f307c4d 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -509,7 +509,7 @@ fn call<'b, I: Iterator>(&mut self, let method_call = ty::MethodCall::expr(call_expr.id); let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) { Some(method) => method.ty, - None => ty::expr_ty(self.tcx, func_or_rcvr) + None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr) }); let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 06fef66c1e0..8a2ecbca20d 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -60,16 +60,16 @@ fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { if i == self.cfg.entry { - dot::LabelStr("entry".into_cow()) + dot::LabelText::LabelStr("entry".into_cow()) } else if i == self.cfg.exit { - dot::LabelStr("exit".into_cow()) + dot::LabelText::LabelStr("exit".into_cow()) } else if n.data.id == ast::DUMMY_NODE_ID { - dot::LabelStr("(dummy_node)".into_cow()) + dot::LabelText::LabelStr("(dummy_node)".into_cow()) } else { let s = self.ast_map.node_to_string(n.data.id); // left-aligns the lines let s = replace_newline_with_backslash_l(s); - dot::EscStr(s.into_cow()) + dot::LabelText::EscStr(s.into_cow()) } } @@ -87,7 +87,7 @@ fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { let s = replace_newline_with_backslash_l(s); label.push_str(format!("exiting scope_{} {}", i, s[])[]); } - dot::EscStr(label.into_cow()) + dot::LabelText::EscStr(label.into_cow()) } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6277656e03a..ac53bdbefcf 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -14,9 +14,7 @@ use util::ppaux; use syntax::ast; -use syntax::ast_util; -use syntax::visit::Visitor; -use syntax::visit; +use syntax::visit::{self, Visitor}; struct CheckCrateVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, @@ -37,24 +35,39 @@ fn inside_const(&mut self, f: F) where { self.with_const(true, f); } - fn outside_const(&mut self, f: F) where - F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>), - { - self.with_const(false, f); - } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { - check_item(self, i); + match i.node { + ast::ItemStatic(_, _, ref ex) | + ast::ItemConst(_, ref ex) => { + self.inside_const(|v| v.visit_expr(&**ex)); + } + ast::ItemEnum(ref enum_definition, _) => { + self.inside_const(|v| { + for var in enum_definition.variants.iter() { + if let Some(ref ex) = var.node.disr_expr { + v.visit_expr(&**ex); + } + } + }); + } + _ => self.with_const(false, |v| visit::walk_item(v, i)) + } } fn visit_pat(&mut self, p: &ast::Pat) { - check_pat(self, p); + let is_const = match p.node { + ast::PatLit(_) | ast::PatRange(..) => true, + _ => false + }; + self.with_const(is_const, |v| visit::walk_pat(v, p)) } fn visit_expr(&mut self, ex: &ast::Expr) { - if check_expr(self, ex) { - visit::walk_expr(self, ex); + if self.in_const { + check_expr(self, ex); } + visit::walk_expr(self, ex); } } @@ -64,57 +77,13 @@ pub fn check_crate(tcx: &ty::ctxt) { tcx.sess.abort_if_errors(); } -fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) { - match it.node { - ast::ItemStatic(_, _, ref ex) | - ast::ItemConst(_, ref ex) => { - v.inside_const(|v| v.visit_expr(&**ex)); - } - ast::ItemEnum(ref enum_definition, _) => { - for var in (*enum_definition).variants.iter() { - for ex in var.node.disr_expr.iter() { - v.inside_const(|v| v.visit_expr(&**ex)); - } - } - } - _ => v.outside_const(|v| visit::walk_item(v, it)) - } -} - -fn check_pat(v: &mut CheckCrateVisitor, p: &ast::Pat) { - fn is_str(e: &ast::Expr) -> bool { - match e.node { - ast::ExprBox(_, ref expr) => { - match expr.node { - ast::ExprLit(ref lit) => ast_util::lit_is_str(&**lit), - _ => false, - } - } - _ => false, - } - } - match p.node { - // Let through plain ~-string literals here - ast::PatLit(ref a) => if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); }, - ast::PatRange(ref a, ref b) => { - if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); } - if !is_str(&**b) { v.inside_const(|v| v.visit_expr(&**b)); } - } - _ => v.outside_const(|v| visit::walk_pat(v, p)) - } -} - -fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { - if !v.in_const { return true } - +fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { match e.node { ast::ExprUnary(ast::UnDeref, _) => {} ast::ExprUnary(ast::UnUniq, _) => { span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions"); - return false; } - ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {} ast::ExprBinary(..) | ast::ExprUnary(..) => { let method_call = ty::MethodCall::expr(e.id); if v.tcx.method_map.borrow().contains_key(&method_call) { @@ -123,7 +92,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { expressions"); } } - ast::ExprLit(_) => (), + ast::ExprLit(_) => {} ast::ExprCast(ref from, _) => { let toty = ty::expr_ty(v.tcx, e); let fromty = ty::expr_ty(v.tcx, &**from); @@ -142,39 +111,23 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { expression"); } } - ast::ExprPath(ref pth) => { - // NB: In the future you might wish to relax this slightly - // to handle on-demand instantiation of functions via - // foo:: in a const. Currently that is only done on - // a path in trans::callee that only works in block contexts. - if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) { - span_err!(v.tcx.sess, e.span, E0013, - "paths in constants may only refer to items without \ - type parameters"); - } - match v.tcx.def_map.borrow().get(&e.id) { - Some(&DefStatic(..)) | - Some(&DefConst(..)) | - Some(&DefFn(..)) | - Some(&DefVariant(_, _, _)) | - Some(&DefStruct(_)) => { } + ast::ExprPath(_) => { + match v.tcx.def_map.borrow()[e.id] { + DefStatic(..) | DefConst(..) | + DefFn(..) | DefStaticMethod(..) | DefMethod(..) | + DefStruct(_) | DefVariant(_, _, _) => {} - Some(&def) => { + def => { debug!("(checking const) found bad def: {}", def); span_err!(v.tcx.sess, e.span, E0014, "paths in constants may only refer to constants \ or functions"); } - None => { - v.tcx.sess.span_bug(e.span, "unbound path in const?!"); - } } } ast::ExprCall(ref callee, _) => { - match v.tcx.def_map.borrow().get(&callee.id) { - Some(&DefStruct(..)) | - Some(&DefVariant(..)) => {} // OK. - + match v.tcx.def_map.borrow()[callee.id] { + DefStruct(..) | DefVariant(..) => {} // OK. _ => { span_err!(v.tcx.sess, e.span, E0015, "function calls in constants are limited to \ @@ -190,9 +143,9 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { "blocks in constants are limited to items and \ tail expressions"); match stmt.node { - ast::StmtDecl(ref span, _) => { - match span.node { - ast::DeclLocal(_) => block_span_err(span.span), + ast::StmtDecl(ref decl, _) => { + match decl.node { + ast::DeclLocal(_) => block_span_err(decl.span), // Item statements are allowed ast::DeclItem(_) => {} @@ -206,10 +159,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { } } } - match block.expr { - Some(ref expr) => { check_expr(v, &**expr); } - None => {} - } } ast::ExprVec(_) | ast::ExprAddrOf(ast::MutImmutable, _) | @@ -232,11 +181,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { } } - _ => { - span_err!(v.tcx.sess, e.span, E0019, - "constant contains unimplemented expression type"); - return false; - } + _ => span_err!(v.tcx.sess, e.span, E0019, + "constant contains unimplemented expression type") } - true } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index a62b134c48e..a95523f2e06 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -132,7 +132,7 @@ fn variant_expr<'a>(variants: &'a [P], id: ast::NodeId) None => {} } let expr_id = match csearch::maybe_get_item_ast(tcx, enum_def, - |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) { + box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) { csearch::found(&ast::IIItem(ref item)) => match item.node { ast::ItemEnum(ast::EnumDef { ref variants }, _) => { // NOTE this doesn't do the right thing, it compares inlined @@ -172,7 +172,7 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId) None => {} } let expr_id = match csearch::maybe_get_item_ast(tcx, def_id, - |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) { + box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) { csearch::found(&ast::IIItem(ref item)) => match item.node { ast::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None @@ -311,8 +311,8 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P { ast::ExprCall(ref callee, ref args) => { let def = tcx.def_map.borrow()[callee.id].clone(); - if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) { - entry.set(def); + if let Vacant(entry) = tcx.def_map.borrow_mut().entry(&expr.id) { + entry.insert(def); } let path = match def { def::DefStruct(def_id) => def_to_path(tcx, def_id), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 5a2085bee24..2e40bdd001a 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -355,7 +355,7 @@ fn visit_item(&mut self, item: &ast::Item) { ast::ItemEnum(ref enum_def, _) if allow_dead_code => { self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id)); } - ast::ItemImpl(_, _, Some(ref _trait_ref), _, ref impl_items) => { + ast::ItemImpl(_, _, _, Some(ref _trait_ref), _, ref impl_items) => { for impl_item in impl_items.iter() { match *impl_item { ast::MethodImplItem(ref method) => { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 1075263e751..f7eea6e5cb7 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -33,7 +33,6 @@ enum UnsafeContext { fn type_is_unsafe_function(ty: Ty) -> bool { match ty.sty { ty::ty_bare_fn(_, ref f) => f.unsafety == ast::Unsafety::Unsafe, - ty::ty_closure(ref f) => f.unsafety == ast::Unsafety::Unsafe, _ => false, } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5b786ec9922..df2a4e4c253 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -656,19 +656,6 @@ fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) { ty::ty_bare_fn(..) => { self.consume_expr(callee); } - ty::ty_closure(ref f) => { - match f.onceness { - ast::Many => { - self.borrow_expr(callee, - ty::ReScope(call_scope), - ty::UniqueImmBorrow, - ClosureInvocation); - } - ast::Once => { - self.consume_expr(callee); - } - } - } ty::ty_err => { } _ => { let overloaded_call_type = @@ -836,7 +823,6 @@ fn walk_adjustment(&mut self, expr: &ast::Expr) { None => { } Some(adjustment) => { match *adjustment { - ty::AdjustAddEnv(..) | ty::AdjustReifyFnPointer(..) => { // Creating a closure/fn-pointer consumes the // input and stores it into the resulting diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index d42817bce93..42bc70b5b56 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -80,9 +80,6 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_tup(ref tys) => { Some(TupleSimplifiedType(tys.len())) } - ty::ty_closure(ref f) => { - Some(FunctionSimplifiedType(f.sig.0.inputs.len())) - } ty::ty_bare_fn(_, ref f) => { Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index f6f62e03590..65de3a083d2 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -71,7 +71,6 @@ use util::ppaux; use util::ppaux::Repr; -use syntax::abi; use syntax::ast; // Note: Coerce is not actually a combiner, in that it does not @@ -160,15 +159,6 @@ pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { }; } - ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(..), - .. - }) => { - return self.unpack_actual_value(a, |a| { - self.coerce_borrowed_fn(a, b) - }); - } - _ => {} } @@ -511,21 +501,6 @@ fn coerce_from_fn_item(&self, a.repr(self.tcx()), b.repr(self.tcx())); match b.sty { - ty::ty_closure(ref f) => { - if fn_ty_a.abi != abi::Rust || fn_ty_a.unsafety != ast::Unsafety::Normal { - return self.subtype(a, b); - } - - let fn_ty_b = (*f).clone(); - let adj = ty::AdjustAddEnv(fn_def_id_a, fn_ty_b.store); - let a_closure = ty::mk_closure(self.tcx(), - ty::ClosureTy { - sig: fn_ty_a.sig.clone(), - .. *fn_ty_b - }); - try!(self.subtype(a_closure, b)); - Ok(Some(adj)) - } ty::ty_bare_fn(None, _) => { let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 29507058761..dd711fcbf02 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -644,12 +644,6 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) } - (&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => { - this.closure_tys(&**a_fty, &**b_fty).and_then(|fty| { - Ok(ty::mk_closure(tcx, fty)) - }) - } - (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => { let projection_ty = try!(this.projection_tys(a_data, b_data)); Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 7ff585087f5..e58ff53b00c 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -66,7 +66,8 @@ use super::region_inference::ConcreteFailure; use super::region_inference::SubSupConflict; use super::region_inference::SupSupConflict; -use super::region_inference::ParamBoundFailure; +use super::region_inference::GenericBoundFailure; +use super::region_inference::GenericKind; use super::region_inference::ProcessedErrors; use super::region_inference::SameRegions; @@ -120,11 +121,11 @@ fn report_concrete_failure(&self, sub: Region, sup: Region); - fn report_param_bound_failure(&self, - origin: SubregionOrigin<'tcx>, - param_ty: ty::ParamTy, - sub: Region, - sups: Vec); + fn report_generic_bound_failure(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + sub: Region, + sups: Vec); fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, @@ -175,8 +176,8 @@ fn report_region_errors(&self, self.report_concrete_failure(origin, sub, sup); } - ParamBoundFailure(origin, param_ty, sub, sups) => { - self.report_param_bound_failure(origin, param_ty, sub, sups); + GenericBoundFailure(kind, param_ty, sub, sups) => { + self.report_generic_bound_failure(kind, param_ty, sub, sups); } SubSupConflict(var_origin, @@ -421,30 +422,35 @@ fn expected_found_str + Resolvable<'tcx>>( found.user_string(self.tcx))) } - fn report_param_bound_failure(&self, - origin: SubregionOrigin<'tcx>, - param_ty: ty::ParamTy, - sub: Region, - _sups: Vec) { - + fn report_generic_bound_failure(&self, + origin: SubregionOrigin<'tcx>, + bound_kind: GenericKind<'tcx>, + sub: Region, + _sups: Vec) + { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span // where the error was detected. But that span is not readily // accessible. + let labeled_user_string = match bound_kind { + GenericKind::Param(ref p) => + format!("the parameter type `{}`", p.user_string(self.tcx)), + GenericKind::Projection(ref p) => + format!("the associated type `{}`", p.user_string(self.tcx)), + }; + match sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? self.tcx.sess.span_err( origin.span(), - format!( - "the parameter type `{}` may not live long enough", - param_ty.user_string(self.tcx))[]); + format!("{} may not live long enough", labeled_user_string)[]); self.tcx.sess.span_help( origin.span(), format!( "consider adding an explicit lifetime bound `{}: {}`...", - param_ty.user_string(self.tcx), + bound_kind.user_string(self.tcx), sub.user_string(self.tcx))[]); } @@ -452,14 +458,12 @@ fn report_param_bound_failure(&self, // Does the required lifetime have a nice name we can print? self.tcx.sess.span_err( origin.span(), - format!( - "the parameter type `{}` may not live long enough", - param_ty.user_string(self.tcx))[]); + format!("{} may not live long enough", labeled_user_string)[]); self.tcx.sess.span_help( origin.span(), format!( "consider adding an explicit lifetime bound `{}: 'static`...", - param_ty.user_string(self.tcx))[]); + bound_kind.user_string(self.tcx))[]); } _ => { @@ -467,17 +471,16 @@ fn report_param_bound_failure(&self, self.tcx.sess.span_err( origin.span(), format!( - "the parameter type `{}` may not live long enough", - param_ty.user_string(self.tcx))[]); + "{} may not live long enough", + labeled_user_string)[]); self.tcx.sess.span_help( origin.span(), format!( - "consider adding an explicit lifetime bound to `{}`", - param_ty.user_string(self.tcx))[]); + "consider adding an explicit lifetime bound for `{}`", + bound_kind.user_string(self.tcx))[]); note_and_explain_region( self.tcx, - format!("the parameter type `{}` must be valid for ", - param_ty.user_string(self.tcx))[], + format!("{} must be valid for ", labeled_user_string)[], sub, "..."); } @@ -1712,7 +1715,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt, match tcx.map.find(parent) { Some(node) => match node { ast_map::NodeItem(item) => match item.node { - ast::ItemImpl(_, ref gen, _, _, _) => { + ast::ItemImpl(_, _, ref gen, _, _, _) => { taken.push_all(gen.lifetimes.as_slice()); } _ => () diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 0ae4a3d851e..608ae314753 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -66,13 +66,13 @@ fn freshen(&mut self, None => { } } - match self.freshen_map.entry(key) { + match self.freshen_map.entry(&key) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let index = self.freshen_count; self.freshen_count += 1; let t = ty::mk_infer(self.infcx.tcx, freshener(index)); - entry.set(t); + entry.insert(t); t } } @@ -152,7 +152,6 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { ty::ty_ptr(..) | ty::ty_rptr(..) | ty::ty_bare_fn(..) | - ty::ty_closure(..) | ty::ty_trait(..) | ty::ty_struct(..) | ty::ty_unboxed_closure(..) | diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index e1401898f7a..c2db81d3114 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -20,6 +20,7 @@ pub use self::fixup_err::*; pub use middle::ty::IntVarValue; pub use self::freshen::TypeFreshener; +pub use self::region_inference::GenericKind; use middle::subst; use middle::subst::Substs; @@ -382,19 +383,6 @@ pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, cx.region_vars.commit(snapshot); } -pub fn verify_param_bound<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - origin: SubregionOrigin<'tcx>, - param_ty: ty::ParamTy, - a: ty::Region, - bs: Vec) { - debug!("verify_param_bound({}, {} <: {})", - param_ty.repr(cx.tcx), - a.repr(cx.tcx), - bs.repr(cx.tcx)); - - cx.region_vars.verify_param_bound(origin, param_ty, a, bs); -} - pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, origin: TypeOrigin, @@ -1070,6 +1058,20 @@ pub fn replace_late_bound_regions_with_fresh_var( value, |br, _| self.next_region_var(LateBoundRegion(span, br, lbrct))) } + + /// See `verify_generic_bound` method in `region_inference` + pub fn verify_generic_bound(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region, + bs: Vec) { + debug!("verify_generic_bound({}, {} <: {})", + kind.repr(self.tcx), + a.repr(self.tcx), + bs.repr(self.tcx)); + + self.region_vars.verify_generic_bound(origin, kind, a, bs); + } } impl<'tcx> TypeTrace<'tcx> { diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 2bf32e7bdae..98c69962bc2 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -137,8 +137,8 @@ fn new(tcx: &'a ty::ctxt<'tcx>, let mut node_ids = FnvHashMap::new(); { let mut add_node = |&mut : node| { - if let Vacant(e) = node_ids.entry(node) { - e.set(i); + if let Vacant(e) = node_ids.entry(&node) { + e.insert(i); i += 1; } }; diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index f0ee63c08e8..23e96dafa61 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -22,7 +22,7 @@ use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use middle::region; -use middle::ty; +use middle::ty::{mod, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; @@ -30,7 +30,7 @@ use middle::graph::{Direction, NodeIndex}; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; -use util::ppaux::Repr; +use util::ppaux::{Repr, UserString}; use std::cell::{Cell, RefCell}; use std::cmp::Ordering::{self, Less, Greater, Equal}; @@ -61,12 +61,18 @@ pub enum Verify<'tcx> { // `b` are inference variables. VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region), - // VerifyParamBound(T, _, R, RS): The parameter type `T` must - // outlive the region `R`. `T` is known to outlive `RS`. Therefore - // verify that `R <= RS[i]` for some `i`. Inference variables may - // be involved (but this verification step doesn't influence - // inference). - VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec), + // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or + // associated type) must outlive the region `R`. `T` is known to + // outlive `RS`. Therefore verify that `R <= RS[i]` for some + // `i`. Inference variables may be involved (but this verification + // step doesn't influence inference). + VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec), +} + +#[deriving(Clone, Show, PartialEq, Eq)] +pub enum GenericKind<'tcx> { + Param(ty::ParamTy), + Projection(ty::ProjectionTy<'tcx>), } #[derive(Copy, PartialEq, Eq, Hash)] @@ -98,12 +104,12 @@ pub enum RegionResolutionError<'tcx> { /// `o` requires that `a <= b`, but this does not hold ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), - /// `ParamBoundFailure(p, s, a, bs) + /// `GenericBoundFailure(p, s, a, bs) /// - /// The parameter type `p` must be known to outlive the lifetime + /// The parameter/assocated-type `p` must be known to outlive the lifetime /// `a`, but it is only known to outlive `bs` (and none of the /// regions in `bs` outlive `a`). - ParamBoundFailure(SubregionOrigin<'tcx>, ty::ParamTy, Region, Vec), + GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec), /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// @@ -489,12 +495,13 @@ pub fn make_subregion(&self, } } - pub fn verify_param_bound(&self, - origin: SubregionOrigin<'tcx>, - param_ty: ty::ParamTy, - sub: Region, - sups: Vec) { - self.add_verify(VerifyParamBound(param_ty, origin, sub, sups)); + /// See `Verify::VerifyGenericBound` + pub fn verify_generic_bound(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + sub: Region, + sups: Vec) { + self.add_verify(VerifyGenericBound(kind, origin, sub, sups)); } pub fn lub_regions(&self, @@ -660,7 +667,7 @@ pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { &mut result_set, r, a, b); } - VerifyParamBound(_, _, a, ref bs) => { + VerifyGenericBound(_, _, a, ref bs) => { for &b in bs.iter() { consider_adding_bidirectional_edges( &mut result_set, r, @@ -1211,7 +1218,7 @@ fn collect_concrete_region_errors(&self, errors.push(ConcreteFailure((*origin).clone(), sub, sup)); } - VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => { + VerifyGenericBound(ref kind, ref origin, sub, ref sups) => { let sub = normalize(values, sub); if sups.iter() .map(|&sup| normalize(values, sup)) @@ -1223,8 +1230,8 @@ fn collect_concrete_region_errors(&self, let sups = sups.iter().map(|&sup| normalize(values, sup)) .collect(); errors.push( - ParamBoundFailure( - (*origin).clone(), *param_ty, sub, sups)); + GenericBoundFailure( + (*origin).clone(), kind.clone(), sub, sups)); } } } @@ -1584,8 +1591,8 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { VerifyRegSubReg(_, ref a, ref b) => { format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx)) } - VerifyParamBound(_, ref p, ref a, ref bs) => { - format!("VerifyParamBound({}, {}, {})", + VerifyGenericBound(_, ref p, ref a, ref bs) => { + format!("VerifyGenericBound({}, {}, {})", p.repr(tcx), a.repr(tcx), bs.repr(tcx)) } } @@ -1624,3 +1631,32 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { self.origin.repr(tcx)) } } + +impl<'tcx> Repr<'tcx> for GenericKind<'tcx> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + match *self { + GenericKind::Param(ref p) => p.repr(tcx), + GenericKind::Projection(ref p) => p.repr(tcx), + } + } +} + +impl<'tcx> UserString<'tcx> for GenericKind<'tcx> { + fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String { + match *self { + GenericKind::Param(ref p) => p.user_string(tcx), + GenericKind::Projection(ref p) => p.user_string(tcx), + } + } +} + +impl<'tcx> GenericKind<'tcx> { + pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + GenericKind::Param(ref p) => + p.to_ty(tcx), + GenericKind::Projection(ref p) => + ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name), + } + } +} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 75d5b4fd7f9..77875139be3 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1149,7 +1149,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode) ast::ExprCall(ref f, ref args) => { let diverges = !self.ir.tcx.is_method_call(expr.id) && { - let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f)); + let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f)); t_ret == ty::FnDiverging }; let succ = if diverges { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8325cebf1ed..dd61db4270c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -197,8 +197,7 @@ pub enum deref_kind { // pointer adjustment). pub fn deref_kind(t: Ty) -> McResult { match t.sty { - ty::ty_uniq(_) | - ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => { + ty::ty_uniq(_) => { Ok(deref_ptr(Unique)) } @@ -207,13 +206,6 @@ pub fn deref_kind(t: Ty) -> McResult { Ok(deref_ptr(BorrowedPtr(kind, *r))) } - ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(r, _), - .. - }) => { - Ok(deref_ptr(BorrowedPtr(ty::ImmBorrow, r))) - } - ty::ty_ptr(ref mt) => { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } @@ -421,8 +413,8 @@ pub fn cat_expr(&self, expr: &ast::Expr) -> McResult> { Some(adjustment) => { match *adjustment { - ty::AdjustAddEnv(..) | ty::AdjustReifyFnPointer(..) => { - debug!("cat_expr(AdjustAddEnv|AdjustReifyFnPointer): {}", + ty::AdjustReifyFnPointer(..) => { + debug!("cat_expr(AdjustReifyFnPointer): {}", expr.repr(self.tcx())); // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. @@ -559,14 +551,14 @@ pub fn cat_def(&self, id, expr_ty.repr(self.tcx()), def); match def { - def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) | - def::DefStaticMethod(..) | def::DefConst(..) => { + def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) | + def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | - def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) | + def::DefLabel(_) | def::DefSelfTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> { Ok(Rc::new(cmt_ { id:id, @@ -592,25 +584,6 @@ pub fn cat_def(&self, def::DefUpvar(var_id, fn_node_id, _) => { let ty = try!(self.node_ty(fn_node_id)); match ty.sty { - ty::ty_closure(ref closure_ty) => { - // Translate old closure type info into unboxed - // closure kind/capture mode - let (mode, kind) = match (closure_ty.store, closure_ty.onceness) { - // stack closure - (ty::RegionTraitStore(..), ast::Many) => { - (ast::CaptureByRef, ty::FnMutUnboxedClosureKind) - } - // proc or once closure - (_, ast::Once) => { - (ast::CaptureByValue, ty::FnOnceUnboxedClosureKind) - } - // There should be no such old closure type - (ty::UniqTraitStore, ast::Many) => { - self.tcx().sess.span_bug(span, "Impossible closure type"); - } - }; - self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false) - } ty::ty_unboxed_closure(closure_id, _, _) => { let kind = self.typer.unboxed_closure_kind(closure_id); let mode = self.typer.capture_mode(fn_node_id); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index e6665699b7b..50e328ef0e3 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -287,7 +287,7 @@ fn visit_item(&mut self, item: &ast::Item) { // undefined symbols at linkage time if this case is not handled. // // * Private trait impls for private types can be completely ignored - ast::ItemImpl(_, _, _, ref ty, ref impl_items) => { + ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => { let public_ty = match ty.node { ast::TyPath(_, id) => { match self.tcx.def_map.borrow()[id].clone() { @@ -657,7 +657,7 @@ fn ensure_public(&self, span: Span, to_check: ast::DefId, // invoked, and the struct/enum itself is private. Crawl // back up the chains to find the relevant struct/enum that // was private. - ast::ItemImpl(_, _, _, ref ty, _) => { + ast::ItemImpl(_, _, _, _, ref ty, _) => { let id = match ty.node { ast::TyPath(_, id) => id, _ => return Some((err_span, err_msg, None)), @@ -750,7 +750,7 @@ fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) { debug!("privacy - path {}", self.nodestr(path_id)); let orig_def = self.tcx.def_map.borrow()[path_id].clone(); let ck = |&: tyname: &str| { - let ck_public = |def: ast::DefId| { + let ck_public = |&: def: ast::DefId| { let name = token::get_ident(path.segments.last().unwrap().identifier); let origdid = orig_def.def_id(); self.ensure_public(span, @@ -1137,7 +1137,7 @@ fn check_sane_privacy(&self, item: &ast::Item) { match item.node { // implementations of traits don't need visibility qualifiers because // that's controlled by having the trait in scope. - ast::ItemImpl(_, _, Some(..), _, ref impl_items) => { + ast::ItemImpl(_, _, _, Some(..), _, ref impl_items) => { check_inherited(item.span, item.vis, "visibility qualifiers have no effect on trait \ impls"); @@ -1216,7 +1216,7 @@ fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) { }; check_inherited(tcx, item.span, item.vis); match item.node { - ast::ItemImpl(_, _, _, _, ref impl_items) => { + ast::ItemImpl(_, _, _, _, _, ref impl_items) => { for impl_item in impl_items.iter() { match *impl_item { ast::MethodImplItem(ref m) => { @@ -1361,7 +1361,7 @@ fn visit_item(&mut self, item: &ast::Item) { // (i.e. we could just return here to not check them at // all, or some worse estimation of whether an impl is // publicly visible. - ast::ItemImpl(_, ref g, ref trait_ref, ref self_, ref impl_items) => { + ast::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4d83075480b..5736e307286 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -55,7 +55,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool { } match item.node { - ast::ItemImpl(_, ref generics, _, _, _) | + ast::ItemImpl(_, _, ref generics, _, _, _) | ast::ItemFn(_, _, _, ref generics, _) => { generics_require_inlining(generics) } @@ -216,7 +216,7 @@ fn def_id_represents_local_inlined_item(&self, def_id: ast::DefId) -> bool { .map .expect_item(impl_did.node) .node { - ast::ItemImpl(_, ref generics, _, _, _) => { + ast::ItemImpl(_, _, ref generics, _, _, _) => { generics_require_inlining(generics) } _ => false diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5eb033a01bd..68cb8ca39b4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -106,7 +106,7 @@ fn visit_item(&mut self, item: &ast::Item) { ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | ast::ItemTrait(_, ref generics, _, _) | - ast::ItemImpl(_, ref generics, _, _, _) => { + ast::ItemImpl(_, _, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE); @@ -136,18 +136,6 @@ fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, fn visit_ty(&mut self, ty: &ast::Ty) { match ty.node { - ast::TyClosure(ref c) => { - // Careful, the bounds on a closure/proc are *not* within its binder. - visit::walk_ty_param_bounds_helper(self, &c.bounds); - visit::walk_lifetime_decls_helper(self, &c.lifetimes); - self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { - this.check_lifetime_defs(old_scope, &c.lifetimes); - for argument in c.decl.inputs.iter() { - this.visit_ty(&*argument.ty) - } - visit::walk_fn_ret_ty(this, &c.decl.output); - }); - } ast::TyBareFn(ref c) => { visit::walk_lifetime_decls_helper(self, &c.lifetimes); self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 505352fa123..362d5fedaa3 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -82,7 +82,7 @@ fn visit_item(&mut self, i: &Item) { // stability of the trait. This is WRONG, but expedient to get // libstd stabilized for the 1.0 release. let use_parent = match i.node { - ast::ItemImpl(_, _, Some(_), _, _) => false, + ast::ItemImpl(_, _, _, Some(_), _, _) => false, _ => true, }; diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index e6805cddae0..55abe895183 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -118,7 +118,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::ty_float(..) | ty::ty_str(..) | ty::ty_bare_fn(..) | - ty::ty_closure(..) | ty::ty_vec(..) | ty::ty_ptr(..) | ty::ty_rptr(..) | diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 8bb7012fb07..c2327adece8 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -437,8 +437,9 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("register_region_obligation({})", region_obligation.repr(tcx)); - match region_obligations.entry(region_obligation.cause.body_id) { - Vacant(entry) => { entry.set(vec![region_obligation]); }, + let body_id = region_obligation.cause.body_id; + match region_obligations.entry(&body_id) { + Vacant(entry) => { entry.insert(vec![region_obligation]); }, Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index d5b41d23806..65f7ad296db 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -643,11 +643,12 @@ fn confirm_candidate<'cx,'tcx>( match impl_ty { Some(ty) => (ty, impl_vtable.nested.to_vec()), None => { - selcx.tcx().sess.span_bug( - obligation.cause.span, - format!("impl `{}` did not contain projection for `{}`", - impl_vtable.repr(selcx.tcx()), - obligation.repr(selcx.tcx())).as_slice()); + // This means that the impl is missing a + // definition for the associated type. This error + // ought to be reported by the type checker method + // `check_impl_items_against_trait`, so here we + // just return ty_err. + (selcx.tcx().types.err, vec!()) } } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f499cf61301..2393b7d733d 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1273,62 +1273,6 @@ fn builtin_bound(&mut self, } } - ty::ty_closure(ref c) => { - match c.store { - ty::UniqTraitStore => { - // proc: Equivalent to `Box` - match bound { - ty::BoundCopy => { - Err(Unimplemented) - } - - ty::BoundSized => { - Ok(If(Vec::new())) - } - - ty::BoundSync | - ty::BoundSend => { - if c.bounds.builtin_bounds.contains(&bound) { - Ok(If(Vec::new())) - } else { - Err(Unimplemented) - } - } - } - } - ty::RegionTraitStore(_, mutbl) => { - // ||: Equivalent to `&FnMut` or `&mut FnMut` or something like that. - match bound { - ty::BoundCopy => { - match mutbl { - ast::MutMutable => { - // &mut T is affine - Err(Unimplemented) - } - ast::MutImmutable => { - // &T is copyable, no matter what T is - Ok(If(Vec::new())) - } - } - } - - ty::BoundSized => { - Ok(If(Vec::new())) - } - - ty::BoundSync | - ty::BoundSend => { - if c.bounds.builtin_bounds.contains(&bound) { - Ok(If(Vec::new())) - } else { - Err(Unimplemented) - } - } - } - } - } - } - ty::ty_trait(ref data) => { match bound { ty::BoundSized => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d168e84a01c..291bb4c9820 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -78,7 +78,6 @@ use std::rc::Rc; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::abi; use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; @@ -294,7 +293,6 @@ pub enum Variance { #[derive(Clone, Show)] pub enum AutoAdjustment<'tcx> { - AdjustAddEnv(ast::DefId, ty::TraitStore), AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type AdjustDerefRef(AutoDerefRef<'tcx>) } @@ -917,7 +915,7 @@ impl<'tcx> ctxt<'tcx> { pub fn print_debug_stats(&self) { sty_debug_print!( self, - ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_closure, ty_trait, + ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_trait, ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer, ty_projection); println!("Substs interner: #{}", self.substs_interner.borrow().len()); @@ -1354,7 +1352,6 @@ pub enum sty<'tcx> { // fn item. Otherwise, if None(_), it a fn pointer type. ty_bare_fn(Option, &'tcx BareFnTy<'tcx>), - ty_closure(Box>), ty_trait(Box>), ty_struct(DefId, &'tcx Substs<'tcx>), @@ -1779,6 +1776,10 @@ pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { !self.regions.is_empty_in(space) } + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> GenericBounds<'tcx> { GenericBounds { @@ -2595,14 +2596,6 @@ fn add_sty(&mut self, st: &sty) { &ty_bare_fn(_, ref f) => { self.add_fn_sig(&f.sig); } - - &ty_closure(ref f) => { - if let RegionTraitStore(r, _) = f.store { - self.add_region(r); - } - self.add_fn_sig(&f.sig); - self.add_bounds(&f.bounds); - } } } @@ -2749,10 +2742,6 @@ pub fn mk_nil<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { mk_tup(cx, Vec::new()) } -pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, fty: ClosureTy<'tcx>) -> Ty<'tcx> { - mk_t(cx, ty_closure(box fty)) -} - pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>, opt_def_id: Option, fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> { @@ -3029,7 +3018,7 @@ pub fn type_is_vec(ty: Ty) -> bool { pub fn type_is_structural(ty: Ty) -> bool { match ty.sty { - ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) | + ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_vec(_, Some(_)) | ty_unboxed_closure(..) => true, _ => type_is_slice(ty) | type_is_trait(ty) } @@ -3346,10 +3335,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>, TC::None } - ty_closure(ref c) => { - closure_contents(&**c) | TC::ReachesFfiUnsafe - } - ty_uniq(typ) => { TC::ReachesFfiUnsafe | match typ.sty { ty_str => TC::OwnsOwned, @@ -3520,23 +3505,6 @@ fn borrowed_contents(region: ty::Region, b | (TC::ReachesBorrowed).when(region != ty::ReStatic) } - fn closure_contents(cty: &ClosureTy) -> TypeContents { - // Closure contents are just like trait contents, but with potentially - // even more stuff. - let st = object_contents(&cty.bounds); - - let st = match cty.store { - UniqTraitStore => { - st.owned_pointer() - } - RegionTraitStore(r, mutbl) => { - st.reference(borrowed_contents(r, mutbl)) - } - }; - - st - } - fn object_contents(bounds: &ExistentialBounds) -> TypeContents { // These are the type contents of the (opaque) interior. We // make no assumptions (other than that it cannot have an @@ -3650,7 +3618,6 @@ fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, ty_float(_) | ty_str | ty_bare_fn(..) | - ty_closure(_) | ty_param(_) | ty_projection(_) | ty_vec(_, None) => { @@ -4154,7 +4121,6 @@ pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts pub fn fn_is_variadic(fty: Ty) -> bool { match fty.sty { ty_bare_fn(_, ref f) => f.sig.0.variadic, - ty_closure(ref f) => f.sig.0.variadic, ref s => { panic!("fn_is_variadic() called on non-fn type: {}", s) } @@ -4164,7 +4130,6 @@ pub fn fn_is_variadic(fty: Ty) -> bool { pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { match fty.sty { ty_bare_fn(_, ref f) => &f.sig, - ty_closure(ref f) => &f.sig, ref s => { panic!("ty_fn_sig() called on non-fn type: {}", s) } @@ -4175,7 +4140,6 @@ pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { pub fn ty_fn_abi(fty: Ty) -> abi::Abi { match fty.sty { ty_bare_fn(_, ref f) => f.abi, - ty_closure(ref f) => f.abi, _ => panic!("ty_fn_abi() called on non-fn type"), } } @@ -4187,7 +4151,6 @@ pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] { pub fn ty_closure_store(fty: Ty) -> TraitStore { match fty.sty { - ty_closure(ref f) => f.store, ty_unboxed_closure(..) => { // Close enough for the purposes of all the callers of this // function (which is soon to be deprecated anyhow). @@ -4202,7 +4165,6 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore { pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> { match fty.sty { ty_bare_fn(_, ref f) => f.sig.0.output, - ty_closure(ref f) => f.sig.0.output, ref s => { panic!("ty_fn_ret() called on non-fn type: {}", s) } @@ -4212,7 +4174,6 @@ pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> { pub fn is_fn_ty(fty: Ty) -> bool { match fty.sty { ty_bare_fn(..) => true, - ty_closure(_) => true, _ => false } } @@ -4336,33 +4297,6 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, return match adjustment { Some(adjustment) => { match *adjustment { - AdjustAddEnv(_, store) => { - match unadjusted_ty.sty { - ty::ty_bare_fn(Some(_), ref b) => { - let bounds = ty::ExistentialBounds { - region_bound: ReStatic, - builtin_bounds: all_builtin_bounds(), - projection_bounds: vec!(), - }; - - ty::mk_closure( - cx, - ty::ClosureTy {unsafety: b.unsafety, - onceness: ast::Many, - store: store, - bounds: bounds, - sig: b.sig.clone(), - abi: b.abi}) - } - ref b => { - cx.sess.bug( - format!("add_env adjustment on non-fn-item: \ - {}", - b).as_slice()); - } - } - } - AdjustReifyFnPointer(_) => { match unadjusted_ty.sty { ty::ty_bare_fn(Some(_), b) => { @@ -4732,7 +4666,6 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_rptr(_, _) => "&-ptr".to_string(), ty_bare_fn(Some(_), _) => format!("fn item"), ty_bare_fn(None, _) => "fn pointer".to_string(), - ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { format!("trait {}", item_path_str(cx, inner.principal_def_id())) } @@ -5128,7 +5061,7 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) match cx.map.find(id.node) { Some(ast_map::NodeItem(item)) => { match item.node { - ast::ItemImpl(_, _, ref opt_trait, _, _) => { + ast::ItemImpl(_, _, _, ref opt_trait, _, _) => { match opt_trait { &Some(ref t) => { let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id); @@ -5651,10 +5584,8 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, node_id_to_type(tcx, id.node) } else { let mut tcache = tcx.tcache.borrow_mut(); - let pty = match tcache.entry(id) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.set(csearch::get_field_type(tcx, struct_id, id)), - }; + let pty = tcache.entry(&id).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id))); pty.ty }; ty.subst(tcx, substs) @@ -6329,24 +6260,6 @@ fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipS fn_sig(state, &b.sig); return false; } - ty_closure(ref c) => { - byte!(15); - hash!(c.unsafety); - hash!(c.onceness); - hash!(c.bounds); - match c.store { - UniqTraitStore => byte!(0), - RegionTraitStore(r, m) => { - byte!(1); - region(state, r); - assert_eq!(m, ast::MutMutable); - } - } - - fn_sig(state, &c.sig); - - return false; - } ty_trait(ref data) => { byte!(17); did(state, data.principal_def_id()); @@ -6669,12 +6582,6 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_struct(_, substs) => { accum_substs(accumulator, substs); } - ty_closure(ref closure_ty) => { - match closure_ty.store { - RegionTraitStore(region, _) => accumulator.push(region), - UniqTraitStore => {} - } - } ty_unboxed_closure(_, region, substs) => { accumulator.push(*region); accum_substs(accumulator, substs); @@ -6744,7 +6651,6 @@ pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { - AdjustAddEnv(..) => false, AdjustReifyFnPointer(..) => false, AdjustDerefRef(ref r) => r.is_identity(), } @@ -6841,10 +6747,8 @@ pub fn replace_late_bound_regions<'tcx, T, F>( debug!("region={}", region.repr(tcx)); match region { ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { - * match map.entry(br) { - Vacant(entry) => entry.set(mapf(br, debruijn)), - Occupied(entry) => entry.into_mut(), - } + * map.entry(&br).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(mapf(br, debruijn))) } _ => { region @@ -6870,11 +6774,8 @@ pub fn shifted(&self, amount: u32) -> DebruijnIndex { impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AdjustAddEnv(def_id, ref trait_store) => { - format!("AdjustAddEnv({},{})", def_id.repr(tcx), trait_store) - } AdjustReifyFnPointer(def_id) => { - format!("AdjustAddEnv({})", def_id.repr(tcx)) + format!("AdjustReifyFnPointer({})", def_id.repr(tcx)) } AdjustDerefRef(ref data) => { data.repr(tcx) diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 9a66b98ee58..1bc0d709458 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -70,6 +70,13 @@ fn enter_region_binder(&mut self) { } /// track the Debruijn index nesting level. fn exit_region_binder(&mut self) { } + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`. + super_fold_binder(self, t) + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { super_fold_ty(self, t) } @@ -183,12 +190,9 @@ fn fold_with>(&self, folder: &mut F) -> Vec { } } -impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { +impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> TypeFoldable<'tcx> for ty::Binder { fn fold_with>(&self, folder: &mut F) -> ty::Binder { - folder.enter_region_binder(); - let result = ty::Binder(self.0.fold_with(folder)); - folder.exit_region_binder(); - result + folder.fold_binder(self) } } @@ -556,6 +560,17 @@ fn fold_with>(&self, folder: &mut F) -> ty::UnboxedClosureUpv // // They should invoke `foo.fold_with()` to do recursive folding. +pub fn super_fold_binder<'tcx, T, U>(this: &mut T, + binder: &ty::Binder) + -> ty::Binder + where T : TypeFolder<'tcx>, U : TypeFoldable<'tcx> +{ + this.enter_region_binder(); + let result = ty::Binder(binder.0.fold_with(this)); + this.exit_region_binder(); + result +} + pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -589,9 +604,6 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let bfn = f.fold_with(this); ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn)) } - ty::ty_closure(ref f) => { - ty::ty_closure(f.fold_with(this)) - } ty::ty_rptr(r, ref tm) => { let r = r.fold_with(this); ty::ty_rptr(this.tcx().mk_region(r), tm.fold_with(this)) diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 6070a4208f6..4953e9a2ce1 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -51,9 +51,6 @@ fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) { ty::ty_bare_fn(_, ref ft) => { self.push_sig_subtypes(&ft.sig); } - ty::ty_closure(ref ft) => { - self.push_sig_subtypes(&ft.sig); - } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1480ff016b5..138f648049c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -105,6 +105,7 @@ pub struct Options { pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, + pub show_span: Option, pub externs: HashMap>, pub crate_name: Option, /// An optional name to use as the crate for std during std injection, @@ -211,6 +212,7 @@ pub fn basic_options() -> Options { prints: Vec::new(), cg: basic_codegen_options(), color: Auto, + show_span: None, externs: HashMap::new(), crate_name: None, alt_std_name: None, @@ -259,7 +261,6 @@ macro_rules! debugging_opts { BORROWCK_STATS, NO_LANDING_PADS, DEBUG_LLVM, - SHOW_SPAN, COUNT_TYPE_SIZES, META_STATS, GC, @@ -299,7 +300,6 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> { ("no-landing-pads", "omit landing pads for unwinding", NO_LANDING_PADS), ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM), - ("show-span", "show spans for compiler debugging", SHOW_SPAN), ("count-type-sizes", "count the sizes of aggregate types", COUNT_TYPE_SIZES), ("meta-stats", "gather metadata statistics", META_STATS), @@ -754,7 +754,7 @@ pub fn rustc_short_optgroups() -> Vec { "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"), opt::multi("", "print", "Comma separated list of compiler information to \ print on stdout", - "[crate-name|output-file-names|sysroot]"), + "[crate-name|file-names|sysroot]"), opt::flag("g", "", "Equivalent to -C debuginfo=2"), opt::flag("O", "", "Equivalent to -C opt-level=2"), opt::opt("o", "", "Write output to ", "FILENAME"), @@ -823,6 +823,7 @@ pub fn rustc_optgroups() -> Vec { `flowgraph=` (graphviz formatted flowgraph for node), or `everybody_loops` (all function bodies replaced with `loop {}`).", "TYPE"), + opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), opt::flagopt("", "dep-info", "Output dependency info to after compiling, \ in a format suitable for use by Makefiles", "FILENAME"), @@ -1114,8 +1115,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { None => early_error("--extern value must be of the format `foo=bar`"), }; - match externs.entry(name.to_string()) { - Vacant(entry) => { entry.set(vec![location.to_string()]); }, + match externs.entry(&name.to_string()) { + Vacant(entry) => { entry.insert(vec![location.to_string()]); }, Occupied(mut entry) => { entry.get_mut().push(location.to_string()); }, } } @@ -1143,6 +1144,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { prints: prints, cg: cg, color: color, + show_span: None, externs: externs, crate_name: crate_name, alt_std_name: None, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 770e8d73ec7..abb780615ae 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -201,8 +201,8 @@ pub fn lto(&self) -> bool { pub fn no_landing_pads(&self) -> bool { self.debugging_opt(config::NO_LANDING_PADS) } - pub fn show_span(&self) -> bool { - self.debugging_opt(config::SHOW_SPAN) + pub fn unstable_options(&self) -> bool { + self.debugging_opt(config::UNSTABLE_OPTIONS) } pub fn print_enum_sizes(&self) -> bool { self.debugging_opt(config::PRINT_ENUM_SIZES) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9639af5ca1c..e6ee16d1789 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -18,7 +18,7 @@ use middle::ty::{ReSkolemized, ReVar, BrEnv}; use middle::ty::{mt, Ty, ParamTy}; use middle::ty::{ty_bool, ty_char, ty_struct, ty_enum}; -use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; +use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn}; use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; @@ -417,9 +417,6 @@ fn infer_ty_to_string(cx: &ctxt, ty: ty::InferTy) -> String { strs => format!("({})", strs.connect(", ")) } } - ty_closure(ref f) => { - closure_to_string(cx, &**f) - } ty_bare_fn(opt_def_id, ref f) => { bare_fn_to_string(cx, opt_def_id, f.unsafety, f.abi, None, &f.sig) } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 75545634b40..e1f0c9ec266 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -662,13 +662,6 @@ fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>, default_msgs: (&'static str, &'static str)) -> (&'static str, &'static str) { match ty.sty { - ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(..), - .. - }) => { - ("a non-copyable stack closure", - "capture it in a new closure, e.g. `|x| f(x)`, to override") - } _ => { if ty::type_moves_by_default(param_env, span, ty) { ("non-copyable", diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 388cbf2f18b..f2c35851d0d 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -137,8 +137,8 @@ fn node_label(&'a self, n: &Node<'a>) -> dot::LabelText<'a> { let suffix = self.dataflow_for(dataflow::Exit, n); let inner_label = self.inner.node_label(n); inner_label - .prefix_line(dot::LabelStr(prefix.into_cow())) - .suffix_line(dot::LabelStr(suffix.into_cow())) + .prefix_line(dot::LabelText::LabelStr(prefix.into_cow())) + .suffix_line(dot::LabelText::LabelStr(suffix.into_cow())) } fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1455aa3c99b..f5c29a6b30b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -146,8 +146,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) println!("{}", json::as_json(&krate)); } - if sess.show_span() { - syntax::show_span::run(sess.diagnostic(), &krate); + if let Some(ref s) = sess.opts.show_span { + syntax::show_span::run(sess.diagnostic(), s.as_slice(), &krate); } krate @@ -572,7 +572,7 @@ pub fn stop_after_phase_1(sess: &Session) -> bool { debug!("invoked with --parse-only, returning early from compile_input"); return true; } - if sess.show_span() { + if sess.opts.show_span.is_some() { return true; } return sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0; @@ -638,7 +638,7 @@ fn write_out_deps(sess: &Session, _ => return, }; - let result = (|| -> io::IoResult<()> { + let result = (|&:| -> io::IoResult<()> { // Build a list of files used to compile the output and // write Makefile-compatible dependency rules let files: Vec = sess.codemap().files.borrow() diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9a993de098e..2e8cde65890 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -54,7 +54,6 @@ use rustc::metadata; use rustc::DIAGNOSTICS; -use std::any::AnyRefExt; use std::cmp::Ordering::Equal; use std::io; use std::iter::repeat; @@ -135,7 +134,7 @@ fn run_compiler(args: &[String]) { _ => early_error("multiple input filenames provided") }; - let sess = build_session(sopts, input_file_path, descriptions); + let mut sess = build_session(sopts, input_file_path, descriptions); let cfg = config::build_configuration(&sess); if print_crate_info(&sess, Some(&input), &odir, &ofile) { return @@ -146,7 +145,7 @@ fn run_compiler(args: &[String]) { pretty::parse_pretty(&sess, a.as_slice(), false) }); let pretty = if pretty.is_none() && - sess.debugging_opt(config::UNSTABLE_OPTIONS) { + sess.unstable_options() { matches.opt_str("xpretty").map(|a| { // extended with unstable pretty-print variants pretty::parse_pretty(&sess, a.as_slice(), true) @@ -163,6 +162,10 @@ fn run_compiler(args: &[String]) { None => {/* continue */ } } + if sess.unstable_options() { + sess.opts.show_span = matches.opt_str("show-span"); + } + let r = matches.opt_strs("Z"); if r.contains(&("ls".to_string())) { match input { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ab41ade576a..b1e65dce604 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -277,26 +277,6 @@ pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> { ty::mk_tup(self.infcx.tcx, vec![ty1, ty2]) } - pub fn t_closure(&self, - input_tys: &[Ty<'tcx>], - output_ty: Ty<'tcx>, - region_bound: ty::Region) - -> Ty<'tcx> - { - ty::mk_closure(self.infcx.tcx, ty::ClosureTy { - unsafety: ast::Unsafety::Normal, - onceness: ast::Many, - store: ty::RegionTraitStore(region_bound, ast::MutMutable), - bounds: ty::region_existential_bound(region_bound), - sig: ty::Binder(ty::FnSig { - inputs: input_tys.to_vec(), - output: ty::FnConverging(output_ty), - variadic: false, - }), - abi: abi::Rust, - }) - } - pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); ty::mk_param(self.infcx.tcx, space, index, token::intern(name[])) @@ -780,19 +760,6 @@ fn escaping() { assert!(!ty::type_has_escaping_regions(t_param)); let t_fn = env.t_fn(&[t_param], env.t_nil()); assert!(!ty::type_has_escaping_regions(t_fn)); - - // t_fn = |&int|+'a - let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1)); - assert!(!ty::type_has_escaping_regions(t_fn)); - - // t_fn = |&int|+'a (where &int has depth 2) - let t_fn = env.t_closure(&[t_rptr_bound2], env.t_nil(), env.re_free(0, 1)); - assert!(ty::type_has_escaping_regions(t_fn)); - - // t_fn = |&int|+&int - let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), - env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1))); - assert!(ty::type_has_escaping_regions(t_fn)); }) } diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs index 53992d4567a..d3555e4c043 100644 --- a/src/librustc_llvm/archive_ro.rs +++ b/src/librustc_llvm/archive_ro.rs @@ -13,7 +13,7 @@ use libc; use ArchiveRef; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::raw; @@ -30,9 +30,8 @@ impl ArchiveRO { /// raised. pub fn open(dst: &Path) -> Option { unsafe { - let ar = dst.with_c_str(|dst| { - ::LLVMRustOpenArchive(dst) - }); + let s = CString::from_slice(dst.as_vec()); + let ar = ::LLVMRustOpenArchive(s.as_ptr()); if ar.is_null() { None } else { @@ -45,9 +44,9 @@ pub fn open(dst: &Path) -> Option { pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> { unsafe { let mut size = 0 as libc::size_t; - let ptr = file.with_c_str(|file| { - ::LLVMRustArchiveReadSection(self.ptr, file, &mut size) - }); + let file = CString::from_slice(file.as_bytes()); + let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(), + &mut size); if ptr.is_null() { None } else { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 2ec5f37634a..854ac5ff5c0 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -47,7 +47,7 @@ pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::RefCell; use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; @@ -2114,10 +2114,9 @@ fn drop(&mut self) { } pub fn mk_target_data(string_rep: &str) -> TargetData { + let string_rep = CString::from_slice(string_rep.as_bytes()); TargetData { - lltd: string_rep.with_c_str(|buf| { - unsafe { LLVMCreateTargetData(buf) } - }) + lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d7c1a4fe17b..10788f9f7cb 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -386,7 +386,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc) -> parent.clone() } - ItemImpl(_, _, None, ref ty, ref impl_items) => { + ItemImpl(_, _, _, None, ref ty, ref impl_items) => { // If this implements an anonymous trait, then add all the // methods within to a new module, if the type was defined // within this module. @@ -527,7 +527,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc) -> parent.clone() } - ItemImpl(_, _, Some(_), _, _) => parent.clone(), + ItemImpl(_, _, _, Some(_), _, _) => parent.clone(), ItemTrait(_, _, _, ref items) => { let name_bindings = diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3be7aa294f1..a2c86c3cdb7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -71,7 +71,7 @@ use syntax::ast::{PolyTraitRef, PrimTy, SelfExplicit}; use syntax::ast::{RegionTyParamBound, StructField}; use syntax::ast::{TraitRef, TraitTyParamBound}; -use syntax::ast::{Ty, TyBool, TyChar, TyClosure, TyF32}; +use syntax::ast::{Ty, TyBool, TyChar, TyF32}; use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum}; use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath}; use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint}; @@ -972,7 +972,6 @@ fn new(session: &'a Session, } } - // Import resolution // // This is a fixed-point algorithm. We resolve imports until our efforts @@ -1688,15 +1687,11 @@ fn merge_import_resolution(&mut self, let is_public = import_directive.is_public; let mut import_resolutions = module_.import_resolutions.borrow_mut(); - let dest_import_resolution = match import_resolutions.entry(name) { - Occupied(entry) => { - entry.into_mut() - } - Vacant(entry) => { + let dest_import_resolution = import_resolutions.entry(&name).get().unwrap_or_else( + |vacant_entry| { // Create a new import resolution from this child. - entry.set(ImportResolution::new(id, is_public)) - } - }; + vacant_entry.insert(ImportResolution::new(id, is_public)) + }); debug!("(resolving glob import) writing resolution `{}` in `{}` \ to `{}`", @@ -2630,16 +2625,16 @@ fn upvarify(&self, def = DefUpvar(node_id, function_id, last_proc_body_id); let mut seen = self.freevars_seen.borrow_mut(); - let seen = match seen.entry(function_id) { + let seen = match seen.entry(&function_id) { Occupied(v) => v.into_mut(), - Vacant(v) => v.set(NodeSet::new()), + Vacant(v) => v.insert(NodeSet::new()), }; if seen.contains(&node_id) { continue; } - match self.freevars.borrow_mut().entry(function_id) { + match self.freevars.borrow_mut().entry(&function_id) { Occupied(v) => v.into_mut(), - Vacant(v) => v.set(vec![]), + Vacant(v) => v.insert(vec![]), }.push(Freevar { def: prev_def, span: span }); seen.insert(node_id); } @@ -2841,7 +2836,7 @@ fn resolve_item(&mut self, item: &Item) { }); } - ItemImpl(_, + ItemImpl(_, _, ref generics, ref implemented_traits, ref self_type, @@ -3611,14 +3606,6 @@ fn resolve_type(&mut self, ty: &Ty) { self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath); } - TyClosure(ref c) => { - self.resolve_type_parameter_bounds( - ty.id, - &c.bounds, - TraitBoundingTypeParameter); - visit::walk_ty(self, ty); - } - TyPolyTraitRef(ref bounds) => { self.resolve_type_parameter_bounds( ty.id, @@ -4722,7 +4709,7 @@ fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) { "Import should only be used for `use` directives"); self.last_private.insert(node_id, lp); - match self.def_map.borrow_mut().entry(node_id) { + match self.def_map.borrow_mut().entry(&node_id) { // Resolve appears to "resolve" the same ID multiple // times, so here is a sanity check it at least comes to // the same conclusion! - nmatsakis @@ -4734,7 +4721,7 @@ fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) { *entry.get(), def)[]); }, - Vacant(entry) => { entry.set(def); }, + Vacant(entry) => { entry.insert(def); }, } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index c6488ec6638..f3e90c43a84 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -20,7 +20,7 @@ use libc; use flate; -use std::c_str::ToCStr; +use std::ffi::CString; use std::iter; use std::mem; use std::num::Int; @@ -139,9 +139,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } // Internalize everything but the reachable symbols of the current module - let cstrs: Vec<::std::c_str::CString> = - reachable.iter().map(|s| s.to_c_str()).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let cstrs: Vec = reachable.iter().map(|s| { + CString::from_slice(s.as_bytes()) + }).collect(); + let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, @@ -164,7 +165,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); let builder = llvm::LLVMPassManagerBuilderCreate(); llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm, @@ -172,7 +173,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, /* RunInliner = */ True); llvm::LLVMPassManagerBuilderDispose(builder); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); time(sess.time_passes(), "LTO passes", (), |()| llvm::LLVMRunPassManager(pm, llmod)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 33011d9e35c..089d7f737d3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,7 +22,7 @@ use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level, mk_handler}; -use std::c_str::{ToCStr, CString}; +use std::ffi::{mod, CString}; use std::io::Command; use std::io::fs; use std::iter::Unfold; @@ -32,7 +32,7 @@ use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{c_uint, c_int, c_void}; +use libc::{mod, c_uint, c_int, c_void}; #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { @@ -49,8 +49,9 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { if cstr == ptr::null() { handler.fatal(msg[]); } else { - let err = CString::new(cstr, true); - let err = String::from_utf8_lossy(err.as_bytes()); + let err = ffi::c_str_to_bytes(&cstr); + let err = String::from_utf8_lossy(err.as_slice()).to_string(); + libc::free(cstr as *mut _); handler.fatal(format!("{}: {}", msg[], err[])[]); @@ -66,13 +67,12 @@ pub fn write_output_file( output: &Path, file_type: llvm::FileType) { unsafe { - output.with_c_str(|output| { - let result = llvm::LLVMRustWriteOutputFile( - target, pm, m, output, file_type); - if !result { - llvm_err(handler, "could not write output".to_string()); - } - }) + let output = CString::from_slice(output.as_vec()); + let result = llvm::LLVMRustWriteOutputFile( + target, pm, m, output.as_ptr(), file_type); + if !result { + llvm_err(handler, "could not write output".to_string()); + } } } @@ -221,28 +221,25 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let triple = sess.target.target.llvm_target[]; let tm = unsafe { - triple.with_c_str(|t| { - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => s[], - None => sess.target.target.options.cpu[] - }; - cpu.with_c_str(|cpu| { - target_feature(sess).with_c_str(|features| { - llvm::LLVMRustCreateTargetMachine( - t, cpu, features, - code_model, - reloc_model, - opt_level, - true /* EnableSegstk */, - use_softfp, - no_fp_elim, - !any_library && reloc_model == llvm::RelocPIC, - ffunction_sections, - fdata_sections, - ) - }) - }) - }) + let triple = CString::from_slice(triple.as_bytes()); + let cpu = match sess.opts.cg.target_cpu { + Some(ref s) => s.as_slice(), + None => sess.target.target.options.cpu.as_slice() + }; + let cpu = CString::from_slice(cpu.as_bytes()); + let features = CString::from_slice(target_feature(sess).as_bytes()); + llvm::LLVMRustCreateTargetMachine( + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + code_model, + reloc_model, + opt_level, + true /* EnableSegstk */, + use_softfp, + no_fp_elim, + !any_library && reloc_model == llvm::RelocPIC, + ffunction_sections, + fdata_sections, + ) }; if tm.is_null() { @@ -371,8 +368,9 @@ struct HandlerFreeVars<'a> { match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::Optimization(opt) => { - let pass_name = CString::new(opt.pass_name, false); - let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM"); + let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name)) + .ok() + .expect("got a non-UTF8 pass name from LLVM"); let enabled = match cgcx.remark { AllPasses => true, SomePasses(ref v) => v.iter().any(|s| *s == pass_name), @@ -416,9 +414,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_no_opt_bc { let ext = format!("{}.no-opt.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } match config.opt_level { @@ -433,7 +431,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. let addpass = |&: pass: &str| { - pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s)) + let pass = CString::from_slice(pass.as_bytes()); + llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; if !config.no_verify { assert!(addpass("verify")); } @@ -445,12 +444,11 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } for pass in config.passes.iter() { - pass.with_c_str(|s| { - if !llvm::LLVMRustAddPass(mpm, s) { - cgcx.handler.warn(format!("unknown pass {}, ignoring", - *pass)[]); - } - }) + let pass = CString::from_slice(pass.as_bytes()); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.warn(format!("unknown pass {}, ignoring", + pass).as_slice()); + } } // Finally, run the actual optimization passes @@ -470,9 +468,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_lto_bc { let name = format!("{}.lto.bc", name_extra); - output_names.with_extension(name[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(name.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } }, _ => {}, @@ -504,18 +502,18 @@ unsafe fn with_codegen(tm: TargetMachineRef, if config.emit_bc { let ext = format!("{}.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } time(config.time_passes, "codegen passes", (), |()| { if config.emit_ir { let ext = format!("{}.ll", name_extra); - output_names.with_extension(ext[]).with_c_str(|output| { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, output); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + with_codegen(tm, llmod, config.no_builtins, |cpm| { + llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); }) } @@ -995,7 +993,7 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_args = Vec::new(); { let mut add = |&mut : arg: &str| { - let s = arg.to_c_str(); + let s = CString::from_slice(arg.as_bytes()); llvm_args.push(s.as_ptr()); llvm_c_strs.push(s); }; @@ -1083,7 +1081,7 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, match opt { llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - "mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s)); + llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); } _ => {} }; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 55bdff81910..8e6276b61f9 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -283,7 +283,7 @@ fn process_method(&mut self, method: &ast::Method) { NodeItem(item) => { scope_id = item.id; match item.node { - ast::ItemImpl(_, _, _, ref ty, _) => { + ast::ItemImpl(_, _, _, _, ref ty, _) => { let mut result = String::from_str("<"); result.push_str(ty_to_string(&**ty)[]); @@ -1040,7 +1040,7 @@ fn visit_item(&mut self, item: &ast::Item) { self.process_const(item, &**typ, &**expr), ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params), ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), - ast::ItemImpl(_, + ast::ItemImpl(_, _, ref ty_params, ref trait_ref, ref typ, diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 223df5d3a57..01b47b728b6 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -355,12 +355,6 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Functions are just pointers ty::ty_bare_fn(..) => Some(path), - // Closures are a pair of pointers: the code and environment - ty::ty_closure(..) => { - path.push(FAT_PTR_ADDR); - Some(path) - }, - // Is this the NonZero lang item wrapping a pointer or integer type? ty::ty_struct(did, substs) if Some(did) == tcx.lang_items.non_zero() => { let nonzero_fields = ty::lookup_struct_fields(tcx, did); diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 5597e112f76..f18d483f703 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -20,9 +20,8 @@ use trans::type_of; use trans::type_::Type; -use std::c_str::ToCStr; -use std::string::String; use syntax::ast; +use std::ffi::CString; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM @@ -121,18 +120,16 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) ast::AsmIntel => llvm::AD_Intel }; - let r = ia.asm.get().with_c_str(|a| { - constraints.with_c_str(|c| { - InlineAsmCall(bcx, - a, - c, - inputs[], + let asm = CString::from_slice(ia.asm.get().as_bytes()); + let constraints = CString::from_slice(constraints.as_bytes()); + let r = InlineAsmCall(bcx, + asm.as_ptr(), + constraints.as_ptr(), + inputs.as_slice(), output_type, ia.volatile, ia.alignstack, - dialect) - }) - }); + dialect); // Again, based on how many outputs we have if num_outputs == 1 { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 58cb2ebd256..7031710c679 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -88,11 +88,12 @@ use arena::TypedArena; use libc::{c_uint, uint64_t}; -use std::c_str::ToCStr; +use std::ffi::{mod, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::mem; use std::rc::Rc; +use std::str; use std::{i8, i16, i32, i64}; use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; use syntax::ast_util::local_def; @@ -187,11 +188,10 @@ fn drop(&mut self) { pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, ty: Type, output: ty::FnOutput) -> ValueRef { - let llfn: ValueRef = name.with_c_str(|buf| { - unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref()) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let llfn: ValueRef = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) + }; // diverging functions may unwind, but can never return normally if output == ty::FnDiverging { @@ -287,9 +287,6 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(_, ref f) => { (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None) } - ty::ty_closure(ref f) => { - (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx))) - } ty::ty_unboxed_closure(closure_did, _, substs) => { let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx()); let function_type = typer.unboxed_closure_type(closure_did, substs); @@ -334,9 +331,8 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, None => () } unsafe { - let c = name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf) - }); + let buf = CString::from_slice(name.as_bytes()); + let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the // thread-local attribute locally if it was present remotely. If we @@ -475,15 +471,17 @@ pub fn set_always_inline(f: ValueRef) { } pub fn set_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } pub fn unset_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } // Double-check that we never ask LLVM to declare the same symbol twice. It @@ -511,7 +509,7 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Since we're in trans we don't care for any region parameters let substs = subst::Substs::erased(substs.types.clone()); - let (val, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None); + let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None); val } else if did.krate == ast::LOCAL_CRATE { @@ -537,11 +535,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Structural comparison: a rather involved form of glue. pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { if cx.sess().opts.cg.save_temps { - s.with_c_str(|buf| { - unsafe { - llvm::LLVMSetValueName(v, buf) - } - }) + let buf = CString::from_slice(s.as_bytes()); + unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) } } } @@ -669,30 +664,31 @@ pub fn compare_simd_types<'blk, 'tcx>( } } -pub type val_and_ty_fn<'a, 'blk, 'tcx> = - |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>; - // Iterates through the elements of a structural type. -pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, - av: ValueRef, - t: Ty<'tcx>, - f: val_and_ty_fn<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { +pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, + av: ValueRef, + t: Ty<'tcx>, + mut f: F) + -> Block<'blk, 'tcx> where + F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, +{ let _icx = push_ctxt("iter_structural_ty"); - fn iter_variant<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, - repr: &adt::Repr<'tcx>, - av: ValueRef, - variant: &ty::VariantInfo<'tcx>, - substs: &subst::Substs<'tcx>, - f: val_and_ty_fn<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, + repr: &adt::Repr<'tcx>, + av: ValueRef, + variant: &ty::VariantInfo<'tcx>, + substs: &subst::Substs<'tcx>, + f: &mut F) + -> Block<'blk, 'tcx> where + F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, + { let _icx = push_ctxt("iter_variant"); let tcx = cx.tcx(); let mut cx = cx; for (i, &arg) in variant.args.iter().enumerate() { - cx = f(cx, + cx = (*f)(cx, adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), arg.subst(tcx, substs)); } @@ -764,7 +760,7 @@ fn iter_variant<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, match adt::trans_switch(cx, &*repr, av) { (_match::Single, None) => { cx = iter_variant(cx, &*repr, av, &*(*variants)[0], - substs, f); + substs, &mut f); } (_match::Switch, Some(lldiscrim_a)) => { cx = f(cx, lldiscrim_a, cx.tcx().types.int); @@ -793,7 +789,7 @@ fn iter_variant<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, data_ptr, &**variant, substs, - |x,y,z| f(x,y,z)); + &mut f); Br(variant_cx, next_cx.llbb); } cx = next_cx; @@ -951,9 +947,6 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } } - ty::ty_closure(_) => { - get_extern_rust_fn(ccx, t, name[], did) - } _ => { get_extern_const(ccx, did, t) } @@ -2317,7 +2310,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let mut v = TransItemVisitor{ ccx: ccx }; v.visit_block(&**body); } - ast::ItemImpl(_, ref generics, _, _, ref impl_items) => { + ast::ItemImpl(_, _, ref generics, _, _, ref impl_items) => { meth::trans_impl(ccx, item.ident, impl_items[], @@ -2437,7 +2430,6 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< use middle::ty::{BrAnon, ReLateBound}; let (fn_sig, abi, has_env) = match fn_ty.sty { - ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false), ty::ty_unboxed_closure(closure_did, _, substs) => { let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx()); @@ -2645,11 +2637,10 @@ fn create_entry_fn(ccx: &CrateContext, unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) } } - let llbb = "top".with_c_str(|buf| { - unsafe { - llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf) - } - }); + let llbb = unsafe { + llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, + "top\0".as_ptr() as *const _) + }; let bld = ccx.raw_builder(); unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); @@ -2670,9 +2661,9 @@ fn create_entry_fn(ccx: &CrateContext, }; let args = { - let opaque_rust_main = "rust_main".with_c_str(|buf| { - llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf) - }); + let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, + rust_main, Type::i8p(ccx).to_ref(), + "rust_main\0".as_ptr() as *const _); vec!( opaque_rust_main, @@ -2779,9 +2770,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { format!("Illegal null byte in export_name \ value: `{}`", sym)[]); } - let g = sym.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty, buf) - }); + let buf = CString::from_slice(sym.as_bytes()); + let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, + buf.as_ptr()); if attr::contains_name(i.attrs[], "thread_local") { @@ -2823,9 +2814,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sect.get())[]); } unsafe { - sect.get().with_c_str(|buf| { - llvm::LLVMSetSection(v, buf); - }) + let buf = CString::from_slice(sect.get().as_bytes()); + llvm::LLVMSetSection(v, buf.as_ptr()); } }, None => () @@ -2978,7 +2968,7 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { } let encode_inlined_item: encoder::EncodeInlinedItem = - |ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii); + box |ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii); let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item); let metadata = encoder::encode_metadata(encode_parms, krate); @@ -2992,17 +2982,16 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { let name = format!("rust_metadata_{}_{}", cx.link_meta().crate_name, cx.link_meta().crate_hash); - let llglobal = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf) - } - }); + let buf = CString::from_vec(name.into_bytes()); + let llglobal = unsafe { + llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), + buf.as_ptr()) + }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx); - name.with_c_str(|buf| { - llvm::LLVMSetSection(llglobal, buf) - }); + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMSetSection(llglobal, name.as_ptr()) } return metadata; } @@ -3010,8 +2999,6 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { - use std::c_str::CString; - unsafe { let mut declared = HashSet::new(); @@ -3041,7 +3028,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); declared.insert(name); } } @@ -3057,9 +3045,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); if !declared.contains(&name) && - !reachable.contains(name.as_str().unwrap()) { + !reachable.contains(str::from_utf8(name.as_slice()).unwrap()) { llvm::SetLinkage(val, llvm::InternalLinkage); } } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index 97f0b92a290..e09d36ddae9 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -20,7 +20,8 @@ use trans::type_::Type; use util::nodemap::FnvHashMap; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; + +use std::ffi::CString; use syntax::codemap::Span; pub struct Builder<'a, 'tcx: 'a> { @@ -429,9 +430,9 @@ pub fn alloca(&self, ty: Type, name: &str) -> ValueRef { if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { - name.with_c_str(|c| { - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c) - }) + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), + name.as_ptr()) } } } @@ -774,12 +775,12 @@ pub fn add_comment(&self, text: &str) { let comment_text = format!("{} {}", "#", sanitized.replace("\n", "\n\t# ")); self.count_insn("inlineasm"); - let asm = comment_text.with_c_str(|c| { - unsafe { - llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), - c, noname(), False, False) - } - }); + let comment_text = CString::from_vec(comment_text.into_bytes()); + let asm = unsafe { + llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), + comment_text.as_ptr(), noname(), False, + False) + }; self.call(asm, &[], None); } } @@ -926,9 +927,8 @@ pub fn trap(&self) { let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let t: ValueRef = "llvm.trap".with_c_str(|buf| { - llvm::LLVMGetNamedFunction(m, buf) - }); + let p = "llvm.trap\0".as_ptr(); + let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); assert!((t as int != 0)); let args: &[ValueRef] = &[]; self.count_insn("trap"); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index f001786bec4..65e6d7e1924 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -19,7 +19,7 @@ pub use self::CallArgs::*; use arena::TypedArena; -use back::{abi,link}; +use back::link; use session; use llvm::{ValueRef}; use llvm::get_param; @@ -38,6 +38,7 @@ use trans::closure; use trans::common; use trans::common::*; +use trans::consts; use trans::datum::*; use trans::expr; use trans::glue; @@ -65,8 +66,6 @@ pub struct MethodData { } pub enum CalleeData<'tcx> { - Closure(Datum<'tcx, Lvalue>), - // Constructor for enum variant/tuple-like-struct // i.e. Some, Ok NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr), @@ -101,7 +100,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) -> Callee<'blk, 'tcx> { - let DatumBlock {mut bcx, datum} = expr::trans(bcx, expr); + let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr); match datum.ty.sty { ty::ty_bare_fn(..) => { let llval = datum.to_llscalarish(bcx); @@ -110,14 +109,6 @@ fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) data: Fn(llval), }; } - ty::ty_closure(..) => { - let datum = unpack_datum!( - bcx, datum.to_lvalue_datum(bcx, "callee", expr.id)); - return Callee { - bcx: bcx, - data: Closure(datum), - }; - } _ => { bcx.tcx().sess.span_bug( expr.span, @@ -152,7 +143,8 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => false } } => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); Callee { bcx: bcx, data: NamedTupleConstructor(substs, 0) @@ -162,23 +154,28 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic, _ => false } => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) } } def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) | def::DefStaticMethod(did, def::FromImpl(_)) => { - fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id))) + fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), + bcx.fcx.param_substs).val) } def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) | def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => { - fn_callee(bcx, meth::trans_static_method_callee(bcx, meth_did, + fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(), + meth_did, trait_did, - ref_expr.id)) + ref_expr.id, + bcx.fcx.param_substs).val) } def::DefVariant(tid, vid, _) => { let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); // Nullary variants are not callable assert!(vinfo.args.len() > 0u); @@ -189,7 +186,8 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } def::DefStruct(_) => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); Callee { bcx: bcx, data: NamedTupleConstructor(substs, 0) @@ -217,15 +215,19 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function /// pointer. This may require monomorphization or inlining. -pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef { +pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: ast::DefId, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref"); - let substs = node_id_substs(bcx, node); + let substs = node_id_substs(ccx, node, param_substs); debug!("trans_fn_ref(def_id={}, node={}, substs={})", - def_id.repr(bcx.tcx()), + def_id.repr(ccx.tcx()), node, - substs.repr(bcx.tcx())); - trans_fn_ref_with_substs(bcx, def_id, node, substs) + substs.repr(ccx.tcx())); + trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs) } fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -235,10 +237,11 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Callee<'blk, 'tcx> { Callee { bcx: bcx, - data: Fn(trans_fn_ref_with_substs(bcx, + data: Fn(trans_fn_ref_with_substs(bcx.ccx(), def_id, ExprId(ref_id), - substs)), + bcx.fcx.param_substs, + substs).val), } } @@ -364,28 +367,30 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// /// # Parameters /// -/// - `bcx`: the current block where the reference to the fn occurs +/// - `ccx`: the crate context /// - `def_id`: def id of the fn or method item being referenced /// - `node`: node id of the reference to the fn/method, if applicable. /// This parameter may be zero; but, if so, the resulting value may not /// have the right type, so it must be cast before being used. +/// - `param_substs`: if the `node` is in a polymorphic function, these +/// are the substitutions required to monomorphize its type /// - `substs`: values for each of the fn/method's parameters -pub fn trans_fn_ref_with_substs<'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, // - def_id: ast::DefId, // def id of fn - node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A - substs: subst::Substs<'tcx>) // vtables for the call - -> ValueRef +pub fn trans_fn_ref_with_substs<'a, 'tcx>( + ccx: &CrateContext<'a, 'tcx>, + def_id: ast::DefId, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>, + substs: subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref_with_substs"); - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); + let tcx = ccx.tcx(); - debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={}, \ - substs={})", - bcx.to_str(), + debug!("trans_fn_ref_with_substs(def_id={}, node={}, \ + param_substs={}, substs={})", def_id.repr(tcx), node, + param_substs.repr(tcx), substs.repr(tcx)); assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); @@ -443,15 +448,15 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( (true, source_id, new_substs) } ty::TypeTraitItem(_) => { - bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \ - to translate an associated type?!") + tcx.sess.bug("trans_fn_ref_with_vtables() tried \ + to translate an associated type?!") } } } }; // If this is an unboxed closure, redirect to it. - match closure::get_or_create_declaration_if_unboxed_closure(bcx, + match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id, &substs) { None => {} @@ -494,24 +499,27 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( MethodCallKey(_) => None, }; - let (val, must_cast) = + let (val, fn_ty, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id); - let mut val = val; if must_cast && node != ExprId(0) { // Monotype of the REFERENCE to the function (type params // are subst'd) let ref_ty = match node { - ExprId(id) => node_id_type(bcx, id), + ExprId(id) => ty::node_id_to_type(tcx, id), MethodCallKey(method_call) => { - let t = (*bcx.tcx().method_map.borrow())[method_call].ty; - monomorphize_type(bcx, t) + (*tcx.method_map.borrow())[method_call].ty } }; - - val = PointerCast( - bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to()); + let ref_ty = monomorphize::apply_param_substs(tcx, + param_substs, + &ref_ty); + let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to(); + if llptrty != val_ty(val) { + let val = consts::ptrcast(val, llptrty); + return Datum::new(val, ref_ty, Rvalue::new(ByValue)); + } } - return val; + return Datum::new(val, fn_ty, Rvalue::new(ByValue)); } // Type scheme of the function item (may have type params) @@ -556,12 +564,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( let llptrty = llty.ptr_to(); if val_ty(val) != llptrty { debug!("trans_fn_ref_with_vtables(): casting pointer!"); - val = BitCast(bcx, val, llptrty); + val = consts::ptrcast(val, llptrty); } else { debug!("trans_fn_ref_with_vtables(): not casting pointer!"); } - val + Datum::new(val, fn_type, Rvalue::new(ByValue)) } // ______________________________________________________________________ @@ -576,7 +584,7 @@ pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_call"); trans_call_inner(in_cx, Some(common::expr_info(call_ex)), - expr_ty(in_cx, f), + expr_ty_adjusted(in_cx, f), |cx, _| trans(cx, f), args, Some(dest)).bcx @@ -661,7 +669,6 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let (abi, ret_ty) = match callee_ty.sty { ty::ty_bare_fn(_, ref f) => (f.abi, f.sig.0.output), - ty::ty_closure(ref f) => (f.abi, f.sig.0.output), _ => panic!("expected bare rust fn or closure in trans_call_inner") }; @@ -672,16 +679,6 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, TraitItem(d) => { (d.llfn, None, Some(d.llself)) } - Closure(d) => { - // Closures are represented as (llfn, llclosure) pair: - // load the requisite values out. - let pair = d.to_llref(); - let llfn = GEPi(bcx, pair, &[0u, abi::FAT_PTR_ADDR]); - let llfn = Load(bcx, llfn); - let llenv = GEPi(bcx, pair, &[0u, abi::FAT_PTR_EXTRA]); - let llenv = Load(bcx, llenv); - (llfn, Some(llenv), None) - } Intrinsic(node, substs) => { assert!(abi == synabi::RustIntrinsic); assert!(dest.is_some()); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 59ba56bbbc8..79a5898e3d3 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -726,7 +726,10 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef { // specify any of the types for the function, we just make it a symbol // that LLVM can later use. let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { - Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)), + Some(def_id) => { + callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0), + pad_bcx.fcx.param_substs).val + } None => { let mut personality = self.ccx.eh_personality().borrow_mut(); match *personality { diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index cb5302f7234..6f2def16e76 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -19,7 +19,8 @@ use trans::build::*; use trans::cleanup::{CleanupMethods, ScopeId}; use trans::common::*; -use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum}; +use trans::datum::{Datum, Lvalue, rvalue_scratch_datum}; +use trans::datum::{Rvalue, ByValue}; use trans::debuginfo; use trans::expr; use trans::monomorphize::{self, MonoId}; @@ -28,10 +29,8 @@ use middle::ty::{self, Ty, UnboxedClosureTyper}; use middle::subst::{Substs}; use session::config::FullDebugInfo; -use util::ppaux::Repr; use util::ppaux::ty_to_string; -use arena::TypedArena; use syntax::ast; use syntax::ast_util; @@ -453,22 +452,21 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Returns the LLVM function declaration for an unboxed closure, creating it /// if necessary. If the ID does not correspond to a closure ID, returns None. -pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option { - let ccx = bcx.ccx(); +pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + closure_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option> { if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) { // Not an unboxed closure. return None } - let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node); - let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type); + let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node); + let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type); // Normalize type so differences in regions and typedefs don't cause // duplicate declarations - let function_type = ty::normalize_ty(bcx.tcx(), function_type); + let function_type = ty::normalize_ty(ccx.tcx(), function_type); let params = match function_type.sty { ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(), _ => unreachable!() @@ -479,10 +477,10 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, }; match ccx.unboxed_closure_vals().borrow().get(&mono_id) { - Some(llfn) => { + Some(&llfn) => { debug!("get_or_create_declaration_if_unboxed_closure(): found \ closure"); - return Some(*llfn) + return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) } None => {} } @@ -502,7 +500,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, ccx.tn().type_to_string(val_ty(llfn))); ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn); - Some(llfn) + Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) } pub fn trans_unboxed_closure<'blk, 'tcx>( @@ -519,7 +517,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( let closure_id = ast_util::local_def(id); let llfn = get_or_create_declaration_if_unboxed_closure( - bcx, + bcx.ccx(), closure_id, bcx.fcx.param_substs).unwrap(); @@ -530,7 +528,6 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( // of the closure expression. let typer = NormalizingUnboxedClosureTyper::new(bcx.tcx()); let function_type = typer.unboxed_closure_type(closure_id, bcx.fcx.param_substs); - let function_type = ty::mk_closure(bcx.tcx(), function_type); let freevars: Vec = ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect()); @@ -539,12 +536,12 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( trans_closure(bcx.ccx(), decl, body, - llfn, + llfn.val, bcx.fcx.param_substs, id, &[], - ty::ty_fn_ret(function_type), - ty::ty_fn_abi(function_type), + function_type.sig.0.output, + function_type.abi, ClosureEnv::new(freevars[], UnboxedClosure(freevar_mode))); @@ -582,98 +579,3 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( bcx } - -pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_ty: Ty<'tcx>, - def_id: ast::DefId, - fn_ptr: ValueRef, - is_local: bool) -> ValueRef { - - match ccx.closure_bare_wrapper_cache().borrow().get(&fn_ptr) { - Some(&llval) => return llval, - None => {} - } - - let tcx = ccx.tcx(); - - debug!("get_wrapper_for_bare_fn(closure_ty={})", closure_ty.repr(tcx)); - - let f = match closure_ty.sty { - ty::ty_closure(ref f) => f, - _ => { - ccx.sess().bug(format!("get_wrapper_for_bare_fn: \ - expected a closure ty, got {}", - closure_ty.repr(tcx))[]); - } - }; - - let name = ty::with_path(tcx, def_id, |path| { - mangle_internal_name_by_path_and_seq(path, "as_closure") - }); - let llfn = if is_local { - decl_internal_rust_fn(ccx, closure_ty, name[]) - } else { - decl_rust_fn(ccx, closure_ty, name[]) - }; - - ccx.closure_bare_wrapper_cache().borrow_mut().insert(fn_ptr, llfn); - - // This is only used by statics inlined from a different crate. - if !is_local { - // Don't regenerate the wrapper, just reuse the original one. - return llfn; - } - - let _icx = push_ctxt("closure::get_wrapper_for_bare_fn"); - - let arena = TypedArena::new(); - let empty_param_substs = Substs::trans_empty(); - let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.0.output, - &empty_param_substs, None, &arena); - let bcx = init_function(&fcx, true, f.sig.0.output); - - let args = create_datums_for_fn_args(&fcx, - ty::ty_fn_args(closure_ty) - []); - let mut llargs = Vec::new(); - match fcx.llretslotptr.get() { - Some(llretptr) => { - assert!(!fcx.needs_ret_allocas); - llargs.push(llretptr); - } - None => {} - } - llargs.extend(args.iter().map(|arg| arg.val)); - - let retval = Call(bcx, fn_ptr, llargs.as_slice(), None); - match f.sig.0.output { - ty::FnConverging(output_type) => { - if return_type_is_void(ccx, output_type) || fcx.llretslotptr.get().is_some() { - RetVoid(bcx); - } else { - Ret(bcx, retval); - } - } - ty::FnDiverging => { - RetVoid(bcx); - } - } - - // HACK(eddyb) finish_fn cannot be used here, we returned directly. - debuginfo::clear_source_location(&fcx); - fcx.cleanup(); - - llfn -} - -pub fn make_closure_from_bare_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - closure_ty: Ty<'tcx>, - def_id: ast::DefId, - fn_ptr: ValueRef) - -> DatumBlock<'blk, 'tcx, Expr> { - let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust"); - let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def_id, fn_ptr, true); - fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p(bcx.ccx()))); - - DatumBlock::new(bcx, scratch.to_expr_datum()) -} diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 87a1862186a..094f98e988a 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -28,6 +28,7 @@ use trans::base; use trans::build; use trans::cleanup; +use trans::consts; use trans::datum; use trans::debuginfo; use trans::machine; @@ -43,7 +44,7 @@ use arena::TypedArena; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::vec::Vec; use syntax::ast::Ident; @@ -400,9 +401,8 @@ pub fn get_llreturn(&self) -> BasicBlockRef { if self.llreturn.get().is_none() { self.llreturn.set(Some(unsafe { - "return".with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf) - }) + llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, + "return\0".as_ptr() as *const _) })) } @@ -428,11 +428,10 @@ pub fn new_block(&'a self, opt_node_id: Option) -> Block<'a, 'tcx> { unsafe { - let llbb = name.with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), - self.llfn, - buf) - }); + let name = CString::from_slice(name.as_bytes()); + let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), + self.llfn, + name.as_ptr()); BlockS::new(llbb, is_lpad, opt_node_id, self) } } @@ -707,7 +706,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf)) + let s = CString::from_slice(s.as_bytes()); + llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr()) } } @@ -788,9 +788,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let g = format!("str{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf) - }); + let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); @@ -803,12 +802,9 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va // NB: Do not use `do_spill_noroot` to make this into a constant string, or // you will be kicked off fast isel. See issue #4352 for an example of this. pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { - unsafe { - let len = s.get().len(); - let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false), - Type::i8p(cx).to_ref()); - C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) - } + let len = s.get().len(); + let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); + C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) } pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { @@ -817,14 +813,15 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { let lldata = C_bytes(cx, data); let gsym = token::gensym("binary"); - let g = format!("binary{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf) - }); + let name = format!("binary{}", gsym.uint()); + let name = CString::from_vec(name.into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), + name.as_ptr()); llvm::LLVMSetInitializer(g, lldata); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); - let cs = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); + let cs = consts::ptrcast(g, Type::i8p(cx)); C_struct(cx, &[cs, C_uint(cx, len)], false) } } @@ -1095,11 +1092,11 @@ pub enum ExprOrMethodCall { MethodCallKey(ty::MethodCall) } -pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - node: ExprOrMethodCall) - -> subst::Substs<'tcx> -{ - let tcx = bcx.tcx(); +pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>) + -> subst::Substs<'tcx> { + let tcx = ccx.tcx(); let substs = match node { ExprId(id) => { @@ -1111,15 +1108,13 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; if substs.types.any(|t| ty::type_needs_infer(*t)) { - bcx.sess().bug( - format!("type parameters for node {} include inference types: \ - {}", - node, - substs.repr(bcx.tcx()))[]); + tcx.sess.bug(format!("type parameters for node {} include inference types: {}", + node, substs.repr(tcx))[]); } - let substs = substs.erase_regions(); - bcx.monomorphize(&substs) + monomorphize::apply_param_substs(tcx, + param_substs, + &substs.erase_regions()) } pub fn langcall(bcx: Block, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 4f8554195e5..a3861e71d83 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -14,17 +14,16 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False}; use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; -use metadata::csearch; use middle::{const_eval, def}; -use trans::{adt, closure, consts, debuginfo, expr, inline, machine}; +use trans::{adt, consts, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; use trans::type_::Type; use trans::type_of; +use middle::subst::Substs; use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; -use std::c_str::ToCStr; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; @@ -79,11 +78,9 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) } } -pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { +pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { unsafe { - let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref()); - assert!(cx.const_globals().borrow_mut().insert(b as int, a).is_none()); - b + llvm::LLVMConstPointerCast(val, ty.to_ref()) } } @@ -105,9 +102,8 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr, pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { unsafe { - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name) - }); + let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), + "const\0".as_ptr() as *const _); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, if mutbl == ast::MutImmutable {True} else {False}); @@ -191,20 +187,6 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr) None => { } Some(adj) => { match adj { - ty::AdjustAddEnv(def_id, ty::RegionTraitStore(ty::ReStatic, _)) => { - let wrapper = closure::get_wrapper_for_bare_fn(cx, - ety_adjusted, - def_id, - llconst, - true); - llconst = C_struct(cx, &[wrapper, C_null(Type::i8p(cx))], false) - } - ty::AdjustAddEnv(_, store) => { - cx.sess() - .span_bug(e.span, - format!("unexpected static function: {}", - store)[]) - } ty::AdjustReifyFnPointer(_def_id) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here @@ -258,7 +240,9 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr) match ty.sty { ty::ty_vec(unit_ty, Some(len)) => { let llunitty = type_of::type_of(cx, unit_ty); - let llptr = const_ptrcast(cx, llconst, llunitty); + let llptr = ptrcast(llconst, llunitty.ptr_to()); + assert!(cx.const_globals().borrow_mut() + .insert(llptr as int, llconst).is_none()); assert_eq!(abi::FAT_PTR_ADDR, 0); assert_eq!(abi::FAT_PTR_EXTRA, 1); llconst = C_struct(cx, &[ @@ -523,7 +507,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { } } (expr::cast_pointer, expr::cast_pointer) => { - llvm::LLVMConstPointerCast(v, llty.to_ref()) + ptrcast(v, llty) } (expr::cast_integral, expr::cast_pointer) => { llvm::LLVMConstIntToPtr(v, llty.to_ref()) @@ -616,36 +600,38 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { C_array(llunitty, vs[]) } } - ast::ExprPath(ref pth) => { - // Assert that there are no type parameters in this path. - assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types())); - - let opt_def = cx.tcx().def_map.borrow().get(&e.id).cloned(); - match opt_def { - Some(def::DefFn(def_id, _)) => { - if !ast_util::is_local(def_id) { - let ty = csearch::get_type(cx.tcx(), def_id).ty; - base::trans_external_path(cx, def_id, ty) - } else { - assert!(ast_util::is_local(def_id)); - base::get_item_val(cx, def_id.node) - } + ast::ExprPath(_) => { + let def = cx.tcx().def_map.borrow()[e.id]; + match def { + def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val } - Some(def::DefConst(def_id)) => { + def::DefConst(def_id) => { get_const_val(cx, def_id) } - Some(def::DefVariant(enum_did, variant_did, _)) => { - let ety = ty::expr_ty(cx.tcx(), e); - let repr = adt::represent_type(cx, ety); + def::DefVariant(enum_did, variant_did, _) => { let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, variant_did); - adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + if vinfo.args.len() > 0 { + // N-ary variant. + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val + } else { + // Nullary variant. + let ety = ty::expr_ty(cx.tcx(), e); + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + } } - Some(def::DefStruct(_)) => { + def::DefStruct(_) => { let ety = ty::expr_ty(cx.tcx(), e); - let llty = type_of::type_of(cx, ety); - C_null(llty) + if let ty::ty_bare_fn(..) = ety.sty { + // Tuple struct. + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val + } else { + // Unit struct. + C_null(type_of::type_of(cx, ety)) + } } _ => { cx.sess().span_bug(e.span, "expected a const, fn, struct, \ diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index e5a0e2e9234..f974a6faf4c 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -29,8 +29,8 @@ use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; -use std::c_str::ToCStr; use std::ptr; use std::rc::Rc; use syntax::ast; @@ -221,21 +221,16 @@ fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> { unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); - let llmod = mod_name.with_c_str(|buf| { - llvm::LLVMModuleCreateWithNameInContext(buf, llcx) - }); - sess.target - .target - .data_layout - .with_c_str(|buf| { - llvm::LLVMSetDataLayout(llmod, buf); - }); - sess.target - .target - .llvm_target - .with_c_str(|buf| { - llvm::LLVMRustSetNormalizedTarget(llmod, buf); - }); + let mod_name = CString::from_slice(mod_name.as_bytes()); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + let data_layout = sess.target.target.data_layout.as_slice(); + let data_layout = CString::from_slice(data_layout.as_bytes()); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_slice(); + let llvm_target = CString::from_slice(llvm_target.as_bytes()); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); (llcx, llmod) } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 916fcbfe13e..f6c09629f31 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -207,7 +207,7 @@ use util::ppaux; use libc::c_uint; -use std::c_str::{CString, ToCStr}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::{Rc, Weak}; @@ -465,11 +465,6 @@ fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>, } } }, - ty::ty_closure(box ref closure_ty) => { - self.get_unique_type_id_of_closure_type(cx, - closure_ty.clone(), - &mut unique_type_id); - }, ty::ty_unboxed_closure(def_id, _, substs) => { let typer = NormalizingUnboxedClosureTyper::new(cx.tcx()); let closure_ty = typer.unboxed_closure_type(def_id, substs); @@ -760,14 +755,15 @@ pub fn finalize(cx: &CrateContext) { // for OS X to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. if cx.sess().target.target.options.is_like_osx { - "Dwarf Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2)); + llvm::LLVMRustAddModuleFlag(cx.llmod(), + "Dwarf Version\0".as_ptr() as *const _, + 2) } // Prevent bitcode readers from deleting the debug info. - "Debug Info Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, - llvm::LLVMRustDebugMetadataVersion)); + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _, + llvm::LLVMRustDebugMetadataVersion); }; } @@ -829,22 +825,20 @@ pub fn create_global_var_metadata(cx: &CrateContext, namespace_node.mangled_name_of_contained_item(var_name[]); let var_scope = namespace_node.scope; - var_name.with_c_str(|var_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name, - linkage_name, - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); - } - }) - }); + let var_name = CString::from_slice(var_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); + } } /// Creates debug information for the given local variable. @@ -1388,28 +1382,26 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id); - let fn_metadata = function_name.with_c_str(|function_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name, - linkage_name, - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - FlagPrototyped as c_uint, - cx.sess().opts.optimize != config::No, - llfn, - template_parameters, - ptr::null_mut()) - } - }) - }); + let function_name = CString::from_slice(function_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + let fn_metadata = unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + FlagPrototyped as c_uint, + cx.sess().opts.optimize != config::No, + llfn, + template_parameters, + ptr::null_mut()) + }; let scope_map = create_scope_map(cx, fn_decl.inputs.as_slice(), @@ -1514,19 +1506,18 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let ident = special_idents::type_self; - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_self_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_self_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } @@ -1549,19 +1540,18 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == FullDebugInfo { let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP); - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } } @@ -1606,19 +1596,19 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { } else { match abs_path.path_relative_from(work_dir) { Some(ref p) if p.is_relative() => { - // prepend "./" if necessary - let dotdot = b".."; - let prefix = [dotdot[0], ::std::path::SEP_BYTE]; - let mut path_bytes = p.as_vec().to_vec(); - - if path_bytes.slice_to(2) != prefix && - path_bytes.slice_to(2) != dotdot { - path_bytes.insert(0, prefix[0]); - path_bytes.insert(1, prefix[1]); - } - - path_bytes.to_c_str() + // prepend "./" if necessary + let dotdot = b".."; + let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE]; + let mut path_bytes = p.as_vec().to_vec(); + + if path_bytes.slice_to(2) != prefix && + path_bytes.slice_to(2) != dotdot { + path_bytes.insert(0, prefix[0]); + path_bytes.insert(1, prefix[1]); } + + CString::from_vec(path_bytes) + } _ => fallback_path(cx) } } @@ -1630,29 +1620,25 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); - return work_dir.as_vec().with_c_str(|work_dir| { - producer.with_c_str(|producer| { - "".with_c_str(|flags| { - "".with_c_str(|split_name| { - unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, - DW_LANG_RUST, - compile_unit_name, - work_dir, - producer, - cx.sess().opts.optimize != config::No, - flags, - 0, - split_name) - } - }) - }) - }) - }); + let work_dir = CString::from_slice(work_dir.as_vec()); + let producer = CString::from_slice(producer.as_bytes()); + let flags = "\0"; + let split_name = "\0"; + return unsafe { + llvm::LLVMDIBuilderCreateCompileUnit( + debug_context(cx).builder, + DW_LANG_RUST, + compile_unit_name, + work_dir.as_ptr(), + producer.as_ptr(), + cx.sess().opts.optimize != config::No, + flags.as_ptr() as *const _, + 0, + split_name.as_ptr() as *const _) + }; fn fallback_path(cx: &CrateContext) -> CString { - cx.link_meta().crate_name.to_c_str() + CString::from_slice(cx.link_meta().crate_name.as_bytes()) } } @@ -1678,42 +1664,41 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, CapturedVariable => (0, DW_TAG_auto_variable) }; - let (var_alloca, var_metadata) = name.get().with_c_str(|name| { - match variable_access { - DirectVariable { alloca } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::No, - 0, - argument_index) - } - ), - IndirectVariable { alloca, address_operations } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateComplexVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - argument_index) - } - ) - } - }); + let name = CString::from_slice(name.get().as_bytes()); + let (var_alloca, var_metadata) = match variable_access { + DirectVariable { alloca } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::No, + 0, + argument_index) + } + ), + IndirectVariable { alloca, address_operations } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + argument_index) + } + ) + }; set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, @@ -1758,14 +1743,12 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile { full_path }; - let file_metadata = - file_name.with_c_str(|file_name| { - work_dir.with_c_str(|work_dir| { - unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) - } - }) - }); + let file_name = CString::from_slice(file_name.as_bytes()); + let work_dir = CString::from_slice(work_dir.as_bytes()); + let file_metadata = unsafe { + llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) + }; let mut created_files = debug_context(cx).created_files.borrow_mut(); created_files.insert(full_path.to_string(), file_metadata); @@ -1793,16 +1776,14 @@ fn scope_metadata(fcx: &FunctionContext, } fn diverging_type_metadata(cx: &CrateContext) -> DIType { - "!".with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(0), - bytes_to_bits(0), - DW_ATE_unsigned) - } - }) + unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + "!\0".as_ptr() as *const _, + bytes_to_bits(0), + bytes_to_bits(0), + DW_ATE_unsigned) + } } fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -1838,16 +1819,15 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let llvm_type = type_of::type_of(cx, t); let (size, align) = size_and_align_of(cx, llvm_type); - let ty_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(size), - bytes_to_bits(align), - encoding) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ty_metadata = unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr(), + bytes_to_bits(size), + bytes_to_bits(align), + encoding) + }; return ty_metadata; } @@ -1859,16 +1839,15 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let pointer_llvm_type = type_of::type_of(cx, pointer_type); let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type); let name = compute_debuginfo_type_name(cx, pointer_type, false); - let ptr_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align), - name) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ptr_metadata = unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + bytes_to_bits(pointer_size), + bytes_to_bits(pointer_align), + name.as_ptr()) + }; return ptr_metadata; } @@ -2478,14 +2457,14 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enumerators_metadata: Vec = variants .iter() .map(|v| { - token::get_name(v.name).get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerator( - DIB(cx), - name, - v.disr_val as u64) - } - }) + let token = token::get_name(v.name); + let name = CString::from_slice(token.get().as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + v.disr_val as u64) + } }) .collect(); @@ -2509,20 +2488,19 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, codemap::DUMMY_SP); let discriminant_name = get_enum_discriminant_name(cx, enum_def_id); - let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align), - create_DIArray(DIB(cx), enumerators_metadata[]), - discriminant_base_type_metadata) - } - }); + let name = CString::from_slice(discriminant_name.get().as_bytes()); + let discriminant_type_metadata = unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata.as_slice()), + discriminant_base_type_metadata) + }; debug_context(cx).created_enum_disr_types .borrow_mut() @@ -2553,24 +2531,22 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .borrow() .get_unique_type_id_as_string(unique_type_id); - let enum_metadata = enum_name.with_c_str(|enum_name| { - unique_type_id_str.with_c_str(|unique_type_id_str| { - unsafe { - llvm::LLVMDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align), - 0, // Flags - ptr::null_mut(), - 0, // RuntimeLang - unique_type_id_str) - } - }) - }); + let enum_name = CString::from_slice(enum_name.as_bytes()); + let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes()); + let enum_metadata = unsafe { + llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + ptr::null_mut(), + 0, // RuntimeLang + unique_type_id_str.as_ptr()) + }; return create_and_register_recursive_type_forward_declaration( cx, @@ -2681,21 +2657,20 @@ fn set_members_of_composite_type(cx: &CrateContext, ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i) }; - member_description.name.with_c_str(|member_name| { - unsafe { - llvm::LLVMDIBuilderCreateMemberType( - DIB(cx), - composite_type_metadata, - member_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(member_size), - bytes_to_bits(member_align), - bytes_to_bits(member_offset), - member_description.flags, - member_description.type_metadata) - } - }) + let member_name = CString::from_slice(member_description.name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + member_description.flags, + member_description.type_metadata) + } }) .collect(); @@ -2719,30 +2694,28 @@ fn create_struct_stub(cx: &CrateContext, let unique_type_id_str = debug_context(cx).type_map .borrow() .get_unique_type_id_as_string(unique_type_id); + let name = CString::from_slice(struct_type_name.as_bytes()); + let unique_type_id = CString::from_slice(unique_type_id_str.as_bytes()); let metadata_stub = unsafe { - struct_type_name.with_c_str(|name| { - unique_type_id_str.with_c_str(|unique_type_id| { - // LLVMDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - llvm::LLVMDIBuilderCreateStructType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(struct_size), - bytes_to_bits(struct_align), - 0, - ptr::null_mut(), - empty_array, - 0, - ptr::null_mut(), - unique_type_id) - }) - }) + // LLVMDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(struct_size), + bytes_to_bits(struct_align), + 0, + ptr::null_mut(), + empty_array, + 0, + ptr::null_mut(), + unique_type_id.as_ptr()) }; return metadata_stub; @@ -3017,9 +2990,6 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(_, ref barefnty) => { subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) } - ty::ty_closure(ref closurety) => { - subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span) - } ty::ty_unboxed_closure(def_id, _, substs) => { let typer = NormalizingUnboxedClosureTyper::new(cx.tcx()); let sig = typer.unboxed_closure_type(def_id, substs).sig; @@ -3870,66 +3840,6 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } }, - ty::ty_closure(box ty::ClosureTy { unsafety, - onceness, - store, - ref sig, - .. // omitting bounds ... - }) => { - if unsafety == ast::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - if onceness == ast::Once { - output.push_str("once "); - } - - let param_list_closing_char; - match store { - ty::UniqTraitStore => { - output.push_str("proc("); - param_list_closing_char = ')'; - } - ty::RegionTraitStore(_, ast::MutMutable) => { - output.push_str("&mut|"); - param_list_closing_char = '|'; - } - ty::RegionTraitStore(_, ast::MutImmutable) => { - output.push_str("&|"); - param_list_closing_char = '|'; - } - }; - - if sig.0.inputs.len() > 0 { - for ¶meter_type in sig.0.inputs.iter() { - push_debuginfo_type_name(cx, parameter_type, true, output); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.0.variadic { - if sig.0.inputs.len() > 0 { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(param_list_closing_char); - - match sig.0.output { - ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} - ty::FnConverging(result_type) => { - output.push_str(" -> "); - push_debuginfo_type_name(cx, result_type, true, output); - } - ty::FnDiverging => { - output.push_str(" -> !"); - } - } - }, ty::ty_unboxed_closure(..) => { output.push_str("closure"); } @@ -4079,18 +3989,18 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc ptr::null_mut() }; let namespace_name = token::get_name(name); - let scope = namespace_name.get().with_c_str(|namespace_name| { - unsafe { - llvm::LLVMDIBuilderCreateNameSpace( - DIB(cx), - parent_scope, - namespace_name, - // cannot reconstruct file ... - ptr::null_mut(), - // ... or line information, but that's not so important. - 0) - } - }); + let namespace_name = CString::from_slice(namespace_name + .get().as_bytes()); + let scope = unsafe { + llvm::LLVMDIBuilderCreateNameSpace( + DIB(cx), + parent_scope, + namespace_name.as_ptr(), + // cannot reconstruct file ... + ptr::null_mut(), + // ... or line information, but that's not so important. + 0) + }; let node = Rc::new(NamespaceTreeNode { name: name, @@ -4128,7 +4038,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__".to_c_str(); + let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; let section_var = unsafe { - llvm::LLVMGetNamedGlobal(ccx.llmod(), section_var_name.as_ptr()) + llvm::LLVMGetNamedGlobal(ccx.llmod(), + section_var_name.as_ptr() as *const _) }; if section_var == ptr::null_mut() { - let section_name = b".debug_gdb_scripts".to_c_str(); + let section_name = b".debug_gdb_scripts\0"; let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; unsafe { @@ -4160,8 +4071,9 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) section_contents.len() as u64); let section_var = llvm::LLVMAddGlobal(ccx.llmod(), llvm_type.to_ref(), - section_var_name.as_ptr()); - llvm::LLVMSetSection(section_var, section_name.as_ptr()); + section_var_name.as_ptr() + as *const _); + llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index c525e6fcfe3..9221ae09df9 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -54,7 +54,7 @@ use trans::tvec; use trans::type_of; use middle::ty::{struct_fields, tup_fields}; -use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustAddEnv, AutoUnsafe}; +use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AutoUnsafe}; use middle::ty::{AutoPtr}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; @@ -179,9 +179,6 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum.to_string(bcx.ccx()), adjustment.repr(bcx.tcx())); match adjustment { - AdjustAddEnv(def_id, _) => { - datum = unpack_datum!(bcx, add_env(bcx, def_id, expr, datum)); - } AdjustReifyFnPointer(_def_id) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here @@ -476,22 +473,6 @@ fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, scratch.to_expr_datum()) } - - fn add_env<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def_id: ast::DefId, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { - // This is not the most efficient thing possible; since closures - // 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 - // code and keep it DRY that accommodates that use case at the - // moment. - - let closure_ty = expr_ty_adjusted(bcx, expr); - let fn_ptr = datum.to_llscalarish(bcx); - closure::make_closure_from_bare_fn(bcx, closure_ty, def_id, fn_ptr) - } } /// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory @@ -853,7 +834,9 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) | def::DefStruct(_) | def::DefVariant(..) => { - trans_def_fn_unadjusted(bcx, ref_expr, def) + let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def, + bcx.fcx.param_substs); + DatumBlock::new(bcx, datum.to_expr_datum()) } def::DefStatic(did, _) => { // There are two things that may happen here: @@ -1250,7 +1233,9 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); if variant_info.args.len() > 0u { // N-ary variant. - let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id)); + let llfn = callee::trans_fn_ref(bcx.ccx(), vid, + ExprId(ref_expr.id), + bcx.fcx.param_substs).val; Store(bcx, llfn, lldest); return bcx; } else { @@ -1281,34 +1266,33 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - ref_expr: &ast::Expr, - def: def::Def) - -> DatumBlock<'blk, 'tcx, Expr> { +pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ref_expr: &ast::Expr, + def: def::Def, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_def_datum_unadjusted"); - let llfn = match def { + match def { def::DefFn(did, _) | def::DefStruct(did) | def::DefVariant(_, did, _) | def::DefStaticMethod(did, def::FromImpl(_)) | def::DefMethod(did, _, def::FromImpl(_)) => { - callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id)) + callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) } def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) | def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => { - meth::trans_static_method_callee(bcx, impl_did, - trait_did, ref_expr.id) + meth::trans_static_method_callee(ccx, impl_did, + trait_did, ref_expr.id, + param_substs) } _ => { - bcx.tcx().sess.span_bug(ref_expr.span, format!( + ccx.tcx().sess.span_bug(ref_expr.span, format!( "trans_def_fn_unadjusted invoked on: {} for {}", def, - ref_expr.repr(bcx.tcx()))[]); + ref_expr.repr(ccx.tcx()))[]); } - }; - - let fn_ty = expr_ty(bcx, ref_expr); - DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue)))) + } } /// Translates a reference to a local variable or argument. This always results in an lvalue datum. diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index a4cfec791d8..1c9be6ae4a8 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -24,9 +24,10 @@ use trans::type_of::*; use trans::type_of; use middle::ty::{self, Ty}; -use middle::subst::{Substs}; +use middle::subst::Substs; + +use std::ffi::CString; use std::cmp; -use std::c_str::ToCStr; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; @@ -132,9 +133,9 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf) - }); + let buf = CString::from_slice(ident.get().as_bytes()); + let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), + buf.as_ptr()); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -145,9 +146,9 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(ident.get()); - let g2 = real_name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }); + let real_name = CString::from_vec(real_name.into_bytes()); + let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), + real_name.as_ptr()); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 @@ -155,9 +156,8 @@ pub fn register_static(ccx: &CrateContext, } None => unsafe { // Generate an external declaration. - ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }) + let buf = CString::from_slice(ident.get().as_bytes()); + llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) } } } @@ -606,9 +606,9 @@ unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } - let the_block = - "the block".with_c_str( - |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s)); + let ptr = "the block\0".as_ptr(); + let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, + ptr as *const _); let builder = ccx.builder(); builder.position_at_end(the_block); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 0ff53a1af71..2fd9031fdfe 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -26,6 +26,7 @@ use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; +use trans::consts; use trans::common::*; use trans::datum; use trans::debuginfo; @@ -39,8 +40,8 @@ use util::ppaux; use arena::TypedArena; -use std::c_str::ToCStr; use libc::c_uint; +use std::ffi::CString; use syntax::ast; use syntax::parse::token; @@ -440,18 +441,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None)), - ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => { - let box_cell_v = GEPi(bcx, v0, &[0u, abi::FAT_PTR_EXTRA]); - let env = Load(bcx, box_cell_v); - let env_ptr_ty = Type::at_box(bcx.ccx(), Type::i8(bcx.ccx())).ptr_to(); - let env = PointerCast(bcx, env, env_ptr_ty); - with_cond(bcx, IsNotNull(bcx, env), |bcx| { - let dtor_ptr = GEPi(bcx, env, &[0u, abi::BOX_FIELD_DROP_GLUE]); - let dtor = Load(bcx, dtor_ptr); - Call(bcx, dtor, &[PointerCast(bcx, box_cell_v, Type::i8p(bcx.ccx()))], None); - bcx - }) - } ty::ty_trait(..) => { // No need to do a null check here (as opposed to the Box(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) let llalign = llalign_of(ccx, llty); let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc"); debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name); - let gvar = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let gvar = unsafe { + llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), + buf.as_ptr()) + }; note_unique_llvm_symbol(ccx, name); let ty_name = token::intern_and_get_ident( @@ -530,13 +519,14 @@ fn declare_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, return (fn_nm, llfn); } -fn make_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, - llfn: ValueRef, - helper: for<'blk> |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>| - -> Block<'blk, 'tcx>, - name: &str) - -> ValueRef { +fn make_generic_glue<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>, + t: Ty<'tcx>, + llfn: ValueRef, + helper: F, + name: &str) + -> ValueRef where + F: for<'blk> FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, +{ let _icx = push_ctxt("make_generic_glue"); let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx(), t)); let _s = StatRecorder::new(ccx, glue_name); @@ -577,9 +567,7 @@ pub fn emit_tydescs(ccx: &CrateContext) { // before being put into the tydesc because we only have a singleton // tydesc type. Then we'll recast each function to its real type when // calling it. - let drop_glue = unsafe { - llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref()) - }; + let drop_glue = consts::ptrcast(get_drop_glue(ccx, ti.ty), glue_fn_ty); ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1); let tydesc = C_named_struct(ccx.tydesc_type(), diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index bde9051ec74..dd1cfc5ad6d 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -40,7 +40,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) let csearch_result = csearch::maybe_get_item_ast( ccx.tcx(), fn_id, - |a,b,c,d| astencode::decode_inlined_item(a, b, c, d)); + box |a,b,c,d| astencode::decode_inlined_item(a, b, c, d)); let inline_def = match csearch_result { csearch::not_found => { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index ca17f3558ae..f6d69959dad 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -34,7 +34,7 @@ use middle::ty::MethodCall; use util::ppaux::Repr; -use std::c_str::ToCStr; +use std::ffi::CString; use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; @@ -122,9 +122,10 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::MethodStaticUnboxedClosure(did) => { Callee { bcx: bcx, - data: Fn(callee::trans_fn_ref(bcx, + data: Fn(callee::trans_fn_ref(bcx.ccx(), did, - MethodCallKey(method_call))), + MethodCallKey(method_call), + bcx.fcx.param_substs).val), } } @@ -166,30 +167,31 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn trans_static_method_callee(bcx: Block, - method_id: ast::DefId, - trait_id: ast::DefId, - expr_id: ast::NodeId) - -> ValueRef +pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + method_id: ast::DefId, + trait_id: ast::DefId, + expr_id: ast::NodeId, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("meth::trans_static_method_callee"); - let ccx = bcx.ccx(); + let tcx = ccx.tcx(); debug!("trans_static_method_callee(method_id={}, trait_id={}, \ expr_id={})", method_id, - ty::item_path_str(bcx.tcx(), trait_id), + ty::item_path_str(tcx, trait_id), expr_id); let mname = if method_id.krate == ast::LOCAL_CRATE { - match bcx.tcx().map.get(method_id.node) { + match tcx.map.get(method_id.node) { ast_map::NodeTraitItem(method) => { let ident = match *method { ast::RequiredMethod(ref m) => m.ident, ast::ProvidedMethod(ref m) => m.pe_ident(), ast::TypeTraitItem(_) => { - bcx.tcx().sess.bug("trans_static_method_callee() on \ - an associated type?!") + tcx.sess.bug("trans_static_method_callee() on \ + an associated type?!") } }; ident.name @@ -197,7 +199,7 @@ pub fn trans_static_method_callee(bcx: Block, _ => panic!("callee is not a trait method") } } else { - csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name() + csearch::get_item_path(tcx, method_id).last().unwrap().name() }; debug!("trans_static_method_callee: method_id={}, expr_id={}, \ name={}", method_id, expr_id, token::get_name(mname)); @@ -205,7 +207,7 @@ pub fn trans_static_method_callee(bcx: Block, // Find the substitutions for the fn itself. This includes // type parameters that belong to the trait but also some that // belong to the method: - let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); + let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs); let subst::SeparateVecsPerParamSpace { types: rcvr_type, selfs: rcvr_self, @@ -238,11 +240,11 @@ pub fn trans_static_method_callee(bcx: Block, Substs::erased(VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())); - let trait_substs = bcx.tcx().mk_substs(trait_substs); - debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); + let trait_substs = tcx.mk_substs(trait_substs); + debug!("trait_substs={}", trait_substs.repr(tcx)); let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id, substs: trait_substs })); - let vtbl = fulfill_obligation(bcx.ccx(), + let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); @@ -282,17 +284,13 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_method)); let mth_id = method_with_name(ccx, impl_did, mname); - let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id), - callee_substs); - - let callee_ty = node_id_type(bcx, expr_id); - let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); - PointerCast(bcx, llfn, llty) + trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id), + param_substs, + callee_substs) } _ => { - bcx.tcx().sess.bug( - format!("static call to invalid vtable: {}", - vtbl.repr(bcx.tcx()))[]); + tcx.sess.bug(format!("static call to invalid vtable: {}", + vtbl.repr(tcx))[]); } } } @@ -346,20 +344,22 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, MethodCallKey(method_call), vtable_impl.substs); // translate the function - let llfn = trans_fn_ref_with_substs(bcx, + let llfn = trans_fn_ref_with_substs(bcx.ccx(), mth_id, MethodCallKey(method_call), - callee_substs); + bcx.fcx.param_substs, + callee_substs).val; Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableUnboxedClosure(closure_def_id, substs) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let llfn = trans_fn_ref_with_substs(bcx, + let llfn = trans_fn_ref_with_substs(bcx.ccx(), closure_def_id, MethodCallKey(method_call), - substs); + bcx.fcx.param_substs, + substs).val; Callee { bcx: bcx, @@ -400,7 +400,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, { let ccx = bcx.ccx(); - let node_substs = node_id_substs(bcx, node); + let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs); debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx())); debug!("node_substs={}", node_substs.repr(ccx.tcx())); @@ -599,8 +599,27 @@ pub fn trans_object_shim<'a, 'tcx>( bcx.val_to_string(llobject)); // the remaining arguments will be, well, whatever they are + let input_tys = + match fty.abi { + RustCall => { + // unpack the tuple to extract the input type arguments: + match fty.sig.0.inputs[1].sty { + ty::ty_tup(ref tys) => tys.as_slice(), + _ => { + bcx.sess().bug( + format!("rust-call expects a tuple not {}", + fty.sig.0.inputs[1].repr(tcx)).as_slice()); + } + } + } + _ => { + // skip the self parameter: + fty.sig.0.inputs.slice_from(1) + } + }; + let llargs: Vec<_> = - fty.sig.0.inputs[1..].iter() + input_tys.iter() .enumerate() .map(|(i, _)| { let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32); @@ -609,6 +628,7 @@ pub fn trans_object_shim<'a, 'tcx>( llarg }) .collect(); + assert!(!fcx.needs_ret_allocas); let dest = @@ -684,10 +704,11 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } traits::VtableUnboxedClosure(closure_def_id, substs) => { let llfn = trans_fn_ref_with_substs( - bcx, + bcx.ccx(), closure_def_id, ExprId(0), - substs.clone()); + bcx.fcx.param_substs, + substs.clone()).val; (vec!(llfn)).into_iter() } @@ -741,9 +762,9 @@ pub fn make_vtable>(ccx: &CrateContext, unsafe { let tbl = C_struct(ccx, components[], false); let sym = token::gensym("vtable"); - let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf) - }); + let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes()); + let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), + buf.as_ptr()); llvm::LLVMSetInitializer(vt_gvar, tbl); llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True); llvm::SetLinkage(vt_gvar, llvm::InternalLinkage); @@ -788,10 +809,11 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(C_null(Type::nil(ccx).ptr_to())).into_iter() } else { let fn_ref = trans_fn_ref_with_substs( - bcx, + ccx, m_id, ExprId(0), - substs.clone()); + bcx.fcx.param_substs, + substs.clone()).val; // currently, at least, by-value self is not object safe assert!(m.explicit_self != ty::ByValueExplicitSelfCategory); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 51a6bc3bfd5..e6db462a342 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -38,7 +38,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: ast::DefId, psubsts: &subst::Substs<'tcx>, ref_id: Option) - -> (ValueRef, bool) { + -> (ValueRef, Ty<'tcx>, bool) { debug!("monomorphic_fn(\ fn_id={}, \ real_substs={}, \ @@ -58,11 +58,14 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, params: psubsts.types.clone() }; + let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty; + let mono_ty = item_ty.subst(ccx.tcx(), psubsts); + match ccx.monomorphized().borrow().get(&hash_id) { Some(&val) => { debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); - return (val, false); + return (val, mono_ty, false); } None => () } @@ -75,8 +78,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, psubsts.repr(ccx.tcx()), hash_id); - let tpt = ty::lookup_item_type(ccx.tcx(), fn_id); - let llitem_ty = tpt.ty; let map_node = session::expect( ccx.sess(), @@ -91,13 +92,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let ast_map::NodeForeignItem(_) = map_node { if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic { // Foreign externs don't have to be monomorphized. - return (get_item_val(ccx, fn_id.node), true); + return (get_item_val(ccx, fn_id.node), mono_ty, true); } } - debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx())); + debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx())); - let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts); debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx())); let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty); @@ -283,7 +283,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.monomorphizing().borrow_mut().insert(fn_id, depth); debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); - (lldecl, true) + (lldecl, mono_ty, true) } #[derive(PartialEq, Eq, Hash, Show)] diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index f8d0d4f5c7b..e3288466aa7 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -19,6 +19,7 @@ use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; +use trans::consts; use trans::datum::*; use trans::expr::{Dest, Ignore, SaveIn}; use trans::expr; @@ -213,15 +214,13 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match dest { Ignore => bcx, SaveIn(lldest) => { - unsafe { - let bytes = str_lit.get().len(); - let llbytes = C_uint(bcx.ccx(), bytes); - let llcstr = C_cstr(bcx.ccx(), str_lit, false); - let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref()); - Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR])); - Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA])); - bcx - } + let bytes = str_lit.get().len(); + let llbytes = C_uint(bcx.ccx(), bytes); + let llcstr = C_cstr(bcx.ccx(), str_lit, false); + let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx())); + Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR])); + Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA])); + bcx } } } @@ -417,15 +416,14 @@ pub fn get_base_and_len(bcx: Block, } } -pub type iter_vec_block<'a, 'blk, 'tcx> = - |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>; - -pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, data_ptr: ValueRef, vt: &VecTypes<'tcx>, count: ValueRef, - f: iter_vec_block<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: F) + -> Block<'blk, 'tcx> where + F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, +{ let _icx = push_ctxt("tvec::iter_vec_loop"); let fcx = bcx.fcx; @@ -476,12 +474,14 @@ pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, next_bcx } -pub fn iter_vec_raw<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - data_ptr: ValueRef, - unit_ty: Ty<'tcx>, - len: ValueRef, - f: iter_vec_block<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { +pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, + data_ptr: ValueRef, + unit_ty: Ty<'tcx>, + len: ValueRef, + f: F) + -> Block<'blk, 'tcx> where + F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, +{ let _icx = push_ctxt("tvec::iter_vec_raw"); let fcx = bcx.fcx; diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 5b76f5bb827..3785c2fb9bc 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -19,7 +19,7 @@ use syntax::ast; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::cell::RefCell; use std::iter::repeat; @@ -157,7 +157,8 @@ pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type { } pub fn named_struct(ccx: &CrateContext, name: &str) -> Type { - ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx(), s))) + let name = CString::from_slice(name.as_bytes()); + ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr())) } pub fn empty_struct(ccx: &CrateContext) -> Type { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index fbbf2ac80d5..3e499ea8498 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -143,13 +143,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Given a function type and a count of ty params, construct an llvm type pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type { match fty.sty { - ty::ty_closure(ref f) => { - type_of_rust_fn(cx, - Some(Type::i8p(cx)), - f.sig.0.inputs.as_slice(), - f.sig.0.output, - f.abi) - } ty::ty_bare_fn(_, ref f) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here @@ -207,7 +200,6 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } ty::ty_bare_fn(..) => Type::i8p(cx), - ty::ty_closure(..) => Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false), ty::ty_vec(ty, Some(size)) => { let llty = sizing_type_of(cx, ty); @@ -369,10 +361,6 @@ fn type_of_unsize_info<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty ty::ty_bare_fn(..) => { type_of_fn_from_ty(cx, t).ptr_to() } - ty::ty_closure(_) => { - let fn_ty = type_of_fn_from_ty(cx, t).ptr_to(); - Type::struct_(cx, &[fn_ty, Type::i8p(cx)], false) - } ty::ty_tup(ref tys) if tys.is_empty() => Type::nil(cx), ty::ty_tup(..) => { let repr = adt::represent_type(cx, t); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1d62733875e..bde834c2ff8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,7 +53,8 @@ use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; -use middle::ty::{self, RegionEscape, Ty}; +use middle::traits; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; @@ -70,7 +71,9 @@ pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; + fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>; + fn get_trait_def(&self, id: ast::DefId) -> Rc>; /// Return an (optional) substitution to convert bound type parameters that @@ -162,9 +165,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) r } -pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn opt_ast_region_to_region<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, default_span: Span, opt_lifetime: &Option) -> ty::Region { @@ -241,13 +244,12 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, /// returns an appropriate set of substitutions for this particular reference to `I`. -fn ast_path_substs_for_ty<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn ast_path_substs_for_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, decl_generics: &ty::Generics<'tcx>, path: &ast::Path) -> Substs<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope { let tcx = this.tcx(); @@ -285,16 +287,15 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( regions) } -fn create_substs_for_ast_path<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn create_substs_for_ast_path<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, regions: Vec) - -> Substs<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope + -> Substs<'tcx> { let tcx = this.tcx(); @@ -408,13 +409,12 @@ struct ConvertedBinding<'tcx> { span: Span, } -fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC, - rscope: &RS, - data: &ast::AngleBracketedParameterData) - -> (Vec, - Vec>, - Vec>) - where AC: AstConv<'tcx>, RS: RegionScope +fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + data: &ast::AngleBracketedParameterData) + -> (Vec, + Vec>, + Vec>) { let regions: Vec<_> = data.lifetimes.iter() @@ -468,12 +468,11 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) (implied_output_region, lifetimes_for_params) } -fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC, - implied_output_region: Option, - param_lifetimes: Vec<(String, uint)>, - ty: &ast::Ty) - -> Ty<'tcx> - where AC: AstConv<'tcx> +fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, + implied_output_region: Option, + param_lifetimes: Vec<(String, uint)>, + ty: &ast::Ty) + -> Ty<'tcx> { match implied_output_region { Some(implied_output_region) => { @@ -490,10 +489,9 @@ fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC, } } -fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, - data: &ast::ParenthesizedParameterData) - -> Vec> - where AC: AstConv<'tcx> +fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, + data: &ast::ParenthesizedParameterData) + -> Vec> { let binding_rscope = BindingRscope::new(); let inputs = data.inputs.iter() @@ -517,14 +515,13 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } -pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn instantiate_poly_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_trait_ref: &ast::PolyTraitRef, self_ty: Option>, poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope { let mut projections = Vec::new(); @@ -545,14 +542,13 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( /// /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. -pub fn instantiate_trait_ref<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn instantiate_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_trait_ref: &ast::TraitRef, self_ty: Option>, projections: Option<&mut Vec>>) -> Rc> - where AC: AstConv<'tcx>, RS: RegionScope { match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { @@ -573,15 +569,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>( } } -fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn ast_path_to_trait_ref<'a,'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, trait_def_id: ast::DefId, self_ty: Option>, path: &ast::Path, mut projections: Option<&mut Vec>>) -> Rc> - where AC: AstConv<'tcx>, RS: RegionScope { debug!("ast_path_to_trait_ref {}", path); let trait_def = this.get_trait_def(trait_def_id); @@ -632,7 +627,8 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( } Some(ref mut v) => { for binding in assoc_bindings.iter() { - match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) { + match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), + self_ty, binding) { Ok(pp) => { v.push(pp); } Err(ErrorReported) => { } } @@ -643,13 +639,15 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( trait_ref } -pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( - this: &AC, - trait_ref: Rc>, +fn ast_type_binding_to_projection_predicate<'tcx>( + this: &AstConv<'tcx>, + mut trait_ref: Rc>, + self_ty: Option>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> - where AC : AstConv<'tcx> { + let tcx = this.tcx(); + // Given something like `U : SomeTrait`, we want to produce a // predicate like `::T = X`. This is somewhat // subtle in the event that `T` is defined in a supertrait of @@ -666,29 +664,93 @@ pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( // // We want to produce `>::T == foo`. - // FIXME(#19541): supertrait upcasting not actually impl'd :) + // Simple case: X is defined in the current trait. + if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { + return Ok(ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: binding.item_name, + }, + ty: binding.ty, + }); + } - if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { - this.tcx().sess.span_err( + // Otherwise, we have to walk through the supertraits to find + // those that do. This is complicated by the fact that, for an + // object type, the `Self` type is not present in the + // substitutions (after all, it's being constructed right now), + // but the `supertraits` iterator really wants one. To handle + // this, we currently insert a dummy type and then remove it + // later. Yuck. + + let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); + if self_ty.is_none() { // if converting for an object type + let mut dummy_substs = trait_ref.substs.clone(); + assert!(dummy_substs.self_ty().is_none()); + dummy_substs.types.push(SelfSpace, dummy_self_ty); + trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id, + tcx.mk_substs(dummy_substs))); + } + + let mut candidates: Vec = + traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) + .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name)) + .collect(); + + // If converting for an object type, then remove the dummy-ty from `Self` now. + // Yuckety yuck. + if self_ty.is_none() { + for candidate in candidates.iter_mut() { + let mut dummy_substs = candidate.0.substs.clone(); + assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); + dummy_substs.types.pop(SelfSpace); + *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(), + tcx.mk_substs(dummy_substs)))); + } + } + + if candidates.len() > 1 { + tcx.sess.span_err( + binding.span, + format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`", + token::get_name(binding.item_name), + candidates.user_string(tcx)).as_slice()); + return Err(ErrorReported); + } + + let candidate = match candidates.pop() { + Some(c) => c, + None => { + tcx.sess.span_err( + binding.span, + format!("no associated type `{}` defined in `{}`", + token::get_name(binding.item_name), + trait_ref.user_string(tcx)).as_slice()); + return Err(ErrorReported); + } + }; + + if ty::binds_late_bound_regions(tcx, &candidate) { + tcx.sess.span_err( binding.span, - format!("no associated type `{}` defined in `{}`", + format!("associated type `{}` defined in higher-ranked supertrait `{}`", token::get_name(binding.item_name), - trait_ref.user_string(this.tcx())).as_slice()); + candidate.user_string(tcx)).as_slice()); return Err(ErrorReported); } Ok(ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, + trait_ref: candidate.0, item_name: binding.item_name, }, ty: binding.ty, }) } -pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn ast_path_to_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, did: ast::DefId, path: &ast::Path) -> TypeAndSubsts<'tcx> @@ -712,13 +774,12 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( /// and/or region variables are substituted. /// /// This is used when checking the constructor in struct literals. -pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn ast_path_to_ty_relaxed<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, did: ast::DefId, path: &ast::Path) -> TypeAndSubsts<'tcx> - where AC : AstConv<'tcx>, RS : RegionScope { let tcx = this.tcx(); let ty::TypeScheme { @@ -754,9 +815,9 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( /// Converts the given AST type to a built-in type. A "built-in type" is, at /// present, either a core numeric type, a string, or `Box`. -pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn ast_ty_to_builtin_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_ty: &ast::Ty) -> Option> { match ast_ty_to_prim_ty(this.tcx(), ast_ty) { @@ -807,12 +868,11 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); -fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, - rscope: &RS, - ty: &ast::Ty, - bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> - where AC : AstConv<'tcx>, RS : RegionScope +fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + ty: &ast::Ty, + bounds: &[ast::TyParamBound]) + -> Result, ErrorReported> { /*! * In a type like `Foo + Send`, we want to wait to collect the @@ -878,14 +938,13 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, } } -fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, - rscope: &RS, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - bounds: &[ast::TyParamBound]) - -> Ty<'tcx> - where AC : AstConv<'tcx>, RS : RegionScope +fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, + bounds: &[ast::TyParamBound]) + -> Ty<'tcx> { let existential_bounds = conv_existential_bounds(this, rscope, @@ -909,6 +968,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, { let tcx = this.tcx(); let ty_param_def_id = provenance.def_id(); + let mut suitable_bounds: Vec<_>; let ty_param_name: ast::Name; { // contain scope of refcell: @@ -916,13 +976,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_def = &ty_param_defs[ty_param_def_id.node]; ty_param_name = ty_param_def.name; - // FIXME(#19541): we should consider associated types in - // super-traits. Probably by elaborating the bounds. - + // FIXME(#20300) -- search where clauses, not bounds suitable_bounds = - ty_param_def.bounds.trait_bounds // FIXME(#20300) -- search where clauses, not bounds - .iter() - .cloned() + traits::transitive_bounds(tcx, ty_param_def.bounds.trait_bounds.as_slice()) .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) .collect(); } @@ -963,12 +1019,11 @@ fn trait_defines_associated_type_named(this: &AstConv, trait_def.associated_type_names.contains(&assoc_name) } -fn qpath_to_ty<'tcx,AC,RS>(this: &AC, - rscope: &RS, - ast_ty: &ast::Ty, // the TyQPath - qpath: &ast::QPath) - -> Ty<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope +fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + ast_ty: &ast::Ty, // the TyQPath + qpath: &ast::QPath) + -> Ty<'tcx> { debug!("qpath_to_ty(ast_ty={})", ast_ty.repr(this.tcx())); @@ -992,8 +1047,8 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC, // Parses the programmer's textual representation of a type into our // internal notion of a type. -pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> +pub fn ast_ty_to_ty<'tcx>( + this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx> { debug!("ast_ty_to_ty(ast_ty={})", ast_ty.repr(this.tcx())); @@ -1057,28 +1112,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) } - ast::TyClosure(ref f) => { - // Use corresponding trait store to figure out default bounds - // if none were specified. - let bounds = conv_existential_bounds(this, - rscope, - ast_ty.span, - None, - Vec::new(), - f.bounds.as_slice()); - let region_bound = bounds.region_bound; - let fn_decl = ty_of_closure(this, - f.unsafety, - f.onceness, - bounds, - ty::RegionTraitStore( - region_bound, - ast::MutMutable), - &*f.decl, - abi::Rust, - None); - ty::mk_closure(tcx, fn_decl) - } ast::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds[]) } @@ -1205,10 +1238,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( return typ; } -pub fn ty_of_arg<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(this: &AC, rscope: &RS, - a: &ast::Arg, - expected_ty: Option>) - -> Ty<'tcx> { +pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + a: &ast::Arg, + expected_ty: Option>) + -> Ty<'tcx> +{ match a.ty.node { ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), ast::TyInfer => this.ty_infer(a.ty.span), @@ -1221,14 +1256,13 @@ struct SelfInfo<'a, 'tcx> { explicit_self: &'a ast::ExplicitSelf, } -pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>( - this: &AC, - unsafety: ast::Unsafety, - untransformed_self_ty: Ty<'tcx>, - explicit_self: &ast::ExplicitSelf, - decl: &ast::FnDecl, - abi: abi::Abi) - -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { +pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>, + unsafety: ast::Unsafety, + untransformed_self_ty: Ty<'tcx>, + explicit_self: &ast::ExplicitSelf, + decl: &ast::FnDecl, + abi: abi::Abi) + -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { let self_info = Some(SelfInfo { untransformed_self_ty: untransformed_self_ty, explicit_self: explicit_self, @@ -1242,20 +1276,18 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>( (bare_fn_ty, optional_explicit_self_category.unwrap()) } -pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, unsafety: ast::Unsafety, abi: abi::Abi, +pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> { let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl); bare_fn_ty } -fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( - this: &AC, - unsafety: ast::Unsafety, - abi: abi::Abi, - opt_self_info: Option>, - decl: &ast::FnDecl) - -> (ty::BareFnTy<'tcx>, - Option) +fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, + unsafety: ast::Unsafety, + abi: abi::Abi, + opt_self_info: Option>, + decl: &ast::FnDecl) + -> (ty::BareFnTy<'tcx>, Option) { debug!("ty_of_method_or_bare_fn"); @@ -1357,12 +1389,10 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( }, explicit_self_category_result) } -fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>, - RS:RegionScope>( - this: &AC, - rscope: &RS, - self_info: &SelfInfo<'a, 'tcx>) - -> ty::ExplicitSelfCategory +fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + self_info: &SelfInfo<'a, 'tcx>) + -> ty::ExplicitSelfCategory { return match self_info.explicit_self.node { ast::SelfStatic => ty::StaticExplicitSelfCategory, @@ -1439,8 +1469,8 @@ fn count_modifiers(ty: Ty) -> uint { } } -pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( - this: &AC, +pub fn ty_of_closure<'tcx>( + this: &AstConv<'tcx>, unsafety: ast::Unsafety, onceness: ast::Onceness, bounds: ty::ExistentialBounds<'tcx>, @@ -1501,9 +1531,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( /// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent /// for closures. Eventually this should all be normalized, I think, so that there is no "main /// trait ref" and instead we just have a flat list of bounds as the existential type. -pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( - this: &AC, - rscope: &RS, +pub fn conv_existential_bounds<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, principal_trait_ref: Option>, // None for boxed closures projection_bounds: Vec>, @@ -1517,13 +1547,12 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) } -fn conv_ty_poly_trait_ref<'tcx, AC, RS>( - this: &AC, - rscope: &RS, +fn conv_ty_poly_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, ast_bounds: &[ast::TyParamBound]) -> Ty<'tcx> - where AC: AstConv<'tcx>, RS:RegionScope { let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]); @@ -1556,15 +1585,14 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( } } -pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( - this: &AC, - rscope: &RS, +pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, principal_trait_ref: Option>, // None for boxed closures mut projection_bounds: Vec>, // Empty for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds<'tcx> - where AC: AstConv<'tcx>, RS:RegionScope { let PartitionedBounds { builtin_bounds, trait_bounds, @@ -1657,9 +1685,9 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, /// A version of `compute_opt_region_bound` for use where some region bound is required /// (existential types, basically). Reports an error if no region bound can be derived and we are /// in an `rscope` that does not provide a default. -fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( - this: &AC, - rscope: &RS, +fn compute_region_bound<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, region_bounds: &[&ast::Lifetime], principal_trait_ref: Option>, // None for closures diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d8b410abf84..aef856b2b2b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -30,7 +30,9 @@ use syntax::ptr::P; pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &ast::Pat, expected: Ty<'tcx>) { + pat: &ast::Pat, + expected: Ty<'tcx>) +{ let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; @@ -46,6 +48,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_expr(fcx, &**lt); let expr_ty = fcx.expr_ty(&**lt); fcx.write_ty(pat.id, expr_ty); + + // somewhat surprising: in this case, the subtyping + // relation goes the opposite way as the other + // cases. Actually what we really want is not a subtyping + // relation at all but rather that there exists a LUB (so + // that they can be compared). However, in practice, + // constants are always scalars or strings. For scalars + // subtyping is irrelevant, and for strings `expr_ty` is + // type is `&'static str`, so if we say that + // + // &'static str <: expected + // + // that's equivalent to there existing a LUB. demand::suptype(fcx, pat.span, expected, expr_ty); } ast::PatRange(ref begin, ref end) => { @@ -54,10 +69,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let lhs_ty = fcx.expr_ty(&**begin); let rhs_ty = fcx.expr_ty(&**end); - if require_same_types( - tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, - || "mismatched types in range".to_string()) - && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(rhs_ty)) { + + let lhs_eq_rhs = + require_same_types( + tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, + || "mismatched types in range".to_string()); + + let numeric_or_char = + lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty)); + + if numeric_or_char { match valid_range_bounds(fcx.ccx, &**begin, &**end) { Some(false) => { span_err!(tcx.sess, begin.span, E0030, @@ -71,17 +92,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } else { span_err!(tcx.sess, begin.span, E0029, - "only char and numeric types are allowed in range"); + "only char and numeric types are allowed in range"); } fcx.write_ty(pat.id, lhs_ty); + + // subtyping doens't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { let const_did = tcx.def_map.borrow()[pat.id].clone().def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); - fcx.write_ty(pat.id, const_scheme.ty); - demand::suptype(fcx, pat.span, expected, const_scheme.ty); + assert!(const_scheme.generics.is_empty()); + let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + fcx.write_ty(pat.id, const_ty); + + // FIXME(#20489) -- we should limit the types here to scalars or something! + + // As with PatLit, what we really want here is that there + // exist a LUB, but for the cases that can occur, subtype + // is good enough. + demand::suptype(fcx, pat.span, expected, const_ty); } ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => { let typ = fcx.local_ty(pat.span, pat.id); @@ -89,20 +122,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::BindByRef(mutbl) => { // if the binding is like // ref x | ref const x | ref mut x - // then the type of x is &M T where M is the mutability - // and T is the expected type + // then `x` is assigned a value of type `&M T` where M is the mutability + // and T is the expected type. let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let mt = ty::mt { ty: expected, mutbl: mutbl }; let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt); + + // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is + // required. However, we use equality, which is stronger. See (*) for + // an explanation. demand::eqtype(fcx, pat.span, region_ty, typ); } // otherwise the type of x is the expected type T ast::BindByValue(_) => { + // As above, `T <: typeof(x)` is required but we + // use equality, see (*) below. demand::eqtype(fcx, pat.span, expected, typ); } } + fcx.write_ty(pat.id, typ); + // if there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be let canon_id = pcx.map[path.node]; if canon_id != pat.id { let ct = fcx.local_ty(pat.span, canon_id); @@ -124,8 +166,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat_struct(pcx, pat, path, fields.as_slice(), etc, expected); } ast::PatTup(ref elements) => { - let element_tys: Vec<_> = range(0, elements.len()).map(|_| fcx.infcx() - .next_ty_var()).collect(); + let element_tys: Vec<_> = + range(0, elements.len()).map(|_| fcx.infcx().next_ty_var()) + .collect(); let pat_ty = ty::mk_tup(tcx, element_tys.clone()); fcx.write_ty(pat.id, pat_ty); demand::eqtype(fcx, pat.span, expected, pat_ty); @@ -138,7 +181,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let uniq_ty = ty::mk_uniq(tcx, inner_ty); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, uniq_ty); + // Here, `demand::subtype` is good enough, but I don't + // think any errors can be introduced by using + // `demand::eqtype`. + demand::eqtype(fcx, pat.span, expected, uniq_ty); fcx.write_ty(pat.id, uniq_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -150,15 +196,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let inner_ty = fcx.infcx().next_ty_var(); let mutbl = - ty::deref(fcx.infcx().shallow_resolve(expected), true) - .map_or(ast::MutImmutable, |mt| mt.mutbl); + ty::deref(fcx.infcx().shallow_resolve(expected), true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, rptr_ty); + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, rptr_ty); fcx.write_ty(pat.id, rptr_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -181,14 +230,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); ty::mk_slice(tcx, tcx.mk_region(region), ty::mt { ty: inner_ty, - mutbl: ty::deref(expected_ty, true) - .map_or(ast::MutImmutable, |mt| mt.mutbl) + mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable) }) } }; fcx.write_ty(pat.id, pat_ty); - demand::suptype(fcx, pat.span, expected, pat_ty); + + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, pat_ty); for elt in before.iter() { check_pat(pcx, &**elt, inner_ty); @@ -210,6 +263,56 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } ast::PatMac(_) => tcx.sess.bug("unexpanded macro") } + + + // (*) In most of the cases above (literals and constants being + // the exception), we relate types using strict equality, evewn + // though subtyping would be sufficient. There are a few reasons + // for this, some of which are fairly subtle and which cost me + // (nmatsakis) an hour or two debugging to remember, so I thought + // I'd write them down this time. + // + // 1. Most importantly, there is no loss of expressiveness + // here. What we are saying is that the type of `x` + // becomes *exactly* what is expected. This might seem + // like it will cause errors in a case like this: + // + // ``` + // fn foo<'x>(x: &'x int) { + // let a = 1; + // let mut z = x; + // z = &a; + // } + // ``` + // + // The reason we might get an error is that `z` might be + // assigned a type like `&'x int`, and then we would have + // a problem when we try to assign `&a` to `z`, because + // the lifetime of `&a` (i.e., the enclosing block) is + // shorter than `'x`. + // + // HOWEVER, this code works fine. The reason is that the + // expected type here is whatever type the user wrote, not + // the initializer's type. In this case the user wrote + // nothing, so we are going to create a type variable `Z`. + // Then we will assign the type of the initializer (`&'x + // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we + // will instantiate `Z` as a type `&'0 int` where `'0` is + // a fresh region variable, with the constraint that `'x : + // '0`. So basically we're all set. + // + // Note that there are two tests to check that this remains true + // (`regions-reassign-{match,let}-bound-pointer.rs`). + // + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_inference`, as well as the test + // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. } pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, @@ -496,7 +599,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Typecheck each field. for &Spanned { node: ref field, span } in fields.iter() { - let field_type = match used_fields.entry(field.ident.name) { + let field_type = match used_fields.entry(&field.ident.name) { Occupied(occupied) => { span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times in the pattern", @@ -507,7 +610,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, tcx.types.err } Vacant(vacant) => { - vacant.set(span); + vacant.insert(span); field_type_map.get(&field.ident.name).cloned() .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index ee93c896433..98a826355a7 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,8 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::autoderef; +use super::AutorefArgs; +use super::check_argument_types; +use super::check_expr; +use super::check_method_argument_types; +use super::err_args; +use super::FnCtxt; +use super::LvaluePreference; +use super::method; +use super::structurally_resolved_type; +use super::TupleArgumentsFlag; +use super::write_call; + +use middle::infer; +use middle::ty::{mod, Ty}; use syntax::ast; use syntax::codemap::Span; +use syntax::parse::token; +use syntax::ptr::P; use CrateCtxt; /// Check that it is legal to call methods of the trait corresponding @@ -44,3 +61,164 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } } + +pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + callee_expr: &ast::Expr, + arg_exprs: &[P]) +{ + check_expr(fcx, callee_expr); + let original_callee_ty = fcx.expr_ty(callee_expr); + let (callee_ty, _, result) = + autoderef(fcx, + callee_expr.span, + original_callee_ty, + Some(callee_expr.id), + LvaluePreference::NoPreference, + |adj_ty, idx| { + let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; + try_overloaded_call_step(fcx, call_expr, callee_expr, + adj_ty, autoderefref) + }); + + match result { + None => { + // this will report an error since original_callee_ty is not a fn + confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs); + } + + Some(CallStep::Builtin) => { + confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs); + } + + Some(CallStep::Overloaded(method_callee)) => { + confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee); + } + } +} + +enum CallStep<'tcx> { + Builtin, + Overloaded(ty::MethodCallee<'tcx>) +} + +fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + callee_expr: &ast::Expr, + adjusted_ty: Ty<'tcx>, + autoderefref: ty::AutoDerefRef<'tcx>) + -> Option> +{ + // If the callee is a bare function or a closure, then we're all set. + match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { + ty::ty_bare_fn(..) => { + fcx.write_adjustment(callee_expr.id, + callee_expr.span, + ty::AdjustDerefRef(autoderefref)); + return Some(CallStep::Builtin); + } + + _ => {} + } + + // Try the options that are least restrictive on the caller first. + for &(opt_trait_def_id, method_name) in [ + (fcx.tcx().lang_items.fn_trait(), token::intern("call")), + (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), + (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), + ].iter() { + let trait_def_id = match opt_trait_def_id { + Some(def_id) => def_id, + None => continue, + }; + + match method::lookup_in_trait_adjusted(fcx, + call_expr.span, + Some(&*callee_expr), + method_name, + trait_def_id, + autoderefref.clone(), + adjusted_ty, + None) { + None => continue, + Some(method_callee) => { + return Some(CallStep::Overloaded(method_callee)); + } + } + } + + None +} + +fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + call_expr: &ast::Expr, + callee_ty: Ty<'tcx>, + arg_exprs: &[P]) +{ + let error_fn_sig; + + let fn_sig = match callee_ty.sty { + ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) => { + sig + } + _ => { + fcx.type_error_message(call_expr.span, |actual| { + format!("expected function, found `{}`", actual) + }, callee_ty, None); + + // This is the "default" function signature, used in case of error. + // In that case, we check each argument against "error" in order to + // set up all the node type bindings. + error_fn_sig = ty::Binder(ty::FnSig { + inputs: err_args(fcx.tcx(), arg_exprs.len()), + output: ty::FnConverging(fcx.tcx().types.err), + variadic: false + }); + + &error_fn_sig + } + }; + + // Replace any late-bound regions that appear in the function + // signature with region variables. We also have to + // renormalize the associated types at this point, since they + // previously appeared within a `Binder<>` and hence would not + // have been normalized before. + let fn_sig = + fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + fn_sig).0; + let fn_sig = + fcx.normalize_associated_types_in(call_expr.span, &fn_sig); + + // Call the generic checker. + let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>]. + check_argument_types(fcx, + call_expr.span, + fn_sig.inputs[], + arg_exprs.as_slice(), + AutorefArgs::No, + fn_sig.variadic, + TupleArgumentsFlag::DontTupleArguments); + + write_call(fcx, call_expr, fn_sig.output); +} + +fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + arg_exprs: &[P], + method_callee: ty::MethodCallee<'tcx>) +{ + let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>]. + let output_type = check_method_argument_types(fcx, + call_expr.span, + method_callee.ty, + call_expr, + arg_exprs.as_slice(), + AutorefArgs::No, + TupleArgumentsFlag::TupleArguments); + let method_call = ty::MethodCall::expr(call_expr.id); + fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); + write_call(fcx, call_expr, output_type); +} + diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index db84f1dce97..9945e264bfc 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,20 +13,18 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv; -use middle::infer; use middle::region::CodeExtent; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; use rscope::RegionScope; use syntax::abi; use syntax::ast; -use syntax::ast::CaptureClause::*; use syntax::ast_util; use util::ppaux::Repr; pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &ast::Expr, - capture: ast::CaptureClause, + _capture: ast::CaptureClause, opt_kind: Option, decl: &ast::FnDecl, body: &ast::Block, @@ -46,30 +44,17 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // evidence than an unboxed closure is desired, we'll use // that, otherwise we'll fall back to boxed closures. match expected_sig_and_kind { - None => { // doesn't look like an unboxed closure - let region = astconv::opt_ast_region_to_region(fcx, - fcx, - expr.span, - &None); - - check_boxed_closure(fcx, - expr, - ty::RegionTraitStore(region, ast::MutMutable), - decl, - body, - expected); - - match capture { - CaptureByValue => { - fcx.ccx.tcx.sess.span_err( - expr.span, - "boxed closures can't capture by value, \ - if you want to use an unboxed closure, \ - explicitly annotate its kind: e.g. `move |:|`"); - }, - CaptureByRef => {} - } - } + None => { // don't have information about the kind, request explicit annotation + // NB We still need to typeck the body, so assume `FnMut` kind just for that + let kind = ty::FnMutUnboxedClosureKind; + + check_unboxed_closure(fcx, expr, kind, decl, body, None); + + fcx.ccx.tcx.sess.span_err( + expr.span, + "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \ + `|&:| {}`"); + }, Some((sig, kind)) => { check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig)); } @@ -254,92 +239,3 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>( None } - - -fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &ast::Expr, - store: ty::TraitStore, - decl: &ast::FnDecl, - body: &ast::Block, - expected: Expectation<'tcx>) { - let tcx = fcx.ccx.tcx; - - // Find the expected input/output types (if any). Substitute - // fresh bound regions for any bound regions we find in the - // expected types so as to avoid capture. - let expected_cenv = expected.map_to_option(fcx, |ty| match ty.sty { - ty::ty_closure(ref cenv) => Some(cenv), - _ => None - }); - let (expected_sig, expected_onceness, expected_bounds) = match expected_cenv { - Some(cenv) => { - let (sig, _) = - ty::replace_late_bound_regions( - tcx, - &cenv.sig, - |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn)); - let onceness = match (&store, &cenv.store) { - // As the closure type and onceness go, only three - // combinations are legit: - // once closure - // many closure - // once proc - // If the actual and expected closure type disagree with - // each other, set expected onceness to be always Once or - // Many according to the actual type. Otherwise, it will - // yield either an illegal "many proc" or a less known - // "once closure" in the error message. - (&ty::UniqTraitStore, &ty::UniqTraitStore) | - (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) => - cenv.onceness, - (&ty::UniqTraitStore, _) => ast::Once, - (&ty::RegionTraitStore(..), _) => ast::Many, - }; - (Some(sig), onceness, cenv.bounds.clone()) - } - _ => { - // Not an error! Means we're inferring the closure type - let region = fcx.infcx().next_region_var( - infer::AddrOfRegion(expr.span)); - let bounds = ty::region_existential_bound(region); - let onceness = ast::Many; - (None, onceness, bounds) - } - }; - - // construct the function type - let fn_ty = astconv::ty_of_closure(fcx, - ast::Unsafety::Normal, - expected_onceness, - expected_bounds, - store, - decl, - abi::Rust, - expected_sig); - let fn_sig = fn_ty.sig.clone(); - let fty = ty::mk_closure(tcx, fn_ty); - debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty)); - - fcx.write_ty(expr.id, fty); - - // If the closure is a stack closure and hasn't had some non-standard - // style inferred for it, then check it under its parent's style. - // Otherwise, use its own - let (inherited_style, inherited_style_id) = match store { - ty::RegionTraitStore(..) => (fcx.ps.borrow().unsafety, - fcx.ps.borrow().def), - ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id) - }; - - let fn_sig = - ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig); - - check_fn(fcx.ccx, - inherited_style, - inherited_style_id, - &fn_sig, - &*decl, - expr.id, - &*body, - fcx.inh); -} diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 5b586bb0b66..a51e89c1669 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -18,14 +18,15 @@ use syntax::codemap::Span; use util::ppaux::Repr; -// Requires that the two types unify, and prints an error message if they -// don't. +// Requires that the two types unify, and prints an error message if +// they don't. pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, false, expected, actual, + ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) { + suptype_with_fn(fcx, sp, false, ty_expected, ty_actual, |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) } +/// As `suptype`, but call `handle_err` if unification for subtyping fails. pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, b_is_expected: bool, @@ -48,9 +49,7 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) { Ok(()) => { /* ok */ } - Err(ref err) => { - fcx.report_mismatched_types(sp, expected, actual, err); - } + Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 54d2378256d..adea5084aab 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -462,7 +462,6 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, method_callee: &MethodCallee) { let sig = match method_callee.ty.sty { ty::ty_bare_fn(_, ref f) => f.sig.clone(), - ty::ty_closure(ref f) => f.sig.clone(), _ => return, }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8adb592633f..beb51590b41 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -387,14 +387,18 @@ fn assemble_inherent_candidates_from_param(&mut self, // Do a search through a list of bounds, using a callback to actually // create the candidates. - fn elaborate_bounds( + fn elaborate_bounds( &mut self, bounds: &[ty::PolyTraitRef<'tcx>], num_includes_types: bool, - mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: ty::PolyTraitRef<'tcx>, - m: Rc>, - method_num: uint|) + mut mk_cand: F, + ) where + F: for<'b> FnMut( + &mut ProbeContext<'b, 'tcx>, + ty::PolyTraitRef<'tcx>, + Rc>, + uint, + ), { debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx())); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e6ae5f0a447..1b51434a58c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -699,7 +699,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env); } - ast::ItemImpl(_, _, _, _, ref impl_items) => { + ast::ItemImpl(_, _, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); @@ -1850,7 +1850,6 @@ fn register_adjustment_obligations(&self, span: Span, adj: &ty::AutoAdjustment<'tcx>) { match *adj { - ty::AdjustAddEnv(..) | ty::AdjustReifyFnPointer(..) => { } ty::AdjustDerefRef(ref d_r) => { @@ -2229,7 +2228,8 @@ pub enum LvaluePreference { /// /// Note: this method does not modify the adjustments table. The caller is responsible for /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. -pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, +pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, base_ty: Ty<'tcx>, expr_id: Option, mut lvalue_pref: LvaluePreference, @@ -2276,58 +2276,6 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, (fcx.tcx().types.err, 0, None) } -/// Attempts to resolve a call expression as an overloaded call. -fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expression: &ast::Expr, - callee: &ast::Expr, - callee_type: Ty<'tcx>, - args: &[&P]) - -> bool { - // Bail out if the callee is a bare function or a closure. We check those - // manually. - match structurally_resolved_type(fcx, callee.span, callee_type).sty { - ty::ty_bare_fn(..) | ty::ty_closure(_) => return false, - _ => {} - } - - // Try the options that are least restrictive on the caller first. - for &(maybe_function_trait, method_name) in [ - (fcx.tcx().lang_items.fn_trait(), token::intern("call")), - (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), - (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), - ].iter() { - let function_trait = match maybe_function_trait { - None => continue, - Some(function_trait) => function_trait, - }; - let method_callee = - match method::lookup_in_trait(fcx, - call_expression.span, - Some(&*callee), - method_name, - function_trait, - callee_type, - None) { - None => continue, - Some(method_callee) => method_callee, - }; - let method_call = MethodCall::expr(call_expression.id); - let output_type = check_method_argument_types(fcx, - call_expression.span, - method_callee.ty, - call_expression, - args, - AutorefArgs::No, - TupleArguments); - fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); - write_call(fcx, call_expression, output_type); - - return true - } - - false -} - fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_call: Option, @@ -2689,7 +2637,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_argument_types(fcx, sp, err_inputs[], - callee_expr, args_no_rcvr, autoref_args, false, @@ -2702,7 +2649,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_argument_types(fcx, sp, fty.sig.0.inputs.slice_from(1), - callee_expr, args_no_rcvr, autoref_args, fty.sig.0.variadic, @@ -2722,7 +2668,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, fn_inputs: &[Ty<'tcx>], - _callee_expr: &ast::Expr, args: &[&P], autoref_args: AutorefArgs, variadic: bool, @@ -3106,63 +3051,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, debug!(">> typechecking: expr={} expected={}", expr.repr(fcx.tcx()), expected.repr(fcx.tcx())); - // A generic function for doing all of the checking for call expressions - fn check_call(fcx: &FnCtxt, - call_expr: &ast::Expr, - f: &ast::Expr, - args: &[&P]) { - // Store the type of `f` as the type of the callee - let fn_ty = fcx.expr_ty(f); - - // Extract the function signature from `in_fty`. - let fn_ty = structurally_resolved_type(fcx, f.span, fn_ty); - - // This is the "default" function signature, used in case of error. - // In that case, we check each argument against "error" in order to - // set up all the node type bindings. - let error_fn_sig = ty::Binder(FnSig { - inputs: err_args(fcx.tcx(), args.len()), - output: ty::FnConverging(fcx.tcx().types.err), - variadic: false - }); - - let fn_sig = match fn_ty.sty { - ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) | - ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig, - _ => { - fcx.type_error_message(call_expr.span, |actual| { - format!("expected function, found `{}`", actual) - }, fn_ty, None); - &error_fn_sig - } - }; - - // Replace any late-bound regions that appear in the function - // signature with region variables. We also have to - // renormalize the associated types at this point, since they - // previously appeared within a `Binder<>` and hence would not - // have been normalized before. - let fn_sig = - fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - fn_sig).0; - let fn_sig = - fcx.normalize_associated_types_in(call_expr.span, - &fn_sig); - - // Call the generic checker. - check_argument_types(fcx, - call_expr.span, - fn_sig.inputs[], - f, - args, - AutorefArgs::No, - fn_sig.variadic, - DontTupleArguments); - - write_call(fcx, call_expr, fn_sig.output); - } - // Checks a method call. fn check_method_call(fcx: &FnCtxt, expr: &ast::Expr, @@ -4164,24 +4052,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt, check_block_with_expected(fcx, &**b, expected); fcx.write_ty(id, fcx.node_ty(b.id)); } - ast::ExprCall(ref f, ref args) => { - // Index expressions need to be handled separately, to inform them - // that they appear in call position. - check_expr(fcx, &**f); - let f_ty = fcx.expr_ty(&**f); - - let args: Vec<_> = args.iter().map(|x| x).collect(); - if !try_overloaded_call(fcx, expr, &**f, f_ty, args[]) { - check_call(fcx, expr, &**f, args[]); - let args_err = args.iter().fold(false, - |rest_err, a| { - // is this not working? - let a_ty = fcx.expr_ty(&***a); - rest_err || ty::type_is_error(a_ty)}); - if ty::type_is_error(f_ty) || args_err { - fcx.write_error(id); - } - } + ast::ExprCall(ref callee, ref args) => { + callee::check_call(fcx, expr, &**callee, args.as_slice()); } ast::ExprMethodCall(ident, ref tps, ref args) => { check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref); @@ -4682,7 +4554,7 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { pub fn check_decl_initializer(fcx: &FnCtxt, nid: ast::NodeId, init: &ast::Expr) - { +{ let local_ty = fcx.local_ty(init.span, nid); check_expr_coercable_to_type(fcx, init, local_ty) } @@ -5066,7 +4938,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, Some(i) => { span_err!(ccx.tcx.sess, v.span, E0081, "discriminant value `{}` already exists", disr_vals[i]); - span_note!(ccx.tcx.sess, ccx.tcx().map.span(variants[i].id.node), + span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node), "conflicting discriminant here") } None => {} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b5ddb528c2f..b7397b5f9ee 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -92,7 +92,7 @@ use middle::traits; use middle::ty::{ReScope}; use middle::ty::{self, Ty, MethodCall}; -use middle::infer; +use middle::infer::{mod, GenericKind}; use middle::pat_util; use util::ppaux::{ty_to_string, Repr}; @@ -164,7 +164,7 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub struct Rcx<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - region_param_pairs: Vec<(ty::Region, ty::ParamTy)>, + region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>, // id of innermost fn or loop repeating_scope: ast::NodeId, @@ -205,7 +205,7 @@ pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, Rcx { fcx: fcx, repeating_scope: initial_repeating_scope, subject: subject, - region_param_pairs: Vec::new() } + region_bound_pairs: Vec::new() } } pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { @@ -286,12 +286,12 @@ fn visit_fn_body(&mut self, } }; - let len = self.region_param_pairs.len(); + let len = self.region_bound_pairs.len(); self.relate_free_regions(fn_sig[], body.id); link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs[]); self.visit_block(body); self.visit_region_obligations(body.id); - self.region_param_pairs.truncate(len); + self.region_bound_pairs.truncate(len); } fn visit_region_obligations(&mut self, node_id: ast::NodeId) @@ -357,11 +357,11 @@ fn relate_free_regions(&mut self, // relationship that arises here, but // presently we do not.) } - regionmanip::RegionSubParamConstraint(_, r_a, p_b) => { - debug!("RegionSubParamConstraint: {} <= {}", - r_a.repr(tcx), p_b.repr(tcx)); + regionmanip::RegionSubGenericConstraint(_, r_a, ref generic_b) => { + debug!("RegionSubGenericConstraint: {} <= {}", + r_a.repr(tcx), generic_b.repr(tcx)); - self.region_param_pairs.push((r_a, p_b)); + self.region_bound_pairs.push((r_a, generic_b.clone())); } } } @@ -735,29 +735,6 @@ fn check_expr_fn_block(rcx: &mut Rcx, let function_type = rcx.resolve_node_type(expr.id); match function_type.sty { - ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..), - ref bounds, - ..}) => { - // For closure, ensure that the variables outlive region - // bound, since they are captured by reference. - ty::with_freevars(tcx, expr.id, |freevars| { - if freevars.is_empty() { - // No free variables means that the environment - // will be NULL at runtime and hence the closure - // has static lifetime. - } else { - // Variables being referenced must outlive closure. - constrain_free_variables_in_by_ref_closure( - rcx, bounds.region_bound, expr, freevars); - - // Closure is stack allocated and hence cannot - // outlive the appropriate temporary scope. - let s = rcx.repeating_scope; - rcx.fcx.mk_subr(infer::InfStackClosure(expr.span), - bounds.region_bound, ty::ReScope(CodeExtent::from_node_id(s))); - } - }); - } ty::ty_unboxed_closure(_, region, _) => { if tcx.capture_modes.borrow()[expr.id].clone() == ast::CaptureByRef { ty::with_freevars(tcx, expr.id, |freevars| { @@ -778,11 +755,6 @@ fn check_expr_fn_block(rcx: &mut Rcx, rcx.set_repeating_scope(repeating_scope); match function_type.sty { - ty::ty_closure(box ty::ClosureTy {ref bounds, ..}) => { - ty::with_freevars(tcx, expr.id, |freevars| { - ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars); - }) - } ty::ty_unboxed_closure(_, region, _) => { ty::with_freevars(tcx, expr.id, |freevars| { let bounds = ty::region_existential_bound(*region); @@ -884,33 +856,11 @@ fn constrain_free_variables_in_by_ref_closure( fn constrain_callee(rcx: &mut Rcx, callee_id: ast::NodeId, - call_expr: &ast::Expr, - callee_expr: &ast::Expr) { - let call_region = ty::ReScope(CodeExtent::from_node_id(call_expr.id)); - + _call_expr: &ast::Expr, + _callee_expr: &ast::Expr) { let callee_ty = rcx.resolve_node_type(callee_id); match callee_ty.sty { ty::ty_bare_fn(..) => { } - ty::ty_closure(ref closure_ty) => { - let region = match closure_ty.store { - ty::RegionTraitStore(r, _) => { - // While we're here, link the closure's region with a unique - // immutable borrow (gathered later in borrowck) - let mc = mc::MemCategorizationContext::new(rcx.fcx); - let expr_cmt = ignore_err!(mc.cat_expr(callee_expr)); - link_region(rcx, callee_expr.span, call_region, - ty::UniqueImmBorrow, expr_cmt); - r - } - ty::UniqTraitStore => ty::ReStatic - }; - rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span), - call_region, region); - - let region = closure_ty.bounds.region_bound; - rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span), - call_region, region); - } _ => { // this should not happen, but it does if the program is // erroneous @@ -1477,31 +1427,31 @@ fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); rcx.fcx.mk_subr(o1, r_a, r_b); } - regionmanip::RegionSubParamConstraint(None, r_a, param_b) => { - param_must_outlive(rcx, origin.clone(), r_a, param_b); + regionmanip::RegionSubGenericConstraint(None, r_a, ref generic_b) => { + generic_must_outlive(rcx, origin.clone(), r_a, generic_b); } - regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => { + regionmanip::RegionSubGenericConstraint(Some(ty), r_a, ref generic_b) => { let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); - param_must_outlive(rcx, o1, r_a, param_b); + generic_must_outlive(rcx, o1, r_a, generic_b); } } } } -fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, - param_ty: ty::ParamTy) { +fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + generic: &GenericKind<'tcx>) { let param_env = &rcx.fcx.inh.param_env; - debug!("param_must_outlive(region={}, param_ty={})", + debug!("param_must_outlive(region={}, generic={})", region.repr(rcx.tcx()), - param_ty.repr(rcx.tcx())); + generic.repr(rcx.tcx())); // To start, collect bounds from user: let mut param_bounds = ty::required_region_bounds(rcx.tcx(), - param_ty.to_ty(rcx.tcx()), + generic.to_ty(rcx.tcx()), param_env.caller_bounds.predicates.as_slice().to_vec()); // Add in the default bound of fn body that applies to all in @@ -1517,22 +1467,21 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, // fn foo<'a, A>(x: &'a A) { x.bar() } // // The problem is that the type of `x` is `&'a A`. To be - // well-formed, then, A must be lower-bounded by `'a`, but we + // well-formed, then, A must be lower-generic by `'a`, but we // don't know that this holds from first principles. - for &(ref r, ref p) in rcx.region_param_pairs.iter() { - debug!("param_ty={} p={}", - param_ty.repr(rcx.tcx()), + for &(ref r, ref p) in rcx.region_bound_pairs.iter() { + debug!("generic={} p={}", + generic.repr(rcx.tcx()), p.repr(rcx.tcx())); - if param_ty == *p { + if generic == p { param_bounds.push(*r); } } - // Inform region inference that this parameter type must be - // properly bounded. - infer::verify_param_bound(rcx.fcx.infcx(), - origin, - param_ty, - region, - param_bounds); + // Inform region inference that this generic must be properly + // bounded. + rcx.fcx.infcx().verify_generic_bound(origin, + generic.clone(), + region, + param_bounds); } diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index 66cf077d4c2..7ca21bdf5b8 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -12,6 +12,7 @@ pub use self::WfConstraint::*; +use middle::infer::GenericKind; use middle::subst::{ParamSpace, Subst, Substs}; use middle::ty::{self, Ty}; use middle::ty_fold::{TypeFolder}; @@ -24,7 +25,7 @@ pub enum WfConstraint<'tcx> { RegionSubRegionConstraint(Option>, ty::Region, ty::Region), - RegionSubParamConstraint(Option>, ty::Region, ty::ParamTy), + RegionSubGenericConstraint(Option>, ty::Region, GenericKind<'tcx>), } struct Wf<'a, 'tcx: 'a> { @@ -67,10 +68,6 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) { // No borrowed content reachable here. } - ty::ty_closure(box ref c) => { - self.accumulate_from_closure_ty(ty, c); - } - ty::ty_unboxed_closure(_, region, _) => { // An "unboxed closure type" is basically // modeled here as equivalent to a struct like @@ -125,8 +122,7 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) { ty::ty_projection(ref data) => { // `>::Name` - // FIXME(#20303) -- gain ability to require that ty_projection : in-scope region, - // like a type parameter + self.push_projection_constraint_from_top(data); // this seems like a minimal requirement: let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id); @@ -215,12 +211,21 @@ fn push_param_constraint_from_top(&mut self, self.push_param_constraint(region, opt_ty, param_ty); } + /// Pushes a constraint that `projection_ty` must outlive the top region on the stack. + fn push_projection_constraint_from_top(&mut self, + projection_ty: &ty::ProjectionTy<'tcx>) { + let &(region, opt_ty) = self.stack.last().unwrap(); + self.out.push(RegionSubGenericConstraint( + opt_ty, region, GenericKind::Projection(projection_ty.clone()))); + } + /// Pushes a constraint that `region <= param_ty`, due to `opt_ty` fn push_param_constraint(&mut self, region: ty::Region, opt_ty: Option>, param_ty: ty::ParamTy) { - self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty)); + self.out.push(RegionSubGenericConstraint( + opt_ty, region, GenericKind::Param(param_ty))); } fn accumulate_from_adt(&mut self, @@ -323,22 +328,6 @@ fn accumulate_from_adt(&mut self, } } - fn accumulate_from_closure_ty(&mut self, - ty: Ty<'tcx>, - c: &ty::ClosureTy<'tcx>) - { - match c.store { - ty::RegionTraitStore(r_b, _) => { - self.push_region_constraint_from_top(r_b); - } - ty::UniqTraitStore => { } - } - - let required_region_bounds = - ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds); - self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds); - } - fn accumulate_from_object_ty(&mut self, ty: Ty<'tcx>, region_bound: ty::Region, @@ -393,16 +382,16 @@ fn accumulate_from_object_ty(&mut self, } impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> { - fn repr(&self, tcx: &ty::ctxt) -> String { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { - RegionSubRegionConstraint(_, r_a, r_b) => { + RegionSubRegionConstraint(_, ref r_a, ref r_b) => { format!("RegionSubRegionConstraint({}, {})", r_a.repr(tcx), r_b.repr(tcx)) } - RegionSubParamConstraint(_, r, p) => { - format!("RegionSubParamConstraint({}, {})", + RegionSubGenericConstraint(_, ref r, ref p) => { + format!("RegionSubGenericConstraint({}, {})", r.repr(tcx), p.repr(tcx)) } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 1fdb68854c0..92fda96595c 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -122,7 +122,6 @@ fn check_closure(&mut self, _body: &ast::Block) { let is_old_skool_closure = match self.fcx.expr_ty(expr).sty { - ty::ty_closure(..) => true, _ => false, }; diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 704025f38ce..d4a5bda5f97 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -81,10 +81,9 @@ fn check_item_well_formed(&mut self, item: &ast::Item) { } } - fn with_fcx(&mut self, - item: &ast::Item, - f: for<'fcx> |&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, - &FnCtxt<'fcx, 'tcx>|) { + fn with_fcx(&mut self, item: &ast::Item, mut f: F) where + F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), + { let ccx = self.ccx; let item_def_id = local_def(item.id); let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); @@ -100,10 +99,8 @@ fn with_fcx(&mut self, } /// In a type definition, we check that to ensure that the types of the fields are well-formed. - fn check_type_defn(&mut self, - item: &ast::Item, - lookup_fields: for<'fcx> |&FnCtxt<'fcx, 'tcx>| - -> Vec>) + fn check_type_defn(&mut self, item: &ast::Item, mut lookup_fields: F) where + F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, { self.with_fcx(item, |this, fcx| { let variants = lookup_fields(fcx); @@ -301,6 +298,18 @@ fn tcx(&self) -> &ty::ctxt<'tcx> { self.fcx.tcx() } + fn fold_binder(&mut self, binder: &ty::Binder) -> ty::Binder + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + self.binding_count += 1; + let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder); + debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}", + value.repr(self.tcx())); + let value = value.fold_with(self); + self.binding_count -= 1; + ty::Binder(value) + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { debug!("BoundsChecker t={}", t.repr(self.tcx())); @@ -361,19 +370,6 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { self.fold_substs(substs); } - ty::ty_bare_fn(_, &ty::BareFnTy{sig: ref fn_sig, ..}) | - ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => { - self.binding_count += 1; - - let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope, fn_sig); - - debug!("late-bound regions replaced: {}", - fn_sig.repr(self.tcx())); - - self.fold_fn_sig(&fn_sig); - - self.binding_count -= 1; - } _ => { super_fold_ty(self, t); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4154937b3fd..70644b6e7de 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -266,10 +266,6 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { Some(adjustment) => { let adj_object = ty::adjust_is_object(&adjustment); let resolved_adjustment = match adjustment { - ty::AdjustAddEnv(def_id, store) => { - ty::AdjustAddEnv(def_id, self.resolve(&store, reason)) - } - ty::AdjustReifyFnPointer(def_id) => { ty::AdjustReifyFnPointer(def_id) } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 45b248dac93..09ab98745bd 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -22,7 +22,7 @@ use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; -use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err}; +use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err}; use middle::ty::{ty_param, TypeScheme, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; @@ -69,7 +69,7 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | - ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | + ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_tup(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => { None @@ -102,7 +102,7 @@ fn visit_item(&mut self, item: &Item) { //debug!("(checking coherence) item '{}'", token::get_ident(item.ident)); match item.node { - ItemImpl(_, _, ref opt_trait, _, _) => { + ItemImpl(_, _, _, ref opt_trait, _, _) => { match opt_trait.clone() { Some(opt_trait) => { self.cc.check_implementation(item, &[opt_trait]); @@ -283,7 +283,7 @@ fn get_self_type_for_implementation(&self, impl_did: DefId) // Converts an implementation in the AST to a vector of items. fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { - ItemImpl(_, _, ref trait_refs, _, ref ast_items) => { + ItemImpl(_, _, _, ref trait_refs, _, ref ast_items) => { let mut items: Vec = ast_items.iter() .map(|ast_item| { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 1da49799712..d90bfe04ea1 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -44,7 +44,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v ast::Item) { let def_id = ast_util::local_def(item.id); match item.node { - ast::ItemImpl(_, _, None, _, _) => { + ast::ItemImpl(_, _, _, None, _, _) => { // For inherent impls, self type must be a nominal type // defined in this crate. debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx)); @@ -69,7 +69,7 @@ fn visit_item(&mut self, item: &'v ast::Item) { } } } - ast::ItemImpl(_, _, Some(_), _, _) => { + ast::ItemImpl(_, _, _, Some(_), _, _) => { // "Trait" impl debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx)); match traits::orphan_check(self.tcx, def_id) { diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 07a84846c47..1acea6fd581 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -30,7 +30,7 @@ struct UnsafetyChecker<'cx, 'tcx:'cx> { impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v ast::Item) { match item.node { - ast::ItemImpl(unsafety, _, _, _, _) => { + ast::ItemImpl(unsafety, _, _, _, _, _) => { match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) { None => { // Inherent impl. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 009f1e50e9b..bbafcdae1bb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -40,11 +40,12 @@ use middle::ty::{self, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; +use no_params; use rscope::*; -use {CrateCtxt, no_params, write_ty_to_tcx}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; +use write_ty_to_tcx; use std::rc::Rc; @@ -61,13 +62,8 @@ /////////////////////////////////////////////////////////////////////////// // Main entry point -pub fn collect_item_types(ccx: &CrateCtxt) { - fn collect_intrinsic_type(ccx: &CrateCtxt, - lang_item: ast::DefId) { - let ty::TypeScheme { ty, .. } = - ccx.get_item_type_scheme(lang_item); - ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); - } +pub fn collect_item_types(tcx: &ty::ctxt) { + let ccx = &CollectCtxt { tcx: tcx }; match ccx.tcx.lang_items.ty_desc() { Some(id) => { collect_intrinsic_type(ccx, id); } @@ -85,13 +81,29 @@ fn collect_intrinsic_type(ccx: &CrateCtxt, visit::walk_crate(&mut visitor, ccx.tcx.map.krate()); } +/////////////////////////////////////////////////////////////////////////// + +struct CollectCtxt<'a,'tcx:'a> { + tcx: &'a ty::ctxt<'tcx>, +} + +/////////////////////////////////////////////////////////////////////////// +// Zeroth phase: collect types of intrinsics + +fn collect_intrinsic_type(ccx: &CollectCtxt, + lang_item: ast::DefId) { + let ty::TypeScheme { ty, .. } = + ccx.get_item_type_scheme(lang_item); + ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); +} + /////////////////////////////////////////////////////////////////////////// // First phase: just collect *trait definitions* -- basically, the set // of type parameters and supertraits. This is information we need to // know later when parsing field defs. struct CollectTraitDefVisitor<'a, 'tcx: 'a> { - ccx: &'a CrateCtxt<'a, 'tcx> + ccx: &'a CollectCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> { @@ -112,7 +124,7 @@ fn visit_item(&mut self, i: &ast::Item) { // Second phase: collection proper. struct CollectItemTypesVisitor<'a, 'tcx: 'a> { - ccx: &'a CrateCtxt<'a, 'tcx> + ccx: &'a CollectCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { @@ -133,13 +145,13 @@ pub trait ToTy<'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; } -impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> { +impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) } } -impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { +impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { @@ -148,7 +160,9 @@ fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { } match self.tcx.map.find(id.node) { - Some(ast_map::NodeItem(item)) => ty_of_item(self, &*item), + Some(ast_map::NodeItem(item)) => { + ty_of_item(self, &*item) + } Some(ast_map::NodeForeignItem(foreign_item)) => { let abi = self.tcx.map.get_foreign_abi(id.node); ty_of_foreign_item(self, &*foreign_item, abi) @@ -181,7 +195,7 @@ fn projected_ty(&self, } } -pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, enum_ty: Ty<'tcx>, variants: &[P], generics: &ast::Generics) { @@ -226,7 +240,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_def: &ty::TraitDef<'tcx>) { let tcx = ccx.tcx; @@ -322,7 +336,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } - fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { + fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { ccx.tcx.tcache.borrow_mut().insert( m.def_id, TypeScheme { @@ -330,7 +344,7 @@ fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) }); } - fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, _trait_items: &[ast::TraitItem], @@ -372,7 +386,7 @@ fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, v: &ast::StructField, origin: ast::DefId) -> ty::field_ty { @@ -405,7 +419,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) { @@ -422,7 +436,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::TypeTraitItem(associated_type)); } -fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, mut ms: I, untransformed_rcvr_ty: Ty<'tcx>, @@ -469,7 +483,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, .insert(mty.def_id, ty::MethodTraitItem(mty)); } - fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, @@ -506,7 +520,7 @@ fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, +fn ensure_no_ty_param_bounds(ccx: &CollectCtxt, span: Span, generics: &ast::Generics, thing: &'static str) { @@ -535,7 +549,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } -pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { +fn convert(ccx: &CollectCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); match it.node { @@ -549,7 +563,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { enum_definition.variants.as_slice(), generics); }, - ast::ItemImpl(_, + ast::ItemImpl(_, _, ref generics, ref opt_trait_ref, ref selfty, @@ -636,7 +650,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { debug!("trait_def: ident={} trait_def={}", it.ident.repr(ccx.tcx), - trait_def.repr(ccx.tcx())); + trait_def.repr(ccx.tcx)); for trait_method in trait_methods.iter() { let self_type = ty::mk_self_type(tcx); @@ -706,7 +720,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } } -pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, struct_def: &ast::StructDef, scheme: ty::TypeScheme<'tcx>, id: ast::NodeId) { @@ -773,7 +787,7 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { +fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) { // 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. @@ -790,7 +804,7 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme); } -fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::DefId) -> Rc> { if trait_id.krate != ast::LOCAL_CRATE { @@ -806,9 +820,9 @@ fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - it: &ast::Item) - -> Rc> +fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + it: &ast::Item) + -> Rc> { let def_id = local_def(it.id); let tcx = ccx.tcx; @@ -872,7 +886,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return trait_def; - fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics: &ast::Generics) -> subst::Substs<'tcx> { @@ -903,7 +917,7 @@ fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) +fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) -> ty::TypeScheme<'tcx> { let def_id = local_def(it.id); let tcx = ccx.tcx; @@ -985,7 +999,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } } -pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::ForeignItem, abi: abi::Abi) -> ty::TypeScheme<'tcx> { @@ -1006,7 +1020,7 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics: &ast::Generics) -> ty::Generics<'tcx> { ty_generics(ccx, @@ -1017,7 +1031,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &generics.where_clause) } -fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, substs: &'tcx subst::Substs<'tcx>, ast_generics: &ast::Generics, @@ -1077,7 +1091,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return generics; - fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, self_trait_ref: &Rc>, trait_items: &[ast::TraitItem]) -> Vec> @@ -1108,14 +1122,13 @@ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_fn_or_method<'tcx,AC>( - this: &AC, - generics: &ast::Generics, - base_generics: ty::Generics<'tcx>) - -> ty::Generics<'tcx> - where AC: AstConv<'tcx> { +fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + generics: &ast::Generics, + base_generics: ty::Generics<'tcx>) + -> ty::Generics<'tcx> +{ let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - ty_generics(this, + ty_generics(ccx, subst::FnSpace, early_lifetimes[], generics.ty_params[], @@ -1124,11 +1137,11 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'tcx,AC>(this: &AC, +fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, bounds: &mut ty::BuiltinBounds, ast_bounds: &[ast::TyParamBound], span: Span) - where AC: AstConv<'tcx> { +{ // Try to find an unbound in bounds. let mut unbound = None; for ab in ast_bounds.iter() { @@ -1137,24 +1150,24 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, assert!(ptr.bound_lifetimes.is_empty()); unbound = Some(ptr.trait_ref.clone()); } else { - this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \ + ccx.tcx.sess.span_err(span, "type parameter has more than one relaxed default \ bound, only one is supported"); } } } - let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); + let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); + let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { - this.tcx().sess.span_warn(span, + ccx.tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); - ty::try_add_builtin_trait(this.tcx(), + ty::try_add_builtin_trait(ccx.tcx, kind_id, bounds); } @@ -1162,27 +1175,26 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, } } _ if kind_id.is_ok() => { - ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); + ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. None => {} } } -fn ty_generics<'tcx,AC>(this: &AC, +fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics<'tcx>, where_clause: &ast::WhereClause) -> ty::Generics<'tcx> - where AC: AstConv<'tcx> { let mut result = base_generics; for (i, l) in lifetime_defs.iter().enumerate() { let bounds = l.bounds.iter() - .map(|l| ast_region_to_region(this.tcx(), l)) + .map(|l| ast_region_to_region(ccx.tcx, l)) .collect(); let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, @@ -1197,25 +1209,25 @@ fn ty_generics<'tcx,AC>(this: &AC, // Now create the real type parameters. for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(this, + let def = get_or_create_type_parameter_def(ccx, space, param, i as u32); debug!("ty_generics: def for type param: {}, {}", - def.repr(this.tcx()), + def.repr(ccx.tcx), space); result.types.push(space, def); } // Just for fun, also push the bounds from the type parameters // into the predicates list. This is currently kind of non-DRY. - create_predicates(this.tcx(), &mut result, space); + create_predicates(ccx.tcx, &mut result, space); // Add the bounds not associated with a type parameter for predicate in where_clause.predicates.iter() { match predicate { &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty); + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty); for bound in bound_pred.bounds.iter() { match bound { @@ -1223,7 +1235,7 @@ fn ty_generics<'tcx,AC>(this: &AC, let mut projections = Vec::new(); let trait_ref = astconv::instantiate_poly_trait_ref( - this, + ccx, &ExplicitRscope, poly_trait_ref, Some(ty), @@ -1238,7 +1250,7 @@ fn ty_generics<'tcx,AC>(this: &AC, } &ast::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(this.tcx(), lifetime); + let region = ast_region_to_region(ccx.tcx, lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); result.predicates.push(space, ty::Predicate::TypeOutlives(pred)) } @@ -1247,9 +1259,9 @@ fn ty_generics<'tcx,AC>(this: &AC, } &ast::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = ast_region_to_region(this.tcx(), ®ion_pred.lifetime); + let r1 = ast_region_to_region(ccx.tcx, ®ion_pred.lifetime); for bound in region_pred.bounds.iter() { - let r2 = ast_region_to_region(this.tcx(), bound); + let r2 = ast_region_to_region(ccx.tcx, bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); result.predicates.push(space, ty::Predicate::RegionOutlives(pred)) } @@ -1257,7 +1269,7 @@ fn ty_generics<'tcx,AC>(this: &AC, &ast::WherePredicate::EqPredicate(ref eq_pred) => { // FIXME(#20041) - this.tcx().sess.span_bug(eq_pred.span, + ccx.tcx.sess.span_bug(eq_pred.span, "Equality constraints are not yet \ implemented (#20041)") } @@ -1292,34 +1304,33 @@ fn create_predicates<'tcx>( } } -fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, +fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, space: subst::ParamSpace, param: &ast::TyParam, index: u32) -> ty::TypeParameterDef<'tcx> - where AC: AstConv<'tcx> { - match this.tcx().ty_param_defs.borrow().get(¶m.id) { + match ccx.tcx.ty_param_defs.borrow().get(¶m.id) { Some(d) => { return (*d).clone(); } None => { } } let param_ty = ty::ParamTy::new(space, index, param.ident.name); - let bounds = compute_bounds(this, - param_ty.to_ty(this.tcx()), + let bounds = compute_bounds(ccx, + param_ty.to_ty(ccx.tcx), param.bounds[], SizedByDefault::Yes, param.span); let default = match param.default { None => None, Some(ref path) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path); let cur_idx = index; ty::walk_ty(ty, |t| { match t.sty { ty::ty_param(p) => if p.idx > cur_idx { - span_err!(this.tcx().sess, path.span, E0128, + span_err!(ccx.tcx.sess, path.span, E0128, "type parameters with a default cannot use \ forward declared identifiers"); }, @@ -1340,7 +1351,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, default: default }; - this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); + ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); def } @@ -1350,26 +1361,25 @@ enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an 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 the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'tcx,AC>(this: &AC, +fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], sized_by_default: SizedByDefault, span: Span) -> ty::ParamBounds<'tcx> - where AC: AstConv<'tcx> { - let mut param_bounds = conv_param_bounds(this, + let mut param_bounds = conv_param_bounds(ccx, span, param_ty, ast_bounds); if let SizedByDefault::Yes = sized_by_default { - add_unsized_bound(this, + add_unsized_bound(ccx, &mut param_bounds.builtin_bounds, ast_bounds, span); - check_bounds_compatible(this.tcx(), + check_bounds_compatible(ccx.tcx, param_ty, ¶m_bounds, span); @@ -1404,24 +1414,23 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, } } -fn conv_param_bounds<'tcx,AC>(this: &AC, +fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> - where AC: AstConv<'tcx> { let astconv::PartitionedBounds { builtin_bounds, trait_bounds, region_bounds } = - astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice()); + astconv::partition_bounds(ccx.tcx, span, ast_bounds.as_slice()); let mut projection_bounds = Vec::new(); let trait_bounds: Vec = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_poly_trait_ref(this, + astconv::instantiate_poly_trait_ref(ccx, &ExplicitRscope, bound, Some(param_ty), @@ -1430,7 +1439,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, .collect(); let region_bounds: Vec = region_bounds.into_iter() - .map(|r| ast_region_to_region(this.tcx(), r)) + .map(|r| ast_region_to_region(ccx.tcx, r)) .collect(); ty::ParamBounds { region_bounds: region_bounds, @@ -1440,7 +1449,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, } } -pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, decl: &ast::FnDecl, def_id: ast::DefId, ast_generics: &ast::Generics, @@ -1492,9 +1501,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return scheme; } -pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ty_generics: &ty::Generics<'tcx>) - -> subst::Substs<'tcx> +fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + ty_generics: &ty::Generics<'tcx>) + -> subst::Substs<'tcx> { let types = ty_generics.types.map( @@ -1514,14 +1523,14 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, /// comes back to check after the fact that explicit type the user /// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( - crate_context: &CrateCtxt<'a, 'tcx>, + ccx: &CollectCtxt<'a, 'tcx>, rs: &RS, required_type: Ty<'tcx>, explicit_self: &ast::ExplicitSelf, body_id: ast::NodeId) { if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node { - let typ = crate_context.to_ty(rs, &**ast_type); + let typ = ccx.to_ty(rs, &**ast_type); let base_type = match typ.sty { ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty, ty::ty_uniq(typ) => typ, @@ -1537,27 +1546,27 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = liberate_early_bound_regions( - crate_context.tcx, body_scope, + ccx.tcx, body_scope, &ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::Binder(required_type))); + ccx.tcx, body_scope, &ty::Binder(required_type))); // The "base type" comes from the impl. It too may have late-bound // regions from the method. assert!(!base_type.has_regions_escaping_depth(1)); let base_type_free = liberate_early_bound_regions( - crate_context.tcx, body_scope, + ccx.tcx, body_scope, &ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::Binder(base_type))); + ccx.tcx, body_scope, &ty::Binder(base_type))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", - required_type.repr(crate_context.tcx), - required_type_free.repr(crate_context.tcx), - base_type.repr(crate_context.tcx), - base_type_free.repr(crate_context.tcx)); - let infcx = infer::new_infer_ctxt(crate_context.tcx); - drop(::require_same_types(crate_context.tcx, + required_type.repr(ccx.tcx), + required_type_free.repr(ccx.tcx), + base_type.repr(ccx.tcx), + base_type_free.repr(ccx.tcx)); + let infcx = infer::new_infer_ctxt(ccx.tcx); + drop(::require_same_types(ccx.tcx, Some(&infcx), false, explicit_self.span, @@ -1565,7 +1574,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( required_type_free, || { format!("mismatched self type: expected `{}`", - ppaux::ty_to_string(crate_context.tcx, required_type)) + ppaux::ty_to_string(ccx.tcx, required_type)) })); infcx.resolve_regions_and_report_errors(body_id); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 48f9b129719..3146a118139 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -119,7 +119,7 @@ struct TypeAndSubsts<'tcx> { struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. trait_map: ty::TraitMap, - tcx: &'a ty::ctxt<'tcx> + tcx: &'a ty::ctxt<'tcx>, } // Functions that write types into the node type table @@ -320,7 +320,7 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { }; time(time_passes, "type collecting", (), |_| - collect::collect_item_types(&ccx)); + collect::collect_item_types(tcx)); // this ensures that later parts of type checking can assume that items // have valid types and not error diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 6bef7e713af..e58c2275fcd 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -831,20 +831,7 @@ fn add_constraints_from_ty(&mut self, } } - ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) | - ty::ty_closure(box ty::ClosureTy { - ref sig, - store: ty::UniqTraitStore, - .. - }) => - { - self.add_constraints_from_sig(generics, sig, variance); - } - - ty::ty_closure(box ty::ClosureTy { ref sig, - store: ty::RegionTraitStore(region, _), .. }) => { - let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, region, contra); + ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) => { self.add_constraints_from_sig(generics, sig, variance); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3f5b0eaee12..e01dbac68ee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -50,7 +50,6 @@ use std::rc::Rc; use std::u32; use std::str::Str as StrTrait; // Conflicts with Str variant -use std::char::Char as CharTrait; // Conflicts with Char variant use std::path::Path as FsPath; // Conflicts with Path struct use core::DocContext; @@ -1367,7 +1366,6 @@ fn clean(&self, cx: &DocContext) -> Type { } } } - TyClosure(ref c) => Closure(box c.clean(cx)), TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyParen(ref ty) => ty.clean(cx), TyQPath(ref qp) => qp.clean(cx), @@ -1427,19 +1425,6 @@ fn clean(&self, cx: &DocContext) -> Type { decl: (ast_util::local_def(0), &fty.sig).clean(cx), abi: fty.abi.to_string(), }), - ty::ty_closure(ref fty) => { - let decl = box ClosureDecl { - lifetimes: Vec::new(), // FIXME: this looks wrong... - decl: (ast_util::local_def(0), &fty.sig).clean(cx), - onceness: fty.onceness, - unsafety: fty.unsafety, - bounds: fty.bounds.clean(cx), - }; - match fty.store { - ty::UniqTraitStore => Proc(decl), - ty::RegionTraitStore(..) => Closure(decl), - } - } ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => { let fqn = csearch::get_item_path(cx.tcx(), did); @@ -2243,8 +2228,12 @@ fn name_from_pat(p: &ast::Pat) -> String { }, PatRange(..) => panic!("tried to get argument name from PatRange, \ which is not allowed in function arguments"), - PatVec(..) => panic!("tried to get argument name from pat_vec, \ - which is not allowed in function arguments"), + PatVec(ref begin, ref mid, ref end) => { + let begin = begin.iter().map(|p| name_from_pat(&**p)); + let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); + let end = end.iter().map(|p| name_from_pat(&**p)); + format!("[{}]", begin.chain(mid).chain(end).collect::>().connect(", ")) + }, PatMac(..) => { warn!("can't document the name of a function argument \ produced by a pattern macro"); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d05e15ff251..99afef4173f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -182,6 +182,7 @@ pub struct Trait { pub struct Impl { pub unsafety: ast::Unsafety, + pub polarity: ast::ImplPolarity, pub generics: ast::Generics, pub trait_: Option, pub for_: P, diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 0f0dbf6a24d..dcc90117d26 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -20,8 +20,8 @@ #[cfg(unix)] mod imp { + use std::ffi::CString; use libc; - use std::c_str::ToCStr; #[cfg(target_os = "linux")] mod os { @@ -111,9 +111,11 @@ pub struct Lock { impl Lock { pub fn new(p: &Path) -> Lock { - let fd = p.with_c_str(|s| unsafe { - libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU) - }); + let buf = CString::from_slice(p.as_vec()); + let fd = unsafe { + libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT, + libc::S_IRWXU) + }; assert!(fd > 0); let flock = os::flock { l_start: 0, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9d003eca27f..3b9265cf569 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,7 +29,7 @@ use libc; use std::ascii::AsciiExt; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::fmt; @@ -215,7 +215,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let id = id.as_ref().map(|a| a.as_slice()); s.push_str(highlight::highlight(text.as_slice(), None, id) .as_slice()); - let output = s.to_c_str(); + let output = CString::from_vec(s.into_bytes()); hoedown_buffer_puts(ob, output.as_ptr()); }) } @@ -224,15 +224,16 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, level: libc::c_int, opaque: *mut libc::c_void) { // hoedown does this, we may as well too - "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } // Extract the text provided let s = if text.is_null() { "".to_string() } else { - unsafe { - String::from_raw_buf_len((*text).data, (*text).size as uint) - } + let s = unsafe { + slice::from_raw_buf(&(*text).data, (*text).size as uint) + }; + str::from_utf8(s).unwrap().to_string() }; // Transform the contents of the header into a hyphenated string @@ -273,7 +274,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { format!("{} ", sec) }); - text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + let text = CString::from_vec(text.into_bytes()); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } } reset_headers(); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 338b9b3e0eb..ddb14d6944b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -36,7 +36,6 @@ use std::cell::RefCell; use std::cmp::Ordering::{self, Less, Greater, Equal}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::default::Default; use std::fmt; @@ -822,10 +821,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option { if let clean::ImplItem(ref i) = item.inner { match i.trait_ { Some(clean::ResolvedPath{ did, .. }) => { - let v = match self.implementors.entry(did) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let v = self.implementors.entry(&did).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(Implementor { def_id: item.def_id, generics: i.generics.clone(), @@ -1014,10 +1011,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option { }; if let Some(did) = did { - let v = match self.impls.entry(did) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let v = self.impls.entry(&did).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(Impl { impl_: i, dox: dox, @@ -1264,10 +1259,9 @@ fn build_sidebar(&self, m: &clean::Module) -> HashMap> { None => continue, Some(ref s) => s.to_string(), }; - let v = match map.entry(short.to_string()) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let short = short.to_string(); + let v = map.entry(&short).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(myname); } @@ -2259,9 +2253,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { cols += 1; tmp /= 10; } - try!(write!(fmt, "