Skip to content

Commit 585d2c4

Browse files
committed
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
1 parent 01501eb commit 585d2c4

17 files changed

+226
-77
lines changed

src/librustc/ty/context.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,15 +1484,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
14841484
/// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
14851485
/// or by opting into an edition after 2015.
14861486
pub fn two_phase_borrows(self) -> bool {
1487-
if self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows {
1488-
return true;
1489-
}
1490-
1491-
match self.sess.edition() {
1492-
Edition::Edition2015 => false,
1493-
Edition::Edition2018 => true,
1494-
_ => true,
1495-
}
1487+
self.sess.rust_2018() || self.features().nll ||
1488+
self.sess.opts.debugging_opts.two_phase_borrows
14961489
}
14971490

14981491
/// What mode(s) of borrowck should we run? AST? MIR? both?

src/librustc/ty/item_path.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use ty::{self, DefIdTree, Ty, TyCtxt};
1414
use middle::cstore::{ExternCrate, ExternCrateSource};
1515
use syntax::ast;
1616
use syntax::symbol::{keywords, LocalInternedString, Symbol};
17-
use syntax_pos::edition::Edition;
1817

1918
use std::cell::Cell;
2019
use std::fmt::Debug;
@@ -140,7 +139,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
140139
debug!("push_krate_path: name={:?}", name);
141140
buffer.push(&name);
142141
}
143-
} else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
142+
} else if self.sess.rust_2018() && !pushed_prelude_crate {
144143
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
145144
// We only add the `crate::` keyword where appropriate. In particular,
146145
// when we've not previously pushed a prelude crate to this path.

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,17 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
133133
// The root is prepended lazily, when the first non-empty prefix or terminating glob
134134
// appears, so imports in braced groups can have roots prepended independently.
135135
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
136-
let crate_root = if !self.session.rust_2018() &&
137-
prefix_iter.peek().map_or(is_glob, |seg| !seg.ident.is_path_segment_keyword())
138-
{
139-
Some(Segment::from_ident(Ident::new(
140-
keywords::CrateRoot.name(),
141-
use_tree.prefix.span.shrink_to_lo(),
142-
)))
143-
} else {
144-
None
145-
};
136+
let crate_root = match prefix_iter.peek() {
137+
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
138+
Some(seg.ident.span.ctxt())
139+
}
140+
None if is_glob && use_tree.span.rust_2015() => {
141+
Some(use_tree.span.ctxt())
142+
}
143+
_ => None,
144+
}.map(|ctxt| Segment::from_ident(Ident::new(
145+
keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt)
146+
)));
146147

147148
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
148149
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);

src/librustc_resolve/error_reporting.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
3333
(Some(fst), Some(snd)) if fst.ident.name == keywords::CrateRoot.name() &&
3434
!snd.ident.is_path_segment_keyword() => {}
3535
// `ident::...` on 2018
36-
(Some(fst), _) if self.session.rust_2018() && !fst.ident.is_path_segment_keyword() => {
36+
(Some(fst), _) if fst.ident.span.rust_2018() &&
37+
!fst.ident.is_path_segment_keyword() => {
3738
// Insert a placeholder that's later replaced by `self`/`super`/etc.
3839
path.insert(0, Segment::from_ident(keywords::Invalid.ident()));
3940
}
@@ -141,7 +142,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
141142
mut path: Vec<Segment>,
142143
parent_scope: &ParentScope<'b>,
143144
) -> Option<(Vec<Segment>, Option<String>)> {
144-
if !self.session.rust_2018() {
145+
if path[1].ident.span.rust_2015() {
145146
return None;
146147
}
147148

src/librustc_resolve/lib.rs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,14 +2359,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
23592359
}
23602360

23612361
fn future_proof_import(&mut self, use_tree: &ast::UseTree) {
2362-
if !self.session.rust_2018() {
2363-
return;
2364-
}
2365-
23662362
let segments = &use_tree.prefix.segments;
23672363
if !segments.is_empty() {
23682364
let ident = segments[0].ident;
2369-
if ident.is_path_segment_keyword() {
2365+
if ident.is_path_segment_keyword() || ident.span.rust_2015() {
23702366
return;
23712367
}
23722368

@@ -3186,10 +3182,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
31863182

31873183
// Try to lookup the name in more relaxed fashion for better error reporting.
31883184
let ident = path.last().unwrap().ident;
3189-
let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
3185+
let candidates = this.lookup_import_candidates(ident, ns, is_expected);
31903186
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
31913187
let enum_candidates =
3192-
this.lookup_import_candidates(ident.name, ns, is_enum_variant);
3188+
this.lookup_import_candidates(ident, ns, is_enum_variant);
31933189
let mut enum_candidates = enum_candidates.iter()
31943190
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
31953191
enum_candidates.sort();
@@ -3774,7 +3770,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
37743770
continue;
37753771
}
37763772
if name == keywords::Extern.name() ||
3777-
name == keywords::CrateRoot.name() && self.session.rust_2018() {
3773+
name == keywords::CrateRoot.name() && ident.span.rust_2018() {
37783774
module =
37793775
Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude));
37803776
continue;
@@ -3877,7 +3873,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
38773873
let msg = if module_def == self.graph_root.def() {
38783874
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
38793875
let mut candidates =
3880-
self.lookup_import_candidates(name, TypeNS, is_mod);
3876+
self.lookup_import_candidates(ident, TypeNS, is_mod);
38813877
candidates.sort_by_cached_key(|c| {
38823878
(c.path.segments.len(), c.path.to_string())
38833879
});
@@ -3913,11 +3909,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
39133909
path_span: Span,
39143910
second_binding: Option<&NameBinding>,
39153911
) {
3916-
// In the 2018 edition this lint is a hard error, so nothing to do
3917-
if self.session.rust_2018() {
3918-
return
3919-
}
3920-
39213912
let (diag_id, diag_span) = match crate_lint {
39223913
CrateLint::No => return,
39233914
CrateLint::SimplePath(id) => (id, path_span),
@@ -3926,8 +3917,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
39263917
};
39273918

39283919
let first_name = match path.get(0) {
3929-
Some(ident) => ident.ident.name,
3930-
None => return,
3920+
// In the 2018 edition this lint is a hard error, so nothing to do
3921+
Some(seg) if seg.ident.span.rust_2015() => seg.ident.name,
3922+
_ => return,
39313923
};
39323924

39333925
// We're only interested in `use` paths which should start with
@@ -4509,7 +4501,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45094501
}
45104502

45114503
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
4512-
lookup_name: Name,
4504+
lookup_ident: Ident,
45134505
namespace: Namespace,
45144506
start_module: &'a ModuleData<'a>,
45154507
crate_name: Ident,
@@ -4536,11 +4528,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45364528
if !name_binding.is_importable() { return; }
45374529

45384530
// collect results based on the filter function
4539-
if ident.name == lookup_name && ns == namespace {
4531+
if ident.name == lookup_ident.name && ns == namespace {
45404532
if filter_fn(name_binding.def()) {
45414533
// create the path
45424534
let mut segms = path_segments.clone();
4543-
if self.session.rust_2018() {
4535+
if lookup_ident.span.rust_2018() {
45444536
// crate-local absolute paths start with `crate::` in edition 2018
45454537
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
45464538
segms.insert(
@@ -4574,7 +4566,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45744566

45754567
let is_extern_crate_that_also_appears_in_prelude =
45764568
name_binding.is_extern_crate() &&
4577-
self.session.rust_2018();
4569+
lookup_ident.span.rust_2018();
45784570

45794571
let is_visible_to_user =
45804572
!in_module_is_extern || name_binding.vis == ty::Visibility::Public;
@@ -4601,16 +4593,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
46014593
/// NOTE: The method does not look into imports, but this is not a problem,
46024594
/// since we report the definitions (thus, the de-aliased imports).
46034595
fn lookup_import_candidates<FilterFn>(&mut self,
4604-
lookup_name: Name,
4596+
lookup_ident: Ident,
46054597
namespace: Namespace,
46064598
filter_fn: FilterFn)
46074599
-> Vec<ImportSuggestion>
46084600
where FilterFn: Fn(Def) -> bool
46094601
{
46104602
let mut suggestions = self.lookup_import_candidates_from_module(
4611-
lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn);
4603+
lookup_ident, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn);
46124604

4613-
if self.session.rust_2018() {
4605+
if lookup_ident.span.rust_2018() {
46144606
let extern_prelude_names = self.extern_prelude.clone();
46154607
for (ident, _) in extern_prelude_names.into_iter() {
46164608
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
@@ -4622,7 +4614,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
46224614
self.populate_module_if_necessary(&crate_root);
46234615

46244616
suggestions.extend(self.lookup_import_candidates_from_module(
4625-
lookup_name, namespace, crate_root, ident, &filter_fn));
4617+
lookup_ident, namespace, crate_root, ident, &filter_fn));
46264618
}
46274619
}
46284620
}
@@ -4714,19 +4706,26 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
47144706
ast::VisibilityKind::Restricted { ref path, id, .. } => {
47154707
// For visibilities we are not ready to provide correct implementation of "uniform
47164708
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
4717-
let first_ident = path.segments[0].ident;
4718-
if self.session.rust_2018() && !first_ident.is_path_segment_keyword() {
4709+
// On 2015 edition visibilities are resolved as crate-relative by default,
4710+
// so we are prepending a root segment if necessary.
4711+
let ident = path.segments.get(0).expect("empty path in visibility").ident;
4712+
let crate_root = if ident.is_path_segment_keyword() {
4713+
None
4714+
} else if ident.span.rust_2018() {
47194715
let msg = "relative paths are not supported in visibilities on 2018 edition";
4720-
self.session.struct_span_err(first_ident.span, msg)
4716+
self.session.struct_span_err(ident.span, msg)
47214717
.span_suggestion(path.span, "try", format!("crate::{}", path))
47224718
.emit();
47234719
return ty::Visibility::Public;
4724-
}
4725-
// On 2015 visibilities are resolved as crate-relative by default,
4726-
// add starting root segment if necessary.
4727-
let segments = path.make_root().iter().chain(path.segments.iter())
4728-
.map(|seg| Segment { ident: seg.ident, id: Some(seg.id) })
4729-
.collect::<Vec<_>>();
4720+
} else {
4721+
let ctxt = ident.span.ctxt();
4722+
Some(Segment::from_ident(Ident::new(
4723+
keywords::CrateRoot.name(), path.span.shrink_to_lo().with_ctxt(ctxt)
4724+
)))
4725+
};
4726+
4727+
let segments = crate_root.into_iter()
4728+
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
47304729
let def = self.smart_resolve_path_fragment(
47314730
id,
47324731
None,
@@ -4839,7 +4838,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
48394838
help_msgs.push(format!("consider adding an explicit import of \
48404839
`{ident}` to disambiguate", ident = ident))
48414840
}
4842-
if b.is_extern_crate() && self.session.rust_2018() {
4841+
if b.is_extern_crate() && ident.span.rust_2018() {
48434842
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously",
48444843
ident = ident, thing = b.descr()))
48454844
}

src/librustc_resolve/macros.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
605605

606606
assert!(force || !record_used); // `record_used` implies `force`
607607
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
608+
let rust_2015 = ident.span.rust_2015();
608609
ident = ident.modern();
609610

610611
// Make sure `self`, `super` etc produce an error when passed to here.
@@ -696,7 +697,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
696697
}
697698
}
698699
WhereToResolve::MacroUsePrelude => {
699-
if use_prelude || self.session.rust_2015() {
700+
if use_prelude || rust_2015 {
700701
match self.macro_use_prelude.get(&ident.name).cloned() {
701702
Some(binding) =>
702703
Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
@@ -725,7 +726,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
725726
}
726727
}
727728
WhereToResolve::LegacyPluginHelpers => {
728-
if (use_prelude || self.session.rust_2015()) &&
729+
if (use_prelude || rust_2015) &&
729730
self.session.plugin_attributes.borrow().iter()
730731
.any(|(name, _)| ident.name == &**name) {
731732
let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),

src/libsyntax/parse/parser.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp};
4343
use ast::{RangeEnd, RangeSyntax};
4444
use {ast, attr};
4545
use source_map::{self, SourceMap, Spanned, respan};
46-
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, edition::Edition};
46+
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName};
4747
use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId};
4848
use parse::{self, SeqSep, classify, token};
4949
use parse::lexer::TokenAndSpan;
@@ -1403,11 +1403,7 @@ impl<'a> Parser<'a> {
14031403
// definition...
14041404

14051405
// We don't allow argument names to be left off in edition 2018.
1406-
if p.span.edition() >= Edition::Edition2018 {
1407-
p.parse_arg_general(true)
1408-
} else {
1409-
p.parse_arg_general(false)
1410-
}
1406+
p.parse_arg_general(p.span.rust_2018())
14111407
})?;
14121408
generics.where_clause = self.parse_where_clause()?;
14131409

@@ -1600,9 +1596,9 @@ impl<'a> Parser<'a> {
16001596
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
16011597
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
16021598
} else if self.check_keyword(keywords::Dyn) &&
1603-
(self.span.edition() == Edition::Edition2018 ||
1599+
(self.span.rust_2018() ||
16041600
self.look_ahead(1, |t| t.can_begin_bound() &&
1605-
!can_continue_type_after_non_fn_ident(t))) {
1601+
!can_continue_type_after_non_fn_ident(t))) {
16061602
self.bump(); // `dyn`
16071603
// Always parse bounds greedily for better error recovery.
16081604
let bounds = self.parse_generic_bounds()?;
@@ -2043,8 +2039,9 @@ impl<'a> Parser<'a> {
20432039

20442040
let lo = self.meta_var_span.unwrap_or(self.span);
20452041
let mut segments = Vec::new();
2042+
let mod_sep_ctxt = self.span.ctxt();
20462043
if self.eat(&token::ModSep) {
2047-
segments.push(PathSegment::crate_root(lo.shrink_to_lo()));
2044+
segments.push(PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
20482045
}
20492046
self.parse_path_segments(&mut segments, style, enable_warning)?;
20502047

@@ -2382,8 +2379,7 @@ impl<'a> Parser<'a> {
23822379
hi = path.span;
23832380
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
23842381
}
2385-
if self.span.edition() >= Edition::Edition2018 &&
2386-
self.check_keyword(keywords::Async)
2382+
if self.span.rust_2018() && self.check_keyword(keywords::Async)
23872383
{
23882384
if self.is_async_block() { // check for `async {` and `async move {`
23892385
return self.parse_async_block(attrs);
@@ -3395,7 +3391,7 @@ impl<'a> Parser<'a> {
33953391
} else {
33963392
Movability::Movable
33973393
};
3398-
let asyncness = if self.span.edition() >= Edition::Edition2018 {
3394+
let asyncness = if self.span.rust_2018() {
33993395
self.parse_asyncness()
34003396
} else {
34013397
IsAsync::NotAsync
@@ -4508,9 +4504,7 @@ impl<'a> Parser<'a> {
45084504
fn is_try_block(&mut self) -> bool {
45094505
self.token.is_keyword(keywords::Try) &&
45104506
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
4511-
4512-
self.span.edition() >= Edition::Edition2018 &&
4513-
4507+
self.span.rust_2018() &&
45144508
// prevent `while try {} {}`, `if try {} {} else {}`, etc.
45154509
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
45164510
}
@@ -7599,8 +7593,11 @@ impl<'a> Parser<'a> {
75997593
self.check(&token::BinOp(token::Star)) ||
76007594
self.is_import_coupler() {
76017595
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
7596+
let mod_sep_ctxt = self.span.ctxt();
76027597
if self.eat(&token::ModSep) {
7603-
prefix.segments.push(PathSegment::crate_root(lo.shrink_to_lo()));
7598+
prefix.segments.push(
7599+
PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))
7600+
);
76047601
}
76057602

76067603
if self.eat(&token::BinOp(token::Star)) {

src/libsyntax_pos/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,16 @@ impl Span {
325325
|einfo| einfo.edition)
326326
}
327327

328+
#[inline]
329+
pub fn rust_2015(&self) -> bool {
330+
self.edition() == edition::Edition::Edition2015
331+
}
332+
333+
#[inline]
334+
pub fn rust_2018(&self) -> bool {
335+
self.edition() >= edition::Edition::Edition2018
336+
}
337+
328338
/// Return the source callee.
329339
///
330340
/// Returns `None` if the supplied span has no expansion trace,

0 commit comments

Comments
 (0)