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:
bors 2015-12-19 02:45:15 +00:00
commit 440ef8b154
36 changed files with 321 additions and 24 deletions

View File

@ -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

View File

@ -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, _) => {

View File

@ -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).

View File

@ -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) => {

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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(..) |

View File

@ -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(..) |

View File

@ -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())),

View File

@ -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),

View File

@ -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 }`

View File

@ -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)
}

View File

@ -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);

View File

@ -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)));
}

View File

@ -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, _) => {

View File

@ -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) =>

View File

@ -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(

View File

@ -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, _) =>

View File

@ -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(..) |

View File

@ -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 {

View File

@ -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 }`

View File

@ -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);

View File

@ -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),

View File

@ -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 didnt 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 }

View File

@ -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)));
}

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -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);
}

View 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) -> _>>;
}

View 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
}

View 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
}

View 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
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View 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]);
}