resolve: Fallback to uniform paths in 2015 imports used from global 2018 edition

This commit is contained in:
Vadim Petrochenkov 2018-11-24 15:07:03 +03:00
parent dae4c7b1ff
commit c06e69ee70
9 changed files with 187 additions and 38 deletions

View File

@ -132,9 +132,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// so prefixes are prepended with crate root segment if necessary.
// The root is prepended lazily, when the first non-empty prefix or terminating glob
// appears, so imports in braced groups can have roots prepended independently.
// 2015 identifiers used on global 2018 edition enter special "virtual 2015 mode", don't
// get crate root prepended, but get special treatment during in-scope resolution instead.
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
let crate_root = match prefix_iter.peek() {
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
Some(seg) if !seg.ident.is_path_segment_keyword() &&
seg.ident.span.rust_2015() && self.session.rust_2015() => {
Some(seg.ident.span.ctxt())
}
None if is_glob && use_tree.span.rust_2015() => {

View File

@ -13,6 +13,7 @@
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
@ -2191,28 +2192,45 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_ident_in_module(
&mut self,
module: ModuleOrUniformRoot<'a>,
mut ident: Ident,
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();
self.resolve_ident_in_module_ext(
module, ident, ns, parent_scope, record_used, path_span
).map_err(|(determinacy, _)| determinacy)
}
fn resolve_ident_in_module_ext(
&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, Weak)> {
let orig_current_module = self.current_module;
match module {
ModuleOrUniformRoot::Module(module) => {
ident.span = ident.span.modern();
if let Some(def) = ident.span.adjust(module.expansion) {
self.current_module = self.macro_def_scope(def);
}
}
ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude) => {
ident.span = ident.span.modern();
ident.span.adjust(Mark::root());
}
_ => {}
ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope) => {
// No adjustments
}
}
let result = self.resolve_ident_in_module_unadjusted_ext(
module, ident, ns, parent_scope, false, record_used, path_span,
).map_err(|(determinacy, _)| determinacy);
);
self.current_module = orig_current_module;
result
}

View File

@ -526,7 +526,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
crate fn early_resolve_ident_in_lexical_scope(
&mut self,
mut ident: Ident,
orig_ident: Ident,
ns: Namespace,
macro_kind: Option<MacroKind>,
is_import: bool,
@ -582,6 +582,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
enum WhereToResolve<'a> {
DeriveHelpers,
MacroRules(LegacyScope<'a>),
CrateRoot,
Module(Module<'a>),
MacroUsePrelude,
BuiltinMacros,
@ -605,8 +606,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
assert!(force || !record_used); // `record_used` implies `force`
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
let rust_2015 = ident.span.rust_2015();
ident = ident.modern();
let rust_2015 = orig_ident.span.rust_2015();
let mut ident = orig_ident.modern();
// Make sure `self`, `super` etc produce an error when passed to here.
if ident.is_path_segment_keyword() {
@ -627,10 +628,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let mut innermost_result: Option<(&NameBinding, Flags)> = None;
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = if ns == MacroNS {
WhereToResolve::DeriveHelpers
} else {
WhereToResolve::Module(parent_scope.module)
let mut where_to_resolve = match ns {
_ if is_import && rust_2015 => WhereToResolve::CrateRoot,
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
MacroNS => WhereToResolve::DeriveHelpers,
};
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
let mut determinacy = Determinacy::Determined;
@ -668,6 +669,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
Err(Determinacy::Undetermined),
_ => Err(Determinacy::Determined),
}
WhereToResolve::CrateRoot => {
let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span);
let root_module = self.resolve_crate_root(root_ident);
let binding = self.resolve_ident_in_module_ext(
ModuleOrUniformRoot::Module(root_module),
orig_ident,
ns,
None,
record_used,
path_span,
);
match binding {
Ok(binding) => Ok((binding, Flags::MODULE)),
Err((Determinacy::Undetermined, Weak::No)) =>
return Err(Determinacy::determined(force)),
Err((Determinacy::Undetermined, Weak::Yes)) =>
Err(Determinacy::Undetermined),
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
}
}
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
let binding = self.resolve_ident_in_module_unadjusted_ext(
@ -816,7 +837,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
} else if innermost_flags.contains(Flags::MACRO_RULES) &&
flags.contains(Flags::MODULE) &&
!self.disambiguate_legacy_vs_modern(innermost_binding,
binding) {
binding) ||
flags.contains(Flags::MACRO_RULES) &&
innermost_flags.contains(Flags::MODULE) &&
!self.disambiguate_legacy_vs_modern(binding,
innermost_binding) {
Some(AmbiguityKind::LegacyVsModern)
} else if innermost_binding.is_glob_import() {
Some(AmbiguityKind::GlobVsOuter)
@ -867,6 +892,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
LegacyScope::Uninitialized => unreachable!(),
}
WhereToResolve::CrateRoot => match ns {
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
MacroNS => WhereToResolve::DeriveHelpers,
}
WhereToResolve::Module(module) => {
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => WhereToResolve::Module(parent_module),
@ -899,30 +928,43 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// The first found solution was the only one, return it.
if let Some((binding, flags)) = innermost_result {
if is_import && !self.session.features_untracked().uniform_paths {
// We get to here only if there's no ambiguity, in ambiguous cases an error will
// be reported anyway, so there's no reason to report an additional feature error.
// The `binding` can actually be introduced by something other than `--extern`,
// but its `Def` should coincide with a crate passed with `--extern`
// (otherwise there would be ambiguity) and we can skip feature error in this case.
if ns != TypeNS || !use_prelude ||
self.extern_prelude_get(ident, true).is_none() {
let msg = "imports can only refer to extern crate names \
passed with `--extern` on stable channel";
let mut err = feature_err(&self.session.parse_sess, "uniform_paths",
ident.span, GateIssue::Language, msg);
let what = self.binding_description(binding, ident,
flags.contains(Flags::MISC_FROM_PRELUDE));
let note_msg = format!("this import refers to {what}", what = what);
if binding.span.is_dummy() {
err.note(&note_msg);
} else {
err.span_note(binding.span, &note_msg);
err.span_label(binding.span, "not an extern crate passed with `--extern`");
}
err.emit();
// We get to here only if there's no ambiguity, in ambiguous cases an error will
// be reported anyway, so there's no reason to report an additional feature error.
// The `binding` can actually be introduced by something other than `--extern`,
// but its `Def` should coincide with a crate passed with `--extern`
// (otherwise there would be ambiguity) and we can skip feature error in this case.
'ok: {
if !is_import || self.session.features_untracked().uniform_paths {
break 'ok;
}
if ns == TypeNS && use_prelude && self.extern_prelude_get(ident, true).is_some() {
break 'ok;
}
if rust_2015 {
let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span);
let root_module = self.resolve_crate_root(root_ident);
if self.resolve_ident_in_module_ext(ModuleOrUniformRoot::Module(root_module),
orig_ident, ns, None, false, path_span)
.is_ok() {
break 'ok;
}
}
let msg = "imports can only refer to extern crate names \
passed with `--extern` on stable channel";
let mut err = feature_err(&self.session.parse_sess, "uniform_paths",
ident.span, GateIssue::Language, msg);
let what = self.binding_description(binding, ident,
flags.contains(Flags::MISC_FROM_PRELUDE));
let note_msg = format!("this import refers to {what}", what = what);
if binding.span.is_dummy() {
err.note(&note_msg);
} else {
err.span_note(binding.span, &note_msg);
err.span_label(binding.span, "not an extern crate passed with `--extern`");
}
err.emit();
}
return Ok(binding);

View File

@ -3,7 +3,7 @@
#[macro_export]
macro_rules! gen_imports { () => {
use import::Path;
// use std::collections::LinkedList; // FIXME
use std::collections::LinkedList;
fn check_absolute() {
::absolute::Path;
@ -15,3 +15,16 @@ macro_rules! gen_imports { () => {
macro_rules! gen_glob { () => {
use *;
}}
#[macro_export]
macro_rules! gen_gated { () => {
fn check_gated() {
enum E { A }
use E::*;
}
}}
#[macro_export]
macro_rules! gen_ambiguous { () => {
use Ambiguous;
}}

View File

@ -17,7 +17,7 @@ mod check {
fn check() {
Path;
// LinkedList::<u8>::new(); // FIXME
LinkedList::<u8>::new();
}
}

View File

@ -0,0 +1,18 @@
// edition:2018
// aux-build:edition-imports-2015.rs
// error-pattern: `Ambiguous` is ambiguous
#[macro_use]
extern crate edition_imports_2015;
pub struct Ambiguous {}
mod check {
pub struct Ambiguous {}
fn check() {
gen_ambiguous!();
}
}
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0659]: `Ambiguous` is ambiguous (name vs any other name during import resolution)
--> <::edition_imports_2015::gen_ambiguous macros>:1:15
|
LL | ( ) => { use Ambiguous ; }
| ^^^^^^^^^ ambiguous name
|
note: `Ambiguous` could refer to the struct defined here
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:8:1
|
LL | pub struct Ambiguous {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: `Ambiguous` could also refer to the struct defined here
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:11:5
|
LL | pub struct Ambiguous {}
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::Ambiguous` to refer to this struct unambiguously
error: aborting due to previous error
For more information about this error, try `rustc --explain E0659`.

View File

@ -0,0 +1,12 @@
// edition:2018
// aux-build:edition-imports-2015.rs
// error-pattern: imports can only refer to extern crate names passed with `--extern`
#[macro_use]
extern crate edition_imports_2015;
mod check {
gen_gated!();
}
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
--> <::edition_imports_2015::gen_gated macros>:1:50
|
LL | ( ) => { fn check_gated ( ) { enum E { A } use E :: * ; } }
| ^
|
::: $DIR/edition-imports-virtual-2015-gated.rs:9:5
|
LL | gen_gated!();
| ------------- not an extern crate passed with `--extern`
|
= help: add #![feature(uniform_paths)] to the crate attributes to enable
note: this import refers to the enum defined here
--> $DIR/edition-imports-virtual-2015-gated.rs:9:5
|
LL | gen_gated!();
| ^^^^^^^^^^^^^
= 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
For more information about this error, try `rustc --explain E0658`.