Skip to content

Commit 42584d3

Browse files
authored
Auto merge of #35777 - nrc:carrier3, r=@nikomatsakis
Carrier trait (third attempt) This adds a `Carrier` trait to operate with `?`. The only public implementation is for `Result`, so effectively the trait does not exist, however, it ensures future compatibility for the `?` operator. This is not intended to be used, nor is it intended to be a long-term solution. Although this exact PR has not been through Crater, I do not expect it to be a breaking change based on putting numerous similar PRs though Crater in the past. cc: * [? tracking issue](#31436) * [previous PR](#35056) * [RFC issue](rust-lang/rfcs#1718) for discussion of long-term Carrier trait solutions. r? @nikomatsakis
2 parents 1576de0 + c32456d commit 42584d3

File tree

5 files changed

+255
-51
lines changed

5 files changed

+255
-51
lines changed

src/libcore/ops.rs

+72
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
use cmp::PartialOrd;
7575
use fmt;
7676
use marker::{Sized, Unsize};
77+
use result::Result::{self, Ok, Err};
7778

7879
/// The `Drop` trait is used to run some code when a value goes out of scope.
7980
/// This is sometimes called a 'destructor'.
@@ -2271,3 +2272,74 @@ pub trait BoxPlace<Data: ?Sized> : Place<Data> {
22712272
/// Creates a globally fresh place.
22722273
fn make_place() -> Self;
22732274
}
2275+
2276+
/// A trait for types which have success and error states and are meant to work
2277+
/// with the question mark operator.
2278+
/// When the `?` operator is used with a value, whether the value is in the
2279+
/// success or error state is determined by calling `translate`.
2280+
///
2281+
/// This trait is **very** experimental, it will probably be iterated on heavily
2282+
/// before it is stabilised. Implementors should expect change. Users of `?`
2283+
/// should not rely on any implementations of `Carrier` other than `Result`,
2284+
/// i.e., you should not expect `?` to continue to work with `Option`, etc.
2285+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2286+
pub trait Carrier {
2287+
/// The type of the value when computation succeeds.
2288+
type Success;
2289+
/// The type of the value when computation errors out.
2290+
type Error;
2291+
2292+
/// Create a `Carrier` from a success value.
2293+
fn from_success(Self::Success) -> Self;
2294+
2295+
/// Create a `Carrier` from an error value.
2296+
fn from_error(Self::Error) -> Self;
2297+
2298+
/// Translate this `Carrier` to another implementation of `Carrier` with the
2299+
/// same associated types.
2300+
fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
2301+
}
2302+
2303+
#[unstable(feature = "question_mark_carrier", issue = "31436")]
2304+
impl<U, V> Carrier for Result<U, V> {
2305+
type Success = U;
2306+
type Error = V;
2307+
2308+
fn from_success(u: U) -> Result<U, V> {
2309+
Ok(u)
2310+
}
2311+
2312+
fn from_error(e: V) -> Result<U, V> {
2313+
Err(e)
2314+
}
2315+
2316+
fn translate<T>(self) -> T
2317+
where T: Carrier<Success=U, Error=V>
2318+
{
2319+
match self {
2320+
Ok(u) => T::from_success(u),
2321+
Err(e) => T::from_error(e),
2322+
}
2323+
}
2324+
}
2325+
2326+
struct _DummyErrorType;
2327+
2328+
impl Carrier for _DummyErrorType {
2329+
type Success = ();
2330+
type Error = ();
2331+
2332+
fn from_success(_: ()) -> _DummyErrorType {
2333+
_DummyErrorType
2334+
}
2335+
2336+
fn from_error(_: ()) -> _DummyErrorType {
2337+
_DummyErrorType
2338+
}
2339+
2340+
fn translate<T>(self) -> T
2341+
where T: Carrier<Success=(), Error=()>
2342+
{
2343+
T::from_success(())
2344+
}
2345+
}

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
}

src/librustc/ty/relate.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,13 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
151151
let b_ty = &b_subst.types[i];
152152
let variance = variances.map_or(ty::Invariant, |v| v.types[i]);
153153
relation.relate_with_variance(variance, a_ty, b_ty)
154-
}).collect()?;
154+
}).collect::<Result<_, _>>()?;
155155

156156
let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| {
157157
let b_r = &b_subst.regions[i];
158158
let variance = variances.map_or(ty::Invariant, |v| v.regions[i]);
159159
relation.relate_with_variance(variance, a_r, b_r)
160-
}).collect()?;
160+
}).collect::<Result<_, _>>()?;
161161

162162
Ok(Substs::new(tcx, types, regions))
163163
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(question_mark, question_mark_carrier)]
12+
13+
// Test that type inference fails where there are multiple possible return types
14+
// for the `?` operator.
15+
16+
fn f(x: &i32) -> Result<i32, ()> {
17+
Ok(*x)
18+
}
19+
20+
fn g() -> Result<Vec<i32>, ()> {
21+
let l = [1, 2, 3, 4];
22+
l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve
23+
}
24+
25+
fn main() {
26+
g();
27+
}

0 commit comments

Comments
 (0)