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

View File

@ -332,7 +332,7 @@ pub fn lower_crate<'a, 'hir>(
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::try_trait][..].into()),
allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
}
.lower_crate(krate)
@ -2490,14 +2490,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.pat(span, hir::PatKind::Lit(expr))
}
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
}
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
}
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {

View File

@ -308,12 +308,12 @@ language_item_table! {
Termination, sym::termination, termination, Target::Trait;
Try, kw::Try, try_trait, Target::Trait;
Try, sym::Try, try_trait, Target::Trait;
// Language items from AST lowering
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false });
TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false });
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
@ -331,6 +331,9 @@ language_item_table! {
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
ResultErr, sym::Err, result_err_variant, Target::Variant;
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant;
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});

View File

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

View File

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

View File

@ -140,7 +140,8 @@
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(trusted_random_access)]
#![feature(try_trait)]
#![cfg_attr(bootstrap, feature(try_trait))]
#![cfg_attr(not(bootstrap), feature(try_trait_v2))]
#![feature(min_type_alias_impl_trait)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -87,7 +87,7 @@ where
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
}
@ -117,7 +117,7 @@ where
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
}

View File

@ -110,7 +110,7 @@ where
where
Self: Sized,
G: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
self.iter.try_fold(init, map_try_fold(&mut self.f, g))
}
@ -146,7 +146,7 @@ where
where
Self: Sized,
G: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
}

View File

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

View File

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

View File

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

View File

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

View File

@ -56,9 +56,9 @@ where
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
fn scan<'a, T, St, B, Acc, R: Try<Output = Acc>>(
state: &'a mut St,
f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a,

View File

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

View File

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

View File

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

View File

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

View File

@ -68,9 +68,9 @@ where
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
R: Try<Output = Acc>,
{
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
fn check<'a, T, Acc, R: Try<Output = Acc>>(
flag: &'a mut bool,
p: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a,

View File

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

View File

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

View File

@ -1999,7 +1999,7 @@ pub trait Iterator {
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
R: Try<Output = B>,
{
let mut accum = init;
while let Some(x) = self.next() {
@ -2041,7 +2041,7 @@ pub trait Iterator {
where
Self: Sized,
F: FnMut(Self::Item) -> R,
R: Try<Ok = ()>,
R: Try<Output = ()>,
{
#[inline]
fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
@ -2412,17 +2412,48 @@ pub trait Iterator {
/// ```
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
#[cfg(not(bootstrap))]
fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
R: Try<Output = bool>,
// FIXME: This bound is rather strange, but means minimal breakage on nightly.
// See #85115 for the issue tracking a holistic solution for this and try_map.
R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
{
#[inline]
fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
where
F: FnMut(&T) -> R,
R: Try<Output = bool>,
R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
{
move |(), x| match f(&x).branch() {
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
}
}
self.try_fold((), check(f)).break_value().transpose()
}
/// We're bootstrapping.
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
#[cfg(bootstrap)]
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
R: Try<Ok = bool>,
R: Try<Output = bool>,
{
#[inline]
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
where
F: FnMut(&T) -> R,
R: Try<Ok = bool>,
R: Try<Output = bool>,
{
move |(), x| match f(&x).into_result() {
Ok(false) => ControlFlow::CONTINUE,

View File

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

View File

@ -183,13 +183,21 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
#[unstable(feature = "try_trait", issue = "42327")]
#[cfg(bootstrap)]
pub use self::r#try::Try;
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
pub(crate) use self::r#try::Try as TryV1;
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub use self::try_trait::FromResidual;
#[unstable(feature = "try_trait_v2", issue = "84277")]
#[cfg(not(bootstrap))]
pub use self::try_trait::Try;
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
pub use self::try_trait::Try as TryV2;
pub(crate) use self::try_trait::Try as TryV2;
#[unstable(feature = "generator_trait", issue = "43122")]
pub use self::generator::{Generator, GeneratorState};

View File

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

View File

@ -41,8 +41,7 @@ use crate::ops::ControlFlow;
/// output type that we want:
/// ```
/// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # use std::ops::TryV2 as Try;
/// # use std::ops::Try;
/// fn simple_try_fold_1<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
/// mut accum: A,
@ -56,9 +55,8 @@ use crate::ops::ControlFlow;
/// into the return type using [`Try::from_output`]:
/// ```
/// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # #![feature(control_flow_enum)]
/// # use std::ops::{ControlFlow, TryV2 as Try};
/// # use std::ops::{ControlFlow, Try};
/// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
/// mut accum: A,
@ -81,9 +79,8 @@ use crate::ops::ControlFlow;
/// recreated from their corresponding residual, so we'll just call it:
/// ```
/// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # #![feature(control_flow_enum)]
/// # use std::ops::{ControlFlow, TryV2 as Try};
/// # use std::ops::{ControlFlow, Try};
/// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
/// mut accum: A,
@ -103,10 +100,9 @@ use crate::ops::ControlFlow;
/// But this "call `branch`, then `match` on it, and `return` if it was a
/// `Break`" is exactly what happens inside the `?` operator. So rather than
/// do all this manually, we can just use `?` instead:
/// ```compile_fail (enable again once ? converts to the new trait)
/// ```
/// # #![feature(try_trait_v2)]
/// # #![feature(try_trait_transition)]
/// # use std::ops::TryV2 as Try;
/// # use std::ops::Try;
/// fn simple_try_fold<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
/// mut accum: A,
@ -119,6 +115,22 @@ use crate::ops::ControlFlow;
/// }
/// ```
#[unstable(feature = "try_trait_v2", issue = "84277")]
#[rustc_on_unimplemented(
on(
all(from_method = "from_output", from_desugaring = "TryBlock"),
message = "a `try` block must return `Result` or `Option` \
(or another type that implements `{Try}`)",
label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
),
on(
all(from_method = "branch", from_desugaring = "QuestionMark"),
message = "the `?` operator can only be applied to values \
that implement `{Try}`",
label = "the `?` operator cannot be applied to type `{Self}`"
)
)]
#[doc(alias = "?")]
#[cfg_attr(not(bootstrap), lang = "Try")]
pub trait Try: FromResidual {
/// The type of the value produced by `?` when *not* short-circuiting.
#[unstable(feature = "try_trait_v2", issue = "84277")]
@ -159,8 +171,7 @@ pub trait Try: FromResidual {
/// ```
/// #![feature(try_trait_v2)]
/// #![feature(control_flow_enum)]
/// #![feature(try_trait_transition)]
/// use std::ops::TryV2 as Try;
/// use std::ops::Try;
///
/// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
/// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));
@ -178,6 +189,7 @@ pub trait Try: FromResidual {
/// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
/// assert_eq!(r, Some(4));
/// ```
#[cfg_attr(not(bootstrap), lang = "from_output")]
#[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_output(output: Self::Output) -> Self;
@ -191,8 +203,7 @@ pub trait Try: FromResidual {
/// ```
/// #![feature(try_trait_v2)]
/// #![feature(control_flow_enum)]
/// #![feature(try_trait_transition)]
/// use std::ops::{ControlFlow, TryV2 as Try};
/// use std::ops::{ControlFlow, Try};
///
/// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
/// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
@ -206,15 +217,80 @@ pub trait Try: FromResidual {
/// ControlFlow::Break(ControlFlow::Break(3)),
/// );
/// ```
#[cfg_attr(not(bootstrap), lang = "branch")]
#[unstable(feature = "try_trait_v2", issue = "84277")]
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
}
/// Used to specify which residuals can be converted into which [`Try`] types.
/// Used to specify which residuals can be converted into which [`crate::ops::Try`] types.
///
/// Every `Try` type needs to be recreatable from its own associated
/// `Residual` type, but can also have additional `FromResidual` implementations
/// to support interconversion with other `Try` types.
#[rustc_on_unimplemented(
on(
all(
from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::result::Result<T, E>",
R = "std::option::Option<std::convert::Infallible>"
),
message = "the `?` operator can only be used on `Result`s, not `Option`s, \
in {ItemContext} that returns `Result`",
label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
enclosing_scope = "this function returns a `Result`"
),
on(
all(
from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::result::Result<T, E>",
),
// There's a special error message in the trait selection code for
// `From` in `?`, so this is not shown for result-in-result errors,
// and thus it can be phrased more strongly than `ControlFlow`'s.
message = "the `?` operator can only be used on `Result`s \
in {ItemContext} that returns `Result`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
enclosing_scope = "this function returns a `Result`"
),
on(
all(
from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::option::Option<T>",
),
// `Option`-in-`Option` always works, as there's only one possible
// residual, so this can also be phrased strongly.
message = "the `?` operator can only be used on `Option`s \
in {ItemContext} that returns `Option`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
enclosing_scope = "this function returns an `Option`"
),
on(
all(
from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::ops::ControlFlow<B, C>",
),
message = "the `?` operator can only be used on `ControlFlow<B, _>`s \
in {ItemContext} that returns `ControlFlow<B, _>`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
enclosing_scope = "this function returns a `ControlFlow`",
note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
),
on(
all(
from_method = "from_residual",
from_desugaring = "QuestionMark"
),
message = "the `?` operator can only be used in {ItemContext} \
that returns `Result` or `Option` \
(or another type that implements `{FromResidual}`)",
label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
),
)]
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type.
@ -238,6 +314,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
/// ControlFlow::Break(5),
/// );
/// ```
#[cfg_attr(not(bootstrap), lang = "from_residual")]
#[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_residual(residual: R) -> Self;
}

View File

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

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")]
impl<T, E> ops::Try for Result<T, E> {
type Ok = T;
impl<T, E> ops::TryV1 for Result<T, E> {
type Output = T;
type Error = E;
#[inline]

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
where
Fold: FnMut(Acc, Self::Item) -> R,
R: ops::Try<Ok = Acc>,
R: ops::Try<Output = Acc>,
{
self.inner.try_fold(init, fold)
}

View File

@ -1467,7 +1467,7 @@ macro_rules! escape_types_impls {
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>
{
self.inner.try_fold(init, fold)
}

View File

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

View File

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

View File

@ -301,18 +301,6 @@ fn test_try() {
Some(val)
}
assert_eq!(try_option_none(), None);
fn try_option_ok() -> Result<u8, NoneError> {
let val = Some(1)?;
Ok(val)
}
assert_eq!(try_option_ok(), Ok(1));
fn try_option_err() -> Result<u8, NoneError> {
let val = None?;
Ok(val)
}
assert_eq!(try_option_err(), Err(NoneError));
}
#[test]

View File

@ -249,26 +249,14 @@ pub fn test_into_err() {
#[test]
fn test_try() {
fn try_result_some() -> Option<u8> {
let val = Ok(1)?;
Some(val)
}
assert_eq!(try_result_some(), Some(1));
fn try_result_none() -> Option<u8> {
let val = Err(NoneError)?;
Some(val)
}
assert_eq!(try_result_none(), None);
fn try_result_ok() -> Result<u8, u8> {
fn try_result_ok() -> Result<u8, u32> {
let result: Result<u8, u8> = Ok(1);
let val = result?;
Ok(val)
}
assert_eq!(try_result_ok(), Ok(1));
fn try_result_err() -> Result<u8, u8> {
fn try_result_err() -> Result<u8, u32> {
let result: Result<u8, u8> = Err(1);
let val = result?;
Ok(val)
@ -401,3 +389,17 @@ fn result_opt_conversions() {
assert_eq!(res, Err(BadNumErr))
}
#[test]
#[cfg(not(bootstrap))] // Needs the V2 trait
fn result_try_trait_v2_branch() {
use core::num::NonZeroU32;
use core::ops::{ControlFlow::*, Try};
assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4));
assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4)));
let one = NonZeroU32::new(1).unwrap();
assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(()));
assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one)));
assert_eq!(Ok::<NonZeroU32, ()>(one).branch(), Continue(one));
assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(())));
}

View File

@ -7,11 +7,28 @@
type R = Result<u64, i32>;
// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
// so the relevant desugar is copied inline in order to keep the test testing the same thing.
// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
#[no_mangle]
fn try_identity(x: R) -> R {
pub fn try_identity(x: R) -> R {
// CHECK: start:
// CHECK-NOT: br {{.*}}
// CHECK ret void
let y = x?;
let y = match into_result(x) {
Err(e) => return from_error(From::from(e)),
Ok(v) => v,
};
Ok(y)
}
#[inline]
fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
r
}
#[inline]
fn from_error<T, E>(e: E) -> Result<T, E> {
Err(e)
}

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 _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
let mut _2: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
let mut _3: std::result::Result<u32, std::option::NoneError>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let _6: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let _6: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let mut _8: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let mut _9: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let _10: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
let mut _8: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
scope 1 {
debug err => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
scope 2 {
}
}
scope 3 {
debug val => _10; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
scope 4 {
}
}
@ -30,10 +29,10 @@ fn test() -> Option<Box<u32>> {
StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
_4 = Option::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
_3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
_3 = <Option<u32> as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
// mir::Constant
// + span: $DIR/issue-62289.rs:9:15: 9:20
// + literal: Const { ty: fn(std::option::Option<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
// + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
}
bb1: {
@ -43,12 +42,12 @@ fn test() -> Option<Box<u32>> {
}
bb2: {
StorageLive(_10); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
_10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
(*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
_9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
(*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
_1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
}
bb3: {
@ -57,62 +56,53 @@ fn test() -> Option<Box<u32>> {
bb4: {
StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
_6 = ((_3 as Err).0: std::option::NoneError); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
_6 = ((_3 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
// mir::Constant
// + span: $DIR/issue-62289.rs:9:19: 9:20
// + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) }
// + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
}
bb5: {
StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
_0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
// mir::Constant
// + span: $DIR/issue-62289.rs:9:15: 9:20
// + literal: Const { ty: fn(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
}
bb6: {
StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
_0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
}
bb7: {
StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
_0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
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 -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
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(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
bb10: {
bb9: {
return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
bb10 (cleanup): {
drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
}
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): {
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
}
}

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> {
let x = r?;
let x = match into_result(r) {
Err(e) => return from_error(From::from(e)),
Ok(v) => v,
};
Ok(x)
}

View File

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

View File

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

View File

@ -4,8 +4,24 @@
// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff
fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
r
}
fn from_error<T, E>(e: E) -> Result<T, E> {
Err(e)
}
// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
// so the relevant desugar is copied inline in order to keep the test testing the same thing.
// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
let y = x?;
let y = match into_result(x) {
Err(e) => return from_error(From::from(e)),
Ok(v) => v,
};
Ok(y)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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
error[E0282]: type annotations needed for `impl Future`
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9
|
LL | let fut = async {
| --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
LL | make_unit()?;
| ^ cannot infer type of error for `?` operator
|
= note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
| --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified
...
LL | Ok(())
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
error: aborting due to previous error; 1 warning emitted

View File

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

View File

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

View File

@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>`
--> $DIR/cannot-infer-closure-circular.rs:7:14
|
LL | let x = |r| {
| ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified
| ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
error: aborting due to previous error

View File

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

View File

@ -1,10 +1,9 @@
error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
--> $DIR/cannot-infer-closure.rs:3:15
--> $DIR/cannot-infer-closure.rs:4:9
|
LL | Err(a)?;
| ^ cannot infer type of error for `?` operator
LL | Ok(b)
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
|
= note: `?` implicitly converts the error value into a type implementing `From<()>`
help: give this closure an explicit return type without `_` placeholders
|
LL | let x = |a: (), b: ()| -> Result<(), _> {

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
|
LL | infallible()?;
| ^^^^^^^^^^^^^ cannot infer type of error for `?` operator
| ^^^^^^^^^^^^^ cannot infer type
|
= note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>`
help: give this closure an explicit return type without `_` placeholders
|
LL | let x = || -> Result<(), QualifiedError<_>> {

View File

@ -7,7 +7,8 @@ LL | Err(5)?;
| ^ the trait `From<{integer}>` is not implemented for `()`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `from`
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
= note: required by `from_residual`
error: aborting due to previous error

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
|
LL | l.iter().map(f).collect()?
| ^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: Try`
= note: required by `into_result`
= note: cannot satisfy `<_ as Try>::Residual == _`
help: consider specifying the type argument in the method call
|
LL | l.iter().map(f).collect::<B>()?
@ -13,4 +12,4 @@ LL | l.iter().map(f).collect::<B>()?
error: aborting due to previous error
For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0284`.

View File

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

View File

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

View File

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

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
= help: the following implementations were found:
<TryFromSliceError as From<Infallible>>
= note: required by `from`
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>`
= note: required by `from_residual`
error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == &str`
error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str`
--> $DIR/try-block-bad-type.rs:12:9
|
LL | ""
| ^^ expected `i32`, found `&str`
error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == ()`
error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()`
--> $DIR/try-block-bad-type.rs:15:39
|
LL | let res: Result<i32, i32> = try { };
| ^ expected `i32`, found `()`
error[E0277]: the trait bound `(): Try` is not satisfied
error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
--> $DIR/try-block-bad-type.rs:17:25
|
LL | let res: () = try { };
| ^ the trait `Try` is not implemented for `()`
| ^ could not wrap the final value of the block as `()` doesn't implement `Try`
|
= note: required by `from_ok`
= help: the trait `Try` is not implemented for `()`
= note: required by `from_output`
error[E0277]: the trait bound `(): Try` is not satisfied
--> $DIR/try-block-bad-type.rs:17:25
|
LL | let res: () = try { };
| ^ the trait `Try` is not implemented for `()`
error[E0277]: the trait bound `i32: Try` is not satisfied
--> $DIR/try-block-bad-type.rs:21:26
error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
--> $DIR/try-block-bad-type.rs:20:26
|
LL | let res: i32 = try { 5 };
| ^ the trait `Try` is not implemented for `i32`
| ^ could not wrap the final value of the block as `i32` doesn't implement `Try`
|
= note: required by `from_ok`
= help: the trait `Try` is not implemented for `i32`
= note: required by `from_output`
error: aborting due to 6 previous errors
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.

View File

@ -4,5 +4,5 @@
fn main() {
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
|
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

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
|
LL | 42
@ -7,7 +7,7 @@ LL | 42
| expected `f32`, found integer
| help: use a float literal: `42.0`
error[E0271]: type mismatch resolving `<Option<i32> as Try>::Ok == ()`
error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
--> $DIR/try-block-type-error.rs:16:5
|
LL | };

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<(),()> {
let a:Option<()> = Some(());
a?;//~ ERROR `?` couldn't convert the error
a?;//~ ERROR the `?` operator can only be used
Ok(())
}
fn test_option() -> Option<i32>{
let a:Result<i32, i32> = Ok(5);
a?;//~ ERROR `?` couldn't convert the error
a?;//~ ERROR the `?` operator can only be used
Some(5)
}

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

View File

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

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

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

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

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::Call(match_fun, try_args) = match_arg.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _));
if let Some(try_arg) = try_args.get(0);
if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
if let Some(err_arg) = err_args.get(0);

View File

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