librustc: Forbid duplicate name bindings in the same parameter or type

parameter list.

This breaks code like:

    fn f(a: int, a: int) { ... }
    fn g<T,T>(a: T) { ... }

Change this code to not use the same name for a parameter. For example:

    fn f(a: int, b: int) { ... }
    fn g<T,U>(a: T) { ... }

Code like this is *not* affected, since `_` is not an identifier:

    fn f(_: int, _: int) { ... } // OK

Closes #17568.

[breaking-change]
This commit is contained in:
Patrick Walton 2014-10-08 21:28:50 -07:00
parent 63fe80e1ff
commit 1498814195
3 changed files with 83 additions and 6 deletions

View file

@ -4232,15 +4232,25 @@ impl<'a> Resolver<'a> {
type_parameters: TypeParameters, type_parameters: TypeParameters,
f: |&mut Resolver|) { f: |&mut Resolver|) {
match type_parameters { match type_parameters {
HasTypeParameters(generics, space, node_id, HasTypeParameters(generics, space, node_id, rib_kind) => {
rib_kind) => {
let mut function_type_rib = Rib::new(rib_kind); let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = HashSet::new();
for (index, type_parameter) in generics.ty_params.iter().enumerate() { for (index, type_parameter) in generics.ty_params.iter().enumerate() {
let ident = type_parameter.ident; let ident = type_parameter.ident;
debug!("with_type_parameter_rib: {} {}", node_id, debug!("with_type_parameter_rib: {} {}", node_id,
type_parameter.id); type_parameter.id);
if seen_bindings.contains(&ident) {
self.resolve_error(type_parameter.span,
format!("the name `{}` is already \
used for a type \
parameter in this type \
parameter list",
token::get_ident(
ident)).as_slice())
}
seen_bindings.insert(ident);
let def_like = DlDef(DefTyParam(space, let def_like = DlDef(DefTyParam(space,
local_def(type_parameter.id), local_def(type_parameter.id),
index)); index));
@ -4313,8 +4323,8 @@ impl<'a> Resolver<'a> {
// Nothing to do. // Nothing to do.
} }
Some(declaration) => { Some(declaration) => {
let mut bindings_list = HashMap::new();
for argument in declaration.inputs.iter() { for argument in declaration.inputs.iter() {
let mut bindings_list = HashMap::new();
this.resolve_pattern(&*argument.pat, this.resolve_pattern(&*argument.pat,
ArgumentIrrefutableMode, ArgumentIrrefutableMode,
&mut bindings_list); &mut bindings_list);
@ -5056,12 +5066,24 @@ impl<'a> Resolver<'a> {
// must not add it if it's in the bindings list // must not add it if it's in the bindings list
// because that breaks the assumptions later // because that breaks the assumptions later
// passes make about or-patterns.) // passes make about or-patterns.)
if !bindings_list.contains_key(&renamed) { if !bindings_list.contains_key(&renamed) {
let this = &mut *self; let this = &mut *self;
let last_rib = this.value_ribs.last_mut().unwrap(); let last_rib = this.value_ribs.last_mut().unwrap();
last_rib.bindings.insert(renamed, DlDef(def)); last_rib.bindings.insert(renamed, DlDef(def));
bindings_list.insert(renamed, pat_id); bindings_list.insert(renamed, pat_id);
} else if mode == ArgumentIrrefutableMode &&
bindings_list.contains_key(&renamed) {
// Forbid duplicate bindings in the same
// parameter list.
self.resolve_error(pattern.span,
format!("identifier `{}` \
is bound more \
than once in \
this parameter \
list",
token::get_ident(
ident))
.as_slice())
} else if bindings_list.find(&renamed) == } else if bindings_list.find(&renamed) ==
Some(&pat_id) { Some(&pat_id) {
// Then this is a duplicate variable in the // Then this is a duplicate variable in the

View file

@ -0,0 +1,16 @@
// 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.
fn f(a: int, a: int) {}
//~^ ERROR identifier `a` is bound more than once in this parameter list
fn main() {
}

View file

@ -0,0 +1,39 @@
// 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.
type Foo<T,T> = Option<T>;
//~^ ERROR the name `T` is already used
struct Bar<T,T>(T);
//~^ ERROR the name `T` is already used
struct Baz<T,T> {
//~^ ERROR the name `T` is already used
x: T,
}
enum Boo<T,T> {
//~^ ERROR the name `T` is already used
A(T),
B,
}
fn quux<T,T>(x: T) {}
//~^ ERROR the name `T` is already used
trait Qux<T,T> {}
//~^ ERROR the name `T` is already used
impl<T,T> Qux<T,T> for Option<T> {}
//~^ ERROR the name `T` is already used
fn main() {
}