Skip to content

Commit f9ff8d3

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

File tree

5 files changed

+252
-47
lines changed

5 files changed

+252
-47
lines changed

src/libcore/ops.rs

+125
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ use fmt;
7272
use convert::From;
7373
use marker::{Sized, Unsize};
7474
use num::One;
75+
use result::Result::{self, Ok, Err};
76+
use option::Option::{self, Some, None};
7577

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

src/librustc/hir/lowering.rs

+43-46
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ impl<'a> LoweringContext<'a> {
955955
let inplace_finalize = ["ops", "InPlace", "finalize"];
956956

957957
let make_call = |this: &mut LoweringContext, p, args| {
958-
let path = this.core_path(e.span, p);
958+
let path = this.std_path(e.span, p);
959959
let path = this.expr_path(path, None);
960960
this.expr_call(e.span, path, args, None)
961961
};
@@ -1147,15 +1147,13 @@ impl<'a> LoweringContext<'a> {
11471147
ast_expr: &Expr,
11481148
path: &[&str],
11491149
fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
1150-
let strs = this.std_path(&iter::once(&"ops")
1151-
.chain(path)
1152-
.map(|s| *s)
1153-
.collect::<Vec<_>>());
1154-
1155-
let structpath = this.path_global(ast_expr.span, strs);
1150+
let struct_path = this.std_path(ast_expr.span,
1151+
&iter::once(&"ops").chain(path)
1152+
.map(|s| *s)
1153+
.collect::<Vec<_>>());
11561154

11571155
let hir_expr = if fields.len() == 0 {
1158-
this.expr_path(structpath, ast_expr.attrs.clone())
1156+
this.expr_path(struct_path, ast_expr.attrs.clone())
11591157
} else {
11601158
let fields = fields.into_iter().map(|&(s, e)| {
11611159
let expr = this.lower_expr(&e);
@@ -1168,7 +1166,7 @@ impl<'a> LoweringContext<'a> {
11681166
}).collect();
11691167
let attrs = ast_expr.attrs.clone();
11701168

1171-
this.expr_struct(ast_expr.span, structpath, fields, None, attrs)
1169+
this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
11721170
};
11731171

11741172
this.signal_block_expr(hir_vec![],
@@ -1452,11 +1450,7 @@ impl<'a> LoweringContext<'a> {
14521450

14531451
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
14541452
let match_expr = {
1455-
let next_path = {
1456-
let strs = self.std_path(&["iter", "Iterator", "next"]);
1457-
1458-
self.path_global(e.span, strs)
1459-
};
1453+
let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
14601454
let iter = self.expr_ident(e.span, iter, None, iter_pat.id);
14611455
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter, None);
14621456
let next_path = self.expr_path(next_path, None);
@@ -1483,11 +1477,8 @@ impl<'a> LoweringContext<'a> {
14831477

14841478
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14851479
let into_iter_expr = {
1486-
let into_iter_path = {
1487-
let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]);
1488-
1489-
self.path_global(e.span, strs)
1490-
};
1480+
let into_iter_path = self.std_path(e.span,
1481+
&["iter", "IntoIterator", "into_iter"]);
14911482

14921483
let into_iter = self.expr_path(into_iter_path, None);
14931484
self.expr_call(e.span, into_iter, hir_vec![head], None)
@@ -1517,16 +1508,25 @@ impl<'a> LoweringContext<'a> {
15171508
// to:
15181509
//
15191510
// {
1520-
// match <expr> {
1511+
// match { Carrier::translate( { <expr> } ) } {
15211512
// Ok(val) => val,
1522-
// Err(err) => {
1523-
// return Err(From::from(err))
1524-
// }
1513+
// Err(err) => return { Carrier::from_error(From::from(err)) },
15251514
// }
15261515
// }
15271516

1528-
// expand <expr>
1529-
let sub_expr = self.lower_expr(sub_expr);
1517+
// { Carrier::translate( { <expr> } ) }
1518+
let discr = {
1519+
// expand <expr>
1520+
let sub_expr = self.lower_expr(sub_expr);
1521+
let sub_expr = self.signal_block_expr(hir_vec![], sub_expr, e.span,
1522+
hir::PopUnstableBlock, None);
1523+
1524+
let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
1525+
let path = self.expr_path(path, None);
1526+
let call = self.expr_call(e.span, path, hir_vec![sub_expr], None);
1527+
1528+
self.signal_block_expr(hir_vec![], call, e.span, hir::PushUnstableBlock, None)
1529+
};
15301530

15311531
// Ok(val) => val
15321532
let ok_arm = {
@@ -1538,32 +1538,33 @@ impl<'a> LoweringContext<'a> {
15381538
self.arm(hir_vec![ok_pat], val_expr)
15391539
};
15401540

1541-
// Err(err) => return Err(From::from(err))
1541+
// Err(err) => return { Carrier::from_error(From::from(err)) },
15421542
let err_arm = {
15431543
let err_ident = self.str_to_ident("err");
15441544
let err_local = self.pat_ident(e.span, err_ident);
15451545
let from_expr = {
1546-
let path = self.std_path(&["convert", "From", "from"]);
1547-
let path = self.path_global(e.span, path);
1546+
let path = self.std_path(e.span, &["convert", "From", "from"]);
15481547
let from = self.expr_path(path, None);
15491548
let err_expr = self.expr_ident(e.span, err_ident, None, err_local.id);
15501549

15511550
self.expr_call(e.span, from, hir_vec![err_expr], None)
15521551
};
1553-
let err_expr = {
1554-
let path = self.std_path(&["result", "Result", "Err"]);
1555-
let path = self.path_global(e.span, path);
1556-
let err_ctor = self.expr_path(path, None);
1557-
self.expr_call(e.span, err_ctor, hir_vec![from_expr], None)
1552+
let from_err_expr = {
1553+
let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
1554+
let from_err = self.expr_path(path, None);
1555+
let call = self.expr_call(e.span, from_err, hir_vec![from_expr], None);
1556+
1557+
self.signal_block_expr(hir_vec![], call, e.span,
1558+
hir::PushUnstableBlock, None)
15581559
};
15591560
let err_pat = self.pat_err(e.span, err_local);
15601561
let ret_expr = self.expr(e.span,
1561-
hir::Expr_::ExprRet(Some(err_expr)), None);
1562+
hir::Expr_::ExprRet(Some(from_err_expr)), None);
15621563

15631564
self.arm(hir_vec![err_pat], ret_expr)
15641565
};
15651566

1566-
return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
1567+
return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
15671568
hir::MatchSource::TryDesugar, None);
15681569
}
15691570

@@ -1798,26 +1799,22 @@ impl<'a> LoweringContext<'a> {
17981799
}
17991800

18001801
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1801-
let ok = self.std_path(&["result", "Result", "Ok"]);
1802-
let path = self.path_global(span, ok);
1802+
let path = self.std_path(span, &["result", "Result", "Ok"]);
18031803
self.pat_enum(span, path, hir_vec![pat])
18041804
}
18051805

18061806
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1807-
let err = self.std_path(&["result", "Result", "Err"]);
1808-
let path = self.path_global(span, err);
1807+
let path = self.std_path(span, &["result", "Result", "Err"]);
18091808
self.pat_enum(span, path, hir_vec![pat])
18101809
}
18111810

18121811
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1813-
let some = self.std_path(&["option", "Option", "Some"]);
1814-
let path = self.path_global(span, some);
1812+
let path = self.std_path(span, &["option", "Option", "Some"]);
18151813
self.pat_enum(span, path, hir_vec![pat])
18161814
}
18171815

18181816
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
1819-
let none = self.std_path(&["option", "Option", "None"]);
1820-
let path = self.path_global(span, none);
1817+
let path = self.std_path(span, &["option", "Option", "None"]);
18211818
self.pat_enum(span, path, hir_vec![])
18221819
}
18231820

@@ -1915,7 +1912,7 @@ impl<'a> LoweringContext<'a> {
19151912
}
19161913
}
19171914

1918-
fn std_path(&mut self, components: &[&str]) -> Vec<hir::Ident> {
1915+
fn std_path_components(&mut self, components: &[&str]) -> Vec<hir::Ident> {
19191916
let mut v = Vec::new();
19201917
if let Some(s) = self.crate_root {
19211918
v.push(hir::Ident::from_name(token::intern(s)));
@@ -1926,8 +1923,8 @@ impl<'a> LoweringContext<'a> {
19261923

19271924
// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
19281925
// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
1929-
fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1930-
let idents = self.std_path(components);
1926+
fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
1927+
let idents = self.std_path_components(components);
19311928
self.path_global(span, idents)
19321929
}
19331930

src/libstd/net/addr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>>
453453
a.set_port(p);
454454
a
455455
})
456-
}).collect()?;
456+
}).collect::<Result<_, _>>()?;
457457
Ok(v.into_iter())
458458
}
459459

0 commit comments

Comments
 (0)