From 14988141952e29e1d46396e99cf286cd7aa9ee95 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Oct 2014 21:28:50 -0700 Subject: [PATCH] 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(a: T) { ... } Change this code to not use the same name for a parameter. For example: fn f(a: int, b: int) { ... } fn g(a: T) { ... } Code like this is *not* affected, since `_` is not an identifier: fn f(_: int, _: int) { ... } // OK Closes #17568. [breaking-change] --- src/librustc/middle/resolve.rs | 34 +++++++++++++--- src/test/compile-fail/duplicate-parameter.rs | 16 ++++++++ .../compile-fail/duplicate-type-parameter.rs | 39 +++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/duplicate-parameter.rs create mode 100644 src/test/compile-fail/duplicate-type-parameter.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 595739585a398..9c8cc3cc9ad88 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4232,15 +4232,25 @@ impl<'a> Resolver<'a> { type_parameters: TypeParameters, f: |&mut Resolver|) { match type_parameters { - HasTypeParameters(generics, space, node_id, - rib_kind) => { - + HasTypeParameters(generics, space, node_id, 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() { let ident = type_parameter.ident; debug!("with_type_parameter_rib: {} {}", node_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, local_def(type_parameter.id), index)); @@ -4313,8 +4323,8 @@ impl<'a> Resolver<'a> { // Nothing to do. } Some(declaration) => { + let mut bindings_list = HashMap::new(); for argument in declaration.inputs.iter() { - let mut bindings_list = HashMap::new(); this.resolve_pattern(&*argument.pat, ArgumentIrrefutableMode, &mut bindings_list); @@ -5056,12 +5066,24 @@ impl<'a> Resolver<'a> { // must not add it if it's in the bindings list // because that breaks the assumptions later // passes make about or-patterns.) - if !bindings_list.contains_key(&renamed) { let this = &mut *self; let last_rib = this.value_ribs.last_mut().unwrap(); last_rib.bindings.insert(renamed, DlDef(def)); 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) == Some(&pat_id) { // Then this is a duplicate variable in the diff --git a/src/test/compile-fail/duplicate-parameter.rs b/src/test/compile-fail/duplicate-parameter.rs new file mode 100644 index 0000000000000..c1c0f974de9e5 --- /dev/null +++ b/src/test/compile-fail/duplicate-parameter.rs @@ -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 or the MIT license +// , 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() { +} + diff --git a/src/test/compile-fail/duplicate-type-parameter.rs b/src/test/compile-fail/duplicate-type-parameter.rs new file mode 100644 index 0000000000000..d535ce4a69a2d --- /dev/null +++ b/src/test/compile-fail/duplicate-type-parameter.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Foo = Option; +//~^ ERROR the name `T` is already used + +struct Bar(T); +//~^ ERROR the name `T` is already used + +struct Baz { +//~^ ERROR the name `T` is already used + x: T, +} + +enum Boo { +//~^ ERROR the name `T` is already used + A(T), + B, +} + +fn quux(x: T) {} +//~^ ERROR the name `T` is already used + +trait Qux {} +//~^ ERROR the name `T` is already used + +impl Qux for Option {} +//~^ ERROR the name `T` is already used + +fn main() { +} +