|
| 1 | +- Start Date: 2014-11-29 |
| 2 | +- RFC PR: #459 |
| 3 | +- Rust Issue: [19390](https://github.com/rust-lang/rust/issues/19390) |
| 4 | + |
| 5 | +# Summary |
| 6 | + |
| 7 | +Disallow type/lifetime parameter shadowing. |
| 8 | + |
| 9 | +# Motivation |
| 10 | + |
| 11 | +Today we allow type and lifetime parameters to be shadowed. This is a |
| 12 | +common source of bugs as well as confusing errors. An example of such a confusing case is: |
| 13 | + |
| 14 | +```rust |
| 15 | +struct Foo<'a> { |
| 16 | + x: &'a int |
| 17 | +} |
| 18 | + |
| 19 | +impl<'a> Foo<'a> { |
| 20 | + fn set<'a>(&mut self, v: &'a int) { |
| 21 | + self.x = v; |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +fn main() { } |
| 26 | +``` |
| 27 | + |
| 28 | +In this example, the lifetime parameter `'a` is shadowed on the method, leading to two |
| 29 | +logically distinct lifetime parameters with the same name. This then leads to the error |
| 30 | +message: |
| 31 | + |
| 32 | + mismatched types: expected `&'a int`, found `&'a int` (lifetime mismatch) |
| 33 | + |
| 34 | +which is obviously completely unhelpful. |
| 35 | + |
| 36 | +Similar errors can occur with type parameters: |
| 37 | + |
| 38 | +```rust |
| 39 | +struct Foo<T> { |
| 40 | + x: T |
| 41 | +} |
| 42 | + |
| 43 | +impl<T> Foo<T> { |
| 44 | + fn set<T>(&mut self, v: T) { |
| 45 | + self.x = v; |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +fn main() { } |
| 50 | +``` |
| 51 | + |
| 52 | +Compiling this program yields: |
| 53 | + |
| 54 | + mismatched types: expected `T`, found `T` (expected type parameter, found a different type parameter) |
| 55 | + |
| 56 | +Here the error message was improved by [a recent PR][pr], but this is |
| 57 | +still a somewhat confusing situation. |
| 58 | + |
| 59 | +Anecdotally, this kind of accidental shadowing is fairly frequent |
| 60 | +occurrence. It recently arose on [this discuss thread][dt], for |
| 61 | +example. |
| 62 | + |
| 63 | +[dt]: http://discuss.rust-lang.org/t/confused-by-lifetime-error-messages-tell-me-about-it/358/41?u=nikomatsakis |
| 64 | +[pr]: https://github.com/rust-lang/rust/pull/18264 |
| 65 | + |
| 66 | +# Detailed design |
| 67 | + |
| 68 | +Disallow shadowed type/lifetime parameter declarations. An error would |
| 69 | +be reported by the resolve/resolve-lifetime passes in the compiler and |
| 70 | +hence fairly early in the pipeline. |
| 71 | + |
| 72 | +# Drawbacks |
| 73 | + |
| 74 | +We otherwise allow shadowing, so it is inconsistent. |
| 75 | + |
| 76 | +# Alternatives |
| 77 | + |
| 78 | +We could use a lint instead. However, we'd want to ensure that the |
| 79 | +lint error messages were printed *before* type-checking begins. We |
| 80 | +could do this, perhaps, by running the lint printing pass multiple |
| 81 | +times. This might be useful in any case as the placement of lints in |
| 82 | +the compiler pipeline has proven problematic before. |
| 83 | + |
| 84 | +We could also attempt to improve the error messages. Doing so for |
| 85 | +lifetimes is definitely important in any case, but also somewhat |
| 86 | +tricky due to the extensive inference. It is usually easier and more |
| 87 | +reliable to help avoid the error in the first place. |
| 88 | + |
| 89 | +# Unresolved questions |
| 90 | + |
| 91 | +None. |
0 commit comments