diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 483135ed3a3af..866f2180bb6e3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -560,8 +560,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::from_output() }`, + /// `try { ; }` into `{ ; ::std::ops::Try::from_output(()) }` /// 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| { @@ -590,9 +590,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::from_output($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( - hir::LangItem::TryFromOk, + hir::LangItem::TryTraitFromOutput, try_span, tail_expr, ok_wrapped_span, @@ -1579,14 +1579,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::TryTraitBranch, arena_vec![self; sub_expr], ) }; @@ -1604,8 +1604,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( @@ -1614,27 +1614,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)] - // 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, - unstable_span, - from_expr, + // `ControlFlow::Break(residual) => + // #[allow(unreachable_code)] + // return Try::from_residual(residual),` + let break_arm = { + let residual_ident = Ident::with_dummy_span(sym::residual); + let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident); + let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid); + let from_residual_expr = self.wrap_in_try_constructor( + hir::LangItem::TryTraitFromResidual, + try_span, + self.arena.alloc(residual_expr), unstable_span, ); let thin_attrs = ThinVec::from(attrs); @@ -1645,25 +1639,25 @@ impl<'hir> LoweringContext<'_, 'hir> { try_span, hir::ExprKind::Break( hir::Destination { label: None, target_id }, - Some(from_err_expr), + Some(from_residual_expr), ), thin_attrs, )) } else { self.arena.alloc(self.expr( try_span, - hir::ExprKind::Ret(Some(from_err_expr)), + hir::ExprKind::Ret(Some(from_residual_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(try_span, residual_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 740dfc65df8c5..56f97054f9624 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -332,7 +332,7 @@ 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::control_flow_enum, sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), } .lower_crate(krate) @@ -2490,14 +2490,14 @@ 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> { + 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::ResultOk, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field) } - fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + 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::ResultErr, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7b788b13b9f7d..0b8535f8ca549 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -308,12 +308,12 @@ language_item_table! { Termination, sym::termination, termination, Target::Trait; - Try, kw::Try, try_trait, Target::Trait; + Try, sym::Try, try_trait, Target::Trait; // Language items from AST lowering - 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 }); + TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }); + TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }); + TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }); PollReady, sym::Ready, poll_ready_variant, Target::Variant; PollPending, sym::Pending, poll_pending_variant, Target::Variant; @@ -331,6 +331,9 @@ language_item_table! { ResultOk, sym::Ok, result_ok_variant, Target::Variant; ResultErr, sym::Err, result_err_variant, Target::Variant; + ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant; + ControlFlowBreak, sym::Break, cf_break_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_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 03a8f2be1561c..14ee083eceebe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -130,10 +130,12 @@ symbols! { BTreeSet, BinaryHeap, Borrow, + Break, C, CString, Center, Clone, + Continue, Copy, Count, Debug, @@ -326,6 +328,7 @@ symbols! { box_patterns, box_syntax, braced_empty_structs, + branch, breakpoint, bridge, bswap, @@ -411,6 +414,7 @@ symbols! { constructor, contents, context, + control_flow_enum, convert, copy, copy_closures, @@ -511,7 +515,6 @@ symbols! { env, eq, ermsb_target_feature, - err, exact_div, except, exchange_malloc, @@ -581,10 +584,10 @@ symbols! { frem_fast, from, from_desugaring, - from_error, from_generator, from_method, - from_ok, + from_output, + from_residual, from_size_align_unchecked, from_trait, from_usize, @@ -653,7 +656,6 @@ symbols! { instruction_set, intel, into_iter, - into_result, into_trait, intra_doc_pointers, intrinsics, @@ -965,6 +967,7 @@ symbols! { repr_packed, repr_simd, repr_transparent, + residual, result, result_type, rhs, @@ -1232,7 +1235,7 @@ symbols! { try_blocks, try_from_trait, try_into_trait, - try_trait, + try_trait_v2, tt, tuple, tuple_from_req, diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index e4cfb3acdfd5c..f3eb228c9e380 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -66,7 +66,7 @@ impl<'a, T> Iterator for Iter<'a, T> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let (mut iter, final_res); if self.tail <= self.head { @@ -140,7 +140,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let (mut iter, final_res); if self.tail <= self.head { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 66b1036f2ab0b..3bc376482e998 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,7 +140,8 @@ #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] -#![feature(try_trait)] +#![cfg_attr(bootstrap, feature(try_trait))] +#![cfg_attr(not(bootstrap), feature(try_trait_v2))] #![feature(min_type_alias_impl_trait)] #![feature(associated_type_bounds)] #![feature(slice_group_by)] diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index ce5e9936bbd7f..53e48500e3b4d 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -98,7 +98,7 @@ where where Self: Sized, F: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { if let Some(ref mut a) = self.a { acc = a.try_fold(acc, &mut f)?; @@ -281,7 +281,7 @@ where where Self: Sized, F: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { if let Some(ref mut b) = self.b { acc = b.try_rfold(acc, &mut f)?; diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 0abdbba2ef1b0..7efc155175c34 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -46,7 +46,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.it.try_fold(init, clone_try_fold(f)) } @@ -82,7 +82,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.it.try_rfold(init, clone_try_fold(f)) } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 0a5822452a347..def2408927589 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -50,7 +50,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.it.try_fold(init, copy_try_fold(f)) } @@ -98,7 +98,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.it.try_rfold(init, copy_try_fold(f)) } diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 6e9a011f819af..815e708f9ec0f 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -53,7 +53,7 @@ where fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { // fully iterate the current iterator. this is necessary because // `self.iter` may be empty even when `self.orig` isn't diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 73cee1df30c5e..91722a4b62a2e 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -71,7 +71,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { #[inline] fn enumerate<'a, T, Acc, R>( @@ -150,7 +150,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { // Can safely add and subtract the count, as `ExactSizeIterator` promises // that the number of elements fits into a `usize`. diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index 0337892b9e8e1..d5f19f127470e 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -37,7 +37,7 @@ fn filter_fold( move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } } -fn filter_try_fold<'a, T, Acc, R: Try>( +fn filter_try_fold<'a, T, Acc, R: Try>( predicate: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -88,7 +88,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) } @@ -117,7 +117,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) } diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 0dccf2c533b57..01b7be9d52daf 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -39,7 +39,7 @@ fn filter_map_fold( } } -fn filter_map_try_fold<'a, T, B, Acc, R: Try>( +fn filter_map_try_fold<'a, T, B, Acc, R: Try>( f: &'a mut impl FnMut(T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -72,7 +72,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) } @@ -111,7 +111,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 0114d7af4f410..3315d34659611 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -61,7 +61,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.inner.try_fold(init, fold) } @@ -91,7 +91,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.inner.try_rfold(init, fold) } @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.inner.try_fold(init, fold) } @@ -208,7 +208,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.inner.try_rfold(init, fold) } @@ -293,10 +293,10 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( + fn flatten<'a, T: IntoIterator, Acc, R: Try>( frontiter: &'a mut Option, fold: &'a mut impl FnMut(Acc, T::Item) -> R, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -382,10 +382,10 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( + fn flatten<'a, T: IntoIterator, Acc, R: Try>( backiter: &'a mut Option, fold: &'a mut impl FnMut(Acc, T::Item) -> R, ) -> impl FnMut(Acc, T) -> R + 'a diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index c01f384dec5d6..aff48b1b220c4 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -92,7 +92,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { FuseImpl::try_fold(self, acc, fold) } @@ -148,7 +148,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { FuseImpl::try_rfold(self, acc, fold) } @@ -219,7 +219,7 @@ trait FuseImpl { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try; + R: Try; fn fold(self, acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc; @@ -238,7 +238,7 @@ trait FuseImpl { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, I: DoubleEndedIterator; fn rfold(self, acc: Acc, fold: Fold) -> Acc where @@ -305,7 +305,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { if let Some(ref mut iter) = self.iter { acc = iter.try_fold(acc, fold)?; @@ -354,7 +354,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, I: DoubleEndedIterator, { if let Some(ref mut iter) = self.iter { @@ -443,7 +443,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { unchecked!(self).try_fold(init, fold) } @@ -485,7 +485,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, I: DoubleEndedIterator, { unchecked!(self).try_rfold(init, fold) diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 88f5ee61b6b73..36835d12e5685 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -87,7 +87,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) } @@ -117,7 +117,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) } diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 2a4b7efd5e665..0bf9f4b0327e9 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -110,7 +110,7 @@ where where Self: Sized, G: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_fold(init, map_try_fold(&mut self.f, g)) } @@ -146,7 +146,7 @@ where where Self: Sized, G: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) } diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index 26114d5328498..8f89e1588048f 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -54,7 +54,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 4f69b82ba4c3b..9fdd4fca04c97 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -168,7 +168,7 @@ where fn try_fold(&mut self, init: B, mut f: F) -> R where F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let error = &mut *self.error; self.iter diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 21386e28a9643..8ee7d0955c6d1 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -1,5 +1,5 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator with a `peek()` that returns an optional reference to the next /// element. @@ -91,7 +91,7 @@ impl Iterator for Peekable { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let acc = match self.peeked.take() { Some(None) => return try { init }, @@ -130,19 +130,42 @@ where } #[inline] + #[cfg(not(bootstrap))] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { + 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] + #[cfg(bootstrap)] + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let _use_the_import: ControlFlow<()>; match self.peeked.take() { Some(None) => try { init }, Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { self.peeked = Some(Some(v)); - Try::from_error(e) + R::from_error(e) } }, None => self.iter.try_rfold(init, f), diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs index 105ed40a3ed11..139fb7bbdd996 100644 --- a/library/core/src/iter/adapters/rev.rs +++ b/library/core/src/iter/adapters/rev.rs @@ -51,7 +51,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_rfold(init, f) } @@ -96,7 +96,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { self.iter.try_fold(init, f) } diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 0214899295e35..96705b01f661f 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -56,9 +56,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { - fn scan<'a, T, St, B, Acc, R: Try>( + fn scan<'a, T, St, B, Acc, R: Try>( state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index e55c7a6bf5df1..c358a6d12b7bc 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -88,7 +88,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { let n = self.n; self.n = 0; @@ -146,9 +146,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { - fn check>( + fn check>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, ) -> impl FnMut(Acc, T) -> ControlFlow { diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index efcb469fc9577..93e29edc8df39 100644 --- a/library/core/src/iter/adapters/skip_while.rs +++ b/library/core/src/iter/adapters/skip_while.rs @@ -70,7 +70,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { if !self.flag { match self.next() { diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 2ba56eeccba17..4252c34a0e0fc 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -111,7 +111,7 @@ where fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { #[inline] fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { @@ -187,7 +187,7 @@ where fn try_rfold(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { #[inline] fn nth_back( diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 54a47f1323ebf..92f82ae232502 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -80,9 +80,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { - fn check<'a, T, Acc, R: Try>( + fn check<'a, T, Acc, R: Try>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { if self.n == 0 { try { init } diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index 746eb41f4c387..93457d20f7c23 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -68,9 +68,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try, + R: Try, { - fn check<'a, T, Acc, R: Try>( + fn check<'a, T, Acc, R: Try>( flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 5e39e71252f5a..8d0b2b9f55c9c 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -755,7 +755,7 @@ impl Iterator for ops::RangeInclusive { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { if self.is_empty() { return try { init }; @@ -860,7 +860,7 @@ impl DoubleEndedIterator for ops::RangeInclusive { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { if self.is_empty() { return try { init }; diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 6f8cb6b5a65b6..c302502b3b7e6 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -218,7 +218,7 @@ pub trait DoubleEndedIterator: Iterator { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let mut accum = init; while let Some(x) = self.next_back() { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index da9e5fde7ccec..777e4bc2c8920 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1999,7 +1999,7 @@ pub trait Iterator { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try, + R: Try, { let mut accum = init; while let Some(x) = self.next() { @@ -2041,7 +2041,7 @@ pub trait Iterator { where Self: Sized, F: FnMut(Self::Item) -> R, - R: Try, + R: Try, { #[inline] fn call(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { @@ -2412,17 +2412,48 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[cfg(not(bootstrap))] + fn try_find(&mut self, f: F) -> Result, E> + where + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: Try, + // FIXME: This bound is rather strange, but means minimal breakage on nightly. + // See #85115 for the issue tracking a holistic solution for this and try_map. + R: crate::ops::TryV2>, + { + #[inline] + fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow> + where + F: FnMut(&T) -> R, + R: Try, + R: crate::ops::TryV2>, + { + move |(), x| match f(&x).branch() { + ControlFlow::Continue(false) => ControlFlow::CONTINUE, + ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)), + ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)), + } + } + + self.try_fold((), check(f)).break_value().transpose() + } + + /// We're bootstrapping. + #[inline] + #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[cfg(bootstrap)] fn try_find(&mut self, f: F) -> Result, R::Error> where Self: Sized, F: FnMut(&Self::Item) -> R, - R: Try, + R: Try, { #[inline] fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow> where F: FnMut(&T) -> R, - R: Try, + R: Try, { move |(), x| match f(&x).into_result() { Ok(false) => ControlFlow::CONTINUE, diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ecaff053bd5c0..dbb51540bd475 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -1,5 +1,4 @@ -use crate::convert; -use crate::ops::{self, Try}; +use crate::{convert, ops}; /// Used to tell an operation whether it should exit early or go on as usual. /// @@ -53,8 +52,10 @@ use crate::ops::{self, 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` @@ -62,11 +63,11 @@ pub enum ControlFlow { } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] -impl Try for ControlFlow { - type Ok = C; +impl ops::TryV1 for ControlFlow { + type Output = C; type Error = B; #[inline] - fn into_result(self) -> Result { + fn into_result(self) -> Result { match self { ControlFlow::Continue(y) => Ok(y), ControlFlow::Break(x) => Err(x), @@ -77,7 +78,7 @@ impl Try for ControlFlow { ControlFlow::Break(v) } #[inline] - fn from_ok(v: Self::Ok) -> Self { + fn from_ok(v: Self::Output) -> Self { ControlFlow::Continue(v) } } @@ -182,14 +183,38 @@ impl ControlFlow { } } -impl ControlFlow { +#[cfg(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 Try::into_result(r) { + match R::into_result(r) { Ok(v) => ControlFlow::Continue(v), - Err(v) => ControlFlow::Break(Try::from_error(v)), + Err(v) => ControlFlow::Break(R::from_error(v)), + } + } + + /// 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_ok(v), + ControlFlow::Break(v) => v, + } + } +} + +#[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(r) { + ControlFlow::Continue(v) => ControlFlow::Continue(v), + ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)), } } @@ -198,7 +223,7 @@ impl ControlFlow { #[inline] pub fn into_try(self) -> R { match self { - ControlFlow::Continue(v) => Try::from_ok(v), + ControlFlow::Continue(v) => R::from_output(v), ControlFlow::Break(v) => v, } } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 1b07936ccde1d..beef74de61728 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -183,13 +183,21 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] +#[cfg(bootstrap)] pub use self::r#try::Try; +#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] +pub(crate) use self::r#try::Try as TryV1; + #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::FromResidual; +#[unstable(feature = "try_trait_v2", issue = "84277")] +#[cfg(not(bootstrap))] +pub use self::try_trait::Try; + #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] -pub use self::try_trait::Try as TryV2; +pub(crate) use self::try_trait::Try as TryV2; #[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..9d659e78d3cce 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -25,11 +25,11 @@ ) )] #[doc(alias = "?")] -#[lang = "try"] +#[cfg_attr(bootstrap, lang = "try")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] - type Ok; + type Output; // This no longer follows its RFC, but is only used in bootstrap. /// The type of this value when viewed as failed. #[unstable(feature = "try_trait", issue = "42327")] type Error; @@ -43,19 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. - #[lang = "into_result"] + #[cfg_attr(bootstrap, lang = "into_result")] #[unstable(feature = "try_trait", issue = "42327")] - fn into_result(self) -> Result; + fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[lang = "from_error"] + #[cfg_attr(bootstrap, lang = "from_error")] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[lang = "from_ok"] + #[cfg_attr(bootstrap, lang = "from_ok")] #[unstable(feature = "try_trait", issue = "42327")] - fn from_ok(v: Self::Ok) -> Self; + fn from_ok(v: Self::Output) -> Self; } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 0c819b000aaab..87044ed2fcee1 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -41,8 +41,7 @@ use crate::ops::ControlFlow; /// output type that we want: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] -/// # use std::ops::TryV2 as Try; +/// # use std::ops::Try; /// fn simple_try_fold_1>( /// iter: impl Iterator, /// mut accum: A, @@ -56,9 +55,8 @@ use crate::ops::ControlFlow; /// into the return type using [`Try::from_output`]: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] /// # #![feature(control_flow_enum)] -/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// # use std::ops::{ControlFlow, Try}; /// fn simple_try_fold_2>( /// iter: impl Iterator, /// mut accum: A, @@ -81,9 +79,8 @@ use crate::ops::ControlFlow; /// recreated from their corresponding residual, so we'll just call it: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] /// # #![feature(control_flow_enum)] -/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// # use std::ops::{ControlFlow, Try}; /// pub fn simple_try_fold_3>( /// iter: impl Iterator, /// mut accum: A, @@ -103,10 +100,9 @@ use crate::ops::ControlFlow; /// But this "call `branch`, then `match` on it, and `return` if it was a /// `Break`" is exactly what happens inside the `?` operator. So rather than /// do all this manually, we can just use `?` instead: -/// ```compile_fail (enable again once ? converts to the new trait) +/// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] -/// # use std::ops::TryV2 as Try; +/// # use std::ops::Try; /// fn simple_try_fold>( /// iter: impl Iterator, /// mut accum: A, @@ -119,6 +115,22 @@ use crate::ops::ControlFlow; /// } /// ``` #[unstable(feature = "try_trait_v2", issue = "84277")] +#[rustc_on_unimplemented( + on( + all(from_method = "from_output", from_desugaring = "TryBlock"), + message = "a `try` block must return `Result` or `Option` \ + (or another type that implements `{Try}`)", + label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", + ), + on( + all(from_method = "branch", from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values \ + that implement `{Try}`", + label = "the `?` operator cannot be applied to type `{Self}`" + ) +)] +#[doc(alias = "?")] +#[cfg_attr(not(bootstrap), lang = "Try")] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. #[unstable(feature = "try_trait_v2", issue = "84277")] @@ -159,8 +171,7 @@ pub trait Try: FromResidual { /// ``` /// #![feature(try_trait_v2)] /// #![feature(control_flow_enum)] - /// #![feature(try_trait_transition)] - /// use std::ops::TryV2 as Try; + /// use std::ops::Try; /// /// assert_eq!( as Try>::from_output(3), Ok(3)); /// assert_eq!( as Try>::from_output(4), Some(4)); @@ -178,6 +189,7 @@ pub trait Try: FromResidual { /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); /// assert_eq!(r, Some(4)); /// ``` + #[cfg_attr(not(bootstrap), lang = "from_output")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_output(output: Self::Output) -> Self; @@ -191,8 +203,7 @@ pub trait Try: FromResidual { /// ``` /// #![feature(try_trait_v2)] /// #![feature(control_flow_enum)] - /// #![feature(try_trait_transition)] - /// use std::ops::{ControlFlow, TryV2 as Try}; + /// use std::ops::{ControlFlow, Try}; /// /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); /// assert_eq!(Err::(3).branch(), ControlFlow::Break(Err(3))); @@ -206,15 +217,80 @@ pub trait Try: FromResidual { /// ControlFlow::Break(ControlFlow::Break(3)), /// ); /// ``` + #[cfg_attr(not(bootstrap), lang = "branch")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn branch(self) -> ControlFlow; } -/// Used to specify which residuals can be converted into which [`Try`] types. +/// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. /// /// Every `Try` type needs to be recreatable from its own associated /// `Residual` type, but can also have additional `FromResidual` implementations /// to support interconversion with other `Try` types. +#[rustc_on_unimplemented( + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + R = "std::option::Option" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + enclosing_scope = "this function returns a `Result`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns a `Result`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns an `Option`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + 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 = "84277")] pub trait FromResidual::Residual> { /// Constructs the type from a compatible `Residual` type. @@ -238,6 +314,7 @@ pub trait FromResidual::Residual> { /// ControlFlow::Break(5), /// ); /// ``` + #[cfg_attr(not(bootstrap), lang = "from_residual")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_residual(residual: R) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 04551dded8c77..c5b1c804eadd2 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1644,8 +1644,8 @@ impl> FromIterator> for Option { pub struct NoneError; #[unstable(feature = "try_trait", issue = "42327")] -impl ops::Try for Option { - type Ok = T; +impl ops::TryV1 for Option { + type Output = T; type Error = NoneError; #[inline] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e0071f806aaaf..21e406194bc9e 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1627,8 +1627,8 @@ impl> FromIterator> for Result { } #[unstable(feature = "try_trait", issue = "42327")] -impl ops::Try for Result { - type Ok = T; +impl ops::TryV1 for Result { + type Output = T; type Error = E; #[inline] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 906dcb1e8bcee..b92ab7e347555 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -110,7 +110,7 @@ impl<'a> iter::Iterator for EscapeAscii<'a> { fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Fold: FnMut(Acc, Self::Item) -> R, - R: ops::Try, + R: ops::Try, { self.inner.try_fold(init, fold) } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 724137aba9f3c..6ec6b70b57119 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1467,7 +1467,7 @@ macro_rules! escape_types_impls { #[inline] fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { self.inner.try_fold(init, fold) } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 2765c21a46db1..188639e7962e4 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -1,7 +1,7 @@ #![stable(feature = "futures_api", since = "1.36.0")] use crate::convert; -use crate::ops::{self, ControlFlow, Try}; +use crate::ops::{self, ControlFlow}; use crate::result::Result; /// Indicates whether a value is available or if the current task has been @@ -129,12 +129,12 @@ impl From for Poll { } #[stable(feature = "futures_api", since = "1.36.0")] -impl Try for Poll> { - type Ok = Poll; +impl ops::TryV1 for Poll> { + type Output = Poll; type Error = E; #[inline] - fn into_result(self) -> Result { + fn into_result(self) -> Result { match self { Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), Poll::Ready(Err(e)) => Err(e), @@ -148,7 +148,7 @@ impl Try for Poll> { } #[inline] - fn from_ok(x: Self::Ok) -> Self { + fn from_ok(x: Self::Output) -> Self { x.map(Ok) } } @@ -184,12 +184,12 @@ impl> ops::FromResidual> for Pol } #[stable(feature = "futures_api", since = "1.36.0")] -impl Try for Poll>> { - type Ok = Poll>; +impl ops::TryV1 for Poll>> { + type Output = Poll>; type Error = E; #[inline] - fn into_result(self) -> Result { + fn into_result(self) -> Result { match self { Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), Poll::Ready(Some(Err(e))) => Err(e), @@ -204,7 +204,7 @@ impl Try for Poll>> { } #[inline] - fn from_ok(x: Self::Ok) -> Self { + fn from_ok(x: Self::Output) -> Self { x.map(|x| x.map(Ok)) } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 35e4d213dde1e..db12d79c00c30 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -45,6 +45,7 @@ #![feature(test)] #![feature(trusted_len)] #![feature(try_trait)] +#![feature(try_trait_v2)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(int_error_matching)] 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 c461ab380ad3d..f4e5e7751b8e3 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -249,26 +249,14 @@ pub fn test_into_err() { #[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 { + fn try_result_ok() -> Result { let result: Result = Ok(1); let val = result?; Ok(val) } assert_eq!(try_result_ok(), Ok(1)); - fn try_result_err() -> Result { + fn try_result_err() -> Result { let result: Result = Err(1); let val = result?; Ok(val) @@ -401,3 +389,17 @@ fn result_opt_conversions() { assert_eq!(res, Err(BadNumErr)) } + +#[test] +#[cfg(not(bootstrap))] // Needs the V2 trait +fn result_try_trait_v2_branch() { + use core::num::NonZeroU32; + use core::ops::{ControlFlow::*, Try}; + assert_eq!(Ok::(4).branch(), Continue(4)); + assert_eq!(Err::(4).branch(), Break(Err(4))); + let one = NonZeroU32::new(1).unwrap(); + assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(())); + assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one))); + assert_eq!(Ok::(one).branch(), Continue(one)); + assert_eq!(Err::(()).branch(), Break(Err(()))); +} diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index 81e2435e5b80e..3ff77163b9f3d 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -7,11 +7,28 @@ type R = Result; +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. #[no_mangle] -fn try_identity(x: R) -> R { +pub fn try_identity(x: R) -> R { // CHECK: start: // CHECK-NOT: br {{.*}} // CHECK ret void - let y = x?; + let y = match into_result(x) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(y) } + +#[inline] +fn into_result(r: Result) -> Result { + r +} + +#[inline] +fn from_error(e: E) -> Result { + Err(e) +} 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..ba17a45f984ef 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 _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 residual => _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,10 +29,10 @@ 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::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } } bb1: { @@ -43,12 +42,12 @@ fn test() -> Option> { } 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 + _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:19: 9:20 - // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, 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 - // 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()) } - } - - bb6: { 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.rs b/src/test/mir-opt/simplify-arm.rs index 50b5147e0cf65..f7dcaa13449ea 100644 --- a/src/test/mir-opt/simplify-arm.rs +++ b/src/test/mir-opt/simplify-arm.rs @@ -20,8 +20,23 @@ fn id_result(r: Result) -> Result { } } +fn into_result(r: Result) -> Result { + r +} + +fn from_error(e: E) -> Result { + Err(e) +} + +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. fn id_try(r: Result) -> Result { - let x = r?; + let x = match into_result(r) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(x) } 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..a3bad4f0c623d 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff @@ -2,101 +2,93 @@ + // MIR for `id_try` after SimplifyArmIdentity fn id_try(_1: Result) -> Result { - 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 _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 _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 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40: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:36:9: 36:10 ++ debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:36:9: 36: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 - 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 - } +- debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 ++ debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 + scope 5 (inlined >::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 +- debug t => _9; // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 ++ debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 } - } - 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 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify-arm.rs:37:26: 37:51 +- debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 ++ debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 3 { +- debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 ++ debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify-arm.rs:36:19: 36:33 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - 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(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37: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(_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 - 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 +- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 +- _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 +- _2 = _10; // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19 +- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19 ++ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 +- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 +- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 +- ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 +- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 } 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 - 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 +- StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 +- StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50 +- StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 +- _9 = _6; // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 +- _8 = move _9; // scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 +- StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50 +- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51 +- StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51 ++ _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } } 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..b6b7511b3f597 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff @@ -2,75 +2,70 @@ + // MIR for `id_try` after SimplifyBranchSame fn id_try(_1: Result) -> Result { - 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 _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 _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 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9 scope 1 { - debug x => ((_0 as Ok).0: u8); // 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:36:9: 36:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // 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 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 + scope 5 (inlined >::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify-arm.rs:37:26: 37:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 } } - scope 6 (inlined as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 3 { + debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify-arm.rs:36:19: 36:33 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - 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(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 +- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 ++ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 - 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 -> bb2; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 ++ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { -- unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 +- unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 - } - - 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 +- _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 +- StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index eb307de20744a..15e351e7d5016 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -4,8 +4,24 @@ // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir // EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff + +fn into_result(r: Result) -> Result { + r +} + +fn from_error(e: E) -> Result { + Err(e) +} + +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. fn try_identity(x: Result) -> Result { - let y = x?; + let y = match into_result(x) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(y) } 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..e09b8cb39bd51 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,67 +2,62 @@ + // MIR for `try_identity` after DestinationPropagation 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 _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 _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 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // 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:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // 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 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - 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 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 +- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 ++ debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - 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: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(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ nop; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -+ 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 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } 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..488ad33f80a2d 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,93 +2,85 @@ + // MIR for `try_identity` after SimplifyArmIdentity 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 _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 _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 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25: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:21:9: 21:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21: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 - 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 - } +- debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 ++ debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 +- debug t => _9; // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 ++ debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - 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 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 +- debug e => _8; // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 ++ debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - 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 + scope 3 { +- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 ++ debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - 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 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:22:9: 22: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(_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 - 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 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26: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 - 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 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 +- StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 +- StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 +- _9 = _6; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 +- _8 = move _9; // scope 5 at $DIR/simplify_try.rs:22:37: 22:50 +- StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 +- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 +- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 +- StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 ++ _0 = move _3; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } 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..5d829f859e9d9 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 @@ -1,57 +1,52 @@ // MIR for `try_identity` after SimplifyBranchSame 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 _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 _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 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // 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:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // 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 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - 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 + scope 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - 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 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - 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 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } 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..1b5232422b6c3 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 @@ -1,33 +1,29 @@ // MIR for `try_identity` after SimplifyLocals 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 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // 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:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // 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 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - 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 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 4a8e841b33d49..9fe3313ee6cc6 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -42,7 +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` + //~| NOTE required by `branch` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` @@ -65,7 +65,7 @@ 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` + //~| NOTE required by `branch` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index fd00522fac703..ad661fb2833fa 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -5,7 +5,7 @@ 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` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | foo().await?; @@ -18,7 +18,7 @@ LL | t?; | ^^ the `?` operator cannot be applied to type `T` | = help: the trait `Try` is not implemented for `T` - = note: required by `into_result` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | t.await?; 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..a3f122a466361 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,47 +1,47 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-in-async.rs:8:9 +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:10 | LL | async { | ___________- LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async block that returns `{integer}` + | | ^ cannot use the `?` operator in an async block that returns `{integer}` 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`) - --> $DIR/try-on-option-in-async.rs:17:9 +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:10 | LL | let async_closure = async || { | __________________________________- LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async closure that returns `u32` + | | ^ cannot use the `?` operator in an async closure that returns `u32` 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`) - --> $DIR/try-on-option-in-async.rs:26:5 +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:6 | LL | async fn an_async_function() -> u32 { | _____________________________________- LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async function that returns `u32` + | | ^ cannot use the `?` operator in an async function that returns `u32` 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..2d020188198af 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -7,7 +7,8 @@ LL | Err(5)?; | ^ 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.stderr b/src/test/ui/option-to-result.stderr deleted file mode 100644 index 551b9f4650aac..0000000000000 --- a/src/test/ui/option-to-result.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/option-to-result.rs:5:6 - | -LL | fn test_result() -> Result<(),()> { - | ------------- expected `()` because of this -LL | let a:Option<()> = Some(()); -LL | a?; - | ^ 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 */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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` - | - = 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 | a.ok()?; - | ^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. 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 1adce5e01506d..6985f1b71a8db 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 @@ -502,10 +502,10 @@ 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`) - --> $DIR/disallowed-positions.rs:46:8 +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:19 | LL | / fn nested_within_if_expr() { LL | | if &let 0 = 0 {} @@ -513,14 +513,14 @@ LL | | LL | | ... | LL | | if (let 0 = 0)? {} - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | 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 @@ -660,7 +660,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 @@ -690,10 +690,10 @@ 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`) - --> $DIR/disallowed-positions.rs:110:11 +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:22 | LL | / fn nested_within_while_expr() { LL | | while &let 0 = 0 {} @@ -701,14 +701,14 @@ LL | | LL | | ... | LL | | while (let 0 = 0)? {} - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | 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 @@ -848,7 +848,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 @@ -869,10 +869,10 @@ 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`) - --> $DIR/disallowed-positions.rs:183:5 +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:16 | LL | / fn outside_if_and_while_expr() { LL | | &let 0 = 0; @@ -880,14 +880,14 @@ LL | | LL | | !let 0 = 0; ... | LL | | (let 0 = 0)?; - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | 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 @@ -916,7 +916,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..eb67170d47cdf 100644 --- a/src/test/ui/suggestions/issue-72766.stderr +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -5,7 +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` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | SadGirl {}.call().await?; 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..30ae96763c0e2 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -15,8 +15,7 @@ pub fn main() { let res: Result = try { }; //~ ERROR type mismatch let res: () = try { }; - //~^ ERROR the trait bound `(): Try` is not satisfied - //~| ERROR the trait bound `(): Try` is not satisfied + //~^ ERROR a `try` block must return `Result` or `Option` - let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied + let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option` } 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..ec5e91f10c286 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -7,43 +7,40 @@ LL | Err("")?; = 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` +error[E0271]: type mismatch resolving ` as Try>::Output == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `i32`, found `&str` -error[E0271]: type mismatch resolving ` as Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Output == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result = try { }; | ^ expected `i32`, found `()` -error[E0277]: the trait bound `(): Try` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type.rs:17:25 | LL | let res: () = try { }; - | ^ the trait `Try` is not implemented for `()` + | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_output` -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 `()` - -error[E0277]: the trait bound `i32: Try` is not satisfied - --> $DIR/try-block-bad-type.rs:21:26 +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type.rs:20:26 | LL | let res: i32 = try { 5 }; - | ^ the trait `Try` is not implemented for `i32` + | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `i32` + = 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.rs b/src/test/ui/try-block/try-block-in-while.rs index 5d8748f1dd325..69793df525e77 100644 --- a/src/test/ui/try-block/try-block-in-while.rs +++ b/src/test/ui/try-block/try-block-in-while.rs @@ -4,5 +4,5 @@ fn main() { while try { false } {} - //~^ ERROR the trait bound `bool: Try` is not satisfied + //~^ ERROR a `try` block must } 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..c83351d5c4346 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,10 +1,11 @@ -error[E0277]: the trait bound `bool: Try` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-in-while.rs:6:17 | LL | while try { false } {} - | ^^^^^ the trait `Try` is not implemented for `bool` + | ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `bool` + = note: required by `from_output` error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr index df1441c83d4f1..3e9a584a5510a 100644 --- a/src/test/ui/try-block/try-block-type-error.stderr +++ b/src/test/ui/try-block/try-block-type-error.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Try>::Ok == {integer}` +error[E0271]: type mismatch resolving ` as Try>::Output == {integer}` --> $DIR/try-block-type-error.rs:10:9 | LL | 42 @@ -7,7 +7,7 @@ LL | 42 | expected `f32`, found integer | help: use a float literal: `42.0` -error[E0271]: type mismatch resolving ` as Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Output == ()` --> $DIR/try-block-type-error.rs:16:5 | LL | }; diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr deleted file mode 100644 index ecd12c430f1f6..0000000000000 --- a/src/test/ui/try-on-option.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/try-on-option.rs:7:6 - | -LL | fn foo() -> Result { - | --------------- expected `()` because of this -LL | let x: Option = None; -LL | x?; - | ^ 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 */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option.rs:13:5 - | -LL | / fn bar() -> u32 { -LL | | let x: Option = None; -LL | | x?; - | | ^^ cannot use the `?` operator in a function that returns `u32` -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` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. 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-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs new file mode 100644 index 0000000000000..87585822f5719 --- /dev/null +++ b/src/test/ui/try-trait/bad-interconversion.rs @@ -0,0 +1,48 @@ +#![feature(control_flow_enum)] + +use std::ops::ControlFlow; + +fn result_to_result() -> Result { + Ok(Err(123_i32)?) + //~^ ERROR `?` couldn't convert the error to `u8` +} + +fn option_to_result() -> Result { + Some(3)?; + //~^ ERROR the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + Ok(10) +} + +fn control_flow_to_result() -> Result { + Ok(ControlFlow::Break(123)?) + //~^ ERROR the `?` operator can only be used on `Result`s in a function that returns `Result` +} + +fn result_to_option() -> Option { + Some(Err("hello")?) + //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option` +} + +fn control_flow_to_option() -> Option { + Some(ControlFlow::Break(123)?) + //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option` +} + +fn result_to_control_flow() -> ControlFlow { + ControlFlow::Continue(Err("hello")?) + //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` +} + +fn option_to_control_flow() -> ControlFlow { + Some(3)?; + //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + ControlFlow::Break(10) +} + +fn control_flow_to_control_flow() -> ControlFlow { + ControlFlow::Break(4_u8)?; + //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + ControlFlow::Continue(()) +} + +fn main() {} diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr new file mode 100644 index 0000000000000..e396256de2245 --- /dev/null +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -0,0 +1,115 @@ +error[E0277]: `?` couldn't convert the error to `u8` + --> $DIR/bad-interconversion.rs:6:20 + | +LL | fn result_to_result() -> Result { + | --------------- expected `u8` because of this +LL | Ok(Err(123_i32)?) + | ^ the trait `From` is not implemented for `u8` + | + = 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 because of the requirements on the impl of `FromResidual>` for `Result` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/bad-interconversion.rs:11:12 + | +LL | / fn option_to_result() -> Result { +LL | | Some(3)?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` +LL | | +LL | | Ok(10) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual>` is not implemented for `Result` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` + --> $DIR/bad-interconversion.rs:17:31 + | +LL | / fn control_flow_to_result() -> Result { +LL | | Ok(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result` +LL | | +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual>` is not implemented for `Result` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` + --> $DIR/bad-interconversion.rs:22:22 + | +LL | / fn result_to_option() -> Option { +LL | | Some(Err("hello")?) + | | ^ this `?` produces `Result`, which is incompatible with `Option` +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual>` is not implemented for `Option` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` + --> $DIR/bad-interconversion.rs:27:33 + | +LL | / fn control_flow_to_option() -> Option { +LL | | Some(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option` +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual>` is not implemented for `Option` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + --> $DIR/bad-interconversion.rs:32:39 + | +LL | / fn result_to_control_flow() -> ControlFlow { +LL | | ControlFlow::Continue(Err("hello")?) + | | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` +LL | | +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + --> $DIR/bad-interconversion.rs:37:12 + | +LL | / fn option_to_control_flow() -> ControlFlow { +LL | | Some(3)?; + | | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` +LL | | +LL | | ControlFlow::Break(10) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + --> $DIR/bad-interconversion.rs:43:29 + | +LL | / fn control_flow_to_control_flow() -> ControlFlow { +LL | | ControlFlow::Break(4_u8)?; + | | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` +LL | | +LL | | ControlFlow::Continue(()) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` + = note: required by `from_residual` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/try-trait/option-to-result.rs similarity index 63% rename from src/test/ui/option-to-result.rs rename to src/test/ui/try-trait/option-to-result.rs index 00e8b5244c54a..45aaf361a9c0e 100644 --- a/src/test/ui/option-to-result.rs +++ b/src/test/ui/try-trait/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 the `?` operator can only be used 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 Some(5) } diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr new file mode 100644 index 0000000000000..92087c2aba252 --- /dev/null +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -0,0 +1,31 @@ +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/option-to-result.rs:5:6 + | +LL | / fn test_result() -> Result<(),()> { +LL | | let a:Option<()> = Some(()); +LL | | a?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` +LL | | Ok(()) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` + --> $DIR/option-to-result.rs:11:6 + | +LL | / fn test_option() -> Option{ +LL | | let a:Result = Ok(5); +LL | | a?; + | | ^ this `?` produces `Result`, which is incompatible with `Option` +LL | | Some(5) +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual>` is not implemented for `Option` + = note: required by `from_residual` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-trait/try-as-monad.rs b/src/test/ui/try-trait/try-as-monad.rs new file mode 100644 index 0000000000000..cf09838b304b3 --- /dev/null +++ b/src/test/ui/try-trait/try-as-monad.rs @@ -0,0 +1,24 @@ +// run-pass + +#![feature(try_trait_v2)] + +use std::ops::Try; + +fn monad_unit(x: ::Output) -> T { + T::from_output(x) +} + +fn monad_bind, T2: Try, R>( + mx: T1, + f: impl FnOnce(::Output) -> T2) +-> T2 { + let x = mx?; + f(x) +} + +fn main() { + let mx: Option = monad_unit(1); + let my = monad_bind(mx, |x| Some(x + 1)); + let mz = monad_bind(my, |x| Some(-x)); + assert_eq!(mz, Some(-2)); +} diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-trait/try-on-option-diagnostics.rs similarity index 100% rename from src/test/ui/try-on-option-diagnostics.rs rename to src/test/ui/try-trait/try-on-option-diagnostics.rs diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr similarity index 60% rename from src/test/ui/try-on-option-diagnostics.stderr rename to src/test/ui/try-trait/try-on-option-diagnostics.stderr index a71ee20aacf93..e7c67c21bb3e3 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr @@ -1,57 +1,57 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-diagnostics.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-on-option-diagnostics.rs:7:6 | LL | / fn a_function() -> u32 { LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in a function that returns `u32` + | | ^ cannot use the `?` operator in a function that returns `u32` 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`) - --> $DIR/try-on-option-diagnostics.rs:14:9 +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:10 | LL | let a_closure = || { | _____________________- LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in a closure that returns `{integer}` + | | ^ cannot use the `?` operator in a closure that returns `{integer}` 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`) - --> $DIR/try-on-option-diagnostics.rs:26:13 +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:14 | LL | / fn a_method() { LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in a method that returns `()` + | | ^ cannot use the `?` operator in a method that returns `()` 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`) - --> $DIR/try-on-option-diagnostics.rs:39:13 +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:14 | LL | / fn a_trait_method() { LL | | let x: Option = None; LL | | x?; - | | ^^ cannot use the `?` operator in a trait method that returns `()` + | | ^ cannot use the `?` operator in a trait method that returns `()` 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-on-option.rs b/src/test/ui/try-trait/try-on-option.rs similarity index 80% rename from src/test/ui/try-on-option.rs rename to src/test/ui/try-trait/try-on-option.rs index 5d94cee8e3721..f2012936a1174 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 the `?` operator Ok(22) } diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr new file mode 100644 index 0000000000000..604baa8550b45 --- /dev/null +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -0,0 +1,31 @@ +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/try-on-option.rs:7:6 + | +LL | / fn foo() -> Result { +LL | | let x: Option = None; +LL | | x?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` +LL | | Ok(22) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual>` is not implemented 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 `FromResidual`) + --> $DIR/try-on-option.rs:13:6 + | +LL | / fn bar() -> u32 { +LL | | let x: Option = None; +LL | | x?; + | | ^ cannot use the `?` operator in a function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual>` is not implemented for `u32` + = note: required by `from_residual` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. 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..45636a7fceddf --- /dev/null +++ b/src/test/ui/try-trait/try-operator-custom.rs @@ -0,0 +1,91 @@ +// run-pass + +#![feature(control_flow_enum)] +#![feature(try_trait_v2)] + +use std::ops::{ControlFlow, FromResidual, Try}; + +enum MyResult { + Awesome(T), + Terrible(U) +} + +enum Never {} + +impl Try for MyResult { + type Output = U; + type Residual = MyResult; + + fn from_output(u: U) -> MyResult { + MyResult::Awesome(u) + } + + fn branch(self) -> ControlFlow { + match self { + MyResult::Awesome(u) => ControlFlow::Continue(u), + MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)), + } + } +} + +impl FromResidual> for MyResult where V: Into { + fn from_residual(x: MyResult) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => MyResult::Terrible(e.into()), + } + } +} + +type ResultResidual = Result; + +impl FromResidual> for MyResult where V: Into { + fn from_residual(x: ResultResidual) -> Self { + match x { + Ok(v) => match v {} + Err(e) => MyResult::Terrible(e.into()), + } + } +} + +impl FromResidual> for Result where V: Into { + fn from_residual(x: MyResult) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => Err(e.into()), + } + } +} + +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-trait/try-operator-on-main.rs similarity index 75% rename from src/test/ui/try-operator-on-main.rs rename to src/test/ui/try-trait/try-operator-on-main.rs index e1b6cfbe5ae1b..3b364f7e7d39d 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-trait/try-operator-on-main.rs @@ -1,4 +1,4 @@ -#![feature(try_trait)] +#![feature(try_trait_v2)] use std::ops::Try; @@ -7,14 +7,13 @@ fn main() { std::fs::File::open("foo")?; //~ ERROR the `?` operator can only // a non-`Try` type on a non-`Try` fn - ()?; //~ ERROR the `?` operator can only + ()?; //~ ERROR the `?` operator can only be applied to + //~^ ERROR the `?` operator can only be used in a function that // an unrelated use of `Try` try_trait_generic::<()>(); //~ ERROR the trait bound } - - fn try_trait_generic() -> T { // and a non-`Try` object on a `Try` fn. ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr similarity index 52% rename from src/test/ui/try-operator-on-main.stderr rename to src/test/ui/try-trait/try-operator-on-main.stderr index be17de2fe7cc0..7d42c2e4d10d3 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-trait/try-operator-on-main.stderr @@ -1,18 +1,18 @@ -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:7:31 | LL | / fn main() { LL | | // error for a `Try` type on a non-`Try` fn LL | | std::fs::File::open("foo")?; - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` LL | | ... | 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 @@ -21,10 +21,28 @@ 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 `?` 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:7 + | +LL | / fn main() { +LL | | // error for a `Try` type on a non-`Try` fn +LL | | std::fs::File::open("foo")?; +LL | | +LL | | // a non-`Try` type on a non-`Try` fn +LL | | ()?; + | | ^ cannot use the `?` operator in a function that returns `()` +... | +LL | | try_trait_generic::<()>(); +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-operator-on-main.rs:13:25 + --> $DIR/try-operator-on-main.rs:14:25 | LL | try_trait_generic::<()>(); | ^^ the trait `Try` is not implemented for `()` @@ -33,14 +51,14 @@ 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:19: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 +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. 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/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 7b156a8c49dd9..d8417c7dc70d8 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -147,7 +147,7 @@ fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option if let ExprKind::Call(called, args) = &inner_expr_with_q.kind; if args.len() == 1; - if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind; + if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind; then { // Extract inner expr type from match argument generated by // question mark operator diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs index ebb39ea4877de..f2ba2b2ecf639 100644 --- a/src/tools/clippy/clippy_lints/src/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/try_err.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind; if let ExprKind::Call(match_fun, try_args) = match_arg.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; - if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _)); + if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _)); if let Some(try_arg) = try_args.get(0); if let ExprKind::Call(err_fun, err_args) = try_arg.kind; if let Some(err_arg) = err_args.get(0); diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 3387f35bac3d4..c27a6d4e347b5 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { if let hir::ExprKind::Call(func, args) = res.kind { if matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _)) + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _)) ) { check_map_error(cx, &args[0], expr); }