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
This commit is contained in:
commit
440ef8b154
@ -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
|
||||
|
@ -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, _) => {
|
||||
|
@ -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).
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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(..) |
|
||||
|
@ -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(..) |
|
||||
|
@ -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())),
|
||||
|
@ -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),
|
||||
|
@ -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 }`
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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, _) => {
|
||||
|
@ -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) =>
|
||||
|
@ -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(
|
||||
|
@ -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, _) =>
|
||||
|
@ -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(..) |
|
||||
|
@ -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 {
|
||||
|
@ -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 }`
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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 }
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
42
src/test/compile-fail/coerce-expect-unsized-ascribed.rs
Normal file
42
src/test/compile-fail/coerce-expect-unsized-ascribed.rs
Normal file
@ -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) -> _>>;
|
||||
}
|
15
src/test/compile-fail/type-ascription-feature-gate.rs
Normal file
15
src/test/compile-fail/type-ascription-feature-gate.rs
Normal file
@ -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
|
||||
}
|
64
src/test/compile-fail/type-ascription-precedence.rs
Normal file
64
src/test/compile-fail/type-ascription-precedence.rs
Normal file
@ -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
|
||||
}
|
23
src/test/compile-fail/type-ascription-soundness.rs
Normal file
23
src/test/compile-fail/type-ascription-soundness.rs
Normal file
@ -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
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
45
src/test/run-pass/type-ascription.rs
Normal file
45
src/test/run-pass/type-ascription.rs
Normal file
@ -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]);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user