about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-19 02:45:15 +0000
committerbors <bors@rust-lang.org>2015-12-19 02:45:15 +0000
commit440ef8b1548edf9d03a5b880d77a8b476cfb7fa2 (patch)
tree035b909d2c9572fe5d3e491a57e8b36b7649e914 /src
parent8ad12c3e251df6b8ed42b4d32709f4f55470a0be (diff)
parent95fdaf237575e44ecf16f9fb13ab60058909f281 (diff)
downloadrust-440ef8b1548edf9d03a5b880d77a8b476cfb7fa2.tar.gz
rust-440ef8b1548edf9d03a5b880d77a8b476cfb7fa2.zip
Auto merge of #30184 - petrochenkov:ascr, r=nikomatsakis
This PR is a rebase of the original PR by @eddyb https://github.com/rust-lang/rust/pull/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 https://github.com/rust-lang/rust/issues/23416
Diffstat (limited to 'src')
-rw-r--r--src/doc/reference.md2
-rw-r--r--src/librustc/middle/cfg/construct.rs1
-rw-r--r--src/librustc/middle/check_const.rs1
-rw-r--r--src/librustc/middle/const_eval.rs1
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/liveness.rs5
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/middle/ty/mod.rs4
-rw-r--r--src/librustc_back/svh.rs2
-rw-r--r--src/librustc_front/fold.rs3
-rw-r--r--src/librustc_front/hir.rs1
-rw-r--r--src/librustc_front/intravisit.rs2
-rw-r--r--src/librustc_front/lowering.rs4
-rw-r--r--src/librustc_front/print/pprust.rs8
-rw-r--r--src/librustc_lint/unused.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs2
-rw-r--r--src/librustc_trans/trans/consts.rs1
-rw-r--r--src/librustc_trans/trans/debuginfo/create_scope_map.rs1
-rw-r--r--src/librustc_trans/trans/expr.rs13
-rw-r--r--src/librustc_typeck/check/mod.rs13
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/parser.rs12
-rw-r--r--src/libsyntax/print/pprust.rs7
-rw-r--r--src/libsyntax/util/parser.rs16
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/libsyntax_ext/asm.rs29
-rw-r--r--src/test/compile-fail/coerce-expect-unsized-ascribed.rs42
-rw-r--r--src/test/compile-fail/type-ascription-feature-gate.rs15
-rw-r--r--src/test/compile-fail/type-ascription-precedence.rs64
-rw-r--r--src/test/compile-fail/type-ascription-soundness.rs23
-rw-r--r--src/test/parse-fail/struct-literal-in-for.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-if.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-while.rs2
-rw-r--r--src/test/run-pass/type-ascription.rs45
36 files changed, 321 insertions, 24 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md
index a722c0e38f4..e7cc1436824 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2388,6 +2388,8 @@ The currently implemented features of the reference compiler are:
 
 * - `deprecated` - Allows using the `#[deprecated]` attribute.
 
+* - `type_ascription` - Allows type ascription expressions `expr: Type`.
+
 If a feature is promoted to a language feature, then all existing programs will
 start to receive compilation warnings about `#![feature]` directives which enabled
 the new feature (because the directive is no longer necessary). However, if a
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 8baae99c2f2..abe85125215 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -352,6 +352,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ExprBox(ref e) |
             hir::ExprAddrOf(_, ref e) |
             hir::ExprCast(ref e, _) |
+            hir::ExprType(ref e, _) |
             hir::ExprUnary(_, ref e) |
             hir::ExprField(ref e, _) |
             hir::ExprTupField(ref e, _) => {
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 69d8dfc3613..d6f05ffd8a5 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -784,6 +784,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
         hir::ExprField(..) |
         hir::ExprTupField(..) |
         hir::ExprVec(_) |
+        hir::ExprType(..) |
         hir::ExprTup(..) => {}
 
         // Conditional control flow (possible to implement).
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 54061a14d14..d5cfff4aff8 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -1126,6 +1126,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
             None => unreachable!(),
         }
       }
+      hir::ExprType(ref e, _) => try!(eval_const_expr_partial(tcx, &**e, ty_hint, fn_args)),
       hir::ExprTup(_) => Tuple(e.id),
       hir::ExprStruct(..) => Struct(e.id),
       hir::ExprIndex(ref arr, ref idx) => {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 73776304bc8..ff3e99d487c 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -373,6 +373,10 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         match expr.node {
             hir::ExprPath(..) => { }
 
+            hir::ExprType(ref subexpr, _) => {
+                self.walk_expr(&**subexpr)
+            }
+
             hir::ExprUnary(hir::UnDeref, ref base) => {      // *base
                 if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
                     self.select_from_expr(&**base);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 4a75309f1a6..540af4ae001 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -496,7 +496,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprInlineAsm(..) | hir::ExprBox(..) |
-      hir::ExprRange(..) => {
+      hir::ExprRange(..) | hir::ExprType(..) => {
           intravisit::walk_expr(ir, expr);
       }
     }
@@ -1160,6 +1160,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprBox(ref e) |
           hir::ExprAddrOf(_, ref e) |
           hir::ExprCast(ref e, _) |
+          hir::ExprType(ref e, _) |
           hir::ExprUnary(_, ref e) => {
             self.propagate_through_expr(&**e, succ)
           }
@@ -1443,7 +1444,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprBlock(..) | hir::ExprAddrOf(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
-      hir::ExprRange(..) => {
+      hir::ExprRange(..) | hir::ExprType(..) => {
         intravisit::walk_expr(this, expr);
       }
     }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 560d7eeed9e..1eb5efa0bda 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -518,6 +518,10 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
             self.cat_def(expr.id, expr.span, expr_ty, def)
           }
 
+          hir::ExprType(ref e, _) => {
+            self.cat_expr(&**e)
+          }
+
           hir::ExprAddrOf(..) | hir::ExprCall(..) |
           hir::ExprAssign(..) | hir::ExprAssignOp(..) |
           hir::ExprClosure(..) | hir::ExprRet(..) |
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 20e98821ca3..308883cf063 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -2114,6 +2114,10 @@ impl<'tcx> ctxt<'tcx> {
                 }
             }
 
+            hir::ExprType(ref e, _) => {
+                self.expr_is_lval(e)
+            }
+
             hir::ExprUnary(hir::UnDeref, _) |
             hir::ExprField(..) |
             hir::ExprTupField(..) |
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index a5df0b94b33..2532882d012 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -234,6 +234,7 @@ mod svh_visitor {
         SawExprUnary(hir::UnOp),
         SawExprLit(ast::Lit_),
         SawExprCast,
+        SawExprType,
         SawExprIf,
         SawExprWhile,
         SawExprMatch,
@@ -262,6 +263,7 @@ mod svh_visitor {
             ExprUnary(op, _)         => SawExprUnary(op),
             ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
             ExprCast(..)             => SawExprCast,
+            ExprType(..)             => SawExprType,
             ExprIf(..)               => SawExprIf,
             ExprWhile(..)            => SawExprWhile,
             ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.name.as_str())),
diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs
index 784428cc114..5da679c3495 100644
--- a/src/librustc_front/fold.rs
+++ b/src/librustc_front/fold.rs
@@ -1043,6 +1043,9 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
             ExprCast(expr, ty) => {
                 ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
             }
+            ExprType(expr, ty) => {
+                ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
+            }
             ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
             ExprIf(cond, tr, fl) => {
                 ExprIf(folder.fold_expr(cond),
diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs
index 6b2664af60b..d079024bc96 100644
--- a/src/librustc_front/hir.rs
+++ b/src/librustc_front/hir.rs
@@ -737,6 +737,7 @@ pub enum Expr_ {
     ExprLit(P<Lit>),
     /// A cast (`foo as f64`)
     ExprCast(P<Expr>, P<Ty>),
+    ExprType(P<Expr>, P<Ty>),
     /// An `if` block, with an optional else block
     ///
     /// `if expr { block } else { expr }`
diff --git a/src/librustc_front/intravisit.rs b/src/librustc_front/intravisit.rs
index 13d7e81cc6e..03b021cfa63 100644
--- a/src/librustc_front/intravisit.rs
+++ b/src/librustc_front/intravisit.rs
@@ -732,7 +732,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(subexpression)
         }
         ExprLit(_) => {}
-        ExprCast(ref subexpression, ref typ) => {
+        ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => {
             visitor.visit_expr(subexpression);
             visitor.visit_ty(typ)
         }
diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index 136c25f425e..52e771bd5c3 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -1128,6 +1128,10 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 let expr = lower_expr(lctx, expr);
                 hir::ExprCast(expr, lower_ty(lctx, ty))
             }
+            ExprType(ref expr, ref ty) => {
+                let expr = lower_expr(lctx, expr);
+                hir::ExprType(expr, lower_ty(lctx, ty))
+            }
             ExprAddrOf(m, ref ohs) => {
                 let m = lower_mutability(lctx, m);
                 let ohs = lower_expr(lctx, ohs);
diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs
index 9ac0e65cba3..f1b963bf11d 100644
--- a/src/librustc_front/print/pprust.rs
+++ b/src/librustc_front/print/pprust.rs
@@ -335,7 +335,8 @@ fn needs_parentheses(expr: &hir::Expr) -> bool {
         hir::ExprBinary(..) |
         hir::ExprClosure(..) |
         hir::ExprAssignOp(..) |
-        hir::ExprCast(..) => true,
+        hir::ExprCast(..) |
+        hir::ExprType(..) => true,
         _ => false,
     }
 }
@@ -1353,6 +1354,11 @@ impl<'a> State<'a> {
                 try!(self.word_space("as"));
                 try!(self.print_type(&**ty));
             }
+            hir::ExprType(ref expr, ref ty) => {
+                try!(self.print_expr(&**expr));
+                try!(self.word_space(":"));
+                try!(self.print_type(&**ty));
+            }
             hir::ExprIf(ref test, ref blk, ref elseopt) => {
                 try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
             }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index b8750cccb4b..18a3a96069e 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -319,6 +319,7 @@ impl UnusedParens {
                 }
                 ast::ExprUnary(_, ref x) |
                 ast::ExprCast(ref x, _) |
+                ast::ExprType(ref x, _) |
                 ast::ExprField(ref x, _) |
                 ast::ExprTupField(ref x, _) |
                 ast::ExprIndex(ref x, _) => {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index d1455e70165..5cb12627d6b 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -320,6 +320,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                                   name: Field::new(index.node as usize) },
             hir::ExprCast(ref source, _) =>
                 ExprKind::Cast { source: source.to_ref() },
+            hir::ExprType(ref source, _) =>
+                return source.make_mirror(cx),
             hir::ExprBox(ref value) =>
                 ExprKind::Box { value: value.to_ref() },
             hir::ExprVec(ref fields) =>
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 038e699a043..0fafe08178a 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -1003,6 +1003,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             try!(const_fn_call(cx, MethodCallKey(method_call),
                                method_did, &arg_vals, param_substs, trueconst))
         },
+        hir::ExprType(ref e, _) => try!(const_expr(cx, &**e, param_substs, fn_args, trueconst)).0,
         hir::ExprBlock(ref block) => {
             match block.expr {
                 Some(ref expr) => try!(const_expr(
diff --git a/src/librustc_trans/trans/debuginfo/create_scope_map.rs b/src/librustc_trans/trans/debuginfo/create_scope_map.rs
index 231dec276d9..237d31c4778 100644
--- a/src/librustc_trans/trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/trans/debuginfo/create_scope_map.rs
@@ -320,6 +320,7 @@ fn walk_expr(cx: &CrateContext,
         hir::ExprPath(..) => {}
 
         hir::ExprCast(ref sub_exp, _)     |
+        hir::ExprType(ref sub_exp, _) |
         hir::ExprAddrOf(_, ref sub_exp)  |
         hir::ExprField(ref sub_exp, _) |
         hir::ExprTupField(ref sub_exp, _) =>
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index d2cbb9892f6..ecf54cde9f6 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -656,6 +656,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("trans_datum_unadjusted");
 
     match expr.node {
+        hir::ExprType(ref e, _) => {
+            trans(bcx, &**e)
+        }
         hir::ExprPath(..) => {
             trans_def(bcx, expr, bcx.def(expr.id))
         }
@@ -941,6 +944,9 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         hir::ExprBreak(label_opt) => {
             controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name))
         }
+        hir::ExprType(ref e, _) => {
+            trans_into(bcx, &**e, Ignore)
+        }
         hir::ExprAgain(label_opt) => {
             controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name))
         }
@@ -1064,6 +1070,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
 
     match expr.node {
+        hir::ExprType(ref e, _) => {
+            trans_into(bcx, &**e, dest)
+        }
         hir::ExprPath(..) => {
             trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
         }
@@ -2601,6 +2610,10 @@ fn expr_kind(tcx: &ty::ctxt, expr: &hir::Expr) -> ExprKind {
             }
         }
 
+        hir::ExprType(ref expr, _) => {
+            expr_kind(tcx, expr)
+        }
+
         hir::ExprUnary(hir::UnDeref, _) |
         hir::ExprField(..) |
         hir::ExprTupField(..) |
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f61d0992d1f..c91f6581418 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2648,6 +2648,14 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 }
 
+fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                expr: &'tcx hir::Expr,
+                                expected: Ty<'tcx>) {
+    check_expr_with_unifier(
+        fcx, expr, ExpectHasType(expected), NoPreference,
+        || demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)));
+}
+
 pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                      expr: &'tcx hir::Expr,
                                      expected: Ty<'tcx>) {
@@ -3510,6 +3518,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
             deferred_cast_checks.push(cast_check);
         }
       }
