Record that an import succeeded or failed in one namespace even while it is indeterminate in the other namespace (fixes #31444)
This commit is contained in:
parent
c97524bef9
commit
064f17c6a3
@ -207,7 +207,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
ResolutionError::SelfImportsOnlyAllowedWithin);
|
||||
}
|
||||
|
||||
let subclass = SingleImport(binding, source_name);
|
||||
let subclass = ImportDirectiveSubclass::single(binding, source_name);
|
||||
self.build_import_directive(parent,
|
||||
module_path,
|
||||
subclass,
|
||||
@ -258,9 +258,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
(module_path.to_vec(), name, rename)
|
||||
}
|
||||
};
|
||||
let subclass = ImportDirectiveSubclass::single(rename, name);
|
||||
self.build_import_directive(parent,
|
||||
module_path,
|
||||
SingleImport(rename, name),
|
||||
subclass,
|
||||
source_item.span,
|
||||
source_item.node.id(),
|
||||
is_public,
|
||||
@ -683,11 +684,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
id: NodeId,
|
||||
is_public: bool,
|
||||
shadowable: Shadowable) {
|
||||
module_.unresolved_imports
|
||||
.borrow_mut()
|
||||
.push(ImportDirective::new(module_path, subclass, span, id, is_public, shadowable));
|
||||
self.unresolved_imports += 1;
|
||||
|
||||
if is_public {
|
||||
module_.inc_pub_count();
|
||||
}
|
||||
@ -696,7 +692,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
// the appropriate flag.
|
||||
|
||||
match subclass {
|
||||
SingleImport(target, _) => {
|
||||
SingleImport { target, .. } => {
|
||||
module_.increment_outstanding_references_for(target, ValueNS);
|
||||
module_.increment_outstanding_references_for(target, TypeNS);
|
||||
}
|
||||
@ -710,6 +706,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module_.unresolved_imports
|
||||
.borrow_mut()
|
||||
.push(ImportDirective::new(module_path, subclass, span, id, is_public, shadowable));
|
||||
self.unresolved_imports += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,14 +32,31 @@ use syntax::codemap::Span;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
use std::mem::replace;
|
||||
use std::cell::Cell;
|
||||
|
||||
/// Contains data for specific types of import directives.
|
||||
#[derive(Copy, Clone,Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImportDirectiveSubclass {
|
||||
SingleImport(Name /* target */, Name /* source */),
|
||||
SingleImport {
|
||||
target: Name,
|
||||
source: Name,
|
||||
type_determined: Cell<bool>,
|
||||
value_determined: Cell<bool>,
|
||||
},
|
||||
GlobImport,
|
||||
}
|
||||
|
||||
impl ImportDirectiveSubclass {
|
||||
pub fn single(target: Name, source: Name) -> Self {
|
||||
SingleImport {
|
||||
target: target,
|
||||
source: source,
|
||||
type_determined: Cell::new(false),
|
||||
value_determined: Cell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether an import can be shadowed by another import.
|
||||
#[derive(Debug,PartialEq,Clone,Copy)]
|
||||
pub enum Shadowable {
|
||||
@ -218,7 +235,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
fn import_resolving_error(&self, e: ImportResolvingError<'b>) {
|
||||
// If it's a single failed import then create a "fake" import
|
||||
// resolution for it so that later resolve stages won't complain.
|
||||
if let SingleImport(target, _) = e.import_directive.subclass {
|
||||
if let SingleImport { target, .. } = e.import_directive.subclass {
|
||||
let dummy_binding = self.resolver.new_name_binding(NameBinding {
|
||||
modifiers: DefModifiers::PRELUDE,
|
||||
kind: NameBindingKind::Def(Def::Err),
|
||||
@ -304,15 +321,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
.and_then(|containing_module| {
|
||||
// We found the module that the target is contained
|
||||
// within. Attempt to resolve the import within it.
|
||||
if let SingleImport(target, source) = import_directive.subclass {
|
||||
self.resolve_single_import(module_,
|
||||
containing_module,
|
||||
target,
|
||||
source,
|
||||
import_directive)
|
||||
} else {
|
||||
self.resolve_glob_import(module_, containing_module, import_directive)
|
||||
}
|
||||
self.resolve_import(module_, containing_module, import_directive)
|
||||
})
|
||||
.and_then(|()| {
|
||||
// Decrement the count of unresolved imports.
|
||||
@ -332,36 +341,53 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_single_import(&mut self,
|
||||
module_: Module<'b>,
|
||||
target_module: Module<'b>,
|
||||
target: Name,
|
||||
source: Name,
|
||||
directive: &ImportDirective)
|
||||
-> ResolveResult<()> {
|
||||
debug!("(resolving single import) resolving `{}` = `{}::{}` from `{}` id {}",
|
||||
target,
|
||||
module_to_string(&target_module),
|
||||
source,
|
||||
module_to_string(module_),
|
||||
directive.id);
|
||||
|
||||
// If this is a circular import, we temporarily count it as determined so that
|
||||
// it fails (as opposed to being indeterminate) when nothing else can define it.
|
||||
if target_module.def_id() == module_.def_id() && source == target {
|
||||
module_.decrement_outstanding_references_for(target, ValueNS);
|
||||
module_.decrement_outstanding_references_for(target, TypeNS);
|
||||
}
|
||||
fn resolve_import(&mut self,
|
||||
module_: Module<'b>,
|
||||
target_module: Module<'b>,
|
||||
directive: &ImportDirective)
|
||||
-> ResolveResult<()> {
|
||||
let (source, target, value_determined, type_determined) = match directive.subclass {
|
||||
SingleImport { source, target, ref value_determined, ref type_determined } =>
|
||||
(source, target, value_determined, type_determined),
|
||||
GlobImport => return self.resolve_glob_import(module_, target_module, directive),
|
||||
};
|
||||
|
||||
// We need to resolve both namespaces for this to succeed.
|
||||
let value_result =
|
||||
self.resolver.resolve_name_in_module(target_module, source, ValueNS, false, true);
|
||||
let type_result =
|
||||
self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true);
|
||||
let (value_result, type_result) = {
|
||||
let mut resolve_in_ns = |ns, determined: bool| {
|
||||
// Temporarily count the directive as determined so that the resolution fails
|
||||
// (as opposed to being indeterminate) when it can only be defined by the directive.
|
||||
if !determined { module_.decrement_outstanding_references_for(target, ns) }
|
||||
let result =
|
||||
self.resolver.resolve_name_in_module(target_module, source, ns, false, true);
|
||||
if !determined { module_.increment_outstanding_references_for(target, ns) }
|
||||
result
|
||||
};
|
||||
(resolve_in_ns(ValueNS, value_determined.get()),
|
||||
resolve_in_ns(TypeNS, type_determined.get()))
|
||||
};
|
||||
|
||||
if target_module.def_id() == module_.def_id() && source == target {
|
||||
module_.increment_outstanding_references_for(target, ValueNS);
|
||||
module_.increment_outstanding_references_for(target, TypeNS);
|
||||
for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined),
|
||||
(TypeNS, &type_result, type_determined)] {
|
||||
if determined.get() { continue }
|
||||
if let Indeterminate = *result { continue }
|
||||
|
||||
determined.set(true);
|
||||
if let Success(binding) = *result {
|
||||
if !binding.defined_with(DefModifiers::IMPORTABLE) {
|
||||
let msg = format!("`{}` is not directly importable", target);
|
||||
span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
|
||||
}
|
||||
|
||||
let privacy_error = if !self.resolver.is_visible(binding, target_module) {
|
||||
Some(Box::new(PrivacyError(directive.span, source, binding)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.define(module_, target, ns, directive.import(binding, privacy_error));
|
||||
}
|
||||
module_.decrement_outstanding_references_for(target, ns);
|
||||
}
|
||||
|
||||
match (&value_result, &type_result) {
|
||||
@ -425,37 +451,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Report a privacy error here if all successful namespaces are privacy errors.
|
||||
let mut privacy_error = None;
|
||||
let mut report_privacy_error = true;
|
||||
for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] {
|
||||
if let Success(binding) = *result {
|
||||
if !binding.defined_with(DefModifiers::IMPORTABLE) {
|
||||
let msg = format!("`{}` is not directly importable", target);
|
||||
span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
|
||||
}
|
||||
|
||||
privacy_error = if !self.resolver.is_visible(binding, target_module) {
|
||||
Some(Box::new(PrivacyError(directive.span, source, binding)))
|
||||
} else {
|
||||
report_privacy_error = false;
|
||||
None
|
||||
};
|
||||
|
||||
self.define(module_, target, ns, directive.import(binding, privacy_error.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if report_privacy_error { // then all successful namespaces are privacy errors
|
||||
// We report here so there is an error even if the imported name is not used
|
||||
self.resolver.privacy_errors.push(*privacy_error.unwrap());
|
||||
for &ns in &[ValueNS, TypeNS] {
|
||||
privacy_error = match module_.resolve_name(target, ns, true) {
|
||||
Success(&NameBinding {
|
||||
kind: NameBindingKind::Import { ref privacy_error, .. }, ..
|
||||
}) => privacy_error.as_ref().map(|error| (**error).clone()),
|
||||
_ => continue,
|
||||
};
|
||||
if privacy_error.is_none() { break }
|
||||
}
|
||||
privacy_error.map(|error| self.resolver.privacy_errors.push(error));
|
||||
|
||||
// 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.
|
||||
module_.decrement_outstanding_references_for(target, ValueNS);
|
||||
module_.decrement_outstanding_references_for(target, TypeNS);
|
||||
|
||||
let def = match type_result.success().and_then(NameBinding::def) {
|
||||
Some(def) => def,
|
||||
None => value_result.success().and_then(NameBinding::def).unwrap(),
|
||||
@ -610,7 +621,7 @@ fn import_path_to_string(names: &[Name], subclass: ImportDirectiveSubclass) -> S
|
||||
|
||||
fn import_directive_subclass_to_string(subclass: ImportDirectiveSubclass) -> String {
|
||||
match subclass {
|
||||
SingleImport(_, source) => source.to_string(),
|
||||
SingleImport { source, .. } => source.to_string(),
|
||||
GlobImport => "*".to_string(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user