Skip to content

Commit 252a459

Browse files
committed
Auto merge of #49371 - scottmcm:catch-wrapping, r=nikomatsakis
Add ok-wrapping to catch blocks, per RFC Updates the `catch{}` lowering to wrap the result in `Try::from_ok`. r? @nikomatsakis Fixes #41414 Fixes #43818
2 parents 4777881 + 311ff5b commit 252a459

File tree

14 files changed

+132
-43
lines changed

14 files changed

+132
-43
lines changed

src/doc/unstable-book/src/language-features/catch-expr.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ expression creates a new scope one can use the `?` operator in.
1515
use std::num::ParseIntError;
1616

1717
let result: Result<i32, ParseIntError> = do catch {
18-
Ok("1".parse::<i32>()?
18+
"1".parse::<i32>()?
1919
+ "2".parse::<i32>()?
20-
+ "3".parse::<i32>()?)
20+
+ "3".parse::<i32>()?
2121
};
2222
assert_eq!(result, Ok(6));
2323

2424
let result: Result<i32, ParseIntError> = do catch {
25-
Ok("1".parse::<i32>()?
25+
"1".parse::<i32>()?
2626
+ "foo".parse::<i32>()?
27-
+ "3".parse::<i32>()?)
27+
+ "3".parse::<i32>()?
2828
};
2929
assert!(result.is_err());
3030
```

src/librustc/hir/lowering.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -3010,7 +3010,28 @@ impl<'a> LoweringContext<'a> {
30103010
)
30113011
}),
30123012
ExprKind::Catch(ref body) => {
3013-
self.with_catch_scope(body.id, |this| hir::ExprBlock(this.lower_block(body, true)))
3013+
self.with_catch_scope(body.id, |this| {
3014+
let unstable_span =
3015+
this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span);
3016+
let mut block = this.lower_block(body, true).into_inner();
3017+
let tail = block.expr.take().map_or_else(
3018+
|| {
3019+
let LoweredNodeId { node_id, hir_id } = this.next_id();
3020+
let span = this.sess.codemap().end_point(unstable_span);
3021+
hir::Expr {
3022+
id: node_id,
3023+
span,
3024+
node: hir::ExprTup(hir_vec![]),
3025+
attrs: ThinVec::new(),
3026+
hir_id,
3027+
}
3028+
},
3029+
|x: P<hir::Expr>| x.into_inner(),
3030+
);
3031+
block.expr = Some(this.wrap_in_try_constructor(
3032+
"from_ok", tail, unstable_span));
3033+
hir::ExprBlock(P(block))
3034+
})
30143035
}
30153036
ExprKind::Match(ref expr, ref arms) => hir::ExprMatch(
30163037
P(self.lower_expr(expr)),
@@ -3539,12 +3560,8 @@ impl<'a> LoweringContext<'a> {
35393560

35403561
self.expr_call(e.span, from, hir_vec![err_expr])
35413562
};
3542-
let from_err_expr = {
3543-
let path = &["ops", "Try", "from_error"];
3544-
let from_err = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
3545-
P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
3546-
};
3547-
3563+
let from_err_expr =
3564+
self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
35483565
let thin_attrs = ThinVec::from(attrs);
35493566
let catch_scope = self.catch_scopes.last().map(|x| *x);
35503567
let ret_expr = if let Some(catch_node) = catch_scope {
@@ -4079,6 +4096,18 @@ impl<'a> LoweringContext<'a> {
40794096
)
40804097
}
40814098
}
4099+
4100+
fn wrap_in_try_constructor(
4101+
&mut self,
4102+
method: &'static str,
4103+
e: hir::Expr,
4104+
unstable_span: Span,
4105+
) -> P<hir::Expr> {
4106+
let path = &["ops", "Try", method];
4107+
let from_err = P(self.expr_std_path(unstable_span, path,
4108+
ThinVec::new()));
4109+
P(self.expr_call(e.span, from_err, hir_vec![e]))
4110+
}
40824111
}
40834112

40844113
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {

src/librustc/ich/impls_syntax.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,8 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
372372

373373
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
374374
DotFill,
375-
QuestionMark
375+
QuestionMark,
376+
Catch
376377
});
377378

378379
impl_stable_hash_for!(enum ::syntax_pos::FileName {

src/librustc_mir/borrow_check/nll/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
202202
});
203203

204204
// Also dump the inference graph constraints as a graphviz file.
205-
let _: io::Result<()> = do catch {
205+
let _: io::Result<()> = do_catch! {{
206206
let mut file =
207207
pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?;
208-
regioncx.dump_graphviz(&mut file)
209-
};
208+
regioncx.dump_graphviz(&mut file)?;
209+
}};
210210
}
211211

212212
fn dump_annotation<'a, 'gcx, 'tcx>(

src/librustc_mir/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
3232
#![feature(nonzero)]
3333
#![feature(inclusive_range_fields)]
3434
#![feature(crate_visibility_modifier)]
35+
#![cfg_attr(stage0, feature(try_trait))]
3536

3637
extern crate arena;
3738
#[macro_use]
@@ -53,6 +54,16 @@ extern crate log_settings;
5354
extern crate rustc_apfloat;
5455
extern crate byteorder;
5556

57+
#[cfg(stage0)]
58+
macro_rules! do_catch {
59+
($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() }
60+
}
61+
62+
#[cfg(not(stage0))]
63+
macro_rules! do_catch {
64+
($t:expr) => { do catch { $t } }
65+
}
66+
5667
mod diagnostics;
5768

5869
mod borrow_check;

src/librustc_mir/util/pretty.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
137137
) where
138138
F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
139139
{
140-
let _: io::Result<()> = do catch {
140+
let _: io::Result<()> = do_catch! {{
141141
let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
142142
writeln!(file, "// MIR for `{}`", node_path)?;
143143
writeln!(file, "// source = {:?}", source)?;
@@ -150,16 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
150150
extra_data(PassWhere::BeforeCFG, &mut file)?;
151151
write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
152152
extra_data(PassWhere::AfterCFG, &mut file)?;
153-
Ok(())
154-
};
153+
}};
155154

156155
if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
157-
let _: io::Result<()> = do catch {
156+
let _: io::Result<()> = do_catch! {{
158157
let mut file =
159158
create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
160159
write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?;
161-
Ok(())
162-
};
160+
}};
163161
}
164162
}
165163

src/libsyntax_pos/hygiene.rs

+2
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ pub enum ExpnFormat {
432432
pub enum CompilerDesugaringKind {
433433
DotFill,
434434
QuestionMark,
435+
Catch,
435436
}
436437

437438
impl CompilerDesugaringKind {
@@ -440,6 +441,7 @@ impl CompilerDesugaringKind {
440441
let s = match *self {
441442
DotFill => "...",
442443
QuestionMark => "?",
444+
Catch => "do catch",
443445
};
444446
Symbol::intern(s)
445447
}

src/test/compile-fail/catch-bad-lifetime.rs

-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ pub fn main() {
2121
//~^ ERROR `my_string` does not live long enough
2222
Err(my_str) ?;
2323
Err("") ?;
24-
Ok(())
2524
};
2625
}
2726

@@ -32,7 +31,6 @@ pub fn main() {
3231
let mut j: Result<(), &mut i32> = do catch {
3332
Err(k) ?;
3433
i = 10; //~ ERROR cannot assign to `i` because it is borrowed
35-
Ok(())
3634
};
3735
::std::mem::drop(k); //~ ERROR use of moved value: `k`
3836
i = 40; //~ ERROR cannot assign to `i` because it is borrowed

src/test/compile-fail/catch-bad-type.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,18 @@
1111
#![feature(catch_expr)]
1212

1313
pub fn main() {
14-
let res: Result<i32, i32> = do catch {
14+
let res: Result<u32, i32> = do catch {
1515
Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied
16-
Ok(5)
16+
5
1717
};
18+
1819
let res: Result<i32, i32> = do catch {
19-
Ok("") //~ mismatched types
20+
"" //~ ERROR type mismatch
2021
};
22+
23+
let res: Result<i32, i32> = do catch { }; //~ ERROR type mismatch
24+
25+
let res: () = do catch { }; //~ the trait bound `(): std::ops::Try` is not satisfied
26+
27+
let res: i32 = do catch { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied
2128
}

src/test/compile-fail/catch-maybe-bad-lifetime.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn main() {
1717
let mut i = 222;
1818
let x: Result<&i32, ()> = do catch {
1919
Err(())?;
20-
Ok(&i)
20+
&i
2121
};
2222
x.ok().cloned();
2323
i = 0; //~ ERROR cannot assign to `i` because it is borrowed
@@ -29,7 +29,6 @@ pub fn main() {
2929
let _y: Result<(), ()> = do catch {
3030
Err(())?;
3131
::std::mem::drop(x);
32-
Ok(())
3332
};
3433
println!("{}", x); //~ ERROR use of moved value: `x`
3534
}
@@ -42,7 +41,6 @@ pub fn main() {
4241
let x: Result<(), ()> = do catch {
4342
Err(())?;
4443
j = &i;
45-
Ok(())
4644
};
4745
i = 0; //~ ERROR cannot assign to `i` because it is borrowed
4846
let _ = i;

src/test/compile-fail/catch-opt-init.rs

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ pub fn main() {
1919
cfg_res = 5;
2020
Ok::<(), ()>(())?;
2121
use_val(cfg_res);
22-
Ok(())
2322
};
2423
assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable
2524
}

src/test/run-pass/catch-expr.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
struct catch {}
1414

1515
pub fn main() {
16-
let catch_result = do catch {
16+
let catch_result: Option<_> = do catch {
1717
let x = 5;
1818
x
1919
};
20-
assert_eq!(catch_result, 5);
20+
assert_eq!(catch_result, Some(5));
2121

2222
let mut catch = true;
2323
while catch { catch = false; }
@@ -30,51 +30,50 @@ pub fn main() {
3030
_ => {}
3131
};
3232

33-
let catch_err = do catch {
33+
let catch_err: Result<_, i32> = do catch {
3434
Err(22)?;
35-
Ok(1)
35+
1
3636
};
3737
assert_eq!(catch_err, Err(22));
3838

3939
let catch_okay: Result<i32, i32> = do catch {
4040
if false { Err(25)?; }
4141
Ok::<(), i32>(())?;
42-
Ok(28)
42+
28
4343
};
4444
assert_eq!(catch_okay, Ok(28));
4545

4646
let catch_from_loop: Result<i32, i32> = do catch {
4747
for i in 0..10 {
4848
if i < 5 { Ok::<i32, i32>(i)?; } else { Err(i)?; }
4949
}
50-
Ok(22)
50+
22
5151
};
5252
assert_eq!(catch_from_loop, Err(5));
5353

5454
let cfg_init;
5555
let _res: Result<(), ()> = do catch {
5656
cfg_init = 5;
57-
Ok(())
5857
};
5958
assert_eq!(cfg_init, 5);
6059

6160
let cfg_init_2;
6261
let _res: Result<(), ()> = do catch {
6362
cfg_init_2 = 6;
6463
Err(())?;
65-
Ok(())
6664
};
6765
assert_eq!(cfg_init_2, 6);
6866

6967
let my_string = "test".to_string();
7068
let res: Result<&str, ()> = do catch {
71-
Ok(&my_string)
69+
// Unfortunately, deref doesn't fire here (#49356)
70+
&my_string[..]
7271
};
7372
assert_eq!(res, Ok("test"));
7473

75-
do catch {
76-
()
77-
}
74+
let my_opt: Option<_> = do catch { () };
75+
assert_eq!(my_opt, Some(()));
7876

79-
();
77+
let my_opt: Option<_> = do catch { };
78+
assert_eq!(my_opt, Some(()));
8079
}

src/test/ui/catch-block-type-error.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(catch_expr)]
12+
13+
fn foo() -> Option<()> { Some(()) }
14+
15+
fn main() {
16+
let _: Option<f32> = do catch {
17+
foo()?;
18+
42
19+
//~^ ERROR type mismatch
20+
};
21+
22+
let _: Option<i32> = do catch {
23+
foo()?;
24+
};
25+
//~^ ERROR type mismatch
26+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0271]: type mismatch resolving `<std::option::Option<f32> as std::ops::Try>::Ok == {integer}`
2+
--> $DIR/catch-block-type-error.rs:18:9
3+
|
4+
LL | 42
5+
| ^^ expected f32, found integral variable
6+
|
7+
= note: expected type `f32`
8+
found type `{integer}`
9+
10+
error[E0271]: type mismatch resolving `<std::option::Option<i32> as std::ops::Try>::Ok == ()`
11+
--> $DIR/catch-block-type-error.rs:24:5
12+
|
13+
LL | };
14+
| ^ expected i32, found ()
15+
|
16+
= note: expected type `i32`
17+
found type `()`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)