about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2017-09-26 23:04:00 +0200
committerPietro Albini <pietro@pietroalbini.org>2017-11-30 13:10:26 +0100
commit91ba8b42fcce0491fa8a1b95e4088bcabf9abf4a (patch)
tree8816e095bc7a534e8d9ecbe542a5e640d35b6c2c /src/libsyntax
parentd6b010f98beae1591ea6e8e21008de97d6cf5be4 (diff)
downloadrust-91ba8b42fcce0491fa8a1b95e4088bcabf9abf4a.tar.gz
rust-91ba8b42fcce0491fa8a1b95e4088bcabf9abf4a.zip
Implement RFC 2128 (use_nested_groups)
This commit adds support for nested groups inside `use` declarations,
such as `use foo::{bar, sub::{baz::Foo, *}};`.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs47
-rw-r--r--src/libsyntax/ext/build.rs41
-rw-r--r--src/libsyntax/feature_gate.rs26
-rw-r--r--src/libsyntax/fold.rs42
-rw-r--r--src/libsyntax/parse/parser.rs143
-rw-r--r--src/libsyntax/print/pprust.rs50
-rw-r--r--src/libsyntax/std_inject.rs16
-rw-r--r--src/libsyntax/test.rs16
-rw-r--r--src/libsyntax/util/node_count.rs4
-rw-r--r--src/libsyntax/visit.rs43
10 files changed, 222 insertions, 206 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ad9d5865120..3c1d6ea18f7 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -12,7 +12,6 @@
 
 pub use self::TyParamBound::*;
 pub use self::UnsafeSource::*;
-pub use self::ViewPath_::*;
 pub use self::PathParameters::*;
 pub use symbol::{Ident, Symbol as Name};
 pub use util::ThinVec;
