Skip to content

Implement tuple and tuple struct indexing (RFC 53) #16866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -2555,6 +2555,8 @@ The currently implemented features of the reference compiler are:
which is considered wildly unsafe and will be
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
start to receive compilation warnings about #[feature] directives which enabled
the new feature (because the directive is no longer necessary). However, if
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("unboxed_closures", Active),
("import_shadowing", Active),
("advanced_slice_patterns", Active),
("tuple_indexing", Active),

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

Expand Down Expand Up @@ -338,6 +339,11 @@ impl<'a> Visitor<()> for Context<'a> {
"unboxed closures are a work-in-progress \
feature with known bugs");
}
ast::ExprTupField(..) => {
self.gate_feature("tuple_indexing",
e.span,
"tuple indexing is experimental");
}
_ => {}
}
visit::walk_expr(self, e, ());
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ impl UnnecessaryParens {
ast::ExprUnary(_, ref x) |
ast::ExprCast(ref x, _) |
ast::ExprField(ref x, _, _) |
ast::ExprTupField(ref x, _, _) |
ast::ExprIndex(ref x, _) => {
// &X { y: 1 }, X { y: 1 }.y
contains_exterior_struct_lit(&**x)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
out.push_str(token::get_name(fname).get());
}
mc::PositionalField(idx) => {
out.push_char('#'); // invent a notation here
out.push_char('.');
out.push_str(idx.to_string().as_slice());
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
ast::ExprCast(e, _) |
ast::ExprUnary(_, e) |
ast::ExprParen(e) |
ast::ExprField(e, _, _) => {
ast::ExprField(e, _, _) |
ast::ExprTupField(e, _, _) => {
self.straightline(expr, pred, [e])
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
ExprAddrOf(MutImmutable, _) |
ExprParen(..) |
ExprField(..) |
ExprTupField(..) |
ExprIndex(..) |
ExprTup(..) |
ExprRepeat(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl<'a, 'tcx> Visitor<bool> for CheckStaticVisitor<'a, 'tcx> {
}

match e.node {
ast::ExprField(..) | ast::ExprVec(..) |
ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
ast::ExprBlock(..) | ast::ExprTup(..) => {
visit::walk_expr(self, e, is_const);
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> {

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

ast::ExprTupField(ref base, _, _) => self.classify(&**base),

ast::ExprIndex(ref base, ref idx) =>
join(self.classify(&**base), self.classify(&**idx)),

Expand Down
14 changes: 14 additions & 0 deletions src/librustc/middle/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
let id = match self.tcx.def_map.borrow().get(&lhs.id) {
&def::DefVariant(_, id, _) => id,
Expand Down Expand Up @@ -255,6 +266,9 @@ impl<'a, 'tcx> Visitor<MarkSymbolVisitorContext> for MarkSymbolVisitor<'a, 'tcx>
ast::ExprField(ref lhs, ref ident, _) => {
self.handle_field_access(&**lhs, &ident.node);
}
ast::ExprTupField(ref lhs, idx, _) => {
self.handle_tup_field_access(&**lhs, idx.node);
}
_ => ()
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
self.select_from_expr(&**base);
}

ast::ExprTupField(ref base, _, _) => { // base.<n>
self.select_from_expr(&**base);
}

ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
if !self.walk_overloaded_operator(expr, &**lhs, [rhs.clone()]) {
self.select_from_expr(&**lhs);
Expand Down
9 changes: 7 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
}

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

ExprTupField(ref e, _, _) => {
self.propagate_through_expr(&**e, succ)
}

ExprFnBlock(_, _, ref blk) |
ExprProc(_, ref blk) |
ExprUnboxedFn(_, _, _, ref blk) => {
Expand Down Expand Up @@ -1271,6 +1275,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
match expr.node {
ExprPath(_) => 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)
}
}
Expand Down Expand Up @@ -1445,7 +1450,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
// no correctness conditions related to liveness
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
ExprVec(..) | ExprTup(..) | ExprBinary(..) |
ExprTupField(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) |
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
Expand Down
20 changes: 20 additions & 0 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

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, _) => {
let method_call = typeck::MethodCall::expr(expr.id());
match self.typer.node_method_ty(method_call) {
Expand Down Expand Up @@ -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 {
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
}
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _, _) => {
let method_call = MethodCall::expr(expr.id);
match self.tcx.method_map.borrow().find(&method_call) {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor,
ast::ExprAddrOf(_, ref subexpr) |
ast::ExprUnary(ast::UnDeref, ref subexpr) |
ast::ExprField(ref subexpr, _, _) |
ast::ExprTupField(ref subexpr, _, _) |
ast::ExprIndex(ref subexpr, _) |
ast::ExprParen(ref subexpr) => {
let subexpr: &'a Gc<Expr> = subexpr; // FIXME(#11586)
Expand Down
28 changes: 28 additions & 0 deletions src/librustc/middle/save/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,34 @@ impl<'l, 'tcx> Visitor<DxrVisitorEnv> for DxrVisitor<'l, 'tcx> {
"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) => {
if generated_code(body.span) {
return
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
(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) => {
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3457,6 +3457,7 @@ fn populate_scope_map(cx: &CrateContext,
ast::ExprCast(ref sub_exp, _) |
ast::ExprAddrOf(_, ref sub_exp) |
ast::ExprField(ref sub_exp, _, _) |
ast::ExprTupField(ref sub_exp, _, _) |
ast::ExprParen(ref sub_exp) =>
walk_expr(cx, &**sub_exp, scope_stack, scope_map),

Expand Down
38 changes: 30 additions & 8 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use middle::trans::meth;
use middle::trans::inline;
use middle::trans::tvec;
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::{AutoPtr};
use middle::ty;
Expand Down Expand Up @@ -593,6 +593,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ast::ExprField(ref base, ident, _) => {
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) => {
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
}
Expand Down Expand Up @@ -666,20 +669,18 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}

fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
base: &ast::Expr,
field: ast::Ident)
-> DatumBlock<'blk, 'tcx, Expr> {
//! Translates `base.field`.

fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
base: &ast::Expr,
get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field]| -> uint)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let _icx = push_ctxt("trans_rec_field");

let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
let bare_ty = ty::unopen_type(base_datum.ty);
let repr = adt::represent_type(bcx.ccx(), bare_ty);
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(
bcx,
field_tys[ix].mt.ty,
Expand All @@ -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>,
Expand Down Expand Up @@ -1238,6 +1256,10 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
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) => {
// We want the *variant* ID here, not the enum ID.
match node_id_opt {
Expand Down
21 changes: 21 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3599,6 +3599,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {

ast::ExprUnary(ast::UnDeref, _) |
ast::ExprField(..) |
ast::ExprTupField(..) |
ast::ExprIndex(..) => {
LvalueExpr
}
Expand Down Expand Up @@ -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,
parent: ast::DefId,
field_id: ast::DefId)
Expand Down Expand Up @@ -4554,6 +4560,21 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
}).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 def: def::Def,
pub span: Span,
Expand Down
Loading