Skip to content

Commit 2d4e34c

Browse files
committed
Auto merge of #53778 - petrochenkov:shadrelax2, r=nikomatsakis
resolve: Relax shadowing restrictions on macro-expanded macros Previously any macro-expanded macros weren't allowed to shadow macros from outer scopes. Now only "more macro-expanded" macros cannot shadow "less macro-expanded" macros. See comments to `fn may_appear_after` and added tests for more details and examples. The functional changes are a21f6f588fc28c97533130ae44a6957b579ab58c and 46dd365ce9ca0a6b8653849b80267763c542842a, other commits are refactorings.
2 parents f50b775 + 2dce377 commit 2d4e34c

27 files changed

+1230
-245
lines changed

src/librustc_resolve/build_reduced_graph.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
946946

947947
pub struct BuildReducedGraphVisitor<'a, 'b: 'a, 'c: 'b> {
948948
pub resolver: &'a mut Resolver<'b, 'c>,
949-
pub legacy_scope: LegacyScope<'b>,
949+
pub current_legacy_scope: LegacyScope<'b>,
950950
pub expansion: Mark,
951951
}
952952

@@ -956,7 +956,8 @@ impl<'a, 'b, 'cl> BuildReducedGraphVisitor<'a, 'b, 'cl> {
956956
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
957957
let invocation = self.resolver.invocations[&mark];
958958
invocation.module.set(self.resolver.current_module);
959-
invocation.legacy_scope.set(self.legacy_scope);
959+
invocation.parent_legacy_scope.set(self.current_legacy_scope);
960+
invocation.output_legacy_scope.set(self.current_legacy_scope);
960961
invocation
961962
}
962963
}
@@ -982,29 +983,30 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
982983
fn visit_item(&mut self, item: &'a Item) {
983984
let macro_use = match item.node {
984985
ItemKind::MacroDef(..) => {
985-
self.resolver.define_macro(item, self.expansion, &mut self.legacy_scope);
986+
self.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope);
986987
return
987988
}
988989
ItemKind::Mac(..) => {
989-
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
990+
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id));
990991
return
991992
}
992993
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
993994
_ => false,
994995
};
995996

996-
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
997+
let orig_current_module = self.resolver.current_module;
998+
let orig_current_legacy_scope = self.current_legacy_scope;
997999
self.resolver.build_reduced_graph_for_item(item, self.expansion);
9981000
visit::walk_item(self, item);
999-
self.resolver.current_module = parent;
1001+
self.resolver.current_module = orig_current_module;
10001002
if !macro_use {
1001-
self.legacy_scope = legacy_scope;
1003+
self.current_legacy_scope = orig_current_legacy_scope;
10021004
}
10031005
}
10041006

10051007
fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
10061008
if let ast::StmtKind::Mac(..) = stmt.node {
1007-
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
1009+
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id));
10081010
} else {
10091011
visit::walk_stmt(self, stmt);
10101012
}
@@ -1021,11 +1023,12 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
10211023
}
10221024

10231025
fn visit_block(&mut self, block: &'a Block) {
1024-
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
1026+
let orig_current_module = self.resolver.current_module;
1027+
let orig_current_legacy_scope = self.current_legacy_scope;
10251028
self.resolver.build_reduced_graph_for_block(block, self.expansion);
10261029
visit::walk_block(self, block);
1027-
self.resolver.current_module = parent;
1028-
self.legacy_scope = legacy_scope;
1030+
self.resolver.current_module = orig_current_module;
1031+
self.current_legacy_scope = orig_current_legacy_scope;
10291032
}
10301033

10311034
fn visit_trait_item(&mut self, item: &'a TraitItem) {

src/librustc_resolve/lib.rs

+62-57
Original file line numberDiff line numberDiff line change
@@ -1177,9 +1177,7 @@ struct UseError<'a> {
11771177
}
11781178

11791179
struct AmbiguityError<'a> {
1180-
span: Span,
1181-
name: Name,
1182-
lexical: bool,
1180+
ident: Ident,
11831181
b1: &'a NameBinding<'a>,
11841182
b2: &'a NameBinding<'a>,
11851183
}
@@ -1283,6 +1281,26 @@ impl<'a> NameBinding<'a> {
12831281
fn descr(&self) -> &'static str {
12841282
if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
12851283
}
1284+
1285+
// Suppose that we resolved macro invocation with `invoc_id` to binding `binding` at some
1286+
// expansion round `max(invoc_id, binding)` when they both emerged from macros.
1287+
// Then this function returns `true` if `self` may emerge from a macro *after* that
1288+
// in some later round and screw up our previously found resolution.
1289+
// See more detailed explanation in
1290+
// https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049
1291+
fn may_appear_after(&self, invoc_id: Mark, binding: &NameBinding) -> bool {
1292+
// self > max(invoc_id, binding) => !(self <= invoc_id || self <= binding)
1293+
// Expansions are partially ordered, so "may appear after" is an inversion of
1294+
// "certainly appears before or simultaneously" and includes unordered cases.
1295+
let self_parent_expansion = self.expansion;
1296+
let other_parent_expansion = binding.expansion;
1297+
let invoc_parent_expansion = invoc_id.parent();
1298+
let certainly_before_other_or_simultaneously =
1299+
other_parent_expansion.is_descendant_of(self_parent_expansion);
1300+
let certainly_before_invoc_or_simultaneously =
1301+
invoc_parent_expansion.is_descendant_of(self_parent_expansion);
1302+
!(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
1303+
}
12861304
}
12871305