@@ -1705,46 +1704,20 @@ pub struct Variant_ {
 
 pub type Variant = Spanned<Variant_>;
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct PathListItem_ {
-    pub name: Ident,
-    /// renamed in list, e.g. `use foo::{bar as baz};`
-    pub rename: Option<Ident>,
-    pub id: NodeId,
-}
-
-pub type PathListItem = Spanned<PathListItem_>;
-
-pub type ViewPath = Spanned<ViewPath_>;
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum ViewPath_ {
-
-    /// `foo::bar::baz as quux`
-    ///
-    /// or just
-    ///
-    /// `foo::bar::baz` (with `as baz` implicitly on the right)
-    ViewPathSimple(Ident, Path),
-
-    /// `foo::bar::*`
-    ViewPathGlob(Path),
-
-    /// `foo::bar::{a,b,c}`
-    ViewPathList(Path, Vec<PathListItem>)
+pub enum UseTreeKind {
+    Simple(Ident),
+    Glob,
+    Nested(Vec<(UseTree, NodeId)>),
 }
 
-impl ViewPath_ {
-    pub fn path(&self) -> &Path {
-        match *self {
-            ViewPathSimple(_, ref path) |
-            ViewPathGlob (ref path) |
-            ViewPathList(ref path, _) => path
-        }
-    }
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct UseTree {
+    pub kind: UseTreeKind,
+    pub prefix: Path,
+    pub span: Span,
 }
 
-
 /// Distinguishes between Attributes that decorate items and Attributes that
 /// are contained as statements within items. These two cases need to be
 /// distinguished for pretty-printing.
@@ -1913,7 +1886,7 @@ pub enum ItemKind {
     /// A use declaration (`use` or `pub use`) item.
     ///
     /// E.g. `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`
-    Use(P<ViewPath>),
+    Use(P<UseTree>),
     /// A static item (`static` or `pub static`).
     ///
     /// E.g. `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 48d789372a0..25eef6db930 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -291,7 +291,7 @@ pub trait AstBuilder {
                        -> ast::MetaItem;
 
     fn item_use(&self, sp: Span,
-                vis: ast::Visibility, vp: P<ast::ViewPath>) -> P<ast::Item>;
+                vis: ast::Visibility, vp: P<ast::UseTree>) -> P<ast::Item>;
     fn item_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> P<ast::Item>;
     fn item_use_simple_(&self, sp: Span, vis: ast::Visibility,
                         ident: ast::Ident, path: ast::Path) -> P<ast::Item>;
@@ -1142,7 +1142,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn item_use(&self, sp: Span,
-                vis: ast::Visibility, vp: P<ast::ViewPath>) -> P<ast::Item> {
+                vis: ast::Visibility, vp: P<ast::UseTree>) -> P<ast::Item> {
         P(ast::Item {
             id: ast::DUMMY_NODE_ID,
             ident: keywords::Invalid.ident(),
@@ -1161,33 +1161,36 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
     fn item_use_simple_(&self, sp: Span, vis: ast::Visibility,
                         ident: ast::Ident, path: ast::Path) -> P<ast::Item> {
-        self.item_use(sp, vis,
-                      P(respan(sp,
-                               ast::ViewPathSimple(ident,
-                                                   path))))
+        self.item_use(sp, vis, P(ast::UseTree {
+            span: sp,
+            prefix: path,
+            kind: ast::UseTreeKind::Simple(ident),
+        }))
     }
 
     fn item_use_list(&self, sp: Span, vis: ast::Visibility,
                      path: Vec<ast::Ident>, imports: &[ast::Ident]) -> P<ast::Item> {
         let imports = imports.iter().map(|id| {
-            let item = ast::PathListItem_ {
-                name: *id,
-                rename: None,
-                id: ast::DUMMY_NODE_ID,
-            };
-            respan(sp, item)
+            (ast::UseTree {
+                span: sp,
+                prefix: self.path(sp, vec![*id]),
+                kind: ast::UseTreeKind::Simple(*id),
+            }, ast::DUMMY_NODE_ID)
         }).collect();
 
-        self.item_use(sp, vis,
-                      P(respan(sp,
-                               ast::ViewPathList(self.path(sp, path),
-                                                 imports))))
+        self.item_use(sp, vis, P(ast::UseTree {
+            span: sp,
+            prefix: self.path(sp, path),
+            kind: ast::UseTreeKind::Nested(imports),
+        }))
     }
 
     fn item_use_glob(&self, sp: Span,
                      vis: ast::Visibility, path: Vec<ast::Ident>) -> P<ast::Item> {
-        self.item_use(sp, vis,
-                      P(respan(sp,
-                               ast::ViewPathGlob(self.path(sp, path)))))
+        self.item_use(sp, vis, P(ast::UseTree {
+            span: sp,
+            prefix: self.path(sp, path),
+            kind: ast::UseTreeKind::Glob,
+        }))
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 89d1a3699e8..8507c9653db 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -428,6 +428,9 @@ declare_features! (
 
     // In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
     (active, in_band_lifetimes, "1.23.0", Some(44524)),
+
+    // Nested groups in `use` (RFC 2128)
+    (active, use_nested_groups, "1.23.0", Some(44494)),
 );
 
 declare_features! (
@@ -1661,6 +1664,29 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_path(self, path);
     }
 
+    fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, nested: bool) {
+        if nested {
+            match use_tree.kind {
+                ast::UseTreeKind::Simple(_) => {
+                    if use_tree.prefix.segments.len() != 1 {
+                        gate_feature_post!(&self, use_nested_groups, use_tree.span,
+                                           "paths in `use` groups are experimental");
+                    }
+                }
+                ast::UseTreeKind::Glob => {
+                    gate_feature_post!(&self, use_nested_groups, use_tree.span,
+                                       "glob imports in `use` groups are experimental");
+                }
+                ast::UseTreeKind::Nested(_) => {
+                    gate_feature_post!(&self, use_nested_groups, use_tree.span,
+                                       "nested groups in `use` are experimental");
+                }
+            }
+        }
+
+        visit::walk_use_tree(self, use_tree, id);
+    }
+
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
         if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
             gate_feature_post!(&self, crate_visibility_modifier, span,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index cc63bffec48..1a92f057e5e 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -56,8 +56,8 @@ pub trait Folder : Sized {
         noop_fold_meta_item(meta_item, self)
     }
 
-    fn fold_view_path(&mut self, view_path: P<ViewPath>) -> P<ViewPath> {
-        noop_fold_view_path(view_path, self)
+    fn fold_use_tree(&mut self, use_tree: UseTree) -> UseTree {
+        noop_fold_use_tree(use_tree, self)
     }
 
     fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem {
@@ -310,30 +310,18 @@ pub fn noop_fold_meta_items<T: Folder>(meta_items: Vec<MetaItem>, fld: &mut T) -
     meta_items.move_map(|x| fld.fold_meta_item(x))
 }
 
-pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<ViewPath> {
-    view_path.map(|Spanned {node, span}| Spanned {
-        node: match node {
-            ViewPathSimple(ident, path) => {
-                ViewPathSimple(fld.fold_ident(ident), fld.fold_path(path))
-            }
-            ViewPathGlob(path) => {
-                ViewPathGlob(fld.fold_path(path))
-            }
-            ViewPathList(path, path_list_idents) => {
-                let path = fld.fold_path(path);
-                let path_list_idents = path_list_idents.move_map(|path_list_ident| Spanned {
-                    node: PathListItem_ {
-                        id: fld.new_id(path_list_ident.node.id),
-                        rename: path_list_ident.node.rename.map(|ident| fld.fold_ident(ident)),
-                        name: fld.fold_ident(path_list_ident.node.name),
-                    },
-                    span: fld.new_span(path_list_ident.span)
-                });
-                ViewPathList(path, path_list_idents)
-            }
+pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree {
+    UseTree {
+        span: fld.new_span(use_tree.span),
+        prefix: fld.fold_path(use_tree.prefix),
+        kind: match use_tree.kind {
+            UseTreeKind::Simple(ident) => UseTreeKind::Simple(fld.fold_ident(ident)),
+            UseTreeKind::Glob => UseTreeKind::Glob,
+            UseTreeKind::Nested(items) => UseTreeKind::Nested(items.move_map(|(tree, id)| {
+                (fld.fold_use_tree(tree), fld.new_id(id))
+            })),
         },
-        span: fld.new_span(span)
-    })
+    }
 }
 
 pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
@@ -874,8 +862,8 @@ pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
 pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
     match i {
         ItemKind::ExternCrate(string) => ItemKind::ExternCrate(string),
-        ItemKind::Use(view_path) => {
-            ItemKind::Use(folder.fold_view_path(view_path))
+        ItemKind::Use(use_tree) => {
+            ItemKind::Use(use_tree.map(|tree| folder.fold_use_tree(tree)))
         }
         ItemKind::Static(t, m, e) => {
             ItemKind::Static(folder.fold_ty(t), m, folder.fold_expr(e))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0f32d588b37..07956ecb5af 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -35,8 +35,8 @@ use ast::StrStyle;
 use ast::SelfKind;
 use ast::{TraitItem, TraitRef, TraitObjectSyntax};
 use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
-use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause, CrateSugar};
+use ast::{UseTree, UseTreeKind};
 use ast::{BinOpKind, UnOp};
 use ast::{RangeEnd, RangeSyntax};
 use {ast, attr};
@@ -1861,7 +1861,7 @@ impl<'a> Parser<'a> {
         loop {
             segments.push(self.parse_path_segment(style, enable_warning)?);
 
-            if self.is_import_coupler() || !self.eat(&token::ModSep) {
+            if self.is_import_coupler(false) || !self.eat(&token::ModSep) {
                 return Ok(());
             }
         }
@@ -5964,7 +5964,7 @@ impl<'a> Parser<'a> {
 
         if self.eat_keyword(keywords::Use) {
             // USE ITEM
-            let item_ = ItemKind::Use(self.parse_view_path()?);
+            let item_ = ItemKind::Use(P(self.parse_use_tree(false)?));
             self.expect(&token::Semi)?;
 
             let prev_span = self.prev_span;
@@ -6407,74 +6407,101 @@ impl<'a> Parser<'a> {
         }))
     }
 
-    fn parse_path_list_items(&mut self) -> PResult<'a, Vec<ast::PathListItem>> {
-        self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
-                                 &token::CloseDelim(token::Brace),
-                                 SeqSep::trailing_allowed(token::Comma), |this| {
-            let lo = this.span;
-            let ident = if this.eat_keyword(keywords::SelfValue) {
-                keywords::SelfValue.ident()
-            } else {
-                this.parse_ident()?
-            };
-            let rename = this.parse_rename()?;
-            let node = ast::PathListItem_ {
-                name: ident,
-                rename,
-                id: ast::DUMMY_NODE_ID
-            };
-            Ok(respan(lo.to(this.prev_span), node))
-        })
+    /// `{` or `::{` or `*` or `::*`
+    /// `::{` or `::*` (also `{`  or `*` if unprefixed is true)
+    fn is_import_coupler(&mut self, unprefixed: bool) -> bool {
+        self.is_import_coupler_inner(&token::OpenDelim(token::Brace), unprefixed) ||
+            self.is_import_coupler_inner(&token::BinOp(token::Star), unprefixed)
     }
 
-    /// `::{` or `::*`
-    fn is_import_coupler(&mut self) -> bool {
-        self.check(&token::ModSep) &&
-            self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) ||
-                                   *t == token::BinOp(token::Star))
+    fn is_import_coupler_inner(&mut self, token: &token::Token, unprefixed: bool) -> bool {
+        if self.check(&token::ModSep) {
+            self.look_ahead(1, |t| t == token)
+        } else if unprefixed {
+            self.check(token)
+        } else {
+            false
+        }
     }
 
-    /// Matches ViewPath:
-    /// MOD_SEP? non_global_path
-    /// MOD_SEP? non_global_path as IDENT
-    /// MOD_SEP? non_global_path MOD_SEP STAR
-    /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE
-    /// MOD_SEP? LBRACE item_seq RBRACE
-    fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
+    /// Parse UseTree
+    ///
+    /// USE_TREE = `*` |
+    ///            `{` USE_TREE_LIST `}` |
+    ///            PATH `::` `*` |
+    ///            PATH `::` `{` USE_TREE_LIST `}` |
+    ///            PATH [`as` IDENT]
+    fn parse_use_tree(&mut self, nested: bool) -> PResult<'a, UseTree> {
         let lo = self.span;
-        if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
-           self.is_import_coupler() {
-            // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
-            self.eat(&token::ModSep);
-            let prefix = ast::Path {
-                segments: vec![PathSegment::crate_root(lo)],
-                span: lo.to(self.span),
-            };
-            let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
-                ViewPathGlob(prefix)
+
+        let mut prefix = ast::Path {
+            segments: vec![],
+            span: lo.to(self.span),
+        };
+
+        let kind = if self.is_import_coupler(true) {
+            // `use *;` or `use ::*;` or `use {...};` `use ::{...};`
+
+            // Remove the first `::`
+            if self.eat(&token::ModSep) {
+                prefix.segments.push(PathSegment::crate_root(self.prev_span));
+            } else if !nested {
+                prefix.segments.push(PathSegment::crate_root(self.span));
+            }
+
+            if self.eat(&token::BinOp(token::Star)) {
+                // `use *;`
+                UseTreeKind::Glob
+            } else if self.check(&token::OpenDelim(token::Brace)) {
+                // `use {...};`
+                UseTreeKind::Nested(self.parse_use_tree_list()?)
             } else {
-                ViewPathList(prefix, self.parse_path_list_items()?)
-            };
-            Ok(P(respan(lo.to(self.span), view_path_kind)))
+                return self.unexpected();
+            }
         } else {
-            let prefix = self.parse_path(PathStyle::Mod)?.default_to_global();
-            if self.is_import_coupler() {
-                // `foo::bar::{a, b}` or `foo::bar::*`
-                self.bump();
-                if self.check(&token::BinOp(token::Star)) {
-                    self.bump();
-                    Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix))))
+            // `use path::...;`
+            let mut parsed = self.parse_path(PathStyle::Mod)?;
+            if !nested {
+                parsed = parsed.default_to_global();
+            }
+
+            prefix.segments.append(&mut parsed.segments);
+            prefix.span = prefix.span.to(parsed.span);
+
+            if self.eat(&token::ModSep) {
+                if self.eat(&token::BinOp(token::Star)) {
+                    // `use path::*;`
+                    UseTreeKind::Glob
+                } else if self.check(&token::OpenDelim(token::Brace)) {
+                    // `use path::{...};`
+                    UseTreeKind::Nested(self.parse_use_tree_list()?)
                 } else {
-                    let items = self.parse_path_list_items()?;
-                    Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items))))
+                    return self.unexpected();
                 }
             } else {
-                // `foo::bar` or `foo::bar as baz`
+                // `use path::foo;` or `use path::foo as bar;`
                 let rename = self.parse_rename()?.
                                   unwrap_or(prefix.segments.last().unwrap().identifier);
-                Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix))))
+                UseTreeKind::Simple(rename)
             }
-        }
+        };
+
+        Ok(UseTree {
+            span: lo.to(self.prev_span),
+            kind,
+            prefix,
+        })
+    }
+
+    /// Parse UseTreeKind::Nested(list)
+    ///
+    /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
+    fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
+        self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
+                                 &token::CloseDelim(token::Brace),
+                                 SeqSep::trailing_allowed(token::Comma), |this| {
+            Ok((this.parse_use_tree(true)?, ast::DUMMY_NODE_ID))
+        })
     }
 
     fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 38627b40544..a2d3ed4deb6 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1185,9 +1185,9 @@ impl<'a> State<'a> {
                 self.end()?; // end inner head-block
                 self.end()?; // end outer head-block
             }
