Skip to content

Commit 440ef8b

Browse files
committed
Auto merge of #30184 - petrochenkov:ascr, r=nikomatsakis
This PR is a rebase of the original PR by @eddyb #21836 with some unrebasable parts manually reapplied, feature gate added + type equality restriction added as described below. This implementation is partial because the type equality restriction is applied to all type ascription expressions and not only those in lvalue contexts. Thus, all difficulties with detection of these contexts and translation of coercions having effect in runtime are avoided. So, you can't write things with coercions like `let slice = &[1, 2, 3]: &[u8];`. It obviously makes type ascription less useful than it should be, but it's still much more useful than not having type ascription at all. In particular, things like `let v = something.iter().collect(): Vec<_>;` and `let u = t.into(): U;` work as expected and I'm pretty happy with these improvements alone. Part of #23416
2 parents 8ad12c3 + 95fdaf2 commit 440ef8b

36 files changed

+321
-24
lines changed

src/doc/reference.md

+2
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,8 @@ The currently implemented features of the reference compiler are:
23882388

23892389
* - `deprecated` - Allows using the `#[deprecated]` attribute.
23902390

2391+
* - `type_ascription` - Allows type ascription expressions `expr: Type`.
2392+
23912393
If a feature is promoted to a language feature, then all existing programs will
23922394
start to receive compilation warnings about `#![feature]` directives which enabled
23932395
the new feature (because the directive is no longer necessary). However, if a

src/librustc/middle/cfg/construct.rs

