Skip to content

Commit 39ce9ef

Browse files
cramertjeddyb
authored andcommitted
#[feature(uniform_paths)]: allow use x::y; to resolve through self::x, not just ::x.
1 parent f9b1176 commit 39ce9ef

File tree

7 files changed

+367
-7
lines changed

7 files changed

+367
-7
lines changed

src/librustc_resolve/build_reduced_graph.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
142142
if source.name == keywords::SelfValue.name() {
143143
type_ns_only = true;
144144

145-
let last_segment = *module_path.last().unwrap();
146-
if last_segment.name == keywords::CrateRoot.name() {
145+
let empty_prefix = module_path.last().map_or(true, |ident| {
146+
ident.name == keywords::CrateRoot.name()
147+
});
148+
if empty_prefix {
147149
resolve_error(
148150
self,
149151
use_tree.span,
@@ -154,10 +156,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
154156
}
155157

156158
// Replace `use foo::self;` with `use foo;`
157-
let _ = module_path.pop();
158-
source = last_segment;
159+
source = module_path.pop().unwrap();
159160
if rename.is_none() {
160-
ident = last_segment;
161+
ident = source;
161162
}
162163
}
163164
} else {
@@ -169,7 +170,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
169170
}
170171

171172
// Disallow `use $crate;`
172-
if source.name == keywords::DollarCrate.name() && path.segments.len() == 1 {
173+
if source.name == keywords::DollarCrate.name() && module_path.is_empty() {
173174
let crate_root = self.resolve_crate_root(source);
174175
let crate_name = match crate_root.kind {
175176
ModuleKind::Def(_, name) => name,
@@ -179,6 +180,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
179180
// in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
180181
// while the current crate doesn't have a valid `crate_name`.
181182
if crate_name != keywords::Invalid.name() {
183+
// `crate_name` should not be interpreted as relative.
184+
module_path.push(Ident {
185+
name: keywords::CrateRoot.name(),
186+
span: source.span,
187+
});
182188
source.name = crate_name;
183189
}
184190
if rename.is_none() {
@@ -283,9 +289,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
283289

284290
match item.node {
285291
ItemKind::Use(ref use_tree) => {
292+
let uniform_paths =
293+
self.session.rust_2018() &&
294+
self.session.features_untracked().uniform_paths;
286295
// Imports are resolved as global by default, add starting root segment.
296+
let root = if !uniform_paths {
297+
use_tree.prefix.make_root()
298+
} else {
299+
// Except when `#![feature(uniform_paths)]` is on.
300+
None
301+
};
287302
let prefix = ast::Path {
288-
segments: use_tree.prefix.make_root().into_iter().collect(),
303+
segments: root.into_iter().collect(),
289304
span: use_tree.span,
290305
};
291306

src/librustc_resolve/resolve_imports.rs

+44
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,50 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
144144
let module = match module {
145145
ModuleOrUniformRoot::Module(module) => module,
146146
ModuleOrUniformRoot::UniformRoot(root) => {
147+
// HACK(eddyb): `resolve_path` uses `keywords::Invalid` to indicate
148+
// paths of length 0, and currently these are relative `use` paths.
149+
let can_be_relative = !ident.is_path_segment_keyword() &&
150+
root == keywords::Invalid.name();
151+
if can_be_relative {
152+
// Relative paths should only get here if the feature-gate is on.
153+
assert!(self.session.rust_2018() &&
154+
self.session.features_untracked().uniform_paths);
155+
156+
// Try first to resolve relatively.
157+
let mut ctxt = ident.span.ctxt().modern();
158+
let self_module = self.resolve_self(&mut ctxt, self.current_module);
159+
160+
let binding = self.resolve_ident_in_module_unadjusted(
161+
ModuleOrUniformRoot::Module(self_module),
162+
ident,
163+
ns,
164+
restricted_shadowing,
165+
record_used,
166+
path_span,
167+
);
168+
169+
// FIXME(eddyb) This may give false negatives, specifically
170+
// if a crate with the same name is found in `extern_prelude`,
171+
// preventing the check below this one from returning `binding`
172+
// in all cases.
173+
//
174+
// That is, if there's no crate with the same name, `binding`
175+
// is always returned, which is the result of doing the exact
176+
// same lookup of `ident`, in the `self` module.
177+
// But when a crate does exist, it will get chosen even when
178+
// macro expansion could result in a success from the lookup
179+
// in the `self` module, later on.
180+
if binding.is_ok() {
181+
return binding;
182+
}
183+
184+
// Fall back to resolving to an external crate.
185+
if !self.extern_prelude.contains(&ident.name) {
186+
// ... unless the crate name is not in the `extern_prelude`.
187+
return binding;
188+
}
189+
}
190+
147191
let crate_root = if
148192
root != keywords::Extern.name() &&
149193
(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
#![feature(uniform_paths)]
14+
15+
// This test is similar to `basic.rs`, but nested in modules.
16+
17+
mod foo {
18+
// Test that ambiguity errors are not emitted between `self::test` and
19+
// `::test`, assuming the latter (crate) is not in `extern_prelude`.
20+
mod test {
21+
pub struct Foo(pub ());
22+
}
23+
pub use test::Foo;
24+
25+
// Test that qualified paths can refer to both the external crate and local item.
26+
mod std {
27+
pub struct io(pub ());
28+
}
29+
pub use ::std::io as std_io;
30+
pub use self::std::io as local_io;
31+
}
32+
33+
// Test that we can refer to the external crate unqualified
34+
// (when there isn't a local item with the same name).
35+
use std::io;
36+
37+
mod bar {
38+
// Also test the unqualified external crate import in a nested module,
39+
// to show that the above import doesn't resolve through a local `std`
40+
// item, e.g. the automatically injected `extern crate std;`, which in
41+
// the Rust 2018 should no longer be visible through `crate::std`.
42+
pub use std::io;
43+
}
44+
45+
46+
fn main() {
47+
foo::Foo(());
48+
foo::std_io::stdout();
49+
foo::local_io(());
50+
io::stdout();
51+
bar::io::stdout();
52+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
#![feature(uniform_paths)]
14+
15+
// Test that ambiguity errors are not emitted between `self::test` and
16+
// `::test`, assuming the latter (crate) is not in `extern_prelude`.
17+
mod test {
18+
pub struct Foo(pub ());
19+
}
20+
use test::Foo;
21+
22+
// Test that qualified paths can refer to both the external crate and local item.
23+
mod std {
24+
pub struct io(pub ());
25+
}
26+
use ::std::io as std_io;
27+
use self::std::io as local_io;
28+
29+
fn main() {
30+
Foo(());
31+
std_io::stdout();
32+
local_io(());
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
#![feature(uniform_paths)]
14+
15+
// This test is similar to `macros.rs`, but nested in modules.
16+
17+
mod foo {
18+
// Test that ambiguity errors are not emitted between `self::test` and
19+
// `::test`, assuming the latter (crate) is not in `extern_prelude`.
20+
macro_rules! m1 {
21+
() => {
22+
mod test {
23+
pub struct Foo(pub ());
24+
}
25+
}
26+
}
27+
pub use test::Foo;
28+
m1!();
29+
30+
// Test that qualified paths can refer to both the external crate and local item.
31+
macro_rules! m2 {
32+
() => {
33+
mod std {
34+
pub struct io(pub ());
35+
}
36+
}
37+
}
38+
pub use ::std::io as std_io;
39+
pub use self::std::io as local_io;
40+
m2!();
41+
}
42+
43+
// Test that we can refer to the external crate unqualified
44+
// (when there isn't a local item with the same name).
45+
use std::io;
46+
47+
mod bar {
48+
// Also test the unqualified external crate import in a nested module,
49+
// to show that the above import doesn't resolve through a local `std`
50+
// item, e.g. the automatically injected `extern crate std;`, which in
51+
// the Rust 2018 should no longer be visible through `crate::std`.
52+
pub use std::io;
53+
}
54+
55+
56+
fn main() {
57+
foo::Foo(());
58+
foo::std_io::stdout();
59+
foo::local_io(());
60+
io::stdout();
61+
bar::io::stdout();
62+
}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
#![feature(uniform_paths)]
14+
15+
// This test is similar to `basic.rs`, but with macros defining local items.
16+
17+
// Test that ambiguity errors are not emitted between `self::test` and
18+
// `::test`, assuming the latter (crate) is not in `extern_prelude`.
19+
macro_rules! m1 {
20+
() => {
21+
mod test {
22+
pub struct Foo(pub ());
23+
}
24+
}
25+
}
26+
use test::Foo;
27+
m1!();
28+
29+
// Test that qualified paths can refer to both the external crate and local item.
30+
macro_rules! m2 {
31+
() => {
32+
mod std {
33+
pub struct io(pub ());
34+
}
35+
}
36+
}
37+
use ::std::io as std_io;
38+
use self::std::io as local_io;
39+
m2!();
40+
41+
fn main() {
42+
Foo(());
43+
std_io::stdout();
44+
local_io(());
45+
}

0 commit comments

Comments
 (0)