if source.name == keywords::SelfValue.name() {
type_ns_only = true;
- let last_segment = *module_path.last().unwrap();
- if last_segment.name == keywords::CrateRoot.name() {
+ let empty_prefix = module_path.last().map_or(true, |ident| {
+ ident.name == keywords::CrateRoot.name()
+ });
+ if empty_prefix {
resolve_error(
self,
use_tree.span,
}
// Replace `use foo::self;` with `use foo;`
- let _ = module_path.pop();
- source = last_segment;
+ source = module_path.pop().unwrap();
if rename.is_none() {
- ident = last_segment;
+ ident = source;
}
}
} else {
}
// Disallow `use $crate;`
- if source.name == keywords::DollarCrate.name() && path.segments.len() == 1 {
+ if source.name == keywords::DollarCrate.name() && module_path.is_empty() {
let crate_root = self.resolve_crate_root(source);
let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name,
// in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
// while the current crate doesn't have a valid `crate_name`.
if crate_name != keywords::Invalid.name() {
+ // `crate_name` should not be interpreted as relative.
+ module_path.push(Ident {
+ name: keywords::CrateRoot.name(),
+ span: source.span,
+ });
source.name = crate_name;
}
if rename.is_none() {
match item.node {
ItemKind::Use(ref use_tree) => {
+ let uniform_paths =
+ self.session.rust_2018() &&
+ self.session.features_untracked().uniform_paths;
// Imports are resolved as global by default, add starting root segment.
+ let root = if !uniform_paths {
+ use_tree.prefix.make_root()
+ } else {
+ // Except when `#![feature(uniform_paths)]` is on.
+ None
+ };
let prefix = ast::Path {
- segments: use_tree.prefix.make_root().into_iter().collect(),
+ segments: root.into_iter().collect(),
span: use_tree.span,
};
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
ModuleOrUniformRoot::UniformRoot(root) => {
+ // HACK(eddyb): `resolve_path` uses `keywords::Invalid` to indicate
+ // paths of length 0, and currently these are relative `use` paths.
+ let can_be_relative = !ident.is_path_segment_keyword() &&
+ root == keywords::Invalid.name();
+ if can_be_relative {
+ // Relative paths should only get here if the feature-gate is on.
+ assert!(self.session.rust_2018() &&
+ self.session.features_untracked().uniform_paths);
+
+ // Try first to resolve relatively.
+ let mut ctxt = ident.span.ctxt().modern();
+ let self_module = self.resolve_self(&mut ctxt, self.current_module);
+
+ let binding = self.resolve_ident_in_module_unadjusted(
+ ModuleOrUniformRoot::Module(self_module),
+ ident,
+ ns,
+ restricted_shadowing,
+ record_used,
+ path_span,
+ );
+
+ // FIXME(eddyb) This may give false negatives, specifically
+ // if a crate with the same name is found in `extern_prelude`,
+ // preventing the check below this one from returning `binding`
+ // in all cases.
+ //
+ // That is, if there's no crate with the same name, `binding`
+ // is always returned, which is the result of doing the exact
+ // same lookup of `ident`, in the `self` module.
+ // But when a crate does exist, it will get chosen even when
+ // macro expansion could result in a success from the lookup
+ // in the `self` module, later on.
+ if binding.is_ok() {
+ return binding;
+ }
+
+ // Fall back to resolving to an external crate.
+ if !self.extern_prelude.contains(&ident.name) {
+ // ... unless the crate name is not in the `extern_prelude`.
+ return binding;
+ }
+ }
+
let crate_root = if
root != keywords::Extern.name() &&
(
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+// This test is similar to `basic.rs`, but nested in modules.
+
+mod foo {
+ // Test that ambiguity errors are not emitted between `self::test` and
+ // `::test`, assuming the latter (crate) is not in `extern_prelude`.
+ mod test {
+ pub struct Foo(pub ());
+ }
+ pub use test::Foo;
+
+ // Test that qualified paths can refer to both the external crate and local item.
+ mod std {
+ pub struct io(pub ());
+ }
+ pub use ::std::io as std_io;
+ pub use self::std::io as local_io;
+}
+
+// Test that we can refer to the external crate unqualified
+// (when there isn't a local item with the same name).
+use std::io;
+
+mod bar {
+ // Also test the unqualified external crate import in a nested module,
+ // to show that the above import doesn't resolve through a local `std`
+ // item, e.g. the automatically injected `extern crate std;`, which in
+ // the Rust 2018 should no longer be visible through `crate::std`.
+ pub use std::io;
+}
+
+
+fn main() {
+ foo::Foo(());
+ foo::std_io::stdout();
+ foo::local_io(());
+ io::stdout();
+ bar::io::stdout();
+}
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+// Test that ambiguity errors are not emitted between `self::test` and
+// `::test`, assuming the latter (crate) is not in `extern_prelude`.
+mod test {
+ pub struct Foo(pub ());
+}
+use test::Foo;
+
+// Test that qualified paths can refer to both the external crate and local item.
+mod std {
+ pub struct io(pub ());
+}
+use ::std::io as std_io;
+use self::std::io as local_io;
+
+fn main() {
+ Foo(());
+ std_io::stdout();
+ local_io(());
+}
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+// This test is similar to `macros.rs`, but nested in modules.
+
+mod foo {
+ // Test that ambiguity errors are not emitted between `self::test` and
+ // `::test`, assuming the latter (crate) is not in `extern_prelude`.
+ macro_rules! m1 {
+ () => {
+ mod test {
+ pub struct Foo(pub ());
+ }
+ }
+ }
+ pub use test::Foo;
+ m1!();
+
+ // Test that qualified paths can refer to both the external crate and local item.
+ macro_rules! m2 {
+ () => {
+ mod std {
+ pub struct io(pub ());
+ }
+ }
+ }
+ pub use ::std::io as std_io;
+ pub use self::std::io as local_io;
+ m2!();
+}
+
+// Test that we can refer to the external crate unqualified
+// (when there isn't a local item with the same name).
+use std::io;
+
+mod bar {
+ // Also test the unqualified external crate import in a nested module,
+ // to show that the above import doesn't resolve through a local `std`
+ // item, e.g. the automatically injected `extern crate std;`, which in
+ // the Rust 2018 should no longer be visible through `crate::std`.
+ pub use std::io;
+}
+
+
+fn main() {
+ foo::Foo(());
+ foo::std_io::stdout();
+ foo::local_io(());
+ io::stdout();
+ bar::io::stdout();
+}
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+// This test is similar to `basic.rs`, but with macros defining local items.
+
+// Test that ambiguity errors are not emitted between `self::test` and
+// `::test`, assuming the latter (crate) is not in `extern_prelude`.
+macro_rules! m1 {
+ () => {
+ mod test {
+ pub struct Foo(pub ());
+ }
+ }
+}
+use test::Foo;
+m1!();
+
+// Test that qualified paths can refer to both the external crate and local item.
+macro_rules! m2 {
+ () => {
+ mod std {
+ pub struct io(pub ());
+ }
+ }
+}
+use ::std::io as std_io;
+use self::std::io as local_io;
+m2!();
+
+fn main() {
+ Foo(());
+ std_io::stdout();
+ local_io(());
+}
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+pub const A: usize = 0;
+
+pub mod foo {
+ pub const B: usize = 1;
+
+ pub mod bar {
+ pub const C: usize = 2;
+
+ pub enum E {
+ V1(usize),
+ V2(String),
+ }
+
+ pub fn test() -> String {
+ format!("{} {} {}", crate::A, crate::foo::B, C)
+ }
+
+ pub fn test_use() -> String {
+ use crate::A;
+ use crate::foo::B;
+
+ format!("{} {} {}", A, B, C)
+ }
+
+ pub fn test_enum() -> String {
+ use E::*;
+ match E::V1(10) {
+ V1(i) => { format!("V1: {}", i) }
+ V2(s) => { format!("V2: {}", s) }
+ }
+ }
+ }
+
+ pub fn test() -> String {
+ format!("{} {} {}", crate::A, B, bar::C)
+ }
+
+ pub fn test_use() -> String {
+ use crate::A;
+ use bar::C;
+
+ format!("{} {} {}", A, B, C)
+ }
+
+ pub fn test_enum() -> String {
+ use bar::E::*;
+ match bar::E::V1(10) {
+ V1(i) => { format!("V1: {}", i) }
+ V2(s) => { format!("V2: {}", s) }
+ }
+ }
+}
+
+pub fn test() -> String {
+ format!("{} {} {}", A, foo::B, foo::bar::C)
+}
+
+pub fn test_use() -> String {
+ use foo::B;
+ use foo::bar::C;
+
+ format!("{} {} {}", A, B, C)
+}
+
+pub fn test_enum() -> String {
+ use foo::bar::E::*;
+ match foo::bar::E::V1(10) {
+ V1(i) => { format!("V1: {}", i) }
+ V2(s) => { format!("V2: {}", s) }
+ }
+}
+
+fn main() {
+ let output = [
+ test(),
+ foo::test(),
+ foo::bar::test(),
+ test_use(),
+ foo::test_use(),
+ foo::bar::test_use(),
+ test_enum(),
+ foo::test_enum(),
+ foo::bar::test_enum(),
+ ].join("\n");
+ assert_eq!(output, "\
+0 1 2
+0 1 2
+0 1 2
+0 1 2
+0 1 2
+0 1 2
+V1: 10
+V1: 10
+V1: 10");
+}