1
Fork 0

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.
This commit is contained in:
bors 2021-05-18 20:50:01 +00:00
commit 4e3e6db011
91 changed files with 1179 additions and 801 deletions

View file

@ -560,8 +560,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
) )
} }
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`, /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }` /// `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. /// 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> { fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
self.with_catch_scope(body.id, |this| { self.with_catch_scope(body.id, |this| {
@ -590,9 +590,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ok_wrapped_span = let ok_wrapped_span =
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None); 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( block.expr = Some(this.wrap_in_try_constructor(
hir::LangItem::TryFromOk, hir::LangItem::TryTraitFromOutput,
try_span, try_span,
tail_expr, tail_expr,
ok_wrapped_span, ok_wrapped_span,
@ -1579,14 +1579,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.allow_try_trait.clone(), self.allow_try_trait.clone(),
); );
// `Try::into_result(<expr>)` // `Try::branch(<expr>)`
let scrutinee = { let scrutinee = {
// expand <expr> // expand <expr>
let sub_expr = self.lower_expr_mut(sub_expr); let sub_expr = self.lower_expr_mut(sub_expr);
self.expr_call_lang_item_fn( self.expr_call_lang_item_fn(
unstable_span, unstable_span,
hir::LangItem::TryIntoResult, hir::LangItem::TryTraitBranch,
arena_vec![self; sub_expr], arena_vec![self; sub_expr],
) )
}; };
@ -1604,8 +1604,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}; };
let attrs = vec![attr]; let attrs = vec![attr];
// `Ok(val) => #[allow(unreachable_code)] val,` // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
let ok_arm = { let continue_arm = {
let val_ident = Ident::with_dummy_span(sym::val); let val_ident = Ident::with_dummy_span(sym::val);
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
let val_expr = self.arena.alloc(self.expr_ident_with_attrs( let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
@ -1614,27 +1614,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
val_pat_nid, val_pat_nid,
ThinVec::from(attrs.clone()), ThinVec::from(attrs.clone()),
)); ));
let ok_pat = self.pat_ok(span, val_pat); let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
self.arm(ok_pat, val_expr) self.arm(continue_pat, val_expr)
}; };
// `Err(err) => #[allow(unreachable_code)] // `ControlFlow::Break(residual) =>
// return Try::from_error(From::from(err)),` // #[allow(unreachable_code)]
let err_arm = { // return Try::from_residual(residual),`
let err_ident = Ident::with_dummy_span(sym::err); let break_arm = {
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let residual_ident = Ident::with_dummy_span(sym::residual);
let from_expr = { let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid); let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
self.expr_call_lang_item_fn( let from_residual_expr = self.wrap_in_try_constructor(
try_span, hir::LangItem::TryTraitFromResidual,
hir::LangItem::FromFrom, try_span,
arena_vec![self; err_expr], self.arena.alloc(residual_expr),
)
};
let from_err_expr = self.wrap_in_try_constructor(
hir::LangItem::TryFromError,
unstable_span,
from_expr,
unstable_span, unstable_span,
); );
let thin_attrs = ThinVec::from(attrs); let thin_attrs = ThinVec::from(attrs);
@ -1645,25 +1639,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
try_span, try_span,
hir::ExprKind::Break( hir::ExprKind::Break(
hir::Destination { label: None, target_id }, hir::Destination { label: None, target_id },
Some(from_err_expr), Some(from_residual_expr),
), ),
thin_attrs, thin_attrs,
)) ))
} else { } else {
self.arena.alloc(self.expr( self.arena.alloc(self.expr(
try_span, try_span,
hir::ExprKind::Ret(Some(from_err_expr)), hir::ExprKind::Ret(Some(from_residual_expr)),
thin_attrs, thin_attrs,
)) ))
}; };
let err_pat = self.pat_err(try_span, err_local); let break_pat = self.pat_cf_break(try_span, residual_local);
self.arm(err_pat, ret_expr) self.arm(break_pat, ret_expr)
}; };
hir::ExprKind::Match( hir::ExprKind::Match(
scrutinee, scrutinee,
arena_vec![self; err_arm, ok_arm], arena_vec![self; break_arm, continue_arm],
hir::MatchSource::TryDesugar, hir::MatchSource::TryDesugar,
) )
} }

View file

@ -332,7 +332,7 @@ pub fn lower_crate<'a, 'hir>(
lifetimes_to_define: Vec::new(), lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false, is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(), 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()), allow_gen_future: Some([sym::gen_future][..].into()),
} }
.lower_crate(krate) .lower_crate(krate)
@ -2490,14 +2490,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.pat(span, hir::PatKind::Lit(expr)) 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); 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); 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> { fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {

View file

@ -308,12 +308,12 @@ language_item_table! {
Termination, sym::termination, termination, Target::Trait; 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 // Language items from AST lowering
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false });
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false });
TryIntoResult, sym::into_result, into_result_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; PollReady, sym::Ready, poll_ready_variant, Target::Variant;
PollPending, sym::Pending, poll_pending_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; ResultOk, sym::Ok, result_ok_variant, Target::Variant;
ResultErr, sym::Err, result_err_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 }); IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});

View file

@ -130,10 +130,12 @@ symbols! {
BTreeSet, BTreeSet,
BinaryHeap, BinaryHeap,
Borrow, Borrow,
Break,
C, C,
CString, CString,
Center, Center,
Clone, Clone,
Continue,
Copy, Copy,
Count, Count,
Debug, Debug,
@ -326,6 +328,7 @@ symbols! {
box_patterns, box_patterns,
box_syntax, box_syntax,
braced_empty_structs, braced_empty_structs,
branch,
breakpoint, breakpoint,
bridge, bridge,
bswap, bswap,
@ -411,6 +414,7 @@ symbols! {
constructor, constructor,
contents, contents,
context, context,
control_flow_enum,
convert, convert,
copy, copy,
copy_closures, copy_closures,
@ -511,7 +515,6 @@ symbols! {
env, env,
eq, eq,
ermsb_target_feature, ermsb_target_feature,
err,
exact_div, exact_div,
except, except,
exchange_malloc, exchange_malloc,
@ -581,10 +584,10 @@ symbols! {
frem_fast, frem_fast,
from, from,
from_desugaring, from_desugaring,
from_error,
from_generator, from_generator,
from_method, from_method,
from_ok, from_output,
from_residual,
from_size_align_unchecked, from_size_align_unchecked,
from_trait, from_trait,
from_usize, from_usize,
@ -653,7 +656,6 @@ symbols! {
instruction_set, instruction_set,
intel, intel,
into_iter, into_iter,
into_result,
into_trait, into_trait,
intra_doc_pointers, intra_doc_pointers,
intrinsics, intrinsics,
@ -965,6 +967,7 @@ symbols! {
repr_packed, repr_packed,
repr_simd, repr_simd,
repr_transparent, repr_transparent,
residual,
result, result,
result_type, result_type,
rhs, rhs,
@ -1232,7 +1235,7 @@ symbols! {
try_blocks, try_blocks,
try_from_trait, try_from_trait,
try_into_trait, try_into_trait,
try_trait, try_trait_v2,
tt, tt,
tuple, tuple,
tuple_from_req, tuple_from_req,

View file

@ -66,7 +66,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let (mut iter, final_res); let (mut iter, final_res);
if self.tail <= self.head { if self.tail <= self.head {
@ -140,7 +140,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let (mut iter, final_res); let (mut iter, final_res);
if self.tail <= self.head { if self.tail <= self.head {

View file

@ -140,7 +140,8 @@
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
#![feature(alloc_layout_extra)] #![feature(alloc_layout_extra)]
#![feature(trusted_random_access)] #![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(min_type_alias_impl_trait)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(slice_group_by)] #![feature(slice_group_by)]

View file

@ -98,7 +98,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(Acc, Self::Item) -> R, F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
if let Some(ref mut a) = self.a { if let Some(ref mut a) = self.a {
acc = a.try_fold(acc, &mut f)?; acc = a.try_fold(acc, &mut f)?;
@ -281,7 +281,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(Acc, Self::Item) -> R, F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
if let Some(ref mut b) = self.b { if let Some(ref mut b) = self.b {
acc = b.try_rfold(acc, &mut f)?; acc = b.try_rfold(acc, &mut f)?;

View file

@ -46,7 +46,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.it.try_fold(init, clone_try_fold(f)) self.it.try_fold(init, clone_try_fold(f))
} }
@ -82,7 +82,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.it.try_rfold(init, clone_try_fold(f)) self.it.try_rfold(init, clone_try_fold(f))
} }

View file

@ -50,7 +50,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.it.try_fold(init, copy_try_fold(f)) self.it.try_fold(init, copy_try_fold(f))
} }
@ -98,7 +98,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.it.try_rfold(init, copy_try_fold(f)) self.it.try_rfold(init, copy_try_fold(f))
} }

View file

@ -53,7 +53,7 @@ where
fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
where where
F: FnMut(Acc, Self::Item) -> R, F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
// fully iterate the current iterator. this is necessary because // fully iterate the current iterator. this is necessary because
// `self.iter` may be empty even when `self.orig` isn't // `self.iter` may be empty even when `self.orig` isn't

View file

@ -71,7 +71,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
#[inline] #[inline]
fn enumerate<'a, T, Acc, R>( fn enumerate<'a, T, Acc, R>(
@ -150,7 +150,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
// Can safely add and subtract the count, as `ExactSizeIterator` promises // Can safely add and subtract the count, as `ExactSizeIterator` promises
// that the number of elements fits into a `usize`. // that the number of elements fits into a `usize`.

View file

@ -37,7 +37,7 @@ fn filter_fold<T, Acc>(
move |acc, item| if predicate(&item) { fold(acc, item) } else { 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, predicate: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a, mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a { ) -> impl FnMut(Acc, T) -> R + 'a {
@ -88,7 +88,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
} }
@ -117,7 +117,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
} }

View file

@ -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>, f: &'a mut impl FnMut(T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a, mut fold: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a { ) -> impl FnMut(Acc, T) -> R + 'a {
@ -72,7 +72,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
} }
@ -111,7 +111,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
} }

View file

@ -61,7 +61,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
self.inner.try_fold(init, fold) self.inner.try_fold(init, fold)
} }
@ -91,7 +91,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
self.inner.try_rfold(init, fold) self.inner.try_rfold(init, fold)
} }
@ -178,7 +178,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
self.inner.try_fold(init, fold) self.inner.try_fold(init, fold)
} }
@ -208,7 +208,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
self.inner.try_rfold(init, fold) self.inner.try_rfold(init, fold)
} }
@ -293,10 +293,10 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
#[inline] #[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>, frontiter: &'a mut Option<T::IntoIter>,
fold: &'a mut impl FnMut(Acc, T::Item) -> R, fold: &'a mut impl FnMut(Acc, T::Item) -> R,
) -> impl FnMut(Acc, T) -> R + 'a { ) -> impl FnMut(Acc, T) -> R + 'a {
@ -382,10 +382,10 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
#[inline] #[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>, backiter: &'a mut Option<T::IntoIter>,
fold: &'a mut impl FnMut(Acc, T::Item) -> R, fold: &'a mut impl FnMut(Acc, T::Item) -> R,
) -> impl FnMut(Acc, T) -> R + 'a ) -> impl FnMut(Acc, T) -> R + 'a

View file

@ -92,7 +92,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
FuseImpl::try_fold(self, acc, fold) FuseImpl::try_fold(self, acc, fold)
} }
@ -148,7 +148,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
FuseImpl::try_rfold(self, acc, fold) FuseImpl::try_rfold(self, acc, fold)
} }
@ -219,7 +219,7 @@ trait FuseImpl<I> {
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>; R: Try<Output = Acc>;
fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
where where
Fold: FnMut(Acc, Self::Item) -> Acc; Fold: FnMut(Acc, Self::Item) -> Acc;
@ -238,7 +238,7 @@ trait FuseImpl<I> {
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
I: DoubleEndedIterator; I: DoubleEndedIterator;
fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
where where
@ -305,7 +305,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
if let Some(ref mut iter) = self.iter { if let Some(ref mut iter) = self.iter {
acc = iter.try_fold(acc, fold)?; acc = iter.try_fold(acc, fold)?;
@ -354,7 +354,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
if let Some(ref mut iter) = self.iter { if let Some(ref mut iter) = self.iter {
@ -443,7 +443,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
unchecked!(self).try_fold(init, fold) unchecked!(self).try_fold(init, fold)
} }
@ -485,7 +485,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
I: DoubleEndedIterator, I: DoubleEndedIterator,
{ {
unchecked!(self).try_rfold(init, fold) unchecked!(self).try_rfold(init, fold)

View file

@ -87,7 +87,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
} }
@ -117,7 +117,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
} }

View file

@ -110,7 +110,7 @@ where
where where
Self: Sized, Self: Sized,
G: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_fold(init, map_try_fold(&mut self.f, g))
} }
@ -146,7 +146,7 @@ where
where where
Self: Sized, Self: Sized,
G: FnMut(Acc, Self::Item) -> R, 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)) self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
} }

View file

@ -54,7 +54,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
let Self { iter, predicate } = self; let Self { iter, predicate } = self;
iter.try_fold(init, |acc, x| match predicate(x) { iter.try_fold(init, |acc, x| match predicate(x) {

View file

@ -168,7 +168,7 @@ where
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
where where
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let error = &mut *self.error; let error = &mut *self.error;
self.iter self.iter

View file

@ -1,5 +1,5 @@
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; 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 /// An iterator with a `peek()` that returns an optional reference to the next
/// element. /// element.
@ -91,7 +91,7 @@ impl<I: Iterator> Iterator for Peekable<I> {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let acc = match self.peeked.take() { let acc = match self.peeked.take() {
Some(None) => return try { init }, Some(None) => return try { init },
@ -130,19 +130,42 @@ where
} }
#[inline] #[inline]
#[cfg(not(bootstrap))]
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, 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() { match self.peeked.take() {
Some(None) => try { init }, Some(None) => try { init },
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
Ok(acc) => f(acc, v), Ok(acc) => f(acc, v),
Err(e) => { Err(e) => {
self.peeked = Some(Some(v)); self.peeked = Some(Some(v));
Try::from_error(e) R::from_error(e)
} }
}, },
None => self.iter.try_rfold(init, f), None => self.iter.try_rfold(init, f),

View file

@ -51,7 +51,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.iter.try_rfold(init, f) self.iter.try_rfold(init, f)
} }
@ -96,7 +96,7 @@ where
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
self.iter.try_fold(init, f) self.iter.try_fold(init, f)
} }

View file

@ -56,9 +56,9 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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, state: &'a mut St,
f: &'a mut impl FnMut(&mut St, T) -> Option<B>, f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a, mut fold: impl FnMut(Acc, B) -> R + 'a,

View file

@ -88,7 +88,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
let n = self.n; let n = self.n;
self.n = 0; self.n = 0;
@ -146,9 +146,9 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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 n: usize,
mut fold: impl FnMut(Acc, T) -> R, mut fold: impl FnMut(Acc, T) -> R,
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> { ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {

View file

@ -70,7 +70,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
if !self.flag { if !self.flag {
match self.next() { match self.next() {

View file

@ -111,7 +111,7 @@ where
fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
where where
F: FnMut(Acc, Self::Item) -> R, F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
#[inline] #[inline]
fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { 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 fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
where where
F: FnMut(Acc, Self::Item) -> R, F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
#[inline] #[inline]
fn nth_back<I: DoubleEndedIterator>( fn nth_back<I: DoubleEndedIterator>(

View file

@ -80,9 +80,9 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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, n: &'a mut usize,
mut fold: impl FnMut(Acc, T) -> R + 'a, mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a { ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
@ -178,7 +178,7 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>, R: Try<Output = Acc>,
{ {
if self.n == 0 { if self.n == 0 {
try { init } try { init }

View file

@ -68,9 +68,9 @@ where
where where
Self: Sized, Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R, 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, flag: &'a mut bool,
p: &'a mut impl FnMut(&T) -> bool, p: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a, mut fold: impl FnMut(Acc, T) -> R + 'a,

View file

@ -755,7 +755,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
if self.is_empty() { if self.is_empty() {
return try { init }; return try { init };
@ -860,7 +860,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
if self.is_empty() { if self.is_empty() {
return try { init }; return try { init };

View file

@ -218,7 +218,7 @@ pub trait DoubleEndedIterator: Iterator {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let mut accum = init; let mut accum = init;
while let Some(x) = self.next_back() { while let Some(x) = self.next_back() {

View file

@ -1999,7 +1999,7 @@ pub trait Iterator {
where where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>, R: Try<Output = B>,
{ {
let mut accum = init; let mut accum = init;
while let Some(x) = self.next() { while let Some(x) = self.next() {
@ -2041,7 +2041,7 @@ pub trait Iterator {
where where
Self: Sized, Self: Sized,
F: FnMut(Self::Item) -> R, F: FnMut(Self::Item) -> R,
R: Try<Ok = ()>, R: Try<Output = ()>,
{ {
#[inline] #[inline]
fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
@ -2412,17 +2412,48 @@ pub trait Iterator {
/// ``` /// ```
#[inline] #[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")] #[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> fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
where where
Self: Sized, Self: Sized,
F: FnMut(&Self::Item) -> R, F: FnMut(&Self::Item) -> R,
R: Try<Ok = bool>, R: Try<Output = bool>,
{ {
#[inline] #[inline]
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>> fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
where where
F: FnMut(&T) -> R, F: FnMut(&T) -> R,
R: Try<Ok = bool>, R: Try<Output = bool>,
{ {
move |(), x| match f(&x).into_result() { move |(), x| match f(&x).into_result() {
Ok(false) => ControlFlow::CONTINUE, Ok(false) => ControlFlow::CONTINUE,

View file

@ -1,5 +1,4 @@
use crate::convert; use crate::{convert, ops};
use crate::ops::{self, Try};
/// Used to tell an operation whether it should exit early or go on as usual. /// 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)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> { pub enum ControlFlow<B, C = ()> {
/// Move on to the next phase of the operation as normal. /// Move on to the next phase of the operation as normal.
#[cfg_attr(not(bootstrap), lang = "Continue")]
Continue(C), Continue(C),
/// Exit the operation without running subsequent phases. /// Exit the operation without running subsequent phases.
#[cfg_attr(not(bootstrap), lang = "Break")]
Break(B), Break(B),
// Yes, the order of the variants doesn't match the type parameters. // 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>` // 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")] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
impl<B, C> Try for ControlFlow<B, C> { impl<B, C> ops::TryV1 for ControlFlow<B, C> {
type Ok = C; type Output = C;
type Error = B; type Error = B;
#[inline] #[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> { fn into_result(self) -> Result<Self::Output, Self::Error> {
match self { match self {
ControlFlow::Continue(y) => Ok(y), ControlFlow::Continue(y) => Ok(y),
ControlFlow::Break(x) => Err(x), ControlFlow::Break(x) => Err(x),
@ -77,7 +78,7 @@ impl<B, C> Try for ControlFlow<B, C> {
ControlFlow::Break(v) ControlFlow::Break(v)
} }
#[inline] #[inline]
fn from_ok(v: Self::Ok) -> Self { fn from_ok(v: Self::Output) -> Self {
ControlFlow::Continue(v) ControlFlow::Continue(v)
} }
} }
@ -182,14 +183,15 @@ 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`. /// Create a `ControlFlow` from any type implementing `Try`.
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline] #[inline]
pub fn from_try(r: R) -> Self { pub fn from_try(r: R) -> Self {
match Try::into_result(r) { match R::into_result(r) {
Ok(v) => ControlFlow::Continue(v), Ok(v) => ControlFlow::Continue(v),
Err(v) => ControlFlow::Break(Try::from_error(v)), Err(v) => ControlFlow::Break(R::from_error(v)),
} }
} }
@ -198,7 +200,30 @@ impl<R: Try> ControlFlow<R, R::Ok> {
#[inline] #[inline]
pub fn into_try(self) -> R { pub fn into_try(self) -> R {
match self { match self {
ControlFlow::Continue(v) => Try::from_ok(v), 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)),
}
}
/// Convert a `ControlFlow` into any type implementing `Try`;
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_output(v),
ControlFlow::Break(v) => v, ControlFlow::Break(v) => v,
} }
} }

View file

@ -183,13 +183,21 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
#[unstable(feature = "try_trait", issue = "42327")] #[unstable(feature = "try_trait", issue = "42327")]
#[cfg(bootstrap)]
pub use self::r#try::Try; 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")] #[unstable(feature = "try_trait_v2", issue = "84277")]
pub use self::try_trait::FromResidual; 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")] #[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")] #[unstable(feature = "generator_trait", issue = "43122")]
pub use self::generator::{Generator, GeneratorState}; pub use self::generator::{Generator, GeneratorState};

View file

@ -25,11 +25,11 @@
) )
)] )]
#[doc(alias = "?")] #[doc(alias = "?")]
#[lang = "try"] #[cfg_attr(bootstrap, lang = "try")]
pub trait Try { pub trait Try {
/// The type of this value when viewed as successful. /// The type of this value when viewed as successful.
#[unstable(feature = "try_trait", issue = "42327")] #[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. /// The type of this value when viewed as failed.
#[unstable(feature = "try_trait", issue = "42327")] #[unstable(feature = "try_trait", issue = "42327")]
type Error; type Error;
@ -43,19 +43,19 @@ pub trait Try {
/// in the return type of the enclosing scope (which must itself implement /// in the return type of the enclosing scope (which must itself implement
/// `Try`). Specifically, the value `X::from_error(From::from(e))` /// `Try`). Specifically, the value `X::from_error(From::from(e))`
/// is returned, where `X` is the return type of the enclosing function. /// 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")] #[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, /// Wrap an error value to construct the composite result. For example,
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent. /// `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")] #[unstable(feature = "try_trait", issue = "42327")]
fn from_error(v: Self::Error) -> Self; fn from_error(v: Self::Error) -> Self;
/// Wrap an OK value to construct the composite result. For example, /// Wrap an OK value to construct the composite result. For example,
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. /// `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")] #[unstable(feature = "try_trait", issue = "42327")]
fn from_ok(v: Self::Ok) -> Self; fn from_ok(v: Self::Output) -> Self;
} }

View file

@ -41,8 +41,7 @@ use crate::ops::ControlFlow;
/// output type that we want: /// output type that we want:
/// ``` /// ```
/// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)] /// # use std::ops::Try;
/// # use std::ops::TryV2 as Try;
/// fn simple_try_fold_1<A, T, R: Try<Output = A>>( /// fn simple_try_fold_1<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>, /// iter: impl Iterator<Item = T>,
/// mut accum: A, /// mut accum: A,
@ -56,9 +55,8 @@ use crate::ops::ControlFlow;
/// into the return type using [`Try::from_output`]: /// into the return type using [`Try::from_output`]:
/// ``` /// ```
/// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # #![feature(control_flow_enum)] /// # #![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>>( /// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>, /// iter: impl Iterator<Item = T>,
/// mut accum: A, /// mut accum: A,
@ -81,9 +79,8 @@ use crate::ops::ControlFlow;
/// recreated from their corresponding residual, so we'll just call it: /// recreated from their corresponding residual, so we'll just call it:
/// ``` /// ```
/// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # #![feature(control_flow_enum)] /// # #![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>>( /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>, /// iter: impl Iterator<Item = T>,
/// mut accum: A, /// 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 /// 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 /// `Break`" is exactly what happens inside the `?` operator. So rather than
/// do all this manually, we can just use `?` instead: /// 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_v2)]
/// # #![feature(try_trait_transition)] /// # use std::ops::Try;
/// # use std::ops::TryV2 as Try;
/// fn simple_try_fold<A, T, R: Try<Output = A>>( /// fn simple_try_fold<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>, /// iter: impl Iterator<Item = T>,
/// mut accum: A, /// mut accum: A,
@ -119,6 +115,22 @@ use crate::ops::ControlFlow;
/// } /// }
/// ``` /// ```
#[unstable(feature = "try_trait_v2", issue = "84277")] #[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 { pub trait Try: FromResidual {
/// The type of the value produced by `?` when *not* short-circuiting. /// The type of the value produced by `?` when *not* short-circuiting.
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
@ -159,8 +171,7 @@ pub trait Try: FromResidual {
/// ``` /// ```
/// #![feature(try_trait_v2)] /// #![feature(try_trait_v2)]
/// #![feature(control_flow_enum)] /// #![feature(control_flow_enum)]
/// #![feature(try_trait_transition)] /// use std::ops::Try;
/// use std::ops::TryV2 as Try;
/// ///
/// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
/// assert_eq!(<Option<_> as Try>::from_output(4), Some(4)); /// 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!() }); /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
/// assert_eq!(r, Some(4)); /// assert_eq!(r, Some(4));
/// ``` /// ```
#[cfg_attr(not(bootstrap), lang = "from_output")]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_output(output: Self::Output) -> Self; fn from_output(output: Self::Output) -> Self;
@ -191,8 +203,7 @@ pub trait Try: FromResidual {
/// ``` /// ```
/// #![feature(try_trait_v2)] /// #![feature(try_trait_v2)]
/// #![feature(control_flow_enum)] /// #![feature(control_flow_enum)]
/// #![feature(try_trait_transition)] /// use std::ops::{ControlFlow, Try};
/// use std::ops::{ControlFlow, TryV2 as Try};
/// ///
/// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
/// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3))); /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
@ -206,15 +217,80 @@ pub trait Try: FromResidual {
/// ControlFlow::Break(ControlFlow::Break(3)), /// ControlFlow::Break(ControlFlow::Break(3)),
/// ); /// );
/// ``` /// ```
#[cfg_attr(not(bootstrap), lang = "branch")]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; 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 /// Every `Try` type needs to be recreatable from its own associated
/// `Residual` type, but can also have additional `FromResidual` implementations /// `Residual` type, but can also have additional `FromResidual` implementations
/// to support interconversion with other `Try` types. /// 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")] #[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> { pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type. /// Constructs the type from a compatible `Residual` type.
@ -238,6 +314,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
/// ControlFlow::Break(5), /// ControlFlow::Break(5),
/// ); /// );
/// ``` /// ```
#[cfg_attr(not(bootstrap), lang = "from_residual")]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_residual(residual: R) -> Self; fn from_residual(residual: R) -> Self;
} }

View file

@ -1644,8 +1644,8 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
pub struct NoneError; pub struct NoneError;
#[unstable(feature = "try_trait", issue = "42327")] #[unstable(feature = "try_trait", issue = "42327")]
impl<T> ops::Try for Option<T> { impl<T> ops::TryV1 for Option<T> {
type Ok = T; type Output = T;
type Error = NoneError; type Error = NoneError;
#[inline] #[inline]

View file

@ -1627,8 +1627,8 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
} }
#[unstable(feature = "try_trait", issue = "42327")] #[unstable(feature = "try_trait", issue = "42327")]
impl<T, E> ops::Try for Result<T, E> { impl<T, E> ops::TryV1 for Result<T, E> {
type Ok = T; type Output = T;
type Error = E; type Error = E;
#[inline] #[inline]

View file

@ -110,7 +110,7 @@ impl<'a> iter::Iterator for EscapeAscii<'a> {
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where where
Fold: FnMut(Acc, Self::Item) -> R, Fold: FnMut(Acc, Self::Item) -> R,
R: ops::Try<Ok = Acc>, R: ops::Try<Output = Acc>,
{ {
self.inner.try_fold(init, fold) self.inner.try_fold(init, fold)
} }

View file

@ -1467,7 +1467,7 @@ macro_rules! escape_types_impls {
#[inline] #[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where 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) self.inner.try_fold(init, fold)
} }

View file

@ -1,7 +1,7 @@
#![stable(feature = "futures_api", since = "1.36.0")] #![stable(feature = "futures_api", since = "1.36.0")]
use crate::convert; use crate::convert;
use crate::ops::{self, ControlFlow, Try}; use crate::ops::{self, ControlFlow};
use crate::result::Result; use crate::result::Result;
/// Indicates whether a value is available or if the current task has been /// 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")] #[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> { impl<T, E> ops::TryV1 for Poll<Result<T, E>> {
type Ok = Poll<T>; type Output = Poll<T>;
type Error = E; type Error = E;
#[inline] #[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> { fn into_result(self) -> Result<Self::Output, Self::Error> {
match self { match self {
Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
Poll::Ready(Err(e)) => Err(e), Poll::Ready(Err(e)) => Err(e),
@ -148,7 +148,7 @@ impl<T, E> Try for Poll<Result<T, E>> {
} }
#[inline] #[inline]
fn from_ok(x: Self::Ok) -> Self { fn from_ok(x: Self::Output) -> Self {
x.map(Ok) 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")] #[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> { impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> {
type Ok = Poll<Option<T>>; type Output = Poll<Option<T>>;
type Error = E; type Error = E;
#[inline] #[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> { fn into_result(self) -> Result<Self::Output, Self::Error> {
match self { match self {
Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
Poll::Ready(Some(Err(e))) => Err(e), Poll::Ready(Some(Err(e))) => Err(e),
@ -204,7 +204,7 @@ impl<T, E> Try for Poll<Option<Result<T, E>>> {
} }
#[inline] #[inline]
fn from_ok(x: Self::Ok) -> Self { fn from_ok(x: Self::Output) -> Self {
x.map(|x| x.map(Ok)) x.map(|x| x.map(Ok))
} }
} }

View file

@ -45,6 +45,7 @@
#![feature(test)] #![feature(test)]
#![feature(trusted_len)] #![feature(trusted_len)]
#![feature(try_trait)] #![feature(try_trait)]
#![feature(try_trait_v2)]
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(slice_partition_dedup)] #![feature(slice_partition_dedup)]
#![feature(int_error_matching)] #![feature(int_error_matching)]

View file

@ -301,18 +301,6 @@ fn test_try() {
Some(val) Some(val)
} }
assert_eq!(try_option_none(), None); 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] #[test]

View file

@ -249,26 +249,14 @@ pub fn test_into_err() {
#[test] #[test]
fn test_try() { fn test_try() {
fn try_result_some() -> Option<u8> { fn try_result_ok() -> Result<u8, u32> {
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> {
let result: Result<u8, u8> = Ok(1); let result: Result<u8, u8> = Ok(1);
let val = result?; let val = result?;
Ok(val) Ok(val)
} }
assert_eq!(try_result_ok(), Ok(1)); 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 result: Result<u8, u8> = Err(1);
let val = result?; let val = result?;
Ok(val) Ok(val)
@ -401,3 +389,17 @@ fn result_opt_conversions() {
assert_eq!(res, Err(BadNumErr)) 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(())));
}

View file

@ -7,11 +7,28 @@
type R = Result<u64, i32>; 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] #[no_mangle]
fn try_identity(x: R) -> R { pub fn try_identity(x: R) -> R {
// CHECK: start: // CHECK: start:
// CHECK-NOT: br {{.*}} // CHECK-NOT: br {{.*}}
// CHECK ret void // 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) 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)
}

View file

@ -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 _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 _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 _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 _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 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 _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 _8: std::option::Option<std::convert::Infallible>; // 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 _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
let _10: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
scope 1 { 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 2 {
} }
} }
scope 3 { 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 { 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(_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 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 _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 // mir::Constant
// + span: $DIR/issue-62289.rs:9:15: 9:20 // + 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: { bb1: {
@ -43,12 +42,12 @@ fn test() -> Option<Box<u32>> {
} }
bb2: { bb2: {
StorageLive(_10); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_9); // 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 _9 = ((_3 as Continue).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 (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 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 _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: { bb3: {
@ -57,62 +56,53 @@ fn test() -> Option<Box<u32>> {
bb4: { bb4: {
StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 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(_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 _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_9 = _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
_8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
// mir::Constant // mir::Constant
// + span: $DIR/issue-62289.rs:9:19: 9:20 // + 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: { bb5: {
StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_8); // 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 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
// mir::Constant drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
// + 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: { bb6: {
StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
} }
bb7: { bb7: {
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
_0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
} }
bb8: { bb8: {
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
}
bb9: {
StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 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(_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 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 return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
} }
bb10 (cleanup): {
drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
}
bb11 (cleanup): { bb11 (cleanup): {
drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
} }
bb12 (cleanup): { bb12 (cleanup): {
drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
}
bb13 (cleanup): {
resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
} }
} }

View file

@ -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> { 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) Ok(x)
} }

View file

@ -2,101 +2,93 @@
+ // MIR for `id_try` after SimplifyArmIdentity + // MIR for `id_try` after SimplifyArmIdentity
fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> { 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 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:23:34: 23:49 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:24:9: 24:10 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:24:13: 24:15 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:24:13: 24:14 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:24:14: 24:15 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:24:14: 24: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:24:14: 24:15 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:24:14: 24:15 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:24:14: 24:15 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:24:13: 24:15 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:25:8: 25:9 let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
scope 1 { scope 1 {
- debug x => _2; // 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: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 { scope 2 {
- debug err => _6; // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 - debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:24:14: 24:15 - debug t => _9; // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
- debug t => _9; // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 }
} scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
- debug v => _8; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
}
} }
} }
scope 4 { scope 3 {
- debug val => _10; // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 - debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
+ debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 + debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
scope 5 {
}
} }
scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
} }
bb0: { bb0: {
StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
_4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
_3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33
_5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 _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:24:14: 24:15 switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
} }
bb1: { bb1: {
- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - 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:24:13: 24:15 - _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
- _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 - _2 = _10; // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19
- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19
+ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 - StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25: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:25:5: 25:10 - ((_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:25:5: 25:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 - StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10
StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
} }
bb2: { 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: { bb3: {
- StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - 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:24:14: 24:15 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
- StorageLive(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 - StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50
- StorageLive(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 - StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
- _9 = _6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 - _9 = _6; // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
- _8 = move _9; // scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 - _8 = move _9; // scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
- StorageDead(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 - StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50
- StorageLive(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
- _12 = move _8; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51
- discriminant(_0) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51
- StorageDead(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 + _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
- StorageDead(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
- StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+ _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
} }
bb4: { 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
} }
} }

View file

@ -2,75 +2,70 @@
+ // MIR for `id_try` after SimplifyBranchSame + // MIR for `id_try` after SimplifyBranchSame
fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> { 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 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:23:34: 23:49 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:24:9: 24:10 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:24:13: 24:15 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:24:13: 24:14 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:24:14: 24:15 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:24:14: 24: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:24:14: 24:15 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:24:14: 24:15 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:24:14: 24:15 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:24:13: 24:15 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:25:8: 25:9 let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
scope 1 { 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 { scope 2 {
debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
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 5 at $DIR/simplify-arm.rs:37:37: 37:50
debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 }
} scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
}
} }
} }
scope 4 { scope 3 {
debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
scope 5 {
}
} }
scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
} }
bb0: { bb0: {
StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
_4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
_3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33
_5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 _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:24:14: 24: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:24:14: 24:15 + goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
} }
bb1: { bb1: {
_0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
+ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
} }
bb2: { 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: { - bb3: {
- _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
- StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
- } - }
- -
- bb4: { - 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
} }
} }

View file

@ -4,8 +4,24 @@
// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff // 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> { 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) Ok(y)
} }

View file

@ -2,67 +2,62 @@
+ // MIR for `try_identity` after DestinationPropagation + // MIR for `try_identity` after DestinationPropagation
fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { 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 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:7:41: 7:57 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:8:9: 8:10 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:8:13: 8:15 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:8:13: 8:14 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:8:14: 8:15 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:8:14: 8: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:8:14: 8:15 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:8:14: 8:15 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:8:14: 8:15 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:8:13: 8:15 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:9:8: 9:9 let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
scope 1 { 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 { scope 2 {
debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
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 5 at $DIR/simplify_try.rs:22:37: 22:50
debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 }
} scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
}
} }
} }
scope 4 { scope 3 {
debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
scope 5 {
}
} }
scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
- debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
+ debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
} }
bb0: { bb0: {
StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
- _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + nop; // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + nop; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + nop; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
+ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + nop; // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
} }
bb1: { bb1: {
- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + nop; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + nop; // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
} }
} }

View file

@ -2,93 +2,85 @@
+ // MIR for `try_identity` after SimplifyArmIdentity + // MIR for `try_identity` after SimplifyArmIdentity
fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { 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 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:7:41: 7:57 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:8:9: 8:10 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:8:13: 8:15 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:8:13: 8:14 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:8:14: 8:15 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:8:14: 8: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:8:14: 8:15 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:8:14: 8:15 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:8:14: 8:15 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:8:13: 8:15 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:9:8: 9:9 let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
scope 1 { scope 1 {
- debug y => _2; // 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: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 { scope 2 {
- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 - debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => _9; // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
- debug t => _9; // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 }
} scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug e => _8; // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
- debug v => _8; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
}
} }
} }
scope 4 { scope 3 {
- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
scope 5 {
}
} }
scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
} }
bb0: { bb0: {
StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
_4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
_3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
_5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 _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:8:14: 8:15 switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
} }
bb1: { bb1: {
- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - 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:8:13: 8:15 - _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 - _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 - StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9: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:9:5: 9:10 - ((_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:9:5: 9:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 - StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
} }
bb2: { bb2: {
- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - 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:8:14: 8:15 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - _9 = _6; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
- _8 = move _9; // scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - _8 = move _9; // scope 5 at $DIR/simplify_try.rs:22:37: 22:50
- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
- StorageLive(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
- _12 = move _8; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
- discriminant(_0) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
- StorageDead(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 + _0 = move _3; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+ _0 = move _3; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
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
} }
} }

View file

@ -1,57 +1,52 @@
// MIR for `try_identity` after SimplifyBranchSame // MIR for `try_identity` after SimplifyBranchSame
fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { 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 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:7:41: 7:57 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:8:9: 8:10 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:8:13: 8:15 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:8:13: 8:14 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:8:14: 8:15 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:8:14: 8: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:8:14: 8:15 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:8:14: 8:15 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:8:14: 8:15 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:8:13: 8:15 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:9:8: 9:9 let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
scope 1 { 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 { scope 2 {
debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
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 5 at $DIR/simplify_try.rs:22:37: 22:50
debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 }
} scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
}
} }
} }
scope 4 { scope 3 {
debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
scope 5 {
}
} }
scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
} }
bb0: { bb0: {
StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
_4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
_3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
_5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
} }
bb1: { bb1: {
_0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
} }
} }

View file

@ -1,33 +1,29 @@
// MIR for `try_identity` after SimplifyLocals // MIR for `try_identity` after SimplifyLocals
fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { 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 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:7:41: 7:57 let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
scope 1 { 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 { scope 2 {
debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
scope 3 { scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
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 5 at $DIR/simplify_try.rs:22:37: 22:50
debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 }
} scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
}
} }
} }
scope 4 { scope 3 {
debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
scope 5 {
}
} }
scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
} }
bb0: { bb0: {
_0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
} }
} }

View file

@ -42,7 +42,7 @@ async fn bar() -> Result<(), ()> {
foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
//~^ NOTE the `?` operator cannot be applied to type `impl Future` //~^ NOTE the `?` operator cannot be applied to type `impl Future`
//~| HELP the trait `Try` is not implemented for `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` //~| HELP consider `await`ing on the `Future`
//~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?`
//~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?`
@ -65,7 +65,7 @@ async fn baz() -> Result<(), ()> {
t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` t?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
//~^ NOTE the `?` operator cannot be applied to type `T` //~^ NOTE the `?` operator cannot be applied to type `T`
//~| HELP the trait `Try` is not implemented for `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` //~| HELP consider `await`ing on the `Future`
//~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?`
//~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?`

View file

@ -5,7 +5,7 @@ LL | foo()?;
| ^^^^^^ the `?` operator cannot be applied to type `impl Future` | ^^^^^^ the `?` operator cannot be applied to type `impl Future`
| |
= help: the trait `Try` is not implemented for `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` help: consider `await`ing on the `Future`
| |
LL | foo().await?; LL | foo().await?;
@ -18,7 +18,7 @@ LL | t?;
| ^^ the `?` operator cannot be applied to type `T` | ^^ the `?` operator cannot be applied to type `T`
| |
= help: the trait `Try` is not implemented for `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` help: consider `await`ing on the `Future`
| |
LL | t.await?; LL | t.await?;

View file

@ -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`) error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-in-async.rs:8:9 --> $DIR/try-on-option-in-async.rs:8:10
| |
LL | async { LL | async {
| ___________- | ___________-
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; 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 | | 22
LL | | } LL | | }
| |_____- this function should return `Result` or `Option` to accept `?` | |_____- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `{integer}` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-in-async.rs:17:9 --> $DIR/try-on-option-in-async.rs:17:10
| |
LL | let async_closure = async || { LL | let async_closure = async || {
| __________________________________- | __________________________________-
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; 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 | | 22_u32
LL | | }; LL | | };
| |_____- this function should return `Result` or `Option` to accept `?` | |_____- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `u32` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-in-async.rs:26:5 --> $DIR/try-on-option-in-async.rs:26:6
| |
LL | async fn an_async_function() -> u32 { LL | async fn an_async_function() -> u32 {
| _____________________________________- | _____________________________________-
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; 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 | | 22
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `u32` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
= note: required by `from_error` = note: required by `from_residual`
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View file

@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> {
fn main() { fn main() {
let fut = async { let fut = async {
make_unit()?; //~ ERROR type annotations needed make_unit()?;
Ok(()) Ok(()) //~ ERROR type annotations needed
}; };
} }

View file

@ -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 = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
error[E0282]: type annotations needed for `impl Future` 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 { LL | let fut = async {
| --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified | --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified
LL | make_unit()?; ...
| ^ cannot infer type of error for `?` operator LL | Ok(())
| | ^^ cannot infer type for type parameter `E` declared on the enum `Result`
= note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
error: aborting due to previous error; 1 warning emitted error: aborting due to previous error; 1 warning emitted

View file

@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> {
fn main() { fn main() {
let fut = async { let fut = async {
make_unit()?; //~ ERROR type annotations needed make_unit()?;
Ok(()) Ok(()) //~ ERROR type annotations needed
}; };
} }

View file

@ -1,12 +1,11 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/cannot-infer-async.rs:11:20 --> $DIR/cannot-infer-async.rs:13:9
| |
LL | let fut = async { LL | let fut = async {
| --- consider giving `fut` a type | --- consider giving `fut` a type
LL | make_unit()?; ...
| ^ cannot infer type of error for `?` operator LL | Ok(())
| | ^^ cannot infer type for type parameter `E` declared on the enum `Result`
= note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>`
--> $DIR/cannot-infer-closure-circular.rs:7:14 --> $DIR/cannot-infer-closure-circular.rs:7:14
| |
LL | let x = |r| { 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 error: aborting due to previous error

View file

@ -1,6 +1,6 @@
fn main() { fn main() {
let x = |a: (), b: ()| { let x = |a: (), b: ()| {
Err(a)?; //~ ERROR type annotations needed for the closure Err(a)?;
Ok(b) Ok(b) //~ ERROR type annotations needed for the closure
}; };
} }

View file

@ -1,10 +1,9 @@
error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>` 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)?; LL | Ok(b)
| ^ cannot infer type of error for `?` operator | ^^ 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 help: give this closure an explicit return type without `_` placeholders
| |
LL | let x = |a: (), b: ()| -> Result<(), _> { LL | let x = |a: (), b: ()| -> Result<(), _> {

View file

@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif
--> $DIR/cannot-infer-partial-try-return.rs:19:9 --> $DIR/cannot-infer-partial-try-return.rs:19:9
| |
LL | infallible()?; 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 help: give this closure an explicit return type without `_` placeholders
| |
LL | let x = || -> Result<(), QualifiedError<_>> { LL | let x = || -> Result<(), QualifiedError<_>> {

View file

@ -7,7 +7,8 @@ LL | Err(5)?;
| ^ the trait `From<{integer}>` is not implemented for `()` | ^ the trait `From<{integer}>` is not implemented for `()`
| |
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: 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 error: aborting due to previous error

View file

@ -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`.

View file

@ -1,11 +1,10 @@
error[E0283]: type annotations needed error[E0284]: type annotations needed
--> $DIR/question-mark-type-infer.rs:12:21 --> $DIR/question-mark-type-infer.rs:12:21
| |
LL | l.iter().map(f).collect()? LL | l.iter().map(f).collect()?
| ^^^^^^^ cannot infer type | ^^^^^^^ cannot infer type
| |
= note: cannot satisfy `_: Try` = note: cannot satisfy `<_ as Try>::Residual == _`
= note: required by `into_result`
help: consider specifying the type argument in the method call help: consider specifying the type argument in the method call
| |
LL | l.iter().map(f).collect::<B>()? LL | l.iter().map(f).collect::<B>()?
@ -13,4 +12,4 @@ LL | l.iter().map(f).collect::<B>()?
error: aborting due to previous error 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`.

View file

@ -502,10 +502,10 @@ LL | if (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
| |
= help: the trait `Try` is not implemented for `bool` = help: the trait `Try` is not implemented for `bool`
= note: required by `into_result` = note: required by `branch`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:46:8 --> $DIR/disallowed-positions.rs:46:19
| |
LL | / fn nested_within_if_expr() { LL | / fn nested_within_if_expr() {
LL | | if &let 0 = 0 {} LL | | if &let 0 = 0 {}
@ -513,14 +513,14 @@ LL | |
LL | | LL | |
... | ... |
LL | | if (let 0 = 0)? {} 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 | | if let true = let true = true {}
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<_>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:56:8 --> $DIR/disallowed-positions.rs:56:8
@ -660,7 +660,7 @@ LL | if let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}` | ^^ the `?` operator cannot be applied to type `{integer}`
| |
= help: the trait `Try` is not implemented for `{integer}` = help: the trait `Try` is not implemented for `{integer}`
= note: required by `into_result` = note: required by `branch`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:96:11 --> $DIR/disallowed-positions.rs:96:11
@ -690,10 +690,10 @@ LL | while (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
| |
= help: the trait `Try` is not implemented for `bool` = help: the trait `Try` is not implemented for `bool`
= note: required by `into_result` = note: required by `branch`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:110:11 --> $DIR/disallowed-positions.rs:110:22
| |
LL | / fn nested_within_while_expr() { LL | / fn nested_within_while_expr() {
LL | | while &let 0 = 0 {} LL | | while &let 0 = 0 {}
@ -701,14 +701,14 @@ LL | |
LL | | LL | |
... | ... |
LL | | while (let 0 = 0)? {} 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 | | while let true = let true = true {}
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<_>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:120:11 --> $DIR/disallowed-positions.rs:120:11
@ -848,7 +848,7 @@ LL | while let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}` | ^^ the `?` operator cannot be applied to type `{integer}`
| |
= help: the trait `Try` is not implemented for `{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 error[E0614]: type `bool` cannot be dereferenced
--> $DIR/disallowed-positions.rs:173:5 --> $DIR/disallowed-positions.rs:173:5
@ -869,10 +869,10 @@ LL | (let 0 = 0)?;
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
| |
= help: the trait `Try` is not implemented for `bool` = help: the trait `Try` is not implemented for `bool`
= note: required by `into_result` = note: required by `branch`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:183:5 --> $DIR/disallowed-positions.rs:183:16
| |
LL | / fn outside_if_and_while_expr() { LL | / fn outside_if_and_while_expr() {
LL | | &let 0 = 0; LL | | &let 0 = 0;
@ -880,14 +880,14 @@ LL | |
LL | | !let 0 = 0; LL | | !let 0 = 0;
... | ... |
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 | |
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<_>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:198:10 --> $DIR/disallowed-positions.rs:198:10
@ -916,7 +916,7 @@ LL | let 0 = 0?;
| ^^ the `?` operator cannot be applied to type `{integer}` | ^^ the `?` operator cannot be applied to type `{integer}`
| |
= help: the trait `Try` is not implemented for `{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 error: aborting due to 104 previous errors; 2 warnings emitted

View file

@ -5,7 +5,7 @@ LL | SadGirl {}.call()?;
| ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future` | ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future`
| |
= help: the trait `Try` is not implemented for `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` help: consider `await`ing on the `Future`
| |
LL | SadGirl {}.call().await?; LL | SadGirl {}.call().await?;

View file

@ -15,8 +15,7 @@ pub fn main() {
let res: Result<i32, i32> = try { }; //~ ERROR type mismatch let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
let res: () = try { }; let res: () = try { };
//~^ ERROR the trait bound `(): Try` is not satisfied //~^ ERROR a `try` block must return `Result` or `Option`
//~| ERROR the trait bound `(): Try` is not satisfied
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`
} }

View file

@ -7,43 +7,40 @@ LL | Err("")?;
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found: = help: the following implementations were found:
<TryFromSliceError as From<Infallible>> <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 --> $DIR/try-block-bad-type.rs:12:9
| |
LL | "" LL | ""
| ^^ expected `i32`, found `&str` | ^^ 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 --> $DIR/try-block-bad-type.rs:15:39
| |
LL | let res: Result<i32, i32> = try { }; LL | let res: Result<i32, i32> = try { };
| ^ expected `i32`, found `()` | ^ 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 --> $DIR/try-block-bad-type.rs:17:25
| |
LL | let res: () = try { }; 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 error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
--> $DIR/try-block-bad-type.rs:17:25 --> $DIR/try-block-bad-type.rs:20:26
|
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
| |
LL | let res: i32 = try { 5 }; 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. Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`. For more information about an error, try `rustc --explain E0271`.

View file

@ -4,5 +4,5 @@
fn main() { fn main() {
while try { false } {} while try { false } {}
//~^ ERROR the trait bound `bool: Try` is not satisfied //~^ ERROR a `try` block must
} }

View file

@ -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 --> $DIR/try-block-in-while.rs:6:17
| |
LL | while try { false } {} 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 error: aborting due to previous error

View file

@ -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 --> $DIR/try-block-type-error.rs:10:9
| |
LL | 42 LL | 42
@ -7,7 +7,7 @@ LL | 42
| expected `f32`, found integer | expected `f32`, found integer
| help: use a float literal: `42.0` | 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 --> $DIR/try-block-type-error.rs:16:5
| |
LL | }; LL | };

View file

@ -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`.

View file

@ -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();
}

View file

@ -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() {}

View file

@ -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`.

View file

@ -2,12 +2,12 @@ fn main(){ }
fn test_result() -> Result<(),()> { fn test_result() -> Result<(),()> {
let a:Option<()> = Some(()); let a:Option<()> = Some(());
a?;//~ ERROR `?` couldn't convert the error a?;//~ ERROR the `?` operator can only be used
Ok(()) Ok(())
} }
fn test_option() -> Option<i32>{ fn test_option() -> Option<i32>{
let a:Result<i32, i32> = Ok(5); let a:Result<i32, i32> = Ok(5);
a?;//~ ERROR `?` couldn't convert the error a?;//~ ERROR the `?` operator can only be used
Some(5) Some(5)
} }

View file

@ -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`.

View file

@ -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));
}

View file

@ -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`) error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:7:5 --> $DIR/try-on-option-diagnostics.rs:7:6
| |
LL | / fn a_function() -> u32 { LL | / fn a_function() -> u32 {
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; 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 | | 22
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `u32` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:14:9 --> $DIR/try-on-option-diagnostics.rs:14:10
| |
LL | let a_closure = || { LL | let a_closure = || {
| _____________________- | _____________________-
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; 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 | | 22
LL | | }; LL | | };
| |_____- this function should return `Result` or `Option` to accept `?` | |_____- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `{integer}` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:26:13 --> $DIR/try-on-option-diagnostics.rs:26:14
| |
LL | / fn a_method() { LL | / fn a_method() {
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; LL | | x?;
| | ^^ cannot use the `?` operator in a method that returns `()` | | ^ cannot use the `?` operator in a method that returns `()`
LL | | } LL | | }
| |_________- this function should return `Result` or `Option` to accept `?` | |_________- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`) error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:39:13 --> $DIR/try-on-option-diagnostics.rs:39:14
| |
LL | / fn a_trait_method() { LL | / fn a_trait_method() {
LL | | let x: Option<u32> = None; LL | | let x: Option<u32> = None;
LL | | x?; LL | | x?;
| | ^^ cannot use the `?` operator in a trait method that returns `()` | | ^ cannot use the `?` operator in a trait method that returns `()`
LL | | } LL | | }
| |_________- this function should return `Result` or `Option` to accept `?` | |_________- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -4,7 +4,7 @@ fn main() {}
fn foo() -> Result<u32, ()> { fn foo() -> Result<u32, ()> {
let x: Option<u32> = None; let x: Option<u32> = None;
x?; //~ ERROR `?` couldn't convert the error x?; //~ ERROR the `?` operator
Ok(22) Ok(22)
} }

View file

@ -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`.

View file

@ -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();
}

View file

@ -1,4 +1,4 @@
#![feature(try_trait)] #![feature(try_trait_v2)]
use std::ops::Try; use std::ops::Try;
@ -7,14 +7,13 @@ fn main() {
std::fs::File::open("foo")?; //~ ERROR the `?` operator can only std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
// a non-`Try` type on a non-`Try` fn // 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` // an unrelated use of `Try`
try_trait_generic::<()>(); //~ ERROR the trait bound try_trait_generic::<()>(); //~ ERROR the trait bound
} }
fn try_trait_generic<T: Try>() -> T { fn try_trait_generic<T: Try>() -> T {
// and a non-`Try` object on a `Try` fn. // and a non-`Try` object on a `Try` fn.
()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`

View file

@ -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`) 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:5 --> $DIR/try-operator-on-main.rs:7:31
| |
LL | / fn main() { LL | / fn main() {
LL | | // error for a `Try` type on a non-`Try` fn LL | | // error for a `Try` type on a non-`Try` fn
LL | | std::fs::File::open("foo")?; 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 | |
... | ... |
LL | | try_trait_generic::<()>(); LL | | try_trait_generic::<()>();
LL | | } LL | | }
| |_- this function should return `Result` or `Option` to accept `?` | |_- this function should return `Result` or `Option` to accept `?`
| |
= help: the trait `Try` is not implemented for `()` = help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
= note: required by `from_error` = note: required by `from_residual`
error[E0277]: the `?` operator can only be applied to values that implement `Try` error[E0277]: the `?` operator can only be applied to values that implement `Try`
--> $DIR/try-operator-on-main.rs:10:5 --> $DIR/try-operator-on-main.rs:10:5
@ -21,10 +21,28 @@ LL | ()?;
| ^^^ the `?` operator cannot be applied to type `()` | ^^^ the `?` operator cannot be applied to type `()`
| |
= help: the trait `Try` is not implemented for `()` = 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 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::<()>(); LL | try_trait_generic::<()>();
| ^^ the trait `Try` is not implemented for `()` | ^^ 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` | --- required by this bound in `try_trait_generic`
error[E0277]: the `?` operator can only be applied to values that implement `Try` 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 | ()?; LL | ()?;
| ^^^ the `?` operator cannot be applied to type `()` | ^^^ the `?` operator cannot be applied to type `()`
| |
= help: the trait `Try` is not implemented for `()` = 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`. For more information about this error, try `rustc --explain E0277`.

View file

@ -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 let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
if args.len() == 1; 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 { then {
// Extract inner expr type from match argument generated by // Extract inner expr type from match argument generated by
// question mark operator // question mark operator

View file

@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind; if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
if let ExprKind::Call(match_fun, try_args) = match_arg.kind; if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.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 Some(try_arg) = try_args.get(0);
if let ExprKind::Call(err_fun, err_args) = try_arg.kind; if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
if let Some(err_arg) = err_args.get(0); if let Some(err_arg) = err_args.get(0);

View file

@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
if let hir::ExprKind::Call(func, args) = res.kind { if let hir::ExprKind::Call(func, args) = res.kind {
if matches!( if matches!(
func.kind, 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); check_map_error(cx, &args[0], expr);
} }