12881306
/// Interns the names of the primitive types.
@@ -1416,8 +1434,6 @@ pub struct Resolver<'a, 'b: 'a> {
14161434
proc_mac_errors: Vec<macros::ProcMacError>,
14171435
/// crate-local macro expanded `macro_export` referred to by a module-relative path
14181436
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
1419-
/// macro-expanded `macro_rules` shadowing existing macros
1420-
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
14211437

14221438
arenas: &'a ResolverArenas<'a>,
14231439
dummy_binding: &'a NameBinding<'a>,
@@ -1729,7 +1745,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
17291745
ambiguity_errors: Vec::new(),
17301746
use_injections: Vec::new(),
17311747
proc_mac_errors: Vec::new(),
1732-
disallowed_shadowing: Vec::new(),
17331748
macro_expanded_macro_export_errors: BTreeSet::new(),
17341749

17351750
arenas,
@@ -1815,7 +1830,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18151830
self.arenas.alloc_module(module)
18161831
}
18171832

1818-
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
1833+
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
18191834
-> bool /* true if an error was reported */ {
18201835
match binding.kind {
18211836
NameBindingKind::Import { directive, binding, ref used }
@@ -1824,13 +1839,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18241839
directive.used.set(true);
18251840
self.used_imports.insert((directive.id, ns));
18261841
self.add_to_glob_map(directive.id, ident);
1827-
self.record_use(ident, ns, binding, span)
1842+
self.record_use(ident, ns, binding)
18281843
}
18291844
NameBindingKind::Import { .. } => false,
18301845
NameBindingKind::Ambiguity { b1, b2 } => {
1831-
self.ambiguity_errors.push(AmbiguityError {
1832-
span, name: ident.name, lexical: false, b1, b2,
1833-
});
1846+
self.ambiguity_errors.push(AmbiguityError { ident, b1, b2 });
18341847
true
18351848
}
18361849
_ => false
@@ -2850,7 +2863,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
28502863
Def::Const(..) if is_syntactic_ambiguity => {
28512864
// Disambiguate in favor of a unit struct/variant
28522865
// or constant pattern.
2853-
self.record_use(ident, ValueNS, binding.unwrap(), ident.span);
2866+
self.record_use(ident, ValueNS, binding.unwrap());
28542867
Some(PathResolution::new(def))
28552868
}
28562869
Def::StructCtor(..) | Def::VariantCtor(..) |
@@ -3483,6 +3496,20 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
34833496
record_used: bool,
34843497
path_span: Span,
34853498
crate_lint: CrateLint,
3499+
) -> PathResult<'a> {
3500+
self.resolve_path_with_invoc_id(base_module, path, opt_ns, Mark::root(),
3501+
record_used, path_span, crate_lint)
3502+
}
3503+
3504+
fn resolve_path_with_invoc_id(
3505+
&mut self,
3506+
base_module: Option<ModuleOrUniformRoot<'a>>,
3507+
path: &[Ident],
3508+
opt_ns: Option<Namespace>, // `None` indicates a module path
3509+
invoc_id: Mark,
3510+
record_used: bool,
3511+
path_span: Span,
3512+
crate_lint: CrateLint,
34863513
) -> PathResult<'a> {
34873514
let mut module = base_module;
34883515
let mut allow_super = true;
@@ -3572,8 +3599,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
35723599
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
35733600
} else if opt_ns == Some(MacroNS) {
35743601
assert!(ns == TypeNS);
3575-
self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
3576-
false, path_span).map(|(b, _)| b)
3602+
self.resolve_lexical_macro_path_segment(ident, ns, invoc_id, record_used,
3603+
record_used, false, path_span)
3604+
.map(|(binding, _)| binding)
35773605
} else {
35783606
let record_used_id =
35793607
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
@@ -4514,35 +4542,33 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45144542
vis.is_accessible_from(module.normal_ancestor_id, self)
45154543
}
45164544

4517-
fn report_ambiguity_error(
4518-
&self, name: Name, span: Span, _lexical: bool,
4519-
def1: Def, is_import1: bool, is_glob1: bool, from_expansion1: bool, span1: Span,
4520-
def2: Def, is_import2: bool, _is_glob2: bool, _from_expansion2: bool, span2: Span,
4521-
) {
4545+
fn report_ambiguity_error(&self, ident: Ident, b1: &NameBinding, b2: &NameBinding) {
45224546
let participle = |is_import: bool| if is_import { "imported" } else { "defined" };
4523-
let msg1 = format!("`{}` could refer to the name {} here", name, participle(is_import1));
4547+
let msg1 =
4548+
format!("`{}` could refer to the name {} here", ident, participle(b1.is_import()));
45244549
let msg2 =
4525-
format!("`{}` could also refer to the name {} here", name, participle(is_import2));
4526-
let note = if from_expansion1 {
4527-
Some(if let Def::Macro(..) = def1 {
4550+
format!("`{}` could also refer to the name {} here", ident, participle(b2.is_import()));
4551+
let note = if b1.expansion != Mark::root() {
4552+
Some(if let Def::Macro(..) = b1.def() {
45284553
format!("macro-expanded {} do not shadow",
4529-
if is_import1 { "macro imports" } else { "macros" })
4554+
if b1.is_import() { "macro imports" } else { "macros" })
45304555
} else {
45314556
format!("macro-expanded {} do not shadow when used in a macro invocation path",
4532-
if is_import1 { "imports" } else { "items" })
4557+
if b1.is_import() { "imports" } else { "items" })
45334558
})
4534-
} else if is_glob1 {
4535-
Some(format!("consider adding an explicit import of `{}` to disambiguate", name))
4559+
} else if b1.is_glob_import() {
4560+
Some(format!("consider adding an explicit import of `{}` to disambiguate", ident))
45364561
} else {
45374562
None
45384563
};
45394564

4540-
let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
4541-
err.span_note(span1, &msg1);
4542-
match def2 {
4543-
Def::Macro(..) if span2.is_dummy() =>
4544-
err.note(&format!("`{}` is also a builtin macro", name)),
4545-
_ => err.span_note(span2, &msg2),
4565+
let mut err = struct_span_err!(self.session, ident.span, E0659, "`{}` is ambiguous", ident);
4566+
err.span_label(ident.span, "ambiguous name");
4567+
err.span_note(b1.span, &msg1);
4568+
match b2.def() {
4569+
Def::Macro(..) if b2.span.is_dummy() =>
4570+
err.note(&format!("`{}` is also a builtin macro", ident)),
4571+
_ => err.span_note(b2.span, &msg2),
45464572
};
45474573
if let Some(note) = note {
45484574
err.note(&note);
@@ -4551,7 +4577,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45514577
}
45524578

45534579
fn report_errors(&mut self, krate: &Crate) {
4554-
self.report_shadowing_errors();
45554580
self.report_with_use_injections(krate);
45564581
self.report_proc_macro_import(krate);
45574582
let mut reported_spans = FxHashSet();
@@ -4567,15 +4592,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45674592
);
45684593
}
45694594

4570-
for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
4571-
if reported_spans.insert(span) {
4572-
self.report_ambiguity_error(
4573-
name, span, lexical,
4574-
b1.def(), b1.is_import(), b1.is_glob_import(),
4575-
b1.expansion != Mark::root(), b1.span,
4576-
b2.def(), b2.is_import(), b2.is_glob_import(),
4577-
b2.expansion != Mark::root(), b2.span,
4578-
);
4595+
for &AmbiguityError { ident, b1, b2 } in &self.ambiguity_errors {
4596+
if reported_spans.insert(ident.span) {
4597+
self.report_ambiguity_error(ident, b1, b2);
45794598
}
45804599
}
45814600

@@ -4595,20 +4614,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45954614
}
45964615
}
45974616

4598-
fn report_shadowing_errors(&mut self) {
4599-
let mut reported_errors = FxHashSet();
4600-
for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
4601-
if self.resolve_legacy_scope(&binding.parent, binding.ident, false).is_some() &&
4602-
reported_errors.insert((binding.ident, binding.span)) {
4603-
let msg = format!("`{}` is already in scope", binding.ident);
4604-
self.session.struct_span_err(binding.span, &msg)
4605-
.note("macro-expanded `macro_rules!`s may not shadow \
4606-
existing macros (see RFC 1560)")
4607-
.emit();
4608-
}
4609-
}
4610-
}
4611-
46124617
fn report_conflict<'b>(&mut self,
46134618
parent: Module,
46144619
ident: Ident,

0 commit comments

Comments
 (0)