mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-11 22:43:42 +00:00
resolve: Fallback to uniform paths in 2015 imports used from global 2018 edition
This commit is contained in:
parent
dae4c7b1ff
commit
c06e69ee70
@ -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() => {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(¬e_msg);
|
||||
} else {
|
||||
err.span_note(binding.span, ¬e_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(¬e_msg);
|
||||
} else {
|
||||
err.span_note(binding.span, ¬e_msg);
|
||||
err.span_label(binding.span, "not an extern crate passed with `--extern`");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
return Ok(binding);
|
||||
|
@ -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;
|
||||
}}
|
||||
|
@ -17,7 +17,7 @@ mod check {
|
||||
|
||||
fn check() {
|
||||
Path;
|
||||
// LinkedList::<u8>::new(); // FIXME
|
||||
LinkedList::<u8>::new();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
@ -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`.
|
12
src/test/ui/editions/edition-imports-virtual-2015-gated.rs
Normal file
12
src/test/ui/editions/edition-imports-virtual-2015-gated.rs
Normal 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() {}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user