+1
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
352352
hir::ExprBox(ref e) |
353353
hir::ExprAddrOf(_, ref e) |
354354
hir::ExprCast(ref e, _) |
355+
hir::ExprType(ref e, _) |
355356
hir::ExprUnary(_, ref e) |
356357
hir::ExprField(ref e, _) |
357358
hir::ExprTupField(ref e, _) => {

src/librustc/middle/check_const.rs

+1
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
784784
hir::ExprField(..) |
785785
hir::ExprTupField(..) |
786786
hir::ExprVec(_) |
787+
hir::ExprType(..) |
787788
hir::ExprTup(..) => {}
788789

789790
// Conditional control flow (possible to implement).

src/librustc/middle/const_eval.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
11261126
None => unreachable!(),
11271127
}
11281128
}
1129+
hir::ExprType(ref e, _) => try!(eval_const_expr_partial(tcx, &**e, ty_hint, fn_args)),
11291130
hir::ExprTup(_) => Tuple(e.id),
11301131
hir::ExprStruct(..) => Struct(e.id),
11311132
hir::ExprIndex(ref arr, ref idx) => {

src/librustc/middle/expr_use_visitor.rs

+4
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
373373
match expr.node {
374374
hir::ExprPath(..) => { }
375375

376+
hir::ExprType(ref subexpr, _) => {
377+
self.walk_expr(&**subexpr)
378+
}
379+
376380
hir::ExprUnary(hir::UnDeref, ref base) => { // *base
377381
if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
378382
self.select_from_expr(&**base);

src/librustc/middle/liveness.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
496496
hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
497497
hir::ExprStruct(..) | hir::ExprRepeat(..) |
498498
hir::ExprInlineAsm(..) | hir::ExprBox(..) |
499-
hir::ExprRange(..) => {
499+
hir::ExprRange(..) | hir::ExprType(..) => {
500500
intravisit::walk_expr(ir, expr);
501501
}
502502
}
@@ -1160,6 +1160,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11601160
hir::ExprBox(ref e) |
11611161
hir::ExprAddrOf(_, ref e) |
11621162
hir::ExprCast(ref e, _) |
1163+
hir::ExprType(ref e, _) |
11631164
hir::ExprUnary(_, ref e) => {
11641165
self.propagate_through_expr(&**e, succ)
11651166
}
@@ -1443,7 +1444,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
14431444
hir::ExprBlock(..) | hir::ExprAddrOf(..) |
14441445
hir::ExprStruct(..) | hir::ExprRepeat(..) |
14451446
hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
1446-
hir::ExprRange(..) => {
1447+
hir::ExprRange(..) | hir::ExprType(..) => {
14471448
intravisit::walk_expr(this, expr);
14481449
}
14491450
}

src/librustc/middle/mem_categorization.rs

+4
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,10 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
518518
self.cat_def(expr.id, expr.span, expr_ty, def)
519519
}
520520

521+
hir::ExprType(ref e, _) => {
522+
self.cat_expr(&**e)
523+
}
524+
521525
hir::ExprAddrOf(..) | hir::ExprCall(..) |
522526
hir::ExprAssign(..) | hir::ExprAssignOp(..) |
523527
hir::ExprClosure(..) | hir::ExprRet(..) |

src/librustc/middle/ty/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2114,6 +2114,10 @@ impl<'tcx> ctxt<'tcx> {
21142114
}
21152115
}
21162116

2117+
hir::ExprType(ref e, _) => {
2118+
self.expr_is_lval(e)
2119+
}
2120+
21172121
hir::ExprUnary(hir::UnDeref, _) |
21182122
hir::ExprField(..) |
21192123
hir::ExprTupField(..) |

src/librustc_back/svh.rs

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ mod svh_visitor {
234234
SawExprUnary(hir::UnOp),
235235
SawExprLit(ast::Lit_),
236236
SawExprCast,
237+
SawExprType,
237238
SawExprIf,
238239
SawExprWhile,
239240
SawExprMatch,
@@ -262,6 +263,7 @@ mod svh_visitor {
262263
ExprUnary(op, _) => SawExprUnary(op),
263264
ExprLit(ref lit) => SawExprLit(lit.node.clone()),
264265
ExprCast(..) => SawExprCast,
266+
ExprType(..) => SawExprType,
265267
ExprIf(..) => SawExprIf,
266268
ExprWhile(..) => SawExprWhile,
267269
ExprLoop(_, id) => SawExprLoop(id.map(|id| id.name.as_str())),

src/librustc_front/fold.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,9 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
10431043
ExprCast(expr, ty) => {
10441044
ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
10451045
}
1046+
ExprType(expr, ty) => {
1047+
ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
1048+
}
10461049
ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
10471050
ExprIf(cond, tr, fl) => {
10481051
ExprIf(folder.fold_expr(cond),

src/librustc_front/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ pub enum Expr_ {
737737
ExprLit(P<Lit>),
738738
/// A cast (`foo as f64`)
739739
ExprCast(P<Expr>, P<Ty>),
740+
ExprType(P<Expr>, P<Ty>),
740741
/// An `if` block, with an optional else block
741742
///
742743
/// `if expr { block } else { expr }`

src/librustc_front/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
732732
visitor.visit_expr(subexpression)
733733
}
734734
ExprLit(_) => {}
735-
ExprCast(ref subexpression, ref typ) => {
735+
ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => {
736736
visitor.visit_expr(subexpression);
737737
visitor.visit_ty(typ)
738738
}

src/librustc_front/lowering.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,10 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
11281128
let expr = lower_expr(lctx, expr);
11291129
hir::ExprCast(expr, lower_ty(lctx, ty))
11301130
}
1131+
ExprType(ref expr, ref ty) => {
1132+
let expr = lower_expr(lctx, expr);
1133+
hir::ExprType(expr, lower_ty(lctx, ty))
1134+
}
11311135
ExprAddrOf(m, ref ohs) => {
11321136
let m = lower_mutability(lctx, m);
11331137
let ohs = lower_expr(lctx, ohs);

src/librustc_front/print/pprust.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,8 @@ fn needs_parentheses(expr: &hir::Expr) -> bool {
335335
hir::ExprBinary(..) |
336336
hir::ExprClosure(..) |
337337
hir::ExprAssignOp(..) |
338-
hir::ExprCast(..) => true,
338+
hir::ExprCast(..) |
339+
hir::ExprType(..) => true,
339340
_ => false,
340341
}
341342
}
@@ -1353,6 +1354,11 @@ impl<'a> State<'a> {
13531354
try!(self.word_space("as"));
13541355
try!(self.print_type(&**ty));
13551356
}
1357+
hir::ExprType(ref expr, ref ty) => {
1358+
try!(self.print_expr(&**expr));
1359+
try!(self.word_space(":"));
1360+
try!(self.print_type(&**ty));
1361+
}
13561362
hir::ExprIf(ref test, ref blk, ref elseopt) => {
13571363
try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
13581364
}

src/librustc_lint/unused.rs

+1
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ impl UnusedParens {
319319
}
320320
ast::ExprUnary(_, ref x) |
321321
ast::ExprCast(ref x, _) |
322+
ast::ExprType(ref x, _) |
322323
ast::ExprField(ref x, _) |
323324
ast::ExprTupField(ref x, _) |
324325
ast::ExprIndex(ref x, _) => {

src/librustc_mir/hair/cx/expr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
320320
name: Field::new(index.node as usize) },
321321
hir::ExprCast(ref source, _) =>
322322
ExprKind::Cast { source: source.to_ref() },
323+
hir::ExprType(ref source, _) =>
324+
return source.make_mirror(cx),
323325
hir::ExprBox(ref value) =>
324326
ExprKind::Box { value: value.to_ref() },
325327
hir::ExprVec(ref fields) =>

src/librustc_trans/trans/consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
10031003
try!(const_fn_call(cx, MethodCallKey(method_call),
10041004
method_did, &arg_vals, param_substs, trueconst))
10051005
},
1006+
hir::ExprType(ref e, _) => try!(const_expr(cx, &**e, param_substs, fn_args, trueconst)).0,
10061007
hir::ExprBlock(ref block) => {
10071008
match block.expr {
10081009
Some(ref expr) => try!(const_expr(

src/librustc_trans/trans/debuginfo/create_scope_map.rs

+1
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ fn walk_expr(cx: &CrateContext,
320320
hir::ExprPath(..) => {}
321321

322322
hir::ExprCast(ref sub_exp, _) |
323+
hir::ExprType(ref sub_exp, _) |
323324
hir::ExprAddrOf(_, ref sub_exp) |
324325
hir::ExprField(ref sub_exp, _) |
325326
hir::ExprTupField(ref sub_exp, _) =>

src/librustc_trans/trans/expr.rs

+13
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
656656
let _icx = push_ctxt("trans_datum_unadjusted");
657657

658658
match expr.node {
659+
hir::ExprType(ref e, _) => {
660+
trans(bcx, &**e)
661+
}
659662
hir::ExprPath(..) => {
660663
trans_def(bcx, expr, bcx.def(expr.id))
661664
}
@@ -941,6 +944,9 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
941944
hir::ExprBreak(label_opt) => {
942945
controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name))
943946
}
947+
hir::ExprType(ref e, _) => {
948+
trans_into(bcx, &**e, Ignore)
949+
}
944950
hir::ExprAgain(label_opt) => {
945951
controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name))
946952
}
@@ -1064,6 +1070,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10641070
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
10651071

10661072
match expr.node {
1073+
hir::ExprType(ref e, _) => {
1074+
trans_into(bcx, &**e, dest)
1075+
}
10671076
hir::ExprPath(..) => {
10681077
trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
10691078
}
@@ -2601,6 +2610,10 @@ fn expr_kind(tcx: &ty::ctxt, expr: &hir::Expr) -> ExprKind {
26012610
}
26022611
}
26032612

2613+
hir::ExprType(ref expr, _) => {
2614+
expr_kind(tcx, expr)
2615+
}
2616+
26042617
hir::ExprUnary(hir::UnDeref, _) |
26052618
hir::ExprField(..) |
26062619
hir::ExprTupField(..) |

src/librustc_typeck/check/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,14 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26482648
}
26492649
}
26502650

2651+
fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2652+
expr: &'tcx hir::Expr,
2653+
expected: Ty<'tcx>) {
2654+
check_expr_with_unifier(
2655+
fcx, expr, ExpectHasType(expected), NoPreference,
2656+
|| demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)));
2657+
}
2658+
26512659
pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26522660
expr: &'tcx hir::Expr,
26532661
expected: Ty<'tcx>) {
@@ -3510,6 +3518,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
35103518
deferred_cast_checks.push(cast_check);
35113519
}
35123520
}
3521+
hir::ExprType(ref e, ref t) => {
3522+
let typ = fcx.to_ty(&**t);
3523+
check_expr_eq_type(fcx, &**e, typ);
3524+
fcx.write_ty(id, typ);
3525+
}
35133526
hir::ExprVec(ref args) => {
35143527
let uty = expected.to_option(fcx).and_then(|uty| {
35153528
match uty.sty {

src/libsyntax/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ pub enum Expr_ {
942942
ExprLit(P<Lit>),
943943
/// A cast (`foo as f64`)
944944
ExprCast(P<Expr>, P<Ty>),
945+
ExprType(P<Expr>, P<Ty>),
945946
/// An `if` block, with an optional else block
946947
///
947948
/// `if expr { block } else { expr }`

src/libsyntax/feature_gate.rs

+7
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
233233

234234
// Allows `#[deprecated]` attribute
235235
("deprecated", "1.6.0", Some(29935), Active),
236+
237+
// allow using type ascription in expressions
238+
("type_ascription", "1.6.0", Some(23416), Active),
236239
];
237240
// (changing above list without updating src/doc/reference.md makes @cmr sad)
238241

@@ -958,6 +961,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
958961
"box expression syntax is experimental; \
959962
you can call `Box::new` instead.");
960963
}
964+
ast::ExprType(..) => {
965+
self.gate_feature("type_ascription", e.span,
966+
"type ascription is experimental");
967+
}
961968
_ => {}
962969
}
963970
visit::walk_expr(self, e);

src/libsyntax/fold.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
12031203
ExprCast(expr, ty) => {
12041204
ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
12051205
}
1206+
ExprType(expr, ty) => {
1207+
ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
1208+
}
12061209
ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
12071210
ExprIf(cond, tr, fl) => {
12081211
ExprIf(folder.fold_expr(cond),

src/libsyntax/parse/parser.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace};
2626
use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
2727
use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
2828
use ast::{ExprMethodCall, ExprParen, ExprPath};
29-
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
29+
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprType, ExprUnary};
3030
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
3131
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, FunctionRetTy};
3232
use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
@@ -2787,6 +2787,11 @@ impl<'a> Parser<'a> {
27872787
lhs = self.mk_expr(lhs.span.lo, rhs.span.hi,
27882788
ExprCast(lhs, rhs), None);
27892789
continue
2790+
} else if op == AssocOp::Colon {
2791+
let rhs = try!(self.parse_ty());
2792+
lhs = self.mk_expr(lhs.span.lo, rhs.span.hi,
2793+
ExprType(lhs, rhs), None);
2794+
continue
27902795
} else if op == AssocOp::DotDot {
27912796
// If we didn’t have to handle `x..`, it would be pretty easy to generalise
27922797
// it to the Fixity::None code.
@@ -2809,7 +2814,6 @@ impl<'a> Parser<'a> {
28092814
break
28102815
}
28112816

2812-
28132817
let rhs = try!(match op.fixity() {
28142818
Fixity::Right => self.with_res(restrictions, |this|{
28152819
this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed)
@@ -2856,7 +2860,9 @@ impl<'a> Parser<'a> {
28562860
let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
28572861
self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
28582862
}
2859-
AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached")
2863+
AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
2864+
self.bug("As, Colon or DotDot branch reached")
2865+
}
28602866
};
28612867

28622868
if op.fixity() == Fixity::None { break }

src/libsyntax/print/pprust.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
444444
ast::ExprAssign(..) | ast::ExprBinary(..) |
445445
ast::ExprClosure(..) |
446446
ast::ExprAssignOp(..) | ast::ExprCast(..) |
447-
ast::ExprInPlace(..) => true,
447+
ast::ExprInPlace(..) | ast::ExprType(..) => true,
448448
_ => false,
449449
}
450450
}
@@ -2035,6 +2035,11 @@ impl<'a> State<'a> {
20352035
try!(self.word_space("as"));
20362036
try!(self.print_type(&**ty));
20372037
}
2038+
ast::ExprType(ref expr, ref ty) => {
2039+
try!(self.print_expr(&**expr));
2040+
try!(self.word_space(":"));
2041+
try!(self.print_type(&**ty));
2042+
}
20382043
ast::ExprIf(ref test, ref blk, ref elseopt) => {
20392044
try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
20402045
}

0 commit comments

Comments
 (0)