resolve: Implement edition hygiene for imports and absolute paths
Use per-span hygiene in a few other places in resolve Prefer `rust_2015`/`rust_2018` helpers to comparing editions
This commit is contained in:
parent
fba116fc5f
commit
dae4c7b1ff
17 changed files with 226 additions and 75 deletions
|
@ -1478,15 +1478,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
|
/// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
|
||||||
/// or by opting into an edition after 2015.
|
/// or by opting into an edition after 2015.
|
||||||
pub fn two_phase_borrows(self) -> bool {
|
pub fn two_phase_borrows(self) -> bool {
|
||||||
if self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows {
|
self.sess.rust_2018() || self.features().nll ||
|
||||||
return true;
|
self.sess.opts.debugging_opts.two_phase_borrows
|
||||||
}
|
|
||||||
|
|
||||||
match self.sess.edition() {
|
|
||||||
Edition::Edition2015 => false,
|
|
||||||
Edition::Edition2018 => true,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What mode(s) of borrowck should we run? AST? MIR? both?
|
/// What mode(s) of borrowck should we run? AST? MIR? both?
|
||||||
|
|
|
@ -14,7 +14,6 @@ use ty::{self, DefIdTree, Ty, TyCtxt};
|
||||||
use middle::cstore::{ExternCrate, ExternCrateSource};
|
use middle::cstore::{ExternCrate, ExternCrateSource};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::symbol::{keywords, LocalInternedString, Symbol};
|
use syntax::symbol::{keywords, LocalInternedString, Symbol};
|
||||||
use syntax_pos::edition::Edition;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -140,7 +139,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
debug!("push_krate_path: name={:?}", name);
|
debug!("push_krate_path: name={:?}", name);
|
||||||
buffer.push(&name);
|
buffer.push(&name);
|
||||||
}
|
}
|
||||||
} else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
|
} else if self.sess.rust_2018() && !pushed_prelude_crate {
|
||||||
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
|
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
|
||||||
// We only add the `crate::` keyword where appropriate. In particular,
|
// We only add the `crate::` keyword where appropriate. In particular,
|
||||||
// when we've not previously pushed a prelude crate to this path.
|
// when we've not previously pushed a prelude crate to this path.
|
||||||
|
|
|
@ -133,14 +133,17 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
// The root is prepended lazily, when the first non-empty prefix or terminating glob
|
// 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.
|
// appears, so imports in braced groups can have roots prepended independently.
|
||||||
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
|
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
|
||||||
let crate_root = if !self.session.rust_2018() &&
|
let crate_root = match prefix_iter.peek() {
|
||||||
prefix_iter.peek().map_or(is_glob, |seg| !seg.ident.is_path_segment_keyword()) {
|
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
|
||||||
Some(Segment::from_ident(Ident::new(
|
Some(seg.ident.span.ctxt())
|
||||||
keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo()
|
}
|
||||||
)))
|
None if is_glob && use_tree.span.rust_2015() => {
|
||||||
} else {
|
Some(use_tree.span.ctxt())
|
||||||
None
|
}
|
||||||
};
|
_ => None,
|
||||||
|
}.map(|ctxt| Segment::from_ident(Ident::new(
|
||||||
|
keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt)
|
||||||
|
)));
|
||||||
|
|
||||||
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
|
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
|
||||||
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
|
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
|
||||||
|
|
|
@ -33,7 +33,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
(Some(fst), Some(snd)) if fst.ident.name == keywords::CrateRoot.name() &&
|
(Some(fst), Some(snd)) if fst.ident.name == keywords::CrateRoot.name() &&
|
||||||
!snd.ident.is_path_segment_keyword() => {}
|
!snd.ident.is_path_segment_keyword() => {}
|
||||||
// `ident::...` on 2018
|
// `ident::...` on 2018
|
||||||
(Some(fst), _) if self.session.rust_2018() && !fst.ident.is_path_segment_keyword() => {
|
(Some(fst), _) if fst.ident.span.rust_2018() &&
|
||||||
|
!fst.ident.is_path_segment_keyword() => {
|
||||||
// Insert a placeholder that's later replaced by `self`/`super`/etc.
|
// Insert a placeholder that's later replaced by `self`/`super`/etc.
|
||||||
path.insert(0, Segment::from_ident(keywords::Invalid.ident()));
|
path.insert(0, Segment::from_ident(keywords::Invalid.ident()));
|
||||||
}
|
}
|
||||||
|
@ -141,7 +142,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
mut path: Vec<Segment>,
|
mut path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> Option<(Vec<Segment>, Option<String>)> {
|
) -> Option<(Vec<Segment>, Option<String>)> {
|
||||||
if !self.session.rust_2018() {
|
if path[1].ident.span.rust_2015() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2354,14 +2354,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn future_proof_import(&mut self, use_tree: &ast::UseTree) {
|
fn future_proof_import(&mut self, use_tree: &ast::UseTree) {
|
||||||
if !self.session.rust_2018() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let segments = &use_tree.prefix.segments;
|
let segments = &use_tree.prefix.segments;
|
||||||
if !segments.is_empty() {
|
if !segments.is_empty() {
|
||||||
let ident = segments[0].ident;
|
let ident = segments[0].ident;
|
||||||
if ident.is_path_segment_keyword() {
|
if ident.is_path_segment_keyword() || ident.span.rust_2015() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3181,10 +3177,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
|
|
||||||
// Try to lookup the name in more relaxed fashion for better error reporting.
|
// Try to lookup the name in more relaxed fashion for better error reporting.
|
||||||
let ident = path.last().unwrap().ident;
|
let ident = path.last().unwrap().ident;
|
||||||
let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
|
let candidates = this.lookup_import_candidates(ident, ns, is_expected);
|
||||||
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
|
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
|
||||||
let enum_candidates =
|
let enum_candidates =
|
||||||
this.lookup_import_candidates(ident.name, ns, is_enum_variant);
|
this.lookup_import_candidates(ident, ns, is_enum_variant);
|
||||||
let mut enum_candidates = enum_candidates.iter()
|
let mut enum_candidates = enum_candidates.iter()
|
||||||
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
|
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
|
||||||
enum_candidates.sort();
|
enum_candidates.sort();
|
||||||
|
@ -3772,7 +3768,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if name == keywords::Extern.name() ||
|
if name == keywords::Extern.name() ||
|
||||||
name == keywords::CrateRoot.name() && self.session.rust_2018() {
|
name == keywords::CrateRoot.name() && ident.span.rust_2018() {
|
||||||
module =
|
module =
|
||||||
Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude));
|
Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude));
|
||||||
continue;
|
continue;
|
||||||
|
@ -3875,7 +3871,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
let msg = if module_def == self.graph_root.def() {
|
let msg = if module_def == self.graph_root.def() {
|
||||||
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
|
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
|
||||||
let mut candidates =
|
let mut candidates =
|
||||||
self.lookup_import_candidates(name, TypeNS, is_mod);
|
self.lookup_import_candidates(ident, TypeNS, is_mod);
|
||||||
candidates.sort_by_cached_key(|c| {
|
candidates.sort_by_cached_key(|c| {
|
||||||
(c.path.segments.len(), c.path.to_string())
|
(c.path.segments.len(), c.path.to_string())
|
||||||
});
|
});
|
||||||
|
@ -3911,11 +3907,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
second_binding: Option<&NameBinding>,
|
second_binding: Option<&NameBinding>,
|
||||||
) {
|
) {
|
||||||
// In the 2018 edition this lint is a hard error, so nothing to do
|
|
||||||
if self.session.rust_2018() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let (diag_id, diag_span) = match crate_lint {
|
let (diag_id, diag_span) = match crate_lint {
|
||||||
CrateLint::No => return,
|
CrateLint::No => return,
|
||||||
CrateLint::SimplePath(id) => (id, path_span),
|
CrateLint::SimplePath(id) => (id, path_span),
|
||||||
|
@ -3924,8 +3915,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_name = match path.get(0) {
|
let first_name = match path.get(0) {
|
||||||
Some(ident) => ident.ident.name,
|
// In the 2018 edition this lint is a hard error, so nothing to do
|
||||||
None => return,
|
Some(seg) if seg.ident.span.rust_2015() => seg.ident.name,
|
||||||
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We're only interested in `use` paths which should start with
|
// We're only interested in `use` paths which should start with
|
||||||
|
@ -4507,7 +4499,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
|
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
|
||||||
lookup_name: Name,
|
lookup_ident: Ident,
|
||||||
namespace: Namespace,
|
namespace: Namespace,
|
||||||
start_module: &'a ModuleData<'a>,
|
start_module: &'a ModuleData<'a>,
|
||||||
crate_name: Ident,
|
crate_name: Ident,
|
||||||
|
@ -4534,11 +4526,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
if !name_binding.is_importable() { return; }
|
if !name_binding.is_importable() { return; }
|
||||||
|
|
||||||
// collect results based on the filter function
|
// collect results based on the filter function
|
||||||
if ident.name == lookup_name && ns == namespace {
|
if ident.name == lookup_ident.name && ns == namespace {
|
||||||
if filter_fn(name_binding.def()) {
|
if filter_fn(name_binding.def()) {
|
||||||
// create the path
|
// create the path
|
||||||
let mut segms = path_segments.clone();
|
let mut segms = path_segments.clone();
|
||||||
if self.session.rust_2018() {
|
if lookup_ident.span.rust_2018() {
|
||||||
// crate-local absolute paths start with `crate::` in edition 2018
|
// crate-local absolute paths start with `crate::` in edition 2018
|
||||||
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
|
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
|
||||||
segms.insert(
|
segms.insert(
|
||||||
|
@ -4572,7 +4564,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
|
|
||||||
let is_extern_crate_that_also_appears_in_prelude =
|
let is_extern_crate_that_also_appears_in_prelude =
|
||||||
name_binding.is_extern_crate() &&
|
name_binding.is_extern_crate() &&
|
||||||
self.session.rust_2018();
|
lookup_ident.span.rust_2018();
|
||||||
|
|
||||||
let is_visible_to_user =
|
let is_visible_to_user =
|
||||||
!in_module_is_extern || name_binding.vis == ty::Visibility::Public;
|
!in_module_is_extern || name_binding.vis == ty::Visibility::Public;
|
||||||
|
@ -4599,16 +4591,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
/// NOTE: The method does not look into imports, but this is not a problem,
|
/// NOTE: The method does not look into imports, but this is not a problem,
|
||||||
/// since we report the definitions (thus, the de-aliased imports).
|
/// since we report the definitions (thus, the de-aliased imports).
|
||||||
fn lookup_import_candidates<FilterFn>(&mut self,
|
fn lookup_import_candidates<FilterFn>(&mut self,
|
||||||
lookup_name: Name,
|
lookup_ident: Ident,
|
||||||
namespace: Namespace,
|
namespace: Namespace,
|
||||||
filter_fn: FilterFn)
|
filter_fn: FilterFn)
|
||||||
-> Vec<ImportSuggestion>
|
-> Vec<ImportSuggestion>
|
||||||
where FilterFn: Fn(Def) -> bool
|
where FilterFn: Fn(Def) -> bool
|
||||||
{
|
{
|
||||||
let mut suggestions = self.lookup_import_candidates_from_module(
|
let mut suggestions = self.lookup_import_candidates_from_module(
|
||||||
lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn);
|
lookup_ident, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn);
|
||||||
|
|
||||||
if self.session.rust_2018() {
|
if lookup_ident.span.rust_2018() {
|
||||||
let extern_prelude_names = self.extern_prelude.clone();
|
let extern_prelude_names = self.extern_prelude.clone();
|
||||||
for (ident, _) in extern_prelude_names.into_iter() {
|
for (ident, _) in extern_prelude_names.into_iter() {
|
||||||
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
|
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
|
||||||
|
@ -4620,7 +4612,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
self.populate_module_if_necessary(&crate_root);
|
self.populate_module_if_necessary(&crate_root);
|
||||||
|
|
||||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||||
lookup_name, namespace, crate_root, ident, &filter_fn));
|
lookup_ident, namespace, crate_root, ident, &filter_fn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4712,19 +4704,26 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
ast::VisibilityKind::Restricted { ref path, id, .. } => {
|
ast::VisibilityKind::Restricted { ref path, id, .. } => {
|
||||||
// For visibilities we are not ready to provide correct implementation of "uniform
|
// For visibilities we are not ready to provide correct implementation of "uniform
|
||||||
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
|
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
|
||||||
let first_ident = path.segments[0].ident;
|
// On 2015 edition visibilities are resolved as crate-relative by default,
|
||||||
if self.session.rust_2018() && !first_ident.is_path_segment_keyword() {
|
// so we are prepending a root segment if necessary.
|
||||||
|
let ident = path.segments.get(0).expect("empty path in visibility").ident;
|
||||||
|
let crate_root = if ident.is_path_segment_keyword() {
|
||||||
|
None
|
||||||
|
} else if ident.span.rust_2018() {
|
||||||
let msg = "relative paths are not supported in visibilities on 2018 edition";
|
let msg = "relative paths are not supported in visibilities on 2018 edition";
|
||||||
self.session.struct_span_err(first_ident.span, msg)
|
self.session.struct_span_err(ident.span, msg)
|
||||||
.span_suggestion(path.span, "try", format!("crate::{}", path))
|
.span_suggestion(path.span, "try", format!("crate::{}", path))
|
||||||
.emit();
|
.emit();
|
||||||
return ty::Visibility::Public;
|
return ty::Visibility::Public;
|
||||||
}
|
} else {
|
||||||
// On 2015 visibilities are resolved as crate-relative by default,
|
let ctxt = ident.span.ctxt();
|
||||||
// add starting root segment if necessary.
|
Some(Segment::from_ident(Ident::new(
|
||||||
let segments = path.make_root().iter().chain(path.segments.iter())
|
keywords::CrateRoot.name(), path.span.shrink_to_lo().with_ctxt(ctxt)
|
||||||
.map(|seg| Segment { ident: seg.ident, id: Some(seg.id) })
|
)))
|
||||||
.collect::<Vec<_>>();
|
};
|
||||||
|
|
||||||
|
let segments = crate_root.into_iter()
|
||||||
|
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
|
||||||
let def = self.smart_resolve_path_fragment(
|
let def = self.smart_resolve_path_fragment(
|
||||||
id,
|
id,
|
||||||
None,
|
None,
|
||||||
|
@ -4837,7 +4836,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||||
help_msgs.push(format!("consider adding an explicit import of \
|
help_msgs.push(format!("consider adding an explicit import of \
|
||||||
`{ident}` to disambiguate", ident = ident))
|
`{ident}` to disambiguate", ident = ident))
|
||||||
}
|
}
|
||||||
if b.is_extern_crate() && self.session.rust_2018() {
|
if b.is_extern_crate() && ident.span.rust_2018() {
|
||||||
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously",
|
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously",
|
||||||
ident = ident, thing = b.descr()))
|
ident = ident, thing = b.descr()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,6 +605,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
|
|
||||||
assert!(force || !record_used); // `record_used` implies `force`
|
assert!(force || !record_used); // `record_used` implies `force`
|
||||||
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
|
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
|
||||||
|
let rust_2015 = ident.span.rust_2015();
|
||||||
ident = ident.modern();
|
ident = ident.modern();
|
||||||
|
|
||||||
// Make sure `self`, `super` etc produce an error when passed to here.
|
// Make sure `self`, `super` etc produce an error when passed to here.
|
||||||
|
@ -696,7 +697,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WhereToResolve::MacroUsePrelude => {
|
WhereToResolve::MacroUsePrelude => {
|
||||||
if use_prelude || self.session.rust_2015() {
|
if use_prelude || rust_2015 {
|
||||||
match self.macro_use_prelude.get(&ident.name).cloned() {
|
match self.macro_use_prelude.get(&ident.name).cloned() {
|
||||||
Some(binding) =>
|
Some(binding) =>
|
||||||
Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
|
Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
|
||||||
|
@ -725,7 +726,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WhereToResolve::LegacyPluginHelpers => {
|
WhereToResolve::LegacyPluginHelpers => {
|
||||||
if (use_prelude || self.session.rust_2015()) &&
|
if (use_prelude || rust_2015) &&
|
||||||
self.session.plugin_attributes.borrow().iter()
|
self.session.plugin_attributes.borrow().iter()
|
||||||
.any(|(name, _)| ident.name == &**name) {
|
.any(|(name, _)| ident.name == &**name) {
|
||||||
let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
|
let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
|
||||||
|
|
|
@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp};
|
||||||
use ast::{RangeEnd, RangeSyntax};
|
use ast::{RangeEnd, RangeSyntax};
|
||||||
use {ast, attr};
|
use {ast, attr};
|
||||||
use source_map::{self, SourceMap, Spanned, respan};
|
use source_map::{self, SourceMap, Spanned, respan};
|
||||||
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, edition::Edition};
|
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName};
|
||||||
use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId};
|
use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId};
|
||||||
use parse::{self, SeqSep, classify, token};
|
use parse::{self, SeqSep, classify, token};
|
||||||
use parse::lexer::TokenAndSpan;
|
use parse::lexer::TokenAndSpan;
|
||||||
|
@ -1404,11 +1404,7 @@ impl<'a> Parser<'a> {
|
||||||
// definition...
|
// definition...
|
||||||
|
|
||||||
// We don't allow argument names to be left off in edition 2018.
|
// We don't allow argument names to be left off in edition 2018.
|
||||||
if p.span.edition() >= Edition::Edition2018 {
|
p.parse_arg_general(p.span.rust_2018())
|
||||||
p.parse_arg_general(true)
|
|
||||||
} else {
|
|
||||||
p.parse_arg_general(false)
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
generics.where_clause = self.parse_where_clause()?;
|
||||||
|
|
||||||
|
@ -1601,7 +1597,7 @@ impl<'a> Parser<'a> {
|
||||||
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
|
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
|
||||||
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
|
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
|
||||||
} else if self.check_keyword(keywords::Dyn) &&
|
} else if self.check_keyword(keywords::Dyn) &&
|
||||||
(self.span.edition() == Edition::Edition2018 ||
|
(self.span.rust_2018() ||
|
||||||
self.look_ahead(1, |t| t.can_begin_bound() &&
|
self.look_ahead(1, |t| t.can_begin_bound() &&
|
||||||
!can_continue_type_after_non_fn_ident(t))) {
|
!can_continue_type_after_non_fn_ident(t))) {
|
||||||
self.bump(); // `dyn`
|
self.bump(); // `dyn`
|
||||||
|
@ -2084,8 +2080,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let lo = self.meta_var_span.unwrap_or(self.span);
|
let lo = self.meta_var_span.unwrap_or(self.span);
|
||||||
let mut segments = Vec::new();
|
let mut segments = Vec::new();
|
||||||
|
let mod_sep_ctxt = self.span.ctxt();
|
||||||
if self.eat(&token::ModSep) {
|
if self.eat(&token::ModSep) {
|
||||||
segments.push(PathSegment::crate_root(lo.shrink_to_lo()));
|
segments.push(PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
|
||||||
}
|
}
|
||||||
self.parse_path_segments(&mut segments, style, enable_warning)?;
|
self.parse_path_segments(&mut segments, style, enable_warning)?;
|
||||||
|
|
||||||
|
@ -2423,8 +2420,7 @@ impl<'a> Parser<'a> {
|
||||||
hi = path.span;
|
hi = path.span;
|
||||||
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
|
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
|
||||||
}
|
}
|
||||||
if self.span.edition() >= Edition::Edition2018 &&
|
if self.span.rust_2018() && self.check_keyword(keywords::Async)
|
||||||
self.check_keyword(keywords::Async)
|
|
||||||
{
|
{
|
||||||
if self.is_async_block() { // check for `async {` and `async move {`
|
if self.is_async_block() { // check for `async {` and `async move {`
|
||||||
return self.parse_async_block(attrs);
|
return self.parse_async_block(attrs);
|
||||||
|
@ -3440,7 +3436,7 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
Movability::Movable
|
Movability::Movable
|
||||||
};
|
};
|
||||||
let asyncness = if self.span.edition() >= Edition::Edition2018 {
|
let asyncness = if self.span.rust_2018() {
|
||||||
self.parse_asyncness()
|
self.parse_asyncness()
|
||||||
} else {
|
} else {
|
||||||
IsAsync::NotAsync
|
IsAsync::NotAsync
|
||||||
|
@ -4562,9 +4558,7 @@ impl<'a> Parser<'a> {
|
||||||
fn is_try_block(&mut self) -> bool {
|
fn is_try_block(&mut self) -> bool {
|
||||||
self.token.is_keyword(keywords::Try) &&
|
self.token.is_keyword(keywords::Try) &&
|
||||||
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
|
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
|
||||||
|
self.span.rust_2018() &&
|
||||||
self.span.edition() >= Edition::Edition2018 &&
|
|
||||||
|
|
||||||
// prevent `while try {} {}`, `if try {} {} else {}`, etc.
|
// prevent `while try {} {}`, `if try {} {} else {}`, etc.
|
||||||
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||||
}
|
}
|
||||||
|
@ -7648,8 +7642,11 @@ impl<'a> Parser<'a> {
|
||||||
self.check(&token::BinOp(token::Star)) ||
|
self.check(&token::BinOp(token::Star)) ||
|
||||||
self.is_import_coupler() {
|
self.is_import_coupler() {
|
||||||
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
|
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
|
||||||
|
let mod_sep_ctxt = self.span.ctxt();
|
||||||
if self.eat(&token::ModSep) {
|
if self.eat(&token::ModSep) {
|
||||||
prefix.segments.push(PathSegment::crate_root(lo.shrink_to_lo()));
|
prefix.segments.push(
|
||||||
|
PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.eat(&token::BinOp(token::Star)) {
|
if self.eat(&token::BinOp(token::Star)) {
|
||||||
|
|
|
@ -325,6 +325,16 @@ impl Span {
|
||||||
|einfo| einfo.edition)
|
|einfo| einfo.edition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn rust_2015(&self) -> bool {
|
||||||
|
self.edition() == edition::Edition::Edition2015
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn rust_2018(&self) -> bool {
|
||||||
|
self.edition() >= edition::Edition::Edition2018
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the source callee.
|
/// Return the source callee.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the supplied span has no expansion trace,
|
/// Returns `None` if the supplied span has no expansion trace,
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
//! allows bidirectional lookup; i.e. given a value, one can easily find the
|
//! allows bidirectional lookup; i.e. given a value, one can easily find the
|
||||||
//! type, and vice versa.
|
//! type, and vice versa.
|
||||||
|
|
||||||
use edition::Edition;
|
|
||||||
use hygiene::SyntaxContext;
|
use hygiene::SyntaxContext;
|
||||||
use {Span, DUMMY_SP, GLOBALS};
|
use {Span, DUMMY_SP, GLOBALS};
|
||||||
|
|
||||||
|
@ -444,7 +443,7 @@ impl Ident {
|
||||||
pub fn is_unused_keyword(self) -> bool {
|
pub fn is_unused_keyword(self) -> bool {
|
||||||
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
|
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
|
||||||
self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
|
self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
|
||||||
self.name.is_unused_keyword_2018() && self.span.edition() == Edition::Edition2018
|
self.name.is_unused_keyword_2018() && self.span.rust_2018()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is either a special identifier or a keyword.
|
/// Returns `true` if the token is either a special identifier or a keyword.
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// edition:2015
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro_derive(Derive2015)]
|
||||||
|
pub fn derive_2015(_: TokenStream) -> TokenStream {
|
||||||
|
"
|
||||||
|
use import::Path;
|
||||||
|
|
||||||
|
fn check_absolute() {
|
||||||
|
let x = ::absolute::Path;
|
||||||
|
}
|
||||||
|
".parse().unwrap()
|
||||||
|
}
|
24
src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs
Normal file
24
src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// compile-pass
|
||||||
|
// edition:2018
|
||||||
|
// aux-build:edition-imports-2015.rs
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate edition_imports_2015;
|
||||||
|
|
||||||
|
mod import {
|
||||||
|
pub struct Path;
|
||||||
|
}
|
||||||
|
mod absolute {
|
||||||
|
pub struct Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod check {
|
||||||
|
#[derive(Derive2015)] // OK
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn check() {
|
||||||
|
Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
1
src/test/ui/editions/auxiliary/absolute.rs
Normal file
1
src/test/ui/editions/auxiliary/absolute.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub struct Path;
|
17
src/test/ui/editions/auxiliary/edition-imports-2015.rs
Normal file
17
src/test/ui/editions/auxiliary/edition-imports-2015.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// edition:2015
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! gen_imports { () => {
|
||||||
|
use import::Path;
|
||||||
|
// use std::collections::LinkedList; // FIXME
|
||||||
|
|
||||||
|
fn check_absolute() {
|
||||||
|
::absolute::Path;
|
||||||
|
// ::std::collections::LinkedList::<u8>::new(); // FIXME
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! gen_glob { () => {
|
||||||
|
use *;
|
||||||
|
}}
|
17
src/test/ui/editions/auxiliary/edition-imports-2018.rs
Normal file
17
src/test/ui/editions/auxiliary/edition-imports-2018.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! gen_imports { () => {
|
||||||
|
use import::Path;
|
||||||
|
use std::collections::LinkedList;
|
||||||
|
|
||||||
|
fn check_absolute() {
|
||||||
|
::absolute::Path;
|
||||||
|
::std::collections::LinkedList::<u8>::new();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! gen_glob { () => {
|
||||||
|
use *;
|
||||||
|
}}
|
28
src/test/ui/editions/edition-imports-2015.rs
Normal file
28
src/test/ui/editions/edition-imports-2015.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// edition:2015
|
||||||
|
// compile-flags:--extern absolute
|
||||||
|
// aux-build:edition-imports-2018.rs
|
||||||
|
// aux-build:absolute.rs
|
||||||
|
|
||||||
|
#![feature(uniform_paths)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate edition_imports_2018;
|
||||||
|
|
||||||
|
mod check {
|
||||||
|
mod import {
|
||||||
|
pub struct Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_imports!(); // OK
|
||||||
|
|
||||||
|
fn check() {
|
||||||
|
Path;
|
||||||
|
LinkedList::<u8>::new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod check_glob {
|
||||||
|
gen_glob!(); //~ ERROR cannot glob-import all possible crates
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
10
src/test/ui/editions/edition-imports-2015.stderr
Normal file
10
src/test/ui/editions/edition-imports-2015.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: cannot glob-import all possible crates
|
||||||
|
--> $DIR/edition-imports-2015.rs:25: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
|
||||||
|
|
33
src/test/ui/editions/edition-imports-2018.rs
Normal file
33
src/test/ui/editions/edition-imports-2018.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// compile-pass
|
||||||
|
// edition:2018
|
||||||
|
// aux-build:edition-imports-2015.rs
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate edition_imports_2015;
|
||||||
|
|
||||||
|
mod import {
|
||||||
|
pub struct Path;
|
||||||
|
}
|
||||||
|
mod absolute {
|
||||||
|
pub struct Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod check {
|
||||||
|
gen_imports!(); // OK
|
||||||
|
|
||||||
|
fn check() {
|
||||||
|
Path;
|
||||||
|
// LinkedList::<u8>::new(); // FIXME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod check_glob {
|
||||||
|
gen_glob!(); // OK
|
||||||
|
|
||||||
|
fn check() {
|
||||||
|
import::Path;
|
||||||
|
absolute::Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue