Skip to content

Commit 276b715

Browse files
committed
Feature gate import shadowing
1 parent 62bfca4 commit 276b715

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

active/0000-no-module-shadowing.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
- Start Date: 2014-06-12
2+
- RFC PR #:
3+
- Rust Issue #:
4+
5+
# Summary
6+
7+
Feature gate the shadowing of all namespaces between `extern crate`, `use` and items in the
8+
same scope, in order to restrict the module system to something more open to experimentation
9+
and changes post 1.0.
10+
11+
# Motivation
12+
13+
Currently, what is visible under which namespace in a given module is determined by a
14+
somewhat complicated three step process:
15+
16+
1. First, every `extern crate` item creates a name in the module namespace.
17+
2. Then, every `use` can create a name in any of the three namespaces,
18+
where the module ones shadow the `extern crate` ones.
19+
3. Lastly, any declaration can shadow any name brought in scope by both `extern crate` and `use`.
20+
21+
These rules have developed mostly in response to the older, more complicated import system, and
22+
the existence of wildcard imports (`use foo::*`), which can cause the problem that user code breaks
23+
if a used crate gets updated to include a definition name the user has used himself.
24+
25+
However, wildcard imports are now feature gated, and name conflicts can be resolved by using the
26+
renaming feature of `extern crate` and `use`, so in the current state of the language there is no
27+
need for this shadowing behavior.
28+
29+
Gating it off opens the door to remove it altogether in a backwards compatible way, or to
30+
re-enable it in case globs get enabled again.
31+
32+
# Drawbacks
33+
34+
- Feature gating import shadowing might break some code using `#[feature(globs)]`.
35+
- The behavior of `libstd`s prelude either becomes more magical if it still allows shadowing,
36+
or more restricted if it doesn't allow shadowing.
37+
38+
# Detailed design
39+
40+
A new feature gate `import_shadowing` gets created.
41+
42+
During the name resolution phase of compilation, every time the compiler detects a shadowing
43+
between `extern crate`, `use` and declarations in the same scope,
44+
it bails out unless the feature gate got enabled.
45+
46+
Just like for the `globs` feature, the `libstd` prelude import would be preempt from this,
47+
and still be allowed to be shadowed.
48+
49+
# Alternatives
50+
51+
The alternative is to do nothing, and risk running into a backwards compatibility hazard,
52+
or committing to make a final design decision around the whole module system before 1.0 gets
53+
released.
54+
55+
# Unresolved questions
56+
57+
- It is unclear how the `libstd` preludes fits into this.
58+
59+
On the one hand, it basically acts like a hidden `use std::prelude::*;` import
60+
which ignores the `globs` feature, so it could simply also ignore the
61+
`import_shadowing` feature as well, and the rule becomes that the prelude is a magic
62+
compiler feature that injects imports into every module but doesn't prevent the user
63+
from taking the same names.
64+
65+
On the other hand, it is also thinkable to simply forbid shadowing of prelude items as well,
66+
as defining things with the same name as std exports is unrecommended anyway, and this would
67+
nicely enforce that. It would however mean that the prelude can not change without breaking
68+
backwards compatibility, which might be too restricting.
69+
70+
A compromise would be to specialize wildcard imports into a new `prelude use` feature, which
71+
has the explicit properties of being shadow-able and using a wildcard import. `libstd`s prelude
72+
could then simply use that, and users could define and use their own preludes as well.
73+
But that's a somewhat orthogonal feature, and should be discussed in its own RFC.
74+
75+
- Should scoped declarations fall under these rules as well?
76+
77+
Currently, you can also shadow declarations and imports by using lexical scopes. For example,
78+
each struct definition shadows the prior one here:
79+
```rust
80+
struct Foo(());
81+
fn main() {
82+
struct Foo(());
83+
static FOO: () = {
84+
struct Foo(());
85+
()
86+
};
87+
}
88+
```
89+
That feature will probably stay, but there might be consistency problems
90+
or interactions with this proposal, which is why it is included in the discussion here.
91+
92+
- Interaction with overlapping imports.
93+
94+
Right now its legal to write this:
95+
```rust
96+
fn main() {
97+
use Bar = std::result::Result;
98+
use Bar = std::option::Option;
99+
let x: Bar<uint> = None;
100+
}
101+
```
102+
where the latter `use` shadows the former. This would have to be forbidden as well,
103+
however the current semantic seems like a accident anyway.

0 commit comments

Comments
 (0)