Skip to content

Commit 0953d28

Browse files
committed
resolve: Introduce "may appear after" abstraction for macro path resolutions
1 parent 2e3106b commit 0953d28

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

src/librustc_resolve/lib.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,15 @@ impl<'a> NameBinding<'a> {
12691269
fn descr(&self) -> &'static str {
12701270
if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
12711271
}
1272+
1273+
// Suppose that we resolved macro invocation with `invoc_id` to binding `binding` at some
1274+
// expansion round `max(invoc_id, binding)` when they both emerged from macros.
1275+
// Then this function returns `true` if `self` may emerge from a macro *after* that
1276+
// in some later round and screw up our previously found resolution.
1277+
fn may_appear_after(&self, _invoc_id: Mark, _binding: &NameBinding) -> bool {
1278+
// FIXME: This is a very conservative estimation.
1279+
self.expansion != Mark::root()
1280+
}
12721281
}
12731282

12741283
/// Interns the names of the primitive types.
@@ -3464,6 +3473,20 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
34643473
record_used: bool,
34653474
path_span: Span,
34663475
crate_lint: CrateLint,
3476+
) -> PathResult<'a> {
3477+
self.resolve_path_with_invoc_id(base_module, path, opt_ns, Mark::root(),
3478+
record_used, path_span, crate_lint)
3479+
}
3480+
3481+
fn resolve_path_with_invoc_id(
3482+
&mut self,
3483+
base_module: Option<ModuleOrUniformRoot<'a>>,
3484+
path: &[Ident],
3485+
opt_ns: Option<Namespace>, // `None` indicates a module path
3486+
invoc_id: Mark,
3487+
record_used: bool,
3488+
path_span: Span,
3489+
crate_lint: CrateLint,
34673490
) -> PathResult<'a> {
34683491
let mut module = base_module;
34693492
let mut allow_super = true;
@@ -3553,8 +3576,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
35533576
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
35543577
} else if opt_ns == Some(MacroNS) {
35553578
assert!(ns == TypeNS);
3556-
self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
3557-
false, path_span).map(|(b, _)| b)
3579+
self.resolve_lexical_macro_path_segment(ident, ns, invoc_id, record_used,
3580+
record_used, false, path_span)
3581+
.map(|(binding, _)| binding)
35583582
} else {
35593583
let record_used_id =
35603584
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };

src/librustc_resolve/macros.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
414414
Ok((def, self.get_macro(def)))
415415
}
416416

417-
pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
417+
pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
418418
derives_in_scope: &[ast::Path], force: bool)
419419
-> Result<Def, Determinacy> {
420420
let ast::Path { ref segments, span } = *path;
421421
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
422-
let invocation = self.invocations[&scope];
422+
let invocation = self.invocations[&invoc_id];
423423
let module = invocation.module.get();
424424
self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
425425

@@ -431,8 +431,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
431431
}
432432

