Implement tuple and tuple struct indexing
This allows code to access the fields of tuples and tuple structs: let x = (1i, 2i); assert_eq!(x.1, 2); struct Point(int, int); let origin = Point(0, 0); assert_eq!(origin.0, 0); assert_eq!(origin.1, 0);
This commit is contained in:
parent
651106462c
commit
bf274bc18b
34 changed files with 549 additions and 14 deletions
|
@ -2555,6 +2555,8 @@ The currently implemented features of the reference compiler are:
|
||||||
which is considered wildly unsafe and will be
|
which is considered wildly unsafe and will be
|
||||||
obsoleted by language improvements.
|
obsoleted by language improvements.
|
||||||
|
|
||||||
|
* `tuple_indexing` - Allows use of tuple indexing (expressions like `expr.0`)
|
||||||
|
|
||||||
If a feature is promoted to a language feature, then all existing programs will
|
If a feature is promoted to a language feature, then all existing programs will
|
||||||
start to receive compilation warnings about #[feature] directives which enabled
|
start to receive compilation warnings about #[feature] directives which enabled
|
||||||
the new feature (because the directive is no longer necessary). However, if
|
the new feature (because the directive is no longer necessary). However, if
|
||||||
|
|
|
@ -70,6 +70,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
("unboxed_closures", Active),
|
("unboxed_closures", Active),
|
||||||
("import_shadowing", Active),
|
("import_shadowing", Active),
|
||||||
("advanced_slice_patterns", Active),
|
("advanced_slice_patterns", Active),
|
||||||
|
("tuple_indexing", Active),
|
||||||
|
|
||||||
// if you change this list without updating src/doc/rust.md, cmr will be sad
|
// if you change this list without updating src/doc/rust.md, cmr will be sad
|
||||||
|
|
||||||
|
@ -338,6 +339,11 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||||
"unboxed closures are a work-in-progress \
|
"unboxed closures are a work-in-progress \
|
||||||
feature with known bugs");
|
feature with known bugs");
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(..) => {
|
||||||
|
self.gate_feature("tuple_indexing",
|
||||||
|
e.span,
|
||||||
|
"tuple indexing is experimental");
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_expr(self, e, ());
|
visit::walk_expr(self, e, ());
|
||||||
|
|
|
@ -1056,6 +1056,7 @@ impl UnnecessaryParens {
|
||||||
ast::ExprUnary(_, ref x) |
|
ast::ExprUnary(_, ref x) |
|
||||||
ast::ExprCast(ref x, _) |
|
ast::ExprCast(ref x, _) |
|
||||||
ast::ExprField(ref x, _, _) |
|
ast::ExprField(ref x, _, _) |
|
||||||
|
ast::ExprTupField(ref x, _, _) |
|
||||||
ast::ExprIndex(ref x, _) => {
|
ast::ExprIndex(ref x, _) => {
|
||||||
// &X { y: 1 }, X { y: 1 }.y
|
// &X { y: 1 }, X { y: 1 }.y
|
||||||
contains_exterior_struct_lit(&**x)
|
contains_exterior_struct_lit(&**x)
|
||||||
|
|
|
@ -807,7 +807,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
out.push_str(token::get_name(fname).get());
|
out.push_str(token::get_name(fname).get());
|
||||||
}
|
}
|
||||||
mc::PositionalField(idx) => {
|
mc::PositionalField(idx) => {
|
||||||
out.push_char('#'); // invent a notation here
|
out.push_char('.');
|
||||||
out.push_str(idx.to_string().as_slice());
|
out.push_str(idx.to_string().as_slice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -467,7 +467,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||||
ast::ExprCast(e, _) |
|
ast::ExprCast(e, _) |
|
||||||
ast::ExprUnary(_, e) |
|
ast::ExprUnary(_, e) |
|
||||||
ast::ExprParen(e) |
|
ast::ExprParen(e) |
|
||||||
ast::ExprField(e, _, _) => {
|
ast::ExprField(e, _, _) |
|
||||||
|
ast::ExprTupField(e, _, _) => {
|
||||||
self.straightline(expr, pred, [e])
|
self.straightline(expr, pred, [e])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
|
||||||
ExprAddrOf(MutImmutable, _) |
|
ExprAddrOf(MutImmutable, _) |
|
||||||
ExprParen(..) |
|
ExprParen(..) |
|
||||||
ExprField(..) |
|
ExprField(..) |
|
||||||
|
ExprTupField(..) |
|
||||||
ExprIndex(..) |
|
ExprIndex(..) |
|
||||||
ExprTup(..) |
|
ExprTup(..) |
|
||||||
ExprRepeat(..) |
|
ExprRepeat(..) |
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl<'a, 'tcx> Visitor<bool> for CheckStaticVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprField(..) | ast::ExprVec(..) |
|
ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
|
||||||
ast::ExprBlock(..) | ast::ExprTup(..) => {
|
ast::ExprBlock(..) | ast::ExprTup(..) => {
|
||||||
visit::walk_expr(self, e, is_const);
|
visit::walk_expr(self, e, is_const);
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,8 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
ast::ExprField(ref base, _, _) => self.classify(&**base),
|
ast::ExprField(ref base, _, _) => self.classify(&**base),
|
||||||
|
|
||||||
|
ast::ExprTupField(ref base, _, _) => self.classify(&**base),
|
||||||
|
|
||||||
ast::ExprIndex(ref base, ref idx) =>
|
ast::ExprIndex(ref base, ref idx) =>
|
||||||
join(self.classify(&**base), self.classify(&**idx)),
|
join(self.classify(&**base), self.classify(&**idx)),
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: uint) {
|
||||||
|
match ty::get(ty::expr_ty_adjusted(self.tcx, lhs)).sty {
|
||||||
|
ty::ty_struct(id, _) => {
|
||||||
|
let fields = ty::lookup_struct_fields(self.tcx, id);
|
||||||
|
let field_id = fields[idx].id;
|
||||||
|
self.live_symbols.insert(field_id.node);
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[ast::FieldPat]) {
|
fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[ast::FieldPat]) {
|
||||||
let id = match self.tcx.def_map.borrow().get(&lhs.id) {
|
let id = match self.tcx.def_map.borrow().get(&lhs.id) {
|
||||||
&def::DefVariant(_, id, _) => id,
|
&def::DefVariant(_, id, _) => id,
|
||||||
|
@ -255,6 +266,9 @@ impl<'a, 'tcx> Visitor<MarkSymbolVisitorContext> for MarkSymbolVisitor<'a, 'tcx>
|
||||||
ast::ExprField(ref lhs, ref ident, _) => {
|
ast::ExprField(ref lhs, ref ident, _) => {
|
||||||
self.handle_field_access(&**lhs, &ident.node);
|
self.handle_field_access(&**lhs, &ident.node);
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref lhs, idx, _) => {
|
||||||
|
self.handle_tup_field_access(&**lhs, idx.node);
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -324,6 +324,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
|
||||||
self.select_from_expr(&**base);
|
self.select_from_expr(&**base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::ExprTupField(ref base, _, _) => { // base.<n>
|
||||||
|
self.select_from_expr(&**base);
|
||||||
|
}
|
||||||
|
|
||||||
ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
|
ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
|
||||||
if !self.walk_overloaded_operator(expr, &**lhs, [rhs.clone()]) {
|
if !self.walk_overloaded_operator(expr, &**lhs, [rhs.clone()]) {
|
||||||
self.select_from_expr(&**lhs);
|
self.select_from_expr(&**lhs);
|
||||||
|
|
|
@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, live nodes are not required:
|
// otherwise, live nodes are not required:
|
||||||
ExprIndex(..) | ExprField(..) | ExprVec(..) |
|
ExprIndex(..) | ExprField(..) | ExprTupField(..) | ExprVec(..) |
|
||||||
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
|
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
|
||||||
ExprBinary(..) | ExprAddrOf(..) |
|
ExprBinary(..) | ExprAddrOf(..) |
|
||||||
ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
|
ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
|
||||||
|
@ -965,6 +965,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
self.propagate_through_expr(&**e, succ)
|
self.propagate_through_expr(&**e, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprTupField(ref e, _, _) => {
|
||||||
|
self.propagate_through_expr(&**e, succ)
|
||||||
|
}
|
||||||
|
|
||||||
ExprFnBlock(_, _, ref blk) |
|
ExprFnBlock(_, _, ref blk) |
|
||||||
ExprProc(_, ref blk) |
|
ExprProc(_, ref blk) |
|
||||||
ExprUnboxedFn(_, _, _, ref blk) => {
|
ExprUnboxedFn(_, _, _, ref blk) => {
|
||||||
|
@ -1271,6 +1275,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ExprPath(_) => succ,
|
ExprPath(_) => succ,
|
||||||
ExprField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
|
ExprField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
|
||||||
|
ExprTupField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
|
||||||
_ => self.propagate_through_expr(expr, succ)
|
_ => self.propagate_through_expr(expr, succ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1445,7 +1450,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
|
||||||
// no correctness conditions related to liveness
|
// no correctness conditions related to liveness
|
||||||
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
|
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
|
||||||
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
|
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
|
||||||
ExprVec(..) | ExprTup(..) | ExprBinary(..) |
|
ExprTupField(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) |
|
||||||
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
|
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
|
||||||
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
|
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
|
||||||
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
|
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
|
||||||
|
|
|
@ -465,6 +465,11 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||||
Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
|
Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::ExprTupField(ref base, idx, _) => {
|
||||||
|
let base_cmt = if_ok!(self.cat_expr(&**base));
|
||||||
|
Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
|
||||||
|
}
|
||||||
|
|
||||||
ast::ExprIndex(ref base, _) => {
|
ast::ExprIndex(ref base, _) => {
|
||||||
let method_call = typeck::MethodCall::expr(expr.id());
|
let method_call = typeck::MethodCall::expr(expr.id());
|
||||||
match self.typer.node_method_ty(method_call) {
|
match self.typer.node_method_ty(method_call) {
|
||||||
|
@ -737,6 +742,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cat_tup_field<N:ast_node>(&self,
|
||||||
|
node: &N,
|
||||||
|
base_cmt: cmt,
|
||||||
|
f_idx: uint,
|
||||||
|
f_ty: ty::t)
|
||||||
|
-> cmt {
|
||||||
|
Rc::new(cmt_ {
|
||||||
|
id: node.id(),
|
||||||
|
span: node.span(),
|
||||||
|
mutbl: base_cmt.mutbl.inherit(),
|
||||||
|
cat: cat_interior(base_cmt, InteriorField(PositionalField(f_idx))),
|
||||||
|
ty: f_ty
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
|
pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
|
||||||
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
|
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -819,6 +819,14 @@ impl<'a, 'tcx> Visitor<()> for PrivacyVisitor<'a, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref base, idx, _) => {
|
||||||
|
match ty::get(ty::expr_ty_adjusted(self.tcx, &**base)).sty {
|
||||||
|
ty::ty_struct(id, _) => {
|
||||||
|
self.check_field(expr.span, id, UnnamedField(idx.node));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::ExprMethodCall(ident, _, _) => {
|
ast::ExprMethodCall(ident, _, _) => {
|
||||||
let method_call = MethodCall::expr(expr.id);
|
let method_call = MethodCall::expr(expr.id);
|
||||||
match self.tcx.method_map.borrow().find(&method_call) {
|
match self.tcx.method_map.borrow().find(&method_call) {
|
||||||
|
|
|
@ -779,6 +779,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor,
|
||||||
ast::ExprAddrOf(_, ref subexpr) |
|
ast::ExprAddrOf(_, ref subexpr) |
|
||||||
ast::ExprUnary(ast::UnDeref, ref subexpr) |
|
ast::ExprUnary(ast::UnDeref, ref subexpr) |
|
||||||
ast::ExprField(ref subexpr, _, _) |
|
ast::ExprField(ref subexpr, _, _) |
|
||||||
|
ast::ExprTupField(ref subexpr, _, _) |
|
||||||
ast::ExprIndex(ref subexpr, _) |
|
ast::ExprIndex(ref subexpr, _) |
|
||||||
ast::ExprParen(ref subexpr) => {
|
ast::ExprParen(ref subexpr) => {
|
||||||
let subexpr: &'a Gc<Expr> = subexpr; // FIXME(#11586)
|
let subexpr: &'a Gc<Expr> = subexpr; // FIXME(#11586)
|
||||||
|
|
|
@ -1314,6 +1314,34 @@ impl<'l, 'tcx> Visitor<DxrVisitorEnv> for DxrVisitor<'l, 'tcx> {
|
||||||
"Expected struct type, but not ty_struct"),
|
"Expected struct type, but not ty_struct"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ast::ExprTupField(sub_ex, idx, _) => {
|
||||||
|
if generated_code(sub_ex.span) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.visit_expr(&*sub_ex, e);
|
||||||
|
|
||||||
|
let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &*sub_ex);
|
||||||
|
let t_box = ty::get(t);
|
||||||
|
match t_box.sty {
|
||||||
|
ty::ty_struct(def_id, _) => {
|
||||||
|
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
|
||||||
|
for (i, f) in fields.iter().enumerate() {
|
||||||
|
if i == idx.node {
|
||||||
|
let sub_span = self.span.span_for_last_ident(ex.span);
|
||||||
|
self.fmt.ref_str(recorder::VarRef,
|
||||||
|
ex.span,
|
||||||
|
sub_span,
|
||||||
|
f.id,
|
||||||
|
e.cur_scope);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => self.sess.span_bug(ex.span,
|
||||||
|
"Expected struct type, but not ty_struct"),
|
||||||
|
}
|
||||||
|
},
|
||||||
ast::ExprFnBlock(_, decl, body) => {
|
ast::ExprFnBlock(_, decl, body) => {
|
||||||
if generated_code(body.span) {
|
if generated_code(body.span) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -440,6 +440,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||||
(adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
|
(adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref base, idx, _) => {
|
||||||
|
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
|
||||||
|
let brepr = adt::represent_type(cx, bt);
|
||||||
|
expr::with_field_tys(cx.tcx(), bt, None, |discr, _| {
|
||||||
|
(adt::const_get_field(cx, &*brepr, bv, discr, idx.node), inlineable)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ast::ExprIndex(ref base, ref index) => {
|
ast::ExprIndex(ref base, ref index) => {
|
||||||
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
|
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
|
||||||
|
|
|
@ -3457,6 +3457,7 @@ fn populate_scope_map(cx: &CrateContext,
|
||||||
ast::ExprCast(ref sub_exp, _) |
|
ast::ExprCast(ref sub_exp, _) |
|
||||||
ast::ExprAddrOf(_, ref sub_exp) |
|
ast::ExprAddrOf(_, ref sub_exp) |
|
||||||
ast::ExprField(ref sub_exp, _, _) |
|
ast::ExprField(ref sub_exp, _, _) |
|
||||||
|
ast::ExprTupField(ref sub_exp, _, _) |
|
||||||
ast::ExprParen(ref sub_exp) =>
|
ast::ExprParen(ref sub_exp) =>
|
||||||
walk_expr(cx, &**sub_exp, scope_stack, scope_map),
|
walk_expr(cx, &**sub_exp, scope_stack, scope_map),
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ use middle::trans::meth;
|
||||||
use middle::trans::inline;
|
use middle::trans::inline;
|
||||||
use middle::trans::tvec;
|
use middle::trans::tvec;
|
||||||
use middle::trans::type_of;
|
use middle::trans::type_of;
|
||||||
use middle::ty::struct_fields;
|
use middle::ty::{struct_fields, tup_fields};
|
||||||
use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe};
|
use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe};
|
||||||
use middle::ty::{AutoPtr};
|
use middle::ty::{AutoPtr};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
@ -593,6 +593,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
ast::ExprField(ref base, ident, _) => {
|
ast::ExprField(ref base, ident, _) => {
|
||||||
trans_rec_field(bcx, &**base, ident.node)
|
trans_rec_field(bcx, &**base, ident.node)
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref base, idx, _) => {
|
||||||
|
trans_rec_tup_field(bcx, &**base, idx.node)
|
||||||
|
}
|
||||||
ast::ExprIndex(ref base, ref idx) => {
|
ast::ExprIndex(ref base, ref idx) => {
|
||||||
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
|
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
|
||||||
}
|
}
|
||||||
|
@ -666,12 +669,10 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
base: &ast::Expr,
|
base: &ast::Expr,
|
||||||
field: ast::Ident)
|
get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field]| -> uint)
|
||||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||||
//! Translates `base.field`.
|
|
||||||
|
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let _icx = push_ctxt("trans_rec_field");
|
let _icx = push_ctxt("trans_rec_field");
|
||||||
|
|
||||||
|
@ -679,7 +680,7 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
let bare_ty = ty::unopen_type(base_datum.ty);
|
let bare_ty = ty::unopen_type(base_datum.ty);
|
||||||
let repr = adt::represent_type(bcx.ccx(), bare_ty);
|
let repr = adt::represent_type(bcx.ccx(), bare_ty);
|
||||||
with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
|
with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
|
||||||
let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
|
let ix = get_idx(bcx.tcx(), field_tys);
|
||||||
let d = base_datum.get_element(
|
let d = base_datum.get_element(
|
||||||
bcx,
|
bcx,
|
||||||
field_tys[ix].mt.ty,
|
field_tys[ix].mt.ty,
|
||||||
|
@ -697,6 +698,23 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Translates `base.field`.
|
||||||
|
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
|
base: &ast::Expr,
|
||||||
|
field: ast::Ident)
|
||||||
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||||
|
trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Translates `base.<idx>`.
|
||||||
|
fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
|
base: &ast::Expr,
|
||||||
|
idx: uint)
|
||||||
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||||
|
trans_field(bcx, base, |_, _| idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
|
@ -1238,6 +1256,10 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
|
||||||
op(0, struct_fields(tcx, did, substs).as_slice())
|
op(0, struct_fields(tcx, did, substs).as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::ty_tup(ref v) => {
|
||||||
|
op(0, tup_fields(v.as_slice()).as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
ty::ty_enum(_, ref substs) => {
|
ty::ty_enum(_, ref substs) => {
|
||||||
// We want the *variant* ID here, not the enum ID.
|
// We want the *variant* ID here, not the enum ID.
|
||||||
match node_id_opt {
|
match node_id_opt {
|
||||||
|
|
|
@ -3599,6 +3599,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
||||||
|
|
||||||
ast::ExprUnary(ast::UnDeref, _) |
|
ast::ExprUnary(ast::UnDeref, _) |
|
||||||
ast::ExprField(..) |
|
ast::ExprField(..) |
|
||||||
|
ast::ExprTupField(..) |
|
||||||
ast::ExprIndex(..) => {
|
ast::ExprIndex(..) => {
|
||||||
LvalueExpr
|
LvalueExpr
|
||||||
}
|
}
|
||||||
|
@ -4527,6 +4528,11 @@ pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec<field_ty> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_tuple_struct(cx: &ctxt, did: ast::DefId) -> bool {
|
||||||
|
let fields = lookup_struct_fields(cx, did);
|
||||||
|
!fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lookup_struct_field(cx: &ctxt,
|
pub fn lookup_struct_field(cx: &ctxt,
|
||||||
parent: ast::DefId,
|
parent: ast::DefId,
|
||||||
field_id: ast::DefId)
|
field_id: ast::DefId)
|
||||||
|
@ -4554,6 +4560,21 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a list of fields corresponding to the tuple's items. trans uses
|
||||||
|
// this.
|
||||||
|
pub fn tup_fields(v: &[t]) -> Vec<field> {
|
||||||
|
v.iter().enumerate().map(|(i, &f)| {
|
||||||
|
field {
|
||||||
|
// FIXME #6993: change type of field to Name and get rid of new()
|
||||||
|
ident: ast::Ident::new(token::intern(i.to_string().as_slice())),
|
||||||
|
mt: mt {
|
||||||
|
ty: f,
|
||||||
|
mutbl: MutImmutable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UnboxedClosureUpvar {
|
pub struct UnboxedClosureUpvar {
|
||||||
pub def: def::Def,
|
pub def: def::Def,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
|
@ -2603,6 +2603,16 @@ pub fn lookup_field_ty(tcx: &ty::ctxt,
|
||||||
o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
|
o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_tup_field_ty(tcx: &ty::ctxt,
|
||||||
|
class_id: ast::DefId,
|
||||||
|
items: &[ty::field_ty],
|
||||||
|
idx: uint,
|
||||||
|
substs: &subst::Substs) -> Option<ty::t> {
|
||||||
|
|
||||||
|
let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
|
||||||
|
o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
|
||||||
|
}
|
||||||
|
|
||||||
// Controls whether the arguments are automatically referenced. This is useful
|
// Controls whether the arguments are automatically referenced. This is useful
|
||||||
// for overloaded binary and unary operators.
|
// for overloaded binary and unary operators.
|
||||||
pub enum DerefArgs {
|
pub enum DerefArgs {
|
||||||
|
@ -3286,6 +3296,68 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
fcx.write_error(expr.id);
|
fcx.write_error(expr.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check tuple index expressions
|
||||||
|
fn check_tup_field(fcx: &FnCtxt,
|
||||||
|
expr: &ast::Expr,
|
||||||
|
lvalue_pref: LvaluePreference,
|
||||||
|
base: &ast::Expr,
|
||||||
|
idx: codemap::Spanned<uint>,
|
||||||
|
_tys: &[ast::P<ast::Ty>]) {
|
||||||
|
let tcx = fcx.ccx.tcx;
|
||||||
|
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
|
||||||
|
let expr_t = structurally_resolved_type(fcx, expr.span,
|
||||||
|
fcx.expr_ty(base));
|
||||||
|
let mut tuple_like = false;
|
||||||
|
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||||
|
let (_, autoderefs, field_ty) =
|
||||||
|
autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
|
||||||
|
match ty::get(base_t).sty {
|
||||||
|
ty::ty_struct(base_id, ref substs) => {
|
||||||
|
tuple_like = ty::is_tuple_struct(tcx, base_id);
|
||||||
|
if tuple_like {
|
||||||
|
debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t));
|
||||||
|
let fields = ty::lookup_struct_fields(tcx, base_id);
|
||||||
|
lookup_tup_field_ty(tcx, base_id, fields.as_slice(),
|
||||||
|
idx.node, &(*substs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::ty_tup(ref v) => {
|
||||||
|
tuple_like = true;
|
||||||
|
if idx.node < v.len() { Some(v[idx.node]) } else { None }
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
match field_ty {
|
||||||
|
Some(field_ty) => {
|
||||||
|
fcx.write_ty(expr.id, field_ty);
|
||||||
|
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
fcx.type_error_message(
|
||||||
|
expr.span,
|
||||||
|
|actual| {
|
||||||
|
if tuple_like {
|
||||||
|
format!("attempted out-of-bounds tuple index `{}` on \
|
||||||
|
type `{}`",
|
||||||
|
idx.node,
|
||||||
|
actual)
|
||||||
|
} else {
|
||||||
|
format!("attempted tuple index `{}` on type `{}`, but the \
|
||||||
|
type was not a tuple or tuple struct",
|
||||||
|
idx.node,
|
||||||
|
actual)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expr_t, None);
|
||||||
|
|
||||||
|
fcx.write_error(expr.id);
|
||||||
|
}
|
||||||
|
|
||||||
fn check_struct_or_variant_fields(fcx: &FnCtxt,
|
fn check_struct_or_variant_fields(fcx: &FnCtxt,
|
||||||
struct_ty: ty::t,
|
struct_ty: ty::t,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -4065,6 +4137,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
ast::ExprField(ref base, ref field, ref tys) => {
|
ast::ExprField(ref base, ref field, ref tys) => {
|
||||||
check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice());
|
check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice());
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref base, idx, ref tys) => {
|
||||||
|
check_tup_field(fcx, expr, lvalue_pref, &**base, idx, tys.as_slice());
|
||||||
|
}
|
||||||
ast::ExprIndex(ref base, ref idx) => {
|
ast::ExprIndex(ref base, ref idx) => {
|
||||||
check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
|
check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
|
||||||
check_expr(fcx, &**idx);
|
check_expr(fcx, &**idx);
|
||||||
|
|
|
@ -222,6 +222,7 @@ mod svh_visitor {
|
||||||
|
|
||||||
SawExprLoop(Option<token::InternedString>),
|
SawExprLoop(Option<token::InternedString>),
|
||||||
SawExprField(token::InternedString),
|
SawExprField(token::InternedString),
|
||||||
|
SawExprTupField(uint),
|
||||||
SawExprBreak(Option<token::InternedString>),
|
SawExprBreak(Option<token::InternedString>),
|
||||||
SawExprAgain(Option<token::InternedString>),
|
SawExprAgain(Option<token::InternedString>),
|
||||||
|
|
||||||
|
@ -276,6 +277,7 @@ mod svh_visitor {
|
||||||
ExprAssign(..) => SawExprAssign,
|
ExprAssign(..) => SawExprAssign,
|
||||||
ExprAssignOp(op, _, _) => SawExprAssignOp(op),
|
ExprAssignOp(op, _, _) => SawExprAssignOp(op),
|
||||||
ExprField(_, id, _) => SawExprField(content(id.node)),
|
ExprField(_, id, _) => SawExprField(content(id.node)),
|
||||||
|
ExprTupField(_, id, _) => SawExprTupField(id.node),
|
||||||
ExprIndex(..) => SawExprIndex,
|
ExprIndex(..) => SawExprIndex,
|
||||||
ExprPath(..) => SawExprPath,
|
ExprPath(..) => SawExprPath,
|
||||||
ExprAddrOf(m, _) => SawExprAddrOf(m),
|
ExprAddrOf(m, _) => SawExprAddrOf(m),
|
||||||
|
|
|
@ -540,6 +540,7 @@ pub enum Expr_ {
|
||||||
ExprAssign(Gc<Expr>, Gc<Expr>),
|
ExprAssign(Gc<Expr>, Gc<Expr>),
|
||||||
ExprAssignOp(BinOp, Gc<Expr>, Gc<Expr>),
|
ExprAssignOp(BinOp, Gc<Expr>, Gc<Expr>),
|
||||||
ExprField(Gc<Expr>, SpannedIdent, Vec<P<Ty>>),
|
ExprField(Gc<Expr>, SpannedIdent, Vec<P<Ty>>),
|
||||||
|
ExprTupField(Gc<Expr>, Spanned<uint>, Vec<P<Ty>>),
|
||||||
ExprIndex(Gc<Expr>, Gc<Expr>),
|
ExprIndex(Gc<Expr>, Gc<Expr>),
|
||||||
|
|
||||||
/// Variable reference, possibly containing `::` and/or
|
/// Variable reference, possibly containing `::` and/or
|
||||||
|
|
|
@ -120,6 +120,8 @@ pub trait AstBuilder {
|
||||||
fn expr_mut_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr>;
|
fn expr_mut_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr>;
|
||||||
fn expr_field_access(&self, span: Span, expr: Gc<ast::Expr>,
|
fn expr_field_access(&self, span: Span, expr: Gc<ast::Expr>,
|
||||||
ident: ast::Ident) -> Gc<ast::Expr>;
|
ident: ast::Ident) -> Gc<ast::Expr>;
|
||||||
|
fn expr_tup_field_access(&self, sp: Span, expr: Gc<ast::Expr>,
|
||||||
|
idx: uint) -> Gc<ast::Expr>;
|
||||||
fn expr_call(&self, span: Span, expr: Gc<ast::Expr>,
|
fn expr_call(&self, span: Span, expr: Gc<ast::Expr>,
|
||||||
args: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>;
|
args: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>;
|
||||||
fn expr_call_ident(&self, span: Span, id: ast::Ident,
|
fn expr_call_ident(&self, span: Span, id: ast::Ident,
|
||||||
|
@ -605,6 +607,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
let id = Spanned { node: ident, span: field_span };
|
let id = Spanned { node: ident, span: field_span };
|
||||||
self.expr(sp, ast::ExprField(expr, id, Vec::new()))
|
self.expr(sp, ast::ExprField(expr, id, Vec::new()))
|
||||||
}
|
}
|
||||||
|
fn expr_tup_field_access(&self, sp: Span, expr: Gc<ast::Expr>, idx: uint) -> Gc<ast::Expr> {
|
||||||
|
let field_span = Span {
|
||||||
|
lo: sp.lo - Pos::from_uint(idx.to_string().len()),
|
||||||
|
hi: sp.hi,
|
||||||
|
expn_info: sp.expn_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = Spanned { node: idx, span: field_span };
|
||||||
|
self.expr(sp, ast::ExprTupField(expr, id, Vec::new()))
|
||||||
|
}
|
||||||
fn expr_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr> {
|
fn expr_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr> {
|
||||||
self.expr(sp, ast::ExprAddrOf(ast::MutImmutable, e))
|
self.expr(sp, ast::ExprAddrOf(ast::MutImmutable, e))
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,10 @@ pub trait Folder {
|
||||||
noop_fold_ident(i, self)
|
noop_fold_ident(i, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_uint(&mut self, i: uint) -> uint {
|
||||||
|
noop_fold_uint(i, self)
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_path(&mut self, p: &Path) -> Path {
|
fn fold_path(&mut self, p: &Path) -> Path {
|
||||||
noop_fold_path(p, self)
|
noop_fold_path(p, self)
|
||||||
}
|
}
|
||||||
|
@ -466,6 +470,10 @@ pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
|
||||||
i
|
i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
pub fn noop_fold_path<T: Folder>(p: &Path, fld: &mut T) -> Path {
|
pub fn noop_fold_path<T: Folder>(p: &Path, fld: &mut T) -> Path {
|
||||||
ast::Path {
|
ast::Path {
|
||||||
span: fld.new_span(p.span),
|
span: fld.new_span(p.span),
|
||||||
|
@ -1180,6 +1188,11 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
|
||||||
respan(id.span, folder.fold_ident(id.node)),
|
respan(id.span, folder.fold_ident(id.node)),
|
||||||
tys.iter().map(|&x| folder.fold_ty(x)).collect())
|
tys.iter().map(|&x| folder.fold_ty(x)).collect())
|
||||||
}
|
}
|
||||||
|
ExprTupField(el, id, ref tys) => {
|
||||||
|
ExprTupField(folder.fold_expr(el),
|
||||||
|
respan(id.span, folder.fold_uint(id.node)),
|
||||||
|
tys.iter().map(|&x| folder.fold_ty(x)).collect())
|
||||||
|
}
|
||||||
ExprIndex(el, er) => {
|
ExprIndex(el, er) => {
|
||||||
ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
|
ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit
|
||||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||||
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
||||||
use ast::{ExprBreak, ExprCall, ExprCast};
|
use ast::{ExprBreak, ExprCall, ExprCast};
|
||||||
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
|
use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIndex};
|
||||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
||||||
|
@ -1937,6 +1937,11 @@ impl<'a> Parser<'a> {
|
||||||
ExprField(expr, ident, tys)
|
ExprField(expr, ident, tys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mk_tup_field(&mut self, expr: Gc<Expr>, idx: codemap::Spanned<uint>,
|
||||||
|
tys: Vec<P<Ty>>) -> ast::Expr_ {
|
||||||
|
ExprTupField(expr, idx, tys)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mk_assign_op(&mut self, binop: ast::BinOp,
|
pub fn mk_assign_op(&mut self, binop: ast::BinOp,
|
||||||
lhs: Gc<Expr>, rhs: Gc<Expr>) -> ast::Expr_ {
|
lhs: Gc<Expr>, rhs: Gc<Expr>) -> ast::Expr_ {
|
||||||
ExprAssignOp(binop, lhs, rhs)
|
ExprAssignOp(binop, lhs, rhs)
|
||||||
|
@ -2286,6 +2291,41 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
token::LIT_INTEGER(n) => {
|
||||||
|
let index = n.as_str();
|
||||||
|
let dot = self.last_span.hi;
|
||||||
|
hi = self.span.hi;
|
||||||
|
self.bump();
|
||||||
|
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
||||||
|
self.expect_lt();
|
||||||
|
self.parse_generic_values_after_lt()
|
||||||
|
} else {
|
||||||
|
(Vec::new(), Vec::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
let num = from_str::<uint>(index);
|
||||||
|
match num {
|
||||||
|
Some(n) => {
|
||||||
|
let id = spanned(dot, hi, n);
|
||||||
|
let field = self.mk_tup_field(e, id, tys);
|
||||||
|
e = self.mk_expr(lo, hi, field);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let last_span = self.last_span;
|
||||||
|
self.span_err(last_span, "invalid tuple or tuple struct index");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token::LIT_FLOAT(n) => {
|
||||||
|
self.bump();
|
||||||
|
let last_span = self.last_span;
|
||||||
|
self.span_err(last_span,
|
||||||
|
format!("unexpected token: `{}`", n.as_str()).as_slice());
|
||||||
|
self.span_note(last_span,
|
||||||
|
"try parenthesizing the first index; e.g., `(foo.0).1`");
|
||||||
|
self.abort_if_errors();
|
||||||
|
|
||||||
|
}
|
||||||
_ => self.unexpected()
|
_ => self.unexpected()
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1607,6 +1607,18 @@ impl<'a> State<'a> {
|
||||||
try!(word(&mut self.s, ">"));
|
try!(word(&mut self.s, ">"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::ExprTupField(ref expr, id, ref tys) => {
|
||||||
|
try!(self.print_expr(&**expr));
|
||||||
|
try!(word(&mut self.s, "."));
|
||||||
|
try!(self.print_uint(id.node));
|
||||||
|
if tys.len() > 0u {
|
||||||
|
try!(word(&mut self.s, "::<"));
|
||||||
|
try!(self.commasep(
|
||||||
|
Inconsistent, tys.as_slice(),
|
||||||
|
|s, ty| s.print_type_ref(ty)));
|
||||||
|
try!(word(&mut self.s, ">"));
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::ExprIndex(ref expr, ref index) => {
|
ast::ExprIndex(ref expr, ref index) => {
|
||||||
try!(self.print_expr(&**expr));
|
try!(self.print_expr(&**expr));
|
||||||
try!(word(&mut self.s, "["));
|
try!(word(&mut self.s, "["));
|
||||||
|
@ -1738,6 +1750,10 @@ impl<'a> State<'a> {
|
||||||
self.ann.post(self, NodeIdent(&ident))
|
self.ann.post(self, NodeIdent(&ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_uint(&mut self, i: uint) -> IoResult<()> {
|
||||||
|
word(&mut self.s, i.to_string().as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
|
pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
|
||||||
try!(word(&mut self.s, token::get_name(name).get()));
|
try!(word(&mut self.s, token::get_name(name).get()));
|
||||||
self.ann.post(self, NodeName(&name))
|
self.ann.post(self, NodeName(&name))
|
||||||
|
|
|
@ -830,6 +830,12 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
|
||||||
visitor.visit_ty(&**typ, env.clone())
|
visitor.visit_ty(&**typ, env.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ExprTupField(ref subexpression, _, ref types) => {
|
||||||
|
visitor.visit_expr(&**subexpression, env.clone());
|
||||||
|
for typ in types.iter() {
|
||||||
|
visitor.visit_ty(&**typ, env.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
ExprIndex(ref main_expression, ref index_expression) => {
|
ExprIndex(ref main_expression, ref index_expression) => {
|
||||||
visitor.visit_expr(&**main_expression, env.clone());
|
visitor.visit_expr(&**main_expression, env.clone());
|
||||||
visitor.visit_expr(&**index_expression, env.clone())
|
visitor.visit_expr(&**index_expression, env.clone())
|
||||||
|
|
42
src/test/compile-fail/borrow-tuple-fields.rs
Normal file
42
src/test/compile-fail/borrow-tuple-fields.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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Foo(Box<int>, int);
|
||||||
|
|
||||||
|
struct Bar(int, int);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = (box 1i, 2i);
|
||||||
|
let r = &x.0;
|
||||||
|
let y = x; //~ ERROR cannot move out of `x` because it is borrowed
|
||||||
|
|
||||||
|
let mut x = (1i, 2i);
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
|
||||||
|
|
||||||
|
let mut x = (1i, 2i);
|
||||||
|
let a = &mut x.0;
|
||||||
|
let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
|
||||||
|
|
||||||
|
|
||||||
|
let x = Foo(box 1i, 2i);
|
||||||
|
let r = &x.0;
|
||||||
|
let y = x; //~ ERROR cannot move out of `x` because it is borrowed
|
||||||
|
|
||||||
|
let mut x = Bar(1i, 2i);
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
|
||||||
|
|
||||||
|
let mut x = Bar(1i, 2i);
|
||||||
|
let a = &mut x.0;
|
||||||
|
let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
|
||||||
|
}
|
23
src/test/compile-fail/move-out-of-tuple-field.rs
Normal file
23
src/test/compile-fail/move-out-of-tuple-field.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Foo(Box<int>);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = (box 1i,);
|
||||||
|
let y = x.0;
|
||||||
|
let z = x.0; //~ ERROR use of moved value: `x.0`
|
||||||
|
|
||||||
|
let x = Foo(box 1i);
|
||||||
|
let y = x.0;
|
||||||
|
let z = x.0; //~ ERROR use of moved value: `x.0`
|
||||||
|
}
|
22
src/test/compile-fail/tuple-index-not-tuple.rs
Normal file
22
src/test/compile-fail/tuple-index-not-tuple.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Point { x: int, y: int }
|
||||||
|
struct Empty;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let origin = Point { x: 0, y: 0 };
|
||||||
|
origin.0;
|
||||||
|
//~^ ERROR attempted tuple index `0` on type `Point`, but the type was not
|
||||||
|
Empty.0;
|
||||||
|
//~^ ERROR attempted tuple index `0` on type `Empty`, but the type was not
|
||||||
|
}
|
26
src/test/compile-fail/tuple-index-out-of-bounds.rs
Normal file
26
src/test/compile-fail/tuple-index-out-of-bounds.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Point(int, int);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let origin = Point(0, 0);
|
||||||
|
origin.0;
|
||||||
|
origin.1;
|
||||||
|
origin.2;
|
||||||
|
//~^ ERROR attempted out-of-bounds tuple index `2` on type `Point`
|
||||||
|
let tuple = (0i, 0i);
|
||||||
|
tuple.0;
|
||||||
|
tuple.1;
|
||||||
|
tuple.2;
|
||||||
|
//~^ ERROR attempted out-of-bounds tuple index `2` on type `(int,int)`
|
||||||
|
}
|
48
src/test/run-pass/borrow-tuple-fields.rs
Normal file
48
src/test/run-pass/borrow-tuple-fields.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Foo(int, int);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = (1i, 2i);
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &x.0;
|
||||||
|
assert_eq!(*a, 1);
|
||||||
|
assert_eq!(*b, 1);
|
||||||
|
|
||||||
|
let mut x = (1i, 2i);
|
||||||
|
{
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &mut x.1;
|
||||||
|
*b = 5;
|
||||||
|
assert_eq!(*a, 1);
|
||||||
|
}
|
||||||
|
assert_eq!(x.0, 1);
|
||||||
|
assert_eq!(x.1, 5);
|
||||||
|
|
||||||
|
|
||||||
|
let x = Foo(1i, 2i);
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &x.0;
|
||||||
|
assert_eq!(*a, 1);
|
||||||
|
assert_eq!(*b, 1);
|
||||||
|
|
||||||
|
let mut x = Foo(1i, 2i);
|
||||||
|
{
|
||||||
|
let a = &x.0;
|
||||||
|
let b = &mut x.1;
|
||||||
|
*b = 5;
|
||||||
|
assert_eq!(*a, 1);
|
||||||
|
}
|
||||||
|
assert_eq!(x.0, 1);
|
||||||
|
assert_eq!(x.1, 5);
|
||||||
|
}
|
23
src/test/run-pass/tuple-index-fat-types.rs
Normal file
23
src/test/run-pass/tuple-index-fat-types.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Foo<'a>(&'a [int]);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: &[int] = &[1i, 2, 3];
|
||||||
|
let y = (x,);
|
||||||
|
assert_eq!(y.0, x);
|
||||||
|
|
||||||
|
let x: &[int] = &[1i, 2, 3];
|
||||||
|
let y = Foo(x);
|
||||||
|
assert_eq!(y.0, x);
|
||||||
|
}
|
42
src/test/run-pass/tuple-index.rs
Normal file
42
src/test/run-pass/tuple-index.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.
|
||||||
|
|
||||||
|
#![feature(tuple_indexing)]
|
||||||
|
|
||||||
|
struct Point(int, int);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = Point(3, 2);
|
||||||
|
assert_eq!(x.0, 3);
|
||||||
|
assert_eq!(x.1, 2);
|
||||||
|
x.0 += 5;
|
||||||
|
assert_eq!(x.0, 8);
|
||||||
|
{
|
||||||
|
let ry = &mut x.1;
|
||||||
|
*ry -= 2;
|
||||||
|
x.0 += 3;
|
||||||
|
assert_eq!(x.0, 11);
|
||||||
|
}
|
||||||
|
assert_eq!(x.1, 0);
|
||||||
|
|
||||||
|
let mut x = (3i, 2i);
|
||||||
|
assert_eq!(x.0, 3);
|
||||||
|
assert_eq!(x.1, 2);
|
||||||
|
x.0 += 5;
|
||||||
|
assert_eq!(x.0, 8);
|
||||||
|
{
|
||||||
|
let ry = &mut x.1;
|
||||||
|
*ry -= 2;
|
||||||
|
x.0 += 3;
|
||||||
|
assert_eq!(x.0, 11);
|
||||||
|
}
|
||||||
|
assert_eq!(x.1, 0);
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue