Skip to content

Commit 09abbbd

Browse files
committed
auto merge of #16866 : P1start/rust/tuple-indexing, r=brson
This allows code to access the fields of tuples and tuple structs behind the feature gate `tuple_indexing`: ```rust #![feature(tuple_indexing)] 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); ``` Implements [RFC 53](https://github.com/rust-lang/rfcs/blob/master/active/0053-tuple-accessors.md). Closes #16950.
2 parents 9f6d27c + bf274bc commit 09abbbd

34 files changed

+549
-14
lines changed

src/doc/rust.md

+2
Original file line numberDiff line numberDiff line change
@@ -2555,6 +2555,8 @@ The currently implemented features of the reference compiler are:
25552555
which is considered wildly unsafe and will be
25562556
obsoleted by language improvements.
25572557

2558+
* `tuple_indexing` - Allows use of tuple indexing (expressions like `expr.0`)
2559+
25582560
If a feature is promoted to a language feature, then all existing programs will
25592561
start to receive compilation warnings about #[feature] directives which enabled
25602562
the new feature (because the directive is no longer necessary). However, if

src/librustc/front/feature_gate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
7070
("unboxed_closures", Active),
7171
("import_shadowing", Active),
7272
("advanced_slice_patterns", Active),
73+
("tuple_indexing", Active),
7374

7475
// if you change this list without updating src/doc/rust.md, cmr will be sad
7576

@@ -338,6 +339,11 @@ impl<'a> Visitor<()> for Context<'a> {
338339
"unboxed closures are a work-in-progress \
339340
feature with known bugs");
340341
}
342+
ast::ExprTupField(..) => {
343+
self.gate_feature("tuple_indexing",
344+
e.span,
345+
"tuple indexing is experimental");
346+
}
341347
_ => {}
342348
}
343349
visit::walk_expr(self, e, ());

src/librustc/lint/builtin.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ impl UnnecessaryParens {
10561056
ast::ExprUnary(_, ref x) |
10571057
ast::ExprCast(ref x, _) |
10581058
ast::ExprField(ref x, _, _) |
1059+
ast::ExprTupField(ref x, _, _) |
10591060
ast::ExprIndex(ref x, _) => {
10601061
// &X { y: 1 }, X { y: 1 }.y
10611062
contains_exterior_struct_lit(&**x)

src/librustc/middle/borrowck/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
807807
out.push_str(token::get_name(fname).get());
808808
}
809809
mc::PositionalField(idx) => {
810-
out.push_char('#'); // invent a notation here
810+
out.push_char('.');
811811
out.push_str(idx.to_string().as_slice());
812812
}
813813
}

src/librustc/middle/cfg/construct.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
467467
ast::ExprCast(e, _) |
468468
ast::ExprUnary(_, e) |
469469
ast::ExprParen(e) |
470-
ast::ExprField(e, _, _) => {
470+
ast::ExprField(e, _, _) |
471+
ast::ExprTupField(e, _, _) => {
471472
self.straightline(expr, pred, [e])
472473
}
473474

src/librustc/middle/check_const.rs

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
173173
ExprAddrOf(MutImmutable, _) |
174174
ExprParen(..) |
175175
ExprField(..) |
176+
ExprTupField(..) |
176177
ExprIndex(..) |
177178
ExprTup(..) |
178179
ExprRepeat(..) |

src/librustc/middle/check_static.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl<'a, 'tcx> Visitor<bool> for CheckStaticVisitor<'a, 'tcx> {
106106
}
107107

108108
match e.node {
109-
ast::ExprField(..) | ast::ExprVec(..) |
109+
ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
110110
ast::ExprBlock(..) | ast::ExprTup(..) => {
111111
visit::walk_expr(self, e, is_const);
112112
}

src/librustc/middle/const_eval.rs

+2
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> {
225225

226226
ast::ExprField(ref base, _, _) => self.classify(&**base),
227227

228+
ast::ExprTupField(ref base, _, _) => self.classify(&**base),
229+
228230
ast::ExprIndex(ref base, ref idx) =>
229231
join(self.classify(&**base), self.classify(&**idx)),
230232

src/librustc/middle/dead.rs

+14
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
145145
}
146146
}
147147

148+
fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: uint) {
149+
match ty::get(ty::expr_ty_adjusted(self.tcx, lhs)).sty {
150+
ty::ty_struct(id, _) => {
151+
let fields = ty::lookup_struct_fields(self.tcx, id);
152+
let field_id = fields[idx].id;
153+
self.live_symbols.insert(field_id.node);
154+
},
155+
_ => ()
156+
}
157+
}
158+
148159
fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[ast::FieldPat]) {
149160
let id = match self.tcx.def_map.borrow().get(&lhs.id) {
150161
&def::DefVariant(_, id, _) => id,
@@ -255,6 +266,9 @@ impl<'a, 'tcx> Visitor<MarkSymbolVisitorContext> for MarkSymbolVisitor<'a, 'tcx>
255266
ast::ExprField(ref lhs, ref ident, _) => {
256267
self.handle_field_access(&**lhs, &ident.node);
257268
}
269+
ast::ExprTupField(ref lhs, idx, _) => {
270+
self.handle_tup_field_access(&**lhs, idx.node);
271+
}
258272
_ => ()
259273
}
260274

src/librustc/middle/expr_use_visitor.rs

+4
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
324324
self.select_from_expr(&**base);
325325
}
326326

327+
ast::ExprTupField(ref base, _, _) => { // base.<n>
328+
self.select_from_expr(&**base);
329+
}
330+
327331
ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
328332
if !self.walk_overloaded_operator(expr, &**lhs, [rhs.clone()]) {
329333
self.select_from_expr(&**lhs);

src/librustc/middle/liveness.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
511511
}
512512

513513
// otherwise, live nodes are not required:
514-
ExprIndex(..) | ExprField(..) | ExprVec(..) |
514+
ExprIndex(..) | ExprField(..) | ExprTupField(..) | ExprVec(..) |
515515
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
516516
ExprBinary(..) | ExprAddrOf(..) |
517517
ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
@@ -965,6 +965,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
965965
self.propagate_through_expr(&**e, succ)
966966
}
967967

968+
ExprTupField(ref e, _, _) => {
969+
self.propagate_through_expr(&**e, succ)
970+
}
971+
968972
ExprFnBlock(_, _, ref blk) |
969973
ExprProc(_, ref blk) |
970974
ExprUnboxedFn(_, _, _, ref blk) => {
@@ -1271,6 +1275,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12711275
match expr.node {
12721276
ExprPath(_) => succ,
12731277
ExprField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
1278+
ExprTupField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
12741279
_ => self.propagate_through_expr(expr, succ)
12751280
}
12761281
}
@@ -1445,7 +1450,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
14451450
// no correctness conditions related to liveness
14461451
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
14471452
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
1448-
ExprVec(..) | ExprTup(..) | ExprBinary(..) |
1453+
ExprTupField(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) |
14491454
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
14501455
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
14511456
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |

src/librustc/middle/mem_categorization.rs

+20
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,11 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
465465
Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
466466
}
467467

468+
ast::ExprTupField(ref base, idx, _) => {
469+
let base_cmt = if_ok!(self.cat_expr(&**base));
470+
Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
471+
}
472+
468473
ast::ExprIndex(ref base, _) => {
469474
let method_call = typeck::MethodCall::expr(expr.id());
470475
match self.typer.node_method_ty(method_call) {
@@ -737,6 +742,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
737742
})
738743
}
739744

745+
pub fn cat_tup_field<N:ast_node>(&self,
746+
node: &N,
747+
base_cmt: cmt,
748+
f_idx: uint,
749+
f_ty: ty::t)
750+
-> cmt {
751+
Rc::new(cmt_ {
752+
id: node.id(),
753+
span: node.span(),
754+
mutbl: base_cmt.mutbl.inherit(),
755+
cat: cat_interior(base_cmt, InteriorField(PositionalField(f_idx))),
756+
ty: f_ty
757+
})
758+
}
759+
740760
pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
741761
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
742762
}

src/librustc/middle/privacy.rs

+8
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,14 @@ impl<'a, 'tcx> Visitor<()> for PrivacyVisitor<'a, 'tcx> {
819819
_ => {}
820820
}
821821
}
822+
ast::ExprTupField(ref base, idx, _) => {
823+
match ty::get(ty::expr_ty_adjusted(self.tcx, &**base)).sty {
824+
ty::ty_struct(id, _) => {
825+
self.check_field(expr.span, id, UnnamedField(idx.node));
826+
}
827+
_ => {}
828+
}
829+
}
822830
ast::ExprMethodCall(ident, _, _) => {
823831
let method_call = MethodCall::expr(expr.id);
824832
match self.tcx.method_map.borrow().find(&method_call) {

src/librustc/middle/region.rs

+1
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor,
779779
ast::ExprAddrOf(_, ref subexpr) |
780780
ast::ExprUnary(ast::UnDeref, ref subexpr) |
781781
ast::ExprField(ref subexpr, _, _) |
782+
ast::ExprTupField(ref subexpr, _, _) |
782783
ast::ExprIndex(ref subexpr, _) |
783784
ast::ExprParen(ref subexpr) => {
784785
let subexpr: &'a Gc<Expr> = subexpr; // FIXME(#11586)

src/librustc/middle/save/mod.rs

+28
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,34 @@ impl<'l, 'tcx> Visitor<DxrVisitorEnv> for DxrVisitor<'l, 'tcx> {
13141314
"Expected struct type, but not ty_struct"),
13151315
}
13161316
},
1317+
ast::ExprTupField(sub_ex, idx, _) => {
1318+
if generated_code(sub_ex.span) {
1319+
return
1320+
}
1321+
1322+
self.visit_expr(&*sub_ex, e);
1323+
1324+
let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &*sub_ex);
1325+
let t_box = ty::get(t);
1326+
match t_box.sty {
1327+
ty::ty_struct(def_id, _) => {
1328+
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
1329+
for (i, f) in fields.iter().enumerate() {
1330+
if i == idx.node {
1331+
let sub_span = self.span.span_for_last_ident(ex.span);
1332+
self.fmt.ref_str(recorder::VarRef,
1333+
ex.span,
1334+
sub_span,
1335+
f.id,
1336+
e.cur_scope);
1337+
break;
1338+
}
1339+
}
1340+
},
1341+
_ => self.sess.span_bug(ex.span,
1342+
"Expected struct type, but not ty_struct"),
1343+
}
1344+
},
13171345
ast::ExprFnBlock(_, decl, body) => {
13181346
if generated_code(body.span) {
13191347
return

src/librustc/middle/trans/consts.rs

+7
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
440440
(adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
441441
})
442442
}
443+
ast::ExprTupField(ref base, idx, _) => {
444+
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
445+
let brepr = adt::represent_type(cx, bt);
446+
expr::with_field_tys(cx.tcx(), bt, None, |discr, _| {
447+
(adt::const_get_field(cx, &*brepr, bv, discr, idx.node), inlineable)
448+
})
449+
}
443450

444451
ast::ExprIndex(ref base, ref index) => {
445452
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);

src/librustc/middle/trans/debuginfo.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3457,6 +3457,7 @@ fn populate_scope_map(cx: &CrateContext,
34573457
ast::ExprCast(ref sub_exp, _) |
34583458
ast::ExprAddrOf(_, ref sub_exp) |
34593459
ast::ExprField(ref sub_exp, _, _) |
3460+
ast::ExprTupField(ref sub_exp, _, _) |
34603461
ast::ExprParen(ref sub_exp) =>
34613462
walk_expr(cx, &**sub_exp, scope_stack, scope_map),
34623463

src/librustc/middle/trans/expr.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use middle::trans::meth;
6262
use middle::trans::inline;
6363
use middle::trans::tvec;
6464
use middle::trans::type_of;
65-
use middle::ty::struct_fields;
65+
use middle::ty::{struct_fields, tup_fields};
6666
use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe};
6767
use middle::ty::{AutoPtr};
6868
use middle::ty;
@@ -593,6 +593,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
593593
ast::ExprField(ref base, ident, _) => {
594594
trans_rec_field(bcx, &**base, ident.node)
595595
}
596+
ast::ExprTupField(ref base, idx, _) => {
597+
trans_rec_tup_field(bcx, &**base, idx.node)
598+
}
596599
ast::ExprIndex(ref base, ref idx) => {
597600
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
598601
}
@@ -666,20 +669,18 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
666669
}
667670
}
668671

669-
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
670-
base: &ast::Expr,
671-
field: ast::Ident)
672-
-> DatumBlock<'blk, 'tcx, Expr> {
673-
//! Translates `base.field`.
674-
672+
fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
673+
base: &ast::Expr,
674+
get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field]| -> uint)
675+
-> DatumBlock<'blk, 'tcx, Expr> {
675676
let mut bcx = bcx;
676677
let _icx = push_ctxt("trans_rec_field");
677678

678679
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
679680
let bare_ty = ty::unopen_type(base_datum.ty);
680681
let repr = adt::represent_type(bcx.ccx(), bare_ty);
681682
with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
682-
let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
683+
let ix = get_idx(bcx.tcx(), field_tys);
683684
let d = base_datum.get_element(
684685
bcx,
685686
field_tys[ix].mt.ty,
@@ -697,6 +698,23 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
697698

698699
}
699700
})
701+
702+
}
703+
704+
/// Translates `base.field`.
705+
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
706+
base: &ast::Expr,
707+
field: ast::Ident)
708+
-> DatumBlock<'blk, 'tcx, Expr> {
709+
trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys))
710+
}
711+
712+
/// Translates `base.<idx>`.
713+
fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
714+
base: &ast::Expr,
715+
idx: uint)
716+
-> DatumBlock<'blk, 'tcx, Expr> {
717+
trans_field(bcx, base, |_, _| idx)
700718
}
701719

702720
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@@ -1238,6 +1256,10 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
12381256
op(0, struct_fields(tcx, did, substs).as_slice())
12391257
}
12401258

1259+
ty::ty_tup(ref v) => {
1260+
op(0, tup_fields(v.as_slice()).as_slice())
1261+
}
1262+
12411263
ty::ty_enum(_, ref substs) => {
12421264
// We want the *variant* ID here, not the enum ID.
12431265
match node_id_opt {

src/librustc/middle/ty.rs

+21
Original file line numberDiff line numberDiff line change
@@ -3599,6 +3599,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
35993599

36003600
ast::ExprUnary(ast::UnDeref, _) |
36013601
ast::ExprField(..) |
3602+
ast::ExprTupField(..) |
36023603
ast::ExprIndex(..) => {
36033604
LvalueExpr
36043605
}
@@ -4527,6 +4528,11 @@ pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec<field_ty> {
45274528
}
45284529
}
45294530

4531+
pub fn is_tuple_struct(cx: &ctxt, did: ast::DefId) -> bool {
4532+
let fields = lookup_struct_fields(cx, did);
4533+
!fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field)
4534+
}
4535+
45304536
pub fn lookup_struct_field(cx: &ctxt,
45314537
parent: ast::DefId,
45324538
field_id: ast::DefId)
@@ -4554,6 +4560,21 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
45544560
}).collect()
45554561
}
45564562

4563+
// Returns a list of fields corresponding to the tuple's items. trans uses
4564+
// this.
4565+
pub fn tup_fields(v: &[t]) -> Vec<field> {
4566+
v.iter().enumerate().map(|(i, &f)| {
4567+
field {
4568+
// FIXME #6993: change type of field to Name and get rid of new()
4569+
ident: ast::Ident::new(token::intern(i.to_string().as_slice())),
4570+
mt: mt {
4571+
ty: f,
4572+
mutbl: MutImmutable
4573+
}
4574+
}
4575+
}).collect()
4576+
}
4577+
45574578
pub struct UnboxedClosureUpvar {
45584579
pub def: def::Def,
45594580
pub span: Span,

0 commit comments

Comments
 (0)