433433
if path.len() > 1 {
434-
let res = self.resolve_path(None, &path, Some(MacroNS), false, span, CrateLint::No);
435-
let def = match res {
434+
let def = match self.resolve_path_with_invoc_id(None, &path, Some(MacroNS), invoc_id,
435+
false, span, CrateLint::No) {
436436
PathResult::NonModule(path_res) => match path_res.base_def() {
437437
Def::Err => Err(Determinacy::Determined),
438438
def @ _ => {
@@ -457,11 +457,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
457457
return def;
458458
}
459459

460-
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
460+
let legacy_resolution =
461+
self.resolve_legacy_scope(path[0], invoc_id, &invocation.legacy_scope, false);
461462
let result = if let Some(legacy_binding) = legacy_resolution {
462463
Ok(legacy_binding.def())
463464
} else {
464-
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force,
465+
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, invoc_id, false, force,
465466
kind == MacroKind::Attr, span) {
466467
Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
467468
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
@@ -473,7 +474,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
473474
};
474475

475476
self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
476-
.push((scope, path[0], kind, result.ok()));
477+
.push((invoc_id, path[0], kind, result.ok()));
477478

478479
if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
479480
return result;
@@ -492,7 +493,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
492493
enum ConvertToDeriveHelper { Yes, No, DontKnow }
493494
let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
494495
for derive in derives_in_scope {
495-
match self.resolve_macro_path(derive, MacroKind::Derive, scope, &[], force) {
496+
match self.resolve_macro_path(derive, MacroKind::Derive, invoc_id, &[], force) {
496497
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
497498
if inert_attrs.contains(&path[0].name) {
498499
convert_to_derive_helper = ConvertToDeriveHelper::Yes;
@@ -520,10 +521,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
520521
&mut self,
521522
mut ident: Ident,
522523
ns: Namespace,
524+
invoc_id: Mark,
523525
record_used: bool,
524526
force: bool,
525527
is_attr: bool,
526-
path_span: Span
528+
path_span: Span,
527529
) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
528530
// General principles:
529531
// 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -714,7 +716,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
714716
// Found another solution, if the first one was "weak", report an error.
715717
if result.0.def() != innermost_result.0.def() &&
716718
(innermost_result.0.is_glob_import() ||
717-
innermost_result.0.expansion != Mark::root()) {
719+
innermost_result.0.may_appear_after(invoc_id, result.0)) {
718720
self.ambiguity_errors.push(AmbiguityError {
719721
span: path_span,
720722
name: ident.name,
@@ -758,8 +760,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
758760
}
759761

760762
fn resolve_legacy_scope(&mut self,
761-
invocation_legacy_scope: &'a Cell<LegacyScope<'a>>,
762763
ident: Ident,
764+
invoc_id: Mark,
765+
invoc_parent_legacy_scope: &'a Cell<LegacyScope<'a>>,
763766
record_used: bool)
764767
-> Option<&'a NameBinding<'a>> {
765768
let ident = ident.modern();
@@ -778,7 +781,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
778781
let mut innermost_result: Option<&NameBinding> = None;
779782

780783
// Go through all the scopes and try to resolve the name.
781-
let mut where_to_resolve = invocation_legacy_scope;
784+
let mut where_to_resolve = invoc_parent_legacy_scope;
782785
loop {
783786
let result = match where_to_resolve.get() {
784787
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
@@ -814,7 +817,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
814817
if let Some(innermost_result) = innermost_result {
815818
// Found another solution, if the first one was "weak", report an error.
816819
if result.def() != innermost_result.def() &&
817-
innermost_result.expansion != Mark::root() {
820+
innermost_result.may_appear_after(invoc_id, result) {
818821
self.ambiguity_errors.push(AmbiguityError {
819822
span: ident.span,
820823
name: ident.name,
@@ -852,12 +855,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
852855
}
853856
}
854857

855-
for &(mark, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
858+
for &(invoc_id, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
856859
let span = ident.span;
857-
let legacy_scope = &self.invocations[&mark].legacy_scope;
858-
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true);
859-
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true,
860-
kind == MacroKind::Attr, span);
860+
let legacy_scope = &self.invocations[&invoc_id].legacy_scope;
861+
let legacy_resolution = self.resolve_legacy_scope(ident, invoc_id, legacy_scope, true);
862+
let resolution = self.resolve_lexical_macro_path_segment(
863+
ident, MacroNS, invoc_id, true, true, kind == MacroKind::Attr, span
864+
);
861865

862866
let check_consistency = |this: &Self, new_def: Def| {
863867
if let Some(def) = def {
@@ -890,7 +894,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
890894
err.emit();
891895
},
892896
(Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
893-
if !from_prelude || legacy_binding.expansion != Mark::root() => {
897+
if !from_prelude || legacy_binding.may_appear_after(invoc_id, binding) => {
894898
if legacy_binding.def_ignoring_ambiguity() != binding.def_ignoring_ambiguity() {
895899
self.report_ambiguity_error(ident.name, span, legacy_binding, binding);
896900
}

src/libsyntax_pos/hygiene.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ impl Mark {
100100
Mark(raw)
101101
}
102102

103+
#[inline]
104+
pub fn parent(self) -> Mark {
105+
HygieneData::with(|data| data.marks[self.0 as usize].parent)
106+
}
107+
103108
#[inline]
104109
pub fn expn_info(self) -> Option<ExpnInfo> {
105110
HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())

0 commit comments

Comments
 (0)