about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-09-09 06:25:13 +0000
committerbors <bors@rust-lang.org>2018-09-09 06:25:13 +0000
commit3d2fc456a91e898f735f97f1a9ea79432da4e1a5 (patch)
treeb7620e25ede29068f275795f65610a116f215a70
parentdac76020a5a33fa723d578043e422455e598620b (diff)
parente0e7cf303ba2fd63763e6d99a9d67dced1fac8ab (diff)
downloadrust-3d2fc456a91e898f735f97f1a9ea79432da4e1a5.tar.gz
rust-3d2fc456a91e898f735f97f1a9ea79432da4e1a5.zip
Auto merge of #53988 - eddyb:issue-53770, r=petrochenkov
rustc_resolve: only prepend CrateRoot to a non-keyword segment.

Fixes #53770 by treating `use` paths as absolute in a finer-grained manner, specifically:
```rust
use {a, crate::b, self::c, super::d};
```
Used to be interpreted as if it were (when `uniform_paths` is not enabled):
```rust
use ::{a, crate::b, self::c, super::d};
```
With this PR, the `CrateRoot` pseudo-keyword indicating an absolute path is only inserted when the first path segment is found (if it's not a keyword), i.e. the example behaves like:
```rust
use {::a, crate::b, self::c, super::d};
```
This should (finally) make `use {path};` fully equivalent to `use path;`.

r? @petrochenkov cc @cramertj @joshtriplett @nikomatsakis
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs78
-rw-r--r--src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs14
2 files changed, 49 insertions, 43 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 37868a83e34..92a9057d96e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -120,26 +120,48 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         use_tree: &ast::UseTree,
         id: NodeId,
         vis: ty::Visibility,
-        prefix: &ast::Path,
+        parent_prefix: &[Ident],
         mut uniform_paths_canary_emitted: bool,
         nested: bool,
         item: &Item,
         expansion: Mark,
     ) {
-        debug!("build_reduced_graph_for_use_tree(prefix={:?}, \
+        debug!("build_reduced_graph_for_use_tree(parent_prefix={:?}, \
                 uniform_paths_canary_emitted={}, \
                 use_tree={:?}, nested={})",
-               prefix, uniform_paths_canary_emitted, use_tree, nested);
+               parent_prefix, uniform_paths_canary_emitted, use_tree, nested);
 
         let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
-        let path = &use_tree.prefix;
+        let uniform_paths =
+            self.session.rust_2018() &&
+            self.session.features_untracked().uniform_paths;
+
+        let prefix_iter = || parent_prefix.iter().cloned()
+            .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident));
+        let prefix_start = prefix_iter().nth(0);
+        let starts_with_non_keyword = prefix_start.map_or(false, |ident| {
+            !ident.is_path_segment_keyword()
+        });
+
+        // Imports are resolved as global by default, prepend `CrateRoot`,
+        // unless `#![feature(uniform_paths)]` is enabled.
+        let inject_crate_root =
+            !uniform_paths &&
+            match use_tree.kind {
+                // HACK(eddyb) special-case `use *` to mean `use ::*`.
+                ast::UseTreeKind::Glob if prefix_start.is_none() => true,
+                _ => starts_with_non_keyword,
+            };
+        let root = if inject_crate_root {
+            let span = use_tree.prefix.span.shrink_to_lo();
+            Some(Ident::new(keywords::CrateRoot.name(), span))
+        } else {
+            None
+        };
 
-        let mut module_path: Vec<_> = prefix.segments.iter()
-            .chain(path.segments.iter())
-            .map(|seg| seg.ident)
-            .collect();
+        let prefix: Vec<_> = root.into_iter().chain(prefix_iter()).collect();
 
-        debug!("build_reduced_graph_for_use_tree: module_path={:?}", module_path);
+        debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
 
         // `#[feature(uniform_paths)]` allows an unqualified import path,
         // e.g. `use x::...;` to resolve not just globally (`use ::x::...;`)
@@ -172,15 +194,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         // ergonomically unacceptable.
         let emit_uniform_paths_canary =
             !uniform_paths_canary_emitted &&
-            module_path.get(0).map_or(false, |ident| {
-                !ident.is_path_segment_keyword()
-            });
+            uniform_paths &&
+            starts_with_non_keyword;
         if emit_uniform_paths_canary {
-            // Relative paths should only get here if the feature-gate is on.
-            assert!(self.session.rust_2018() &&
-                    self.session.features_untracked().uniform_paths);
-
-            let source = module_path[0];
+            let source = prefix_start.unwrap();
 
             // HACK(eddyb) For `use x::{self, ...};`, use the ID of the
             // `self` nested import for the canary. This allows the
@@ -256,6 +273,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         match use_tree.kind {
             ast::UseTreeKind::Simple(rename, ..) => {
                 let mut ident = use_tree.ident();
+                let mut module_path = prefix;
                 let mut source = module_path.pop().unwrap();
                 let mut type_ns_only = false;
 
@@ -354,7 +372,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     max_vis: Cell::new(ty::Visibility::Invisible),
                 };
                 self.add_import_directive(
-                    module_path,
+                    prefix,
                     subclass,
                     use_tree.span,
                     id,
@@ -366,13 +384,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 );
             }
             ast::UseTreeKind::Nested(ref items) => {
-                let prefix = ast::Path {
-                    segments: module_path.into_iter()
-                        .map(|ident| ast::PathSegment::from_ident(ident))
-                        .collect(),
-                    span: path.span,
-                };
-
                 // Ensure there is at most one `self` in the list
                 let self_spans = items.iter().filter_map(|&(ref use_tree, _)| {
                     if let ast::UseTreeKind::Simple(..) = use_tree.kind {
@@ -422,28 +433,13 @@ 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: root.into_iter().collect(),
-                    span: use_tree.span,
-                };
-
                 self.build_reduced_graph_for_use_tree(
                     use_tree,
                     item.id,
                     use_tree,
                     item.id,
                     vis,
-                    &prefix,
+                    &[],
                     false, // uniform_paths_canary_emitted
                     false,
                     item,
diff --git a/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs b/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs
index e44ab838caf..71904acae72 100644
--- a/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs
+++ b/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs
@@ -23,8 +23,7 @@ mod m {
     pub(in crate::m) struct S;
 }
 
-mod n
-{
+mod n {
     use crate::m::f;
     use crate as root;
     pub fn check() {
@@ -34,9 +33,20 @@ mod n
     }
 }
 
+mod p {
+    use {super::f, crate::m::g, self::root::m::h};
+    use crate as root;
+    pub fn check() {
+        assert_eq!(f(), 1);
+        assert_eq!(g(), 2);
+        assert_eq!(h(), 3);
+    }
+}
+
 fn main() {
     assert_eq!(f(), 1);
     assert_eq!(crate::m::g(), 2);
     assert_eq!(root::m::h(), 3);
     n::check();
+    p::check();
 }