diff options
| author | bors <bors@rust-lang.org> | 2021-05-18 20:50:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-05-18 20:50:01 +0000 |
| commit | 4e3e6db011c5b482d2bef8ba02274657f93b5e0d (patch) | |
| tree | 18c4d91304ab931792236935417dfe51ad998a7a | |
| parent | 491cf5561efb1f5ff33c3234ccd0bc5cacbebe3e (diff) | |
| parent | e2edee4da07032de72ac930df1453780dbe73f3b (diff) | |
| download | rust-4e3e6db011c5b482d2bef8ba02274657f93b5e0d.tar.gz rust-4e3e6db011c5b482d2bef8ba02274657f93b5e0d.zip | |
Auto merge of #84767 - scottmcm:try_trait_actual, r=lcnr
Implement the new desugaring from `try_trait_v2` ~~Currently blocked on https://github.com/rust-lang/rust/issues/84782, which has a PR in https://github.com/rust-lang/rust/pull/84811~~ Rebased atop that fix. `try_trait_v2` tracking issue: https://github.com/rust-lang/rust/issues/84277 Unfortunately this is already touching a ton of things, so if you have suggestions for good ways to split it up, I'd be happy to hear them. (The combination between the use in the library, the compiler changes, the corresponding diagnostic differences, even MIR tests mean that I don't really have a great plan for it other than trying to have decently-readable commits. r? `@ghost` ~~(This probably shouldn't go in during the last week before the fork anyway.)~~ Fork happened.
91 files changed, 1176 insertions, 798 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 483135ed3a3..866f2180bb6 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 { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`, - /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }` + /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`, + /// `try { <stmts>; }` into `{ <stmts>; ::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(<expr>)` + // `Try::branch(<expr>)` let scrutinee = { // expand <expr> 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 740dfc65df8..56f97054f96 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 7b788b13b9f..0b8535f8ca5 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 03a8f2be156..14ee083ecee 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 e4cfb3acdfd..f3eb228c9e3 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<Ok = B>, + R: Try<Output = B>, { 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<Ok = B>, + R: Try<Output = B>, { 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 66b1036f2ab..3bc376482e9 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 ce5e9936bbd..53e48500e3b 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<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 0abdbba2ef1..7efc155175c 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<Ok = B>, + R: Try<Output = B>, { 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<Ok = B>, + R: Try<Output = B>, { 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 0a5822452a3..def24089275 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<Ok = B>, + R: Try<Output = B>, { 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<Ok = B>, + R: Try<Output = B>, { 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 6e9a011f819..815e708f9ec 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<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { // 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 73cee1df30c..91722a4b62a 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<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn enumerate<'a, T, Acc, R>( @@ -150,7 +150,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { // 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 0337892b9e8..d5f19f12747 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -37,7 +37,7 @@ fn filter_fold<T, Acc>( move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } } -fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>( +fn filter_try_fold<'a, T, Acc, R: Try<Output = Acc>>( 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<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 0dccf2c533b..01b7be9d52d 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<T, B, Acc>( } } -fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>( +fn filter_map_try_fold<'a, T, B, Acc, R: Try<Output = Acc>>( f: &'a mut impl FnMut(T) -> Option<B>, 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<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 0114d7af4f4..3315d346596 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<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_fold(init, fold) } @@ -91,7 +91,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_rfold(init, fold) } @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_fold(init, fold) } @@ -208,7 +208,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_rfold(init, fold) } @@ -293,10 +293,10 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>( + fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( frontiter: &'a mut Option<T::IntoIter>, 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<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>( + fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( backiter: &'a mut Option<T::IntoIter>, 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 c01f384dec5..aff48b1b220 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<Ok = Acc>, + R: Try<Output = Acc>, { FuseImpl::try_fold(self, acc, fold) } @@ -148,7 +148,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { FuseImpl::try_rfold(self, acc, fold) } @@ -219,7 +219,7 @@ trait FuseImpl<I> { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>; + R: Try<Output = Acc>; fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc; @@ -238,7 +238,7 @@ trait FuseImpl<I> { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, I: DoubleEndedIterator; fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc where @@ -305,7 +305,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, 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<Ok = Acc>, + R: Try<Output = Acc>, { unchecked!(self).try_fold(init, fold) } @@ -485,7 +485,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, 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 88f5ee61b6b..36835d12e56 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<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 2a4b7efd5e6..0bf9f4b0327 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<Ok = Acc>, + R: Try<Output = Acc>, { 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 26114d53284..8f89e158804 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 4f69b82ba4c..9fdd4fca04c 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<B, F, R>(&mut self, init: B, mut f: F) -> R where F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { 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 21386e28a96..8ee7d0955c6 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<I: Iterator> Iterator for Peekable<I> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let acc = match self.peeked.take() { Some(None) => return try { init }, @@ -130,19 +130,42 @@ where } #[inline] + #[cfg(not(bootstrap))] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { 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<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + 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 105ed40a3ed..139fb7bbdd9 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<Ok = B>, + R: Try<Output = B>, { self.iter.try_rfold(init, f) } @@ -96,7 +96,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { 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 0214899295e..96705b01f66 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<Ok = Acc>, + R: Try<Output = Acc>, { - fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>( + fn scan<'a, T, St, B, Acc, R: Try<Output = Acc>>( state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option<B>, 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 e55c7a6bf5d..c358a6d12b7 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<Ok = Acc>, + R: Try<Output = Acc>, { let n = self.n; self.n = 0; @@ -146,9 +146,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<T, Acc, R: Try<Ok = Acc>>( + fn check<T, Acc, R: Try<Output = Acc>>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> { diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index efcb469fc95..93e29edc8df 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<Ok = Acc>, + R: Try<Output = Acc>, { 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 2ba56eeccba..4252c34a0e0 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<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { @@ -187,7 +187,7 @@ where fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn nth_back<I: DoubleEndedIterator>( diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 54a47f1323e..92f82ae2325 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<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<'a, T, Acc, R: Try<Ok = Acc>>( + fn check<'a, T, Acc, R: Try<Output = Acc>>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a { @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { 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 746eb41f4c3..93457d20f7c 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<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<'a, T, Acc, R: Try<Ok = Acc>>( + fn check<'a, T, Acc, R: Try<Output = Acc>>( 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 5e39e71252f..8d0b2b9f55c 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -755,7 +755,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { if self.is_empty() { return try { init }; @@ -860,7 +860,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { 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 6f8cb6b5a65..c302502b3b7 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<Ok = B>, + R: Try<Output = B>, { 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 da9e5fde7cc..777e4bc2c89 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<Ok = B>, + R: Try<Output = B>, { 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<Ok = ()>, + R: Try<Output = ()>, { #[inline] fn call<T, R>(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<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E> + where + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: Try<Output = bool>, + // 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<Residual = Result<crate::convert::Infallible, E>>, + { + #[inline] + fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>> + where + F: FnMut(&T) -> R, + R: Try<Output = bool>, + R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>, + { + 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<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error> where Self: Sized, F: FnMut(&Self::Item) -> R, - R: Try<Ok = bool>, + R: Try<Output = bool>, { #[inline] fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>> where F: FnMut(&T) -> R, - R: Try<Ok = bool>, + R: Try<Output = bool>, { 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 ecaff053bd5..dbb51540bd4 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<B, C = ()> { /// 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<A, B>` <-> `Result<B, A>` @@ -62,11 +63,11 @@ pub enum ControlFlow<B, C = ()> { } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] -impl<B, C> Try for ControlFlow<B, C> { - type Ok = C; +impl<B, C> ops::TryV1 for ControlFlow<B, C> { + type Output = C; type Error = B; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { ControlFlow::Continue(y) => Ok(y), ControlFlow::Break(x) => Err(x), @@ -77,7 +78,7 @@ impl<B, C> Try for ControlFlow<B, C> { 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<B, C> ControlFlow<B, C> { } } -impl<R: Try> ControlFlow<R, R::Ok> { +#[cfg(bootstrap)] +impl<R: ops::TryV1> ControlFlow<R, R::Output> { /// 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<R: ops::TryV2> ControlFlow<R, R::Output> { + /// 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<R: Try> ControlFlow<R, R::Ok> { #[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 1b07936ccde..beef74de617 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 3bede569978..9d659e78d3c 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<Self::Ok, Self::Error>; + fn into_result(self) -> Result<Self::Output, Self::Error>; /// 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 0c819b000aa..87044ed2fce 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<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// 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<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// 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<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// 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<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// 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!(<Result<_, String> as Try>::from_output(3), Ok(3)); /// assert_eq!(<Option<_> 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::<String, _>(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<Self::Residual, Self::Output>; } -/// 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<T, E>", + R = "std::option::Option<std::convert::Infallible>" + ), + 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<T, E>", + ), + // 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<T>", + ), + // `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<B, C>", + ), + message = "the `?` operator can only be used on `ControlFlow<B, _>`s \ + in {ItemContext} that returns `ControlFlow<B, _>`", + 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<R = <Self as Try>::Residual> { /// Constructs the type from a compatible `Residual` type. @@ -238,6 +314,7 @@ pub trait FromResidual<R = <Self as Try>::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 04551dded8c..c5b1c804ead 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1644,8 +1644,8 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { pub struct NoneError; #[unstable(feature = "try_trait", issue = "42327")] -impl<T> ops::Try for Option<T> { - type Ok = T; +impl<T> ops::TryV1 for Option<T> { + type Output = T; type Error = NoneError; #[inline] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e0071f806aa..21e406194bc 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1627,8 +1627,8 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } #[unstable(feature = "try_trait", issue = "42327")] -impl<T, E> ops::Try for Result<T, E> { - type Ok = T; +impl<T, E> ops::TryV1 for Result<T, E> { + type Output = T; type Error = E; #[inline] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 906dcb1e8bc..b92ab7e3475 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<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where Fold: FnMut(Acc, Self::Item) -> R, - R: ops::Try<Ok = Acc>, + R: ops::Try<Output = Acc>, { self.inner.try_fold(init, fold) } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 724137aba9f..6ec6b70b571 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<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc> + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc> { self.inner.try_fold(init, fold) } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 2765c21a46d..188639e7962 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<T> From<T> for Poll<T> { } #[stable(feature = "futures_api", since = "1.36.0")] -impl<T, E> Try for Poll<Result<T, E>> { - type Ok = Poll<T>; +impl<T, E> ops::TryV1 for Poll<Result<T, E>> { + type Output = Poll<T>; type Error = E; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), Poll::Ready(Err(e)) => Err(e), @@ -148,7 +148,7 @@ impl<T, E> Try for Poll<Result<T, E>> { } #[inline] - fn from_ok(x: Self::Ok) -> Self { + fn from_ok(x: Self::Output) -> Self { x.map(Ok) } } @@ -184,12 +184,12 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } #[stable(feature = "futures_api", since = "1.36.0")] -impl<T, E> Try for Poll<Option<Result<T, E>>> { - type Ok = Poll<Option<T>>; +impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> { + type Output = Poll<Option<T>>; type Error = E; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), Poll::Ready(Some(Err(e))) => Err(e), @@ -204,7 +204,7 @@ impl<T, E> Try for Poll<Option<Result<T, E>>> { } #[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 35e4d213dde..db12d79c00c 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 9470451278c..88ea15a3b33 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<u8, NoneError> { - let val = Some(1)?; - Ok(val) - } - assert_eq!(try_option_ok(), Ok(1)); - - fn try_option_err() -> Result<u8, NoneError> { - 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 c461ab380ad..f4e5e7751b8 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<u8> { - let val = Ok(1)?; - Some(val) - } - assert_eq!(try_result_some(), Some(1)); - - fn try_result_none() -> Option<u8> { - let val = Err(NoneError)?; - Some(val) - } - assert_eq!(try_result_none(), None); - - fn try_result_ok() -> Result<u8, u8> { + fn try_result_ok() -> Result<u8, u32> { let result: Result<u8, u8> = Ok(1); let val = result?; Ok(val) } assert_eq!(try_result_ok(), Ok(1)); - fn try_result_err() -> Result<u8, u8> { + fn try_result_err() -> Result<u8, u32> { let result: Result<u8, u8> = 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::<i32, i32>(4).branch(), Continue(4)); + assert_eq!(Err::<i32, i32>(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::<NonZeroU32, ()>(one).branch(), Continue(one)); + assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(()))); +} diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index 81e2435e5b8..3ff77163b9f 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -7,11 +7,28 @@ type R = Result<u64, i32>; +// 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<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +#[inline] +fn from_error<T, E>(e: E) -> Result<T, E> { + 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 c1421f20a0b..ba17a45f984 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<Box<u32>> { let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 let mut _2: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::result::Result<u32, std::option::NoneError>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 let mut _4: std::option::Option<u32>; // 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<std::convert::Infallible>; // 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<std::convert::Infallible>; // 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<Box<u32>> { 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::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = <Option<u32> 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<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) } } bb1: { @@ -43,12 +42,12 @@ fn test() -> Option<Box<u32>> { } 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<Box<u32>> { 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<std::convert::Infallible>); // 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 = <NoneError as From<NoneError>>::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 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::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 {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) } } bb5: { - StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = <Option<Box<u32>> 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(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) } - } - - 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::<Box<u32>>::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 50b5147e0cf..f7dcaa13449 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<u8, i32>) -> Result<u8, i32> { } } +fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +fn from_error<T, E>(e: E) -> Result<T, E> { + 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<u8, i32>) -> Result<u8, i32> { - 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 ccb3b71817f..a3bad4f0c62 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<u8, i32>) -> Result<u8, i32> { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 - let mut _0: std::result::Result<u8, i32>; // 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<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _4: std::result::Result<u8, i32>; // 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<u8, i32>; // 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<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result<u8, i32>; // 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 <i32 as From<i32>>::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 <Result<u8, i32> 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 <i32 as From<i32>>::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::<u8, i32>) { // 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 <Result<u8, i32> 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::<u8, i32>) { // 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 ec8ac30228e..b6b7511b3f5 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<u8, i32>) -> Result<u8, i32> { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 - let mut _0: std::result::Result<u8, i32>; // 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<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _4: std::result::Result<u8, i32>; // 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<u8, i32>; // 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<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result<u8, i32>; // 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 <i32 as From<i32>>::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 <Result<u8, i32> 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 <i32 as From<i32>>::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::<u8, i32>) { // 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 <Result<u8, i32> 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::<u8, i32>) { // 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 eb307de2074..15e351e7d50 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<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +fn from_error<T, E>(e: E) -> Result<T, E> { + 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<u32, i32>) -> Result<u32, i32> { - 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 b1bae447f9c..e09b8cb39bd 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<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // 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<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // 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 <i32 as From<i32>>::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 <Result<u32, i32> 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 <i32 as From<i32>>::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::<u32, i32>) { // 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 <Result<u32, i32> 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::<u32, i32>) { // 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 df274852f68..488ad33f80a 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<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // 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<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // 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 <i32 as From<i32>>::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 <Result<u32, i32> 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 <i32 as From<i32>>::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::<u32, i32>) { // 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 <Result<u32, i32> 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::<u32, i32>) { // 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 37274691fb4..5d829f859e9 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<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // 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<u32, i32>; // 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<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // 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 <i32 as From<i32>>::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 <Result<u32, i32> 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 <i32 as From<i32>>::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::<u32, i32>) { // 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 <Result<u32, i32> 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::<u32, i32>) { // 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 f8adcced4b3..1b5232422b6 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<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // 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<u32, i32>; // 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 <i32 as From<i32>>::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 <Result<u32, i32> 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 <i32 as From<i32>>::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::<u32, i32>) { // 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 <Result<u32, i32> 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::<u32, i32>) { // 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 4a8e841b33d..9fe3313ee6c 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 fd00522fac7..ad661fb2833 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 8e7823f3571..a3f122a4663 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<u32> = 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<Option<Infallible>>` 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<u32> = 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<Option<Infallible>>` 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<u32> = 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<Option<Infallible>>` 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 2e96022318b..7beb2db3969 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 2875cef6801..8e632fbc1de 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 <https://github.com/rust-lang/rust/issues/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<std::io::Error>` + | --- 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 05f62f3d8cb..e7fabd0ffbc 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 282bc13e9e7..23360483361 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<std::io::Error>` +... +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 211ae13e46d..a6ddb7ae908 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 8f48483c254..6e84b6d5ad0 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 0dcce9e990b..e055d1a94ff 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 86e2126e1ae..c394f6efbda 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<Infallible>` 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 cc12c153621..2d020188198 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<Result<Infallible, {integer}>>` for `Result<i32, ()>` + = 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 551b9f4650a..00000000000 --- 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<NoneError>` 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<T>` into a `Result<T, _>` 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<i32>{ - | ----------- expected `NoneError` because of this -LL | let a:Result<i32, i32> = Ok(5); -LL | a?; - | ^ the trait `From<i32>` 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<T, _>` into an `Option<T>` 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 381959b7ae4..db5042b40d8 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::<B>()? @@ -13,4 +12,4 @@ LL | l.iter().map(f).collect::<B>()? 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 1adce5e0150..6985f1b71a8 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 5c9c549fa07..eb67170d47c 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 ef6e690e1bd..30ae96763c0 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<i32, i32> = 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 75a42c0d6b7..ec5e91f10c2 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: <TryFromSliceError as From<Infallible>> - = note: required by `from` + = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>` + = note: required by `from_residual` -error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == &str` +error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `i32`, found `&str` -error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == ()` +error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result<i32, i32> = 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 5d8748f1dd3..69793df525e 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 75a4e8d065c..c83351d5c43 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 df1441c83d4..3e9a584a551 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 `<Option<f32> as Try>::Ok == {integer}` +error[E0271]: type mismatch resolving `<Option<f32> 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 `<Option<i32> as Try>::Ok == ()` +error[E0271]: type mismatch resolving `<Option<i32> 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 ecd12c430f1..00000000000 --- 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<u32, ()> { - | --------------- expected `()` because of this -LL | let x: Option<u32> = None; -LL | x?; - | ^ the trait `From<NoneError>` 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<T>` into a `Result<T, _>` 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<u32> = 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 9993061ea61..00000000000 --- 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<T, U> { - Awesome(T), - Terrible(U) -} - -impl<U, V> Try for MyResult<U, V> { - type Ok = U; - type Error = V; - - fn from_ok(u: U) -> MyResult<U, V> { - MyResult::Awesome(u) - } - - fn from_error(e: V) -> MyResult<U, V> { - MyResult::Terrible(e) - } - - fn into_result(self) -> Result<U, V> { - match self { - MyResult::Awesome(u) => Ok(u), - MyResult::Terrible(e) => Err(e), - } - } -} - -fn f(x: i32) -> Result<i32, String> { - if x == 0 { - Ok(42) - } else { - let y = g(x)?; - Ok(y) - } -} - -fn g(x: i32) -> MyResult<i32, String> { - let _y = f(x - 1)?; - MyResult::Terrible("Hello".to_owned()) -} - -fn h() -> MyResult<i32, String> { - let a: Result<i32, &'static str> = Err("Hello"); - let b = a?; - MyResult::Awesome(b) -} - -fn i() -> MyResult<i32, String> { - let a: MyResult<i32, &'static str> = 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 00000000000..87585822f57 --- /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<u64, u8> { + Ok(Err(123_i32)?) + //~^ ERROR `?` couldn't convert the error to `u8` +} + +fn option_to_result() -> Result<u64, String> { + 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<u64, String> { + 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<u16> { + 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<u64> { + 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<String> { + ControlFlow::Continue(Err("hello")?) + //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>` +} + +fn option_to_control_flow() -> ControlFlow<u64> { + Some(3)?; + //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>` + ControlFlow::Break(10) +} + +fn control_flow_to_control_flow() -> ControlFlow<i64> { + ControlFlow::Break(4_u8)?; + //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>` + 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 00000000000..e396256de22 --- /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<u64, u8> { + | --------------- expected `u8` because of this +LL | Ok(Err(123_i32)?) + | ^ the trait `From<i32>` 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: + <u8 as From<NonZeroU8>> + <u8 as From<bool>> + = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>` + = 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<u64, String> { +LL | | Some(3)?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>` +LL | | +LL | | Ok(10) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>` + = 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<u64, String> { +LL | | Ok(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>` +LL | | +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>` + = 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<u16> { +LL | | Some(Err("hello")?) + | | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `Option<u16>` +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>` + = 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<u64> { +LL | | Some(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>` +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>` + --> $DIR/bad-interconversion.rs:32:39 + | +LL | / fn result_to_control_flow() -> ControlFlow<String> { +LL | | ControlFlow::Continue(Err("hello")?) + | | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>` +LL | | +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>` + = 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<B, _>`s in a function that returns `ControlFlow<B, _>` + --> $DIR/bad-interconversion.rs:37:12 + | +LL | / fn option_to_control_flow() -> ControlFlow<u64> { +LL | | Some(3)?; + | | ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>` +LL | | +LL | | ControlFlow::Break(10) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>` + = 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<B, _>`s in a function that returns `ControlFlow<B, _>` + --> $DIR/bad-interconversion.rs:43:29 + | +LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> { +LL | | ControlFlow::Break(4_u8)?; + | | ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>` +LL | | +LL | | ControlFlow::Continue(()) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<ControlFlow<u8, Infallible>>` is not implemented for `ControlFlow<i64>` + = 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 index 00e8b5244c5..45aaf361a9c 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<i32>{ let a:Result<i32, i32> = 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 00000000000..92087c2aba2 --- /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<Option<Infallible>>` 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<i32>{ +LL | | let a:Result<i32, i32> = Ok(5); +LL | | a?; + | | ^ this `?` produces `Result<Infallible, i32>`, which is incompatible with `Option<i32>` +LL | | Some(5) +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>` + = 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 00000000000..cf09838b304 --- /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<T: Try>(x: <T as Try>::Output) -> T { + T::from_output(x) +} + +fn monad_bind<T1: Try<Residual = R>, T2: Try<Residual = R>, R>( + mx: T1, + f: impl FnOnce(<T1 as Try>::Output) -> T2) +-> T2 { + let x = mx?; + f(x) +} + +fn main() { + let mx: Option<i32> = 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 index 63d17414c31..63d17414c31 100644 --- a/src/test/ui/try-on-option-diagnostics.rs +++ b/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 index a71ee20aacf..e7c67c21bb3 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<u32> = 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<Option<Infallible>>` 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<u32> = 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<Option<Infallible>>` 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<u32> = 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<Option<Infallible>>` 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<u32> = 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<Option<Infallible>>` 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 index 5d94cee8e37..f2012936a11 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<u32, ()> { let x: Option<u32> = 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 00000000000..604baa8550b --- /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<u32, ()> { +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>` +LL | | Ok(22) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>` + = 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<u32> = 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<Option<Infallible>>` 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 00000000000..45636a7fced --- /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<T, U> { + Awesome(T), + Terrible(U) +} + +enum Never {} + +impl<U, V> Try for MyResult<U, V> { + type Output = U; + type Residual = MyResult<Never, V>; + + fn from_output(u: U) -> MyResult<U, V> { + MyResult::Awesome(u) + } + + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + MyResult::Awesome(u) => ControlFlow::Continue(u), + MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)), + } + } +} + +impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> { + fn from_residual(x: MyResult<Never, V>) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => MyResult::Terrible(e.into()), + } + } +} + +type ResultResidual<E> = Result<std::convert::Infallible, E>; + +impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> { + fn from_residual(x: ResultResidual<V>) -> Self { + match x { + Ok(v) => match v {} + Err(e) => MyResult::Terrible(e.into()), + } + } +} + +impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> { + fn from_residual(x: MyResult<Never, V>) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => Err(e.into()), + } + } +} + +fn f(x: i32) -> Result<i32, String> { + if x == 0 { + Ok(42) + } else { + let y = g(x)?; + Ok(y) + } +} + +fn g(x: i32) -> MyResult<i32, String> { + let _y = f(x - 1)?; + MyResult::Terrible("Hello".to_owned()) +} + +fn h() -> MyResult<i32, String> { + let a: Result<i32, &'static str> = Err("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn i() -> MyResult<i32, String> { + let a: MyResult<i32, &'static str> = 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 index e1b6cfbe5ae..3b364f7e7d3 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: Try>() -> 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 index be17de2fe7c..7d42c2e4d10 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<Result<Infallible, std::io::Error>>` 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: Try>() -> 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 index d42e51c7405..d42e51c7405 100644 --- a/src/test/ui/try-poll.rs +++ b/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 7b156a8c49d..d8417c7dc70 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 ebb39ea4877..f2ba2b2ecf6 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 3387f35bac3..c27a6d4e347 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); } |
