From 4b9bc2e8f268dfe2a2462c4e378e5a0eeefa2cf4 Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Fri, 18 Jul 2014 00:56:56 +0200 Subject: [PATCH] Implement new mod import sugar Implements RFC #168. --- src/librustc/middle/privacy.rs | 36 ++++++++------ src/librustc/middle/resolve.rs | 80 ++++++++++++++++++++---------- src/librustc/middle/save/mod.rs | 25 ++++++---- src/librustdoc/clean/mod.rs | 18 ++++--- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 18 +++++-- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/fold.rs | 18 +++---- src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/parser.rs | 16 +++--- src/libsyntax/print/pprust.rs | 9 +++- src/libsyntax/visit.rs | 7 ++- src/test/compile-fail/use-mod-2.rs | 19 +++++++ src/test/compile-fail/use-mod-3.rs | 24 +++++++++ src/test/compile-fail/use-mod.rs | 32 ++++++++++++ src/test/run-pass/use-mod.rs | 38 ++++++++++++++ 17 files changed, 268 insertions(+), 80 deletions(-) create mode 100644 src/test/compile-fail/use-mod-2.rs create mode 100644 src/test/compile-fail/use-mod-3.rs create mode 100644 src/test/compile-fail/use-mod.rs create mode 100644 src/test/run-pass/use-mod.rs diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index cdb3f9dbb1dbf..bad6a288294f4 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -901,21 +901,29 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> { ast::ViewItemUse(ref vpath) => { match vpath.node { ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {} - ast::ViewPathList(_, ref list, _) => { + ast::ViewPathList(ref prefix, ref list, _) => { for pid in list.iter() { - debug!("privacy - list {}", pid.node.id); - let seg = ast::PathSegment { - identifier: pid.node.name, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - }; - let segs = vec!(seg); - let path = ast::Path { - global: false, - span: pid.span, - segments: segs, - }; - self.check_path(pid.span, pid.node.id, &path); + match pid.node { + ast::PathListIdent { id, name } => { + debug!("privacy - ident item {}", id); + let seg = ast::PathSegment { + identifier: name, + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + }; + let segs = vec![seg]; + let path = ast::Path { + global: false, + span: pid.span, + segments: segs, + }; + self.check_path(pid.span, id, &path); + } + ast::PathListMod { id } => { + debug!("privacy - mod item {}", id); + self.check_path(pid.span, id, prefix); + } + } } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a0adbf6e920ea..0fb377838feb1 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1455,29 +1455,20 @@ impl<'a> Resolver<'a> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - - let mut module_path = Vec::new(); - match view_path.node { + let module_path = match view_path.node { ViewPathSimple(_, ref full_path, _) => { - let path_len = full_path.segments.len(); - assert!(path_len != 0); - - for (i, segment) in full_path.segments - .iter() - .enumerate() { - if i != path_len - 1 { - module_path.push(segment.identifier) - } - } + full_path.segments + .as_slice().init() + .iter().map(|ident| ident.identifier) + .collect() } ViewPathGlob(ref module_ident_path, _) | ViewPathList(ref module_ident_path, _, _) => { - for segment in module_ident_path.segments.iter() { - module_path.push(segment.identifier) - } + module_ident_path.segments + .iter().map(|ident| ident.identifier).collect() } - } + }; // Build up the import directives. let module_ = parent.module(); @@ -1486,6 +1477,11 @@ impl<'a> Resolver<'a> { ViewPathSimple(binding, ref full_path, id) => { let source_ident = full_path.segments.last().unwrap().identifier; + if token::get_ident(source_ident).get() == "mod" { + self.resolve_error(view_path.span, + "`mod` imports are only allowed within a { } list"); + } + let subclass = SingleImport(binding, source_ident); self.build_import_directive(&*module_, @@ -1495,16 +1491,50 @@ impl<'a> Resolver<'a> { id, is_public); } - ViewPathList(_, ref source_idents, _) => { - for source_ident in source_idents.iter() { - let name = source_ident.node.name; + ViewPathList(_, ref source_items, _) => { + // Make sure there's at most one `mod` import in the list. + let mod_spans = source_items.iter().filter_map(|item| match item.node { + PathListMod { .. } => Some(item.span), + _ => None + }).collect::>(); + match mod_spans.as_slice() { + [first, second, ..other] => { + self.resolve_error(first, + "`mod` import can only appear once in the list"); + self.session.span_note(second, + "another `mod` import appears here"); + for &other_span in other.iter() { + self.session.span_note(other_span, + "another `mod` import appears here"); + } + }, + [_] | [] => () + } + + for source_item in source_items.iter() { + let (module_path, name) = match source_item.node { + PathListIdent { name, .. } => + (module_path.clone(), name), + PathListMod { .. } => { + let name = match module_path.last() { + Some(ident) => ident.clone(), + None => { + self.resolve_error(source_item.span, + "`mod` import can only appear in an import list \ + with a non-empty prefix"); + continue; + } + }; + let module_path = module_path.as_slice().init(); + (Vec::from_slice(module_path), name) + } + }; self.build_import_directive( &*module_, - module_path.clone(), + module_path, SingleImport(name, name), - source_ident.span, - source_ident.node.id, - is_public); + source_item.span, + source_item.node.id(), is_public); } } ViewPathGlob(_, id) => { @@ -5492,7 +5522,7 @@ impl<'a> Resolver<'a> { ViewPathSimple(_, _, id) => self.finalize_import(id, p.span), ViewPathList(_, ref list, _) => { for i in list.iter() { - self.finalize_import(i.node.id, i.span); + self.finalize_import(i.node.id(), i.span); } }, ViewPathGlob(_, id) => { diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 9f1f4057be6b9..c4373a023ccb2 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -1120,16 +1120,23 @@ impl<'l> Visitor for DxrVisitor<'l> { } ast::ViewPathList(ref path, ref list, _) => { for plid in list.iter() { - match self.lookup_type_ref(plid.node.id) { - Some(id) => match self.lookup_def_kind(plid.node.id, plid.span) { - Some(kind) => self.fmt.ref_str(kind, - plid.span, - Some(plid.span), - id, - e.cur_scope), - None => (), + match plid.node { + ast::PathListIdent { id, .. } => { + match self.lookup_type_ref(id) { + Some(def_id) => + match self.lookup_def_kind(id, plid.span) { + Some(kind) => { + self.fmt.ref_str( + kind, plid.span, + Some(plid.span), + def_id, e.cur_scope); + } + None => () + }, + None => () + } }, - None => () + ast::PathListMod { .. } => () } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9f5df205aa4c3..3cb2e9c6ec9ac 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1779,13 +1779,13 @@ impl Clean> for ast::ViewItem { // to keep any non-inlineable reexports so they can be // listed in the documentation. let remaining = list.iter().filter(|path| { - match inline::try_inline(path.node.id) { + match inline::try_inline(path.node.id()) { Some(items) => { ret.extend(items.move_iter()); false } None => true, } - }).map(|a| a.clone()).collect::>(); + }).map(|a| a.clone()).collect::>(); if remaining.len() > 0 { let path = ast::ViewPathList(a.clone(), remaining, @@ -1868,11 +1868,17 @@ pub struct ViewListIdent { pub source: Option, } -impl Clean for ast::PathListIdent { +impl Clean for ast::PathListItem { fn clean(&self) -> ViewListIdent { - ViewListIdent { - name: self.node.name.clean(), - source: resolve_def(self.node.id), + match self.node { + ast::PathListIdent { id, name } => ViewListIdent { + name: name.clean(), + source: resolve_def(id) + }, + ast::PathListMod { id } => ViewListIdent { + name: "mod".to_string(), + source: resolve_def(id) + } } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b7ef0956a7c76..c8f9ed64a77f8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -187,7 +187,7 @@ impl<'a> RustdocVisitor<'a> { ast::ViewPathList(ref p, ref paths, ref b) => { let mut mine = Vec::new(); for path in paths.iter() { - if !self.resolve_id(path.node.id, false, om, please_inline) { + if !self.resolve_id(path.node.id(), false, om, please_inline) { mine.push(path.clone()); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 394d4a825167d..7ad9a18a15e1b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1033,12 +1033,20 @@ pub struct Variant_ { pub type Variant = Spanned; #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] -pub struct PathListIdent_ { - pub name: Ident, - pub id: NodeId, +pub enum PathListItem_ { + PathListIdent { pub name: Ident, pub id: NodeId }, + PathListMod { pub id: NodeId } +} + +impl PathListItem_ { + pub fn id(&self) -> NodeId { + match *self { + PathListIdent { id, .. } | PathListMod { id } => id + } + } } -pub type PathListIdent = Spanned; +pub type PathListItem = Spanned; pub type ViewPath = Spanned; @@ -1056,7 +1064,7 @@ pub enum ViewPath_ { ViewPathGlob(Path, NodeId), /// `foo::bar::{a,b,c}` - ViewPathList(Path, Vec , NodeId) + ViewPathList(Path, Vec , NodeId) } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3b4f6a6e0f85f..99726da69c9ec 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -405,7 +405,7 @@ impl<'a, O: IdVisitingOperation> Visitor<()> for IdVisitor<'a, O> { ViewPathList(_, ref paths, node_id) => { self.operation.visit_id(node_id); for path in paths.iter() { - self.operation.visit_id(path.node.id) + self.operation.visit_id(path.node.id()) } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 4d3913da3656a..7d683382589b9 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1045,7 +1045,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn view_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec , imports: &[ast::Ident]) -> ast::ViewItem { let imports = imports.iter().map(|id| { - respan(sp, ast::PathListIdent_ { name: *id, id: ast::DUMMY_NODE_ID }) + respan(sp, ast::PathListIdent { name: *id, id: ast::DUMMY_NODE_ID }) }).collect(); self.view_use(sp, vis, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5417991c9df19..e31ec04865384 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -55,17 +55,17 @@ pub trait Folder { let id = self.new_id(node_id); ViewPathList(self.fold_path(path), path_list_idents.iter().map(|path_list_ident| { - let id = self.new_id(path_list_ident.node - .id); Spanned { - node: PathListIdent_ { - name: path_list_ident.node - .name - .clone(), - id: id, + node: match path_list_ident.node { + PathListIdent { id, name } => + PathListIdent { + id: self.new_id(id), + name: name.clone() + }, + PathListMod { id } => + PathListMod { id: self.new_id(id) } }, - span: self.new_span( - path_list_ident.span) + span: self.new_span(path_list_ident.span) } }).collect(), id) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 8b9cb08694972..13d2a632f3638 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -24,7 +24,7 @@ html_root_url = "http://doc.rust-lang.org/master/")] #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)] -#![feature(quote, unsafe_destructor)] +#![feature(quote, struct_variant, unsafe_destructor)] #![allow(deprecated)] extern crate fmt_macros; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 394288bd9f29b..73de47e7b12e7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -537,12 +537,16 @@ impl<'a> Parser<'a> { } } - pub fn parse_path_list_ident(&mut self) -> ast::PathListIdent { + pub fn parse_path_list_item(&mut self) -> ast::PathListItem { let lo = self.span.lo; - let ident = self.parse_ident(); + let node = if self.eat_keyword(keywords::Mod) { + ast::PathListMod { id: ast::DUMMY_NODE_ID } + } else { + let ident = self.parse_ident(); + ast::PathListIdent { name: ident, id: ast::DUMMY_NODE_ID } + }; let hi = self.last_span.hi; - spanned(lo, hi, ast::PathListIdent_ { name: ident, - id: ast::DUMMY_NODE_ID }) + spanned(lo, hi, node) } /// Consume token 'tok' if it exists. Returns true if the given @@ -5176,7 +5180,7 @@ impl<'a> Parser<'a> { let idents = self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, seq_sep_trailing_allowed(token::COMMA), - |p| p.parse_path_list_ident()); + |p| p.parse_path_list_item()); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, @@ -5232,7 +5236,7 @@ impl<'a> Parser<'a> { &token::LBRACE, &token::RBRACE, seq_sep_trailing_allowed(token::COMMA), - |p| p.parse_path_list_ident() + |p| p.parse_path_list_item() ); let path = ast::Path { span: mk_sp(lo, self.span.hi), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index dd96118ea49ee..305e67a916eb9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2182,7 +2182,14 @@ impl<'a> State<'a> { try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, idents.as_slice(), |s, w| { - s.print_ident(w.node.name) + match w.node { + ast::PathListIdent { name, .. } => { + s.print_ident(name) + }, + ast::PathListMod { .. } => { + word(&mut s.s, "mod") + } + } })); word(&mut self.s, "}") } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d5fb75a4d695d..3c6f06ddfc35d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -186,7 +186,12 @@ pub fn walk_view_item>(visitor: &mut V, vi: &ViewItem, e } ViewPathList(ref path, ref list, _) => { for id in list.iter() { - visitor.visit_ident(id.span, id.node.name, env.clone()) + match id.node { + PathListIdent { name, .. } => { + visitor.visit_ident(id.span, name, env.clone()); + } + PathListMod { .. } => () + } } walk_path(visitor, path, env.clone()); } diff --git a/src/test/compile-fail/use-mod-2.rs b/src/test/compile-fail/use-mod-2.rs new file mode 100644 index 0000000000000..12d4531078dcd --- /dev/null +++ b/src/test/compile-fail/use-mod-2.rs @@ -0,0 +1,19 @@ +// Copyright 2014 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. + +mod foo { + use self::{mod}; + //~^ ERROR unresolved import `self`. There is no `self` in `???` + + use super::{mod}; + //~^ ERROR unresolved import `super`. There is no `super` in `???` +} + +fn main() {} diff --git a/src/test/compile-fail/use-mod-3.rs b/src/test/compile-fail/use-mod-3.rs new file mode 100644 index 0000000000000..0263dc392f1de --- /dev/null +++ b/src/test/compile-fail/use-mod-3.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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::bar::{ + mod //~ ERROR module `bar` is private +}; +use foo::bar::{ + Bar, //~ ERROR type `Bar` is inaccessible + //~^ NOTE module `bar` is private + mod //~ ERROR module `bar` is private +}; + +mod foo { + mod bar { pub type Bar = int; } +} + +fn main() {} diff --git a/src/test/compile-fail/use-mod.rs b/src/test/compile-fail/use-mod.rs new file mode 100644 index 0000000000000..b2b0eb21ace48 --- /dev/null +++ b/src/test/compile-fail/use-mod.rs @@ -0,0 +1,32 @@ +// Copyright 2014 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::bar::{ + mod, +//~^ ERROR `mod` import can only appear once in the list + Bar, + mod +//~^ NOTE another `mod` import appears here +}; + +use {mod}; +//~^ ERROR `mod` import can only appear in an import list with a non-empty prefix + +use foo::mod; +//~^ ERROR `mod` imports are only allowed within a { } list + +mod foo { + pub mod bar { + pub struct Bar; + pub struct Baz; + } +} + +fn main() {} diff --git a/src/test/run-pass/use-mod.rs b/src/test/run-pass/use-mod.rs new file mode 100644 index 0000000000000..34c9f581f0719 --- /dev/null +++ b/src/test/run-pass/use-mod.rs @@ -0,0 +1,38 @@ +// Copyright 2014 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. + +pub use foo::bar::{mod, First}; +use self::bar::Second; + +mod foo { + pub use self::bar::baz::{mod}; + + pub mod bar { + pub mod baz { + pub struct Fourth; + } + pub struct First; + pub struct Second; + } + + pub struct Third; +} + +mod baz { + use super::foo::{bar, mod}; + pub use foo::Third; +} + +fn main() { + let _ = First; + let _ = Second; + let _ = baz::Third; + let _ = foo::baz::Fourth; +}