From c57f0a7201860eb87ad8df1f3e63ea1ed03dcb40 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Oct 2018 23:38:09 +0300 Subject: [PATCH] resolve: Desugar empty import groups into synthetic dummy imports so that they are correctly resolved on 2018 edition --- src/librustc/hir/lowering.rs | 3 +- src/librustc_resolve/build_reduced_graph.rs | 33 +++++++-- src/librustc_resolve/lib.rs | 72 ++----------------- src/test/ui/issues/issue-28388-1.rs | 2 +- src/test/ui/issues/issue-28388-1.stderr | 8 +-- .../ui/resolve/resolve-bad-import-prefix.rs | 6 +- .../resolve/resolve-bad-import-prefix.stderr | 25 ++----- 7 files changed, 51 insertions(+), 98 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6370a520183..9795c0cba61 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3133,7 +3133,8 @@ impl<'a> LoweringContext<'a> { // Privatize the degenerate import base, used only to check // the stability of `use a::{};`, to avoid it showing up as // a re-export by accident when `pub`, e.g. in documentation. - let path = P(self.lower_path(id, &prefix, ParamMode::Explicit)); + let def = self.expect_full_def_from_use(id).next().unwrap_or(Def::Err); + let path = P(self.lower_path_extra(def, &prefix, None, ParamMode::Explicit, None)); *vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited); hir::ItemKind::Use(path, hir::UseKind::ListStem) } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 328d5bb3af0..bb451f554d6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -253,6 +253,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { uniform_paths_canary_emitted = true; } + let empty_for_self = |prefix: &[Segment]| { + prefix.is_empty() || + prefix.len() == 1 && prefix[0].ident.name == keywords::CrateRoot.name() + }; match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { let mut ident = use_tree.ident(); @@ -265,10 +269,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { if source.ident.name == keywords::SelfValue.name() { type_ns_only = true; - let empty_prefix = module_path.last().map_or(true, |seg| { - seg.ident.name == keywords::CrateRoot.name() - }); - if empty_prefix { + if empty_for_self(&module_path) { resolve_error( self, use_tree.span, @@ -400,6 +401,30 @@ impl<'a, 'cl> Resolver<'a, 'cl> { parent_scope.clone(), item, vis, root_span, ); } + + // Empty groups `a::b::{}` are turned into synthetic `self` imports + // `a::b::c::{self as _}`, so that their prefixes are correctly + // resolved and checked for privacy/stability/etc. + if items.is_empty() && !empty_for_self(&prefix) { + let new_span = prefix[prefix.len() - 1].ident.span; + let tree = ast::UseTree { + prefix: ast::Path::from_ident( + Ident::new(keywords::SelfValue.name(), new_span) + ), + kind: ast::UseTreeKind::Simple( + Some(Ident::new(keywords::Underscore.name().gensymed(), new_span)), + ast::DUMMY_NODE_ID, + ast::DUMMY_NODE_ID, + ), + span: use_tree.span, + }; + self.build_reduced_graph_for_use_tree( + // This particular use tree + &tree, id, &prefix, true, uniform_paths_canary_emitted, + // The whole `use` item + parent_scope.clone(), item, ty::Visibility::Invisible, root_span, + ); + } } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 397c67e7587..ebd87e87ff6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -482,15 +482,13 @@ enum PathSource<'a> { TraitItem(Namespace), // Path in `pub(path)` Visibility, - // Path in `use a::b::{...};` - ImportPrefix, } impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { PathSource::Type | PathSource::Trait(_) | PathSource::Struct | - PathSource::Visibility | PathSource::ImportPrefix => TypeNS, + PathSource::Visibility => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, PathSource::TraitItem(ns) => ns, } @@ -498,7 +496,7 @@ impl<'a> PathSource<'a> { fn global_by_default(self) -> bool { match self { - PathSource::Visibility | PathSource::ImportPrefix => true, + PathSource::Visibility => true, PathSource::Type | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct | PathSource::Trait(_) | PathSource::TraitItem(..) => false, @@ -510,7 +508,7 @@ impl<'a> PathSource<'a> { PathSource::Type | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct => true, PathSource::Trait(_) | PathSource::TraitItem(..) | - PathSource::Visibility | PathSource::ImportPrefix => false, + PathSource::Visibility => false, } } @@ -522,7 +520,6 @@ impl<'a> PathSource<'a> { PathSource::Struct => "struct, variant or union type", PathSource::TupleStruct => "tuple struct/variant", PathSource::Visibility => "module", - PathSource::ImportPrefix => "module or enum", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", @@ -587,10 +584,6 @@ impl<'a> PathSource<'a> { Def::AssociatedTy(..) if ns == TypeNS => true, _ => false, }, - PathSource::ImportPrefix => match def { - Def::Mod(..) | Def::Enum(..) => true, - _ => false, - }, PathSource::Visibility => match def { Def::Mod(..) => true, _ => false, @@ -626,8 +619,8 @@ impl<'a> PathSource<'a> { (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531", (PathSource::TraitItem(..), true) => "E0575", (PathSource::TraitItem(..), false) => "E0576", - (PathSource::Visibility, true) | (PathSource::ImportPrefix, true) => "E0577", - (PathSource::Visibility, false) | (PathSource::ImportPrefix, false) => "E0578", + (PathSource::Visibility, true) => "E0577", + (PathSource::Visibility, false) => "E0578", } } } @@ -2350,16 +2343,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { }); } - ItemKind::Use(ref use_tree) => { - // Imports are resolved as global by default, add starting root segment. - let path = Path { - segments: use_tree.prefix.make_root().into_iter().collect(), - span: use_tree.span, - }; - self.resolve_use_tree(item.id, use_tree.span, item.id, use_tree, &path); - } - - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => { + ItemKind::Use(..) | ItemKind::ExternCrate(..) | + ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => { // do nothing, these are just around to be encoded } @@ -2367,49 +2352,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } } - /// For the most part, use trees are desugared into `ImportDirective` instances - /// when building the reduced graph (see `build_reduced_graph_for_use_tree`). But - /// there is one special case we handle here: an empty nested import like - /// `a::{b::{}}`, which desugares into...no import directives. - fn resolve_use_tree( - &mut self, - root_id: NodeId, - root_span: Span, - id: NodeId, - use_tree: &ast::UseTree, - prefix: &Path, - ) { - match use_tree.kind { - ast::UseTreeKind::Nested(ref items) => { - let path = Path { - segments: prefix.segments - .iter() - .chain(use_tree.prefix.segments.iter()) - .cloned() - .collect(), - span: prefix.span.to(use_tree.prefix.span), - }; - - if items.is_empty() { - // Resolve prefix of an import with empty braces (issue #28388). - self.smart_resolve_path_with_crate_lint( - id, - None, - &path, - PathSource::ImportPrefix, - CrateLint::UsePath { root_id, root_span }, - ); - } else { - for &(ref tree, nested_id) in items { - self.resolve_use_tree(root_id, root_span, nested_id, tree, &path); - } - } - } - ast::UseTreeKind::Simple(..) => {}, - ast::UseTreeKind::Glob => {}, - } - } - fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F) where F: FnOnce(&mut Resolver) { diff --git a/src/test/ui/issues/issue-28388-1.rs b/src/test/ui/issues/issue-28388-1.rs index 187d91731d0..b0418a513e3 100644 --- a/src/test/ui/issues/issue-28388-1.rs +++ b/src/test/ui/issues/issue-28388-1.rs @@ -10,6 +10,6 @@ // Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. -use foo::{}; //~ ERROR cannot find module or enum `foo` in the crate root +use foo::{}; //~ ERROR unresolved import `foo` fn main() {} diff --git a/src/test/ui/issues/issue-28388-1.stderr b/src/test/ui/issues/issue-28388-1.stderr index 9f4b6cb56e7..f93252f1d7d 100644 --- a/src/test/ui/issues/issue-28388-1.stderr +++ b/src/test/ui/issues/issue-28388-1.stderr @@ -1,9 +1,9 @@ -error[E0578]: cannot find module or enum `foo` in the crate root +error[E0432]: unresolved import `foo` --> $DIR/issue-28388-1.rs:13:5 | -LL | use foo::{}; //~ ERROR cannot find module or enum `foo` in the crate root - | ^^^ not found in the crate root +LL | use foo::{}; //~ ERROR unresolved import `foo` + | ^^^^^^^ no `foo` in the root error: aborting due to previous error -For more information about this error, try `rustc --explain E0578`. +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/resolve/resolve-bad-import-prefix.rs b/src/test/ui/resolve/resolve-bad-import-prefix.rs index 370782fc7d9..5da5a8c3fef 100644 --- a/src/test/ui/resolve/resolve-bad-import-prefix.rs +++ b/src/test/ui/resolve/resolve-bad-import-prefix.rs @@ -17,8 +17,8 @@ use {}; // OK use ::{}; // OK use m::{}; // OK use E::{}; // OK -use S::{}; //~ ERROR expected module or enum, found struct `S` -use Tr::{}; //~ ERROR expected module or enum, found trait `Tr` -use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root +use S::{}; // FIXME, this and `use S::{self};` should be an error +use Tr::{}; // FIXME, this and `use Tr::{self};` should be an error +use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent` fn main () {} diff --git a/src/test/ui/resolve/resolve-bad-import-prefix.stderr b/src/test/ui/resolve/resolve-bad-import-prefix.stderr index 76d0c035335..c4d9b1d0075 100644 --- a/src/test/ui/resolve/resolve-bad-import-prefix.stderr +++ b/src/test/ui/resolve/resolve-bad-import-prefix.stderr @@ -1,24 +1,9 @@ -error[E0577]: expected module or enum, found struct `S` - --> $DIR/resolve-bad-import-prefix.rs:20:5 - | -LL | use S::{}; //~ ERROR expected module or enum, found struct `S` - | -^^^^ - | | - | did you mean `E`? - -error[E0577]: expected module or enum, found trait `Tr` - --> $DIR/resolve-bad-import-prefix.rs:21:5 - | -LL | use Tr::{}; //~ ERROR expected module or enum, found trait `Tr` - | ^^^^^^ not a module or enum - -error[E0578]: cannot find module or enum `Nonexistent` in the crate root +error[E0432]: unresolved import `Nonexistent` --> $DIR/resolve-bad-import-prefix.rs:22:5 | -LL | use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root - | ^^^^^^^^^^^ not found in the crate root +LL | use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent` + | ^^^^^^^^^^^^^^^ no `Nonexistent` in the root -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0577, E0578. -For more information about an error, try `rustc --explain E0577`. +For more information about this error, try `rustc --explain E0432`.