Auto merge of #31338 - dirk:dirk/add-name-bindings-for-bad-imports, r=nrc

WIP implementation of #31209.

The goal is to insert fake/dummy definitions for names that we failed to import so that later resolver stages won't complain about them.
This commit is contained in:
bors 2016-02-03 08:51:31 +00:00
commit 8c77ffb484
6 changed files with 71 additions and 20 deletions

View File

@ -120,7 +120,7 @@ impl Def {
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
panic!("attempted .def_id() on invalid {:?}", self)
panic!("attempted .var_id() on invalid {:?}", self)
}
}
}

View File

@ -1468,7 +1468,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match search_module.parent_link {
NoParentLink => {
// No more parents. This module was unresolved.
debug!("(resolving item in lexical scope) unresolved module");
debug!("(resolving item in lexical scope) unresolved module: no parent module");
return Failed(None);
}
ModuleParentLink(parent_module_node, _) => {
@ -3109,7 +3109,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
Indeterminate => None,
Failed(err) => {
debug!("(resolving item path by identifier in lexical scope) failed to resolve {}",
debug!("(resolving item path by identifier in lexical scope) failed to \
resolve `{}`",
name);
if let Some((span, msg)) = err {

View File

@ -11,6 +11,7 @@
use self::ImportDirectiveSubclass::*;
use DefModifiers;
use DefOrModule;
use Module;
use Namespace::{self, TypeNS, ValueNS};
use NameBinding;
@ -50,7 +51,7 @@ pub enum Shadowable {
}
/// One import directive.
#[derive(Debug)]
#[derive(Debug,Clone)]
pub struct ImportDirective {
pub module_path: Vec<Name>,
pub subclass: ImportDirectiveSubclass,
@ -140,9 +141,11 @@ impl<'a> ImportResolution<'a> {
}
}
struct ImportResolvingError {
struct ImportResolvingError<'a> {
/// Module where the error happened
source_module: Module<'a>,
import_directive: ImportDirective,
span: Span,
path: String,
help: String,
}
@ -181,9 +184,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
// resolving failed
if errors.len() > 0 {
for e in errors {
resolve_error(self.resolver,
e.span,
ResolutionError::UnresolvedImport(Some((&e.path, &e.help))));
self.import_resolving_error(e)
}
} else {
// Report unresolved imports only if no hard error was already reported
@ -200,11 +201,55 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
}
}
/// Resolves an `ImportResolvingError` into the correct enum discriminant
/// and passes that on to `resolve_error`.
fn import_resolving_error(&self, e: ImportResolvingError) {
// 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 {
let mut import_resolutions = e.source_module.import_resolutions.borrow_mut();
let resolution = import_resolutions.entry((target, ValueNS)).or_insert_with(|| {
debug!("(resolving import error) adding import resolution for `{}`",
target);
ImportResolution::new(e.import_directive.id,
e.import_directive.is_public)
});
if resolution.target.is_none() {
debug!("(resolving import error) adding fake target to import resolution of `{}`",
target);
let name_binding = NameBinding {
modifiers: DefModifiers::IMPORTABLE,
def_or_module: DefOrModule::Def(Def::Err),
span: None,
};
// Create a fake target pointing to a fake name binding in our
// own module
let target = Target::new(e.source_module,
name_binding,
Shadowable::Always);
resolution.target = Some(target);
}
}
let path = import_path_to_string(&e.import_directive.module_path,
e.import_directive.subclass);
resolve_error(self.resolver,
e.span,
ResolutionError::UnresolvedImport(Some((&path, &e.help))));
}
/// Attempts to resolve imports for the given module and all of its
/// submodules.
fn resolve_imports_for_module_subtree(&mut self,
module_: Module<'b>)
-> Vec<ImportResolvingError> {
-> Vec<ImportResolvingError<'b>> {
let mut errors = Vec::new();
debug!("(resolving imports for module subtree) resolving {}",
module_to_string(&*module_));
@ -232,7 +277,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
}
/// Attempts to resolve imports for the given module only.
fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError> {
fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError<'b>> {
let mut errors = Vec::new();
if module.all_imports_resolved() {
@ -254,9 +299,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
None => (import_directive.span, String::new()),
};
errors.push(ImportResolvingError {
source_module: module,
import_directive: import_directive.clone(),
span: span,
path: import_path_to_string(&import_directive.module_path,
import_directive.subclass),
help: help,
});
}
@ -784,7 +829,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
namespace_name,
name);
span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
} else {
} else {
let target = Target::new(containing_module,
name_binding.clone(),
import_directive.shadowable);

View File

@ -15,5 +15,8 @@ mod spam {
pub fn ham() { }
}
fn main() { ham(); eggs(); }
//~^ ERROR unresolved name `eggs`
fn main() {
ham();
// Expect eggs to pass because the compiler inserts a fake name for it
eggs();
}

View File

@ -11,10 +11,10 @@
use baz::zed::bar;
//~^ ERROR unresolved import `baz::zed::bar`. Could not find `zed` in `baz`
mod baz {}
mod zed {
pub fn bar() { println!("bar3"); }
}
fn main() { bar(); }
//~^ ERROR unresolved name `bar`
fn main() {
bar();
}

View File

@ -27,8 +27,10 @@ pub fn foo() {}
fn test1() {
use bar::gpriv;
//~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar`
// This should pass because the compiler will insert a fake name binding
// for `gpriv`
gpriv();
//~^ ERROR unresolved name `gpriv`
}
#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }