rust/src/librustc_resolve/resolve_imports.rs

1052 lines
46 KiB
Rust
Raw Normal View History

// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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 self::ImportDirectiveSubclass::*;
2016-11-27 10:58:46 +00:00
use {AmbiguityError, Module, PerNS};
2016-11-10 10:29:36 +00:00
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use Resolver;
use {names_to_string, module_to_string};
2015-07-14 19:42:38 +02:00
use {resolve_error, ResolutionError};
use rustc::ty;
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use syntax::ast::{Ident, Name, SpannedIdent, NodeId};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::parse::token;
2016-11-25 06:07:21 +00:00
use syntax::symbol::keywords;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
use std::cell::{Cell, RefCell};
2016-10-28 06:52:45 +00:00
use std::mem;
/// Contains data for specific types of import directives.
#[derive(Clone, Debug)]
pub enum ImportDirectiveSubclass<'a> {
SingleImport {
target: Ident,
source: Ident,
2016-11-10 06:19:54 +00:00
result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
type_ns_only: bool,
},
GlobImport {
is_prelude: bool,
max_vis: Cell<ty::Visibility>, // The visibility of the greatest re-export.
// n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
},
ExternCrate(Option<Name>),
2017-01-14 08:58:50 +00:00
MacroUse,
}
/// One import directive.
#[derive(Debug,Clone)]
pub struct ImportDirective<'a> {
2016-04-17 01:57:09 +00:00
pub id: NodeId,
pub parent: Module<'a>,
pub module_path: Vec<SpannedIdent>,
pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
pub subclass: ImportDirectiveSubclass<'a>,
pub span: Span,
pub vis: Cell<ty::Visibility>,
pub expansion: Mark,
pub used: Cell<bool>,
}
impl<'a> ImportDirective<'a> {
2016-04-17 01:57:09 +00:00
pub fn is_glob(&self) -> bool {
match self.subclass { ImportDirectiveSubclass::GlobImport { .. } => true, _ => false }
2016-04-17 01:57:09 +00:00
}
}
#[derive(Clone, Default, Debug)]
/// Records information about the resolution of a name in a namespace of a module.
pub struct NameResolution<'a> {
/// The single imports that define the name in the namespace.
single_imports: SingleImports<'a>,
/// The least shadowable known binding for this name, or None if there are no known bindings.
pub binding: Option<&'a NameBinding<'a>>,
2016-11-27 10:58:46 +00:00
shadows_glob: Option<&'a NameBinding<'a>>,
}
#[derive(Clone, Debug)]
enum SingleImports<'a> {
/// No single imports can define the name in the namespace.
None,
/// Only the given single import can define the name in the namespace.
MaybeOne(&'a ImportDirective<'a>),
/// At least one single import will define the name in the namespace.
AtLeastOne,
}
impl<'a> Default for SingleImports<'a> {
/// Creates a `SingleImports<'a>` of None type.
fn default() -> Self {
SingleImports::None
}
}
impl<'a> SingleImports<'a> {
fn add_directive(&mut self, directive: &'a ImportDirective<'a>) {
match *self {
SingleImports::None => *self = SingleImports::MaybeOne(directive),
// If two single imports can define the name in the namespace, we can assume that at
// least one of them will define it since otherwise both would have to define only one
// namespace, leading to a duplicate error.
SingleImports::MaybeOne(_) => *self = SingleImports::AtLeastOne,
SingleImports::AtLeastOne => {}
};
}
fn directive_failed(&mut self) {
match *self {
SingleImports::None => unreachable!(),
SingleImports::MaybeOne(_) => *self = SingleImports::None,
SingleImports::AtLeastOne => {}
}
}
}
impl<'a> NameResolution<'a> {
// Returns the binding for the name if it is known or None if it not known.
fn binding(&self) -> Option<&'a NameBinding<'a>> {
self.binding.and_then(|binding| match self.single_imports {
SingleImports::None => Some(binding),
2016-04-17 01:57:09 +00:00
_ if !binding.is_glob_import() => Some(binding),
_ => None, // The binding could be shadowed by a single import, so it is not known.
})
}
2016-08-01 20:43:48 +00:00
}
impl<'a> Resolver<'a> {
fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
-> &'a RefCell<NameResolution<'a>> {
2017-03-22 08:39:51 +00:00
*module.resolutions.borrow_mut().entry((ident.modern(), ns))
.or_insert_with(|| self.arenas.alloc_name_resolution())
2016-08-01 20:43:48 +00:00
}
/// Attempts to resolve `ident` in namespaces `ns` of `module`.
/// Invariant: if `record_used` is `Some`, import resolution must be complete.
2017-03-22 08:39:51 +00:00
pub fn resolve_ident_in_module_unadjusted(&mut self,
module: Module<'a>,
ident: Ident,
ns: Namespace,
restricted_shadowing: bool,
record_used: bool,
path_span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> {
2016-08-01 20:43:48 +00:00
self.populate_module_if_necessary(module);
let resolution = self.resolution(module, ident, ns)
2016-12-14 13:02:00 -08:00
.try_borrow_mut()
.map_err(|_| Determined)?; // This happens when there is a cycle of imports
2016-08-01 20:43:48 +00:00
if record_used {
if let Some(binding) = resolution.binding {
2016-11-27 10:58:46 +00:00
if let Some(shadowed_glob) = resolution.shadows_glob {
let name = ident.name;
// Forbid expanded shadowing to avoid time travel.
if restricted_shadowing &&
2016-11-27 10:58:46 +00:00
binding.expansion != Mark::root() &&
ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
binding.def() != shadowed_glob.def() {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
name,
lexical: false,
b1: binding,
b2: shadowed_glob,
legacy: false,
2016-11-27 10:58:46 +00:00
});
}
}
if self.record_use(ident, ns, binding, path_span) {
2016-11-26 12:21:47 +00:00
return Ok(self.dummy_binding);
}
if !self.is_accessible(binding.vis) {
self.privacy_errors.push(PrivacyError(path_span, ident.name, binding));
}
}
2016-11-26 12:21:47 +00:00
return resolution.binding.ok_or(Determined);
}
2016-11-10 10:29:36 +00:00
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
2016-10-11 07:47:21 +00:00
// `extern crate` are always usable for backwards compatability, see issue #37020.
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
2016-11-26 12:21:47 +00:00
if usable { Ok(binding) } else { Err(Determined) }
2016-11-10 10:29:36 +00:00
};
2016-08-01 20:43:48 +00:00
2016-11-10 10:29:36 +00:00
// Items and single imports are not shadowable.
if let Some(binding) = resolution.binding {
if !binding.is_glob_import() {
return check_usable(self, binding);
2016-08-01 20:43:48 +00:00
}
}
// Check if a single import can still define the name.
2016-08-01 20:43:48 +00:00
match resolution.single_imports {
2016-11-26 12:21:47 +00:00
SingleImports::AtLeastOne => return Err(Undetermined),
2016-08-18 00:11:56 +00:00
SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
let module = match directive.imported_module.get() {
Some(module) => module,
2016-11-26 12:21:47 +00:00
None => return Err(Undetermined),
2016-03-18 00:05:08 +00:00
};
let ident = match directive.subclass {
SingleImport { source, .. } => source,
_ => unreachable!(),
2016-03-18 00:05:08 +00:00
};
match self.resolve_ident_in_module(module, ident, ns, false, false, path_span) {
2016-11-26 12:21:47 +00:00
Err(Determined) => {}
_ => return Err(Undetermined),
2016-03-18 00:05:08 +00:00
}
}
SingleImports::MaybeOne(_) | SingleImports::None => {},
}
2016-11-10 10:29:36 +00:00
let no_unresolved_invocations =
restricted_shadowing || module.unresolved_invocations.borrow().is_empty();
2016-11-10 10:29:36 +00:00
match resolution.binding {
// In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`).
Some(binding) if no_unresolved_invocations || ns == MacroNS =>
return check_usable(self, binding),
None if no_unresolved_invocations => {}
2016-11-26 12:21:47 +00:00
_ => return Err(Undetermined),
}
2016-11-10 10:29:36 +00:00
// Check if the globs are determined
if restricted_shadowing && module.def().is_some() {
return Err(Determined);
}
2016-11-10 10:29:36 +00:00
for directive in module.globs.borrow().iter() {
2017-03-22 08:39:51 +00:00
if !self.is_accessible(directive.vis.get()) {
continue
}
let module = unwrap_or!(directive.imported_module.get(), return Err(Undetermined));
let (orig_current_module, mut ident) = (self.current_module, ident.modern());
2017-07-31 23:04:34 +03:00
match ident.ctxt.glob_adjust(module.expansion, directive.span.ctxt().modern()) {
2017-03-22 08:39:51 +00:00
Some(Some(def)) => self.current_module = self.macro_def_scope(def),
Some(None) => {}
None => continue,
};
let result = self.resolve_ident_in_module_unadjusted(
module, ident, ns, false, false, path_span,
);
self.current_module = orig_current_module;
if let Err(Undetermined) = result {
return Err(Undetermined);
2016-11-10 10:29:36 +00:00
}
}
2016-11-26 12:21:47 +00:00
Err(Determined)
}
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
module_path: Vec<SpannedIdent>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
vis: ty::Visibility,
expansion: Mark) {
let current_module = self.current_module;
let directive = self.arenas.alloc_import_directive(ImportDirective {
parent: current_module,
module_path,
imported_module: Cell::new(None),
subclass,
span,
id,
2016-08-18 00:11:56 +00:00
vis: Cell::new(vis),
expansion,
used: Cell::new(false),
});
self.indeterminate_imports.push(directive);
match directive.subclass {
SingleImport { target, .. } => {
2016-11-10 06:19:54 +00:00
self.per_ns(|this, ns| {
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
resolution.single_imports.add_directive(directive);
2016-11-10 06:19:54 +00:00
});
}
// We don't add prelude imports to the globs since they only affect lexical scopes,
// which are not relevant to import resolution.
GlobImport { is_prelude: true, .. } => {}
GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
_ => unreachable!(),
}
}
// Given a binding and an import directive that resolves to it,
// return the corresponding binding defined by the import directive.
pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
2016-11-29 02:53:00 +00:00
-> &'a NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
// c.f. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
!directive.is_glob() && binding.is_extern_crate() {
directive.vis.get()
} else {
binding.pseudo_vis()
};
if let GlobImport { ref max_vis, .. } = directive.subclass {
if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) {
max_vis.set(vis)
}
}
2016-11-29 02:53:00 +00:00
self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
binding,
directive,
used: Cell::new(false),
2017-01-10 05:15:02 +00:00
legacy_self_import: false,
},
span: directive.span,
vis,
expansion: directive.expansion,
2016-11-29 02:53:00 +00:00
})
}
// Define the name or return the existing binding if there is a collision.
2016-11-29 02:53:00 +00:00
pub fn try_define(&mut self,
module: Module<'a>,
ident: Ident,
ns: Namespace,
binding: &'a NameBinding<'a>)
-> Result<(), &'a NameBinding<'a>> {
self.update_resolution(module, ident, ns, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if binding.is_glob_import() {
2016-10-11 07:47:21 +00:00
if !old_binding.is_glob_import() &&
!(ns == MacroNS && old_binding.expansion != Mark::root()) {
2016-11-27 10:58:46 +00:00
resolution.shadows_glob = Some(binding);
} else if binding.def() != old_binding.def() {
2016-11-10 10:29:36 +00:00
resolution.binding = Some(this.ambiguity(old_binding, binding));
} else if !old_binding.vis.is_at_least(binding.vis, &*this) {
// We are glob-importing the same item but with greater visibility.
resolution.binding = Some(binding);
}
} else if old_binding.is_glob_import() {
2016-10-11 07:47:21 +00:00
if ns == MacroNS && binding.expansion != Mark::root() &&
binding.def() != old_binding.def() {
2016-11-10 10:29:36 +00:00
resolution.binding = Some(this.ambiguity(binding, old_binding));
} else {
resolution.binding = Some(binding);
2016-11-27 10:58:46 +00:00
resolution.shadows_glob = Some(old_binding);
2016-11-10 10:29:36 +00:00
}
} else {
return Err(old_binding);
}
} else {
resolution.binding = Some(binding);
}
Ok(())
})
}
pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
-> &'a NameBinding<'a> {
2016-11-10 10:29:36 +00:00
self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
2016-11-10 10:29:36 +00:00
vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
span: b1.span,
expansion: Mark::root(),
})
}
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
-> T
where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
2016-08-20 07:22:32 +00:00
let (binding, t) = {
let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
match resolution.binding() {
2016-10-11 07:47:21 +00:00
_ if old_binding.is_some() => return t,
None => return t,
Some(binding) => match old_binding {
Some(old_binding) if old_binding as *const _ == binding as *const _ => return t,
_ => (binding, t),
}
}
};
2016-08-20 07:22:32 +00:00
// Define `binding` in `module`s glob importers.
for directive in module.glob_importers.borrow_mut().iter() {
2017-03-22 08:39:51 +00:00
let mut ident = ident.modern();
let scope = match ident.ctxt.reverse_glob_adjust(module.expansion,
2017-07-31 23:04:34 +03:00
directive.span.ctxt().modern()) {
2017-03-22 08:39:51 +00:00
Some(Some(def)) => self.macro_def_scope(def),
Some(None) => directive.parent,
None => continue,
};
if self.is_accessible_from(binding.vis, scope) {
2016-08-20 07:22:32 +00:00
let imported_binding = self.import(binding, directive);
let _ = self.try_define(directive.parent, ident, ns, imported_binding);
}
}
t
}
2016-11-10 06:19:54 +00:00
// Define a "dummy" resolution containing a Def::Err as a placeholder for a
// failed resolution
fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) {
if let SingleImport { target, .. } = directive.subclass {
let dummy_binding = self.dummy_binding;
let dummy_binding = self.import(dummy_binding, directive);
self.per_ns(|this, ns| {
2016-11-29 02:53:00 +00:00
let _ = this.try_define(directive.parent, target, ns, dummy_binding);
2016-11-10 06:19:54 +00:00
});
}
}
}
2016-11-10 10:11:25 +00:00
pub struct ImportResolver<'a, 'b: 'a> {
pub resolver: &'a mut Resolver<'b>,
}
impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> {
type Target = Resolver<'b>;
fn deref(&self) -> &Resolver<'b> {
self.resolver
}
}
impl<'a, 'b: 'a> ::std::ops::DerefMut for ImportResolver<'a, 'b> {
fn deref_mut(&mut self) -> &mut Resolver<'b> {
self.resolver
}
}
impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
fn parent(self, id: DefId) -> Option<DefId> {
self.resolver.parent(id)
}
}
2016-04-24 03:26:10 +00:00
impl<'a, 'b:'a> ImportResolver<'a, 'b> {
// Import resolution
//
// This is a fixed-point algorithm. We resolve imports until our efforts
// are stymied by an unresolved import; then we bail out of the current
// module and continue. We terminate successfully once no more imports
// remain or unsuccessfully when no forward progress in resolving imports
// is made.
/// Resolves all imports for the crate. This method performs the fixed-
/// point iteration.
2016-11-10 10:11:25 +00:00
pub fn resolve_imports(&mut self) {
let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
while self.indeterminate_imports.len() < prev_num_indeterminates {
prev_num_indeterminates = self.indeterminate_imports.len();
2016-11-10 10:11:25 +00:00
for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) {
match self.resolve_import(&import) {
2016-11-26 12:21:47 +00:00
true => self.determined_imports.push(import),
false => self.indeterminate_imports.push(import),
}
}
}
2016-11-10 10:11:25 +00:00
}
2016-11-10 10:11:25 +00:00
pub fn finalize_imports(&mut self) {
for module in self.arenas.local_modules().iter() {
self.finalize_resolutions_in(module);
}
2016-08-18 03:39:48 +00:00
let mut errors = false;
let mut seen_spans = FxHashSet();
for i in 0 .. self.determined_imports.len() {
let import = self.determined_imports[i];
if let Some((span, err)) = self.finalize_import(import) {
2016-08-18 03:39:48 +00:00
errors = true;
if let SingleImport { source, ref result, .. } = import.subclass {
if source.name == "self" {
// Silence `unresolved import` error if E0429 is already emitted
match result.value_ns.get() {
Err(Determined) => continue,
_ => {},
}
}
}
2016-08-18 03:39:48 +00:00
// If the error is a single failed import then create a "fake" import
// resolution for it so that later resolve stages won't complain.
self.import_dummy_binding(import);
if !seen_spans.contains(&span) {
let path = import_path_to_string(&import.module_path[..],
&import.subclass,
span);
let error = ResolutionError::UnresolvedImport(Some((span, &path, &err)));
resolve_error(self.resolver, span, error);
seen_spans.insert(span);
}
}
}
// Report unresolved imports only if no hard error was already reported
// to avoid generating multiple errors on the same import.
2016-08-18 03:39:48 +00:00
if !errors {
if let Some(import) = self.indeterminate_imports.iter().next() {
let error = ResolutionError::UnresolvedImport(None);
resolve_error(self.resolver, import.span, error);
}
}
}
2016-11-26 12:21:47 +00:00
/// Attempts to resolve the given import, returning true if its resolution is determined.
/// If successful, the resolved bindings are written into the module.
2016-11-26 12:21:47 +00:00
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
names_to_string(&directive.module_path[..]),
module_to_string(self.current_module).unwrap_or("???".to_string()));
self.current_module = directive.parent;
let module = if let Some(module) = directive.imported_module.get() {
2016-08-18 00:11:56 +00:00
module
} else {
let vis = directive.vis.get();
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
let result = self.resolve_path(&directive.module_path[..], None, false, directive.span);
2016-08-18 00:11:56 +00:00
directive.vis.set(vis);
match result {
2016-11-25 06:07:21 +00:00
PathResult::Module(module) => module,
2016-11-26 12:21:47 +00:00
PathResult::Indeterminate => return false,
_ => return true,
2016-08-18 00:11:56 +00:00
}
};
directive.imported_module.set(Some(module));
let (source, target, result, type_ns_only) = match directive.subclass {
SingleImport { source, target, ref result, type_ns_only } =>
(source, target, result, type_ns_only),
GlobImport { .. } => {
self.resolve_glob_import(directive);
2016-11-26 12:21:47 +00:00
return true;
}
_ => unreachable!(),
};
let mut indeterminate = false;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
2016-11-10 06:19:54 +00:00
if let Err(Undetermined) = result[ns].get() {
result[ns].set(this.resolve_ident_in_module(module,
source,
ns,
false,
false,
directive.span));
} else {
2016-11-10 06:19:54 +00:00
return
};
2016-11-29 02:53:00 +00:00
let parent = directive.parent;
2016-11-10 06:19:54 +00:00
match result[ns].get() {
2016-08-18 05:39:32 +00:00
Err(Undetermined) => indeterminate = true,
Err(Determined) => {
2016-11-29 02:53:00 +00:00
this.update_resolution(parent, target, ns, |_, resolution| {
resolution.single_imports.directive_failed()
});
}
Ok(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
2016-11-10 06:19:54 +00:00
struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
.span_label(directive.span, "cannot be imported directly")
.emit();
// Do not import this illegal binding. Import a dummy binding and pretend
// everything is fine
2016-11-10 06:19:54 +00:00
this.import_dummy_binding(directive);
}
Ok(binding) => {
2016-11-10 06:19:54 +00:00
let imported_binding = this.import(binding, directive);
2016-11-29 02:53:00 +00:00
let conflict = this.try_define(parent, target, ns, imported_binding);
if let Err(old_binding) = conflict {
2016-11-29 02:53:00 +00:00
this.report_conflict(parent, target, ns, imported_binding, old_binding);
}
2016-02-16 13:14:32 +00:00
}
}
2016-11-10 06:19:54 +00:00
});
2016-11-26 12:21:47 +00:00
!indeterminate
}
2016-11-26 12:21:47 +00:00
// If appropriate, returns an error to report.
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;
2018-01-01 17:42:32 +03:00
// FIXME: Last path segment is treated specially in import resolution, so extern crate
// mode for absolute paths needs some special support for single-segment imports.
if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() ||
module_path[0].node.name == keywords::Extern.name()) {
let is_extern = module_path[0].node.name == keywords::Extern.name() ||
self.session.features.borrow().extern_absolute_paths;
match directive.subclass {
2018-01-01 17:42:32 +03:00
GlobImport { .. } if is_extern => {
return Some((directive.span,
"cannot glob-import all possible crates".to_string()));
}
SingleImport { source, target, .. } => {
2018-01-01 17:42:32 +03:00
let crate_root = if source.name == keywords::Crate.name() &&
module_path[0].node.name != keywords::Extern.name() {
if target.name == keywords::Crate.name() {
return Some((directive.span,
"crate root imports need to be explicitly named: \
`use crate as name;`".to_string()));
} else {
Some(self.resolve_crate_root(source.ctxt.modern(), false))
}
2018-01-01 17:42:32 +03:00
} else if is_extern && !token::Ident(source).is_path_segment_keyword() {
let crate_id =
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
let crate_root =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);
Some(crate_root)
} else {
None
};
if let Some(crate_root) = crate_root {
let binding = (crate_root, ty::Visibility::Public, directive.span,
directive.expansion).to_name_binding(self.arenas);
let binding = self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
binding,
directive,
used: Cell::new(false),
legacy_self_import: false,
},
vis: directive.vis.get(),
span: directive.span,
expansion: directive.expansion,
});
let _ = self.try_define(directive.parent, target, TypeNS, binding);
return None;
}
}
_ => {}
}
}
let module_result = self.resolve_path(&module_path, None, true, span);
let module = match module_result {
2016-11-25 06:07:21 +00:00
PathResult::Module(module) => module,
PathResult::Failed(span, msg, false) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
return None;
}
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())
{
self_path[0].node.name = keywords::SelfValue.name();
self_result = Some(self.resolve_path(&self_path, None, false, span));
}
return if let Some(PathResult::Module(..)) = self_result {
Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..]))))
} else {
Some((span, msg))
};
},
2016-11-26 12:21:47 +00:00
_ => return None,
};
let (ident, result, type_ns_only) = match directive.subclass {
SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
// Importing a module into itself is not allowed.
return Some((directive.span,
"Cannot glob-import a module into itself.".to_string()));
}
GlobImport { is_prelude, ref max_vis } => {
if !is_prelude &&
max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
!max_vis.get().is_at_least(directive.vis.get(), &*self) {
let msg = "A non-empty glob must import something with the glob's visibility";
self.session.span_err(directive.span, msg);
}
2016-11-26 12:21:47 +00:00
return None;
}
_ => unreachable!(),
};
2016-11-10 06:19:54 +00:00
let mut all_ns_err = true;
2017-01-10 05:15:02 +00:00
let mut legacy_self_import = None;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
2016-11-10 06:19:54 +00:00
if let Ok(binding) = result[ns].get() {
all_ns_err = false;
if this.record_use(ident, ns, binding, directive.span) {
this.resolution(module, ident, ns).borrow_mut().binding =
2016-11-10 06:19:54 +00:00
Some(this.dummy_binding);
}
}
} else if let Ok(binding) = this.resolve_ident_in_module(module,
ident,
ns,
false,
false,
directive.span) {
2017-01-10 05:15:02 +00:00
legacy_self_import = Some(directive);
let binding = this.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
binding,
directive,
2017-01-10 05:15:02 +00:00
used: Cell::new(false),
legacy_self_import: true,
},
..*binding
});
let _ = this.try_define(directive.parent, ident, ns, binding);
2016-11-10 06:19:54 +00:00
});
2016-11-10 06:19:54 +00:00
if all_ns_err {
2017-01-10 05:15:02 +00:00
if let Some(directive) = legacy_self_import {
self.warn_legacy_self_import(directive);
return None;
}
2016-11-10 06:19:54 +00:00
let mut all_ns_failed = true;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
match this.resolve_ident_in_module(module, ident, ns, false, true, span) {
2016-11-26 12:21:47 +00:00
Ok(_) => all_ns_failed = false,
2016-11-10 06:19:54 +00:00
_ => {}
}
});
2016-11-10 06:19:54 +00:00
return if all_ns_failed {
let resolutions = module.resolutions.borrow();
let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| {
if *i == ident { return None; } // Never suggest the same name
2016-03-31 04:44:04 +00:00
match *resolution.borrow() {
NameResolution { binding: Some(name_binding), .. } => {
match name_binding.kind {
NameBindingKind::Import { binding, .. } => {
match binding.kind {
// Never suggest the name that has binding error
// i.e. the name that cannot be previously resolved
NameBindingKind::Def(Def::Err) => return None,
_ => Some(&i.name),
}
},
_ => Some(&i.name),
}
},
2016-03-31 04:44:04 +00:00
NameResolution { single_imports: SingleImports::None, .. } => None,
_ => Some(&i.name),
2016-03-31 04:44:04 +00:00
}
});
let lev_suggestion =
match find_best_match_for_name(names, &ident.name.as_str(), None) {
Some(name) => format!(". Did you mean to use `{}`?", name),
None => "".to_owned(),
};
let module_str = module_to_string(module);
let msg = if let Some(module_str) = module_str {
format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion)
} else {
format!("no `{}` in the root{}", ident, lev_suggestion)
2016-04-09 01:06:57 +00:00
};
Some((span, msg))
} else {
// `resolve_ident_in_module` reported a privacy error.
self.import_dummy_binding(directive);
2016-11-26 12:21:47 +00:00
None
}
}
2016-11-10 06:19:54 +00:00
let mut reexport_error = None;
let mut any_successful_reexport = false;
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
let vis = directive.vis.get();
if !binding.pseudo_vis().is_at_least(vis, &*this) {
2016-11-10 06:19:54 +00:00
reexport_error = Some((ns, binding));
} else {
2016-11-10 06:19:54 +00:00
any_successful_reexport = true;
}
}
2016-11-10 06:19:54 +00:00
});
2016-11-10 06:19:54 +00:00
// All namespaces must be re-exported with extra visibility for an error to occur.
if !any_successful_reexport {
let (ns, binding) = reexport_error.unwrap();
if ns == TypeNS && binding.is_extern_crate() {
let msg = format!("extern crate `{}` is private, and cannot be \
re-exported (error E0365), consider declaring with \
`pub`",
ident);
rustc: Rearchitect lints to be emitted more eagerly In preparation for incremental compilation this commit refactors the lint handling infrastructure in the compiler to be more "eager" and overall more incremental-friendly. Many passes of the compiler can emit lints at various points but before this commit all lints were buffered in a table to be emitted at the very end of compilation. This commit changes these lints to be emitted immediately during compilation using pre-calculated lint level-related data structures. Linting today is split into two phases, one set of "early" lints run on the `syntax::ast` and a "late" set of lints run on the HIR. This commit moves the "early" lints to running as late as possible in compilation, just before HIR lowering. This notably means that we're catching resolve-related lints just before HIR lowering. The early linting remains a pass very similar to how it was before, maintaining context of the current lint level as it walks the tree. Post-HIR, however, linting is structured as a method on the `TyCtxt` which transitively executes a query to calculate lint levels. Each request to lint on a `TyCtxt` will query the entire crate's 'lint level data structure' and then go from there about whether the lint should be emitted or not. The query depends on the entire HIR crate but should be very quick to calculate (just a quick walk of the HIR) and the red-green system should notice that the lint level data structure rarely changes, and should hopefully preserve incrementality. Overall this resulted in a pretty big change to the test suite now that lints are emitted much earlier in compilation (on-demand vs only at the end). This in turn necessitated the addition of many `#![allow(warnings)]` directives throughout the compile-fail test suite and a number of updates to the UI test suite.
2017-07-26 21:51:09 -07:00
self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
directive.id,
directive.span,
&msg);
} else if ns == TypeNS {
2016-11-10 06:19:54 +00:00
struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be re-exported", ident)
.span_label(directive.span, format!("re-export of private `{}`", ident))
.note(&format!("consider declaring type or module `{}` with `pub`", ident))
2016-11-10 06:19:54 +00:00
.emit();
} else {
let msg = format!("`{}` is private, and cannot be re-exported", ident);
2016-11-10 06:19:54 +00:00
let note_msg =
format!("consider marking `{}` as `pub` in the imported module", ident);
2016-11-10 06:19:54 +00:00
struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
.span_note(directive.span, &note_msg)
.emit();
}
}
// Record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
2016-11-10 06:19:54 +00:00
self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
});
debug!("(resolving single import) successfully resolved import");
2016-11-26 12:21:47 +00:00
None
}
fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
let module = directive.imported_module.get().unwrap();
self.populate_module_if_necessary(module);
2016-09-18 09:45:06 +00:00
if let Some(Def::Trait(_)) = module.def() {
self.session.span_err(directive.span, "items in traits are not importable.");
return;
} else if module.def_id() == directive.parent.def_id() {
return;
} else if let GlobImport { is_prelude: true, .. } = directive.subclass {
self.prelude = Some(module);
return;
2016-03-09 01:46:46 +00:00
}
// Add to module's glob_importers
module.glob_importers.borrow_mut().push(directive);
// Ensure that `resolutions` isn't borrowed during `try_define`,
2016-04-11 18:30:48 +00:00
// since it might get updated via a glob cycle.
let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
resolution.borrow().binding().map(|binding| (ident, binding))
}).collect::<Vec<_>>();
2017-03-22 08:39:51 +00:00
for ((mut ident, ns), binding) in bindings {
let scope = match ident.ctxt.reverse_glob_adjust(module.expansion,
2017-07-31 23:04:34 +03:00
directive.span.ctxt().modern()) {
2017-03-22 08:39:51 +00:00
Some(Some(def)) => self.macro_def_scope(def),
Some(None) => self.current_module,
None => continue,
};
if self.is_accessible_from(binding.pseudo_vis(), scope) {
let imported_binding = self.import(binding, directive);
let _ = self.try_define(directive.parent, ident, ns, imported_binding);
}
}
// Record the destination of this import
self.record_def(directive.id, PathResolution::new(module.def().unwrap()));
}
// Miscellaneous post-processing, including recording re-exports,
// reporting conflicts, and reporting unresolved imports.
fn finalize_resolutions_in(&mut self, module: Module<'b>) {
// Since import resolution is finished, globs will not define any more names.
*module.globs.borrow_mut() = Vec::new();
let mut reexports = Vec::new();
let mut exported_macro_names = FxHashMap();
2016-10-28 06:52:45 +00:00
if module as *const _ == self.graph_root as *const _ {
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
for export in macro_exports.into_iter().rev() {
2017-03-27 00:46:00 +00:00
if exported_macro_names.insert(export.ident.modern(), export.span).is_none() {
reexports.push(export);
}
}
2016-10-28 06:52:45 +00:00
}
for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
let resolution = &mut *resolution.borrow_mut();
let binding = match resolution.binding {
Some(binding) => binding,
None => continue,
};
if binding.is_import() || binding.is_macro_def() {
let def = binding.def();
if def != Def::Err {
if !def.def_id().is_local() {
self.cstore.export_macros_untracked(def.def_id().krate);
}
if let Def::Macro(..) = def {
2017-03-27 00:46:00 +00:00
if let Some(&span) = exported_macro_names.get(&ident.modern()) {
let msg =
format!("a macro named `{}` has already been exported", ident);
self.session.struct_span_err(span, &msg)
.span_label(span, format!("`{}` already exported", ident))
.span_note(binding.span, "previous macro export here")
.emit();
}
}
reexports.push(Export {
ident: ident.modern(),
def: def,
span: binding.span,
vis: binding.vis,
is_import: true,
});
}
}
match binding.kind {
NameBindingKind::Import { binding: orig_binding, directive, .. } => {
if ns == TypeNS && orig_binding.is_variant() &&
!orig_binding.vis.is_at_least(binding.vis, &*self) {
let msg = match directive.subclass {
ImportDirectiveSubclass::SingleImport { .. } => {
format!("variant `{}` is private and cannot be re-exported",
ident)
},
ImportDirectiveSubclass::GlobImport { .. } => {
let msg = "enum is private and its variants \
cannot be re-exported".to_owned();
let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
Some(binding.span),
msg.clone());
let fresh = self.session.one_time_diagnostics
.borrow_mut().insert(error_id);
if !fresh {
continue;
}
msg
},
ref s @ _ => bug!("unexpected import subclass {:?}", s)
};
let mut err = self.session.struct_span_err(binding.span, &msg);
let imported_module = directive.imported_module.get()
.expect("module should exist");
let resolutions = imported_module.parent.expect("parent should exist")
.resolutions.borrow();
let enum_path_segment_index = directive.module_path.len() - 1;
let enum_ident = directive.module_path[enum_path_segment_index].node;
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
.expect("resolution should exist");
let enum_span = enum_resolution.borrow()
.binding.expect("binding should exist")
.span;
let enum_def_span = self.session.codemap().def_span(enum_span);
let enum_def_snippet = self.session.codemap()
.span_to_snippet(enum_def_span).expect("snippet should exist");
// potentially need to strip extant `crate`/`pub(path)` for suggestion
let after_vis_index = enum_def_snippet.find("enum")
.expect("`enum` keyword should exist in snippet");
let suggestion = format!("pub {}",
&enum_def_snippet[after_vis_index..]);
self.session
.diag_span_suggestion_once(&mut err,
DiagnosticMessageId::ErrorId(0),
enum_def_span,
"consider making the enum public",
suggestion);
err.emit();
}
}
NameBindingKind::Ambiguity { b1, b2, .. }
if b1.is_glob_import() && b2.is_glob_import() => {
let (orig_b1, orig_b2) = match (&b1.kind, &b2.kind) {
(&NameBindingKind::Import { binding: b1, .. },
&NameBindingKind::Import { binding: b2, .. }) => (b1, b2),
_ => continue,
};
let (b1, b2) = match (orig_b1.vis, orig_b2.vis) {
(ty::Visibility::Public, ty::Visibility::Public) => continue,
(ty::Visibility::Public, _) => (b1, b2),
(_, ty::Visibility::Public) => (b2, b1),
_ => continue,
};
resolution.binding = Some(self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: true }, ..*b1
}));
}
_ => {}
}
}
if reexports.len() > 0 {
if let Some(def_id) = module.def_id() {
self.export_map.insert(def_id, reexports);
}
}
}
}
fn import_path_to_string(names: &[SpannedIdent],
subclass: &ImportDirectiveSubclass,
span: Span) -> String {
let pos = names.iter()
.position(|p| span == p.span && p.node.name != keywords::CrateRoot.name());
let global = !names.is_empty() && names[0].node.name == keywords::CrateRoot.name();
if let Some(pos) = pos {
let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] };
names_to_string(names)
} else {
let names = if global { &names[1..] } else { names };
if names.is_empty() {
import_directive_subclass_to_string(subclass)
} else {
// Note that this code looks a little wonky, it's currently here to
// hopefully help debug #48116, but otherwise isn't intended to
// cause any problems.
let x = format!(
"{}::{}",
names_to_string(names),
import_directive_subclass_to_string(subclass),
);
rustc: Upgrade to LLVM 6 The following submodules have been updated for a new version of LLVM: - `src/llvm` - `src/libcompiler_builtins` - transitively contains compiler-rt - `src/dlmalloc` This also updates the docker container for dist-i686-freebsd as the old 16.04 container is no longer capable of building LLVM. The compiler-rt/compiler-builtins and dlmalloc updates are pretty routine without much interesting happening, but the LLVM update here is of particular note. Unlike previous updates I haven't cherry-picked all existing patches we had on top of our LLVM branch as we have a [huge amount][patches4] and have at this point forgotten what most of them are for. Instead I started from the current `release_60` branch in LLVM and only applied patches that were necessary to get our tests working and building. The current set of custom rustc-specific patches included in this LLVM update are: * rust-lang/llvm@1187443 - this is how we actually implement `cfg(target_feature)` for now and continues to not be upstreamed. While a hazard for SIMD stabilization this commit is otherwise keeping the status quo of a small rustc-specific feature. * rust-lang/llvm@013f2ec - this is a rustc-specific optimization that we haven't upstreamed, notably teaching LLVM about our allocation-related routines (which aren't malloc/free). Once we stabilize the global allocator routines we will likely want to upstream this patch, but for now it seems reasonable to keep it on our fork. * rust-lang/llvm@a65bbfd - I found this necessary to fix compilation of LLVM in our 32-bit linux container. I'm not really sure why it's necessary but my guess is that it's because of the absolutely ancient glibc that we're using. In any case it's only updating pieces we're not actually using in LLVM so I'm hoping it'll turn out alright. This doesn't seem like something we'll want to upstream.c * rust-lang/llvm@77ab1f0 - this is what's actually enabling LLVM to build in our i686-freebsd container, I'm not really sure what's going on but we for sure probably don't want to upstream this and otherwise it seems not too bad for now at least. * rust-lang/llvm@9eb9267 - we currently suffer on MSVC from an [upstream bug] which although diagnosed to a particular revision isn't currently fixed upstream (and the bug itself doesn't seem too active). This commit is a partial revert of the suspected cause of this regression (found via a bisection). I'm sort of hoping that this eventually gets fixed upstream with a similar fix (which we can replace in our branch), but for now I'm also hoping it's a relatively harmless change to have. After applying these patches (plus one [backport] which should be [backported upstream][llvm-back]) I believe we should have all tests working on all platforms in our current test suite. I'm like 99% sure that we'll need some more backports as issues are reported for LLVM 6 when this propagates through nightlies, but that's sort of just par for the course nowadays! In any case though some extra scrutiny of the patches here would definitely be welcome, along with scrutiny of the "missing patches" like a [change to pass manager order](rust-lang/llvm@27174447533), [another change to pass manager order](rust-lang/llvm@c782febb7b9), some [compile fixes for sparc](rust-lang/llvm@1a83de63c42), and some [fixes for solaris](rust-lang/llvm@c2bfe0abb). [patches4]: https://github.com/rust-lang/llvm/compare/5401fdf23...rust-llvm-release-4-0-1 [backport]: https://github.com/rust-lang/llvm/commit/5c54c252db [llvm-back]: https://bugs.llvm.org/show_bug.cgi?id=36114 [upstream bug]: https://bugs.llvm.org/show_bug.cgi?id=36096 --- The update to LLVM 6 is desirable for a number of reasons, notably: * This'll allow us to keep up with the upstream wasm backend, picking up new features as they start landing. * Upstream LLVM has fixed a number of SIMD-related compilation errors, especially around AVX-512 and such. * There's a few assorted known bugs which are fixed in LLVM 5 and aren't fixed in the LLVM 4 branch we're using. * Overall it's not a great idea to stagnate with our codegen backend! This update is mostly powered by #47730 which is allowing us to update LLVM *independent* of the version of LLVM that Emscripten is locked to. This means that when compiling code for Emscripten we'll still be using the old LLVM 4 backend, but when compiling code for any other target we'll be using the new LLVM 6 target. Once Emscripten updates we may no longer need this distinction, but we're not sure when that will happen! Closes #43370 Closes #43418 Closes #47015 Closes #47683 Closes rust-lang-nursery/stdsimd#157 Closes rust-lang-nursery/rust-wasm#3
2018-01-22 14:23:30 -08:00
assert!(!names.is_empty());
assert!(!x.starts_with("::"));
return x
}
}
}
2016-02-15 02:22:59 +00:00
fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> String {
match *subclass {
SingleImport { source, .. } => source.to_string(),
GlobImport { .. } => "*".to_string(),
ExternCrate(_) => "<extern crate>".to_string(),
2017-01-14 08:58:50 +00:00
MacroUse => "#[macro_use]".to_string(),
}
}