#[feature(uniform_paths)]: allow `use x::y;` to resolve through `self::x`, not just `::x`.
This commit is contained in:
parent
f9b1176eef
commit
39ce9ef00e
|
@ -142,8 +142,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
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,
|
||||
|
@ -154,10 +156,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
|
@ -169,7 +170,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
// 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,
|
||||
|
@ -179,6 +180,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// 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() {
|
||||
|
@ -283,9 +289,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
|
@ -144,6 +144,50 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
|
|||
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() &&
|
||||
(
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// 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();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// 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(());
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// 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();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// 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(());
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
// 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");
|
||||
}
|
Loading…
Reference in New Issue