Skip to content

Commit f7382c4

Browse files
committed
Forbid duplicate fields in record types and exprs
Closes #3033
1 parent a0d0584 commit f7382c4

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

src/rustc/middle/resolve3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import str::{connect, split_str};
4747
import vec::pop;
4848

4949
import std::list::{cons, list, nil};
50-
import std::map::{hashmap, int_hash, str_hash};
50+
import std::map::{hashmap, int_hash};
5151
import ASTMap = syntax::ast_map::map;
5252
import str_eq = str::eq;
5353

src/rustc/middle/typeck/check.rs

+38
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,29 @@ fn check_class_member(ccx: @crate_ctxt, class_t: ty::t,
376376
}
377377
}
378378

379+
fn check_no_duplicate_fields(tcx: ty::ctxt, fields:
380+
~[(ast::ident, span)]) {
381+
let field_names = hashmap::<@~str, span>(|x| str::hash(*x),
382+
|x,y| str::eq(*x, *y));
383+
for fields.each |p| {
384+
let (id, sp) = p;
385+
alt field_names.find(id) {
386+
some(orig_sp) {
387+
tcx.sess.span_err(sp, #fmt("Duplicate field \
388+
name %s in record type declaration",
389+
*id));
390+
tcx.sess.span_note(orig_sp, ~"First declaration of \
391+
this field occurred here");
392+
break;
393+
}
394+
none {
395+
field_names.insert(id, sp);
396+
}
397+
}
398+
}
399+
400+
}
401+
379402
fn check_item(ccx: @crate_ctxt, it: @ast::item) {
380403
alt it.node {
381404
ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
@@ -429,6 +452,14 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
429452
ast::item_ty(t, tps) {
430453
let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
431454
check_bounds_are_used(ccx, t.span, tps, tpt_ty);
455+
// If this is a record ty, check for duplicate fields
456+
alt t.node {
457+
ast::ty_rec(fields) {
458+
check_no_duplicate_fields(ccx.tcx, fields.map(|f|
459+
(f.node.ident, f.span)));
460+
}
461+
_ {}
462+
}
432463
}
433464
ast::item_foreign_mod(m) {
434465
if syntax::attr::foreign_abi(it.attrs) ==
@@ -1617,6 +1648,13 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
16171648
fn get_node(f: spanned<field>) -> field { f.node }
16181649
let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node));
16191650
fcx.write_ty(id, typ);
1651+
/* Check for duplicate fields */
1652+
/* Only do this check if there's no base expr -- the reason is
1653+
that we're extending a record we know has no dup fields, and
1654+
it would be ill-typed anyway if we duplicated one of its
1655+
fields */
1656+
check_no_duplicate_fields(tcx, fields.map(|f|
1657+
(f.node.ident, f.span)));
16201658
}
16211659
some(bexpr) {
16221660
let bexpr_t = fcx.expr_ty(bexpr);

src/test/compile-fail/issue-3033.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type cat = {cat_name: ~str, cat_name: int}; //~ ERROR Duplicate field name cat_name
2+
3+
fn main()
4+
{
5+
io::println(int::str({x: 1, x: 2}.x)); //~ ERROR Duplicate field name x
6+
}

0 commit comments

Comments
 (0)