Skip to content

Commit f7e7b3a

Browse files
petrochenkovpietroalbini
authored andcommitted
resolve: Desugar empty import groups into synthetic dummy imports
so that they are correctly resolved on 2018 edition
1 parent 540d837 commit f7e7b3a

File tree

7 files changed

+51
-98
lines changed

7 files changed

+51
-98
lines changed

src/librustc/hir/lowering.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3094,7 +3094,8 @@ impl<'a> LoweringContext<'a> {
30943094
// Privatize the degenerate import base, used only to check
30953095
// the stability of `use a::{};`, to avoid it showing up as
30963096
// a re-export by accident when `pub`, e.g. in documentation.
3097-
let path = P(self.lower_path(id, &prefix, ParamMode::Explicit));
3097+
let def = self.expect_full_def_from_use(id).next().unwrap_or(Def::Err);
3098+
let path = P(self.lower_path_extra(def, &prefix, None, ParamMode::Explicit, None));
30983099
*vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited);
30993100
hir::ItemKind::Use(path, hir::UseKind::ListStem)
31003101
}

src/librustc_resolve/build_reduced_graph.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
250250
uniform_paths_canary_emitted = true;
251251
}
252252

253+
let empty_for_self = |prefix: &[Segment]| {
254+
prefix.is_empty() ||
255+
prefix.len() == 1 && prefix[0].ident.name == keywords::CrateRoot.name()
256+
};
253257
match use_tree.kind {
254258
ast::UseTreeKind::Simple(rename, ..) => {
255259
let mut ident = use_tree.ident();
@@ -262,10 +266,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
262266
if source.name == keywords::SelfValue.name() {
263267
type_ns_only = true;
264268

265-
let empty_prefix = module_path.last().map_or(true, |ident| {
266-
ident.name == keywords::CrateRoot.name()
267-
});
268-
if empty_prefix {
269+
if empty_for_self(&module_path) {
269270
resolve_error(
270271
self,
271272
use_tree.span,
@@ -394,6 +395,30 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
394395
parent_scope.clone(), item, vis, root_span,
395396
);
396397
}
398+
399+
// Empty groups `a::b::{}` are turned into synthetic `self` imports
400+
// `a::b::c::{self as _}`, so that their prefixes are correctly
401+
// resolved and checked for privacy/stability/etc.
402+
if items.is_empty() && !empty_for_self(&prefix) {
403+
let new_span = prefix[prefix.len() - 1].ident.span;
404+
let tree = ast::UseTree {
405+
prefix: ast::Path::from_ident(
406+
Ident::new(keywords::SelfValue.name(), new_span)
407+
),
408+
kind: ast::UseTreeKind::Simple(
409+
Some(Ident::new(keywords::Underscore.name().gensymed(), new_span)),
410+
ast::DUMMY_NODE_ID,
411+
ast::DUMMY_NODE_ID,
412+
),
413+
span: use_tree.span,
414+
};
415+
self.build_reduced_graph_for_use_tree(
416+
// This particular use tree
417+
&tree, id, &prefix, true, uniform_paths_canary_emitted,
418+
// The whole `use` item
419+
parent_scope.clone(), item, ty::Visibility::Invisible, root_span,
420+
);
421+
}
397422
}
398423
}
399424
}

src/librustc_resolve/lib.rs

+7-65
Original file line numberDiff line numberDiff line change
@@ -482,23 +482,21 @@ enum PathSource<'a> {
482482
TraitItem(Namespace),
483483
// Path in `pub(path)`
484484
Visibility,
485-
// Path in `use a::b::{...};`
486-
ImportPrefix,
487485
}
488486

489487
impl<'a> PathSource<'a> {
490488
fn namespace(self) -> Namespace {
491489
match self {
492490
PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
493-
PathSource::Visibility | PathSource::ImportPrefix => TypeNS,
491+
PathSource::Visibility => TypeNS,
494492
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
495493
PathSource::TraitItem(ns) => ns,
496494
}
497495
}
498496

499497
fn global_by_default(self) -> bool {
500498
match self {
501-
PathSource::Visibility | PathSource::ImportPrefix => true,
499+
PathSource::Visibility => true,
502500
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
503501
PathSource::Struct | PathSource::TupleStruct |
504502
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
@@ -510,7 +508,7 @@ impl<'a> PathSource<'a> {
510508
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
511509
PathSource::Struct | PathSource::TupleStruct => true,
512510
PathSource::Trait(_) | PathSource::TraitItem(..) |
513-
PathSource::Visibility | PathSource::ImportPrefix => false,
511+
PathSource::Visibility => false,
514512
}
515513
}
516514

@@ -522,7 +520,6 @@ impl<'a> PathSource<'a> {
522520
PathSource::Struct => "struct, variant or union type",
523521
PathSource::TupleStruct => "tuple struct/variant",
524522
PathSource::Visibility => "module",
525-
PathSource::ImportPrefix => "module or enum",
526523
PathSource::TraitItem(ns) => match ns {
527524
TypeNS => "associated type",
528525
ValueNS => "method or associated constant",
@@ -587,10 +584,6 @@ impl<'a> PathSource<'a> {
587584
Def::AssociatedTy(..) if ns == TypeNS => true,
588585
_ => false,
589586
},
590-
PathSource::ImportPrefix => match def {
591-
Def::Mod(..) | Def::Enum(..) => true,
592-
_ => false,
593-
},
594587
PathSource::Visibility => match def {
595588
Def::Mod(..) => true,
596589
_ => false,
@@ -626,8 +619,8 @@ impl<'a> PathSource<'a> {
626619
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
627620
(PathSource::TraitItem(..), true) => "E0575",
628621
(PathSource::TraitItem(..), false) => "E0576",
629-
(PathSource::Visibility, true) | (PathSource::ImportPrefix, true) => "E0577",
630-
(PathSource::Visibility, false) | (PathSource::ImportPrefix, false) => "E0578",
622+
(PathSource::Visibility, true) => "E0577",
623+
(PathSource::Visibility, false) => "E0578",
631624
}
632625
}
633626
}
@@ -2298,66 +2291,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
22982291
});
22992292
}
23002293

2301-
ItemKind::Use(ref use_tree) => {
2302-
// Imports are resolved as global by default, add starting root segment.
2303-
let path = Path {
2304-
segments: use_tree.prefix.make_root().into_iter().collect(),
2305-
span: use_tree.span,
2306-
};
2307-
self.resolve_use_tree(item.id, use_tree.span, item.id, use_tree, &path);
2308-
}
2309-
2310-
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => {
2294+
ItemKind::Use(..) | ItemKind::ExternCrate(..) |
2295+
ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
23112296
// do nothing, these are just around to be encoded
23122297
}
23132298

23142299
ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
23152300
}
23162301
}
23172302

2318-
/// For the most part, use trees are desugared into `ImportDirective` instances
2319-
/// when building the reduced graph (see `build_reduced_graph_for_use_tree`). But
2320-
/// there is one special case we handle here: an empty nested import like
2321-
/// `a::{b::{}}`, which desugares into...no import directives.
2322-
fn resolve_use_tree(
2323-
&mut self,
2324-
root_id: NodeId,
2325-
root_span: Span,
2326-
id: NodeId,
2327-
use_tree: &ast::UseTree,
2328-
prefix: &Path,
2329-
) {
2330-
match use_tree.kind {
2331-
ast::UseTreeKind::Nested(ref items) => {
2332-
let path = Path {
2333-
segments: prefix.segments
2334-
.iter()
2335-
.chain(use_tree.prefix.segments.iter())
2336-
.cloned()
2337-
.collect(),
2338-
span: prefix.span.to(use_tree.prefix.span),
2339-
};
2340-
2341-
if items.is_empty() {
2342-
// Resolve prefix of an import with empty braces (issue #28388).
2343-
self.smart_resolve_path_with_crate_lint(
2344-
id,
2345-
None,
2346-
&path,
2347-
PathSource::ImportPrefix,
2348-
CrateLint::UsePath { root_id, root_span },
2349-
);
2350-
} else {
2351-
for &(ref tree, nested_id) in items {
2352-
self.resolve_use_tree(root_id, root_span, nested_id, tree, &path);
2353-
}
2354-
}
2355-
}
2356-
ast::UseTreeKind::Simple(..) => {},
2357-
ast::UseTreeKind::Glob => {},
2358-
}
2359-
}
2360-
23612303
fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F)
23622304
where F: FnOnce(&mut Resolver)
23632305
{

src/test/ui/issues/issue-28388-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
1212

13-
use foo::{}; //~ ERROR cannot find module or enum `foo` in the crate root
13+
use foo::{}; //~ ERROR unresolved import `foo`
1414

1515
fn main() {}
+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
error[E0578]: cannot find module or enum `foo` in the crate root
1+
error[E0432]: unresolved import `foo`
22
--> $DIR/issue-28388-1.rs:13:5
33
|
4-
LL | use foo::{}; //~ ERROR cannot find module or enum `foo` in the crate root
5-
| ^^^ not found in the crate root
4+
LL | use foo::{}; //~ ERROR unresolved import `foo`
5+
| ^^^^^^^ no `foo` in the root
66

77
error: aborting due to previous error
88

9-
For more information about this error, try `rustc --explain E0578`.
9+
For more information about this error, try `rustc --explain E0432`.

src/test/ui/resolve/resolve-bad-import-prefix.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use {}; // OK
1717
use ::{}; // OK
1818
use m::{}; // OK
1919
use E::{}; // OK
20-
use S::{}; //~ ERROR expected module or enum, found struct `S`
21-
use Tr::{}; //~ ERROR expected module or enum, found trait `Tr`
22-
use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root
20+
use S::{}; // FIXME, this and `use S::{self};` should be an error
21+
use Tr::{}; // FIXME, this and `use Tr::{self};` should be an error
22+
use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
2323

2424
fn main () {}
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
1-
error[E0577]: expected module or enum, found struct `S`
2-
--> $DIR/resolve-bad-import-prefix.rs:20:5
3-
|
4-
LL | use S::{}; //~ ERROR expected module or enum, found struct `S`
5-
| -^^^^
6-
| |
7-
| did you mean `E`?
8-
9-
error[E0577]: expected module or enum, found trait `Tr`
10-
--> $DIR/resolve-bad-import-prefix.rs:21:5
11-
|
12-
LL | use Tr::{}; //~ ERROR expected module or enum, found trait `Tr`
13-
| ^^^^^^ not a module or enum
14-
15-
error[E0578]: cannot find module or enum `Nonexistent` in the crate root
1+
error[E0432]: unresolved import `Nonexistent`
162
--> $DIR/resolve-bad-import-prefix.rs:22:5
173
|
18-
LL | use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root
19-
| ^^^^^^^^^^^ not found in the crate root
4+
LL | use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
5+
| ^^^^^^^^^^^^^^^ no `Nonexistent` in the root
206

21-
error: aborting due to 3 previous errors
7+
error: aborting due to previous error
228

23-
Some errors occurred: E0577, E0578.
24-
For more information about an error, try `rustc --explain E0577`.
9+
For more information about this error, try `rustc --explain E0432`.

0 commit comments

Comments
 (0)