Skip to content

Commit 0b12d0d

Browse files
committed
PoC: A new hybrid design for Try
1 parent 3e826bb commit 0b12d0d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+808
-283
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+24-30
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
462462
)
463463
}
464464

465-
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
466-
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }`
465+
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::continue_with(<expr>) }`,
466+
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::continue_with(()) }`
467467
/// and save the block id to use it as a break target for desugaring of the `?` operator.
468468
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
469469
self.with_catch_scope(body.id, |this| {
@@ -492,9 +492,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
492492
let ok_wrapped_span =
493493
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
494494

495-
// `::std::ops::Try::from_ok($tail_expr)`
495+
// `::std::ops::Try::continue_with($tail_expr)`
496496
block.expr = Some(this.wrap_in_try_constructor(
497-
hir::LangItem::TryFromOk,
497+
hir::LangItem::TryContinueWith,
498498
try_span,
499499
tail_expr,
500500
ok_wrapped_span,
@@ -1793,14 +1793,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
17931793
self.allow_try_trait.clone(),
17941794
);
17951795

1796-
// `Try::into_result(<expr>)`
1796+
// `Try::branch(<expr>)`
17971797
let scrutinee = {
17981798
// expand <expr>
17991799
let sub_expr = self.lower_expr_mut(sub_expr);
18001800

18011801
self.expr_call_lang_item_fn(
18021802
unstable_span,
1803-
hir::LangItem::TryIntoResult,
1803+
hir::LangItem::TryBranch,
18041804
arena_vec![self; sub_expr],
18051805
)
18061806
};
@@ -1818,8 +1818,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
18181818
};
18191819
let attrs = vec![attr];
18201820

1821-
// `Ok(val) => #[allow(unreachable_code)] val,`
1822-
let ok_arm = {
1821+
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
1822+
let continue_arm = {
18231823
let val_ident = Ident::with_dummy_span(sym::val);
18241824
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
18251825
let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
@@ -1828,27 +1828,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
18281828
val_pat_nid,
18291829
ThinVec::from(attrs.clone()),
18301830
));
1831-
let ok_pat = self.pat_ok(span, val_pat);
1832-
self.arm(ok_pat, val_expr)
1831+
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
1832+
self.arm(continue_pat, val_expr)
18331833
};
18341834

1835-
// `Err(err) => #[allow(unreachable_code)]
1835+
// `ControlFlow::Break(err) => #[allow(unreachable_code)]
18361836
// return Try::from_error(From::from(err)),`
1837-
let err_arm = {
1838-
let err_ident = Ident::with_dummy_span(sym::err);
1839-
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
1840-
let from_expr = {
1841-
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
1842-
self.expr_call_lang_item_fn(
1843-
try_span,
1844-
hir::LangItem::FromFrom,
1845-
arena_vec![self; err_expr],
1846-
)
1847-
};
1848-
let from_err_expr = self.wrap_in_try_constructor(
1849-
hir::LangItem::TryFromError,
1837+
let break_arm = {
1838+
let holder_ident = Ident::with_dummy_span(sym::holder);
1839+
let (holder_local, holder_local_nid) = self.pat_ident(try_span, holder_ident);
1840+
let holder_expr =
1841+
self.arena.alloc(self.expr_ident_mut(try_span, holder_ident, holder_local_nid));
1842+
let from_holder_expr = self.wrap_in_try_constructor(
1843+
hir::LangItem::FromHolder,
18501844
unstable_span,
1851-
from_expr,
1845+
holder_expr,
18521846
unstable_span,
18531847
);
18541848
let thin_attrs = ThinVec::from(attrs);
@@ -1859,25 +1853,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
18591853
try_span,
18601854
hir::ExprKind::Break(
18611855
hir::Destination { label: None, target_id },
1862-
Some(from_err_expr),
1856+
Some(from_holder_expr),
18631857
),
18641858
thin_attrs,
18651859
))
18661860
} else {
18671861
self.arena.alloc(self.expr(
18681862
try_span,
1869-
hir::ExprKind::Ret(Some(from_err_expr)),
1863+
hir::ExprKind::Ret(Some(from_holder_expr)),
18701864
thin_attrs,
18711865
))
18721866
};
18731867

1874-
let err_pat = self.pat_err(try_span, err_local);
1875-
self.arm(err_pat, ret_expr)
1868+
let break_pat = self.pat_cf_break(unstable_span, holder_local);
1869+
self.arm(break_pat, ret_expr)
18761870
};
18771871

18781872
hir::ExprKind::Match(
18791873
scrutinee,
1880-
arena_vec![self; err_arm, ok_arm],
1874+
arena_vec![self; break_arm, continue_arm],
18811875
hir::MatchSource::TryDesugar,
18821876
)
18831877
}

compiler/rustc_ast_lowering/src/lib.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ pub fn lower_crate<'a, 'hir>(
324324
lifetimes_to_define: Vec::new(),
325325
is_collecting_in_band_lifetimes: false,
326326
in_scope_lifetimes: Vec::new(),
327-
allow_try_trait: Some([sym::try_trait][..].into()),
327+
allow_try_trait: Some([sym::try_trait, sym::try_trait_v2, sym::control_flow_enum][..].into()),
328328
allow_gen_future: Some([sym::gen_future][..].into()),
329329
}
330330
.lower_crate(krate)
@@ -2546,15 +2546,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
25462546
self.pat(span, hir::PatKind::Lit(expr))
25472547
}
25482548

2549-
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2550-
let field = self.single_pat_field(span, pat);
2551-
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
2552-
}
2549+
// fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2550+
// let field = self.single_pat_field(span, pat);
2551+
// self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
2552+
// }
25532553

2554-
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2555-
let field = self.single_pat_field(span, pat);
2556-
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
2557-
}
2554+
// fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2555+
// let field = self.single_pat_field(span, pat);
2556+
// self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
2557+
// }
25582558

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

2568+
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2569+
let field = self.single_pat_field(span, pat);
2570+
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
2571+
}
2572+
2573+
fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2574+
let field = self.single_pat_field(span, pat);
2575+
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
2576+
}
2577+
25682578
fn single_pat_field(
25692579
&mut self,
25702580
span: Span,

compiler/rustc_hir/src/lang_items.rs

+6
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ language_item_table! {
306306
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
307307
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
308308
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
309+
TryContinueWith, sym::continue_with, continue_with_fn, Target::Method(MethodKind::Trait { body: false });
310+
TryBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
311+
FromHolder, sym::from_holder, from_holder_fn, Target::Method(MethodKind::Trait { body: false });
309312

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

329+
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
330+
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant;
331+
326332
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
327333
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
328334

compiler/rustc_middle/src/ty/query/on_disk_cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ impl<'sess> OnDiskCache<'sess> {
405405

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

410410
// DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
411411
// of the footer must be the last thing in the data stream.

compiler/rustc_span/src/symbol.rs

+8
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,12 @@ symbols! {
126126
Argument,
127127
ArgumentV1,
128128
Arguments,
129+
Break,
129130
C,
130131
CString,
131132
Center,
132133
Clone,
134+
Continue,
133135
Copy,
134136
Count,
135137
Debug,
@@ -313,6 +315,7 @@ symbols! {
313315
box_patterns,
314316
box_syntax,
315317
braced_empty_structs,
318+
branch,
316319
breakpoint,
317320
bridge,
318321
bswap,
@@ -392,6 +395,8 @@ symbols! {
392395
constructor,
393396
contents,
394397
context,
398+
continue_with,
399+
control_flow_enum,
395400
convert,
396401
copy,
397402
copy_closures,
@@ -561,6 +566,7 @@ symbols! {
561566
from_desugaring,
562567
from_error,
563568
from_generator,
569+
from_holder,
564570
from_method,
565571
from_ok,
566572
from_size_align_unchecked,
@@ -587,6 +593,7 @@ symbols! {
587593
hash,
588594
hexagon_target_feature,
589595
hidden,
596+
holder,
590597
homogeneous_aggregate,
591598
html_favicon_url,
592599
html_logo_url,
@@ -1177,6 +1184,7 @@ symbols! {
11771184
try_from_trait,
11781185
try_into_trait,
11791186
try_trait,
1187+
try_trait_v2,
11801188
tt,
11811189
tuple,
11821190
tuple_from_req,

compiler/rustc_typeck/src/check/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
164164
) -> Ty<'tcx> {
165165
debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);
166166

167-
// True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block
167+
// True if `expr` is a `Try::continue_with(())` that is a result of desugaring a try block
168168
// without the final expr (e.g. `try { return; }`). We don't want to generate an
169169
// unreachable_code lint for it since warnings for autogenerated code are confusing.
170170
let is_try_block_generated_unit_expr = match expr.kind {

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
#![feature(alloc_layout_extra)]
138138
#![feature(trusted_random_access)]
139139
#![feature(try_trait)]
140+
#![feature(try_trait_v2)]
140141
#![feature(type_alias_impl_trait)]
141142
#![feature(associated_type_bounds)]
142143
#![feature(slice_group_by)]

library/core/src/iter/adapters/peekable.rs

+24
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ where
129129
}
130130
}
131131

132+
#[cfg(bootstrap)]
132133
#[inline]
133134
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
134135
where
@@ -149,6 +150,29 @@ where
149150
}
150151
}
151152

153+
#[cfg(not(bootstrap))]
154+
#[inline]
155+
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
156+
where
157+
Self: Sized,
158+
F: FnMut(B, Self::Item) -> R,
159+
R: Try<Ok = B>,
160+
{
161+
use crate::ops::ControlFlow;
162+
163+
match self.peeked.take() {
164+
Some(None) => try { init },
165+
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).branch() {
166+
ControlFlow::Continue(acc) => f(acc, v),
167+
ControlFlow::Break(h) => {
168+
self.peeked = Some(Some(v));
169+
R::from_holder(h)
170+
}
171+
},
172+
None => self.iter.try_rfold(init, f),
173+
}
174+
}
175+
152176
#[inline]
153177
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
154178
where

library/core/src/iter/traits/iterator.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// can't split that into multiple files.
44

55
use crate::cmp::{self, Ordering};
6-
use crate::ops::{Add, ControlFlow, Try};
6+
use crate::ops::{self, Add, ControlFlow, Try};
77

88
use super::super::TrustedRandomAccess;
99
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
@@ -2388,13 +2388,14 @@ pub trait Iterator {
23882388
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
23892389
/// assert!(result.is_err());
23902390
/// ```
2391+
#[cfg(bootstrap)]
23912392
#[inline]
23922393
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
23932394
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
23942395
where
23952396
Self: Sized,
23962397
F: FnMut(&Self::Item) -> R,
2397-
R: Try<Ok = bool>,
2398+
R: ops::Try<Ok = bool>,
23982399
{
23992400
#[inline]
24002401
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
@@ -2412,6 +2413,59 @@ pub trait Iterator {
24122413
self.try_fold((), check(f)).break_value().transpose()
24132414
}
24142415

2416+
/// Applies function to the elements of iterator and returns
2417+
/// the first true result or the first error.
2418+
///
2419+
/// # Examples
2420+
///
2421+
/// ```
2422+
/// #![feature(try_find)]
2423+
///
2424+
/// let a = ["1", "2", "lol", "NaN", "5"];
2425+
///
2426+
/// let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
2427+
/// Ok(s.parse::<i32>()? == search)
2428+
/// };
2429+
///
2430+
/// let result = a.iter().try_find(|&&s| is_my_num(s, 2));
2431+
/// assert_eq!(result, Ok(Some(&"2")));
2432+
///
2433+
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
2434+
/// assert!(result.is_err());
2435+
/// ```
2436+
#[cfg(not(bootstrap))]
2437+
#[inline]
2438+
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
2439+
fn try_find<F, R>(
2440+
&mut self,
2441+
f: F,
2442+
) -> <R::Holder as ops::BreakHolder<Option<Self::Item>>>::Output
2443+
where
2444+
Self: Sized,
2445+
F: FnMut(&Self::Item) -> R,
2446+
R: ops::Try<Ok = bool>,
2447+
R::Holder: ops::BreakHolder<Option<Self::Item>>,
2448+
{
2449+
#[inline]
2450+
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Holder>>
2451+
where
2452+
F: FnMut(&T) -> R,
2453+
R: Try<Ok = bool>,
2454+
{
2455+
move |(), x| match f(&x).branch() {
2456+
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
2457+
ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
2458+
ControlFlow::Break(h) => ControlFlow::Break(Err(h)),
2459+
}
2460+
}
2461+
2462+
match self.try_fold((), check(f)) {
2463+
ControlFlow::Continue(()) => ops::TryCore::continue_with(None),
2464+
ControlFlow::Break(Ok(x)) => ops::TryCore::continue_with(Some(x)),
2465+
ControlFlow::Break(Err(h)) => Try::from_holder(h),
2466+
}
2467+
}
2468+
24152469
/// Searches for an element in an iterator, returning its index.
24162470
///
24172471
/// `position()` takes a closure that returns `true` or `false`. It applies

0 commit comments

Comments
 (0)