Skip to content

[FOR CRATER ONLY] New implementation of Try per RFC#3058 -- No result-to-option #82322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
54 changes: 24 additions & 30 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,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::continue_with(<expr>) }`,
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::continue_with(()) }`
/// 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| {
Expand Down Expand Up @@ -492,9 +492,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::continue_with($tail_expr)`
block.expr = Some(this.wrap_in_try_constructor(
hir::LangItem::TryFromOk,
hir::LangItem::TryContinueWith,
try_span,
tail_expr,
ok_wrapped_span,
Expand Down Expand Up @@ -1793,14 +1793,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::TryBranch,
arena_vec![self; sub_expr],
)
};
Expand All @@ -1818,8 +1818,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(
Expand All @@ -1828,27 +1828,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)]
// `ControlFlow::Break(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,
let break_arm = {
let holder_ident = Ident::with_dummy_span(sym::holder);
let (holder_local, holder_local_nid) = self.pat_ident(try_span, holder_ident);
let holder_expr =
self.arena.alloc(self.expr_ident_mut(try_span, holder_ident, holder_local_nid));
let from_holder_expr = self.wrap_in_try_constructor(
hir::LangItem::FromHolder,
unstable_span,
from_expr,
holder_expr,
unstable_span,
);
let thin_attrs = ThinVec::from(attrs);
Expand All @@ -1859,25 +1853,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
try_span,
hir::ExprKind::Break(
hir::Destination { label: None, target_id },
Some(from_err_expr),
Some(from_holder_expr),
),
thin_attrs,
))
} else {
self.arena.alloc(self.expr(
try_span,
hir::ExprKind::Ret(Some(from_err_expr)),
hir::ExprKind::Ret(Some(from_holder_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(unstable_span, holder_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,
)
}
Expand Down
30 changes: 21 additions & 9 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,9 @@ 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::try_trait, sym::try_trait_v2, sym::control_flow_enum][..].into(),
),
allow_gen_future: Some([sym::gen_future][..].into()),
}
.lower_crate(krate)
Expand Down Expand Up @@ -2546,15 +2548,15 @@ 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> {
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
}
// fn pat_ok(&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)
// }

fn pat_err(&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)
}
// fn pat_err(&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)
// }

fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
Expand All @@ -2565,6 +2567,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[])
}

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::ControlFlowContinue, field)
}

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::ControlFlowBreak, field)
}

fn single_pat_field(
&mut self,
span: Span,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ language_item_table! {
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 });
TryContinueWith, sym::continue_with, continue_with_fn, Target::Method(MethodKind::Trait { body: false });
TryBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
FromHolder, sym::from_holder, from_holder_fn, Target::Method(MethodKind::Trait { body: false });

PollReady, sym::Ready, poll_ready_variant, Target::Variant;
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
Expand All @@ -323,6 +326,9 @@ language_item_table! {
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
ResultErr, sym::Err, result_err_variant, Target::Variant;

ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
ControlFlowContinue, sym::Continue, cf_continue_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});

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/query/on_disk_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ impl<'sess> OnDiskCache<'sess> {

// Encode the position of the footer as the last 8 bytes of the
// file so we know where to look for it.
IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder).map_err(|x| x)?;

// DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
// of the footer must be the last thing in the data stream.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,12 @@ symbols! {
Argument,
ArgumentV1,
Arguments,
Break,
C,
CString,
Center,
Clone,
Continue,
Copy,
Count,
Debug,
Expand Down Expand Up @@ -313,6 +315,7 @@ symbols! {
box_patterns,
box_syntax,
braced_empty_structs,
branch,
breakpoint,
bridge,
bswap,
Expand Down Expand Up @@ -392,6 +395,8 @@ symbols! {
constructor,
contents,
context,
continue_with,
control_flow_enum,
convert,
copy,
copy_closures,
Expand Down Expand Up @@ -561,6 +566,7 @@ symbols! {
from_desugaring,
from_error,
from_generator,
from_holder,
from_method,
from_ok,
from_size_align_unchecked,
Expand All @@ -587,6 +593,7 @@ symbols! {
hash,
hexagon_target_feature,
hidden,
holder,
homogeneous_aggregate,
html_favicon_url,
html_logo_url,
Expand Down Expand Up @@ -1177,6 +1184,7 @@ symbols! {
try_from_trait,
try_into_trait,
try_trait,
try_trait_v2,
tt,
tuple,
tuple_from_req,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);

// True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block
// True if `expr` is a `Try::continue_with(())` that is a result of desugaring a try block
// without the final expr (e.g. `try { return; }`). We don't want to generate an
// unreachable_code lint for it since warnings for autogenerated code are confusing.
let is_try_block_generated_unit_expr = match expr.kind {
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
#![feature(alloc_layout_extra)]
#![feature(trusted_random_access)]
#![feature(try_trait)]
#![feature(try_trait_v2)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
Expand Down
24 changes: 24 additions & 0 deletions library/core/src/iter/adapters/peekable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ where
}
}

#[cfg(bootstrap)]
#[inline]
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Expand All @@ -149,6 +150,29 @@ where
}
}

#[cfg(not(bootstrap))]
#[inline]
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>,
{
use crate::ops::ControlFlow;

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]
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
where
Expand Down
60 changes: 58 additions & 2 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// can't split that into multiple files.

use crate::cmp::{self, Ordering};
use crate::ops::{Add, ControlFlow, Try};
#[cfg(not(bootstrap))]
use crate::ops::FromResidual;
use crate::ops::{self, Add, ControlFlow, Try};

use super::super::TrustedRandomAccess;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
Expand Down Expand Up @@ -2388,13 +2390,14 @@ pub trait Iterator {
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
/// assert!(result.is_err());
/// ```
#[cfg(bootstrap)]
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
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: ops::Try<Ok = bool>,
{
#[inline]
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
Expand All @@ -2412,6 +2415,59 @@ pub trait Iterator {
self.try_fold((), check(f)).break_value().transpose()
}

/// Applies function to the elements of iterator and returns
/// the first true result or the first error.
///
/// # Examples
///
/// ```
/// #![feature(try_find)]
///
/// let a = ["1", "2", "lol", "NaN", "5"];
///
/// let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
/// Ok(s.parse::<i32>()? == search)
/// };
///
/// let result = a.iter().try_find(|&&s| is_my_num(s, 2));
/// assert_eq!(result, Ok(Some(&"2")));
///
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
/// assert!(result.is_err());
/// ```
#[cfg(not(bootstrap))]
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
fn try_find<F, R>(
&mut self,
f: F,
) -> <R::Residual as ops::GetCorrespondingTryType<Option<Self::Item>>>::Output
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
R: ops::Try<Ok = bool>,
R::Residual: ops::GetCorrespondingTryType<Option<Self::Item>>,
{
#[inline]
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Residual>>
where
F: FnMut(&T) -> R,
R: Try<Ok = bool>,
{
move |(), x| match f(&x).branch() {
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
ControlFlow::Break(r) => ControlFlow::Break(Err(r)),
}
}

match self.try_fold((), check(f)) {
ControlFlow::Continue(()) => Try::from_output(None),
ControlFlow::Break(Ok(x)) => Try::from_output(Some(x)),
ControlFlow::Break(Err(r)) => <_>::from_residual(r),
}
}

/// Searches for an element in an iterator, returning its index.
///
/// `position()` takes a closure that returns `true` or `false`. It applies
Expand Down
Loading