resolve: Fallback to extern prelude in 2015 imports used from global 2018 edition

This commit is contained in:
Vadim Petrochenkov 2018-11-25 00:25:03 +03:00
parent 5e121756ef
commit d1862b4196
8 changed files with 86 additions and 25 deletions

View File

@ -104,6 +104,7 @@ enum Weak {
enum ScopeSet {
Import(Namespace),
AbsolutePath(Namespace),
Macro(MacroKind),
Module,
}
@ -1008,6 +1009,9 @@ enum ModuleOrUniformRoot<'a> {
/// Regular module.
Module(Module<'a>),
/// Virtual module that denotes resolution in crate root with fallback to extern prelude.
CrateRootAndExternPrelude,
/// Virtual module that denotes resolution in extern prelude.
/// Used for paths starting with `::` on 2018 edition or `extern::`.
ExternPrelude,
@ -1021,9 +1025,11 @@ enum ModuleOrUniformRoot<'a> {
impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
(ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
ptr::eq(lhs, rhs),
(ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) => true,
(ModuleOrUniformRoot::Module(lhs),
ModuleOrUniformRoot::Module(rhs)) => ptr::eq(lhs, rhs),
(ModuleOrUniformRoot::CrateRootAndExternPrelude,
ModuleOrUniformRoot::CrateRootAndExternPrelude) |
(ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) |
(ModuleOrUniformRoot::CurrentScope, ModuleOrUniformRoot::CurrentScope) => true,
_ => false,
}
@ -1243,6 +1249,7 @@ struct UseError<'a> {
#[derive(Clone, Copy, PartialEq, Debug)]
enum AmbiguityKind {
Import,
AbsolutePath,
BuiltinAttr,
DeriveHelper,
LegacyHelperVsPrelude,
@ -1258,6 +1265,8 @@ impl AmbiguityKind {
match self {
AmbiguityKind::Import =>
"name vs any other name during import resolution",
AmbiguityKind::AbsolutePath =>
"name in the crate root vs extern crate during absolute path resolution",
AmbiguityKind::BuiltinAttr =>
"built-in attribute vs any other name",
AmbiguityKind::DeriveHelper =>
@ -2226,6 +2235,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
ident.span = ident.span.modern();
ident.span.adjust(Mark::root());
}
ModuleOrUniformRoot::CrateRootAndExternPrelude |
ModuleOrUniformRoot::CurrentScope => {
// No adjustments
}
@ -3791,6 +3801,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
module = Some(ModuleOrUniformRoot::ExternPrelude);
continue;
}
if name == keywords::CrateRoot.name() &&
ident.span.rust_2015() && self.session.rust_2018() {
// `::a::b` from 2015 macro on 2018 global edition
module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
continue;
}
if name == keywords::CrateRoot.name() ||
name == keywords::Crate.name() ||
name == keywords::DollarCrate.name() {

View File

@ -625,13 +625,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// Go through all the scopes and try to resolve the name.
let rust_2015 = orig_ident.span.rust_2015();
let (ns, macro_kind, is_import) = match scope_set {
ScopeSet::Import(ns) => (ns, None, true),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
ScopeSet::Module => (TypeNS, None, false),
let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
ScopeSet::Import(ns) => (ns, None, true, false),
ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
ScopeSet::Module => (TypeNS, None, false, false),
};
let mut where_to_resolve = match ns {
_ if is_import && rust_2015 => WhereToResolve::CrateRoot,
_ if is_absolute_path || is_import && rust_2015 => WhereToResolve::CrateRoot,
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
MacroNS => WhereToResolve::DeriveHelpers,
};
@ -761,7 +762,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
}
WhereToResolve::ExternPrelude => {
if use_prelude {
if use_prelude || is_absolute_path {
match self.extern_prelude_get(ident, !record_used) {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::determined(
@ -827,6 +828,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let ambiguity_error_kind = if is_import {
Some(AmbiguityKind::Import)
} else if is_absolute_path {
Some(AmbiguityKind::AbsolutePath)
} else if innermost_def == builtin || def == builtin {
Some(AmbiguityKind::BuiltinAttr)
} else if innermost_def == derive_helper || def == derive_helper {
@ -894,10 +897,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
LegacyScope::Uninitialized => unreachable!(),
}
WhereToResolve::CrateRoot => match ns {
WhereToResolve::CrateRoot if is_import => match ns {
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
MacroNS => WhereToResolve::DeriveHelpers,
}
WhereToResolve::CrateRoot if is_absolute_path => match ns {
TypeNS => {
ident.span.adjust(Mark::root());
WhereToResolve::ExternPrelude
}
ValueNS | MacroNS => break,
}
WhereToResolve::CrateRoot => unreachable!(),
WhereToResolve::Module(module) => {
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => WhereToResolve::Module(parent_module),
@ -915,6 +926,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
WhereToResolve::ExternPrelude if is_absolute_path => break,
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
WhereToResolve::StdLibPrelude => match ns {

View File

@ -162,6 +162,15 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
ModuleOrUniformRoot::CrateRootAndExternPrelude => {
assert!(!restricted_shadowing);
let parent_scope = self.dummy_parent_scope();
let binding = self.early_resolve_ident_in_lexical_scope(
ident, ScopeSet::AbsolutePath(ns), &parent_scope,
record_used, record_used, path_span,
);
return binding.map_err(|determinacy| (determinacy, Weak::No));
}
ModuleOrUniformRoot::ExternPrelude => {
assert!(!restricted_shadowing);
return if let Some(binding) = self.extern_prelude_get(ident, !record_used) {

View File

@ -7,7 +7,7 @@ macro_rules! gen_imports { () => {
fn check_absolute() {
::absolute::Path;
// ::std::collections::LinkedList::<u8>::new(); // FIXME
::std::collections::LinkedList::<u8>::new();
}
}}
@ -27,4 +27,5 @@ macro_rules! gen_gated { () => {
#[macro_export]
macro_rules! gen_ambiguous { () => {
use Ambiguous;
type A = ::edition_imports_2015::Path;
}}

View File

@ -1,4 +1,3 @@
// compile-pass
// edition:2018
// aux-build:edition-imports-2015.rs
@ -22,12 +21,7 @@ mod check {
}
mod check_glob {
gen_glob!(); // OK
fn check() {
import::Path;
absolute::Path;
}
gen_glob!(); //~ ERROR cannot glob-import all possible crates
}
fn main() {}

View File

@ -0,0 +1,10 @@
error: cannot glob-import all possible crates
--> $DIR/edition-imports-2018.rs:24:5
|
LL | gen_glob!(); //~ ERROR cannot glob-import all possible crates
| ^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error

View File

@ -1,9 +1,12 @@
// edition:2018
// compile-flags:--extern edition_imports_2015
// aux-build:edition-imports-2015.rs
// error-pattern: `Ambiguous` is ambiguous
// error-pattern: `edition_imports_2015` is ambiguous
#[macro_use]
extern crate edition_imports_2015;
mod edition_imports_2015 {
pub struct Path;
}
pub struct Ambiguous {}
@ -11,7 +14,7 @@ mod check {
pub struct Ambiguous {}
fn check() {
gen_ambiguous!();
edition_imports_2015::gen_ambiguous!();
}
}

View File

@ -1,21 +1,37 @@
error[E0659]: `Ambiguous` is ambiguous (name vs any other name during import resolution)
--> <::edition_imports_2015::gen_ambiguous macros>:1:15
|
LL | ( ) => { use Ambiguous ; }
LL | ( ) => { use Ambiguous ; type A = :: edition_imports_2015 :: Path ; }
| ^^^^^^^^^ ambiguous name
|
note: `Ambiguous` could refer to the struct defined here
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:8:1
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:11:1
|
LL | pub struct Ambiguous {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: `Ambiguous` could also refer to the struct defined here
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:11:5
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:14:5
|
LL | pub struct Ambiguous {}
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::Ambiguous` to refer to this struct unambiguously
error: aborting due to previous error
error[E0659]: `edition_imports_2015` is ambiguous (name in the crate root vs extern crate during absolute path resolution)
--> <::edition_imports_2015::gen_ambiguous macros>:1:39
|
LL | ( ) => { use Ambiguous ; type A = :: edition_imports_2015 :: Path ; }
| ^^^^^^^^^^^^^^^^^^^^ ambiguous name
|
= note: `edition_imports_2015` could refer to an extern crate passed with `--extern`
= help: use `::edition_imports_2015` to refer to this extern crate unambiguously
note: `edition_imports_2015` could also refer to the module defined here
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:7:1
|
LL | / mod edition_imports_2015 {
LL | | pub struct Path;
LL | | }
| |_^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0659`.