From 12e8a476cc72a79d0dc98b75ccc5eee0d2ed1579 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 1 Feb 2015 09:59:46 +0200 Subject: [PATCH] Implement type ascription. --- src/librustc/middle/cfg/construct.rs | 1 + src/librustc/middle/check_const.rs | 1 + src/librustc/middle/const_eval.rs | 3 +- src/librustc/middle/expr_use_visitor.rs | 3 +- src/librustc/middle/liveness.rs | 5 ++- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/ty.rs | 3 +- src/librustc_back/svh.rs | 2 + src/librustc_lint/builtin.rs | 1 + src/librustc_trans/trans/consts.rs | 3 +- src/librustc_trans/trans/debuginfo.rs | 3 +- src/librustc_trans/trans/expr.rs | 9 +++-- src/librustc_typeck/check/mod.rs | 5 +++ src/libsyntax/ast.rs | 1 + src/libsyntax/ext/asm.rs | 28 ++++++++++--- src/libsyntax/fold.rs | 3 ++ src/libsyntax/parse/parser.rs | 30 ++++++++------ src/libsyntax/print/pprust.rs | 8 +++- src/libsyntax/visit.rs | 4 ++ src/test/parse-fail/struct-literal-in-for.rs | 2 +- src/test/parse-fail/struct-literal-in-if.rs | 2 +- .../parse-fail/struct-literal-in-while.rs | 2 +- .../coerce-expect-unsized-ascribed.rs | 40 +++++++++++++++++++ 23 files changed, 129 insertions(+), 32 deletions(-) create mode 100644 src/test/run-pass/coerce-expect-unsized-ascribed.rs diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 24c54b53590c0..e1d85fca69f4e 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -372,6 +372,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | + ast::ExprType(ref e, _) | ast::ExprUnary(_, ref e) | ast::ExprParen(ref e) | ast::ExprField(ref e, _) | diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 497022ac6ac49..d244146819f61 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -579,6 +579,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, ast::ExprTupField(..) | ast::ExprVec(_) | ast::ExprParen(..) | + ast::ExprType(..) | ast::ExprTup(..) => {} // Conditional control flow (possible to implement). diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index f9598237ff460..b4b6e4228f23b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -547,7 +547,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, ast::ExprLit(ref lit) => { lit_to_const(&**lit, ety) } - ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)), + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => try!(eval_const_expr_partial(tcx, &**e, ety)), ast::ExprBlock(ref block) => { match block.expr { Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)), diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 97314b57ef656..be18355c6e9bb 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -418,7 +418,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.walk_adjustment(expr); match expr.node { - ast::ExprParen(ref subexpr) => { + ast::ExprParen(ref subexpr) | + ast::ExprType(ref subexpr, _) => { self.walk_expr(&**subexpr) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 705f20559afde..872d054c2b15c 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -507,7 +507,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ast::ExprBlock(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprMac(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprInlineAsm(..) | ast::ExprBox(..) | - ast::ExprRange(..) => { + ast::ExprRange(..) | ast::ExprType(..) => { visit::walk_expr(ir, expr); } } @@ -1190,6 +1190,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | + ast::ExprType(ref e, _) | ast::ExprUnary(_, ref e) | ast::ExprParen(ref e) => { self.propagate_through_expr(&**e, succ) @@ -1470,7 +1471,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) | - ast::ExprRange(..) => { + ast::ExprRange(..) | ast::ExprType(..) => { visit::walk_expr(this, expr); } ast::ExprIfLet(..) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bdcfc67f92b99..1c6a773814251 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -535,7 +535,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { self.cat_def(expr.id, expr.span, expr_ty, def) } - ast::ExprParen(ref e) => { + ast::ExprParen(ref e) | ast::ExprType(ref e, _) => { self.cat_expr(&**e) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 92b444e85d8c3..5400624d09cff 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4859,7 +4859,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { } } - ast::ExprParen(ref e) => expr_kind(tcx, &**e), + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => expr_kind(tcx, &**e), ast::ExprMac(..) => { tcx.sess.span_bug( diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 5aae0e9dbdcf0..e5d9b4ce5f163 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -234,6 +234,7 @@ mod svh_visitor { SawExprUnary(ast::UnOp), SawExprLit(ast::Lit_), SawExprCast, + SawExprType, SawExprIf, SawExprWhile, SawExprMatch, @@ -263,6 +264,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(content)), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8b57a48f3ce72..40b1bc458e877 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1105,6 +1105,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_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 4b1a03e47e7ae..acd0cab33dda1 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -726,7 +726,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, _ => cx.sess().span_bug(e.span, "expected a struct or variant def") } } - ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs).0, + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => const_expr(cx, &**e, param_substs).0, ast::ExprBlock(ref block) => { match block.expr { Some(ref expr) => const_expr(cx, &**expr, param_substs).0, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index b9c59a0bc78d6..68b3272184ca2 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3529,7 +3529,8 @@ fn create_scope_map(cx: &CrateContext, ast::ExprAddrOf(_, ref sub_exp) | ast::ExprField(ref sub_exp, _) | ast::ExprTupField(ref sub_exp, _) | - ast::ExprParen(ref sub_exp) => + ast::ExprParen(ref sub_exp) | + ast::ExprType(ref sub_exp, _) => walk_expr(cx, &**sub_exp, scope_stack, scope_map), ast::ExprBox(ref place, ref sub_expr) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index ba8de6da42f72..0e19843ee2f5f 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -671,7 +671,8 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_datum_unadjusted"); match expr.node { - ast::ExprParen(ref e) => { + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => { trans(bcx, &**e) } ast::ExprPath(..) => { @@ -972,7 +973,8 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); match expr.node { - ast::ExprParen(ref e) => { + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => { trans_into(bcx, &**e, Ignore) } ast::ExprBreak(label_opt) => { @@ -1072,7 +1074,8 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); match expr.node { - ast::ExprParen(ref e) => { + ast::ExprParen(ref e) | + ast::ExprType(ref e, _) => { trans_into(bcx, &**e, dest) } ast::ExprPath(..) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e38a7d2d9f94..8661353f56721 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3864,6 +3864,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }); } } + ast::ExprType(ref e, ref t) => { + let typ = fcx.to_ty(&**t); + check_expr_coercable_to_type(fcx, &**e, typ); + fcx.write_ty(id, typ); + } ast::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 fec67c7aef48f..18c7e7c33f724 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -814,6 +814,7 @@ pub enum Expr_ { ExprLit(P), /// A cast (`foo as f64`) ExprCast(P, P), + ExprType(P, P), /// An `if` block, with an optional else block /// /// `if expr { block } else { expr }` diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index d256698b88598..f14b289ac39cd 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -19,8 +19,7 @@ use codemap::Span; use ext::base; use ext::base::*; use feature_gate; -use parse::token::InternedString; -use parse::token; +use parse::{self, token}; use ptr::P; enum State { @@ -55,8 +54,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::TtToken(_, token::Colon) | + ast::TtToken(_, 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(); @@ -76,12 +84,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, 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, 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 = 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/libsyntax/fold.rs b/src/libsyntax/fold.rs index 105a61d085725..4c737d4ef085e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1192,6 +1192,9 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> 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 220ea30256e03..adf82d537929a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -26,7 +26,7 @@ use ast::{ExprBreak, ExprCall, ExprCast}; 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, ForeignMod, FunctionRetTy}; use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic}; @@ -2661,23 +2661,29 @@ impl<'a> Parser<'a> { let rhs_span = rhs.span; let binary = self.mk_binary(codemap::respan(cur_op_span, cur_op), lhs, rhs); let bin = self.mk_expr(lhs_span.lo, rhs_span.hi, binary); - self.parse_more_binops(bin, min_prec) - } else { - lhs + return self.parse_more_binops(bin, min_prec); } } None => { - if AS_PREC >= min_prec && self.eat_keyword_noexpect(keywords::As) { - let rhs = self.parse_ty(); - let _as = self.mk_expr(lhs.span.lo, - rhs.span.hi, - ExprCast(lhs, rhs)); - self.parse_more_binops(_as, min_prec) - } else { - lhs + if AS_PREC >= min_prec { + if self.eat_keyword_noexpect(keywords::As) { + let rhs = self.parse_ty(); + let _as = self.mk_expr(lhs.span.lo, + rhs.span.hi, + ExprCast(lhs, rhs)); + return self.parse_more_binops(_as, min_prec); + } else if self.token == token::Colon { + self.bump(); + let rhs = self.parse_ty(); + let ex = self.mk_expr(lhs.span.lo, + rhs.span.hi, + ExprType(lhs, rhs)); + return self.parse_more_binops(ex, min_prec); + } } } } + lhs } /// Produce an error if comparison operators are chained (RFC #558). diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2bc3fc1017ae6..cff74d11072ab 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -468,7 +468,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { match expr.node { ast::ExprAssign(..) | ast::ExprBinary(..) | ast::ExprClosure(..) | - ast::ExprAssignOp(..) | ast::ExprCast(..) => true, + ast::ExprAssignOp(..) | ast::ExprCast(..) | + ast::ExprType(..) => true, _ => false, } } @@ -1721,6 +1722,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/visit.rs b/src/libsyntax/visit.rs index 638ddd3ea2e5b..3f93af36e1128 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -765,6 +765,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(&**subexpression); visitor.visit_ty(&**typ) } + ExprType(ref subexpression, ref typ) => { + visitor.visit_expr(&**subexpression); + visitor.visit_ty(&**typ) + } ExprIf(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(&**head_expression); visitor.visit_block(&**if_block); diff --git a/src/test/parse-fail/struct-literal-in-for.rs b/src/test/parse-fail/struct-literal-in-for.rs index a6d4da526fb0e..6a00d4a3ca074 100644 --- a/src/test/parse-fail/struct-literal-in-for.rs +++ b/src/test/parse-fail/struct-literal-in-for.rs @@ -20,7 +20,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 00ece3fcca341..d01a643cd5d71 100644 --- a/src/test/parse-fail/struct-literal-in-if.rs +++ b/src/test/parse-fail/struct-literal-in-if.rs @@ -20,7 +20,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 c23b5dbb9cc86..6ad4d7e651332 100644 --- a/src/test/parse-fail/struct-literal-in-while.rs +++ b/src/test/parse-fail/struct-literal-in-while.rs @@ -20,7 +20,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/coerce-expect-unsized-ascribed.rs b/src/test/run-pass/coerce-expect-unsized-ascribed.rs new file mode 100644 index 0000000000000..2b1204483ba07 --- /dev/null +++ b/src/test/run-pass/coerce-expect-unsized-ascribed.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unknown_features)] +#![feature(box_syntax)] + +use std::fmt::Debug; + +// A version of coerce-expect-unsized that uses type ascription. + +pub fn main() { + let _ = box { [1, 2, 3] }: Box<[int]>; + let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[int]>; + let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[int]>; + let _ = box { |x| (x as u8) }: Box _>; + let _ = box if true { false } else { true }: Box; + let _ = box match true { true => 'a', false => 'b' }: Box; + + let _ = &{ [1, 2, 3] }: &[int]; + let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[int]; + let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[int]; + let _ = &{ |x| (x as u8) }: &Fn(int) -> _; + let _ = &if true { false } else { true }: &Debug; + let _ = &match true { true => 'a', false => 'b' }: &Debug; + + let _ = Box::new([1, 2, 3]): Box<[int]>; + let _ = Box::new(|x| (x as u8)): Box _>; + + let _ = vec![ + Box::new(|x| (x as u8)), + box |x| (x as i16 as u8), + ]: Vec _>>; +}