Skip to content

Commit 399ff25

Browse files
committed
auto merge of #19118 : jakub-/rust/roll-up, r=jakub-
2 parents a24b444 + ee66c84 commit 399ff25

File tree

104 files changed

+1629
-1101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+1629
-1101
lines changed

configure

+1
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ do
10311031
make_dir $h/test/doc-guide-tasks
10321032
make_dir $h/test/doc-guide-plugin
10331033
make_dir $h/test/doc-guide-crates
1034+
make_dir $h/test/doc-guide-error-handling
10341035
make_dir $h/test/doc-rust
10351036
done
10361037

mk/docs.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
######################################################################
2828
DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
2929
guide-tasks guide-container guide-pointers guide-testing \
30-
guide-plugin guide-crates complement-bugreport \
30+
guide-plugin guide-crates complement-bugreport guide-error-handling \
3131
complement-lang-faq complement-design-faq complement-project-faq \
3232
rustdoc guide-unsafe guide-strings reference
3333

mk/grammar.mk

+12-4
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,25 @@ endef
3030
$(BG):
3131
$(Q)mkdir -p $(BG)
3232

33-
$(BG)RustLexer.class: $(SG)RustLexer.g4
33+
$(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4
3434
$(Q)$(CFG_ANTLR4) -o $(B)grammar $(SG)RustLexer.g4
3535
$(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java
3636

37-
$(BG)verify: $(SG)verify.rs rustc-stage2-H-$(CFG_BUILD) $(LD)stamp.regex_macros $(LD)stamp.rustc
38-
$(Q)$(RUSTC) -O --out-dir $(BG) -L $(L) $(SG)verify.rs
37+
check-build-lexer-verifier: $(BG)verify
38+
39+
ifeq ($(NO_REBUILD),)
40+
VERIFY_DEPS := rustc-stage2-H-$(CFG_BUILD) $(LD)stamp.regex_macros $(LD)stamp.rustc
41+
else
42+
VERIFY_DEPS :=
43+
endif
44+
45+
$(BG)verify: $(BG) $(SG)verify.rs $(VERIFY_DEPS)
46+
$(Q)$(RUSTC) --out-dir $(BG) -L $(L) $(SG)verify.rs
3947

4048
ifdef CFG_JAVAC
4149
ifdef CFG_ANTLR4
4250
ifdef CFG_GRUN
43-
check-lexer: $(BG) $(BG)RustLexer.class $(BG)verify
51+
check-lexer: $(BG) $(BG)RustLexer.class check-build-lexer-verifier
4452
$(info Verifying libsyntax against the reference lexer ...)
4553
$(Q)$(SG)check.sh $(S) "$(BG)" \
4654
"$(CFG_GRUN)" "$(BG)verify" "$(BG)RustLexer.tokens"

mk/tests.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ check-docs: cleantestlibs cleantmptestlogs check-stage2-docs
199199

200200
# Some less critical tests that are not prone to breakage.
201201
# Not run as part of the normal test suite, but tested by bors on checkin.
202-
check-secondary: check-build-compiletest check-lexer check-pretty
202+
check-secondary: check-build-compiletest check-build-lexer-verifier check-lexer check-pretty
203203

204204
# check + check-secondary.
205205
#

src/doc/guide-error-handling.md

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
% Error Handling in Rust
2+
3+
> The best-laid plans of mice and men
4+
> Often go awry
5+
>
6+
> "Tae a Moose", Robert Burns
7+
8+
Sometimes, things just go wrong. It's important to have a plan for when the
9+
inevitable happens. Rust has rich support for handling errors that may (let's
10+
be honest: will) occur in your programs.
11+
12+
There are two main kinds of errors that can occur in your programs: failures,
13+
and panics. Let's talk about the difference between the two, and then discuss
14+
how to handle each. Then, we'll discuss upgrading failures to panics.
15+
16+
# Failure vs. Panic
17+
18+
Rust uses two terms to differentiate between two forms of error: failure, and
19+
panic. A **failure** is an error that can be recovered from in some way. A
20+
**panic** is an error that cannot be recovered from.
21+
22+
What do we mean by 'recover'? Well, in most cases, the possibility of an error
23+
is expected. For example, consider the `from_str` function:
24+
25+
```{rust,ignore}
26+
from_str("5");
27+
```
28+
29+
This function takes a string argument and converts it into another type. But
30+
because it's a string, you can't be sure that the conversion actually works.
31+
For example, what should this convert to?
32+
33+
```{rust,ignore}
34+
from_str("hello5world");
35+
```
36+
37+
This won't work. So we know that this function will only work properly for some
38+
inputs. It's expected behavior. We call this kind of error 'failure.'
39+
40+
On the other hand, sometimes, there are errors that are unexpected, or which
41+
we cannot recover from. A classic example is an `assert!`:
42+
43+
```{rust,ignore}
44+
assert!(x == 5);
45+
```
46+
47+
We use `assert!` to declare that something is true. If it's not true, something
48+
is very wrong. Wrong enough that we can't continue with things in the current
49+
state. Another example is using the `unreachable!()` macro
50+
51+
```{rust,ignore}
52+
enum Event {
53+
NewRelease,
54+
}
55+
56+
fn probability(_: &Event) -> f64 {
57+
// real implementation would be more complex, of course
58+
0.95
59+
}
60+
61+
fn descriptive_probability(event: Event) -> &'static str {
62+
match probability(&event) {
63+
1.00 => "certain",
64+
0.00 => "impossible",
65+
0.00 ... 0.25 => "very unlikely",
66+
0.25 ... 0.50 => "unlikely",
67+
0.50 ... 0.75 => "likely",
68+
0.75 ... 1.00 => "very likely",
69+
}
70+
}
71+
72+
fn main() {
73+
std::io::println(descriptive_probability(NewRelease));
74+
}
75+
```
76+
77+
This will give us an error:
78+
79+
```{notrust,ignore}
80+
error: non-exhaustive patterns: `_` not covered [E0004]
81+
```
82+
83+
While we know that we've covered all possible cases, Rust can't tell. It
84+
doesn't know that probability is between 0.0 and 1.0. So we add another case:
85+
86+
```rust
87+
use Event::NewRelease;
88+
89+
enum Event {
90+
NewRelease,
91+
}
92+
93+
fn probability(_: &Event) -> f64 {
94+
// real implementation would be more complex, of course
95+
0.95
96+
}
97+
98+
fn descriptive_probability(event: Event) -> &'static str {
99+
match probability(&event) {
100+
1.00 => "certain",
101+
0.00 => "impossible",
102+
0.00 ... 0.25 => "very unlikely",
103+
0.25 ... 0.50 => "unlikely",
104+
0.50 ... 0.75 => "likely",
105+
0.75 ... 1.00 => "very likely",
106+
_ => unreachable!()
107+
}
108+
}
109+
110+
fn main() {
111+
println!("{}", descriptive_probability(NewRelease));
112+
}
113+
```
114+
115+
We shouldn't ever hit the `_` case, so we use the `unreachable!()` macro to
116+
indicate this. `unreachable!()` gives a different kind of error than `Result`.
117+
Rust calls these sorts of errors 'panics.'
118+
119+
# Handling errors with `Option` and `Result`
120+
121+
The simplest way to indicate that a function may fail is to use the `Option<T>`
122+
type. Remember our `from_str()` example? Here's its type signature:
123+
124+
```{rust,ignore}
125+
pub fn from_str<A: FromStr>(s: &str) -> Option<A>
126+
```
127+
128+
`from_str()` returns an `Option<A>`. If the conversion succeeds, it will return
129+
`Some(value)`, and if it fails, it will return `None`.
130+
131+
This is appropriate for the simplest of cases, but doesn't give us a lot of
132+
information in the failure case. What if we wanted to know _why_ the conversion
133+
failed? For this, we can use the `Result<T, E>` type. It looks like this:
134+
135+
```rust
136+
enum Result<T, E> {
137+
Ok(T),
138+
Err(E)
139+
}
140+
```
141+
142+
This enum is provided by Rust itself, so you don't need to define it to use it
143+
in your code. The `Ok(T)` variant represents a success, and the `Err(E)` variant
144+
represents a failure. Returning a `Result` instead of an `Option` is recommended
145+
for all but the most trivial of situations.
146+
147+
Here's an example of using `Result`:
148+
149+
```rust
150+
#[deriving(Show)]
151+
enum Version { Version1, Version2 }
152+
153+
#[deriving(Show)]
154+
enum ParseError { InvalidHeaderLength, InvalidVersion }
155+
156+
fn parse_version(header: &[u8]) -> Result<Version, ParseError> {
157+
if header.len() < 1 {
158+
return Err(ParseError::InvalidHeaderLength);
159+
}
160+
match header[0] {
161+
1 => Ok(Version::Version1),
162+
2 => Ok(Version::Version2),
163+
_ => Err(ParseError::InvalidVersion)
164+
}
165+
}
166+
167+
let version = parse_version(&[1, 2, 3, 4]);
168+
match version {
169+
Ok(v) => {
170+
println!("working with version: {}", v);
171+
}
172+
Err(e) => {
173+
println!("error parsing header: {}", e);
174+
}
175+
}
176+
```
177+
178+
This function makes use of an enum, `ParseError`, to enumerate the various
179+
errors that can occur.
180+
181+
# Non-recoverable errors with `panic!`
182+
183+
In the case of an error that is unexpected and not recoverable, the `panic!`
184+
macro will induce a panic. This will crash the current task, and give an error:
185+
186+
```{rust,ignore}
187+
panic!("boom");
188+
```
189+
190+
gives
191+
192+
```{notrust,ignore}
193+
task '<main>' panicked at 'boom', hello.rs:2
194+
```
195+
196+
when you run it.
197+
198+
Because these kinds of situations are relatively rare, use panics sparingly.
199+
200+
# Upgrading failures to panics
201+
202+
In certain circumstances, even though a function may fail, we may want to treat
203+
it as a panic instead. For example, `io::stdin().read_line()` returns an
204+
`IoResult<String>`, a form of `Result`, when there is an error reading the
205+
line. This allows us to handle and possibly recover from this sort of error.
206+
207+
If we don't want to handle this error, and would rather just abort the program,
208+
we can use the `unwrap()` method:
209+
210+
```{rust,ignore}
211+
io::stdin().read_line().unwrap();
212+
```
213+
214+
`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give
215+
me the value, and if something goes wrong, just crash." This is less reliable
216+
than matching the error and attempting to recover, but is also significantly
217+
shorter. Sometimes, just crashing is appropriate.
218+
219+
There's another way of doing this that's a bit nicer than `unwrap()`:
220+
221+
```{rust,ignore}
222+
let input = io::stdin().read_line()
223+
.ok()
224+
.expect("Failed to read line");
225+
```
226+
`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same
227+
thing as `unwrap()`, but takes a message. This message is passed along to the
228+
underlying `panic!`, providing a better error message if the code errors.

src/doc/guide.md

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ $ ./main # or main.exe on Windows
159159
Hello, world!
160160
```
161161

162+
You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code.
163+
162164
Success! Let's go over what just happened in detail.
163165

164166
```{rust}

src/doc/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ a guide that can help you out:
5959
* [References and Lifetimes](guide-lifetimes.html)
6060
* [Crates and modules](guide-crates.html)
6161
* [Tasks and Communication](guide-tasks.html)
62+
* [Error Handling](guide-error-handling.html)
6263
* [Foreign Function Interface](guide-ffi.html)
6364
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
6465
* [Macros](guide-macros.html)

src/doc/po4a.conf

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
[type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md
2121
[type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-unsafe.md
2222
[type: text] src/doc/guide-crates.md $lang:doc/l10n/$lang/guide-crates.md
23+
[type: text] src/doc/guide-error-handling.md $lang:doc/l10n/$lang/guide-error-handling.md
2324
[type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md
2425
[type: text] src/doc/index.md $lang:doc/l10n/$lang/index.md
2526
[type: text] src/doc/intro.md $lang:doc/l10n/$lang/intro.md

0 commit comments

Comments
 (0)