Implement new mod import sugar

Implements RFC #168.
This commit is contained in:
Jakub Wieczorek 2014-07-18 00:56:56 +02:00
parent 50481f5503
commit 4b9bc2e8f2
17 changed files with 268 additions and 80 deletions

View file

@ -901,21 +901,29 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
ast::ViewItemUse(ref vpath) => { ast::ViewItemUse(ref vpath) => {
match vpath.node { match vpath.node {
ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {} ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {}
ast::ViewPathList(_, ref list, _) => { ast::ViewPathList(ref prefix, ref list, _) => {
for pid in list.iter() { for pid in list.iter() {
debug!("privacy - list {}", pid.node.id); match pid.node {
let seg = ast::PathSegment { ast::PathListIdent { id, name } => {
identifier: pid.node.name, debug!("privacy - ident item {}", id);
lifetimes: Vec::new(), let seg = ast::PathSegment {
types: OwnedSlice::empty(), identifier: name,
}; lifetimes: Vec::new(),
let segs = vec!(seg); types: OwnedSlice::empty(),
let path = ast::Path { };
global: false, let segs = vec![seg];
span: pid.span, let path = ast::Path {
segments: segs, global: false,
}; span: pid.span,
self.check_path(pid.span, pid.node.id, &path); segments: segs,
};
self.check_path(pid.span, id, &path);
}
ast::PathListMod { id } => {
debug!("privacy - mod item {}", id);
self.check_path(pid.span, id, prefix);
}
}
} }
} }
} }

View file

@ -1455,29 +1455,20 @@ impl<'a> Resolver<'a> {
// Extract and intern the module part of the path. For // Extract and intern the module part of the path. For
// globs and lists, the path is found directly in the AST; // globs and lists, the path is found directly in the AST;
// for simple paths we have to munge the path a little. // for simple paths we have to munge the path a little.
let module_path = match view_path.node {
let mut module_path = Vec::new();
match view_path.node {
ViewPathSimple(_, ref full_path, _) => { ViewPathSimple(_, ref full_path, _) => {
let path_len = full_path.segments.len(); full_path.segments
assert!(path_len != 0); .as_slice().init()
.iter().map(|ident| ident.identifier)
for (i, segment) in full_path.segments .collect()
.iter()
.enumerate() {
if i != path_len - 1 {
module_path.push(segment.identifier)
}
}
} }
ViewPathGlob(ref module_ident_path, _) | ViewPathGlob(ref module_ident_path, _) |
ViewPathList(ref module_ident_path, _, _) => { ViewPathList(ref module_ident_path, _, _) => {
for segment in module_ident_path.segments.iter() { module_ident_path.segments
module_path.push(segment.identifier) .iter().map(|ident| ident.identifier).collect()
}
} }
} };
// Build up the import directives. // Build up the import directives.
let module_ = parent.module(); let module_ = parent.module();
@ -1486,6 +1477,11 @@ impl<'a> Resolver<'a> {
ViewPathSimple(binding, ref full_path, id) => { ViewPathSimple(binding, ref full_path, id) => {
let source_ident = let source_ident =
full_path.segments.last().unwrap().identifier; 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, let subclass = SingleImport(binding,
source_ident); source_ident);
self.build_import_directive(&*module_, self.build_import_directive(&*module_,
@ -1495,16 +1491,50 @@ impl<'a> Resolver<'a> {
id, id,
is_public); is_public);
} }
ViewPathList(_, ref source_idents, _) => { ViewPathList(_, ref source_items, _) => {
for source_ident in source_idents.iter() { // Make sure there's at most one `mod` import in the list.
let name = source_ident.node.name; let mod_spans = source_items.iter().filter_map(|item| match item.node {
PathListMod { .. } => Some(item.span),
_ => None
}).collect::<Vec<Span>>();
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( self.build_import_directive(
&*module_, &*module_,
module_path.clone(), module_path,
SingleImport(name, name), SingleImport(name, name),
source_ident.span, source_item.span,
source_ident.node.id, source_item.node.id(), is_public);
is_public);
} }
} }
ViewPathGlob(_, id) => { ViewPathGlob(_, id) => {
@ -5492,7 +5522,7 @@ impl<'a> Resolver<'a> {
ViewPathSimple(_, _, id) => self.finalize_import(id, p.span), ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
ViewPathList(_, ref list, _) => { ViewPathList(_, ref list, _) => {
for i in list.iter() { for i in list.iter() {
self.finalize_import(i.node.id, i.span); self.finalize_import(i.node.id(), i.span);
} }
}, },
ViewPathGlob(_, id) => { ViewPathGlob(_, id) => {

View file

@ -1120,16 +1120,23 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
} }
ast::ViewPathList(ref path, ref list, _) => { ast::ViewPathList(ref path, ref list, _) => {
for plid in list.iter() { for plid in list.iter() {
match self.lookup_type_ref(plid.node.id) { match plid.node {
Some(id) => match self.lookup_def_kind(plid.node.id, plid.span) { ast::PathListIdent { id, .. } => {
Some(kind) => self.fmt.ref_str(kind, match self.lookup_type_ref(id) {
plid.span, Some(def_id) =>
Some(plid.span), match self.lookup_def_kind(id, plid.span) {
id, Some(kind) => {
e.cur_scope), self.fmt.ref_str(
None => (), kind, plid.span,
Some(plid.span),
def_id, e.cur_scope);
}
None => ()
},
None => ()
}
}, },
None => () ast::PathListMod { .. } => ()
} }
} }

View file

@ -1779,13 +1779,13 @@ impl Clean<Vec<Item>> for ast::ViewItem {
// to keep any non-inlineable reexports so they can be // to keep any non-inlineable reexports so they can be
// listed in the documentation. // listed in the documentation.
let remaining = list.iter().filter(|path| { let remaining = list.iter().filter(|path| {
match inline::try_inline(path.node.id) { match inline::try_inline(path.node.id()) {
Some(items) => { Some(items) => {
ret.extend(items.move_iter()); false ret.extend(items.move_iter()); false
} }
None => true, None => true,
} }
}).map(|a| a.clone()).collect::<Vec<ast::PathListIdent>>(); }).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
if remaining.len() > 0 { if remaining.len() > 0 {
let path = ast::ViewPathList(a.clone(), let path = ast::ViewPathList(a.clone(),
remaining, remaining,
@ -1868,11 +1868,17 @@ pub struct ViewListIdent {
pub source: Option<ast::DefId>, pub source: Option<ast::DefId>,
} }
impl Clean<ViewListIdent> for ast::PathListIdent { impl Clean<ViewListIdent> for ast::PathListItem {
fn clean(&self) -> ViewListIdent { fn clean(&self) -> ViewListIdent {
ViewListIdent { match self.node {
name: self.node.name.clean(), ast::PathListIdent { id, name } => ViewListIdent {
source: resolve_def(self.node.id), name: name.clean(),
source: resolve_def(id)
},
ast::PathListMod { id } => ViewListIdent {
name: "mod".to_string(),
source: resolve_def(id)
}
} }
} }
} }

View file

@ -187,7 +187,7 @@ impl<'a> RustdocVisitor<'a> {
ast::ViewPathList(ref p, ref paths, ref b) => { ast::ViewPathList(ref p, ref paths, ref b) => {
let mut mine = Vec::new(); let mut mine = Vec::new();
for path in paths.iter() { 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()); mine.push(path.clone());
} }
} }

View file

@ -1033,12 +1033,20 @@ pub struct Variant_ {
pub type Variant = Spanned<Variant_>; pub type Variant = Spanned<Variant_>;
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct PathListIdent_ { pub enum PathListItem_ {
pub name: Ident, PathListIdent { pub name: Ident, pub id: NodeId },
pub id: NodeId, PathListMod { pub id: NodeId }
} }
pub type PathListIdent = Spanned<PathListIdent_>; impl PathListItem_ {
pub fn id(&self) -> NodeId {
match *self {
PathListIdent { id, .. } | PathListMod { id } => id
}
}
}
pub type PathListItem = Spanned<PathListItem_>;
pub type ViewPath = Spanned<ViewPath_>; pub type ViewPath = Spanned<ViewPath_>;
@ -1056,7 +1064,7 @@ pub enum ViewPath_ {
ViewPathGlob(Path, NodeId), ViewPathGlob(Path, NodeId),
/// `foo::bar::{a,b,c}` /// `foo::bar::{a,b,c}`
ViewPathList(Path, Vec<PathListIdent> , NodeId) ViewPathList(Path, Vec<PathListItem> , NodeId)
} }
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]

View file

@ -405,7 +405,7 @@ impl<'a, O: IdVisitingOperation> Visitor<()> for IdVisitor<'a, O> {
ViewPathList(_, ref paths, node_id) => { ViewPathList(_, ref paths, node_id) => {
self.operation.visit_id(node_id); self.operation.visit_id(node_id);
for path in paths.iter() { for path in paths.iter() {
self.operation.visit_id(path.node.id) self.operation.visit_id(path.node.id())
} }
} }
} }

View file

@ -1045,7 +1045,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn view_use_list(&self, sp: Span, vis: ast::Visibility, fn view_use_list(&self, sp: Span, vis: ast::Visibility,
path: Vec<ast::Ident> , imports: &[ast::Ident]) -> ast::ViewItem { path: Vec<ast::Ident> , imports: &[ast::Ident]) -> ast::ViewItem {
let imports = imports.iter().map(|id| { 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(); }).collect();
self.view_use(sp, vis, self.view_use(sp, vis,

View file

@ -55,17 +55,17 @@ pub trait Folder {
let id = self.new_id(node_id); let id = self.new_id(node_id);
ViewPathList(self.fold_path(path), ViewPathList(self.fold_path(path),
path_list_idents.iter().map(|path_list_ident| { path_list_idents.iter().map(|path_list_ident| {
let id = self.new_id(path_list_ident.node
.id);
Spanned { Spanned {
node: PathListIdent_ { node: match path_list_ident.node {
name: path_list_ident.node PathListIdent { id, name } =>
.name PathListIdent {
.clone(), id: self.new_id(id),
id: id, name: name.clone()
},
PathListMod { id } =>
PathListMod { id: self.new_id(id) }
}, },
span: self.new_span( span: self.new_span(path_list_ident.span)
path_list_ident.span)
} }
}).collect(), }).collect(),
id) id)

View file

@ -24,7 +24,7 @@
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)] #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
#![feature(quote, unsafe_destructor)] #![feature(quote, struct_variant, unsafe_destructor)]
#![allow(deprecated)] #![allow(deprecated)]
extern crate fmt_macros; extern crate fmt_macros;

View file

@ -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 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; let hi = self.last_span.hi;
spanned(lo, hi, ast::PathListIdent_ { name: ident, spanned(lo, hi, node)
id: ast::DUMMY_NODE_ID })
} }
/// Consume token 'tok' if it exists. Returns true if the given /// 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( let idents = self.parse_unspanned_seq(
&token::LBRACE, &token::RBRACE, &token::LBRACE, &token::RBRACE,
seq_sep_trailing_allowed(token::COMMA), seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_path_list_ident()); |p| p.parse_path_list_item());
let path = ast::Path { let path = ast::Path {
span: mk_sp(lo, self.span.hi), span: mk_sp(lo, self.span.hi),
global: false, global: false,
@ -5232,7 +5236,7 @@ impl<'a> Parser<'a> {
&token::LBRACE, &token::LBRACE,
&token::RBRACE, &token::RBRACE,
seq_sep_trailing_allowed(token::COMMA), seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_path_list_ident() |p| p.parse_path_list_item()
); );
let path = ast::Path { let path = ast::Path {
span: mk_sp(lo, self.span.hi), span: mk_sp(lo, self.span.hi),

View file

@ -2182,7 +2182,14 @@ impl<'a> State<'a> {
try!(word(&mut self.s, "::{")); try!(word(&mut self.s, "::{"));
} }
try!(self.commasep(Inconsistent, idents.as_slice(), |s, w| { 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, "}") word(&mut self.s, "}")
} }

View file

@ -186,7 +186,12 @@ pub fn walk_view_item<E: Clone, V: Visitor<E>>(visitor: &mut V, vi: &ViewItem, e
} }
ViewPathList(ref path, ref list, _) => { ViewPathList(ref path, ref list, _) => {
for id in list.iter() { 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()); walk_path(visitor, path, env.clone());
} }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
}