+      hir::ExprType(ref e, ref t) => {
+        let typ = fcx.to_ty(&**t);
+        check_expr_eq_type(fcx, &**e, typ);
+        fcx.write_ty(id, typ);
+      }
       hir::ExprVec(ref args) => {
         let uty = expected.to_option(fcx).and_then(|uty| {
             match uty.sty {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4b0ec8578c1..abc44407eff 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -942,6 +942,7 @@ pub enum Expr_ {
     ExprLit(P<Lit>),
     /// A cast (`foo as f64`)
     ExprCast(P<Expr>, P<Ty>),
+    ExprType(P<Expr>, P<Ty>),
     /// An `if` block, with an optional else block
     ///
     /// `if expr { block } else { expr }`
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 0d38411ac93..b2989c42a9e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -233,6 +233,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
 
     // Allows `#[deprecated]` attribute
     ("deprecated", "1.6.0", Some(29935), Active),
+
+    // allow using type ascription in expressions
+    ("type_ascription", "1.6.0", Some(23416), Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -958,6 +961,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                                   "box expression syntax is experimental; \
                                    you can call `Box::new` instead.");
             }
+            ast::ExprType(..) => {
+                self.gate_feature("type_ascription", e.span,
+                                  "type ascription is experimental");
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index cd2210c71b8..cb467f9016b 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1203,6 +1203,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
             ExprCast(expr, ty) => {
                 ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
             }
+            ExprType(expr, ty) => {
+                ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
+            }
             ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
             ExprIf(cond, tr, fl) => {
                 ExprIf(folder.fold_expr(cond),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ebfcf8c5180..b625277f2a7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -26,7 +26,7 @@ use ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace};
 use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
 use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
 use ast::{ExprMethodCall, ExprParen, ExprPath};
-use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
+use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprType, ExprUnary};
 use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
 use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, FunctionRetTy};
 use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
@@ -2787,6 +2787,11 @@ impl<'a> Parser<'a> {
                 lhs = self.mk_expr(lhs.span.lo, rhs.span.hi,
                                    ExprCast(lhs, rhs), None);
                 continue
+            } else if op == AssocOp::Colon {
+                let rhs = try!(self.parse_ty());
+                lhs = self.mk_expr(lhs.span.lo, rhs.span.hi,
+                                   ExprType(lhs, rhs), None);
+                continue
             } else if op == AssocOp::DotDot {
                     // If we didn’t have to handle `x..`, it would be pretty easy to generalise
                     // it to the Fixity::None code.
@@ -2809,7 +2814,6 @@ impl<'a> Parser<'a> {
                     break
             }
 
-
             let rhs = try!(match op.fixity() {
                 Fixity::Right => self.with_res(restrictions, |this|{
                     this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed)
@@ -2856,7 +2860,9 @@ impl<'a> Parser<'a> {
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
                     self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
                 }
-                AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached")
+                AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
+                    self.bug("As, Colon or DotDot branch reached")
+                }
             };
 
             if op.fixity() == Fixity::None { break }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 1f296dc5d59..ff01f0ac67e 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -444,7 +444,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
         ast::ExprAssign(..) | ast::ExprBinary(..) |
         ast::ExprClosure(..) |
         ast::ExprAssignOp(..) | ast::ExprCast(..) |
-        ast::ExprInPlace(..) => true,
+        ast::ExprInPlace(..) | ast::ExprType(..) => true,
         _ => false,
     }
 }
@@ -2035,6 +2035,11 @@ impl<'a> State<'a> {
                 try!(self.word_space("as"));
                 try!(self.print_type(&**ty));
             }
+            ast::ExprType(ref expr, ref ty) => {
+                try!(self.print_expr(&**expr));
+                try!(self.word_space(":"));
+                try!(self.print_type(&**ty));
+            }
             ast::ExprIf(ref test, ref blk, ref elseopt) => {
                 try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
             }
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index bf3a8def390..87ef96d87ff 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -60,7 +60,9 @@ pub enum AssocOp {
     /// `as`
     As,
     /// `..` range
-    DotDot
+    DotDot,
+    /// `:`
+    Colon,
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -100,6 +102,7 @@ impl AssocOp {
             Token::AndAnd => Some(LAnd),
             Token::OrOr => Some(LOr),
             Token::DotDot => Some(DotDot),
+            Token::Colon => Some(Colon),
             _ if t.is_keyword(keywords::As) => Some(As),
             _ => None
         }
@@ -134,7 +137,7 @@ impl AssocOp {
     pub fn precedence(&self) -> usize {
         use self::AssocOp::*;
         match *self {
-            As => 14,
+            As | Colon => 14,
             Multiply | Divide | Modulus => 13,
             Add | Subtract => 12,
             ShiftLeft | ShiftRight => 11,
@@ -158,7 +161,7 @@ impl AssocOp {
             Inplace | Assign | AssignOp(_) => Fixity::Right,
             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
-            LAnd | LOr => Fixity::Left,
+            LAnd | LOr | Colon => Fixity::Left,
             DotDot => Fixity::None
         }
     }
@@ -168,7 +171,7 @@ impl AssocOp {
         match *self {
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
             Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
-            ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot => false
+            ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | Colon => false
         }
     }
 
@@ -178,7 +181,7 @@ impl AssocOp {
             Assign | AssignOp(_) | Inplace => true,
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
-            LOr | DotDot => false
+            LOr | DotDot | Colon => false
         }
     }
 
@@ -203,8 +206,7 @@ impl AssocOp {
             BitOr => Some(ast::BiBitOr),
             LAnd => Some(ast::BiAnd),
             LOr => Some(ast::BiOr),
-            Inplace | Assign | AssignOp(_) | As | DotDot => None
+            Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None
         }
     }
-
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 22bf135f4f9..b8dd54790ce 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -693,7 +693,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(subexpression)
         }
         ExprLit(_) => {}
-        ExprCast(ref subexpression, ref typ) => {
+        ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => {
             visitor.visit_expr(subexpression);
             visitor.visit_ty(typ)
         }
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 072be571221..e5c6a17c78b 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -19,8 +19,8 @@ use syntax::codemap::Span;
 use syntax::ext::base;
 use syntax::ext::base::*;
 use syntax::feature_gate;
-use syntax::parse::token::{intern, InternedString};
-use syntax::parse::token;
+use syntax::parse::token::intern;
+use syntax::parse::{self, token};
 use syntax::ptr::P;
 use syntax::ast::AsmDialect;
 
@@ -58,8 +58,17 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
         return DummyResult::expr(sp);
     }
 
-    let mut p = cx.new_parser_from_tts(tts);
-    let mut asm = InternedString::new("");
+    // Split the tts before the first colon, to avoid `asm!("x": y)`  being
+    // parsed as `asm!(z)` with `z = "x": y` which is type ascription.
+    let first_colon = tts.iter().position(|tt| {
+        match *tt {
+            ast::TokenTree::Token(_, token::Colon) |
+            ast::TokenTree::Token(_, token::ModSep) => true,
+            _ => false
+        }
+    }).unwrap_or(tts.len());
+    let mut p = cx.new_parser_from_tts(&tts[first_colon..]);
+    let mut asm = token::InternedString::new("");
     let mut asm_str_style = None;
     let mut outputs = Vec::new();
     let mut inputs = Vec::new();
@@ -79,12 +88,22 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                     cx.span_err(sp, "malformed inline assembly");
                     return DummyResult::expr(sp);
                 }
-                let (s, style) = match expr_to_string(cx, panictry!(p.parse_expr()),
+                // Nested parser, stop before the first colon (see above).
+                let mut p2 = cx.new_parser_from_tts(&tts[..first_colon]);
+                let (s, style) = match expr_to_string(cx, panictry!(p2.parse_expr()),
                                                    "inline assembly must be a string literal") {
                     Some((s, st)) => (s, st),
                     // let compilation continue
                     None => return DummyResult::expr(sp),
                 };
+
+                // This is most likely malformed.
+                if p2.token != token::Eof {
+                    let mut extra_tts = panictry!(p2.parse_all_token_trees());
+                    extra_tts.extend(tts[first_colon..].iter().cloned());
+                    p = parse::tts_to_parser(cx.parse_sess, extra_tts, cx.cfg());
+                }
+
                 asm = s;
                 asm_str_style = Some(style);
             }
diff --git a/src/test/compile-fail/coerce-expect-unsized-ascribed.rs b/src/test/compile-fail/coerce-expect-unsized-ascribed.rs
new file mode 100644
index 00000000000..ef65927fc5d
--- /dev/null
+++ b/src/test/compile-fail/coerce-expect-unsized-ascribed.rs
@@ -0,0 +1,42 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A version of coerce-expect-unsized that uses type ascription.
+// Doesn't work so far, but supposed to work eventually
+
+#![feature(box_syntax, type_ascription)]
+
+use std::fmt::Debug;
+
+pub fn main() {
+    let _ = box { [1, 2, 3] }: Box<[i32]>; //~ ERROR mismatched types
+    let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; //~ ERROR mismatched types
+    let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>;
+    //~^ ERROR mismatched types
+    let _ = box { |x| (x as u8) }: Box<Fn(i32) -> _>; //~ ERROR mismatched types
+    let _ = box if true { false } else { true }: Box<Debug>; //~ ERROR mismatched types
+    let _ = box match true { true => 'a', false => 'b' }: Box<Debug>; //~ ERROR mismatched types
+
+    let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types
+    let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; //~ ERROR mismatched types
+    let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32];
+    //~^ ERROR mismatched types
+    let _ = &{ |x| (x as u8) }: &Fn(i32) -> _; //~ ERROR mismatched types
+    let _ = &if true { false } else { true }: &Debug; //~ ERROR mismatched types
+    let _ = &match true { true => 'a', false => 'b' }: &Debug; //~ ERROR mismatched types
+
+    let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types
+    let _ = Box::new(|x| (x as u8)): Box<Fn(i32) -> _>; //~ ERROR mismatched types
+
+    let _ = vec![
+        Box::new(|x| (x as u8)),
+        box |x| (x as i16 as u8),
+    ]: Vec<Box<Fn(i32) -> _>>;
+}
diff --git a/src/test/compile-fail/type-ascription-feature-gate.rs b/src/test/compile-fail/type-ascription-feature-gate.rs
new file mode 100644
index 00000000000..d3c07d653f4
--- /dev/null
+++ b/src/test/compile-fail/type-ascription-feature-gate.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Type ascription is feature gated
+
+fn main() {
+    let a = 10: u8; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/compile-fail/type-ascription-precedence.rs b/src/test/compile-fail/type-ascription-precedence.rs
new file mode 100644
index 00000000000..bb7a8bc3ddf
--- /dev/null
+++ b/src/test/compile-fail/type-ascription-precedence.rs
@@ -0,0 +1,64 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Operator precedence of type ascription
+// Type ascription has very high precedence, the same as operator `as`
+
+#![feature(type_ascription)]
+
+use std::ops::*;
+
+struct S;
+struct Z;
+
+impl Add<Z> for S {
+    type Output = S;
+    fn add(self, _rhs: Z) -> S { panic!() }
+}
+impl Mul<Z> for S {
+    type Output = S;
+    fn mul(self, _rhs: Z) -> S { panic!() }
+}
+impl Neg for S {
+    type Output = Z;
+    fn neg(self) -> Z { panic!() }
+}
+impl Deref for S {
+    type Target = Z;
+    fn deref(&self) -> &Z { panic!() }
+}
+
+fn main() {
+    &S: &S; // OK
+    (&S): &S; // OK
+    &(S: &S); //~ ERROR mismatched types
+
+    *S: Z; // OK
+    (*S): Z; // OK
+    *(S: Z); //~ ERROR mismatched types
+    //~^ ERROR type `Z` cannot be dereferenced
+
+    -S: Z; // OK
+    (-S): Z; // OK
+    -(S: Z); //~ ERROR mismatched types
+    //~^ ERROR cannot apply unary operator `-` to type `Z`
+
+    S + Z: Z; // OK
+    S + (Z: Z); // OK
+    (S + Z): Z; //~ ERROR mismatched types
+
+    S * Z: Z; // OK
+    S * (Z: Z); // OK
+    (S * Z): Z; //~ ERROR mismatched types
+
+    S .. S: S; // OK
+    S .. (S: S); // OK
+    (S .. S): S; //~ ERROR mismatched types
+}
diff --git a/src/test/compile-fail/type-ascription-soundness.rs b/src/test/compile-fail/type-ascription-soundness.rs
new file mode 100644
index 00000000000..2d882e87ab8
--- /dev/null
+++ b/src/test/compile-fail/type-ascription-soundness.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Type ascription doesn't lead to unsoundness
+
+#![feature(type_ascription)]
+
+fn main() {
+    let arr = &[1u8, 2, 3];
+    let ref x = arr: &[u8]; //~ ERROR mismatched types
+    let ref mut x = arr: &[u8]; //~ ERROR mismatched types
+    match arr: &[u8] { //~ ERROR mismatched types
+        ref x => {}
+    }
+    let _len = (arr: &[u8]).len(); //~ ERROR mismatched types
+}
diff --git a/src/test/parse-fail/struct-literal-in-for.rs b/src/test/parse-fail/struct-literal-in-for.rs
index 8fb71e13f16..107b836d160 100644
--- a/src/test/parse-fail/struct-literal-in-for.rs
+++ b/src/test/parse-fail/struct-literal-in-for.rs
@@ -22,7 +22,7 @@ impl Foo {
 
 fn main() {
     for x in Foo {
-        x: 3    //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
+        x: 3    //~ ERROR expected type, found `3`
     }.hi() {
         println!("yo");
     }
diff --git a/src/test/parse-fail/struct-literal-in-if.rs b/src/test/parse-fail/struct-literal-in-if.rs
index 1560c83bc70..b1cccc51d7b 100644
--- a/src/test/parse-fail/struct-literal-in-if.rs
+++ b/src/test/parse-fail/struct-literal-in-if.rs
@@ -22,7 +22,7 @@ impl Foo {
 
 fn main() {
     if Foo {
-        x: 3    //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
+        x: 3    //~ ERROR expected type, found `3`
     }.hi() {
         println!("yo");
     }
diff --git a/src/test/parse-fail/struct-literal-in-while.rs b/src/test/parse-fail/struct-literal-in-while.rs
index 2052193df91..1c52dc48ccd 100644
--- a/src/test/parse-fail/struct-literal-in-while.rs
+++ b/src/test/parse-fail/struct-literal-in-while.rs
@@ -22,7 +22,7 @@ impl Foo {
 
 fn main() {
     while Foo {
-        x: 3    //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
+        x: 3    //~ ERROR expected type, found `3`
     }.hi() {
         println!("yo");
     }
diff --git a/src/test/run-pass/type-ascription.rs b/src/test/run-pass/type-ascription.rs
new file mode 100644
index 00000000000..bca384c6471
--- /dev/null
+++ b/src/test/run-pass/type-ascription.rs
@@ -0,0 +1,45 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Type ascription doesn't lead to unsoundness
+
+#![feature(type_ascription)]
+
+use std::mem;
+
+const C1: u8 = 10: u8;
+const C2: [u8; 1: usize] = [1];
+
+struct S {
+    a: u8
+}
+
+fn main() {
+    assert_eq!(C1.into(): i32, 10);
+    assert_eq!(C2[0], 1);
+
+    let s = S { a: 10: u8 };
+    let arr = &[1u8, 2, 3];
+
+    let mut v = arr.iter().cloned().collect(): Vec<_>;
+    v.push(4);
+    assert_eq!(v, [1, 2, 3, 4]);
+
+    let a = 1: u8;
+    let b = a.into(): u16;
+    assert_eq!(v[a.into(): usize], 2);
+    assert_eq!(mem::size_of_val(&a), 1);
+    assert_eq!(mem::size_of_val(&b), 2);
+    assert_eq!(b, 1: u16);
+
+    let mut v = Vec::new();
+    v: Vec<u8> = vec![1, 2, 3]; // Lvalue type ascription
+    assert_eq!(v, [1u8, 2, 3]);
+}