From c4b6521327d6662cbfa245a285bed1764692c4b2 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 25 Mar 2018 00:16:16 -0700 Subject: [PATCH] Add ok-wrapping to catch blocks, per RFC --- src/librustc/hir/lowering.rs | 42 +++++++++++++++---- src/librustc/ich/impls_syntax.rs | 3 +- src/librustc_mir/borrow_check/nll/mod.rs | 6 +-- src/librustc_mir/lib.rs | 11 +++++ src/librustc_mir/util/pretty.rs | 10 ++--- src/libsyntax_pos/hygiene.rs | 2 + src/test/compile-fail/catch-bad-lifetime.rs | 2 - src/test/compile-fail/catch-bad-type.rs | 13 ++++-- .../compile-fail/catch-maybe-bad-lifetime.rs | 4 +- src/test/compile-fail/catch-opt-init.rs | 1 - src/test/run-pass/catch-expr.rs | 25 ++++++----- 11 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b13c289394a7..5bc1bf4431c5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3010,7 +3010,27 @@ impl<'a> LoweringContext<'a> { ) }), ExprKind::Catch(ref body) => { - self.with_catch_scope(body.id, |this| hir::ExprBlock(this.lower_block(body, true))) + self.with_catch_scope(body.id, |this| { + let unstable_span = + this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span); + let mut block = this.lower_block(body, true).into_inner(); + let tail = block.expr.take().map_or_else( + || { + let LoweredNodeId { node_id, hir_id } = this.next_id(); + hir::Expr { + id: node_id, + span: unstable_span, + node: hir::ExprTup(hir_vec![]), + attrs: ThinVec::new(), + hir_id, + } + }, + |x: P| x.into_inner(), + ); + block.expr = Some(this.wrap_in_try_constructor( + "from_ok", tail, unstable_span)); + hir::ExprBlock(P(block)) + }) } ExprKind::Match(ref expr, ref arms) => hir::ExprMatch( P(self.lower_expr(expr)), @@ -3539,12 +3559,8 @@ impl<'a> LoweringContext<'a> { self.expr_call(e.span, from, hir_vec![err_expr]) }; - let from_err_expr = { - let path = &["ops", "Try", "from_error"]; - let from_err = P(self.expr_std_path(unstable_span, path, ThinVec::new())); - P(self.expr_call(e.span, from_err, hir_vec![from_expr])) - }; - + let from_err_expr = + self.wrap_in_try_constructor("from_error", from_expr, unstable_span); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().map(|x| *x); let ret_expr = if let Some(catch_node) = catch_scope { @@ -4079,6 +4095,18 @@ impl<'a> LoweringContext<'a> { ) } } + + fn wrap_in_try_constructor( + &mut self, + method: &'static str, + e: hir::Expr, + unstable_span: Span, + ) -> P { + let path = &["ops", "Try", method]; + let from_err = P(self.expr_std_path(unstable_span, path, + ThinVec::new())); + P(self.expr_call(e.span, from_err, hir_vec![e])) + } } fn body_ids(bodies: &BTreeMap) -> Vec { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 3bb4c86e7c22..4ac678aaa052 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -372,7 +372,8 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { DotFill, - QuestionMark + QuestionMark, + Catch }); impl_stable_hash_for!(enum ::syntax_pos::FileName { diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index dbfb8a6d06e6..942e4fb56cab 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -202,11 +202,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }); // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?; - regioncx.dump_graphviz(&mut file) - }; + regioncx.dump_graphviz(&mut file)?; + }}; } fn dump_annotation<'a, 'gcx, 'tcx>( diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 0fc905443008..3741b8feccc0 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -33,6 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nonzero)] #![feature(inclusive_range_fields)] #![feature(crate_visibility_modifier)] +#![cfg_attr(stage0, feature(try_trait))] extern crate arena; #[macro_use] @@ -54,6 +55,16 @@ extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; +#[cfg(stage0)] +macro_rules! do_catch { + ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() } +} + +#[cfg(not(stage0))] +macro_rules! do_catch { + ($t:expr) => { do catch { $t } } +} + mod diagnostics; mod borrow_check; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 4509cace794d..a891e372ad8b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; writeln!(file, "// MIR for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; @@ -150,16 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( extra_data(PassWhere::BeforeCFG, &mut file)?; write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; - Ok(()) - }; + }}; if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; - Ok(()) - }; + }}; } } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index c180563450f8..8cb5776fdeb0 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -432,6 +432,7 @@ pub enum ExpnFormat { pub enum CompilerDesugaringKind { DotFill, QuestionMark, + Catch, } impl CompilerDesugaringKind { @@ -440,6 +441,7 @@ impl CompilerDesugaringKind { let s = match *self { DotFill => "...", QuestionMark => "?", + Catch => "do catch", }; Symbol::intern(s) } diff --git a/src/test/compile-fail/catch-bad-lifetime.rs b/src/test/compile-fail/catch-bad-lifetime.rs index f24561b8887b..f332ffd44942 100644 --- a/src/test/compile-fail/catch-bad-lifetime.rs +++ b/src/test/compile-fail/catch-bad-lifetime.rs @@ -21,7 +21,6 @@ pub fn main() { //~^ ERROR `my_string` does not live long enough Err(my_str) ?; Err("") ?; - Ok(()) }; } @@ -32,7 +31,6 @@ pub fn main() { let mut j: Result<(), &mut i32> = do catch { Err(k) ?; i = 10; //~ ERROR cannot assign to `i` because it is borrowed - Ok(()) }; ::std::mem::drop(k); //~ ERROR use of moved value: `k` i = 40; //~ ERROR cannot assign to `i` because it is borrowed diff --git a/src/test/compile-fail/catch-bad-type.rs b/src/test/compile-fail/catch-bad-type.rs index cff9f508275b..b369847699bd 100644 --- a/src/test/compile-fail/catch-bad-type.rs +++ b/src/test/compile-fail/catch-bad-type.rs @@ -11,11 +11,18 @@ #![feature(catch_expr)] pub fn main() { - let res: Result = do catch { + let res: Result = do catch { Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied - Ok(5) + 5 }; + let res: Result = do catch { - Ok("") //~ mismatched types + "" //~ ERROR type mismatch }; + + let res: Result = do catch { }; //~ ERROR type mismatch + + let res: () = do catch { }; //~ the trait bound `(): std::ops::Try` is not satisfied + + let res: i32 = do catch { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied } diff --git a/src/test/compile-fail/catch-maybe-bad-lifetime.rs b/src/test/compile-fail/catch-maybe-bad-lifetime.rs index b783a3dd7860..faefb5ef18a3 100644 --- a/src/test/compile-fail/catch-maybe-bad-lifetime.rs +++ b/src/test/compile-fail/catch-maybe-bad-lifetime.rs @@ -17,7 +17,7 @@ pub fn main() { let mut i = 222; let x: Result<&i32, ()> = do catch { Err(())?; - Ok(&i) + &i }; x.ok().cloned(); i = 0; //~ ERROR cannot assign to `i` because it is borrowed @@ -29,7 +29,6 @@ pub fn main() { let _y: Result<(), ()> = do catch { Err(())?; ::std::mem::drop(x); - Ok(()) }; println!("{}", x); //~ ERROR use of moved value: `x` } @@ -42,7 +41,6 @@ pub fn main() { let x: Result<(), ()> = do catch { Err(())?; j = &i; - Ok(()) }; i = 0; //~ ERROR cannot assign to `i` because it is borrowed let _ = i; diff --git a/src/test/compile-fail/catch-opt-init.rs b/src/test/compile-fail/catch-opt-init.rs index 48284b4cb90b..0c41102e3bea 100644 --- a/src/test/compile-fail/catch-opt-init.rs +++ b/src/test/compile-fail/catch-opt-init.rs @@ -19,7 +19,6 @@ pub fn main() { cfg_res = 5; Ok::<(), ()>(())?; use_val(cfg_res); - Ok(()) }; assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable } diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index 310b6ea5bcc6..c23bca7f49e5 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -13,11 +13,11 @@ struct catch {} pub fn main() { - let catch_result = do catch { + let catch_result: Option<_> = do catch { let x = 5; x }; - assert_eq!(catch_result, 5); + assert_eq!(catch_result, Some(5)); let mut catch = true; while catch { catch = false; } @@ -30,16 +30,16 @@ pub fn main() { _ => {} }; - let catch_err = do catch { + let catch_err: Result<_, i32> = do catch { Err(22)?; - Ok(1) + 1 }; assert_eq!(catch_err, Err(22)); let catch_okay: Result = do catch { if false { Err(25)?; } Ok::<(), i32>(())?; - Ok(28) + 28 }; assert_eq!(catch_okay, Ok(28)); @@ -47,14 +47,13 @@ pub fn main() { for i in 0..10 { if i < 5 { Ok::(i)?; } else { Err(i)?; } } - Ok(22) + 22 }; assert_eq!(catch_from_loop, Err(5)); let cfg_init; let _res: Result<(), ()> = do catch { cfg_init = 5; - Ok(()) }; assert_eq!(cfg_init, 5); @@ -62,19 +61,19 @@ pub fn main() { let _res: Result<(), ()> = do catch { cfg_init_2 = 6; Err(())?; - Ok(()) }; assert_eq!(cfg_init_2, 6); let my_string = "test".to_string(); let res: Result<&str, ()> = do catch { - Ok(&my_string) + // Unfortunately, deref doesn't fire here (#49356) + &my_string[..] }; assert_eq!(res, Ok("test")); - do catch { - () - } + let my_opt: Option<_> = do catch { () }; + assert_eq!(my_opt, Some(())); - (); + let my_opt: Option<_> = do catch { }; + assert_eq!(my_opt, Some(())); }