Skip to content

Commit c6fa5ee

Browse files
committed
Use a Carrier trait with the ? operator
Allows use with `Option` and custom `Result`-like types.
1 parent 1744c46 commit c6fa5ee

File tree

4 files changed

+289
-49
lines changed

4 files changed

+289
-49
lines changed

src/libcore/ops.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
use cmp::PartialOrd;
7171
use fmt;
7272
use marker::{Sized, Unsize};
73+
use result::Result::{self, Ok, Err};
74+
use option::Option::{self, Some, None};
7375

7476
/// The `Drop` trait is used to run some code when a value goes out of scope.
7577
/// This is sometimes called a 'destructor'.
@@ -2145,3 +2147,126 @@ pub trait BoxPlace<Data: ?Sized> : Place<Data> {
21452147
/// Creates a globally fresh place.
21462148
fn make_place() -> Self;
21472149
}
2150+
2151+
/// A trait for types which have success and error states and are meant to work
2152+
/// with the question mark operator.
2153+
/// When the `?` operator is used with a value, whether the value is in the
2154+
/// success or error state is determined by calling `translate`.
2155+
///
2156+
/// This trait is **very** experimental, it will probably be iterated on heavily
2157+
/// before it is stabilised. Implementors should expect change. Users of `?`
2158+
/// should not rely on any implementations of `Carrier` other than `Result`,
2159+
/// i.e., you should not expect `?` to continue to work with `Option`, etc.
2160+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2161+
pub trait Carrier {
2162+
/// The type of the value when computation succeeds.
2163+
type Success;
2164+
/// The type of the value when computation errors out.
2165+
type Error;
2166+
2167+
/// Create a `Carrier` from a success value.
2168+
fn from_success(Self::Success) -> Self;
2169+
2170+
/// Create a `Carrier` from an error value.
2171+
fn from_error(Self::Error) -> Self;
2172+
2173+
/// Translate this `Carrier` to another implementation of `Carrier` with the
2174+
/// same associated types.
2175+
fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
2176+
}
2177+
2178+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2179+
impl<U, V> Carrier for Result<U, V> {
2180+
type Success = U;
2181+
type Error = V;
2182+
2183+
fn from_success(u: U) -> Result<U, V> {
2184+
Ok(u)
2185+
}
2186+
2187+
fn from_error(e: V) -> Result<U, V> {
2188+
Err(e)
2189+
}
2190+
2191+
fn translate<T>(self) -> T
2192+
where T: Carrier<Success=U, Error=V>
2193+
{
2194+
match self {
2195+
Ok(u) => T::from_success(u),
2196+
Err(e) => T::from_error(e),
2197+
}
2198+
}
2199+
}
2200+
2201+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2202+
impl<U> Carrier for Option<U> {
2203+
type Success = U;
2204+
type Error = ();
2205+
2206+
fn from_success(u: U) -> Option<U> {
2207+
Some(u)
2208+
}
2209+
2210+
fn from_error(_: ()) -> Option<U> {
2211+
None
2212+
}
2213+
2214+
fn translate<T>(self) -> T
2215+
where T: Carrier<Success=U, Error=()>
2216+
{
2217+
match self {
2218+
Some(u) => T::from_success(u),
2219+
None => T::from_error(()),
2220+
}
2221+
}
2222+
}
2223+
2224+
// Implementing Carrier for bools means it's easy to write short-circuiting
2225+
// functions. E.g.,
2226+
// ```
2227+
// fn foo() -> bool {
2228+
// if !(f() || g()) {
2229+
// return false;
2230+
// }
2231+
//
2232+
// some_computation();
2233+
// if h() {
2234+
// return false;
2235+
// }
2236+
//
2237+
// more_computation();
2238+
// i()
2239+
// }
2240+
// ```
2241+
// becomes
2242+
// ```
2243+
// fn foo() -> bool {
2244+
// (f() || g())?;
2245+
// some_computation();
2246+
// (!h())?;
2247+
// more_computation();
2248+
// i()
2249+
// }
2250+
// ```
2251+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2252+
impl Carrier for bool {
2253+
type Success = ();
2254+
type Error = ();
2255+
2256+
fn from_success(_: ()) -> bool {
2257+
true
2258+
}
2259+
2260+
fn from_error(_: ()) -> bool {
2261+
false
2262+
}
2263+
2264+
fn translate<T>(self) -> T
2265+
where T: Carrier<Success=(), Error=()>
2266+
{
2267+
match self {
2268+
true => T::from_success(()),
2269+
false => T::from_error(()),
2270+
}
2271+
}
2272+
}

src/librustc/hir/lowering.rs

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ impl<'a> LoweringContext<'a> {
964964
let inplace_finalize = ["ops", "InPlace", "finalize"];
965965

966966
let make_call = |this: &mut LoweringContext, p, args| {
967-
let path = this.core_path(e.span, p);
967+
let path = this.std_path(e.span, p);
968968
let path = this.expr_path(path, ThinVec::new());
969969
this.expr_call(e.span, path, args)
970970
};
@@ -1157,15 +1157,13 @@ impl<'a> LoweringContext<'a> {
11571157
ast_expr: &Expr,
11581158
path: &[&str],
11591159
fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
1160-
let strs = this.std_path(&iter::once(&"ops")
1161-
.chain(path)
1162-
.map(|s| *s)
1163-
.collect::<Vec<_>>());
1164-
1165-
let structpath = this.path_global(ast_expr.span, strs);
1160+
let struct_path = this.std_path(ast_expr.span,
1161+
&iter::once(&"ops").chain(path)
1162+
.map(|s| *s)
1163+
.collect::<Vec<_>>());
11661164

11671165
let hir_expr = if fields.len() == 0 {
1168-
this.expr_path(structpath, ast_expr.attrs.clone())
1166+
this.expr_path(struct_path, ast_expr.attrs.clone())
11691167
} else {
11701168
let fields = fields.into_iter().map(|&(s, e)| {
11711169
let expr = this.lower_expr(&e);
@@ -1178,7 +1176,7 @@ impl<'a> LoweringContext<'a> {
11781176
}).collect();
11791177
let attrs = ast_expr.attrs.clone();
11801178

1181-
this.expr_struct(ast_expr.span, structpath, fields, None, attrs)
1179+
this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
11821180
};
11831181

11841182
this.signal_block_expr(hir_vec![],
@@ -1461,11 +1459,7 @@ impl<'a> LoweringContext<'a> {
14611459

14621460
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
14631461
let match_expr = {
1464-
let next_path = {
1465-
let strs = self.std_path(&["iter", "Iterator", "next"]);
1466-
1467-
self.path_global(e.span, strs)
1468-
};
1462+
let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
14691463
let iter = self.expr_ident(e.span, iter, iter_pat.id);
14701464
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
14711465
let next_path = self.expr_path(next_path, ThinVec::new());
@@ -1492,11 +1486,8 @@ impl<'a> LoweringContext<'a> {
14921486

14931487
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14941488
let into_iter_expr = {
1495-
let into_iter_path = {
1496-
let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]);
1497-
1498-
self.path_global(e.span, strs)
1499-
};
1489+
let into_iter_path = self.std_path(e.span,
1490+
&["iter", "IntoIterator", "into_iter"]);
15001491

15011492
let into_iter = self.expr_path(into_iter_path, ThinVec::new());
15021493
self.expr_call(e.span, into_iter, hir_vec![head])
@@ -1525,16 +1516,32 @@ impl<'a> LoweringContext<'a> {
15251516
// to:
15261517
//
15271518
// {
1528-
// match <expr> {
1519+
// match { Carrier::translate( { <expr> } ) } {
15291520
// Ok(val) => val,
1530-
// Err(err) => {
1531-
// return Err(From::from(err))
1532-
// }
1521+
// Err(err) => { return Carrier::from_error(From::from(err)); }
15331522
// }
15341523
// }
15351524

1536-
// expand <expr>
1537-
let sub_expr = self.lower_expr(sub_expr);
1525+
// { Carrier::translate( { <expr> } ) }
1526+
let discr = {
1527+
// expand <expr>
1528+
let sub_expr = self.lower_expr(sub_expr);
1529+
let sub_expr = self.signal_block_expr(hir_vec![],
1530+
sub_expr,
1531+
e.span,
1532+
hir::PopUnstableBlock,
1533+
ThinVec::new());
1534+
1535+
let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
1536+
let path = self.expr_path(path, ThinVec::new());
1537+
let call = self.expr_call(e.span, path, hir_vec![sub_expr]);
1538+
1539+
self.signal_block_expr(hir_vec![],
1540+
call,
1541+
e.span,
1542+
hir::PushUnstableBlock,
1543+
ThinVec::new())
1544+
};
15381545

15391546
// Ok(val) => val
15401547
let ok_arm = {
@@ -1546,32 +1553,35 @@ impl<'a> LoweringContext<'a> {
15461553
self.arm(hir_vec![ok_pat], val_expr)
15471554
};
15481555

1549-
// Err(err) => return Err(From::from(err))
1556+
// Err(err) => { return Carrier::from_error(From::from(err)); }
15501557
let err_arm = {
15511558
let err_ident = self.str_to_ident("err");
15521559
let err_local = self.pat_ident(e.span, err_ident);
15531560
let from_expr = {
1554-
let path = self.std_path(&["convert", "From", "from"]);
1555-
let path = self.path_global(e.span, path);
1561+
let path = self.std_path(e.span, &["convert", "From", "from"]);
15561562
let from = self.expr_path(path, ThinVec::new());
15571563
let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
15581564

15591565
self.expr_call(e.span, from, hir_vec![err_expr])
15601566
};
1561-
let err_expr = {
1562-
let path = self.std_path(&["result", "Result", "Err"]);
1563-
let path = self.path_global(e.span, path);
1564-
let err_ctor = self.expr_path(path, ThinVec::new());
1565-
self.expr_call(e.span, err_ctor, hir_vec![from_expr])
1567+
let from_err_expr = {
1568+
let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
1569+
let from_err = self.expr_path(path, ThinVec::new());
1570+
self.expr_call(e.span, from_err, hir_vec![from_expr])
15661571
};
1567-
let err_pat = self.pat_err(e.span, err_local);
1572+
15681573
let ret_expr = self.expr(e.span,
1569-
hir::Expr_::ExprRet(Some(err_expr)),
1570-
ThinVec::new());
1571-
self.arm(hir_vec![err_pat], ret_expr)
1574+
hir::Expr_::ExprRet(Some(from_err_expr)),
1575+
ThinVec::new());
1576+
let ret_stmt = self.stmt_expr(ret_expr);
1577+
let block = self.signal_block_stmt(ret_stmt, e.span,
1578+
hir::PushUnstableBlock, ThinVec::new());
1579+
1580+
let err_pat = self.pat_err(e.span, err_local);
1581+
self.arm(hir_vec![err_pat], block)
15721582
};
15731583

1574-
return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
1584+
return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
15751585
hir::MatchSource::TryDesugar);
15761586
}
15771587

@@ -1785,6 +1795,15 @@ impl<'a> LoweringContext<'a> {
17851795
(respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
17861796
}
17871797

1798+
// Turns `<expr>` into `<expr>;`, note that this produces a StmtSemi, not a
1799+
// StmtExpr.
1800+
fn stmt_expr(&self, expr: P<hir::Expr>) -> hir::Stmt {
1801+
hir::Stmt {
1802+
span: expr.span,
1803+
node: hir::StmtSemi(expr, self.next_id()),
1804+
}
1805+
}
1806+
17881807
fn block_expr(&mut self, expr: P<hir::Expr>) -> P<hir::Block> {
17891808
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
17901809
}
@@ -1801,26 +1820,22 @@ impl<'a> LoweringContext<'a> {
18011820
}
18021821

18031822
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1804-
let ok = self.std_path(&["result", "Result", "Ok"]);
1805-
let path = self.path_global(span, ok);
1823+
let path = self.std_path(span, &["result", "Result", "Ok"]);
18061824
self.pat_enum(span, path, hir_vec![pat])
18071825
}
18081826

18091827
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1810-
let err = self.std_path(&["result", "Result", "Err"]);
1811-
let path = self.path_global(span, err);
1828+
let path = self.std_path(span, &["result", "Result", "Err"]);
18121829
self.pat_enum(span, path, hir_vec![pat])
18131830
}
18141831

18151832
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1816-
let some = self.std_path(&["option", "Option", "Some"]);
1817-
let path = self.path_global(span, some);
1833+
let path = self.std_path(span, &["option", "Option", "Some"]);
18181834
self.pat_enum(span, path, hir_vec![pat])
18191835
}
18201836

18211837
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
1822-
let none = self.std_path(&["option", "Option", "None"]);
1823-
let path = self.path_global(span, none);
1838+
let path = self.std_path(span, &["option", "Option", "None"]);
18241839
self.pat_enum(span, path, hir_vec![])
18251840
}
18261841

@@ -1918,7 +1933,7 @@ impl<'a> LoweringContext<'a> {
19181933
}
19191934
}
19201935

1921-
fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
1936+
fn std_path_components(&mut self, components: &[&str]) -> Vec<Name> {
19221937
let mut v = Vec::new();
19231938
if let Some(s) = self.crate_root {
19241939
v.push(token::intern(s));
@@ -1929,8 +1944,8 @@ impl<'a> LoweringContext<'a> {
19291944

19301945
// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
19311946
// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
1932-
fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1933-
let idents = self.std_path(components);
1947+
fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1948+
let idents = self.std_path_components(components);
19341949
self.path_global(span, idents)
19351950
}
19361951

@@ -1951,4 +1966,21 @@ impl<'a> LoweringContext<'a> {
19511966
});
19521967
self.expr_block(block, attrs)
19531968
}
1969+
1970+
fn signal_block_stmt(&mut self,
1971+
stmt: hir::Stmt,
1972+
span: Span,
1973+
rule: hir::BlockCheckMode,
1974+
attrs: ThinVec<Attribute>)
1975+
-> P<hir::Expr> {
1976+
let id = self.next_id();
1977+
let block = P(hir::Block {
1978+
rules: rule,
1979+
span: span,
1980+
id: id,
1981+
stmts: hir_vec![stmt],
1982+
expr: None,
1983+
});
1984+
self.expr_block(block, attrs)
1985+
}
19541986
}

0 commit comments

Comments
 (0)