From cfcd449c4c36c68541c3389878e3262dac5e4746 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Fri, 31 Jul 2015 22:20:25 -0700 Subject: [PATCH] rustc: rename multiple imports in a list --- src/grammar/parser-lalr.y | 1 + src/librustc_privacy/lib.rs | 4 +-- src/librustc_resolve/build_reduced_graph.rs | 13 +++++----- src/librustdoc/clean/mod.rs | 9 ++++--- src/librustdoc/html/format.rs | 9 +++++-- src/libsyntax/ast.rs | 21 +++++++++++++--- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/fold.rs | 10 +++++--- src/libsyntax/parse/parser.rs | 20 ++++++++++----- src/libsyntax/print/pprust.rs | 20 ++++++++++++--- src/libsyntax/visit.rs | 11 ++++++-- src/test/compile-fail/unresolved-import.rs | 16 +++++++++++- src/test/pretty/import-renames.rs | 14 +++++++++++ src/test/run-pass/import-rename.rs | 21 ++++++++++++++++ src/test/run-pass/use.rs | 3 +++ src/test/rustdoc/viewpath-rename.rs | 28 +++++++++++++++++++++ 16 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 src/test/pretty/import-renames.rs create mode 100644 src/test/run-pass/import-rename.rs create mode 100644 src/test/rustdoc/viewpath-rename.rs diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 1117f4d5ce81c..abdef4aa5ac89 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -472,6 +472,7 @@ visibility idents_or_self : ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } +| ident_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } | idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } ; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 2ffb4cbd4bfb0..d49c5c5517b05 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -862,11 +862,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { if let ast::ViewPathList(ref prefix, ref list) = vpath.node { for pid in list { match pid.node { - ast::PathListIdent { id, name } => { + ast::PathListIdent { id, name, .. } => { debug!("privacy - ident item {}", id); self.check_path(pid.span, id, name.name); } - ast::PathListMod { id } => { + ast::PathListMod { id, .. } => { debug!("privacy - mod item {}", id); let name = prefix.segments.last().unwrap().identifier.name; self.check_path(pid.span, id, name); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 656d6a3661470..66177d3df91a6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -341,10 +341,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } for source_item in source_items { - let (module_path, name) = match source_item.node { - PathListIdent { name, .. } => - (module_path.clone(), name.name), - PathListMod { .. } => { + let (module_path, name, rename) = match source_item.node { + PathListIdent { name, rename, .. } => + (module_path.clone(), name.name, rename.unwrap_or(name).name), + PathListMod { rename, .. } => { let name = match module_path.last() { Some(name) => *name, None => { @@ -358,13 +358,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } }; let module_path = module_path.split_last().unwrap().1; - (module_path.to_vec(), name) + let rename = rename.map(|n| n.name).unwrap_or(name); + (module_path.to_vec(), name, rename) } }; self.build_import_directive( &**parent, module_path, - SingleImport(name, name), + SingleImport(rename, name), source_item.span, source_item.node.id(), is_public, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 11a0e0eaa496e..6431e688c8a17 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2362,7 +2362,7 @@ impl Clean> for doctree::Import { let remaining = if !denied { let mut remaining = vec![]; for path in list { - match inline::try_inline(cx, path.node.id(), None) { + match inline::try_inline(cx, path.node.id(), path.node.rename()) { Some(items) => { ret.extend(items); } @@ -2424,18 +2424,21 @@ pub struct ImportSource { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ViewListIdent { pub name: String, + pub rename: Option, pub source: Option, } impl Clean for ast::PathListItem { fn clean(&self, cx: &DocContext) -> ViewListIdent { match self.node { - ast::PathListIdent { id, name } => ViewListIdent { + ast::PathListIdent { id, name, rename } => ViewListIdent { name: name.clean(cx), + rename: rename.map(|r| r.clean(cx)), source: resolve_def(cx, id) }, - ast::PathListMod { id } => ViewListIdent { + ast::PathListMod { id, rename } => ViewListIdent { name: "self".to_string(), + rename: rename.map(|r| r.clean(cx)), source: resolve_def(cx, id) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2255a2e969f1a..7d86a547e94e9 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -687,10 +687,15 @@ impl fmt::Display for clean::ViewListIdent { match self.source { Some(did) => { let path = clean::Path::singleton(self.name.clone()); - resolved_path(f, did, &path, false) + try!(resolved_path(f, did, &path, false)); } - _ => write!(f, "{}", self.name), + _ => try!(write!(f, "{}", self.name)), + } + + if let Some(ref name) = self.rename { + try!(write!(f, " as {}", name)); } + Ok(()) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index db173d0830815..555a249e3686e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1656,14 +1656,29 @@ pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum PathListItem_ { - PathListIdent { name: Ident, id: NodeId }, - PathListMod { id: NodeId } + PathListIdent { + name: Ident, + /// renamed in list, eg `use foo::{bar as baz};` + rename: Option, + id: NodeId + }, + PathListMod { + /// renamed in list, eg `use foo::{self as baz};` + rename: Option, + id: NodeId + } } impl PathListItem_ { pub fn id(&self) -> NodeId { match *self { - PathListIdent { id, .. } | PathListMod { id } => id + PathListIdent { id, .. } | PathListMod { id, .. } => id + } + } + + pub fn rename(&self) -> Option { + match *self { + PathListIdent { rename, .. } | PathListMod { rename, .. } => rename } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2061165abd224..771ac85ef1921 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1141,7 +1141,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn item_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec, imports: &[ast::Ident]) -> P { let imports = imports.iter().map(|id| { - respan(sp, ast::PathListIdent { name: *id, id: ast::DUMMY_NODE_ID }) + respan(sp, ast::PathListIdent { name: *id, rename: None, id: ast::DUMMY_NODE_ID }) }).collect(); self.item_use(sp, vis, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index dab6d41df3003..418a2cf5a879c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -335,13 +335,17 @@ pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P< path_list_idents.move_map(|path_list_ident| { Spanned { node: match path_list_ident.node { - PathListIdent { id, name } => + PathListIdent { id, name, rename } => PathListIdent { id: fld.new_id(id), + rename: rename, name: name }, - PathListMod { id } => - PathListMod { id: fld.new_id(id) } + PathListMod { id, rename } => + PathListMod { + id: fld.new_id(id), + rename: rename + } }, span: fld.new_span(path_list_ident.span) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e7ab9a73c0ffd..981d6e1055a52 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -573,10 +573,12 @@ impl<'a> Parser<'a> { pub fn parse_path_list_item(&mut self) -> PResult { let lo = self.span.lo; let node = if try!(self.eat_keyword(keywords::SelfValue)) { - ast::PathListMod { id: ast::DUMMY_NODE_ID } + let rename = try!(self.parse_rename()); + ast::PathListMod { id: ast::DUMMY_NODE_ID, rename: rename } } else { let ident = try!(self.parse_ident()); - ast::PathListIdent { name: ident, id: ast::DUMMY_NODE_ID } + let rename = try!(self.parse_rename()); + ast::PathListIdent { name: ident, rename: rename, id: ast::DUMMY_NODE_ID } }; let hi = self.last_span.hi; Ok(spanned(lo, hi, node)) @@ -5104,8 +5106,8 @@ impl<'a> Parser<'a> { -> PResult> { let crate_name = try!(self.parse_ident()); - let (maybe_path, ident) = if try!(self.eat_keyword(keywords::As)) { - (Some(crate_name.name), try!(self.parse_ident())) + let (maybe_path, ident) = if let Some(ident) = try!(self.parse_rename()) { + (Some(crate_name.name), ident) } else { (None, crate_name) }; @@ -5766,10 +5768,16 @@ impl<'a> Parser<'a> { } }).collect() }; + rename_to = try!(self.parse_rename()).unwrap_or(rename_to); + Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))) + } + + fn parse_rename(&mut self) -> PResult> { if try!(self.eat_keyword(keywords::As)) { - rename_to = try!(self.parse_ident()) + self.parse_ident().map(Some) + } else { + Ok(None) } - Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))) } /// Parses a source module as a crate. This is the main diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f0973e0ba6e03..1de922a0428f5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2643,11 +2643,23 @@ impl<'a> State<'a> { } try!(self.commasep(Inconsistent, &idents[..], |s, w| { match w.node { - ast::PathListIdent { name, .. } => { - s.print_ident(name) + ast::PathListIdent { name, rename, .. } => { + try!(s.print_ident(name)); + if let Some(ident) = rename { + try!(space(&mut s.s)); + try!(s.word_space("as")); + try!(s.print_ident(ident)); + } + Ok(()) }, - ast::PathListMod { .. } => { - word(&mut s.s, "self") + ast::PathListMod { rename, .. } => { + try!(word(&mut s.s, "self")); + if let Some(ident) = rename { + try!(space(&mut s.s)); + try!(s.word_space("as")); + try!(s.print_ident(ident)); + } + Ok(()) } } })); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 649052d123c88..27d95cbcf5ba3 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -233,10 +233,17 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { ViewPathList(ref prefix, ref list) => { for id in list { match id.node { - PathListIdent { name, .. } => { + PathListIdent { name, rename, .. } => { visitor.visit_ident(id.span, name); + if let Some(ident) = rename { + visitor.visit_ident(id.span, ident); + } + } + PathListMod { rename, .. } => { + if let Some(ident) = rename { + visitor.visit_ident(id.span, ident); + } } - PathListMod { .. } => () } } diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index 7da7b364bda36..5edcf1d99a02b 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,6 +12,20 @@ use foo::bar; //~ ERROR unresolved import `foo::bar`. Maybe a missing `extern cr use bar::baz as x; //~ ERROR unresolved import `bar::baz`. There is no `baz` in `bar` +use food::baz; //~ ERROR unresolved import `food::baz`. There is no `baz` in `food` + +use food::{quux as beans}; //~ ERROR unresolved import `food::quux`. There is no `quux` in `food` + mod bar { struct bar; } + +mod food { + pub use self::zug::baz::{self as bag, quux as beans}; + + mod zug { + pub mod baz { + pub struct quux; + } + } +} diff --git a/src/test/pretty/import-renames.rs b/src/test/pretty/import-renames.rs new file mode 100644 index 0000000000000..47a878711ba20 --- /dev/null +++ b/src/test/pretty/import-renames.rs @@ -0,0 +1,14 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pp-exact + +use std::io::{self, Error as IoError}; +use std::net::{self as stdnet, TcpStream}; diff --git a/src/test/run-pass/import-rename.rs b/src/test/run-pass/import-rename.rs new file mode 100644 index 0000000000000..f293c284f946f --- /dev/null +++ b/src/test/run-pass/import-rename.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use foo::{x, y as fooy}; +use Maybe::{Yes as MaybeYes}; + +pub enum Maybe { Yes, No } +mod foo { + use super::Maybe::{self as MaybeFoo}; + pub fn x(a: MaybeFoo) {} + pub fn y(a: i32) { println!("{}", a); } +} + +pub fn main() { x(MaybeYes); fooy(10); } diff --git a/src/test/run-pass/use.rs b/src/test/run-pass/use.rs index 592d17922e1a6..09a3849b9153b 100644 --- a/src/test/run-pass/use.rs +++ b/src/test/run-pass/use.rs @@ -19,6 +19,9 @@ extern crate std as zed; use std::str; use zed::str as x; + +use std::io::{self, Error as IoError, Result as IoResult}; +use std::error::{self as foo}; mod baz { pub use std::str as x; } diff --git a/src/test/rustdoc/viewpath-rename.rs b/src/test/rustdoc/viewpath-rename.rs new file mode 100644 index 0000000000000..ccc0acab7f379 --- /dev/null +++ b/src/test/rustdoc/viewpath-rename.rs @@ -0,0 +1,28 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub mod io { + pub trait Reader { fn dummy(&self) { } } +} + +pub enum Maybe { + Just(A), + Nothing +} + +// @has foo/prelude/index.html +pub mod prelude { + // @has foo/prelude/index.html '//code' 'pub use io::{self as FooIo, Reader as FooReader}' + #[doc(no_inline)] pub use io::{self as FooIo, Reader as FooReader}; + // @has foo/prelude/index.html '//code' 'pub use Maybe::{self, Just as MaybeJust, Nothing}' + #[doc(no_inline)] pub use Maybe::{self, Just as MaybeJust, Nothing}; +}