-            ast::ItemKind::Use(ref vp) => {
+            ast::ItemKind::Use(ref tree) => {
                 self.head(&visibility_qualified(&item.vis, "use"))?;
-                self.print_view_path(vp)?;
+                self.print_use_tree(tree)?;
                 self.s.word(";")?;
                 self.end()?; // end inner head-block
                 self.end()?; // end outer head-block
@@ -2918,45 +2918,39 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
-        match vp.node {
-            ast::ViewPathSimple(ident, ref path) => {
-                self.print_path(path, false, 0, true)?;
+    pub fn print_use_tree(&mut self, tree: &ast::UseTree) -> io::Result<()> {
+        match tree.kind {
+            ast::UseTreeKind::Simple(ref ident) => {
+                self.print_path(&tree.prefix, false, 0, true)?;
 
-                if path.segments.last().unwrap().identifier.name !=
-                        ident.name {
+                if tree.prefix.segments.last().unwrap().identifier.name != ident.name {
                     self.s.space()?;
                     self.word_space("as")?;
-                    self.print_ident(ident)?;
+                    self.print_ident(*ident)?;
                 }
-
-                Ok(())
             }
-
-            ast::ViewPathGlob(ref path) => {
-                self.print_path(path, false, 0, true)?;
-                self.s.word("::*")
+            ast::UseTreeKind::Glob => {
+                if !tree.prefix.segments.is_empty() {
+                    self.print_path(&tree.prefix, false, 0, true)?;
+                    self.s.word("::")?;
+                }
+                self.s.word("*")?;
             }
-
-            ast::ViewPathList(ref path, ref idents) => {
-                if path.segments.is_empty() {
+            ast::UseTreeKind::Nested(ref items) => {
+                if tree.prefix.segments.is_empty() {
                     self.s.word("{")?;
                 } else {
-                    self.print_path(path, false, 0, true)?;
+                    self.print_path(&tree.prefix, false, 0, true)?;
                     self.s.word("::{")?;
                 }
-                self.commasep(Inconsistent, &idents[..], |s, w| {
-                    s.print_ident(w.node.name)?;
-                    if let Some(ident) = w.node.rename {
-                        s.s.space()?;
-                        s.word_space("as")?;
-                        s.print_ident(ident)?;
-                    }
-                    Ok(())
+                self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
+                    this.print_use_tree(tree)
                 })?;
-                self.s.word("}")
+                self.s.word("}")?;
             }
         }
+
+        Ok(())
     }
 
     pub fn print_mutability(&mut self,
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 7aa94de9d3d..ae22230198f 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -13,7 +13,7 @@ use attr;
 use ext::hygiene::{Mark, SyntaxContext};
 use symbol::{Symbol, keywords};
 use syntax_pos::{DUMMY_SP, Span};
-use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
+use codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
 use ptr::P;
 use tokenstream::TokenStream;
 
@@ -75,12 +75,16 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<Strin
             span,
         }],
         vis: ast::Visibility::Inherited,
-        node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path {
-            segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| {
-                ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP)
-            }).collect(),
+        node: ast::ItemKind::Use(P(ast::UseTree {
+            prefix: ast::Path {
+                segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| {
+                    ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP)
+                }).collect(),
+                span,
+            },
+            kind: ast::UseTreeKind::Glob,
             span,
-        })))),
+        })),
         id: ast::DUMMY_NODE_ID,
         ident: keywords::Invalid.ident(),
         span,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 5a5a1ce3777..a4ac5826f99 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -455,9 +455,11 @@ fn mk_std(cx: &TestCtxt) -> P<ast::Item> {
     let id_test = Ident::from_str("test");
     let sp = ignored_span(cx, DUMMY_SP);
     let (vi, vis, ident) = if cx.is_libtest {
-        (ast::ItemKind::Use(
-            P(nospan(ast::ViewPathSimple(id_test,
-                                         path_node(vec![id_test]))))),
+        (ast::ItemKind::Use(P(ast::UseTree {
+            span: DUMMY_SP,
+            prefix: path_node(vec![id_test]),
+            kind: ast::UseTreeKind::Simple(id_test),
+        })),
          ast::Visibility::Public, keywords::Invalid.ident())
     } else {
         (ast::ItemKind::ExternCrate(None), ast::Visibility::Inherited, id_test)
@@ -547,9 +549,11 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
         // building `use <ident> = __test::main`
         let reexport_ident = Ident::with_empty_ctxt(s);
 
-        let use_path =
-            nospan(ast::ViewPathSimple(reexport_ident,
-                                       path_node(vec![mod_ident, Ident::from_str("main")])));
+        let use_path = ast::UseTree {
+            span: DUMMY_SP,
+            prefix: path_node(vec![mod_ident, Ident::from_str("main")]),
+            kind: ast::UseTreeKind::Simple(reexport_ident),
+        };
 
         expander.fold_item(P(ast::Item {
             id: ast::DUMMY_NODE_ID,
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index 0a5d0c2e7fe..ac5642e53cf 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -133,9 +133,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_path(self, path)
     }
-    fn visit_path_list_item(&mut self, prefix: &Path, item: &PathListItem) {
+    fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) {
         self.count += 1;
-        walk_path_list_item(self, prefix, item)
+        walk_use_tree(self, use_tree, id)
     }
     fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &PathParameters) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index c2e90f0bb13..9a06ed0ba02 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -120,8 +120,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_path(&mut self, path: &'ast Path, _id: NodeId) {
         walk_path(self, path)
     }
-    fn visit_path_list_item(&mut self, prefix: &'ast Path, item: &'ast PathListItem) {
-        walk_path_list_item(self, prefix, item)
+    fn visit_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId, _nested: bool) {
+        walk_use_tree(self, use_tree, id)
     }
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
         walk_path_segment(self, path_span, path_segment)
@@ -236,22 +236,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         ItemKind::ExternCrate(opt_name) => {
             walk_opt_name(visitor, item.span, opt_name)
         }
-        ItemKind::Use(ref vp) => {
-            match vp.node {
-                ViewPathSimple(ident, ref path) => {
-                    visitor.visit_ident(vp.span, ident);
-                    visitor.visit_path(path, item.id);
-                }
-                ViewPathGlob(ref path) => {
-                    visitor.visit_path(path, item.id);
-                }
-                ViewPathList(ref prefix, ref list) => {
-                    visitor.visit_path(prefix, item.id);
-                    for item in list {
-                        visitor.visit_path_list_item(prefix, item)
-                    }
-                }
-            }
+        ItemKind::Use(ref use_tree) => {
+            visitor.visit_use_tree(use_tree, item.id, false)
         }
         ItemKind::Static(ref typ, _, ref expr) |
         ItemKind::Const(ref typ, ref expr) => {
@@ -381,11 +367,22 @@ pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
     }
 }
 
-pub fn walk_path_list_item<'a, V: Visitor<'a>>(visitor: &mut V,
-                                               _prefix: &Path,
-                                               item: &'a PathListItem) {
-    visitor.visit_ident(item.span, item.node.name);
-    walk_opt_ident(visitor, item.span, item.node.rename);
+pub fn walk_use_tree<'a, V: Visitor<'a>>(
+    visitor: &mut V, use_tree: &'a UseTree, id: NodeId,
+) {
+    visitor.visit_path(&use_tree.prefix, id);
+
+    match use_tree.kind {
+        UseTreeKind::Simple(ident) => {
+            visitor.visit_ident(use_tree.span, ident);
+        }
+        UseTreeKind::Glob => {},
+        UseTreeKind::Nested(ref use_trees) => {
+            for &(ref nested_tree, nested_id) in use_trees {
+                visitor.visit_use_tree(nested_tree, nested_id, true);
+            }
+        }
+    }
 }
 
 pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V,