Skip to content

Commit ca92b5a

Browse files
committedMay 6, 2021
Actually implement the feature in the compiler
Including all the bootstrapping tweaks in the library.
1 parent c10eec3 commit ca92b5a

File tree

10 files changed

+144
-51
lines changed

10 files changed

+144
-51
lines changed
 

‎compiler/rustc_ast_lowering/src/expr.rs

+26-32
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
562562
)
563563
}
564564

565-
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
566-
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }`
565+
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
566+
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
567567
/// and save the block id to use it as a break target for desugaring of the `?` operator.
568568
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
569569
self.with_catch_scope(body.id, |this| {
@@ -592,9 +592,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
592592
let ok_wrapped_span =
593593
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
594594

595-
// `::std::ops::Try::from_ok($tail_expr)`
595+
// `::std::ops::Try::from_output($tail_expr)`
596596
block.expr = Some(this.wrap_in_try_constructor(
597-
hir::LangItem::TryFromOk,
597+
hir::LangItem::TryTraitFromOutput,
598598
try_span,
599599
tail_expr,
600600
ok_wrapped_span,
@@ -1896,14 +1896,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
18961896
self.allow_try_trait.clone(),
18971897
);
18981898

1899-
// `Try::into_result(<expr>)`
1899+
// `Try::branch(<expr>)`
19001900
let scrutinee = {
19011901
// expand <expr>
19021902
let sub_expr = self.lower_expr_mut(sub_expr);
19031903

19041904
self.expr_call_lang_item_fn(
19051905
unstable_span,
1906-
hir::LangItem::TryIntoResult,
1906+
hir::LangItem::TryTraitBranch,
19071907
arena_vec![self; sub_expr],
19081908
)
19091909
};
@@ -1921,8 +1921,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
19211921
};
19221922
let attrs = vec![attr];
19231923

1924-
// `Ok(val) => #[allow(unreachable_code)] val,`
1925-
let ok_arm = {
1924+
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
1925+
let continue_arm = {
19261926
let val_ident = Ident::with_dummy_span(sym::val);
19271927
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
19281928
let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
@@ -1931,27 +1931,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
19311931
val_pat_nid,
19321932
ThinVec::from(attrs.clone()),
19331933
));
1934-
let ok_pat = self.pat_ok(span, val_pat);
1935-
self.arm(ok_pat, val_expr)
1934+
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
1935+
self.arm(continue_pat, val_expr)
19361936
};
19371937

1938-
// `Err(err) => #[allow(unreachable_code)]
1939-
// return Try::from_error(From::from(err)),`
1940-
let err_arm = {
1941-
let err_ident = Ident::with_dummy_span(sym::err);
1942-
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
1943-
let from_expr = {
1944-
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
1945-
self.expr_call_lang_item_fn(
1946-
try_span,
1947-
hir::LangItem::FromFrom,
1948-
arena_vec![self; err_expr],
1949-
)
1950-
};
1951-
let from_err_expr = self.wrap_in_try_constructor(
1952-
hir::LangItem::TryFromError,
1953-
unstable_span,
1954-
from_expr,
1938+
// `ControlFlow::Break(residual) =>
1939+
// #[allow(unreachable_code)]
1940+
// return Try::from_residual(residual),`
1941+
let break_arm = {
1942+
let residual_ident = Ident::with_dummy_span(sym::residual);
1943+
let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
1944+
let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
1945+
let from_residual_expr = self.wrap_in_try_constructor(
1946+
hir::LangItem::TryTraitFromResidual,
1947+
try_span,
1948+
self.arena.alloc(residual_expr),
19551949
unstable_span,
19561950
);
19571951
let thin_attrs = ThinVec::from(attrs);
@@ -1962,25 +1956,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
19621956
try_span,
19631957
hir::ExprKind::Break(
19641958
hir::Destination { label: None, target_id },
1965-
Some(from_err_expr),
1959+
Some(from_residual_expr),
19661960
),
19671961
thin_attrs,
19681962
))
19691963
} else {
19701964
self.arena.alloc(self.expr(
19711965
try_span,
1972-
hir::ExprKind::Ret(Some(from_err_expr)),
1966+
hir::ExprKind::Ret(Some(from_residual_expr)),
19731967
thin_attrs,
19741968
))
19751969
};
19761970

1977-
let err_pat = self.pat_err(try_span, err_local);
1978-
self.arm(err_pat, ret_expr)
1971+
let break_pat = self.pat_cf_break(try_span, residual_local);
1972+
self.arm(break_pat, ret_expr)
19791973
};
19801974

19811975
hir::ExprKind::Match(
19821976
scrutinee,
1983-
arena_vec![self; err_arm, ok_arm],
1977+
arena_vec![self; break_arm, continue_arm],
19841978
hir::MatchSource::TryDesugar,
19851979
)
19861980
}

‎compiler/rustc_ast_lowering/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ pub fn lower_crate<'a, 'hir>(
331331
lifetimes_to_define: Vec::new(),
332332
is_collecting_in_band_lifetimes: false,
333333
in_scope_lifetimes: Vec::new(),
334-
allow_try_trait: Some([sym::try_trait][..].into()),
334+
allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
335335
allow_gen_future: Some([sym::gen_future][..].into()),
336336
}
337337
.lower_crate(krate)
@@ -2479,14 +2479,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24792479
self.pat(span, hir::PatKind::Lit(expr))
24802480
}
24812481

2482-
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2482+
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
24832483
let field = self.single_pat_field(span, pat);
2484-
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
2484+
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
24852485
}
24862486

2487-
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
2487+
fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
24882488
let field = self.single_pat_field(span, pat);
2489-
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
2489+
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
24902490
}
24912491

24922492
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {

‎compiler/rustc_hir/src/lang_items.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,12 @@ language_item_table! {
308308

309309
Termination, sym::termination, termination, Target::Trait;
310310

311-
Try, kw::Try, try_trait, Target::Trait;
311+
Try, sym::Try, try_trait, Target::Trait;
312312

313313
// Language items from AST lowering
314-
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
315-
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
316-
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
314+
TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false });
315+
TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false });
316+
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
317317

318318
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
319319
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
@@ -331,6 +331,9 @@ language_item_table! {
331331
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
332332
ResultErr, sym::Err, result_err_variant, Target::Variant;
333333

334+
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant;
335+
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
336+
334337
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
335338
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
336339

‎compiler/rustc_span/src/symbol.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,12 @@ symbols! {
130130
BTreeSet,
131131
BinaryHeap,
132132
Borrow,
133+
Break,
133134
C,
134135
CString,
135136
Center,
136137
Clone,
138+
Continue,
137139
Copy,
138140
Count,
139141
Debug,
@@ -326,6 +328,7 @@ symbols! {
326328
box_patterns,
327329
box_syntax,
328330
braced_empty_structs,
331+
branch,
329332
breakpoint,
330333
bridge,
331334
bswap,
@@ -410,6 +413,7 @@ symbols! {
410413
constructor,
411414
contents,
412415
context,
416+
control_flow_enum,
413417
convert,
414418
copy,
415419
copy_closures,
@@ -510,7 +514,6 @@ symbols! {
510514
env,
511515
eq,
512516
ermsb_target_feature,
513-
err,
514517
exact_div,
515518
except,
516519
exchange_malloc,
@@ -580,10 +583,10 @@ symbols! {
580583
frem_fast,
581584
from,
582585
from_desugaring,
583-
from_error,
584586
from_generator,
585587
from_method,
586-
from_ok,
588+
from_output,
589+
from_residual,
587590
from_size_align_unchecked,
588591
from_trait,
589592
from_usize,
@@ -652,7 +655,6 @@ symbols! {
652655
instruction_set,
653656
intel,
654657
into_iter,
655-
into_result,
656658
into_trait,
657659
intra_doc_pointers,
658660
intrinsics,
@@ -962,6 +964,7 @@ symbols! {
962964
repr_packed,
963965
repr_simd,
964966
repr_transparent,
967+
residual,
965968
result,
966969
result_type,
967970
rhs,
@@ -1227,7 +1230,7 @@ symbols! {
12271230
try_blocks,
12281231
try_from_trait,
12291232
try_into_trait,
1230-
try_trait,
1233+
try_trait_v2,
12311234
tt,
12321235
tuple,
12331236
tuple_from_req,

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

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
2-
use crate::ops::TryWhereOutputEquals;
2+
use crate::ops::{ControlFlow, TryWhereOutputEquals};
33

44
/// An iterator with a `peek()` that returns an optional reference to the next
55
/// element.
@@ -130,12 +130,35 @@ where
130130
}
131131

132132
#[inline]
133+
#[cfg(not(bootstrap))]
133134
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
134135
where
135136
Self: Sized,
136137
F: FnMut(B, Self::Item) -> R,
137138
R: TryWhereOutputEquals<B>,
138139
{
140+
match self.peeked.take() {
141+
Some(None) => try { init },
142+
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).branch() {
143+
ControlFlow::Continue(acc) => f(acc, v),
144+
ControlFlow::Break(r) => {
145+
self.peeked = Some(Some(v));
146+
R::from_residual(r)
147+
}
148+
},
149+
None => self.iter.try_rfold(init, f),
150+
}
151+
}
152+
153+
#[inline]
154+
#[cfg(bootstrap)]
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: TryWhereOutputEquals<B>,
160+
{
161+
let _use_the_import: ControlFlow<()>;
139162
match self.peeked.take() {
140163
Some(None) => try { init },
141164
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {

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

+30
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,36 @@ pub trait Iterator {
24122412
/// ```
24132413
#[inline]
24142414
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
2415+
#[cfg(not(bootstrap))]
2416+
fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
2417+
where
2418+
Self: Sized,
2419+
F: FnMut(&Self::Item) -> R,
2420+
R: TryWhereOutputEquals<bool>,
2421+
// FIXME: This is a weird bound; the API should change
2422+
R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
2423+
{
2424+
#[inline]
2425+
fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
2426+
where
2427+
F: FnMut(&T) -> R,
2428+
R: TryWhereOutputEquals<bool>,
2429+
R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
2430+
{
2431+
move |(), x| match f(&x).branch() {
2432+
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
2433+
ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
2434+
ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
2435+
}
2436+
}
2437+
2438+
self.try_fold((), check(f)).break_value().transpose()
2439+
}
2440+
2441+
/// We're bootstrapping.
2442+
#[inline]
2443+
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
2444+
#[cfg(bootstrap)]
24152445
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
24162446
where
24172447
Self: Sized,

‎library/core/src/ops/control_flow.rs

+26
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ use crate::{convert, ops};
5252
#[derive(Debug, Clone, Copy, PartialEq)]
5353
pub enum ControlFlow<B, C = ()> {
5454
/// Move on to the next phase of the operation as normal.
55+
#[cfg_attr(not(bootstrap), lang = "Continue")]
5556
Continue(C),
5657
/// Exit the operation without running subsequent phases.
58+
#[cfg_attr(not(bootstrap), lang = "Break")]
5759
Break(B),
5860
// Yes, the order of the variants doesn't match the type parameters.
5961
// They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
@@ -181,6 +183,7 @@ impl<B, C> ControlFlow<B, C> {
181183
}
182184
}
183185

186+
#[cfg(bootstrap)]
184187
impl<R: ops::TryV1> ControlFlow<R, R::Ok> {
185188
/// Create a `ControlFlow` from any type implementing `Try`.
186189
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
@@ -203,6 +206,29 @@ impl<R: ops::TryV1> ControlFlow<R, R::Ok> {
203206
}
204207
}
205208

209+
#[cfg(not(bootstrap))]
210+
impl<R: ops::TryV2> ControlFlow<R, R::Output> {
211+
/// Create a `ControlFlow` from any type implementing `Try`.
212+
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
213+
#[inline]
214+
pub fn from_try(r: R) -> Self {
215+
match R::branch(r) {
216+
ControlFlow::Continue(v) => ControlFlow::Continue(v),
217+
ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
218+
}
219+
}
220+
221+
/// Convert a `ControlFlow` into any type implementing `Try`;
222+
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
223+
#[inline]
224+
pub fn into_try(self) -> R {
225+
match self {
226+
ControlFlow::Continue(v) => R::from_output(v),
227+
ControlFlow::Break(v) => v,
228+
}
229+
}
230+
}
231+
206232
impl<B> ControlFlow<B, ()> {
207233
/// It's frequently the case that there's no value needed with `Continue`,
208234
/// so this provides a way to avoid typing `(())`, if you prefer it.

‎library/core/src/ops/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
183183
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
184184

185185
#[unstable(feature = "try_trait", issue = "42327")]
186+
#[cfg(bootstrap)]
186187
pub use self::r#try::Try;
187188

188189
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
@@ -191,6 +192,10 @@ pub use self::r#try::Try as TryV1;
191192
#[unstable(feature = "try_trait_v2", issue = "84277")]
192193
pub use self::try_trait::FromResidual;
193194

195+
#[unstable(feature = "try_trait_v2", issue = "84277")]
196+
#[cfg(not(bootstrap))]
197+
pub use self::try_trait::Try;
198+
194199
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
195200
pub use self::try_trait::Try as TryV2;
196201

@@ -220,4 +225,9 @@ pub use self::control_flow::ControlFlow;
220225
/// foo::<Option<i32>, i32>();
221226
/// ```
222227
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
228+
#[cfg(not(bootstrap))]
229+
pub trait TryWhereOutputEquals<T> = TryV2<Output = T>;
230+
231+
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
232+
#[cfg(bootstrap)]
223233
pub trait TryWhereOutputEquals<T> = TryV1<Ok = T>;

‎library/core/src/ops/try.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
)
2626
)]
2727
#[doc(alias = "?")]
28-
#[lang = "try"]
28+
#[cfg_attr(bootstrap, lang = "try")]
2929
pub trait Try {
3030
/// The type of this value when viewed as successful.
3131
#[unstable(feature = "try_trait", issue = "42327")]
@@ -43,19 +43,19 @@ pub trait Try {
4343
/// in the return type of the enclosing scope (which must itself implement
4444
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
4545
/// is returned, where `X` is the return type of the enclosing function.
46-
#[lang = "into_result"]
46+
#[cfg_attr(bootstrap, lang = "into_result")]
4747
#[unstable(feature = "try_trait", issue = "42327")]
4848
fn into_result(self) -> Result<Self::Ok, Self::Error>;
4949

5050
/// Wrap an error value to construct the composite result. For example,
5151
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
52-
#[lang = "from_error"]
52+
#[cfg_attr(bootstrap, lang = "from_error")]
5353
#[unstable(feature = "try_trait", issue = "42327")]
5454
fn from_error(v: Self::Error) -> Self;
5555

5656
/// Wrap an OK value to construct the composite result. For example,
5757
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
58-
#[lang = "from_ok"]
58+
#[cfg_attr(bootstrap, lang = "from_ok")]
5959
#[unstable(feature = "try_trait", issue = "42327")]
6060
fn from_ok(v: Self::Ok) -> Self;
6161
}

‎library/core/src/ops/try_trait.rs

+4
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ use crate::ops::ControlFlow;
119119
/// }
120120
/// ```
121121
#[unstable(feature = "try_trait_v2", issue = "84277")]
122+
#[cfg_attr(not(bootstrap), lang = "Try")]
122123
pub trait Try: FromResidual {
123124
/// The type of the value produced by `?` when *not* short-circuiting.
124125
#[unstable(feature = "try_trait_v2", issue = "84277")]
@@ -178,6 +179,7 @@ pub trait Try: FromResidual {
178179
/// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
179180
/// assert_eq!(r, Some(4));
180181
/// ```
182+
#[cfg_attr(not(bootstrap), lang = "from_output")]
181183
#[unstable(feature = "try_trait_v2", issue = "84277")]
182184
fn from_output(output: Self::Output) -> Self;
183185

@@ -206,6 +208,7 @@ pub trait Try: FromResidual {
206208
/// ControlFlow::Break(ControlFlow::Break(3)),
207209
/// );
208210
/// ```
211+
#[cfg_attr(not(bootstrap), lang = "branch")]
209212
#[unstable(feature = "try_trait_v2", issue = "84277")]
210213
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
211214
}
@@ -238,6 +241,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
238241
/// ControlFlow::Break(5),
239242
/// );
240243
/// ```
244+
#[cfg_attr(not(bootstrap), lang = "from_residual")]
241245
#[unstable(feature = "try_trait_v2", issue = "84277")]
242246
fn from_residual(residual: R) -> Self;
243247
}

0 commit comments

Comments
 (0)
Please sign in to comment.