item_like_imports: Allow single imports with a given visibility

to reexport some (but not all) namespaces with less visibility.
This commit is contained in:
Jeffrey Seyfried 2016-08-19 22:52:26 +00:00
parent aad1f3cbf3
commit c56a5afd4d
2 changed files with 77 additions and 11 deletions

View File

@ -285,13 +285,20 @@ impl<'a> Resolver<'a> {
// return the corresponding binding defined by the import directive. // return the corresponding binding defined by the import directive.
fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-> NameBinding<'a> { -> NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
!directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
directive.vis.get()
} else {
binding.pseudo_vis()
};
NameBinding { NameBinding {
kind: NameBindingKind::Import { kind: NameBindingKind::Import {
binding: binding, binding: binding,
directive: directive, directive: directive,
}, },
span: directive.span, span: directive.span,
vis: directive.vis.get(), vis: vis,
} }
} }
@ -597,22 +604,44 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
} }
} }
let session = self.session;
let reexport_error = || {
let msg = format!("`{}` is private, and cannot be reexported", name);
let note_msg =
format!("consider marking `{}` as `pub` in the imported module", name);
struct_span_err!(session, directive.span, E0364, "{}", &msg)
.span_note(directive.span, &note_msg)
.emit();
};
let extern_crate_lint = || {
let msg = format!("extern crate `{}` is private, and cannot be reexported \
(error E0364), consider declaring with `pub`",
name);
session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
};
match (value_result, type_result) { match (value_result, type_result) {
// With `#![feature(item_like_imports)]`, all namespaces
// must be re-exported with extra visibility for an error to occur.
(Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
let vis = directive.vis.get();
if !value_binding.pseudo_vis().is_at_least(vis, self) &&
!type_binding.pseudo_vis().is_at_least(vis, self) {
reexport_error();
} else if type_binding.is_extern_crate() &&
!type_binding.vis.is_at_least(vis, self) {
extern_crate_lint();
}
}
(Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
let msg = format!("`{}` is private, and cannot be reexported", name); reexport_error();
let note_msg =
format!("consider marking `{}` as `pub` in the imported module", name);
struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
.span_note(directive.span, &note_msg)
.emit();
} }
(_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
if binding.is_extern_crate() { if binding.is_extern_crate() {
let msg = format!("extern crate `{}` is private, and cannot be reexported \ extern_crate_lint();
(error E0364), consider declaring with `pub`",
name);
self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
} else { } else {
struct_span_err!(self.session, directive.span, E0365, struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be reexported", name) "`{}` is private, and cannot be reexported", name)

View File

@ -0,0 +1,37 @@
// Copyright 2016 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.
#![feature(item_like_imports)]
mod a {
fn foo() {}
mod foo {}
mod a {
pub use super::foo; //~ ERROR cannot be reexported
}
}
mod b {
pub fn foo() {}
mod foo { pub struct S; }
pub mod a {
pub use super::foo; // This is OK since the value `foo` is visible enough.
fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported).
}
}
mod c {
// Test that `foo` is not reexported.
use b::a::foo::S; //~ ERROR `foo`
}
fn main() {}