Actually implement the feature in the compiler
Including all the bootstrapping tweaks in the library.
This commit is contained in:
parent
c10eec3a1c
commit
ca92b5a23a
10 changed files with 144 additions and 51 deletions
|
@ -562,8 +562,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
|
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
|
||||||
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }`
|
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
|
||||||
/// and save the block id to use it as a break target for desugaring of the `?` operator.
|
/// and save the block id to use it as a break target for desugaring of the `?` operator.
|
||||||
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
|
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
|
||||||
self.with_catch_scope(body.id, |this| {
|
self.with_catch_scope(body.id, |this| {
|
||||||
|
@ -592,9 +592,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let ok_wrapped_span =
|
let ok_wrapped_span =
|
||||||
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
|
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
|
||||||
|
|
||||||
// `::std::ops::Try::from_ok($tail_expr)`
|
// `::std::ops::Try::from_output($tail_expr)`
|
||||||
block.expr = Some(this.wrap_in_try_constructor(
|
block.expr = Some(this.wrap_in_try_constructor(
|
||||||
hir::LangItem::TryFromOk,
|
hir::LangItem::TryTraitFromOutput,
|
||||||
try_span,
|
try_span,
|
||||||
tail_expr,
|
tail_expr,
|
||||||
ok_wrapped_span,
|
ok_wrapped_span,
|
||||||
|
@ -1896,14 +1896,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.allow_try_trait.clone(),
|
self.allow_try_trait.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// `Try::into_result(<expr>)`
|
// `Try::branch(<expr>)`
|
||||||
let scrutinee = {
|
let scrutinee = {
|
||||||
// expand <expr>
|
// expand <expr>
|
||||||
let sub_expr = self.lower_expr_mut(sub_expr);
|
let sub_expr = self.lower_expr_mut(sub_expr);
|
||||||
|
|
||||||
self.expr_call_lang_item_fn(
|
self.expr_call_lang_item_fn(
|
||||||
unstable_span,
|
unstable_span,
|
||||||
hir::LangItem::TryIntoResult,
|
hir::LangItem::TryTraitBranch,
|
||||||
arena_vec![self; sub_expr],
|
arena_vec![self; sub_expr],
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -1921,8 +1921,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
};
|
};
|
||||||
let attrs = vec![attr];
|
let attrs = vec![attr];
|
||||||
|
|
||||||
// `Ok(val) => #[allow(unreachable_code)] val,`
|
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
|
||||||
let ok_arm = {
|
let continue_arm = {
|
||||||
let val_ident = Ident::with_dummy_span(sym::val);
|
let val_ident = Ident::with_dummy_span(sym::val);
|
||||||
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
|
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
|
||||||
let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
|
let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
|
||||||
|
@ -1931,27 +1931,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
val_pat_nid,
|
val_pat_nid,
|
||||||
ThinVec::from(attrs.clone()),
|
ThinVec::from(attrs.clone()),
|
||||||
));
|
));
|
||||||
let ok_pat = self.pat_ok(span, val_pat);
|
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
||||||
self.arm(ok_pat, val_expr)
|
self.arm(continue_pat, val_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `Err(err) => #[allow(unreachable_code)]
|
// `ControlFlow::Break(residual) =>
|
||||||
// return Try::from_error(From::from(err)),`
|
// #[allow(unreachable_code)]
|
||||||
let err_arm = {
|
// return Try::from_residual(residual),`
|
||||||
let err_ident = Ident::with_dummy_span(sym::err);
|
let break_arm = {
|
||||||
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
|
let residual_ident = Ident::with_dummy_span(sym::residual);
|
||||||
let from_expr = {
|
let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
|
||||||
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
|
let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
|
||||||
self.expr_call_lang_item_fn(
|
let from_residual_expr = self.wrap_in_try_constructor(
|
||||||
|
hir::LangItem::TryTraitFromResidual,
|
||||||
try_span,
|
try_span,
|
||||||
hir::LangItem::FromFrom,
|
self.arena.alloc(residual_expr),
|
||||||
arena_vec![self; err_expr],
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let from_err_expr = self.wrap_in_try_constructor(
|
|
||||||
hir::LangItem::TryFromError,
|
|
||||||
unstable_span,
|
|
||||||
from_expr,
|
|
||||||
unstable_span,
|
unstable_span,
|
||||||
);
|
);
|
||||||
let thin_attrs = ThinVec::from(attrs);
|
let thin_attrs = ThinVec::from(attrs);
|
||||||
|
@ -1962,25 +1956,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
try_span,
|
try_span,
|
||||||
hir::ExprKind::Break(
|
hir::ExprKind::Break(
|
||||||
hir::Destination { label: None, target_id },
|
hir::Destination { label: None, target_id },
|
||||||
Some(from_err_expr),
|
Some(from_residual_expr),
|
||||||
),
|
),
|
||||||
thin_attrs,
|
thin_attrs,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
self.arena.alloc(self.expr(
|
self.arena.alloc(self.expr(
|
||||||
try_span,
|
try_span,
|
||||||
hir::ExprKind::Ret(Some(from_err_expr)),
|
hir::ExprKind::Ret(Some(from_residual_expr)),
|
||||||
thin_attrs,
|
thin_attrs,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let err_pat = self.pat_err(try_span, err_local);
|
let break_pat = self.pat_cf_break(try_span, residual_local);
|
||||||
self.arm(err_pat, ret_expr)
|
self.arm(break_pat, ret_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
hir::ExprKind::Match(
|
hir::ExprKind::Match(
|
||||||
scrutinee,
|
scrutinee,
|
||||||
arena_vec![self; err_arm, ok_arm],
|
arena_vec![self; break_arm, continue_arm],
|
||||||
hir::MatchSource::TryDesugar,
|
hir::MatchSource::TryDesugar,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,7 +331,7 @@ pub fn lower_crate<'a, 'hir>(
|
||||||
lifetimes_to_define: Vec::new(),
|
lifetimes_to_define: Vec::new(),
|
||||||
is_collecting_in_band_lifetimes: false,
|
is_collecting_in_band_lifetimes: false,
|
||||||
in_scope_lifetimes: Vec::new(),
|
in_scope_lifetimes: Vec::new(),
|
||||||
allow_try_trait: Some([sym::try_trait][..].into()),
|
allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
|
||||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||||
}
|
}
|
||||||
.lower_crate(krate)
|
.lower_crate(krate)
|
||||||
|
@ -2479,14 +2479,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.pat(span, hir::PatKind::Lit(expr))
|
self.pat(span, hir::PatKind::Lit(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
let field = self.single_pat_field(span, pat);
|
let field = self.single_pat_field(span, pat);
|
||||||
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
|
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
let field = self.single_pat_field(span, pat);
|
let field = self.single_pat_field(span, pat);
|
||||||
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
|
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
|
|
|
@ -308,12 +308,12 @@ language_item_table! {
|
||||||
|
|
||||||
Termination, sym::termination, termination, Target::Trait;
|
Termination, sym::termination, termination, Target::Trait;
|
||||||
|
|
||||||
Try, kw::Try, try_trait, Target::Trait;
|
Try, sym::Try, try_trait, Target::Trait;
|
||||||
|
|
||||||
// Language items from AST lowering
|
// Language items from AST lowering
|
||||||
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
|
TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
|
TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
|
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
|
||||||
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
|
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
|
||||||
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
|
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
|
||||||
|
@ -331,6 +331,9 @@ language_item_table! {
|
||||||
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
|
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
|
||||||
ResultErr, sym::Err, result_err_variant, Target::Variant;
|
ResultErr, sym::Err, result_err_variant, Target::Variant;
|
||||||
|
|
||||||
|
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant;
|
||||||
|
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
|
||||||
|
|
||||||
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
|
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
|
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
|
||||||
|
|
||||||
|
|
|
@ -130,10 +130,12 @@ symbols! {
|
||||||
BTreeSet,
|
BTreeSet,
|
||||||
BinaryHeap,
|
BinaryHeap,
|
||||||
Borrow,
|
Borrow,
|
||||||
|
Break,
|
||||||
C,
|
C,
|
||||||
CString,
|
CString,
|
||||||
Center,
|
Center,
|
||||||
Clone,
|
Clone,
|
||||||
|
Continue,
|
||||||
Copy,
|
Copy,
|
||||||
Count,
|
Count,
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -326,6 +328,7 @@ symbols! {
|
||||||
box_patterns,
|
box_patterns,
|
||||||
box_syntax,
|
box_syntax,
|
||||||
braced_empty_structs,
|
braced_empty_structs,
|
||||||
|
branch,
|
||||||
breakpoint,
|
breakpoint,
|
||||||
bridge,
|
bridge,
|
||||||
bswap,
|
bswap,
|
||||||
|
@ -410,6 +413,7 @@ symbols! {
|
||||||
constructor,
|
constructor,
|
||||||
contents,
|
contents,
|
||||||
context,
|
context,
|
||||||
|
control_flow_enum,
|
||||||
convert,
|
convert,
|
||||||
copy,
|
copy,
|
||||||
copy_closures,
|
copy_closures,
|
||||||
|
@ -510,7 +514,6 @@ symbols! {
|
||||||
env,
|
env,
|
||||||
eq,
|
eq,
|
||||||
ermsb_target_feature,
|
ermsb_target_feature,
|
||||||
err,
|
|
||||||
exact_div,
|
exact_div,
|
||||||
except,
|
except,
|
||||||
exchange_malloc,
|
exchange_malloc,
|
||||||
|
@ -580,10 +583,10 @@ symbols! {
|
||||||
frem_fast,
|
frem_fast,
|
||||||
from,
|
from,
|
||||||
from_desugaring,
|
from_desugaring,
|
||||||
from_error,
|
|
||||||
from_generator,
|
from_generator,
|
||||||
from_method,
|
from_method,
|
||||||
from_ok,
|
from_output,
|
||||||
|
from_residual,
|
||||||
from_size_align_unchecked,
|
from_size_align_unchecked,
|
||||||
from_trait,
|
from_trait,
|
||||||
from_usize,
|
from_usize,
|
||||||
|
@ -652,7 +655,6 @@ symbols! {
|
||||||
instruction_set,
|
instruction_set,
|
||||||
intel,
|
intel,
|
||||||
into_iter,
|
into_iter,
|
||||||
into_result,
|
|
||||||
into_trait,
|
into_trait,
|
||||||
intra_doc_pointers,
|
intra_doc_pointers,
|
||||||
intrinsics,
|
intrinsics,
|
||||||
|
@ -962,6 +964,7 @@ symbols! {
|
||||||
repr_packed,
|
repr_packed,
|
||||||
repr_simd,
|
repr_simd,
|
||||||
repr_transparent,
|
repr_transparent,
|
||||||
|
residual,
|
||||||
result,
|
result,
|
||||||
result_type,
|
result_type,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -1227,7 +1230,7 @@ symbols! {
|
||||||
try_blocks,
|
try_blocks,
|
||||||
try_from_trait,
|
try_from_trait,
|
||||||
try_into_trait,
|
try_into_trait,
|
||||||
try_trait,
|
try_trait_v2,
|
||||||
tt,
|
tt,
|
||||||
tuple,
|
tuple,
|
||||||
tuple_from_req,
|
tuple_from_req,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
|
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
|
||||||
use crate::ops::TryWhereOutputEquals;
|
use crate::ops::{ControlFlow, TryWhereOutputEquals};
|
||||||
|
|
||||||
/// An iterator with a `peek()` that returns an optional reference to the next
|
/// An iterator with a `peek()` that returns an optional reference to the next
|
||||||
/// element.
|
/// element.
|
||||||
|
@ -130,12 +130,35 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
F: FnMut(B, Self::Item) -> R,
|
F: FnMut(B, Self::Item) -> R,
|
||||||
R: TryWhereOutputEquals<B>,
|
R: TryWhereOutputEquals<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: TryWhereOutputEquals<B>,
|
||||||
|
{
|
||||||
|
let _use_the_import: ControlFlow<()>;
|
||||||
match self.peeked.take() {
|
match self.peeked.take() {
|
||||||
Some(None) => try { init },
|
Some(None) => try { init },
|
||||||
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
|
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
|
||||||
|
|
|
@ -2412,6 +2412,36 @@ pub trait Iterator {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
|
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnMut(&Self::Item) -> R,
|
||||||
|
R: TryWhereOutputEquals<bool>,
|
||||||
|
// FIXME: This is a weird bound; the API should change
|
||||||
|
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: TryWhereOutputEquals<bool>,
|
||||||
|
R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
|
||||||
|
{
|
||||||
|
move |(), x| match f(&x).branch() {
|
||||||
|
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
|
||||||
|
ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
|
||||||
|
ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.try_fold((), check(f)).break_value().transpose()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We're bootstrapping.
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
|
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
|
@ -52,8 +52,10 @@ use crate::{convert, ops};
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum ControlFlow<B, C = ()> {
|
pub enum ControlFlow<B, C = ()> {
|
||||||
/// Move on to the next phase of the operation as normal.
|
/// Move on to the next phase of the operation as normal.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Continue")]
|
||||||
Continue(C),
|
Continue(C),
|
||||||
/// Exit the operation without running subsequent phases.
|
/// Exit the operation without running subsequent phases.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Break")]
|
||||||
Break(B),
|
Break(B),
|
||||||
// Yes, the order of the variants doesn't match the type parameters.
|
// Yes, the order of the variants doesn't match the type parameters.
|
||||||
// They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
|
// They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
|
||||||
|
@ -181,6 +183,7 @@ impl<B, C> ControlFlow<B, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
impl<R: ops::TryV1> ControlFlow<R, R::Ok> {
|
impl<R: ops::TryV1> ControlFlow<R, R::Ok> {
|
||||||
/// Create a `ControlFlow` from any type implementing `Try`.
|
/// Create a `ControlFlow` from any type implementing `Try`.
|
||||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||||
|
@ -203,6 +206,29 @@ impl<R: ops::TryV1> ControlFlow<R, R::Ok> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B> ControlFlow<B, ()> {
|
impl<B> ControlFlow<B, ()> {
|
||||||
/// It's frequently the case that there's no value needed with `Continue`,
|
/// It's frequently the case that there's no value needed with `Continue`,
|
||||||
/// so this provides a way to avoid typing `(())`, if you prefer it.
|
/// so this provides a way to avoid typing `(())`, if you prefer it.
|
||||||
|
|
|
@ -183,6 +183,7 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
|
||||||
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
|
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
|
||||||
|
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
pub use self::r#try::Try;
|
pub use self::r#try::Try;
|
||||||
|
|
||||||
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
||||||
|
@ -191,6 +192,10 @@ pub use self::r#try::Try as TryV1;
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
pub use self::try_trait::FromResidual;
|
pub use self::try_trait::FromResidual;
|
||||||
|
|
||||||
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub use self::try_trait::Try;
|
||||||
|
|
||||||
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
||||||
pub use self::try_trait::Try as TryV2;
|
pub use self::try_trait::Try as TryV2;
|
||||||
|
|
||||||
|
@ -220,4 +225,9 @@ pub use self::control_flow::ControlFlow;
|
||||||
/// foo::<Option<i32>, i32>();
|
/// foo::<Option<i32>, i32>();
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub trait TryWhereOutputEquals<T> = TryV2<Output = T>;
|
||||||
|
|
||||||
|
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
pub trait TryWhereOutputEquals<T> = TryV1<Ok = T>;
|
pub trait TryWhereOutputEquals<T> = TryV1<Ok = T>;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#[doc(alias = "?")]
|
#[doc(alias = "?")]
|
||||||
#[lang = "try"]
|
#[cfg_attr(bootstrap, lang = "try")]
|
||||||
pub trait Try {
|
pub trait Try {
|
||||||
/// The type of this value when viewed as successful.
|
/// The type of this value when viewed as successful.
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
|
@ -43,19 +43,19 @@ pub trait Try {
|
||||||
/// in the return type of the enclosing scope (which must itself implement
|
/// in the return type of the enclosing scope (which must itself implement
|
||||||
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
|
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
|
||||||
/// is returned, where `X` is the return type of the enclosing function.
|
/// is returned, where `X` is the return type of the enclosing function.
|
||||||
#[lang = "into_result"]
|
#[cfg_attr(bootstrap, lang = "into_result")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
|
||||||
/// Wrap an error value to construct the composite result. For example,
|
/// Wrap an error value to construct the composite result. For example,
|
||||||
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
|
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
|
||||||
#[lang = "from_error"]
|
#[cfg_attr(bootstrap, lang = "from_error")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn from_error(v: Self::Error) -> Self;
|
fn from_error(v: Self::Error) -> Self;
|
||||||
|
|
||||||
/// Wrap an OK value to construct the composite result. For example,
|
/// Wrap an OK value to construct the composite result. For example,
|
||||||
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
|
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
|
||||||
#[lang = "from_ok"]
|
#[cfg_attr(bootstrap, lang = "from_ok")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn from_ok(v: Self::Ok) -> Self;
|
fn from_ok(v: Self::Ok) -> Self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ use crate::ops::ControlFlow;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Try")]
|
||||||
pub trait Try: FromResidual {
|
pub trait Try: FromResidual {
|
||||||
/// The type of the value produced by `?` when *not* short-circuiting.
|
/// The type of the value produced by `?` when *not* short-circuiting.
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
|
@ -178,6 +179,7 @@ pub trait Try: FromResidual {
|
||||||
/// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
|
/// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
|
||||||
/// assert_eq!(r, Some(4));
|
/// assert_eq!(r, Some(4));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from_output")]
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
fn from_output(output: Self::Output) -> Self;
|
fn from_output(output: Self::Output) -> Self;
|
||||||
|
|
||||||
|
@ -206,6 +208,7 @@ pub trait Try: FromResidual {
|
||||||
/// ControlFlow::Break(ControlFlow::Break(3)),
|
/// ControlFlow::Break(ControlFlow::Break(3)),
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "branch")]
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
|
||||||
}
|
}
|
||||||
|
@ -238,6 +241,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||||
/// ControlFlow::Break(5),
|
/// ControlFlow::Break(5),
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from_residual")]
|
||||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||||
fn from_residual(residual: R) -> Self;
|
fn from_residual(residual: R) -> Self;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue