From c6c6cf9515b330551b04f36025bc72e1288a96d9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 9 Mar 2018 18:51:48 +0300 Subject: [PATCH 1/6] AST/HIR: Clarify what the optional name in extern crate items mean --- src/librustc/hir/intravisit.rs | 6 +++--- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/mod.rs | 4 ++-- src/librustc/hir/print.rs | 11 +++-------- src/librustc/ich/impls_hir.rs | 2 +- src/librustc/session/config.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_metadata/creader.rs | 16 +++++++++------- src/librustc_resolve/build_reduced_graph.rs | 4 ++-- src/librustdoc/visit_ast.rs | 4 ++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 20 +++++++------------- src/libsyntax/print/pprust.rs | 11 +++-------- src/libsyntax/std_inject.rs | 6 ++---- src/libsyntax/visit.rs | 6 +++--- 16 files changed, 42 insertions(+), 58 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b804cf7bf5a..972278bdf86 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -444,10 +444,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_vis(&item.vis); visitor.visit_name(item.span, item.name); match item.node { - ItemExternCrate(opt_name) => { + ItemExternCrate(orig_name) => { visitor.visit_id(item.id); - if let Some(name) = opt_name { - visitor.visit_name(item.span, name); + if let Some(orig_name) = orig_name { + visitor.visit_name(item.span, orig_name); } } ItemUse(ref path, _) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 49611689fc4..41950d21c09 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1904,7 +1904,7 @@ impl<'a> LoweringContext<'a> { i: &ItemKind) -> hir::Item_ { match *i { - ItemKind::ExternCrate(string) => hir::ItemExternCrate(string), + ItemKind::ExternCrate(orig_name) => hir::ItemExternCrate(orig_name), ItemKind::Use(ref use_tree) => { // Start with an empty prefix let prefix = Path { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f4638c23c5f..46c79d03149 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2011,9 +2011,9 @@ pub struct Item { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Item_ { - /// An `extern crate` item, with optional original crate name, + /// An `extern crate` item, with optional *original* crate name if the crate was renamed. /// - /// e.g. `extern crate foo` or `extern crate foo_bar as foo` + /// E.g. `extern crate foo` or `extern crate foo_bar as foo` ItemExternCrate(Option), /// `use foo::bar::*;` or `use foo::bar::baz as quux;` diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 9e755f366a7..3d38c0c8ed9 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -524,15 +524,10 @@ impl<'a> State<'a> { self.print_outer_attributes(&item.attrs)?; self.ann.pre(self, NodeItem(item))?; match item.node { - hir::ItemExternCrate(ref optional_path) => { + hir::ItemExternCrate(orig_name) => { self.head(&visibility_qualified(&item.vis, "extern crate"))?; - if let Some(p) = *optional_path { - let val = p.as_str(); - if val.contains("-") { - self.print_string(&val, ast::StrStyle::Cooked)?; - } else { - self.print_name(p)?; - } + if let Some(orig_name) = orig_name { + self.print_name(orig_name)?; self.s.space()?; self.s.word("as")?; self.s.space()?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index c085b803085..e764cedd658 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -851,7 +851,7 @@ impl<'a> HashStable> for hir::Item { } impl_stable_hash_for!(enum hir::Item_ { - ItemExternCrate(name), + ItemExternCrate(orig_name), ItemUse(path, use_kind), ItemStatic(ty, mutability, body_id), ItemConst(ty, body_id), diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2cf09a002c9..0d91074e946 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -385,7 +385,7 @@ top_level_options!( externs: Externs [UNTRACKED], crate_name: Option [TRACKED], // An optional name to use as the crate for std during std injection, - // written `extern crate std = "name"`. Default to "std". Used by + // written `extern crate name as std`. Defaults to `std`. Used by // out-of-tree drivers. alt_std_name: Option [TRACKED], // Indicates how the compiler should treat unstable features diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b5e31bdf668..710fef8db40 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -683,7 +683,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, }); krate = time(sess, "crate injection", || { - let alt_std_name = sess.opts.alt_std_name.clone(); + let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 789ecd0f613..ee372c0bc5d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1052,12 +1052,14 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { match item.node { - ast::ItemKind::ExternCrate(rename) => { - debug!("resolving extern crate stmt. ident: {} rename: {:?}", item.ident, rename); - let rename = match rename { - Some(rename) => { - validate_crate_name(Some(self.sess), &rename.as_str(), Some(item.span)); - rename + ast::ItemKind::ExternCrate(orig_name) => { + debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", + item.ident, orig_name); + let orig_name = match orig_name { + Some(orig_name) => { + validate_crate_name(Some(self.sess), &orig_name.as_str(), + Some(item.span)); + orig_name } None => item.ident.name, }; @@ -1068,7 +1070,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { }; let (cnum, ..) = self.resolve_crate( - &None, item.ident.name, rename, None, item.span, PathKind::Crate, dep_kind, + &None, item.ident.name, orig_name, None, item.span, PathKind::Crate, dep_kind, ); let def_id = definitions.opt_local_def_id(item.id).unwrap(); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index bf7b81c4d0e..335064402c4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -255,7 +255,7 @@ impl<'a> Resolver<'a> { ); } - ItemKind::ExternCrate(as_name) => { + ItemKind::ExternCrate(orig_name) => { self.crate_loader.process_item(item, &self.definitions); // n.b. we don't need to look at the path option here, because cstore already did @@ -274,7 +274,7 @@ impl<'a> Resolver<'a> { id: item.id, parent, imported_module: Cell::new(Some(module)), - subclass: ImportDirectiveSubclass::ExternCrate(as_name), + subclass: ImportDirectiveSubclass::ExternCrate(orig_name), span: item.span, module_path: Vec::new(), vis: Cell::new(vis), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f692e05d6a2..f45a5b030db 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -406,13 +406,13 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { // If we're inlining, skip private items. _ if self.inlining && item.vis != hir::Public => {} hir::ItemGlobalAsm(..) => {} - hir::ItemExternCrate(ref p) => { + hir::ItemExternCrate(orig_name) => { let def_id = self.cx.tcx.hir.local_def_id(item.id); om.extern_crates.push(ExternCrate { cnum: self.cx.tcx.extern_mod_stmt_cnum(def_id) .unwrap_or(LOCAL_CRATE), name, - path: p.map(|x|x.to_string()), + path: orig_name.map(|x|x.to_string()), vis: item.vis.clone(), attrs: item.attrs.clone(), whence: item.span, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8b3a7164ccc..7ced6424824 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2055,7 +2055,7 @@ pub struct Item { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ItemKind { - /// An `extern crate` item, with optional original crate name. + /// An `extern crate` item, with optional *original* crate name if the crate was renamed. /// /// E.g. `extern crate foo` or `extern crate foo_bar as foo` ExternCrate(Option), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2cf99e15d1f..1a65fb7639a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -886,7 +886,7 @@ pub fn noop_fold_block(b: P, folder: &mut T) -> P { pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { match i { - ItemKind::ExternCrate(string) => ItemKind::ExternCrate(string), + ItemKind::ExternCrate(orig_name) => ItemKind::ExternCrate(orig_name), ItemKind::Use(use_tree) => { ItemKind::Use(use_tree.map(|tree| folder.fold_use_tree(tree))) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a3a6489fe8b..d1234d25764 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6291,23 +6291,17 @@ impl<'a> Parser<'a> { lo: Span, visibility: Visibility, attrs: Vec) - -> PResult<'a, P> { - - let crate_name = self.parse_ident()?; - let (maybe_path, ident) = if let Some(ident) = self.parse_rename()? { - (Some(crate_name.name), ident) + -> PResult<'a, P> { + let orig_name = self.parse_ident()?; + let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { + (rename, Some(orig_name.name)) } else { - (None, crate_name) + (orig_name, None) }; self.expect(&token::Semi)?; - let prev_span = self.prev_span; - - Ok(self.mk_item(lo.to(prev_span), - ident, - ItemKind::ExternCrate(maybe_path), - visibility, - attrs)) + let span = lo.to(self.prev_span); + Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) } /// Parse `extern` for foreign ABIs diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1cf2b7a44bc..097c0fd16d0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1174,15 +1174,10 @@ impl<'a> State<'a> { self.print_outer_attributes(&item.attrs)?; self.ann.pre(self, NodeItem(item))?; match item.node { - ast::ItemKind::ExternCrate(ref optional_path) => { + ast::ItemKind::ExternCrate(orig_name) => { self.head(&visibility_qualified(&item.vis, "extern crate"))?; - if let Some(p) = *optional_path { - let val = p.as_str(); - if val.contains('-') { - self.print_string(&val, ast::StrStyle::Cooked)?; - } else { - self.print_name(p)?; - } + if let Some(orig_name) = orig_name { + self.print_name(orig_name)?; self.s.space()?; self.s.word("as")?; self.s.space()?; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index da24107f4c3..59425929f7e 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -43,7 +43,7 @@ thread_local! { static INJECTED_CRATE_NAME: Cell> = Cell::new(None); } -pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { +pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<&str>) -> ast::Crate { let name = if attr::contains_name(&krate.attrs, "no_core") { return krate; } else if attr::contains_name(&krate.attrs, "no_std") { @@ -54,14 +54,12 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option>(visitor: &mut V, item: &'a Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.span, item.ident); match item.node { - ItemKind::ExternCrate(opt_name) => { - if let Some(name) = opt_name { - visitor.visit_name(item.span, name); + ItemKind::ExternCrate(orig_name) => { + if let Some(orig_name) = orig_name { + visitor.visit_name(item.span, orig_name); } } ItemKind::Use(ref use_tree) => { From b057c554ab9c7615ebdb3c920010a164ec5bf3ed Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 9 Mar 2018 18:58:44 +0300 Subject: [PATCH 2/6] AST: Make renames in imports closer to the source Fix `unused_import_braces` lint false positive on `use prefix::{self as rename}` --- src/librustc/hir/lowering.rs | 6 +++--- src/librustc_lint/unused.rs | 7 ++++--- src/librustc_resolve/build_reduced_graph.rs | 11 ++++++----- src/librustc_save_analysis/dump_visitor.rs | 3 ++- src/libsyntax/ast.rs | 17 ++++++++++++++--- src/libsyntax/ext/build.rs | 11 +++++------ src/libsyntax/fold.rs | 3 ++- src/libsyntax/parse/parser.rs | 4 +--- src/libsyntax/print/pprust.rs | 7 +++---- src/libsyntax/test.rs | 13 +++++++------ src/libsyntax/visit.rs | 7 ++++--- .../lint-unnecessary-import-braces.rs | 4 ++-- 12 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 41950d21c09..1e355bb30cb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2047,8 +2047,8 @@ impl<'a> LoweringContext<'a> { let path = &tree.prefix; match tree.kind { - UseTreeKind::Simple(ident) => { - *name = ident.name; + UseTreeKind::Simple(rename) => { + *name = tree.ident().name; // First apply the prefix to the path let mut path = Path { @@ -2064,7 +2064,7 @@ impl<'a> LoweringContext<'a> { if path.segments.len() > 1 && path.segments.last().unwrap().identifier.name == keywords::SelfValue.name() { let _ = path.segments.pop(); - if ident.name == keywords::SelfValue.name() { + if rename.is_none() { *name = path.segments.last().unwrap().identifier.name; } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d777f6f19b0..86f79c553c3 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -377,11 +377,12 @@ impl UnusedImportBraces { // Trigger the lint if the nested item is a non-self single item let node_ident; match items[0].0.kind { - ast::UseTreeKind::Simple(ident) => { - if ident.name == keywords::SelfValue.name() { + ast::UseTreeKind::Simple(rename) => { + let orig_ident = items[0].0.prefix.segments.last().unwrap().identifier; + if orig_ident.name == keywords::SelfValue.name() { return; } else { - node_ident = ident; + node_ident = rename.unwrap_or(orig_ident); } } ast::UseTreeKind::Glob => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 335064402c4..e6c8dfa8356 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -119,7 +119,8 @@ impl<'a> Resolver<'a> { .collect(); match use_tree.kind { - ast::UseTreeKind::Simple(mut ident) => { + ast::UseTreeKind::Simple(rename) => { + let mut ident = use_tree.ident(); let mut source = module_path.pop().unwrap().node; let mut type_ns_only = false; @@ -142,7 +143,7 @@ impl<'a> Resolver<'a> { // Replace `use foo::self;` with `use foo;` let _ = module_path.pop(); source = last_segment.node; - if ident.name == keywords::SelfValue.name() { + if rename.is_none() { ident = last_segment.node; } } @@ -162,7 +163,7 @@ impl<'a> Resolver<'a> { ModuleKind::Block(..) => unreachable!(), }; source.name = crate_name; - if ident.name == keywords::DollarCrate.name() { + if rename.is_none() { ident.name = crate_name; } @@ -206,8 +207,8 @@ impl<'a> Resolver<'a> { // 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(ident) = use_tree.kind { - if ident.name == keywords::SelfValue.name() { + if let ast::UseTreeKind::Simple(..) = use_tree.kind { + if use_tree.ident().name == keywords::SelfValue.name() { return Some(use_tree.span); } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index d92025a6787..b9b4186c818 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1342,7 +1342,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { .map(::id_from_def_id); match use_tree.kind { - ast::UseTreeKind::Simple(ident) => { + ast::UseTreeKind::Simple(..) => { + let ident = use_tree.ident(); let path = ast::Path { segments: prefix.segments .iter() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7ced6424824..fdb32486b5d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1880,18 +1880,29 @@ pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum UseTreeKind { - Simple(Ident), - Glob, + Simple(Option), Nested(Vec<(UseTree, NodeId)>), + Glob, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct UseTree { - pub kind: UseTreeKind, pub prefix: Path, + pub kind: UseTreeKind, pub span: Span, } +impl UseTree { + pub fn ident(&self) -> Ident { + match self.kind { + UseTreeKind::Simple(Some(rename)) => rename, + UseTreeKind::Simple(None) => + self.prefix.segments.last().expect("empty prefix in a simple import").identifier, + _ => panic!("`UseTree::ident` can only be used on a simple import"), + } + } +} + /// 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. diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index b88e064e7e5..97f784dd617 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -294,7 +294,7 @@ pub trait AstBuilder { vis: ast::Visibility, vp: P) -> P; fn item_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> P; fn item_use_simple_(&self, sp: Span, vis: ast::Visibility, - ident: ast::Ident, path: ast::Path) -> P; + ident: Option, path: ast::Path) -> P; fn item_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec, imports: &[ast::Ident]) -> P; fn item_use_glob(&self, sp: Span, @@ -1159,16 +1159,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> P { - let last = path.segments.last().unwrap().identifier; - self.item_use_simple_(sp, vis, last, path) + self.item_use_simple_(sp, vis, None, path) } fn item_use_simple_(&self, sp: Span, vis: ast::Visibility, - ident: ast::Ident, path: ast::Path) -> P { + rename: Option, path: ast::Path) -> P { self.item_use(sp, vis, P(ast::UseTree { span: sp, prefix: path, - kind: ast::UseTreeKind::Simple(ident), + kind: ast::UseTreeKind::Simple(rename), })) } @@ -1178,7 +1177,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { (ast::UseTree { span: sp, prefix: self.path(sp, vec![*id]), - kind: ast::UseTreeKind::Simple(*id), + kind: ast::UseTreeKind::Simple(None), }, ast::DUMMY_NODE_ID) }).collect(); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a65fb7639a..146f580e04e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -323,7 +323,8 @@ pub fn noop_fold_use_tree(use_tree: UseTree, fld: &mut T) -> 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::Simple(rename) => + UseTreeKind::Simple(rename.map(|ident| 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)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d1234d25764..7a432930490 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7033,9 +7033,7 @@ impl<'a> Parser<'a> { } } else { // `use path::foo;` or `use path::foo as bar;` - let rename = self.parse_rename()?. - unwrap_or(prefix.segments.last().unwrap().identifier); - UseTreeKind::Simple(rename) + UseTreeKind::Simple(self.parse_rename()?) } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 097c0fd16d0..18a758ba968 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2949,13 +2949,12 @@ impl<'a> State<'a> { pub fn print_use_tree(&mut self, tree: &ast::UseTree) -> io::Result<()> { match tree.kind { - ast::UseTreeKind::Simple(ref ident) => { + ast::UseTreeKind::Simple(rename) => { self.print_path(&tree.prefix, false, 0, true)?; - - if tree.prefix.segments.last().unwrap().identifier.name != ident.name { + if let Some(rename) = rename { self.s.space()?; self.word_space("as")?; - self.print_ident(*ident)?; + self.print_ident(rename)?; } } ast::UseTreeKind::Glob => { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 39306229c82..9edfa767d31 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -78,7 +78,7 @@ pub fn modify_for_testing(sess: &ParseSess, span_diagnostic: &errors::Handler, features: &Features) -> ast::Crate { // Check for #[reexport_test_harness_main = "some_name"] which - // creates a `use some_name = __test::main;`. This needs to be + // creates a `use __test::main as some_name;`. This needs to be // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = @@ -240,7 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, cx.ext_cx.path(DUMMY_SP, vec![super_, r])) }).chain(tested_submods.into_iter().map(|(r, sym)| { let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); - cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), r, path) + cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), + Some(r), path) })).collect(); let reexport_mod = ast::Mod { @@ -502,7 +503,7 @@ fn mk_std(cx: &TestCtxt) -> P { (ast::ItemKind::Use(P(ast::UseTree { span: DUMMY_SP, prefix: path_node(vec![id_test]), - kind: ast::UseTreeKind::Simple(id_test), + kind: ast::UseTreeKind::Simple(None), })), ast::VisibilityKind::Public, keywords::Invalid.ident()) } else { @@ -590,13 +591,13 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { tokens: None, })).pop().unwrap(); let reexport = cx.reexport_test_harness_main.map(|s| { - // building `use = __test::main` - let reexport_ident = Ident::with_empty_ctxt(s); + // building `use __test::main as ;` + let rename = Ident::with_empty_ctxt(s); let use_path = ast::UseTree { span: DUMMY_SP, prefix: path_node(vec![mod_ident, Ident::from_str("main")]), - kind: ast::UseTreeKind::Simple(reexport_ident), + kind: ast::UseTreeKind::Simple(Some(rename)), }; expander.fold_item(P(ast::Item { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3bf9bfab245..bbf1fe124f1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -354,10 +354,11 @@ 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::Simple(rename) => { + if let Some(rename) = rename { + visitor.visit_ident(use_tree.span, rename); + } } UseTreeKind::Glob => {}, UseTreeKind::Nested(ref use_trees) => { diff --git a/src/test/compile-fail/lint-unnecessary-import-braces.rs b/src/test/compile-fail/lint-unnecessary-import-braces.rs index 1c0401ec56b..214a03c13f4 100644 --- a/src/test/compile-fail/lint-unnecessary-import-braces.rs +++ b/src/test/compile-fail/lint-unnecessary-import-braces.rs @@ -9,12 +9,12 @@ // except according to those terms. #![deny(unused_import_braces)] -#![allow(dead_code)] -#![allow(unused_imports)] use test::{A}; //~ ERROR braces around A is unnecessary mod test { + use test::{self}; // OK + use test::{self as rename}; // OK pub struct A; } From e5fb13897d947e13a1322a055b71632e30357eff Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 10 Mar 2018 02:02:39 +0300 Subject: [PATCH 3/6] AST: Keep distinction between `path` and `::path` in imports and visibilities Add the root segment for name resolution purposes only --- src/librustc/hir/lowering.rs | 23 ++++------- src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_resolve/lib.rs | 19 +++++---- src/librustc_resolve/resolve_imports.rs | 9 ++--- src/libsyntax/ast.rs | 17 ++++---- src/libsyntax/ext/build.rs | 10 +++-- src/libsyntax/parse/parser.rs | 15 +++---- src/libsyntax/parse/token.rs | 1 + src/libsyntax/print/pprust.rs | 43 +++++++++------------ src/libsyntax/std_inject.rs | 2 +- 10 files changed, 66 insertions(+), 77 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 1e355bb30cb..dd3b9350d91 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1355,17 +1355,11 @@ impl<'a> LoweringContext<'a> { id: NodeId, p: &Path, name: Option, - param_mode: ParamMode, - defaults_to_global: bool) + param_mode: ParamMode) -> hir::Path { - let mut segments = p.segments.iter(); - if defaults_to_global && p.is_global() { - segments.next(); - } - hir::Path { def: self.expect_full_def(id), - segments: segments.map(|segment| { + segments: p.segments.iter().map(|segment| { self.lower_path_segment(p.span, segment, param_mode, 0, ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed) @@ -1378,10 +1372,9 @@ impl<'a> LoweringContext<'a> { fn lower_path(&mut self, id: NodeId, p: &Path, - param_mode: ParamMode, - defaults_to_global: bool) + param_mode: ParamMode) -> hir::Path { - self.lower_path_extra(id, p, None, param_mode, defaults_to_global) + self.lower_path_extra(id, p, None, param_mode) } fn lower_path_segment(&mut self, @@ -2069,7 +2062,7 @@ impl<'a> LoweringContext<'a> { } } - let path = P(self.lower_path(id, &path, ParamMode::Explicit, true)); + let path = P(self.lower_path(id, &path, ParamMode::Explicit)); hir::ItemUse(path, hir::UseKind::Single) } UseTreeKind::Glob => { @@ -2080,7 +2073,7 @@ impl<'a> LoweringContext<'a> { .cloned() .collect(), span: path.span, - }, ParamMode::Explicit, true)); + }, ParamMode::Explicit)); hir::ItemUse(path, hir::UseKind::Glob) } UseTreeKind::Nested(ref trees) => { @@ -2136,7 +2129,7 @@ impl<'a> LoweringContext<'a> { // Privatize the degenerate import base, used only to check // the stability of `use a::{};`, to avoid it showing up as // a re-export by accident when `pub`, e.g. in documentation. - let path = P(self.lower_path(id, &prefix, ParamMode::Explicit, true)); + let path = P(self.lower_path(id, &prefix, ParamMode::Explicit)); *vis = hir::Inherited; hir::ItemUse(path, hir::UseKind::ListStem) } @@ -3379,7 +3372,7 @@ impl<'a> LoweringContext<'a> { VisibilityKind::Crate(..) => hir::Visibility::Crate, VisibilityKind::Restricted { ref path, id, .. } => { hir::Visibility::Restricted { - path: P(self.lower_path(id, path, ParamMode::Explicit, true)), + path: P(self.lower_path(id, path, ParamMode::Explicit)), id: if let Some(owner) = explicit_owner { self.lower_node_id_with_owner(id, owner).node_id } else { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index e6c8dfa8356..c192f349c20 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -245,9 +245,9 @@ impl<'a> Resolver<'a> { match item.node { ItemKind::Use(ref use_tree) => { - // Just an empty prefix to start out + // Imports are resolved as global by default, add starting root segment. let prefix = ast::Path { - segments: vec![], + segments: use_tree.prefix.make_root().into_iter().collect(), span: use_tree.span, }; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c84caee13e8..23ad27ec2c3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2164,8 +2164,9 @@ impl<'a> Resolver<'a> { } ItemKind::Use(ref use_tree) => { + // Imports are resolved as global by default, add starting root segment. let path = Path { - segments: vec![], + segments: use_tree.prefix.make_root().into_iter().collect(), span: use_tree.span, }; self.resolve_use_tree(item.id, use_tree, &path); @@ -2300,7 +2301,6 @@ impl<'a> Resolver<'a> { None, &path, trait_ref.path.span, - trait_ref.path.segments.last().unwrap().span, PathSource::Trait(AliasPossibility::No) ).base_def(); if def != Def::Err { @@ -2731,8 +2731,7 @@ impl<'a> Resolver<'a> { let segments = &path.segments.iter() .map(|seg| respan(seg.span, seg.identifier)) .collect::>(); - let ident_span = path.segments.last().map_or(path.span, |seg| seg.span); - self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source) + self.smart_resolve_path_fragment(id, qself, segments, path.span, source) } fn smart_resolve_path_fragment(&mut self, @@ -2740,9 +2739,9 @@ impl<'a> Resolver<'a> { qself: Option<&QSelf>, path: &[SpannedIdent], span: Span, - ident_span: Span, source: PathSource) -> PathResolution { + let ident_span = path.last().map_or(span, |ident| ident.span); let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; @@ -3090,7 +3089,7 @@ impl<'a> Resolver<'a> { // Make sure `A::B` in `::B::C` is a trait item. let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1], - span, span, PathSource::TraitItem(ns)); + span, PathSource::TraitItem(ns)); return Some(PathResolution::with_unresolved_segments( res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 )); @@ -3941,8 +3940,12 @@ impl<'a> Resolver<'a> { ty::Visibility::Restricted(self.current_module.normal_ancestor_id) } ast::VisibilityKind::Restricted { ref path, id, .. } => { - let def = self.smart_resolve_path(id, None, path, - PathSource::Visibility).base_def(); + // Visibilities are resolved as global by default, add starting root segment. + let segments = path.make_root().iter().chain(path.segments.iter()) + .map(|seg| respan(seg.span, seg.identifier)) + .collect::>(); + let def = self.smart_resolve_path_fragment(id, None, &segments, path.span, + PathSource::Visibility).base_def(); if def == Def::Err { ty::Visibility::Public } else { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 01c1ded9457..4cbebdc3c1c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -667,11 +667,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } PathResult::Failed(span, msg, true) => { let (mut self_path, mut self_result) = (module_path.clone(), None); - if !self_path.is_empty() && - !token::Ident(self_path[0].node).is_path_segment_keyword() && - !(self_path.len() > 1 && - token::Ident(self_path[1].node).is_path_segment_keyword()) - { + let is_special = |ident| token::Ident(ident).is_path_segment_keyword() && + ident.name != keywords::CrateRoot.name(); + if !self_path.is_empty() && !is_special(self_path[0].node) && + !(self_path.len() > 1 && is_special(self_path[1].node)) { self_path[0].node.name = keywords::SelfValue.name(); self_result = Some(self.resolve_path(&self_path, None, false, span)); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fdb32486b5d..4ce6c53d338 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -108,17 +108,16 @@ impl Path { } } - // Add starting "crate root" segment to all paths except those that - // already have it or start with `self`, `super`, `Self` or `$crate`. - pub fn default_to_global(mut self) -> Path { - if !self.is_global() { - let ident = self.segments[0].identifier; - if !::parse::token::Ident(ident).is_path_segment_keyword() || - ident.name == keywords::Crate.name() { - self.segments.insert(0, PathSegment::crate_root(self.span)); + // Make a "crate root" segment for this path unless it already has it + // or starts with something like `self`/`super`/`$crate`/etc. + pub fn make_root(&self) -> Option { + if let Some(ident) = self.segments.get(0).map(|seg| seg.identifier) { + if ::parse::token::Ident(ident).is_path_segment_keyword() && + ident.name != keywords::Crate.name() { + return None; } } - self + Some(PathSegment::crate_root(self.span.with_hi(self.span.lo()))) } pub fn is_global(&self) -> bool { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 97f784dd617..ee646dc9174 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -329,9 +329,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { None }; segments.push(ast::PathSegment { identifier: last_identifier, span, parameters }); - let path = ast::Path { span, segments }; - - if global { path.default_to_global() } else { path } + let mut path = ast::Path { span, segments }; + if global { + if let Some(seg) = path.make_root() { + path.segments.insert(0, seg); + } + } + path } /// Constructs a qualified path. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7a432930490..ca879765b4e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5869,7 +5869,7 @@ impl<'a> Parser<'a> { // `pub(in path)` self.bump(); // `(` self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { path: P(path), @@ -5882,7 +5882,7 @@ impl<'a> Parser<'a> { { // `pub(self)` or `pub(super)` self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { path: P(path), @@ -6480,7 +6480,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Use) { // USE ITEM - let item_ = ItemKind::Use(P(self.parse_use_tree(false)?)); + let item_ = ItemKind::Use(P(self.parse_use_tree()?)); self.expect(&token::Semi)?; let prev_span = self.prev_span; @@ -6984,7 +6984,7 @@ impl<'a> Parser<'a> { /// PATH `::` `*` | /// PATH `::` `{` USE_TREE_LIST `}` | /// PATH [`as` IDENT] - fn parse_use_tree(&mut self, nested: bool) -> PResult<'a, UseTree> { + fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.span; let mut prefix = ast::Path { @@ -6998,8 +6998,6 @@ impl<'a> Parser<'a> { // 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)) { @@ -7014,9 +7012,6 @@ impl<'a> Parser<'a> { } else { // `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); @@ -7051,7 +7046,7 @@ impl<'a> Parser<'a> { 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)) + Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID)) }) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 097a2eb89fd..3c602f1d1a8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -362,6 +362,7 @@ impl Token { id.name == keywords::SelfType.name() || id.name == keywords::Extern.name() || id.name == keywords::Crate.name() || + id.name == keywords::CrateRoot.name() || id.name == keywords::DollarCrate.name(), None => false, } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 18a758ba968..319a9a3bbae 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -353,7 +353,7 @@ pub fn fn_block_to_string(p: &ast::FnDecl) -> String { } pub fn path_to_string(p: &ast::Path) -> String { - to_string(|s| s.print_path(p, false, 0, false)) + to_string(|s| s.print_path(p, false, 0)) } pub fn path_segment_to_string(p: &ast::PathSegment) -> String { @@ -1051,7 +1051,7 @@ impl<'a> State<'a> { &f.generic_params)?; } ast::TyKind::Path(None, ref path) => { - self.print_path(path, false, 0, false)?; + self.print_path(path, false, 0)?; } ast::TyKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false)? @@ -1378,7 +1378,7 @@ impl<'a> State<'a> { self.s.word(";")?; } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { - self.print_path(&node.path, false, 0, false)?; + self.print_path(&node.path, false, 0)?; self.s.word("! ")?; self.print_ident(item.ident)?; self.cbox(INDENT_UNIT)?; @@ -1403,7 +1403,7 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> { - self.print_path(&t.path, false, 0, false) + self.print_path(&t.path, false, 0) } fn print_formal_generic_params( @@ -1460,7 +1460,7 @@ impl<'a> State<'a> { ast::CrateSugar::JustCrate => self.word_nbsp("crate") } ast::VisibilityKind::Restricted { ref path, .. } => { - let path = to_string(|s| s.print_path(path, false, 0, true)); + let path = to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { self.word_nbsp(&format!("pub({})", path)) } else { @@ -1594,7 +1594,7 @@ impl<'a> State<'a> { } ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - self.print_path(&node.path, false, 0, false)?; + self.print_path(&node.path, false, 0)?; self.s.word("! ")?; self.cbox(INDENT_UNIT)?; self.popen()?; @@ -1628,7 +1628,7 @@ impl<'a> State<'a> { } ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - self.print_path(&node.path, false, 0, false)?; + self.print_path(&node.path, false, 0)?; self.s.word("! ")?; self.cbox(INDENT_UNIT)?; self.popen()?; @@ -1814,7 +1814,7 @@ impl<'a> State<'a> { pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken) -> io::Result<()> { - self.print_path(&m.node.path, false, 0, false)?; + self.print_path(&m.node.path, false, 0)?; self.s.word("!")?; match delim { token::Paren => self.popen()?, @@ -1915,7 +1915,7 @@ impl<'a> State<'a> { fields: &[ast::Field], wth: &Option>, attrs: &[Attribute]) -> io::Result<()> { - self.print_path(path, true, 0, false)?; + self.print_path(path, true, 0)?; self.s.word("{")?; self.print_inner_attributes_inline(attrs)?; self.commasep_cmnt( @@ -2236,7 +2236,7 @@ impl<'a> State<'a> { } } ast::ExprKind::Path(None, ref path) => { - self.print_path(path, true, 0, false)? + self.print_path(path, true, 0)? } ast::ExprKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, true)? @@ -2396,17 +2396,12 @@ impl<'a> State<'a> { fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, - depth: usize, - defaults_to_global: bool) + depth: usize) -> io::Result<()> { self.maybe_print_comment(path.span.lo())?; - let mut segments = path.segments[..path.segments.len()-depth].iter(); - if defaults_to_global && path.is_global() { - segments.next(); - } - for (i, segment) in segments.enumerate() { + for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() { if i > 0 { self.s.word("::")? } @@ -2445,7 +2440,7 @@ impl<'a> State<'a> { self.s.space()?; self.word_space("as")?; let depth = path.segments.len() - qself.position; - self.print_path(path, false, depth, false)?; + self.print_path(path, false, depth)?; } self.s.word(">")?; self.s.word("::")?; @@ -2548,7 +2543,7 @@ impl<'a> State<'a> { } } PatKind::TupleStruct(ref path, ref elts, ddpos) => { - self.print_path(path, true, 0, false)?; + self.print_path(path, true, 0)?; self.popen()?; if let Some(ddpos) = ddpos { self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p))?; @@ -2566,13 +2561,13 @@ impl<'a> State<'a> { self.pclose()?; } PatKind::Path(None, ref path) => { - self.print_path(path, true, 0, false)?; + self.print_path(path, true, 0)?; } PatKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false)?; } PatKind::Struct(ref path, ref fields, etc) => { - self.print_path(path, true, 0, false)?; + self.print_path(path, true, 0)?; self.nbsp()?; self.word_space("{")?; self.commasep_cmnt( @@ -2950,7 +2945,7 @@ impl<'a> State<'a> { pub fn print_use_tree(&mut self, tree: &ast::UseTree) -> io::Result<()> { match tree.kind { ast::UseTreeKind::Simple(rename) => { - self.print_path(&tree.prefix, false, 0, true)?; + self.print_path(&tree.prefix, false, 0)?; if let Some(rename) = rename { self.s.space()?; self.word_space("as")?; @@ -2959,7 +2954,7 @@ impl<'a> State<'a> { } ast::UseTreeKind::Glob => { if !tree.prefix.segments.is_empty() { - self.print_path(&tree.prefix, false, 0, true)?; + self.print_path(&tree.prefix, false, 0)?; self.s.word("::")?; } self.s.word("*")?; @@ -2968,7 +2963,7 @@ impl<'a> State<'a> { if tree.prefix.segments.is_empty() { self.s.word("{")?; } else { - self.print_path(&tree.prefix, false, 0, true)?; + self.print_path(&tree.prefix, false, 0)?; self.s.word("::{")?; } self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 59425929f7e..401183e7c7d 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -79,7 +79,7 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<&str> vis: respan(span.empty(), ast::VisibilityKind::Inherited), node: ast::ItemKind::Use(P(ast::UseTree { prefix: ast::Path { - segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { + segments: [name, "prelude", "v1"].into_iter().map(|name| { ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP) }).collect(), span, From f88162654df187923d87254cbb36806976f81771 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 10 Mar 2018 17:45:47 +0300 Subject: [PATCH 4/6] Rename `Span::empty` to `Span::shrink_to_lo`, add `Span::shrink_to_hi` --- src/librustc/hir/lowering.rs | 2 +- src/librustc_allocator/expand.rs | 2 +- src/librustc_lint/builtin.rs | 4 ++-- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_mir/build/mod.rs | 2 +- src/librustc_resolve/lib.rs | 6 +++--- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 6 +++--- src/librustc_typeck/check/mod.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/build.rs | 4 ++-- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 4 ++-- src/libsyntax/std_inject.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 4 ++-- src/libsyntax_ext/global_asm.rs | 2 +- src/libsyntax_pos/lib.rs | 11 +++++++++-- 22 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd3b9350d91..1439410f7e9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -879,7 +879,7 @@ impl<'a> LoweringContext<'a> { TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty, itctx)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { - let span = t.span.with_hi(t.span.lo()); + let span = t.span.shrink_to_lo(); let lifetime = match *region { Some(ref lt) => self.lower_lifetime(lt), None => self.elided_lifetime(span) diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index c088458c355..02e704b6841 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -99,7 +99,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { f.cx.item_extern_crate(f.span, f.alloc), f.cx.item_use_simple( f.span, - respan(f.span.empty(), VisibilityKind::Inherited), + respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), super_path, ), ]; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 031033f7208..bffa8628ff3 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1082,7 +1082,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { if !cx.access_levels.is_reachable(it.id) { let msg = "function is marked #[no_mangle], but not exported"; let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg); - let insertion_span = it.span.with_hi(it.span.lo()); + let insertion_span = it.span.shrink_to_lo(); if it.vis == hir::Visibility::Inherited { err.span_suggestion(insertion_span, "try making it public", @@ -1107,7 +1107,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { !cx.access_levels.is_reachable(it.id) { let msg = "static is marked #[no_mangle], but not exported"; let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg); - let insertion_span = it.span.with_hi(it.span.lo()); + let insertion_span = it.span.shrink_to_lo(); if it.vis == hir::Visibility::Inherited { err.span_suggestion(insertion_span, "try making it public", diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 0b50f5c4496..30ff03a2653 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -523,7 +523,7 @@ impl CrateStore for cstore::CStore { tokens: body.into(), legacy: def.legacy, }), - vis: codemap::respan(local_span.empty(), ast::VisibilityKind::Inherited), + vis: codemap::respan(local_span.shrink_to_lo(), ast::VisibilityKind::Inherited), tokens: None, }) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 23c5499bb63..8494c043f90 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -422,7 +422,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, builder.args_and_body(block, &arguments, arg_scope, &body.value) })); // Attribute epilogue to function's closing brace - let fn_end = span.with_lo(span.hi()); + let fn_end = span.shrink_to_hi(); let source_info = builder.source_info(fn_end); let return_block = builder.return_block(); builder.cfg.terminate(block, source_info, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 23ad27ec2c3..dc22c23271d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -756,7 +756,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { // don't suggest placing a use before the prelude // import or other generated ones if item.span.ctxt().outer().expn_info().is_none() { - self.span = Some(item.span.with_hi(item.span.lo())); + self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; } @@ -768,12 +768,12 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { if item.span.ctxt().outer().expn_info().is_none() { // don't insert between attributes and an item if item.attrs.is_empty() { - self.span = Some(item.span.with_hi(item.span.lo())); + self.span = Some(item.span.shrink_to_lo()); } else { // find the first attribute on the item for attr in &item.attrs { if self.span.map_or(true, |span| attr.span < span) { - self.span = Some(attr.span.with_hi(attr.span.lo())); + self.span = Some(attr.span.shrink_to_lo()); } } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index b9b4186c818..3d4d8571c6e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1209,7 +1209,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span); - let vis_span = trait_item.span.empty(); + let vis_span = trait_item.span.shrink_to_lo(); match trait_item.node { ast::TraitItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 5c20490f823..61afac97d64 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -767,7 +767,7 @@ impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, ' // don't suggest placing a use before the prelude // import or other generated ones if item.span.ctxt().outer().expn_info().is_none() { - self.span = Some(item.span.with_hi(item.span.lo())); + self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; } @@ -779,12 +779,12 @@ impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, ' if item.span.ctxt().outer().expn_info().is_none() { // don't insert between attributes and an item if item.attrs.is_empty() { - self.span = Some(item.span.with_hi(item.span.lo())); + self.span = Some(item.span.shrink_to_lo()); } else { // find the first attribute on the item for attr in &item.attrs { if self.span.map_or(true, |span| attr.span < span) { - self.span = Some(attr.span.with_hi(attr.span.lo())); + self.span = Some(attr.span.shrink_to_lo()); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index dc9455487ed..4a685cfddb7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2520,7 +2520,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if sugg_unit { let sugg_span = sess.codemap().end_point(expr_sp); // remove closing `)` from the span - let sugg_span = sugg_span.with_hi(sugg_span.lo()); + let sugg_span = sugg_span.shrink_to_lo(); err.span_suggestion( sugg_span, "expected the unit value `()`; create it with empty parentheses", diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4ce6c53d338..eef7a6f8b4d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -117,7 +117,7 @@ impl Path { return None; } } - Some(PathSegment::crate_root(self.span.with_hi(self.span.lo()))) + Some(PathSegment::crate_root(self.span.shrink_to_lo())) } pub fn is_global(&self) -> bool { diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index e8c2d325bd6..97cb6b492d7 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -220,7 +220,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ty, expr, ), - vis: codemap::respan(span.empty(), ast::VisibilityKind::Public), + vis: codemap::respan(span.shrink_to_lo(), ast::VisibilityKind::Public), span, tokens: None, }) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index ee646dc9174..9b53553bf69 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -987,7 +987,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, node, - vis: respan(span.empty(), ast::VisibilityKind::Inherited), + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), span, tokens: None, }) @@ -1033,7 +1033,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: respan(span.empty(), ast::VisibilityKind::Inherited), + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 7ccace014d0..34dd7696168 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -239,7 +239,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { node: ast::ItemKind::Mod(krate.module), ident: keywords::Invalid.ident(), id: ast::DUMMY_NODE_ID, - vis: respan(krate.span.empty(), ast::VisibilityKind::Public), + vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), tokens: None, }))); diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 7a024dbad88..b322fd9df3e 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -858,7 +858,7 @@ fn expand_wrapper(cx: &ExtCtxt, let path = path.iter().map(|s| s.to_string()).collect(); let use_item = cx.item_use_glob( sp, - respan(sp.empty(), ast::VisibilityKind::Inherited), + respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), ids_ext(path), ); cx.stmt_item(sp, use_item) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 146f580e04e..46e6027b094 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1019,7 +1019,7 @@ pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, ident: keywords::Invalid.ident(), attrs, id: ast::DUMMY_NODE_ID, - vis: respan(span.empty(), ast::VisibilityKind::Public), + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Public), span, node: ast::ItemKind::Mod(module), tokens: None, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 815ba49a60a..5b8887f3536 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -214,7 +214,7 @@ impl<'a> StringReader<'a> { // Make the range zero-length if the span is invalid. if span.lo() > span.hi() || begin.fm.start_pos != end.fm.start_pos { - span = span.with_hi(span.lo()); + span = span.shrink_to_lo(); } let mut sr = StringReader::new_raw_internal(sess, begin.fm); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ca879765b4e..cb7f165dbd4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1512,7 +1512,7 @@ impl<'a> Parser<'a> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?)) } else { - Ok(FunctionRetTy::Default(self.span.with_hi(self.span.lo()))) + Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 319a9a3bbae..e6ed6d7b84a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1568,7 +1568,7 @@ impl<'a> State<'a> { ti.ident, ty, default.as_ref().map(|expr| &**expr), - &codemap::respan(ti.span.empty(), ast::VisibilityKind::Inherited), + &codemap::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited), )?; } ast::TraitItemKind::Method(ref sig, ref body) => { @@ -1579,7 +1579,7 @@ impl<'a> State<'a> { ti.ident, &ti.generics, sig, - &codemap::respan(ti.span.empty(), ast::VisibilityKind::Inherited), + &codemap::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited), )?; if let Some(ref body) = *body { self.nbsp()?; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 401183e7c7d..fdbc795b2d3 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -76,7 +76,7 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<&str> is_sugared_doc: false, span, }], - vis: respan(span.empty(), ast::VisibilityKind::Inherited), + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), node: ast::ItemKind::Use(P(ast::UseTree { prefix: ast::Path { segments: [name, "prelude", "v1"].into_iter().map(|name| { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1b3917efdd1..49c372b751b 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -530,7 +530,7 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: respan(self.span.empty(), ast::VisibilityKind::Inherited), + vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, attrs: Vec::new(), generics: Generics::default(), @@ -977,7 +977,7 @@ impl<'a> MethodDef<'a> { attrs: self.attributes.clone(), generics: fn_generics, span: trait_.span, - vis: respan(trait_.span.empty(), ast::VisibilityKind::Inherited), + vis: respan(trait_.span.shrink_to_lo(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 9605f6b5c5a..f01a0aacb0a 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -60,7 +60,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, asm, ctxt: cx.backtrace(), })), - vis: respan(sp.empty(), ast::VisibilityKind::Inherited), + vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), span: sp, tokens: None, }))) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 4711d43bfab..9b83d5510fb 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -239,8 +239,15 @@ impl Span { /// Returns a new span representing an empty span at the beginning of this span #[inline] - pub fn empty(self) -> Span { - self.with_hi(self.lo()) + pub fn shrink_to_lo(self) -> Span { + let span = self.data(); + span.with_hi(span.lo) + } + /// Returns a new span representing an empty span at the end of this span + #[inline] + pub fn shrink_to_hi(self) -> Span { + let span = self.data(); + span.with_lo(span.hi) } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. From 636357b09a638661d1ed1473738038d8caa9a02e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 10 Mar 2018 18:44:44 +0300 Subject: [PATCH 5/6] Cleanup import parsing Fix spans of root segments --- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 75 ++++++++++------------------------- 2 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ff097c362fe..f7e5d40b524 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -713,7 +713,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), - segments: vec![ast::PathSegment::crate_root(sp(0, 2)), + segments: vec![ast::PathSegment::crate_root(sp(0, 0)), str2seg("a", 2, 3), str2seg("b", 5, 6)] }), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cb7f165dbd4..f1967ebf590 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1990,7 +1990,7 @@ impl<'a> Parser<'a> { let lo = self.meta_var_span.unwrap_or(self.span); let mut segments = Vec::new(); if self.eat(&token::ModSep) { - segments.push(PathSegment::crate_root(lo)); + segments.push(PathSegment::crate_root(lo.shrink_to_lo())); } self.parse_path_segments(&mut segments, style, enable_warning)?; @@ -2025,7 +2025,7 @@ impl<'a> Parser<'a> { loop { segments.push(self.parse_path_segment(style, enable_warning)?); - if self.is_import_coupler(false) || !self.eat(&token::ModSep) { + if self.is_import_coupler() || !self.eat(&token::ModSep) { return Ok(()); } } @@ -6483,9 +6483,8 @@ impl<'a> Parser<'a> { let item_ = ItemKind::Use(P(self.parse_use_tree()?)); self.expect(&token::Semi)?; - let prev_span = self.prev_span; - let invalid = keywords::Invalid.ident(); - let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs); + let span = lo.to(self.prev_span); + let item = self.mk_item(span, keywords::Invalid.ident(), item_, visibility, attrs); return Ok(Some(item)); } @@ -6960,83 +6959,53 @@ impl<'a> Parser<'a> { })) } - /// `{` 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) - } - - 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 - } + /// `::{` 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)) } /// Parse UseTree /// - /// USE_TREE = `*` | - /// `{` USE_TREE_LIST `}` | + /// USE_TREE = [`::`] `*` | + /// [`::`] `{` USE_TREE_LIST `}` | /// PATH `::` `*` | /// PATH `::` `{` USE_TREE_LIST `}` | /// PATH [`as` IDENT] fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.span; - 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 `::` + let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let kind = if self.check(&token::OpenDelim(token::Brace)) || + self.check(&token::BinOp(token::Star)) || + self.is_import_coupler() { + // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` if self.eat(&token::ModSep) { - prefix.segments.push(PathSegment::crate_root(self.prev_span)); + prefix.segments.push(PathSegment::crate_root(lo.shrink_to_lo())); } 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 { - return self.unexpected(); + UseTreeKind::Nested(self.parse_use_tree_list()?) } } else { - // `use path::...;` - let mut parsed = self.parse_path(PathStyle::Mod)?; - - prefix.segments.append(&mut parsed.segments); - prefix.span = prefix.span.to(parsed.span); + // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` + prefix = self.parse_path(PathStyle::Mod)?; 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 { - return self.unexpected(); + UseTreeKind::Nested(self.parse_use_tree_list()?) } } else { - // `use path::foo;` or `use path::foo as bar;` UseTreeKind::Simple(self.parse_rename()?) } }; - Ok(UseTree { - span: lo.to(self.prev_span), - kind, - prefix, - }) + Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) }) } /// Parse UseTreeKind::Nested(list) From a02b1d7e2bd329bee0ad2f6a3e281c2004325540 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 12 Mar 2018 23:16:09 +0300 Subject: [PATCH 6/6] Add some docs + Fix rebase --- src/libsyntax/ast.rs | 6 ++++++ src/libsyntax/feature_gate.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index eef7a6f8b4d..1f16b728cd2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1877,13 +1877,19 @@ pub struct Variant_ { pub type Variant = Spanned; +/// Part of `use` item to the right of its prefix. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum UseTreeKind { + /// `use prefix` or `use prefix as rename` Simple(Option), + /// `use prefix::{...}` Nested(Vec<(UseTree, NodeId)>), + /// `use prefix::*` Glob, } +/// A tree of paths sharing common prefixes. +/// Used in `use` items both at top-level and inside of braces in import groups. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct UseTree { pub prefix: Path, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f42cb8a2583..0aef5045341 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1438,7 +1438,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, _nested: bool) { - if let ast::UseTreeKind::Simple(ident) = use_tree.kind { + if let ast::UseTreeKind::Simple(Some(ident)) = use_tree.kind { if ident.name == "_" { gate_feature_post!(&self, underscore_imports, use_tree.span, "renaming imports with `_` is unstable");