resolve: Desugar empty import groups into synthetic dummy imports
so that they are correctly resolved on 2018 edition
This commit is contained in:
parent
1f257bd022
commit
c57f0a7201
7 changed files with 51 additions and 98 deletions
|
@ -3133,7 +3133,8 @@ impl<'a> LoweringContext<'a> {
|
||||||
// Privatize the degenerate import base, used only to check
|
// Privatize the degenerate import base, used only to check
|
||||||
// the stability of `use a::{};`, to avoid it showing up as
|
// the stability of `use a::{};`, to avoid it showing up as
|
||||||
// a re-export by accident when `pub`, e.g. in documentation.
|
// 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);
|
*vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited);
|
||||||
hir::ItemKind::Use(path, hir::UseKind::ListStem)
|
hir::ItemKind::Use(path, hir::UseKind::ListStem)
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,6 +253,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
uniform_paths_canary_emitted = true;
|
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 {
|
match use_tree.kind {
|
||||||
ast::UseTreeKind::Simple(rename, ..) => {
|
ast::UseTreeKind::Simple(rename, ..) => {
|
||||||
let mut ident = use_tree.ident();
|
let mut ident = use_tree.ident();
|
||||||
|
@ -265,10 +269,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
if source.ident.name == keywords::SelfValue.name() {
|
if source.ident.name == keywords::SelfValue.name() {
|
||||||
type_ns_only = true;
|
type_ns_only = true;
|
||||||
|
|
||||||
let empty_prefix = module_path.last().map_or(true, |seg| {
|
if empty_for_self(&module_path) {
|
||||||
seg.ident.name == keywords::CrateRoot.name()
|
|
||||||
});
|
|
||||||
if empty_prefix {
|
|
||||||
resolve_error(
|
resolve_error(
|
||||||
self,
|
self,
|
||||||
use_tree.span,
|
use_tree.span,
|
||||||
|
@ -400,6 +401,30 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
parent_scope.clone(), item, vis, root_span,
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -482,15 +482,13 @@ enum PathSource<'a> {
|
||||||
TraitItem(Namespace),
|
TraitItem(Namespace),
|
||||||
// Path in `pub(path)`
|
// Path in `pub(path)`
|
||||||
Visibility,
|
Visibility,
|
||||||
// Path in `use a::b::{...};`
|
|
||||||
ImportPrefix,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PathSource<'a> {
|
impl<'a> PathSource<'a> {
|
||||||
fn namespace(self) -> Namespace {
|
fn namespace(self) -> Namespace {
|
||||||
match self {
|
match self {
|
||||||
PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
|
PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
|
||||||
PathSource::Visibility | PathSource::ImportPrefix => TypeNS,
|
PathSource::Visibility => TypeNS,
|
||||||
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
|
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
|
||||||
PathSource::TraitItem(ns) => ns,
|
PathSource::TraitItem(ns) => ns,
|
||||||
}
|
}
|
||||||
|
@ -498,7 +496,7 @@ impl<'a> PathSource<'a> {
|
||||||
|
|
||||||
fn global_by_default(self) -> bool {
|
fn global_by_default(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PathSource::Visibility | PathSource::ImportPrefix => true,
|
PathSource::Visibility => true,
|
||||||
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
||||||
PathSource::Struct | PathSource::TupleStruct |
|
PathSource::Struct | PathSource::TupleStruct |
|
||||||
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
|
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
|
||||||
|
@ -510,7 +508,7 @@ impl<'a> PathSource<'a> {
|
||||||
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
||||||
PathSource::Struct | PathSource::TupleStruct => true,
|
PathSource::Struct | PathSource::TupleStruct => true,
|
||||||
PathSource::Trait(_) | PathSource::TraitItem(..) |
|
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::Struct => "struct, variant or union type",
|
||||||
PathSource::TupleStruct => "tuple struct/variant",
|
PathSource::TupleStruct => "tuple struct/variant",
|
||||||
PathSource::Visibility => "module",
|
PathSource::Visibility => "module",
|
||||||
PathSource::ImportPrefix => "module or enum",
|
|
||||||
PathSource::TraitItem(ns) => match ns {
|
PathSource::TraitItem(ns) => match ns {
|
||||||
TypeNS => "associated type",
|
TypeNS => "associated type",
|
||||||
ValueNS => "method or associated constant",
|
ValueNS => "method or associated constant",
|
||||||
|
@ -587,10 +584,6 @@ impl<'a> PathSource<'a> {
|
||||||
Def::AssociatedTy(..) if ns == TypeNS => true,
|
Def::AssociatedTy(..) if ns == TypeNS => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
PathSource::ImportPrefix => match def {
|
|
||||||
Def::Mod(..) | Def::Enum(..) => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
PathSource::Visibility => match def {
|
PathSource::Visibility => match def {
|
||||||
Def::Mod(..) => true,
|
Def::Mod(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -626,8 +619,8 @@ impl<'a> PathSource<'a> {
|
||||||
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
|
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
|
||||||
(PathSource::TraitItem(..), true) => "E0575",
|
(PathSource::TraitItem(..), true) => "E0575",
|
||||||
(PathSource::TraitItem(..), false) => "E0576",
|
(PathSource::TraitItem(..), false) => "E0576",
|
||||||
(PathSource::Visibility, true) | (PathSource::ImportPrefix, true) => "E0577",
|
(PathSource::Visibility, true) => "E0577",
|
||||||
(PathSource::Visibility, false) | (PathSource::ImportPrefix, false) => "E0578",
|
(PathSource::Visibility, false) => "E0578",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2350,16 +2343,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::Use(ref use_tree) => {
|
ItemKind::Use(..) | ItemKind::ExternCrate(..) |
|
||||||
// Imports are resolved as global by default, add starting root segment.
|
ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
|
||||||
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(_) => {
|
|
||||||
// do nothing, these are just around to be encoded
|
// 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)
|
fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F)
|
||||||
where F: FnOnce(&mut Resolver)
|
where F: FnOnce(&mut Resolver)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
|
|
||||||
// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
|
// 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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
--> $DIR/issue-28388-1.rs:13:5
|
||||||
|
|
|
|
||||||
LL | use foo::{}; //~ ERROR cannot find module or enum `foo` in the crate root
|
LL | use foo::{}; //~ ERROR unresolved import `foo`
|
||||||
| ^^^ not found in the crate root
|
| ^^^^^^^ no `foo` in the root
|
||||||
|
|
||||||
error: aborting due to previous error
|
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`.
|
||||||
|
|
|
@ -17,8 +17,8 @@ use {}; // OK
|
||||||
use ::{}; // OK
|
use ::{}; // OK
|
||||||
use m::{}; // OK
|
use m::{}; // OK
|
||||||
use E::{}; // OK
|
use E::{}; // OK
|
||||||
use S::{}; //~ ERROR expected module or enum, found struct `S`
|
use S::{}; // FIXME, this and `use S::{self};` should be an error
|
||||||
use Tr::{}; //~ ERROR expected module or enum, found trait `Tr`
|
use Tr::{}; // FIXME, this and `use Tr::{self};` should be an error
|
||||||
use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root
|
use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
|
||||||
|
|
||||||
fn main () {}
|
fn main () {}
|
||||||
|
|
|
@ -1,24 +1,9 @@
|
||||||
error[E0577]: expected module or enum, found struct `S`
|
error[E0432]: unresolved import `Nonexistent`
|
||||||
--> $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
|
|
||||||
--> $DIR/resolve-bad-import-prefix.rs:22:5
|
--> $DIR/resolve-bad-import-prefix.rs:22:5
|
||||||
|
|
|
|
||||||
LL | use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root
|
LL | use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
|
||||||
| ^^^^^^^^^^^ not found in the crate root
|
| ^^^^^^^^^^^^^^^ 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 this error, try `rustc --explain E0432`.
|
||||||
For more information about an error, try `rustc --explain E0577`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue