Skip to content

Commit 8c77ffb

Browse files
committed
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.
2 parents 54664f1 + 026bcbf commit 8c77ffb

File tree

6 files changed

+71
-20
lines changed

6 files changed

+71
-20
lines changed

src/librustc/middle/def.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl Def {
120120
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
121121
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
122122
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
123-
panic!("attempted .def_id() on invalid {:?}", self)
123+
panic!("attempted .var_id() on invalid {:?}", self)
124124
}
125125
}
126126
}

src/librustc_resolve/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14681468
match search_module.parent_link {
14691469
NoParentLink => {
14701470
// No more parents. This module was unresolved.
1471-
debug!("(resolving item in lexical scope) unresolved module");
1471+
debug!("(resolving item in lexical scope) unresolved module: no parent module");
14721472
return Failed(None);
14731473
}
14741474
ModuleParentLink(parent_module_node, _) => {
@@ -3109,7 +3109,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31093109
}
31103110
Indeterminate => None,
31113111
Failed(err) => {
3112-
debug!("(resolving item path by identifier in lexical scope) failed to resolve {}",
3112+
debug!("(resolving item path by identifier in lexical scope) failed to \
3113+
resolve `{}`",
31133114
name);
31143115

31153116
if let Some((span, msg)) = err {

src/librustc_resolve/resolve_imports.rs

+56-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use self::ImportDirectiveSubclass::*;
1212

1313
use DefModifiers;
14+
use DefOrModule;
1415
use Module;
1516
use Namespace::{self, TypeNS, ValueNS};
1617
use NameBinding;
@@ -50,7 +51,7 @@ pub enum Shadowable {
5051
}
5152

5253
/// One import directive.
53-
#[derive(Debug)]
54+
#[derive(Debug,Clone)]
5455
pub struct ImportDirective {
5556
pub module_path: Vec<Name>,
5657
pub subclass: ImportDirectiveSubclass,
@@ -140,9 +141,11 @@ impl<'a> ImportResolution<'a> {
140141
}
141142
}
142143

143-
struct ImportResolvingError {
144+
struct ImportResolvingError<'a> {
145+
/// Module where the error happened
146+
source_module: Module<'a>,
147+
import_directive: ImportDirective,
144148
span: Span,
145-
path: String,
146149
help: String,
147150
}
148151

@@ -181,9 +184,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
181184
// resolving failed
182185
if errors.len() > 0 {
183186
for e in errors {
184-
resolve_error(self.resolver,
185-
e.span,
186-
ResolutionError::UnresolvedImport(Some((&e.path, &e.help))));
187+
self.import_resolving_error(e)
187188
}
188189
} else {
189190
// 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> {
200201
}
201202
}
202203

204+
/// Resolves an `ImportResolvingError` into the correct enum discriminant
205+
/// and passes that on to `resolve_error`.
206+
fn import_resolving_error(&self, e: ImportResolvingError) {
207+
// If it's a single failed import then create a "fake" import
208+
// resolution for it so that later resolve stages won't complain.
209+
if let SingleImport(target, _) = e.import_directive.subclass {
210+
let mut import_resolutions = e.source_module.import_resolutions.borrow_mut();
211+
212+
let resolution = import_resolutions.entry((target, ValueNS)).or_insert_with(|| {
213+
debug!("(resolving import error) adding import resolution for `{}`",
214+
target);
215+
216+
ImportResolution::new(e.import_directive.id,
217+
e.import_directive.is_public)
218+
});
219+
220+
if resolution.target.is_none() {
221+
debug!("(resolving import error) adding fake target to import resolution of `{}`",
222+
target);
223+
224+
let name_binding = NameBinding {
225+
modifiers: DefModifiers::IMPORTABLE,
226+
def_or_module: DefOrModule::Def(Def::Err),
227+
span: None,
228+
};
229+
230+
// Create a fake target pointing to a fake name binding in our
231+
// own module
232+
let target = Target::new(e.source_module,
233+
name_binding,
234+
Shadowable::Always);
235+
236+
resolution.target = Some(target);
237+
}
238+
}
239+
240+
let path = import_path_to_string(&e.import_directive.module_path,
241+
e.import_directive.subclass);
242+
243+
resolve_error(self.resolver,
244+
e.span,
245+
ResolutionError::UnresolvedImport(Some((&path, &e.help))));
246+
}
247+
203248
/// Attempts to resolve imports for the given module and all of its
204249
/// submodules.
205250
fn resolve_imports_for_module_subtree(&mut self,
206251
module_: Module<'b>)
207-
-> Vec<ImportResolvingError> {
252+
-> Vec<ImportResolvingError<'b>> {
208253
let mut errors = Vec::new();
209254
debug!("(resolving imports for module subtree) resolving {}",
210255
module_to_string(&*module_));
@@ -232,7 +277,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
232277
}
233278

234279
/// Attempts to resolve imports for the given module only.
235-
fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError> {
280+
fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError<'b>> {
236281
let mut errors = Vec::new();
237282

238283
if module.all_imports_resolved() {
@@ -254,9 +299,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
254299
None => (import_directive.span, String::new()),
255300
};
256301
errors.push(ImportResolvingError {
302+
source_module: module,
303+
import_directive: import_directive.clone(),
257304
span: span,
258-
path: import_path_to_string(&import_directive.module_path,
259-
import_directive.subclass),
260305
help: help,
261306
});
262307
}
@@ -784,7 +829,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
784829
namespace_name,
785830
name);
786831
span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
787-
} else {
832+
} else {
788833
let target = Target::new(containing_module,
789834
name_binding.clone(),
790835
import_directive.shadowable);

src/test/compile-fail/import-from-missing.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ mod spam {
1515
pub fn ham() { }
1616
}
1717

18-
fn main() { ham(); eggs(); }
19-
//~^ ERROR unresolved name `eggs`
18+
fn main() {
19+
ham();
20+
// Expect eggs to pass because the compiler inserts a fake name for it
21+
eggs();
22+
}

src/test/compile-fail/import2.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
use baz::zed::bar;
1212
//~^ ERROR unresolved import `baz::zed::bar`. Could not find `zed` in `baz`
1313

14-
1514
mod baz {}
1615
mod zed {
1716
pub fn bar() { println!("bar3"); }
1817
}
19-
fn main() { bar(); }
20-
//~^ ERROR unresolved name `bar`
18+
fn main() {
19+
bar();
20+
}

src/test/compile-fail/privacy3.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ pub fn foo() {}
2727
fn test1() {
2828
use bar::gpriv;
2929
//~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar`
30+
31+
// This should pass because the compiler will insert a fake name binding
32+
// for `gpriv`
3033
gpriv();
31-
//~^ ERROR unresolved name `gpriv`
3234
}
3335

3436
#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }

0 commit comments

Comments
 (0)