Skip to content

Commit

Permalink
Auto merge of #33523 - Manishearth:rollup, r=Manishearth
Browse files Browse the repository at this point in the history
Rollup of 10 pull requests

- Successful merges: #33129, #33224, #33370, #33383, #33431, #33474, #33480, #33496, #33509, #33514
- Failed merges:
  • Loading branch information
bors committed May 9, 2016
2 parents 0e7cb8b + 52f48bd commit e0fd34b
Show file tree
Hide file tree
Showing 32 changed files with 1,106 additions and 925 deletions.
120 changes: 61 additions & 59 deletions src/doc/book/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -1573,8 +1573,9 @@ detail on Getopts, but there is [some good documentation][15]
describing it. The short story is that Getopts generates an argument
parser and a help message from a vector of options (The fact that it
is a vector is hidden behind a struct and a set of methods). Once the
parsing is done, we can decode the program arguments into a Rust
struct. From there, we can get information about the flags, for
parsing is done, the parser returns a struct that records matches
for defined options, and remaining "free" arguments.
From there, we can get information about the flags, for
instance, whether they were passed in, and what arguments they
had. Here's our program with the appropriate `extern crate`
statements, and the basic argument setup for Getopts:
Expand Down Expand Up @@ -1605,8 +1606,8 @@ fn main() {
print_usage(&program, opts);
return;
}
let data_path = &args[1];
let city = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];
// Do stuff with information
}
Expand Down Expand Up @@ -1680,8 +1681,8 @@ fn main() {
return;
}
let data_path = &args[1];
let city: &str = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];
let file = File::open(data_path).unwrap();
let mut rdr = csv::Reader::from_reader(file);
Expand Down Expand Up @@ -1792,13 +1793,15 @@ fn main() {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
};
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
let data_path = &args[1];
let city = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];
for pop in search(data_path, city) {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
Expand Down Expand Up @@ -1876,14 +1879,14 @@ when calling `search`:

```rust,ignore
...
match search(&data_file, &city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
match search(data_path, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
Err(err) => println!("{}", err)
}
Err(err) => println!("{}", err)
}
...
```

Expand Down Expand Up @@ -1914,43 +1917,37 @@ fn print_usage(program: &str, opts: Options) {
println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
}
```
The next part is going to be only a little harder:
Of course we need to adapt the argument handling code:

```rust,ignore
...
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
...
let file = matches.opt_str("f");
let data_file = &file.as_ref().map(Path::new);
let city = if !matches.free.is_empty() {
&matches.free[0]
} else {
print_usage(&program, opts);
return;
};
match search(data_file, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
...
let data_path = matches.opt_str("f");
let city = if !matches.free.is_empty() {
&matches.free[0]
} else {
print_usage(&program, opts);
return;
};
match search(&data_path, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
Err(err) => println!("{}", err)
}
Err(err) => println!("{}", err)
}
...
```

In this piece of code, we take `file` (which has the type
`Option<String>`), and convert it to a type that `search` can use, in
this case, `&Option<AsRef<Path>>`. To do this, we take a reference of
file, and map `Path::new` onto it. In this case, `as_ref()` converts
the `Option<String>` into an `Option<&str>`, and from there, we can
execute `Path::new` to the content of the optional, and return the
optional of the new value. Once we have that, it is a simple matter of
getting the `city` argument and executing `search`.
We've made the user experience a bit nicer by showing the usage message,
instead of a panic from an out-of-bounds index, when `city`, the
remaining free argument, is not present.

Modifying `search` is slightly trickier. The `csv` crate can build a
parser out of
Expand Down Expand Up @@ -2000,6 +1997,8 @@ enum CliError {
And now for impls on `Display` and `Error`:

```rust,ignore
use std::fmt;
impl fmt::Display for CliError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand All @@ -2020,13 +2019,13 @@ impl Error for CliError {
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
fn cause(&self) -> Option<&Error> {
match *self {
CliError::Io(ref err) => Some(err),
CliError::Parse(ref err) => Some(err),
// Our custom error doesn't have an underlying cause, but we could
// modify it so that it does.
CliError::NotFound() => None,
CliError::Csv(ref err) => Some(err),
// Our custom error doesn't have an underlying cause,
// but we could modify it so that it does.
CliError::NotFound => None,
}
}
}
Expand Down Expand Up @@ -2122,24 +2121,27 @@ string and add a flag to the Option variable. Once we've done that, Getopts does

```rust,ignore
...
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
opts.optflag("q", "quiet", "Silences errors and warnings.");
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
opts.optflag("q", "quiet", "Silences errors and warnings.");
...
```

Now we only need to implement our “quiet” functionality. This requires us to
tweak the case analysis in `main`:

```rust,ignore
match search(&args.arg_data_path, &args.arg_city) {
Err(CliError::NotFound) if args.flag_quiet => process::exit(1),
Err(err) => panic!("{}", err),
Ok(pops) => for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
use std::process;
...
match search(&data_path, city) {
Err(CliError::NotFound) if matches.opt_present("q") => process::exit(1),
Err(err) => panic!("{}", err),
Ok(pops) => for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
}
...
```

Certainly, we don't want to be quiet if there was an IO error or if the data
Expand Down
2 changes: 1 addition & 1 deletion src/libcollectionstest/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn test_from_utf8() {
String::from("ศไทย中华Việt Nam"));

let xs = b"hello\xFF".to_vec();
let err = String::from_utf8(xs).err().unwrap();
let err = String::from_utf8(xs).unwrap_err();
assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
}
infer::Reborrow(span) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0312,
"lifetime of reference outlines \
"lifetime of reference outlives \
lifetime of borrowed content...");
self.tcx.note_and_explain_region(&mut err,
"...the reference is valid for ",
Expand Down
96 changes: 95 additions & 1 deletion src/librustc_borrowck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,101 @@ You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

E0509: r##"
This error occurs when an attempt is made to move out of a value whose type
implements the `Drop` trait.
Example of erroneous code:
```compile_fail
struct FancyNum {
num: usize
}
struct DropStruct {
fancy: FancyNum
}
impl Drop for DropStruct {
fn drop(&mut self) {
// Destruct DropStruct, possibly using FancyNum
}
}
fn main() {
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
let fancy_field = drop_struct.fancy; // Error E0509
println!("Fancy: {}", fancy_field.num);
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
}
```
Here, we tried to move a field out of a struct of type `DropStruct` which
implements the `Drop` trait. However, a struct cannot be dropped if one or
more of its fields have been moved.
Structs implementing the `Drop` trait have an implicit destructor that gets
called when they go out of scope. This destructor may use the fields of the
struct, so moving out of the struct could make it impossible to run the
destructor. Therefore, we must think of all values whose type implements the
`Drop` trait as single units whose fields cannot be moved.
This error can be fixed by creating a reference to the fields of a struct,
enum, or tuple using the `ref` keyword:
```
struct FancyNum {
num: usize
}
struct DropStruct {
fancy: FancyNum
}
impl Drop for DropStruct {
fn drop(&mut self) {
// Destruct DropStruct, possibly using FancyNum
}
}
fn main() {
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
let ref fancy_field = drop_struct.fancy; // No more errors!
println!("Fancy: {}", fancy_field.num);
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
}
```
Note that this technique can also be used in the arms of a match expression:
```
struct FancyNum {
num: usize
}
enum DropEnum {
Fancy(FancyNum)
}
impl Drop for DropEnum {
fn drop(&mut self) {
// Destruct DropEnum, possibly using FancyNum
}
}
fn main() {
// Creates and enum of type `DropEnum`, which implements `Drop`
let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
match drop_enum {
// Creates a reference to the inside of `DropEnum::Fancy`
DropEnum::Fancy(ref fancy_field) => // No error!
println!("It was fancy-- {}!", fancy_field.num),
}
// implicit call to `drop_enum.drop()` as drop_enum goes out of scope
}
```
"##,

}

register_diagnostics! {
Expand All @@ -664,6 +759,5 @@ register_diagnostics! {
E0504, // cannot move `..` into closure because it is borrowed
E0505, // cannot move out of `..` because it is borrowed
E0508, // cannot move out of type `..`, a non-copy fixed-size array
E0509, // cannot move out of type `..`, which defines the `Drop` trait
E0524, // two closures require unique access to `..` at the same time
}
Loading

0 comments on commit e0fd34b

Please sign in to comment.