Skip to content

Commit 683bcc0

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

File tree

4 files changed

+296
-49
lines changed

4 files changed

+296
-49
lines changed

src/libcore/ops.rs

+125
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
use cmp::PartialOrd;
7676
use fmt;
7777
use marker::{Sized, Unsize};
78+
use result::Result::{self, Ok, Err};
79+
use option::Option::{self, Some, None};
7880

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

src/librustc/hir/lowering.rs

+81-49
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ impl<'a> LoweringContext<'a> {
966966
let inplace_finalize = ["ops", "InPlace", "finalize"];
967967

968968
let make_call = |this: &mut LoweringContext, p, args| {
969-
let path = this.core_path(e.span, p);
969+
let path = this.std_path(e.span, p);
970970
let path = this.expr_path(path, ThinVec::new());
971971
this.expr_call(e.span, path, args)
972972
};
@@ -1159,15 +1159,13 @@ impl<'a> LoweringContext<'a> {
11591159
ast_expr: &Expr,
11601160
path: &[&str],
11611161
fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
1162-
let strs = this.std_path(&iter::once(&"ops")
1163-
.chain(path)
1164-
.map(|s| *s)
1165-
.collect::<Vec<_>>());
1166-
1167-
let structpath = this.path_global(ast_expr.span, strs);
1162+
let struct_path = this.std_path(ast_expr.span,
1163+
&iter::once(&"ops").chain(path)
1164+
.map(|s| *s)
1165+
.collect::<Vec<_>>());
11681166

11691167
let hir_expr = if fields.len() == 0 {
1170-
this.expr_path(structpath, ast_expr.attrs.clone())
1168+
this.expr_path(struct_path, ast_expr.attrs.clone())
11711169
} else {
11721170
let fields = fields.into_iter().map(|&(s, e)| {
11731171
let expr = this.lower_expr(&e);
@@ -1180,7 +1178,7 @@ impl<'a> LoweringContext<'a> {
11801178
}).collect();
11811179
let attrs = ast_expr.attrs.clone();
11821180

1183-
this.expr_struct(ast_expr.span, structpath, fields, None, attrs)
1181+
this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
11841182
};
11851183

11861184
this.signal_block_expr(hir_vec![],
@@ -1463,11 +1461,7 @@ impl<'a> LoweringContext<'a> {
14631461

14641462
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
14651463
let match_expr = {
1466-
let next_path = {
1467-
let strs = self.std_path(&["iter", "Iterator", "next"]);
1468-
1469-
self.path_global(e.span, strs)
1470-
};
1464+
let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
14711465
let iter = self.expr_ident(e.span, iter, iter_pat.id);
14721466
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
14731467
let next_path = self.expr_path(next_path, ThinVec::new());
@@ -1494,11 +1488,8 @@ impl<'a> LoweringContext<'a> {
14941488

14951489
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14961490
let into_iter_expr = {
1497-
let into_iter_path = {
1498-
let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]);
1499-
1500-
self.path_global(e.span, strs)
1501-
};
1491+
let into_iter_path = self.std_path(e.span,
1492+
&["iter", "IntoIterator", "into_iter"]);
15021493

15031494
let into_iter = self.expr_path(into_iter_path, ThinVec::new());
15041495
self.expr_call(e.span, into_iter, hir_vec![head])
@@ -1527,16 +1518,32 @@ impl<'a> LoweringContext<'a> {
15271518
// to:
15281519
//
15291520
// {
1530-
// match <expr> {
1521+
// match { Carrier::translate( { <expr> } ) } {
15311522
// Ok(val) => val,
1532-
// Err(err) => {
1533-
// return Err(From::from(err))
1534-
// }
1523+
// Err(err) => { return Carrier::from_error(From::from(err)); }
15351524
// }
15361525
// }
15371526

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

15411548
// Ok(val) => val
15421549
let ok_arm = {
@@ -1548,32 +1555,35 @@ impl<'a> LoweringContext<'a> {
15481555
self.arm(hir_vec![ok_pat], val_expr)
15491556
};
15501557

1551-
// Err(err) => return Err(From::from(err))
1558+
// Err(err) => { return Carrier::from_error(From::from(err)); }
15521559
let err_arm = {
15531560
let err_ident = self.str_to_ident("err");
15541561
let err_local = self.pat_ident(e.span, err_ident);
15551562
let from_expr = {
1556-
let path = self.std_path(&["convert", "From", "from"]);
1557-
let path = self.path_global(e.span, path);
1563+
let path = self.std_path(e.span, &["convert", "From", "from"]);
15581564
let from = self.expr_path(path, ThinVec::new());
15591565
let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
15601566

15611567
self.expr_call(e.span, from, hir_vec![err_expr])
15621568
};
1563-
let err_expr = {
1564-
let path = self.std_path(&["result", "Result", "Err"]);
1565-
let path = self.path_global(e.span, path);
1566-
let err_ctor = self.expr_path(path, ThinVec::new());
1567-
self.expr_call(e.span, err_ctor, hir_vec![from_expr])
1569+
let from_err_expr = {
1570+
let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
1571+
let from_err = self.expr_path(path, ThinVec::new());
1572+
self.expr_call(e.span, from_err, hir_vec![from_expr])
15681573
};
1569-
let err_pat = self.pat_err(e.span, err_local);
1574+
15701575
let ret_expr = self.expr(e.span,
1571-
hir::Expr_::ExprRet(Some(err_expr)),
1572-
ThinVec::new());
1573-
self.arm(hir_vec![err_pat], ret_expr)
1576+
hir::Expr_::ExprRet(Some(from_err_expr)),
1577+
ThinVec::new());
1578+
let ret_stmt = self.stmt_expr(ret_expr);
1579+
let block = self.signal_block_stmt(ret_stmt, e.span,
1580+
hir::PushUnstableBlock, ThinVec::new());
1581+
1582+
let err_pat = self.pat_err(e.span, err_local);
1583+
self.arm(hir_vec![err_pat], block)
15741584
};
15751585

1576-
return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
1586+
return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
15771587
hir::MatchSource::TryDesugar);
15781588
}
15791589

@@ -1787,6 +1797,15 @@ impl<'a> LoweringContext<'a> {
17871797
(respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
17881798
}
17891799

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

18051824
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1806-
let ok = self.std_path(&["result", "Result", "Ok"]);
1807-
let path = self.path_global(span, ok);
1825+
let path = self.std_path(span, &["result", "Result", "Ok"]);
18081826
self.pat_enum(span, path, hir_vec![pat])
18091827
}
18101828

18111829
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1812-
let err = self.std_path(&["result", "Result", "Err"]);
1813-
let path = self.path_global(span, err);
1830+
let path = self.std_path(span, &["result", "Result", "Err"]);
18141831
self.pat_enum(span, path, hir_vec![pat])
18151832
}
18161833

18171834
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1818-
let some = self.std_path(&["option", "Option", "Some"]);
1819-
let path = self.path_global(span, some);
1835+
let path = self.std_path(span, &["option", "Option", "Some"]);
18201836
self.pat_enum(span, path, hir_vec![pat])
18211837
}
18221838

18231839
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
1824-
let none = self.std_path(&["option", "Option", "None"]);
1825-
let path = self.path_global(span, none);
1840+
let path = self.std_path(span, &["option", "Option", "None"]);
18261841
self.pat_enum(span, path, hir_vec![])
18271842
}
18281843

@@ -1920,7 +1935,7 @@ impl<'a> LoweringContext<'a> {
19201935
}
19211936
}
19221937

1923-
fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
1938+
fn std_path_components(&mut self, components: &[&str]) -> Vec<Name> {
19241939
let mut v = Vec::new();
19251940
if let Some(s) = self.crate_root {
19261941
v.push(token::intern(s));
@@ -1931,8 +1946,8 @@ impl<'a> LoweringContext<'a> {
19311946

19321947
// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
19331948
// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
1934-
fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1935-
let idents = self.std_path(components);
1949+
fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1950+
let idents = self.std_path_components(components);
19361951
self.path_global(span, idents)
19371952
}
19381953

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

0 commit comments

Comments
 (0)