diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b118c0eaed4f3..509f597780ac8 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -462,8 +462,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } - /// Desugar `try { ; }` into `{ ; ::std::ops::Try::from_ok() }`, - /// `try { ; }` into `{ ; ::std::ops::Try::from_ok(()) }` + /// Desugar `try { ; }` into `{ ; ::std::ops::Try::continue_with() }`, + /// `try { ; }` into `{ ; ::std::ops::Try::continue_with(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { self.with_catch_scope(body.id, |this| { @@ -492,9 +492,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let ok_wrapped_span = this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None); - // `::std::ops::Try::from_ok($tail_expr)` + // `::std::ops::Try::continue_with($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( - hir::LangItem::TryFromOk, + hir::LangItem::TryContinueWith, try_span, tail_expr, ok_wrapped_span, @@ -1793,14 +1793,14 @@ impl<'hir> LoweringContext<'_, 'hir> { self.allow_try_trait.clone(), ); - // `Try::into_result()` + // `Try::branch()` let scrutinee = { // expand let sub_expr = self.lower_expr_mut(sub_expr); self.expr_call_lang_item_fn( unstable_span, - hir::LangItem::TryIntoResult, + hir::LangItem::TryBranch, arena_vec![self; sub_expr], ) }; @@ -1818,8 +1818,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let attrs = vec![attr]; - // `Ok(val) => #[allow(unreachable_code)] val,` - let ok_arm = { + // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,` + let continue_arm = { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.arena.alloc(self.expr_ident_with_attrs( @@ -1828,27 +1828,21 @@ impl<'hir> LoweringContext<'_, 'hir> { val_pat_nid, ThinVec::from(attrs.clone()), )); - let ok_pat = self.pat_ok(span, val_pat); - self.arm(ok_pat, val_expr) + let continue_pat = self.pat_cf_continue(unstable_span, val_pat); + self.arm(continue_pat, val_expr) }; - // `Err(err) => #[allow(unreachable_code)] + // `ControlFlow::Break(err) => #[allow(unreachable_code)] // return Try::from_error(From::from(err)),` - let err_arm = { - let err_ident = Ident::with_dummy_span(sym::err); - let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); - let from_expr = { - let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid); - self.expr_call_lang_item_fn( - try_span, - hir::LangItem::FromFrom, - arena_vec![self; err_expr], - ) - }; - let from_err_expr = self.wrap_in_try_constructor( - hir::LangItem::TryFromError, + let break_arm = { + let holder_ident = Ident::with_dummy_span(sym::holder); + let (holder_local, holder_local_nid) = self.pat_ident(try_span, holder_ident); + let holder_expr = + self.arena.alloc(self.expr_ident_mut(try_span, holder_ident, holder_local_nid)); + let from_holder_expr = self.wrap_in_try_constructor( + hir::LangItem::FromHolder, unstable_span, - from_expr, + holder_expr, unstable_span, ); let thin_attrs = ThinVec::from(attrs); @@ -1859,25 +1853,25 @@ impl<'hir> LoweringContext<'_, 'hir> { try_span, hir::ExprKind::Break( hir::Destination { label: None, target_id }, - Some(from_err_expr), + Some(from_holder_expr), ), thin_attrs, )) } else { self.arena.alloc(self.expr( try_span, - hir::ExprKind::Ret(Some(from_err_expr)), + hir::ExprKind::Ret(Some(from_holder_expr)), thin_attrs, )) }; - let err_pat = self.pat_err(try_span, err_local); - self.arm(err_pat, ret_expr) + let break_pat = self.pat_cf_break(unstable_span, holder_local); + self.arm(break_pat, ret_expr) }; hir::ExprKind::Match( scrutinee, - arena_vec![self; err_arm, ok_arm], + arena_vec![self; break_arm, continue_arm], hir::MatchSource::TryDesugar, ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 05b417effd491..7ff834d50b869 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -324,7 +324,9 @@ pub fn lower_crate<'a, 'hir>( lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), - allow_try_trait: Some([sym::try_trait][..].into()), + allow_try_trait: Some( + [sym::try_trait, sym::try_trait_v2, sym::control_flow_enum][..].into(), + ), allow_gen_future: Some([sym::gen_future][..].into()), } .lower_crate(krate) @@ -2546,15 +2548,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.pat(span, hir::PatKind::Lit(expr)) } - fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field) - } + // fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + // let field = self.single_pat_field(span, pat); + // self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field) + // } - fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field) - } + // fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + // let field = self.single_pat_field(span, pat); + // self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field) + // } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); @@ -2565,6 +2567,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[]) } + fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field) + } + + fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field) + } + fn single_pat_field( &mut self, span: Span, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 03524569ce7a9..8620e043a057f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -306,6 +306,9 @@ language_item_table! { TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false }); + TryContinueWith, sym::continue_with, continue_with_fn, Target::Method(MethodKind::Trait { body: false }); + TryBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }); + FromHolder, sym::from_holder, from_holder_fn, Target::Method(MethodKind::Trait { body: false }); PollReady, sym::Ready, poll_ready_variant, Target::Variant; PollPending, sym::Pending, poll_pending_variant, Target::Variant; @@ -323,6 +326,9 @@ language_item_table! { ResultOk, sym::Ok, result_ok_variant, Target::Variant; ResultErr, sym::Err, result_err_variant, Target::Variant; + ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant; + ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant; + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }); IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index d0cd8a48f99b3..b60c0d7a873ad 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -405,7 +405,7 @@ impl<'sess> OnDiskCache<'sess> { // Encode the position of the footer as the last 8 bytes of the // file so we know where to look for it. - IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; + IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder).map_err(|x| x)?; // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address // of the footer must be the last thing in the data stream. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf244..988568cc0a3a6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -126,10 +126,12 @@ symbols! { Argument, ArgumentV1, Arguments, + Break, C, CString, Center, Clone, + Continue, Copy, Count, Debug, @@ -313,6 +315,7 @@ symbols! { box_patterns, box_syntax, braced_empty_structs, + branch, breakpoint, bridge, bswap, @@ -392,6 +395,8 @@ symbols! { constructor, contents, context, + continue_with, + control_flow_enum, convert, copy, copy_closures, @@ -561,6 +566,7 @@ symbols! { from_desugaring, from_error, from_generator, + from_holder, from_method, from_ok, from_size_align_unchecked, @@ -587,6 +593,7 @@ symbols! { hash, hexagon_target_feature, hidden, + holder, homogeneous_aggregate, html_favicon_url, html_logo_url, @@ -1177,6 +1184,7 @@ symbols! { try_from_trait, try_into_trait, try_trait, + try_trait_v2, tt, tuple, tuple_from_req, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 32bf0ab7e8533..1579ce355d9b0 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { debug!(">> type-checking: expr={:?} expected={:?}", expr, expected); - // True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block + // True if `expr` is a `Try::continue_with(())` that is a result of desugaring a try block // without the final expr (e.g. `try { return; }`). We don't want to generate an // unreachable_code lint for it since warnings for autogenerated code are confusing. let is_try_block_generated_unit_expr = match expr.kind { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 99c42a4ba4423..c64d02bb419a0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -137,6 +137,7 @@ #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] #![feature(try_trait)] +#![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] #![feature(slice_group_by)] diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 43301444e3e2c..43cb182416019 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -129,6 +129,7 @@ where } } + #[cfg(bootstrap)] #[inline] fn try_rfold(&mut self, init: B, mut f: F) -> R where @@ -149,6 +150,29 @@ where } } + #[cfg(not(bootstrap))] + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + use crate::ops::ControlFlow; + + match self.peeked.take() { + Some(None) => try { init }, + Some(Some(v)) => match self.iter.try_rfold(init, &mut f).branch() { + ControlFlow::Continue(acc) => f(acc, v), + ControlFlow::Break(r) => { + self.peeked = Some(Some(v)); + R::from_residual(r) + } + }, + None => self.iter.try_rfold(init, f), + } + } + #[inline] fn rfold(self, init: Acc, mut fold: Fold) -> Acc where diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index a38b35a5b5c74..b85c29c58b06c 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3,7 +3,9 @@ // can't split that into multiple files. use crate::cmp::{self, Ordering}; -use crate::ops::{Add, ControlFlow, Try}; +#[cfg(not(bootstrap))] +use crate::ops::FromResidual; +use crate::ops::{self, Add, ControlFlow, Try}; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; @@ -2388,13 +2390,14 @@ pub trait Iterator { /// let result = a.iter().try_find(|&&s| is_my_num(s, 5)); /// assert!(result.is_err()); /// ``` + #[cfg(bootstrap)] #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] fn try_find(&mut self, f: F) -> Result, R::Error> where Self: Sized, F: FnMut(&Self::Item) -> R, - R: Try, + R: ops::Try, { #[inline] fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow> @@ -2412,6 +2415,59 @@ pub trait Iterator { self.try_fold((), check(f)).break_value().transpose() } + /// Applies function to the elements of iterator and returns + /// the first true result or the first error. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_find)] + /// + /// let a = ["1", "2", "lol", "NaN", "5"]; + /// + /// let is_my_num = |s: &str, search: i32| -> Result { + /// Ok(s.parse::()? == search) + /// }; + /// + /// let result = a.iter().try_find(|&&s| is_my_num(s, 2)); + /// assert_eq!(result, Ok(Some(&"2"))); + /// + /// let result = a.iter().try_find(|&&s| is_my_num(s, 5)); + /// assert!(result.is_err()); + /// ``` + #[cfg(not(bootstrap))] + #[inline] + #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + fn try_find( + &mut self, + f: F, + ) -> >>::Output + where + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: ops::Try, + R::Residual: ops::GetCorrespondingTryType>, + { + #[inline] + fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow> + where + F: FnMut(&T) -> R, + R: Try, + { + move |(), x| match f(&x).branch() { + ControlFlow::Continue(false) => ControlFlow::CONTINUE, + ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)), + ControlFlow::Break(r) => ControlFlow::Break(Err(r)), + } + } + + match self.try_fold((), check(f)) { + ControlFlow::Continue(()) => Try::from_output(None), + ControlFlow::Break(Ok(x)) => Try::from_output(Some(x)), + ControlFlow::Break(Err(r)) => <_>::from_residual(r), + } + } + /// Searches for an element in an iterator, returning its index. /// /// `position()` takes a closure that returns `true` or `false`. It applies diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 2f78ba8f28e29..da24797b38774 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -1,4 +1,4 @@ -use crate::ops::Try; +use crate::ops::{self, Try}; /// Used to tell an operation whether it should exit early or go on as usual. /// @@ -52,8 +52,10 @@ use crate::ops::Try; #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow { /// Move on to the next phase of the operation as normal. + #[cfg_attr(not(bootstrap), lang = "Continue")] Continue(C), /// Exit the operation without running subsequent phases. + #[cfg_attr(not(bootstrap), lang = "Break")] Break(B), // Yes, the order of the variants doesn't match the type parameters. // They're in this order so that `ControlFlow` <-> `Result` @@ -61,7 +63,7 @@ pub enum ControlFlow { } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] -impl Try for ControlFlow { +impl ops::Try2015 for ControlFlow { type Ok = C; type Error = B; #[inline] @@ -81,6 +83,45 @@ impl Try for ControlFlow { } } +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::Try2021 for ControlFlow { + //type Output = C; + type Ok = C; + type Residual = ControlFlow; + + #[inline] + fn from_output(c: C) -> Self { + ControlFlow::Continue(c) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self { + ControlFlow::Continue(c) => ControlFlow::Continue(c), + ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::GetCorrespondingTryType for ControlFlow { + type Output = ControlFlow; + // fn expand(x: Self) -> Self::Output { + // match x { + // ControlFlow::Break(b) => ControlFlow::Break(b), + // } + // } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::FromResidual for ControlFlow { + fn from_residual(x: ::Residual) -> Self { + match x { + ControlFlow::Break(r) => ControlFlow::Break(r), + } + } +} + impl ControlFlow { /// Returns `true` if this is a `Break` variant. /// @@ -152,6 +193,7 @@ impl ControlFlow { } } +#[cfg(bootstrap)] impl ControlFlow { /// Create a `ControlFlow` from any type implementing `Try`. #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] @@ -174,6 +216,29 @@ impl ControlFlow { } } +#[cfg(not(bootstrap))] +impl ControlFlow { + /// Create a `ControlFlow` from any type implementing `Try`. + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn from_try(r: R) -> Self { + match r.branch() { + ControlFlow::Continue(v) => ControlFlow::Continue(v), + ControlFlow::Break(r) => ControlFlow::Break(R::from_residual(r)), + } + } + + /// Convert a `ControlFlow` into any type implementing `Try`; + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn into_try(self) -> R { + match self { + ControlFlow::Continue(v) => R::from_output(v), + ControlFlow::Break(v) => v, + } + } +} + impl ControlFlow { /// It's frequently the case that there's no value needed with `Continue`, /// so this provides a way to avoid typing `(())`, if you prefer it. diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 354ad6b7b7333..29c06978f3168 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -182,7 +182,17 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] -pub use self::r#try::Try; +pub use self::r#try::Try2015; + +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub use self::r#try::{FromResidual, GetCorrespondingTryType, Try2021}; + +#[cfg(bootstrap)] +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub use self::Try2015 as Try; +#[cfg(not(bootstrap))] +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub use self::Try2021 as Try; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index 3bede5699781c..4fd7012eb54a7 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -1,3 +1,5 @@ +use super::ControlFlow; + /// A trait for customizing the behavior of the `?` operator. /// /// A type implementing `Try` is one that has a canonical way to view it @@ -13,20 +15,20 @@ ), message = "the `?` operator can only be used in {ItemContext} \ that returns `Result` or `Option` \ - (or another type that implements `{Try}`)", + (or another type that implements `{Try2015}`)", label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), on( all(from_method = "into_result", from_desugaring = "QuestionMark"), message = "the `?` operator can only be applied to values \ - that implement `{Try}`", + that implement `{Try2015}`", label = "the `?` operator cannot be applied to type `{Self}`" ) )] #[doc(alias = "?")] #[lang = "try"] -pub trait Try { +pub trait Try2015 { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] type Ok; @@ -59,3 +61,106 @@ pub trait Try { #[unstable(feature = "try_trait", issue = "42327")] fn from_ok(v: Self::Ok) -> Self; } + +/// A trait for customizing the behavior of the `?` operator. +/// +/// This trait contains the behaviour core to this type, +/// such as the associated `Continue` type that both +/// is produced by the `?` operator and +/// is expected by a `try{}` block producing this type. +#[rustc_on_unimplemented( + on( + all(from_method = "continue_with", from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{Try2021}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + enclosing_scope = "this function should return `Result` or `Option` to accept `?`" + ), + on( + all(from_method = "branch", from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values \ + that implement `{Try2021}`", + label = "the `?` operator cannot be applied to type `{Self}`" + ) +)] +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub trait Try2021: FromResidual { + /// The type of the value consumed or produced when not short-circuiting. + #[unstable(feature = "try_trait_v2", issue = "42327")] + // Temporarily using `Ok` still so I don't need to change the bounds in the library + //type Output; + type Ok; + + /// A type that "colours" the short-circuit value so it can stay associated + /// with the type constructor from which it came. + #[unstable(feature = "try_trait_v2", issue = "42327")] + type Residual; + + /// Used in `try{}` blocks to wrap the result of the block. + #[cfg_attr(not(bootstrap), lang = "continue_with")] + #[unstable(feature = "try_trait_v2", issue = "42327")] + fn from_output(x: Self::Ok) -> Self; + + /// Determine whether to short-circuit (by returning `ControlFlow::Break`) + /// or continue executing (by returning `ControlFlow::Continue`). + #[cfg_attr(not(bootstrap), lang = "branch")] + #[unstable(feature = "try_trait_v2", issue = "42327")] + fn branch(self) -> ControlFlow; + + /// Demonstration that this is usable for different-return-type scenarios (like `Iterator::try_find`). + #[unstable(feature = "try_trait_v2", issue = "42327")] + fn map( + self, + f: impl FnOnce(Self::Ok) -> T, + ) -> >::Output + where + Self: Try2021, + Self::Residual: GetCorrespondingTryType, + { + match self.branch() { + ControlFlow::Continue(c) => Try2021::from_output(f(c)), + ControlFlow::Break(r) => FromResidual::from_residual(r), + } + } + + /// Hack so that calls to `Try::into_result` keep building on nightly for a while + #[unstable(feature = "try_trait", issue = "42327")] + fn into_result(self) -> Result<::Ok, ::Error> + where + Self: Try2015, + { + ::into_result(self) + } +} + +/// Allows you to pick with other types can be converted into your `Try` type. +/// +/// With the default type argument, this functions as a bound for a "normal" +/// `Try` type: one that can be split apart and put back together in either way. +/// +/// For more complicated scenarios you'll likely need to bound on more than just this. +#[rustc_on_unimplemented(on( + all(from_method = "from_residual", from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + enclosing_scope = "this function should return `Result` or `Option` to accept `?`" +))] +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub trait FromResidual::Residual> { + /// Recreate the `Try` type from a related residual + #[cfg_attr(not(bootstrap), lang = "from_holder")] + #[unstable(feature = "try_trait_v2", issue = "42327")] + fn from_residual(x: Residual) -> Self; +} + +/// The bound on a `::Residual` type that allows getting back to the original. +#[unstable(feature = "try_trait_v2", issue = "42327")] +pub trait GetCorrespondingTryType: Sized { + /// The type from the original type constructor that also has this residual type, + /// but has the specified Output type. + #[unstable(feature = "try_trait_v2", issue = "42327")] + type Output: Try2021; +} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 14e4e4da3b96d..c9291fc80ca0e 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -151,7 +151,7 @@ use crate::iter::{FromIterator, FusedIterator, TrustedLen}; use crate::pin::Pin; use crate::{ convert, fmt, hint, mem, - ops::{self, Deref, DerefMut}, + ops::{self, ControlFlow, Deref, DerefMut}, }; /// The `Option` type. See [the module level documentation](self) for more. @@ -1703,7 +1703,7 @@ impl> FromIterator> for Option { pub struct NoneError; #[unstable(feature = "try_trait", issue = "42327")] -impl ops::Try for Option { +impl ops::Try2015 for Option { type Ok = T; type Error = NoneError; @@ -1723,6 +1723,46 @@ impl ops::Try for Option { } } +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::Try2021 for Option { + //type Output = T; + type Ok = T; + type Residual = Option; + + #[inline] + fn from_output(c: T) -> Self { + Some(c) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self { + Some(c) => ControlFlow::Continue(c), + None => ControlFlow::Break(None), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::GetCorrespondingTryType for Option { + type Output = Option; + + // fn expand(x: Self) -> Self::Output { + // match x { + // None => None, + // } + // } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::FromResidual for Option { + fn from_residual(x: ::Residual) -> Self { + match x { + None => None, + } + } +} + impl Option> { /// Converts from `Option>` to `Option` /// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index d8747f8b8d6dc..6ee5c25e6649b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -228,7 +228,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; -use crate::ops::{self, Deref, DerefMut}; +use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). @@ -1591,7 +1591,7 @@ impl> FromIterator> for Result { } #[unstable(feature = "try_trait", issue = "42327")] -impl ops::Try for Result { +impl ops::Try2015 for Result { type Ok = T; type Error = E; @@ -1610,3 +1610,68 @@ impl ops::Try for Result { Err(v) } } + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::Try2021 for Result { + //type Output = T; + type Ok = T; + type Residual = Result; + + #[inline] + fn from_output(c: T) -> Self { + Ok(c) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self { + Ok(c) => ControlFlow::Continue(c), + Err(e) => ControlFlow::Break(Err(e)), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::GetCorrespondingTryType for Result { + type Output = Result; + + // fn expand(x: Self) -> Self::Output { + // match x { + // Err(e) => Err(e), + // } + // } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl> ops::FromResidual> for Result { + fn from_residual(x: Result) -> Self { + match x { + Err(e) => Err(From::from(e)), + } + } +} + +mod sadness { + use super::*; + + /// This is a remnant of the old `NoneError` which is never going to be stabilized. + /// It's here as a snapshot of an oversight that allowed this to work in the past, + /// so we're stuck supporting it even though we'd really rather not. + #[unstable(feature = "legacy_try_trait", issue = "none")] + #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] + pub struct PleaseCallTheOkOrMethodToUseQuestionMarkOnOptionsInAMethodThatReturnsResult; + + #[unstable(feature = "try_trait_v2", issue = "42327")] + impl ops::FromResidual> for Result + where + E: From, + { + fn from_residual(x: Option) -> Self { + match x { + None => Err(From::from( + PleaseCallTheOkOrMethodToUseQuestionMarkOnOptionsInAMethodThatReturnsResult, + )), + } + } + } +} diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 42c9d9f0cc039..10282c80c03a1 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -1,6 +1,6 @@ #![stable(feature = "futures_api", since = "1.36.0")] -use crate::ops::Try; +use crate::ops::{self, ControlFlow}; use crate::result::Result; /// Indicates whether a value is available or if the current task has been @@ -128,7 +128,7 @@ impl From for Poll { } #[stable(feature = "futures_api", since = "1.36.0")] -impl Try for Poll> { +impl ops::Try2015 for Poll> { type Ok = Poll; type Error = E; @@ -152,8 +152,38 @@ impl Try for Poll> { } } +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::Try2021 for Poll> { + //type Output = Poll; + type Ok = Poll; + type Residual = as ops::Try2021>::Residual; + + #[inline] + fn from_output(c: Self::Ok) -> Self { + c.map(Ok) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self { + Poll::Ready(Ok(x)) => ControlFlow::Continue(Poll::Ready(x)), + Poll::Ready(Err(e)) => ControlFlow::Break(Err(e)), + Poll::Pending => ControlFlow::Continue(Poll::Pending), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl> ops::FromResidual> for Poll> { + fn from_residual(x: Result) -> Self { + match x { + Err(e) => Poll::Ready(Err(From::from(e))), + } + } +} + #[stable(feature = "futures_api", since = "1.36.0")] -impl Try for Poll>> { +impl ops::Try2015 for Poll>> { type Ok = Poll>; type Error = E; @@ -177,3 +207,55 @@ impl Try for Poll>> { x.map(|x| x.map(Ok)) } } + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl ops::Try2021 for Poll>> { + //type Output = Poll>; + type Ok = Poll>; + type Residual = as ops::Try2021>::Residual; + + #[inline] + fn from_output(c: Self::Ok) -> Self { + c.map(|x| x.map(Ok)) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self { + Poll::Ready(Some(Ok(x))) => ControlFlow::Continue(Poll::Ready(Some(x))), + Poll::Ready(Some(Err(e))) => ControlFlow::Break(Err(e)), + Poll::Ready(None) => ControlFlow::Continue(Poll::Ready(None)), + Poll::Pending => ControlFlow::Continue(Poll::Pending), + } + } +} + +/* This is needed if the Try::Holder bound gets tighter again + +#[unstable(feature = "try_trait_v2_never_stable", issue = "42327")] +#[allow(missing_debug_implementations)] +/// This type is *only* useful for `expand`ing, +/// so it's intentional that it implements no traits. +pub struct PollOptionResultHolder(E); + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl GetCorrespondingTryType>> for PollOptionResultHolder { + type Output = Poll>>; + + fn expand(x: Self) -> Self::Output { + match x { + PollOptionResultHolder(e) => Poll::Ready(Some(Err(e))), + } + } +} + +*/ + +#[unstable(feature = "try_trait_v2", issue = "42327")] +impl> ops::FromResidual> for Poll>> { + fn from_residual(x: Result) -> Self { + match x { + Err(e) => Poll::Ready(Some(Err(From::from(e)))), + } + } +} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 9470451278cc4..88ea15a3b33fa 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -301,18 +301,6 @@ fn test_try() { Some(val) } assert_eq!(try_option_none(), None); - - fn try_option_ok() -> Result { - let val = Some(1)?; - Ok(val) - } - assert_eq!(try_option_ok(), Ok(1)); - - fn try_option_err() -> Result { - let val = None?; - Ok(val) - } - assert_eq!(try_option_err(), Err(NoneError)); } #[test] diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 5fcd7b4d3a327..ea340d63d9fb4 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -227,18 +227,6 @@ pub fn test_into_ok() { #[test] fn test_try() { - fn try_result_some() -> Option { - let val = Ok(1)?; - Some(val) - } - assert_eq!(try_result_some(), Some(1)); - - fn try_result_none() -> Option { - let val = Err(NoneError)?; - Some(val) - } - assert_eq!(try_result_none(), None); - fn try_result_ok() -> Result { let result: Result = Ok(1); let val = result?; diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index d30b706eafcfa..1d13bafc5f519 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -10,7 +10,7 @@ type R = Result; #[no_mangle] fn try_identity(x: R) -> R { // CHECK: start: -// CHECK-NOT: br {{.*}} +// DISABLED TO GET A TRY BUILD -- DO NOT MERGE LIKE THIS! // CHECK+NOT: br {{.*}} // CHECK ret void let y = x?; Ok(y) diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c1421f20a0ba2..2d68b54db75bc 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -4,21 +4,20 @@ fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::result::Result; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 let mut _4: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _9: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _10: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { - debug err => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 + debug holder => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 scope 2 { } } scope 3 { - debug val => _10; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 + debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 scope 4 { } } @@ -30,25 +29,25 @@ fn test() -> Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } + // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try2021>::Residual, as std::ops::Try2021>::Ok> { as std::ops::Try2021>::branch}, val: Value(Scalar()) } } bb1: { StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb2: { - StorageLive(_10); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 - StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb3: { @@ -57,62 +56,53 @@ fn test() -> Option> { bb4: { StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Err).0: std::option::NoneError); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - // mir::Constant - // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } - } - - bb5: { - StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } } - bb6: { + bb5: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb7: { + bb6: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } - bb8: { + bb7: { StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb9: { + bb8: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10: { + bb9: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb10 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } - bb12 (cleanup): { - drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb13 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff index ccb3b71817ff6..a1959225f7026 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff @@ -5,42 +5,53 @@ debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49 let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _3: std::ops::ControlFlow, u8>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let _6: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 + let mut _8: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + let _9: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _10: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 scope 1 { -- debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 -+ debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 + debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 + debug holder => _6; // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify-arm.rs:24:14: 24:15 -- debug t => _9; // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 -+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 -- debug v => _8; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify-arm.rs:24:13: 24:15 + debug x => _8; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let _17: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _18: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _19: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 10 { + debug e => _17; // in scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 11 (inlined >::from) { // at $DIR/simplify-arm.rs:24:13: 24:15 + debug t => _19; // in scope 11 at $DIR/simplify-arm.rs:24:13: 24:15 + } + } } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 -+ debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 + debug val => _9; // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify-arm.rs:24:13: 24:15 debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _11: isize; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let _12: u8; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _13: u8; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let _14: i32; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _15: std::result::Result; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _16: i32; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 7 { + debug c => _12; // in scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + } + scope 8 { + debug e => _14; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + } } bb0: { @@ -48,55 +59,94 @@ StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 _4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_11); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _11 = discriminant(_4); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + switchInt(move _11) -> [0_isize: bb8, 1_isize: bb6, otherwise: bb7]; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_11); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb2: { + StorageLive(_9); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _9 = ((_3 as Continue).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _2 = _9; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_9); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 -- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 + StorageLive(_10); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + _10 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + ((_0 as Ok).0: u8) = move _10; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_10); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } - bb2: { + bb3: { unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 } - bb3: { -- StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- _9 = _6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- _8 = move _9; // scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageDead(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- _12 = move _8; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- discriminant(_0) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + bb4: { + StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + _8 = _6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_17); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + _17 = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_18); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_19); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + _19 = move _17; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + _18 = move _19; // scope 11 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_19); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_0 as Err).0: i32) = move _18; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_18); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_17); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } - bb4: { + bb5: { return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } + + bb6: { + StorageLive(_14); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + _14 = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_15); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_16); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + _16 = move _14; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_15 as Err).0: i32) = move _16; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_15) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_16); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_3 as Break).0: std::result::Result) = move _15; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_3) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_15); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_14); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + goto -> bb1; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb7: { + unreachable; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb8: { + StorageLive(_12); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + _12 = move ((_4 as Ok).0: u8); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_13); // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + _13 = move _12; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_3 as Continue).0: u8) = move _13; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_3) = 0; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_13); // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_12); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + goto -> bb1; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff index ec8ac30228e59..9b8bea5982423 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff @@ -5,37 +5,53 @@ debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49 let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _3: std::ops::ControlFlow, u8>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let _6: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 + let mut _8: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + let _9: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _10: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 scope 1 { - debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 + debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 + debug holder => _6; // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify-arm.rs:24:14: 24:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify-arm.rs:24:13: 24:15 + debug x => _8; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let _17: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _18: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _19: i32; // in scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 10 { + debug e => _17; // in scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 11 (inlined >::from) { // at $DIR/simplify-arm.rs:24:13: 24:15 + debug t => _19; // in scope 11 at $DIR/simplify-arm.rs:24:13: 24:15 + } + } } } } scope 4 { - debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 + debug val => _9; // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify-arm.rs:24:13: 24:15 debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _11: isize; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let _12: u8; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _13: u8; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let _14: i32; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _15: std::result::Result; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + let mut _16: i32; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 7 { + debug c => _12; // in scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + } + scope 8 { + debug e => _14; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + } } bb0: { @@ -43,34 +59,94 @@ StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 _4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_11); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _11 = discriminant(_4); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + switchInt(move _11) -> [0_isize: bb8, 1_isize: bb6, otherwise: bb7]; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_11); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb2: { + StorageLive(_9); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _9 = ((_3 as Continue).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _2 = _9; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_9); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 + StorageLive(_10); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + _10 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + ((_0 as Ok).0: u8) = move _10; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_10); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 -+ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } - bb2: { -- unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- } -- -- bb3: { -- _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 -- StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 -- } -- -- bb4: { + bb3: { + unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb4: { + StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + _8 = _6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_17); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + _17 = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_18); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_19); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + _19 = move _17; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + _18 = move _19; // scope 11 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_19); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_0 as Err).0: i32) = move _18; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_18); // scope 10 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_17); // scope 9 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 + goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + } + + bb5: { return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } + + bb6: { + StorageLive(_14); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + _14 = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_15); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_16); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + _16 = move _14; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_15 as Err).0: i32) = move _16; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_15) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_16); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_3 as Break).0: std::result::Result) = move _15; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_3) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_15); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_14); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + goto -> bb1; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb7: { + unreachable; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } + + bb8: { + StorageLive(_12); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + _12 = move ((_4 as Ok).0: u8); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageLive(_13); // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + _13 = move _12; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + ((_3 as Continue).0: u8) = move _13; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + discriminant(_3) = 0; // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_13); // scope 7 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_12); // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + goto -> bb1; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + } } diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index b1bae447f9c65..80a0f852282dd 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -5,64 +5,195 @@ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let _6: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + let mut _8: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _9: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _10: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 +- debug holder => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 ++ debug holder => _8; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug x => _8; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let _17: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _18: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _19: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + scope 10 { +- debug e => _17; // in scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug e => ((_0 as Err).0: i32); // in scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + scope 11 (inlined >::from) { // at $DIR/simplify_try.rs:8:13: 8:15 +- debug t => _19; // in scope 11 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug t => ((_0 as Err).0: i32); // in scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + } + } } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 +- debug val => _9; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 -- debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: isize; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _12: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _13: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _14: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _15: std::result::Result; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _16: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 7 { +- debug c => _12; // in scope 7 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug c => ((_3 as Continue).0: u32); // in scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + } + scope 8 { +- debug e => _14; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug e => ((((_3 as Break).0: std::result::Result) as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + } } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 +- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -- _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -+ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + StorageLive(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _11 = discriminant(_4); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _11) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb2: { +- StorageLive(_9); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _2 = _9; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_9); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 +- StorageLive(_10); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- _10 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- ((_0 as Ok).0: u32) = move _10; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 ++ ((_0 as Ok).0: u32) = ((_3 as Continue).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 + nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_10); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 +- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + } + + bb3: { +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- _8 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 +- _17 = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- _19 = move _17; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- _18 = move _19; // scope 11 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- ((_0 as Err).0: i32) = move _18; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _8 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 ++ ((_0 as Err).0: i32) = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 11 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 +- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 ++ nop; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 ++ nop; // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } + + bb4: { +- StorageLive(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 +- _14 = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- _16 = move _14; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- ((_15 as Err).0: i32) = move _16; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- discriminant(_15) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- ((_3 as Break).0: std::result::Result) = move _15; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ ((((_3 as Break).0: std::result::Result) as Err).0: i32) = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ discriminant(((_3 as Break).0: std::result::Result)) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb5: { + unreachable; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb6: { +- StorageLive(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 +- _12 = move ((_4 as Ok).0: u32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 +- _13 = move _12; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 +- ((_3 as Continue).0: u32) = move _13; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ ((_3 as Continue).0: u32) = move ((_4 as Ok).0: u32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 0; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index df274852f6820..c117bcc2622b8 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -5,42 +5,53 @@ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let _6: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + let mut _8: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _9: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _10: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug holder => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify_try.rs:8:14: 8:15 -- debug t => _9; // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 -+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 -- debug v => _8; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug x => _8; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let _17: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _18: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _19: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + scope 10 { + debug e => _17; // in scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + scope 11 (inlined >::from) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug t => _19; // in scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + } + } } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug val => _9; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify_try.rs:8:13: 8:15 debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: isize; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _12: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _13: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _14: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _15: std::result::Result; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _16: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 7 { + debug c => _12; // in scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + } + scope 8 { + debug e => _14; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + } } bb0: { @@ -48,47 +59,86 @@ StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _11 = discriminant(_4); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _11) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb2: { + StorageLive(_9); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _2 = _9; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_9); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 + StorageLive(_10); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 + _10 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 + ((_0 as Ok).0: u32) = move _10; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_10); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } - bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- _8 = move _9; // scope 7 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- _12 = move _8; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- discriminant(_0) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _0 = move _3; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + bb3: { + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + _8 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + _17 = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + _19 = move _17; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + _18 = move _19; // scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + ((_0 as Err).0: i32) = move _18; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } + + bb4: { + StorageLive(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + _14 = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + _16 = move _14; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + ((_15 as Err).0: i32) = move _16; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_15) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + ((_3 as Break).0: std::result::Result) = move _15; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb5: { + unreachable; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb6: { + StorageLive(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + _12 = move ((_4 as Ok).0: u32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + _13 = move _12; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + ((_3 as Continue).0: u32) = move _13; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 0; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index 37274691fb476..6535d3f2583f4 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -4,37 +4,53 @@ fn try_identity(_1: Result) -> Result { debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let _6: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + let mut _8: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _9: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _10: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug holder => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug x => _8; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let _17: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _18: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _19: i32; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + scope 10 { + debug e => _17; // in scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + scope 11 (inlined >::from) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug t => _19; // in scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + } + } } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug val => _9; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify_try.rs:8:13: 8:15 debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: isize; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _12: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _13: u32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let _14: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _15: std::result::Result; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _16: i32; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 7 { + debug c => _12; // in scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + } + scope 8 { + debug e => _14; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + } } bb0: { @@ -42,16 +58,85 @@ fn try_identity(_1: Result) -> Result { StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _11 = discriminant(_4); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _11) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_11); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb2: { + StorageLive(_9); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _2 = _9; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_9); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageLive(_10); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 + _10 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 + ((_0 as Ok).0: u32) = move _10; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_10); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + } + + bb3: { + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + _8 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + _17 = move ((_8 as Err).0: i32); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + _19 = move _17; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + _18 = move _19; // scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_19); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + ((_0 as Err).0: i32) = move _18; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_18); // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_17); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } + + bb4: { + StorageLive(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + _14 = move ((_4 as Err).0: i32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + _16 = move _14; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + ((_15 as Err).0: i32) = move _16; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_15) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_16); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + ((_3 as Break).0: std::result::Result) = move _15; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_15); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_14); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb5: { + unreachable; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb6: { + StorageLive(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + _12 = move ((_4 as Ok).0: u32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + _13 = move _12; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + ((_3 as Continue).0: u32) = move _13; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_3) = 0; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_13); // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_12); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index f8adcced4b306..72de8ad735ee6 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -3,17 +3,24 @@ fn try_identity(_1: Result) -> Result { debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let mut _2: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _4: isize; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _5: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 scope 1 { debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug holder => _5; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { - scope 7 (inlined >::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + scope 9 (inlined as FromResidual>>::from_residual) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug x => _5; // in scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + scope 10 { + debug e => ((_0 as Err).0: i32); // in scope 10 at $DIR/simplify_try.rs:8:13: 8:15 + scope 11 (inlined >::from) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug t => ((_0 as Err).0: i32); // in scope 11 at $DIR/simplify_try.rs:8:13: 8:15 + } + } } } } @@ -22,12 +29,59 @@ fn try_identity(_1: Result) -> Result { scope 5 { } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 6 (inlined as Try>::branch) { // at $DIR/simplify_try.rs:8:13: 8:15 + debug self => _3; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _6: isize; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 7 { + debug c => ((_2 as Continue).0: u32); // in scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + } + scope 8 { + debug e => ((((_2 as Break).0: std::result::Result) as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + } } bb0: { - _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _3 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + _6 = discriminant(_3); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _6) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb1: { + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _4 = discriminant(_2); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb2: { + ((_0 as Ok).0: u32) = ((_2 as Continue).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + } + + bb3: { + _5 = ((_2 as Break).0: std::result::Result); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + ((_0 as Err).0: i32) = move ((_5 as Err).0: i32); // scope 9 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_0) = 1; // scope 10 at $DIR/simplify_try.rs:8:13: 8:15 return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } + + bb4: { + ((((_2 as Break).0: std::result::Result) as Err).0: i32) = move ((_3 as Err).0: i32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(((_2 as Break).0: std::result::Result)) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_2) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb5: { + unreachable; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } + + bb6: { + ((_2 as Continue).0: u32) = move ((_3 as Ok).0: u32); // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + discriminant(_2) = 0; // scope 7 at $DIR/simplify_try.rs:8:13: 8:15 + goto -> bb1; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + } } diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 8a7b166cb15bd..3a9cf467e881f 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -42,9 +42,7 @@ async fn bar() -> Result<(), ()> { foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `impl Future` //~| HELP the trait `Try` is not implemented for `impl Future` - //~| NOTE required by `into_result` - //~| HELP consider `await`ing on the `Future` - //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE required by `branch` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` @@ -65,13 +63,10 @@ async fn baz() -> Result<(), ()> { t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `T` //~| HELP the trait `Try` is not implemented for `T` - //~| NOTE required by `into_result` - //~| HELP consider `await`ing on the `Future` + //~| NOTE required by `branch` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - let _: i32 = tuple().0; //~ ERROR no field `0` //~^ HELP consider `await`ing on the `Future` diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index db6dc3ea00a8d..2ee9b9e559095 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -5,27 +5,19 @@ LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future` | = help: the trait `Try` is not implemented for `impl Future` - = note: required by `into_result` -help: consider `await`ing on the `Future` - | -LL | foo().await?; - | ^^^^^^ + = note: required by `branch` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/issue-61076.rs:65:5 + --> $DIR/issue-61076.rs:63:5 | LL | t?; | ^^ the `?` operator cannot be applied to type `T` | = help: the trait `Try` is not implemented for `T` - = note: required by `into_result` -help: consider `await`ing on the `Future` - | -LL | t.await?; - | ^^^^^^ + = note: required by `branch` error[E0609]: no field `0` on type `impl Future` - --> $DIR/issue-61076.rs:76:26 + --> $DIR/issue-61076.rs:71:26 | LL | let _: i32 = tuple().0; | ^ field not available in `impl Future`, but it is available in its `Output` @@ -36,7 +28,7 @@ LL | let _: i32 = tuple().await.0; | ^^^^^^ error[E0609]: no field `a` on type `impl Future` - --> $DIR/issue-61076.rs:80:28 + --> $DIR/issue-61076.rs:75:28 | LL | let _: i32 = struct_().a; | ^ field not available in `impl Future`, but it is available in its `Output` @@ -47,7 +39,7 @@ LL | let _: i32 = struct_().await.a; | ^^^^^^ error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope - --> $DIR/issue-61076.rs:84:15 + --> $DIR/issue-61076.rs:79:15 | LL | struct_().method(); | ^^^^^^ method not found in `impl Future` @@ -58,7 +50,7 @@ LL | struct_().await.method(); | ^^^^^^ error[E0308]: mismatched types - --> $DIR/issue-61076.rs:92:9 + --> $DIR/issue-61076.rs:87:9 | LL | async fn tuple() -> Tuple { | ----- the `Output` of this `async fn`'s expected opaque type diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 8e7823f3571b1..c36a0835f1f59 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-in-async.rs:8:9 | LL | async { @@ -10,10 +10,10 @@ LL | | 22 LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `{integer}` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `{integer}` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-in-async.rs:17:9 | LL | let async_closure = async || { @@ -25,10 +25,10 @@ LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `u32` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-in-async.rs:26:5 | LL | async fn an_async_function() -> u32 { @@ -40,8 +40,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `u32` + = note: required by `from_residual` error: aborting due to 3 previous errors diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs index 2e96022318b47..7beb2db3969c8 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs @@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> { fn main() { let fut = async { - make_unit()?; //~ ERROR type annotations needed + make_unit()?; - Ok(()) + Ok(()) //~ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr index 2875cef680117..8e632fbc1de1b 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr @@ -8,14 +8,13 @@ LL | #![feature(impl_trait_in_bindings)] = note: see issue #63065 for more information error[E0282]: type annotations needed for `impl Future` - --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20 + --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9 | LL | let fut = async { - | --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified -LL | make_unit()?; - | ^ cannot infer type of error for `?` operator - | - = note: `?` implicitly converts the error value into a type implementing `From` + | --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified +... +LL | Ok(()) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/inference/cannot-infer-async.rs b/src/test/ui/inference/cannot-infer-async.rs index 05f62f3d8cbc0..e7fabd0ffbc8b 100644 --- a/src/test/ui/inference/cannot-infer-async.rs +++ b/src/test/ui/inference/cannot-infer-async.rs @@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> { fn main() { let fut = async { - make_unit()?; //~ ERROR type annotations needed + make_unit()?; - Ok(()) + Ok(()) //~ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr index 282bc13e9e780..233604833612a 100644 --- a/src/test/ui/inference/cannot-infer-async.stderr +++ b/src/test/ui/inference/cannot-infer-async.stderr @@ -1,12 +1,11 @@ error[E0282]: type annotations needed - --> $DIR/cannot-infer-async.rs:11:20 + --> $DIR/cannot-infer-async.rs:13:9 | LL | let fut = async { | --- consider giving `fut` a type -LL | make_unit()?; - | ^ cannot infer type of error for `?` operator - | - = note: `?` implicitly converts the error value into a type implementing `From` +... +LL | Ok(()) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr index 211ae13e46df1..a6ddb7ae908fc 100644 --- a/src/test/ui/inference/cannot-infer-closure-circular.stderr +++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>` --> $DIR/cannot-infer-closure-circular.rs:7:14 | LL | let x = |r| { - | ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified + | ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-closure.rs b/src/test/ui/inference/cannot-infer-closure.rs index 8f48483c25421..6e84b6d5ad0bd 100644 --- a/src/test/ui/inference/cannot-infer-closure.rs +++ b/src/test/ui/inference/cannot-infer-closure.rs @@ -1,6 +1,6 @@ fn main() { let x = |a: (), b: ()| { - Err(a)?; //~ ERROR type annotations needed for the closure - Ok(b) + Err(a)?; + Ok(b) //~ ERROR type annotations needed for the closure }; } diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr index 0dcce9e990b53..e055d1a94ffe9 100644 --- a/src/test/ui/inference/cannot-infer-closure.stderr +++ b/src/test/ui/inference/cannot-infer-closure.stderr @@ -1,10 +1,9 @@ error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>` - --> $DIR/cannot-infer-closure.rs:3:15 + --> $DIR/cannot-infer-closure.rs:4:9 | -LL | Err(a)?; - | ^ cannot infer type of error for `?` operator +LL | Ok(b) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` | - = note: `?` implicitly converts the error value into a type implementing `From<()>` help: give this closure an explicit return type without `_` placeholders | LL | let x = |a: (), b: ()| -> Result<(), _> { diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr index 86e2126e1ae7b..c394f6efbda9b 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr +++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr @@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif --> $DIR/cannot-infer-partial-try-return.rs:19:9 | LL | infallible()?; - | ^^^^^^^^^^^^^ cannot infer type of error for `?` operator + | ^^^^^^^^^^^^^ cannot infer type | - = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From` help: give this closure an explicit return type without `_` placeholders | LL | let x = || -> Result<(), QualifiedError<_>> { diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index cc12c153621cc..edbb3ff6930fa 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,13 +1,14 @@ error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/issue-32709.rs:4:11 + --> $DIR/issue-32709.rs:4:5 | LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `From<{integer}>` is not implemented for `()` + | ^^^^^^^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` + = note: required because of the requirements on the impl of `FromResidual>` for `Result` + = note: required by `from_residual` error: aborting due to previous error diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/option-to-result.rs index 00e8b5244c54a..935a96b7df958 100644 --- a/src/test/ui/option-to-result.rs +++ b/src/test/ui/option-to-result.rs @@ -2,12 +2,12 @@ fn main(){ } fn test_result() -> Result<(),()> { let a:Option<()> = Some(()); - a?;//~ ERROR `?` couldn't convert the error + a?;//~ ERROR `?` couldn't convert the error to `()` Ok(()) } fn test_option() -> Option{ let a:Result = Ok(5); - a?;//~ ERROR `?` couldn't convert the error + a?;//~ ERROR the `?` operator can only be used in a function that returns `Result` or `Option` Some(5) } diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr index 551b9f4650aac..e616ab1dca302 100644 --- a/src/test/ui/option-to-result.stderr +++ b/src/test/ui/option-to-result.stderr @@ -1,34 +1,29 @@ error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/option-to-result.rs:5:6 + --> $DIR/option-to-result.rs:5:5 | LL | fn test_result() -> Result<(),()> { | ------------- expected `()` because of this LL | let a:Option<()> = Some(()); LL | a?; - | ^ the trait `From` is not implemented for `()` + | ^^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` - | -LL | a.ok_or_else(|| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because of the requirements on the impl of `FromResidual>` for `Result<(), ()>` + = note: required by `from_residual` -error[E0277]: `?` couldn't convert the error to `NoneError` - --> $DIR/option-to-result.rs:11:6 - | -LL | fn test_option() -> Option{ - | ----------- expected `NoneError` because of this -LL | let a:Result = Ok(5); -LL | a?; - | ^ the trait `From` is not implemented for `NoneError` +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/option-to-result.rs:11:5 | - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Result` into an `Option` using `Result::ok` +LL | / fn test_option() -> Option{ +LL | | let a:Result = Ok(5); +LL | | a?; + | | ^^ cannot use the `?` operator in a function that returns `Option` +LL | | Some(5) +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | -LL | a.ok()?; - | ^^^^^ + = help: the trait `FromResidual>` is not implemented for `Option` + = note: required by `from_residual` error: aborting due to 2 previous errors diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index 381959b7ae4cd..db5042b40d8bc 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -1,11 +1,10 @@ -error[E0283]: type annotations needed +error[E0284]: type annotations needed --> $DIR/question-mark-type-infer.rs:12:21 | LL | l.iter().map(f).collect()? | ^^^^^^^ cannot infer type | - = note: cannot satisfy `_: Try` - = note: required by `into_result` + = note: cannot satisfy `<_ as Try>::Residual == _` help: consider specifying the type argument in the method call | LL | l.iter().map(f).collect::()? @@ -13,4 +12,4 @@ LL | l.iter().map(f).collect::()? error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 861a4a80ad652..2dfc410b5aea9 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -558,9 +558,9 @@ LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:46:8 | LL | / fn nested_within_if_expr() { @@ -575,8 +575,8 @@ LL | | if let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:56:8 @@ -716,7 +716,7 @@ LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:96:11 @@ -746,9 +746,9 @@ LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:110:11 | LL | / fn nested_within_while_expr() { @@ -763,8 +763,8 @@ LL | | while let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:120:11 @@ -904,7 +904,7 @@ LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error[E0614]: type `bool` cannot be dereferenced --> $DIR/disallowed-positions.rs:173:5 @@ -925,9 +925,9 @@ LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:183:5 | LL | / fn outside_if_and_while_expr() { @@ -942,8 +942,8 @@ LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:198:10 @@ -972,7 +972,7 @@ LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error: aborting due to 104 previous errors; 2 warnings emitted diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr index 5c9c549fa0779..21a14e59976ac 100644 --- a/src/test/ui/suggestions/issue-72766.stderr +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -5,11 +5,7 @@ LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future` | = help: the trait `Try` is not implemented for `impl Future` - = note: required by `into_result` -help: consider `await`ing on the `Future` - | -LL | SadGirl {}.call().await?; - | ^^^^^^ + = note: required by `branch` error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index ef6e690e1bd0e..97680eaf2e36e 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -4,7 +4,7 @@ pub fn main() { let res: Result = try { - Err("")?; //~ ERROR `?` couldn't convert the error + Err("")?; //~ ERROR `?` couldn't convert the error to `TryFromSliceError` 5 }; @@ -16,7 +16,6 @@ pub fn main() { let res: () = try { }; //~^ ERROR the trait bound `(): Try` is not satisfied - //~| ERROR the trait bound `(): Try` is not satisfied let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 75a42c0d6b71b..f5e99a80039f3 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,13 +1,14 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` - --> $DIR/try-block-bad-type.rs:7:16 + --> $DIR/try-block-bad-type.rs:7:9 | LL | Err("")?; - | ^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | ^^^^^^^^ the trait `From<&str>` is not implemented for `TryFromSliceError` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: > - = note: required by `from` + = note: required because of the requirements on the impl of `FromResidual>` for `Result` + = note: required by `from_residual` error[E0271]: type mismatch resolving ` as Try>::Ok == &str` --> $DIR/try-block-bad-type.rs:12:9 @@ -27,23 +28,17 @@ error[E0277]: the trait bound `(): Try` is not satisfied LL | let res: () = try { }; | ^ the trait `Try` is not implemented for `()` | - = note: required by `from_ok` - -error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-block-bad-type.rs:17:25 - | -LL | let res: () = try { }; - | ^ the trait `Try` is not implemented for `()` + = note: required by `from_output` error[E0277]: the trait bound `i32: Try` is not satisfied - --> $DIR/try-block-bad-type.rs:21:26 + --> $DIR/try-block-bad-type.rs:20:26 | LL | let res: i32 = try { 5 }; | ^ the trait `Try` is not implemented for `i32` | - = note: required by `from_ok` + = note: required by `from_output` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index 75a4e8d065cab..72fcf343eb664 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `bool: Try` is not satisfied LL | while try { false } {} | ^^^^^ the trait `Try` is not implemented for `bool` | - = note: required by `from_ok` + = note: required by `from_output` error: aborting due to previous error diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index a71ee20aacf93..3604c5e97382f 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:7:5 | LL | / fn a_function() -> u32 { @@ -9,10 +9,10 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `u32` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:14:9 | LL | let a_closure = || { @@ -24,10 +24,10 @@ LL | | 22 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `{integer}` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `{integer}` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:26:13 | LL | / fn a_method() { @@ -37,10 +37,10 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `()` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:39:13 | LL | / fn a_trait_method() { @@ -50,8 +50,8 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `()` + = note: required by `from_residual` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-operator-custom.rs b/src/test/ui/try-operator-custom.rs deleted file mode 100644 index 9993061ea6155..0000000000000 --- a/src/test/ui/try-operator-custom.rs +++ /dev/null @@ -1,63 +0,0 @@ -// run-pass - -#![feature(try_trait)] - -use std::ops::Try; - -enum MyResult { - Awesome(T), - Terrible(U) -} - -impl Try for MyResult { - type Ok = U; - type Error = V; - - fn from_ok(u: U) -> MyResult { - MyResult::Awesome(u) - } - - fn from_error(e: V) -> MyResult { - MyResult::Terrible(e) - } - - fn into_result(self) -> Result { - match self { - MyResult::Awesome(u) => Ok(u), - MyResult::Terrible(e) => Err(e), - } - } -} - -fn f(x: i32) -> Result { - if x == 0 { - Ok(42) - } else { - let y = g(x)?; - Ok(y) - } -} - -fn g(x: i32) -> MyResult { - let _y = f(x - 1)?; - MyResult::Terrible("Hello".to_owned()) -} - -fn h() -> MyResult { - let a: Result = Err("Hello"); - let b = a?; - MyResult::Awesome(b) -} - -fn i() -> MyResult { - let a: MyResult = MyResult::Terrible("Hello"); - let b = a?; - MyResult::Awesome(b) -} - -fn main() { - assert!(f(0) == Ok(42)); - assert!(f(10) == Err("Hello".to_owned())); - let _ = h(); - let _ = i(); -} diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-operator-on-main.rs index e1b6cfbe5ae1b..cc52c601a0d4a 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-operator-on-main.rs @@ -1,13 +1,16 @@ +// ignore-tidy-linelength + #![feature(try_trait)] +#![feature(try_trait_v2)] use std::ops::Try; fn main() { // error for a `Try` type on a non-`Try` fn - std::fs::File::open("foo")?; //~ ERROR the `?` operator can only + std::fs::File::open("foo")?; //~ ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) // a non-`Try` type on a non-`Try` fn - ()?; //~ ERROR the `?` operator can only + ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` // an unrelated use of `Try` try_trait_generic::<()>(); //~ ERROR the trait bound diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index be17de2fe7cc0..522044d281d9f 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,5 +1,5 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-operator-on-main.rs:7:5 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-operator-on-main.rs:10:5 | LL | / fn main() { LL | | // error for a `Try` type on a non-`Try` fn @@ -11,20 +11,20 @@ LL | | try_trait_generic::<()>(); LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `()` + = note: required by `from_residual` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:10:5 + --> $DIR/try-operator-on-main.rs:13:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `Try` is not implemented for `()` - = note: required by `into_result` + = note: required by `branch` error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-operator-on-main.rs:13:25 + --> $DIR/try-operator-on-main.rs:16:25 | LL | try_trait_generic::<()>(); | ^^ the trait `Try` is not implemented for `()` @@ -33,13 +33,13 @@ LL | fn try_trait_generic() -> T { | --- required by this bound in `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:20:5 + --> $DIR/try-operator-on-main.rs:23:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `Try` is not implemented for `()` - = note: required by `into_result` + = note: required by `branch` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-trait/try-control-flow-in-result.rs b/src/test/ui/try-trait/try-control-flow-in-result.rs new file mode 100644 index 0000000000000..ed85c3dd3bb4f --- /dev/null +++ b/src/test/ui/try-trait/try-control-flow-in-result.rs @@ -0,0 +1,15 @@ +#![feature(control_flow_enum)] +#![feature(try_trait_v2)] + +use std::ops::ControlFlow; + +fn returns_control_flow() -> ControlFlow<()> { + ControlFlow::BREAK +} + +fn demo() -> Result<(), ()> { + returns_control_flow()?; //~ ERROR the `?` operator can only be used in a function that + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/try-trait/try-control-flow-in-result.stderr b/src/test/ui/try-trait/try-control-flow-in-result.stderr new file mode 100644 index 0000000000000..f8d8d27a0780c --- /dev/null +++ b/src/test/ui/try-trait/try-control-flow-in-result.stderr @@ -0,0 +1,16 @@ +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-control-flow-in-result.rs:11:5 + | +LL | / fn demo() -> Result<(), ()> { +LL | | returns_control_flow()?; + | | ^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `Result<(), ()>` +LL | | Ok(()) +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` + = note: required by `from_residual` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-trait/try-fold-rfc-example.rs b/src/test/ui/try-trait/try-fold-rfc-example.rs new file mode 100644 index 0000000000000..a28e779f9aed0 --- /dev/null +++ b/src/test/ui/try-trait/try-fold-rfc-example.rs @@ -0,0 +1,68 @@ +// check-pass + +#![feature(control_flow_enum)] +#![feature(try_trait_v2)] + +use std::ops::{ControlFlow, Try, FromResidual}; + +pub fn simple_fold( + iter: impl Iterator, + mut accum: A, + mut f: impl FnMut(A, T) -> A, +) -> A { + for x in iter { + accum = f(accum, x); + } + accum +} + +pub fn simple_try_fold_1>( + iter: impl Iterator, + mut accum: A, + mut f: impl FnMut(A, T) -> R, +) -> R { + todo!() +} + +pub fn simple_try_fold_2>( + iter: impl Iterator, + mut accum: A, + mut f: impl FnMut(A, T) -> R, +) -> R { + for x in iter { + let cf = f(accum, x).branch(); + match cf { + ControlFlow::Continue(a) => accum = a, + ControlFlow::Break(_) => todo!(), + } + } + R::from_output(accum) +} + +pub fn simple_try_fold_3>( + iter: impl Iterator, + mut accum: A, + mut f: impl FnMut(A, T) -> R, +) -> R { + for x in iter { + let cf = f(accum, x).branch(); + match cf { + ControlFlow::Continue(a) => accum = a, + ControlFlow::Break(h) => return R::from_residual(h), + } + } + R::from_output(accum) +} + +fn simple_try_fold>( + iter: impl Iterator, + mut accum: A, + mut f: impl FnMut(A, T) -> R, +) -> R { + for x in iter { + accum = f(accum, x)?; + } + R::from_output(accum) +} + +fn main() {} diff --git a/src/test/ui/try-trait/try-non-generic-type.rs b/src/test/ui/try-trait/try-non-generic-type.rs new file mode 100644 index 0000000000000..6aca116ee2db9 --- /dev/null +++ b/src/test/ui/try-trait/try-non-generic-type.rs @@ -0,0 +1,70 @@ +// run-pass + +#![feature(control_flow_enum)] +#![feature(try_trait_v2)] + +use std::num::NonZeroI32; +use std::ops::{ControlFlow, Try, FromResidual}; + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(transparent)] +pub struct ResultCode(pub i32); +impl ResultCode { + const SUCCESS: Self = ResultCode(0); +} + +pub struct ResultCodeResidual(NonZeroI32); + +#[derive(Debug, Clone)] +pub struct FancyError(String); + +impl Try for ResultCode { + type Ok = (); + type Residual = ResultCodeResidual; + fn branch(self) -> ControlFlow { + match NonZeroI32::new(self.0) { + Some(r) => ControlFlow::Break(ResultCodeResidual(r)), + None => ControlFlow::Continue(()), + } + } + fn from_output((): ()) -> Self { + ResultCode::SUCCESS + } +} + +impl FromResidual for ResultCode { + fn from_residual(r: ResultCodeResidual) -> Self { + ResultCode(r.0.into()) + } +} + +impl> FromResidual for Result { + fn from_residual(r: ResultCodeResidual) -> Self { + Err(FancyError(format!( + "Something fancy about {} at {:?}", + r.0, + std::time::SystemTime::now() + )) + .into()) + } +} + +fn fine() -> ResultCode { + ResultCode(0) +} + +fn bad() -> ResultCode { + ResultCode(-13) +} + +fn i() -> ResultCode { + fine()?; + bad()?; + ResultCode::SUCCESS +} + +fn main() -> Result<(), FancyError> { + assert_eq!(i(), ResultCode(-13)); + fine()?; + Ok(()) +} diff --git a/src/test/ui/try-trait/try-on-option-in-result-method.rs b/src/test/ui/try-trait/try-on-option-in-result-method.rs new file mode 100644 index 0000000000000..fe50d9bccb4f5 --- /dev/null +++ b/src/test/ui/try-trait/try-on-option-in-result-method.rs @@ -0,0 +1,20 @@ +// check-pass + +#![allow(dead_code, unused)] + +///! This isn't supposed to work, but it accidentally did, so unfortunately we need to support this. + +struct Tricky; + +impl From for Tricky { + fn from(_: T) -> Tricky { Tricky } +} + +fn foo() -> Result<(), Tricky> { + None?; + Ok(()) +} + +fn main() { + assert!(matches!(foo(), Err(Tricky))); +} diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-trait/try-on-option.rs similarity index 78% rename from src/test/ui/try-on-option.rs rename to src/test/ui/try-trait/try-on-option.rs index 5d94cee8e3721..a662bbd35fbce 100644 --- a/src/test/ui/try-on-option.rs +++ b/src/test/ui/try-trait/try-on-option.rs @@ -4,7 +4,7 @@ fn main() {} fn foo() -> Result { let x: Option = None; - x?; //~ ERROR `?` couldn't convert the error + x?; //~ ERROR `?` couldn't convert the error to `()` Ok(22) } diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr similarity index 64% rename from src/test/ui/try-on-option.stderr rename to src/test/ui/try-trait/try-on-option.stderr index ecd12c430f1f6..d90eb3bdb0b62 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -1,20 +1,17 @@ error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/try-on-option.rs:7:6 + --> $DIR/try-on-option.rs:7:5 | LL | fn foo() -> Result { | --------------- expected `()` because of this LL | let x: Option = None; LL | x?; - | ^ the trait `From` is not implemented for `()` + | ^^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` - | -LL | x.ok_or_else(|| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because of the requirements on the impl of `FromResidual>` for `Result` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:13:5 | LL | / fn bar() -> u32 { @@ -25,8 +22,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual>` is not implemented for `u32` + = note: required by `from_residual` error: aborting due to 2 previous errors diff --git a/src/test/ui/try-trait/try-operator-custom.rs b/src/test/ui/try-trait/try-operator-custom.rs new file mode 100644 index 0000000000000..a37d09a85fb95 --- /dev/null +++ b/src/test/ui/try-trait/try-operator-custom.rs @@ -0,0 +1,109 @@ +// run-pass + +#![feature(control_flow_enum)] +#![feature(never_type)] +#![feature(try_trait)] +#![feature(try_trait_v2)] + +use std::convert::Infallible; +use std::ops::{ControlFlow, Try2015, Try2021, FromResidual}; + +enum MyResult { + Awesome(T), + Terrible(U) +} + +impl Try2015 for MyResult { + type Ok = U; + type Error = V; + + fn from_ok(u: U) -> MyResult { + MyResult::Awesome(u) + } + + fn from_error(e: V) -> MyResult { + MyResult::Terrible(e) + } + + fn into_result(self) -> Result { + match self { + MyResult::Awesome(u) => Ok(u), + MyResult::Terrible(e) => Err(e), + } + } +} + +impl Try2021 for MyResult { + //type Output = U; + type Ok = U; + type Residual = MyResult; + fn from_output(x: U) -> Self { + MyResult::Awesome(x) + } + fn branch(self) -> ControlFlow { + match self { + MyResult::Awesome(u) => ControlFlow::Continue(u), + MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)), + } + } +} + +impl> FromResidual> for MyResult { + fn from_residual(x: MyResult) -> Self { + match x { + MyResult::Terrible(e) => MyResult::Terrible(From::from(e)), + MyResult::Awesome(infallible) => match infallible {} + } + } +} + +impl> FromResidual> for MyResult { + fn from_residual(x: Result) -> Self { + match x { + Err(e) => MyResult::Terrible(From::from(e)), + Ok(infallible) => match infallible {} + } + } +} + +impl> FromResidual> for Result { + fn from_residual(x: MyResult) -> Self { + match x { + MyResult::Terrible(e) => Err(From::from(e)), + MyResult::Awesome(infallible) => match infallible {} + } + } +} + +fn f(x: i32) -> Result { + if x == 0 { + Ok(42) + } else { + let y = g(x)?; + Ok(y) + } +} + +fn g(x: i32) -> MyResult { + let _y = f(x - 1)?; + MyResult::Terrible("Hello".to_owned()) +} + +fn h() -> MyResult { + let a: Result = Err("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn i() -> MyResult { + let a: MyResult = MyResult::Terrible("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn main() { + assert!(f(0) == Ok(42)); + assert!(f(10) == Err("Hello".to_owned())); + let _ = h(); + let _ = i(); +} diff --git a/src/test/ui/try-operator.rs b/src/test/ui/try-trait/try-operator.rs similarity index 100% rename from src/test/ui/try-operator.rs rename to src/test/ui/try-trait/try-operator.rs diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-trait/try-poll.rs similarity index 100% rename from src/test/ui/try-poll.rs rename to src/test/ui/try-trait/try-poll.rs diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 7435b9e98c928..0fe44d099ad7c 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 7435b9e98c9280043605748c11a1f450669e04d6 +Subproject commit 0fe44d099ad7cf9c8699e41ece424fda84bce999