resolve: Resolve single-segment imports using in-scope resolution on 2018 edition

This commit is contained in:
Vadim Petrochenkov 2018-11-09 01:29:07 +03:00
parent 1cfd08c0c4
commit 07af4ec7a2
7 changed files with 148 additions and 124 deletions

View File

@ -809,6 +809,7 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>,
ModuleOrUniformRoot::Module(module),
ident,
MacroNS,
None,
false,
span,
);

View File

@ -103,6 +103,15 @@ enum DeterminacyExt {
WeakUndetermined,
}
impl DeterminacyExt {
fn to_determinacy(self) -> Determinacy {
match self {
DeterminacyExt::Determined => Determined,
DeterminacyExt::Undetermined | DeterminacyExt::WeakUndetermined => Undetermined,
}
}
}
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
path: Path,
@ -998,15 +1007,22 @@ fn def(self) -> Def {
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
enum UniformRootKind {
CurrentScope,
ExternPrelude,
}
#[derive(Copy, Clone, Debug)]
pub enum ModuleOrUniformRoot<'a> {
enum ModuleOrUniformRoot<'a> {
/// Regular module.
Module(Module<'a>),
/// The `{{root}}` (`CrateRoot` aka "global") / `extern` initial segment
/// in which external crates resolve, and also `crate` (only in `{{root}}`,
/// but *not* `extern`), in the Rust 2018 edition.
UniformRoot(Name),
/// This "virtual module" denotes either resolution in extern prelude
/// for paths starting with `::` on 2018 edition or `extern::`,
/// or resolution in current scope for single-segment imports.
UniformRoot(UniformRootKind),
}
#[derive(Clone, Debug)]
@ -2158,23 +2174,31 @@ fn hygienic_lexical_parent_with_compatibility_fallback(&mut self, module: Module
None
}
fn resolve_ident_in_module(&mut self,
module: ModuleOrUniformRoot<'a>,
mut ident: Ident,
ns: Namespace,
record_used: bool,
span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> {
fn resolve_ident_in_module(
&mut self,
module: ModuleOrUniformRoot<'a>,
mut ident: Ident,
ns: Namespace,
parent_scope: Option<&ParentScope<'a>>,
record_used: bool,
path_span: Span
) -> Result<&'a NameBinding<'a>, Determinacy> {
ident.span = ident.span.modern();
let orig_current_module = self.current_module;
if let ModuleOrUniformRoot::Module(module) = module {
if let Some(def) = ident.span.adjust(module.expansion) {
self.current_module = self.macro_def_scope(def);
match module {
ModuleOrUniformRoot::Module(module) => {
if let Some(def) = ident.span.adjust(module.expansion) {
self.current_module = self.macro_def_scope(def);
}
}
ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude) => {
ident.span.adjust(Mark::root());
}
_ => {}
}
let result = self.resolve_ident_in_module_unadjusted(
module, ident, ns, record_used, span,
);
let result = self.resolve_ident_in_module_unadjusted_ext(
module, ident, ns, parent_scope, false, record_used, path_span,
).map_err(DeterminacyExt::to_determinacy);
self.current_module = orig_current_module;
result
}
@ -2671,6 +2695,7 @@ fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err:
ModuleOrUniformRoot::Module(module),
ident,
ns,
None,
false,
span,
).is_err() {
@ -3699,9 +3724,9 @@ fn resolve_path(
continue;
}
if name == keywords::Extern.name() ||
name == keywords::CrateRoot.name() &&
self.session.rust_2018() {
module = Some(ModuleOrUniformRoot::UniformRoot(name));
name == keywords::CrateRoot.name() && self.session.rust_2018() {
module =
Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude));
continue;
}
if name == keywords::CrateRoot.name() ||
@ -3731,7 +3756,7 @@ fn resolve_path(
}
let binding = if let Some(module) = module {
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
self.resolve_ident_in_module(module, ident, ns, None, record_used, path_span)
} else if opt_ns.is_none() || opt_ns == Some(MacroNS) {
assert!(ns == TypeNS);
self.early_resolve_ident_in_lexical_scope(ident, ns, None, opt_ns.is_none(),
@ -3751,7 +3776,7 @@ fn resolve_path(
def, path.len() - 1
));
}
_ => Err(if record_used { Determined } else { Undetermined }),
_ => Err(Determinacy::determined(record_used)),
}
};
@ -3825,7 +3850,8 @@ fn resolve_path(
PathResult::Module(match module {
Some(module) => module,
None if path.is_empty() => ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name()),
None if path.is_empty() =>
ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope),
_ => span_bug!(path_span, "resolve_path: non-empty path `{:?}` has no module", path),
})
}
@ -4037,6 +4063,7 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
ModuleOrUniformRoot::Module(module),
ident,
ns,
None,
false,
module.span,
) {
@ -4359,6 +4386,7 @@ fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
ModuleOrUniformRoot::Module(module),
ident,
ns,
None,
false,
module.span,
).is_ok() {
@ -4945,6 +4973,10 @@ fn report_conflict<'b>(&mut self,
fn extern_prelude_get(&mut self, ident: Ident, speculative: bool, skip_feature_gate: bool)
-> Option<&'a NameBinding<'a>> {
if ident.is_path_segment_keyword() {
// Make sure `self`, `super` etc produce an error when passed to here.
return None;
}
self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| {
if let Some(binding) = entry.extern_crate_item {
if !speculative && !skip_feature_gate && entry.introduced_by_item &&

View File

@ -371,11 +371,11 @@ fn check_unused_macros(&self) {
}
impl<'a, 'cl> Resolver<'a, 'cl> {
pub fn dummy_parent_scope(&mut self) -> ParentScope<'a> {
pub fn dummy_parent_scope(&self) -> ParentScope<'a> {
self.invoc_parent_scope(Mark::root(), Vec::new())
}
fn invoc_parent_scope(&mut self, invoc_id: Mark, derives: Vec<ast::Path>) -> ParentScope<'a> {
fn invoc_parent_scope(&self, invoc_id: Mark, derives: Vec<ast::Path>) -> ParentScope<'a> {
let invoc = self.invocations[&invoc_id];
ParentScope {
module: invoc.module.get().nearest_item_scope(),
@ -610,6 +610,11 @@ struct Flags: u8 {
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
ident = ident.modern();
// Make sure `self`, `super` etc produce an error when passed to here.
if ident.is_path_segment_keyword() {
return Err(Determinacy::Determined);
}
// This is *the* result, resolution from the scope closest to the resolved identifier.
// However, sometimes this result is "weak" because it comes from a glob import or
// a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
@ -671,6 +676,7 @@ struct Flags: u8 {
ModuleOrUniformRoot::Module(module),
ident,
ns,
None,
true,
record_used,
path_span,

View File

@ -11,7 +11,7 @@
use self::ImportDirectiveSubclass::*;
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
use {CrateLint, DeterminacyExt, Module, ModuleOrUniformRoot, PerNS};
use {CrateLint, DeterminacyExt, Module, ModuleOrUniformRoot, PerNS, UniformRootKind};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use {Resolver, Segment};
@ -23,7 +23,7 @@
use rustc::ty;
use rustc::lint::builtin::BuiltinLintDiagnostics;
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{CrateNum, DefId};
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::FxHashSet;
@ -61,7 +61,7 @@ pub enum ImportDirectiveSubclass<'a> {
/// One import directive.
#[derive(Debug,Clone)]
pub struct ImportDirective<'a> {
crate struct ImportDirective<'a> {
/// The id of the `extern crate`, `UseTree` etc that imported this `ImportDirective`.
///
/// In the case where the `ImportDirective` was expanded from a "nested" use tree,
@ -144,11 +144,8 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
path_span: Span,
) -> Result<&'a NameBinding<'a>, Determinacy> {
self.resolve_ident_in_module_unadjusted_ext(
module, ident, ns, false, record_used, path_span
).map_err(|determinacy_ext| match determinacy_ext {
DeterminacyExt::Determined => Determined,
DeterminacyExt::Undetermined | DeterminacyExt::WeakUndetermined => Undetermined,
})
module, ident, ns, None, false, record_used, path_span
).map_err(DeterminacyExt::to_determinacy)
}
/// Attempts to resolve `ident` in namespaces `ns` of `module`.
@ -158,87 +155,55 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
module: ModuleOrUniformRoot<'a>,
ident: Ident,
ns: Namespace,
parent_scope: Option<&ParentScope<'a>>,
restricted_shadowing: bool,
record_used: bool,
path_span: Span,
) -> Result<&'a NameBinding<'a>, DeterminacyExt> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
ModuleOrUniformRoot::UniformRoot(root) => {
// HACK(eddyb): `resolve_path` uses `keywords::Invalid` to indicate
// paths of length 0, and currently these are relative `use` paths.
let can_be_relative = !ident.is_path_segment_keyword() &&
root == keywords::Invalid.name();
if can_be_relative {
// Try first to resolve relatively.
let mut ctxt = ident.span.ctxt().modern();
let self_module = self.resolve_self(&mut ctxt, self.current_module);
let binding = self.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(self_module),
ident,
ns,
restricted_shadowing,
record_used,
path_span,
);
// FIXME(eddyb) This may give false negatives, specifically
// if a crate with the same name is found in `extern_prelude`,
// preventing the check below this one from returning `binding`
// in all cases.
//
// That is, if there's no crate with the same name, `binding`
// is always returned, which is the result of doing the exact
// same lookup of `ident`, in the `self` module.
// But when a crate does exist, it will get chosen even when
// macro expansion could result in a success from the lookup
// in the `self` module, later on.
if binding.is_ok() {
return binding;
ModuleOrUniformRoot::UniformRoot(uniform_root_kind) => {
assert!(!restricted_shadowing);
match uniform_root_kind {
UniformRootKind::ExternPrelude => {
return if let Some(binding) =
self.extern_prelude_get(ident, !record_used, false) {
Ok(binding)
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
// Macro-expanded `extern crate` items can add names to extern prelude.
Err(DeterminacyExt::Undetermined)
} else {
Err(DeterminacyExt::Determined)
}
}
UniformRootKind::CurrentScope => {
let parent_scope =
parent_scope.expect("no parent scope for a single-segment import");
// Fall back to resolving to an external crate.
if !(
ns == TypeNS &&
!ident.is_path_segment_keyword() &&
self.extern_prelude.contains_key(&ident.modern())
) {
// ... unless the crate name is not in the `extern_prelude`.
return binding;
if ns == TypeNS {
if ident.name == keywords::Crate.name() ||
ident.name == keywords::DollarCrate.name() {
let module = self.resolve_crate_root(ident);
let binding = (module, ty::Visibility::Public,
module.span, Mark::root())
.to_name_binding(self.arenas);
return Ok(binding);
} else if ident.name == keywords::Super.name() ||
ident.name == keywords::SelfValue.name() {
// FIXME: Implement these with renaming requirements so that e.g.
// `use super;` doesn't work, but `use super as name;` does.
}
}
let binding = self.early_resolve_ident_in_lexical_scope(
ident, ns, None, true, parent_scope, record_used, record_used, path_span
);
return binding.map_err(|determinacy| match determinacy {
Determined => DeterminacyExt::Determined,
Undetermined => DeterminacyExt::Undetermined,
});
}
}
let crate_root = if
ns == TypeNS &&
root != keywords::Extern.name() &&
(
ident.name == keywords::Crate.name() ||
ident.name == keywords::DollarCrate.name()
)
{
self.resolve_crate_root(ident)
} else if
ns == TypeNS &&
!ident.is_path_segment_keyword()
{
if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
let module = self.get_module(binding.def().def_id());
self.populate_module_if_necessary(module);
return Ok(binding);
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
// Macro-expanded `extern crate`items still can add names to extern prelude.
return Err(DeterminacyExt::Undetermined);
} else {
return Err(DeterminacyExt::Determined);
}
} else {
return Err(DeterminacyExt::Determined);
};
self.populate_module_if_necessary(crate_root);
let binding = (crate_root, ty::Visibility::Public,
crate_root.span, Mark::root()).to_name_binding(self.arenas);
return Ok(binding);
}
};
@ -312,7 +277,8 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
SingleImport { source, .. } => source,
_ => unreachable!(),
};
match self.resolve_ident_in_module(module, ident, ns, false, path_span) {
match self.resolve_ident_in_module(module, ident, ns, Some(&single_import.parent_scope),
false, path_span) {
Err(Determined) => continue,
Ok(binding) if !self.is_accessible_from(
binding.vis, single_import.parent_scope.module
@ -439,8 +405,8 @@ pub fn add_import_directive(&mut self,
// Given a binding and an import directive that resolves to it,
// return the corresponding binding defined by the import directive.
pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-> &'a NameBinding<'a> {
crate fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-> &'a NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
// c.f. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
!directive.is_glob() && binding.is_extern_crate() {
@ -768,10 +734,9 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
let module = if let Some(module) = directive.imported_module.get() {
module
} else {
let vis = directive.vis.get();
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
let result = self.resolve_path(
&directive.module_path[..],
None,
@ -780,7 +745,7 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
directive.span,
directive.crate_lint(),
);
directive.vis.set(vis);
directive.vis.set(orig_vis);
match result {
PathResult::Module(module) => module,
@ -803,11 +768,15 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
let mut indeterminate = false;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
if let Err(Undetermined) = result[ns].get() {
result[ns].set(this.resolve_ident_in_module(module,
source,
ns,
false,
directive.span));
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
let binding = this.resolve_ident_in_module(
module, source, ns, Some(&directive.parent_scope), false, directive.span
);
directive.vis.set(orig_vis);
result[ns].set(binding);
} else {
return
};
@ -940,7 +909,10 @@ fn finalize_import(
if all_ns_err {
let mut all_ns_failed = true;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
if this.resolve_ident_in_module(module, ident, ns, true, span).is_ok() {
let binding = this.resolve_ident_in_module(
module, ident, ns, Some(&directive.parent_scope), true, span
);
if binding.is_ok() {
all_ns_failed = false;
}
});
@ -1140,8 +1112,9 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
if binding.is_import() || binding.is_macro_def() {
let def = binding.def();
if def != Def::Err {
if !def.def_id().is_local() {
self.cstore.export_macros_untracked(def.def_id().krate);
let def_id = def.def_id();
if !def_id.is_local() && def_id.krate != CrateNum::BuiltinMacros {
self.cstore.export_macros_untracked(def_id.krate);
}
reexports.push(Export {
ident: ident.modern(),

View File

@ -1,6 +1,6 @@
// edition:2018
#![feature(alloc)]
#![feature(alloc, underscore_imports)]
extern crate alloc;
@ -23,7 +23,7 @@ fn check() {
}
mod import_in_scope {
use alloc;
use alloc as _;
//~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
use alloc::boxed;
//~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable

View File

@ -1,7 +1,7 @@
error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:26:9
|
LL | use alloc;
LL | use alloc as _;
| ^^^^^
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable

View File

@ -0,0 +1,12 @@
// compile-pass
// edition:2018
#![feature(decl_macro)]
macro check() {
::std::vec::Vec::<u8>::new()
}
fn main() {
check!();
}