Skip to content

Commit e8bc1d1

Browse files
committed
resolve: Check resolution consistency for import paths and multi-segment macro paths
1 parent 82ee839 commit e8bc1d1

20 files changed

+371
-202
lines changed

src/librustc/hir/def.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ impl Def {
330330
match *self {
331331
Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::AssociatedExistential(..) |
332332
Def::Enum(..) | Def::Existential(..) | Def::Err => "an",
333+
Def::Macro(.., macro_kind) => macro_kind.article(),
333334
_ => "a",
334335
}
335336
}

src/librustc/hir/def_id.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ pub struct DefId {
225225

226226
impl fmt::Debug for DefId {
227227
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228-
write!(f, "DefId({:?}/{}:{}",
229-
self.krate.index(),
228+
write!(f, "DefId({}/{}:{}",
229+
self.krate,
230230
self.index.address_space().index(),
231231
self.index.as_array_index())?;
232232

src/librustc_resolve/lib.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,18 @@ enum ModuleOrUniformRoot<'a> {
988988
UniformRoot(UniformRootKind),
989989
}
990990

991+
impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
992+
fn eq(&self, other: &Self) -> bool {
993+
match (*self, *other) {
994+
(ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
995+
ptr::eq(lhs, rhs),
996+
(ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) =>
997+
lhs == rhs,
998+
_ => false,
999+
}
1000+
}
1001+
}
1002+
9911003
#[derive(Clone, Debug)]
9921004
enum PathResult<'a> {
9931005
Module(ModuleOrUniformRoot<'a>),
@@ -1029,9 +1041,10 @@ pub struct ModuleData<'a> {
10291041
normal_ancestor_id: DefId,
10301042

10311043
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
1032-
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1033-
Option<&'a NameBinding<'a>>)>>,
1034-
macro_resolutions: RefCell<Vec<(Vec<Ident>, ParentScope<'a>, Span)>>,
1044+
single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1045+
Option<&'a NameBinding<'a>>)>>,
1046+
multi_segment_macro_resolutions: RefCell<Vec<(Vec<Ident>, Span, MacroKind, ParentScope<'a>,
1047+
Option<Def>)>>,
10351048
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
10361049

10371050
// Macro invocations that can expand into items in this module.
@@ -1069,8 +1082,8 @@ impl<'a> ModuleData<'a> {
10691082
kind,
10701083
normal_ancestor_id,
10711084
resolutions: Default::default(),
1072-
legacy_macro_resolutions: RefCell::new(Vec::new()),
1073-
macro_resolutions: RefCell::new(Vec::new()),
1085+
single_segment_macro_resolutions: RefCell::new(Vec::new()),
1086+
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
10741087
builtin_attrs: RefCell::new(Vec::new()),
10751088
unresolved_invocations: Default::default(),
10761089
no_implicit_prelude: false,
@@ -1466,6 +1479,9 @@ pub struct Resolver<'a, 'b: 'a> {
14661479
/// The current self item if inside an ADT (used for better errors).
14671480
current_self_item: Option<NodeId>,
14681481

1482+
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
1483+
last_import_segment: bool,
1484+
14691485
/// The idents for the primitive types.
14701486
primitive_type_table: PrimitiveTypeTable,
14711487

@@ -1793,6 +1809,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
17931809
current_trait_ref: None,
17941810
current_self_type: None,
17951811
current_self_item: None,
1812+
last_import_segment: false,
17961813

17971814
primitive_type_table: PrimitiveTypeTable::new(),
17981815

@@ -1894,27 +1911,23 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18941911
self.arenas.alloc_module(module)
18951912
}
18961913

1897-
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
1898-
-> bool /* true if an error was reported */ {
1914+
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>) {
18991915
match binding.kind {
1900-
NameBindingKind::Import { directive, binding, ref used }
1901-
if !used.get() => {
1916+
NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
19021917
used.set(true);
19031918
directive.used.set(true);
19041919
self.used_imports.insert((directive.id, ns));
19051920
self.add_to_glob_map(directive.id, ident);
1906-
self.record_use(ident, ns, binding)
1921+
self.record_use(ident, ns, binding);
19071922
}
1908-
NameBindingKind::Import { .. } => false,
19091923
NameBindingKind::Ambiguity { kind, b1, b2 } => {
19101924
self.ambiguity_errors.push(AmbiguityError {
19111925
kind, ident, b1, b2,
19121926
misc1: AmbiguityErrorMisc::None,
19131927
misc2: AmbiguityErrorMisc::None,
19141928
});
1915-
true
19161929
}
1917-
_ => false
1930+
_ => {}
19181931
}
19191932
}
19201933

@@ -4735,7 +4748,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
47354748

47364749
fn report_errors(&mut self, krate: &Crate) {
47374750
self.report_with_use_injections(krate);
4738-
let mut reported_spans = FxHashSet::default();
47394751

47404752
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
47414753
let msg = "macro-expanded `macro_export` macros from the current crate \
@@ -4749,11 +4761,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
47494761
}
47504762

47514763
for ambiguity_error in &self.ambiguity_errors {
4752-
if reported_spans.insert(ambiguity_error.ident.span) {
4753-
self.report_ambiguity_error(ambiguity_error);
4754-
}
4764+
self.report_ambiguity_error(ambiguity_error);
47554765
}
47564766

4767+
let mut reported_spans = FxHashSet::default();
47574768
for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
47584769
if reported_spans.insert(dedup_span) {
47594770
span_err!(self.session, ident.span, E0603, "{} `{}` is private",

src/librustc_resolve/macros.rs

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// except according to those terms.
1010

1111
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
12-
use {CrateLint, DeterminacyExt, Resolver, ResolutionError, is_known_tool, resolve_error};
12+
use {CrateLint, DeterminacyExt, Resolver, ResolutionError};
1313
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
14+
use {is_known_tool, names_to_string, resolve_error};
1415
use ModuleOrUniformRoot;
1516
use Namespace::{self, *};
1617
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@@ -450,6 +451,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
450451
return Err(Determinacy::Determined);
451452
}
452453
}
454+
Def::Err => {
455+
return Err(Determinacy::Determined);
456+
}
453457
_ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
454458
}
455459

@@ -476,29 +480,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
476480
if path.len() > 1 {
477481
let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
478482
false, path_span, CrateLint::No) {
479-
PathResult::NonModule(path_res) => match path_res.base_def() {
480-
Def::Err => Err(Determinacy::Determined),
481-
def @ _ => {
482-
if path_res.unresolved_segments() > 0 {
483-
self.found_unresolved_macro = true;
484-
self.session.span_err(path_span,
485-
"fail to resolve non-ident macro path");
486-
Err(Determinacy::Determined)
487-
} else {
488-
Ok(def)
489-
}
490-
}
491-
},
492-
PathResult::Module(..) => unreachable!(),
483+
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
484+
Ok(path_res.base_def())
485+
}
493486
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
494-
_ => {
487+
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
495488
self.found_unresolved_macro = true;
496489
Err(Determinacy::Determined)
497-
},
490+
}
491+
PathResult::Module(..) => unreachable!(),
498492
};
499493

500-
parent_scope.module.macro_resolutions.borrow_mut()
501-
.push((path, parent_scope.clone(), path_span));
494+
parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
495+
.push((path, path_span, kind, parent_scope.clone(), def.ok()));
502496

503497
def
504498
} else {
@@ -511,7 +505,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
511505
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
512506
}
513507

514-
parent_scope.module.legacy_macro_resolutions.borrow_mut()
508+
parent_scope.module.single_segment_macro_resolutions.borrow_mut()
515509
.push((path[0], kind, parent_scope.clone(), binding.ok()));
516510

517511
binding.map(|binding| binding.def_ignoring_ambiguity())
@@ -918,48 +912,66 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
918912
pub fn finalize_current_module_macro_resolutions(&mut self) {
919913
let module = self.current_module;
920914

915+
let check_consistency = |this: &mut Self, path: &[Ident], span,
916+
kind: MacroKind, initial_def, def| {
917+
if let Some(initial_def) = initial_def {
918+
if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() {
919+
// Make sure compilation does not succeed if preferred macro resolution
920+
// has changed after the macro had been expanded. In theory all such
921+
// situations should be reported as ambiguity errors, so this is a bug.
922+
span_bug!(span, "inconsistent resolution for a macro");
923+
}
924+
} else {
925+
// It's possible that the macro was unresolved (indeterminate) and silently
926+
// expanded into a dummy fragment for recovery during expansion.
927+
// Now, post-expansion, the resolution may succeed, but we can't change the
928+
// past and need to report an error.
929+
// However, non-speculative `resolve_path` can successfully return private items
930+
// even if speculative `resolve_path` returned nothing previously, so we skip this
931+
// less informative error if the privacy error is reported elsewhere.
932+
if this.privacy_errors.is_empty() {
933+
let msg = format!("cannot determine resolution for the {} `{}`",
934+
kind.descr(), names_to_string(path));
935+
let msg_note = "import resolution is stuck, try simplifying macro imports";
936+
this.session.struct_span_err(span, &msg).note(msg_note).emit();
937+
}
938+
}
939+
};
940+
921941
let macro_resolutions =
922-
mem::replace(&mut *module.macro_resolutions.borrow_mut(), Vec::new());
923-
for (path, parent_scope, path_span) in macro_resolutions {
942+
mem::replace(&mut *module.multi_segment_macro_resolutions.borrow_mut(), Vec::new());
943+
for (path, path_span, kind, parent_scope, initial_def) in macro_resolutions {
924944
match self.resolve_path(&path, Some(MacroNS), &parent_scope,
925945
true, path_span, CrateLint::No) {
926-
PathResult::NonModule(_) => {},
927-
PathResult::Failed(span, msg, _) => {
946+
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
947+
let def = path_res.base_def();
948+
check_consistency(self, &path, path_span, kind, initial_def, def);
949+
}
950+
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => {
951+
let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
952+
(span, msg)
953+
} else {
954+
(path_span, format!("partially resolved path in {} {}",
955+
kind.article(), kind.descr()))
956+
};
928957
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
929958
}
930-
_ => unreachable!(),
959+
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
931960
}
932961
}
933962

934-
let legacy_macro_resolutions =
935-
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
936-
for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
937-
let binding = self.early_resolve_ident_in_lexical_scope(
938-
ident, MacroNS, Some(kind), false, &parent_scope, true, true, ident.span
939-
);
940-
match binding {
963+
let macro_resolutions =
964+
mem::replace(&mut *module.single_segment_macro_resolutions.borrow_mut(), Vec::new());
965+
for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
966+
match self.early_resolve_ident_in_lexical_scope(ident, MacroNS, Some(kind), false,
967+
&parent_scope, true, true, ident.span) {
941968
Ok(binding) => {
942-
let def = binding.def_ignoring_ambiguity();
943-
if let Some(initial_binding) = initial_binding {
969+
let initial_def = initial_binding.map(|initial_binding| {
944970
self.record_use(ident, MacroNS, initial_binding);
945-
let initial_def = initial_binding.def_ignoring_ambiguity();
946-
if self.ambiguity_errors.is_empty() &&
947-
def != initial_def && def != Def::Err {
948-
// Make sure compilation does not succeed if preferred macro resolution
949-
// has changed after the macro had been expanded. In theory all such
950-
// situations should be reported as ambiguity errors, so this is a bug.
951-
span_bug!(ident.span, "inconsistent resolution for a macro");
952-
}
953-
} else {
954-
// It's possible that the macro was unresolved (indeterminate) and silently
955-
// expanded into a dummy fragment for recovery during expansion.
956-
// Now, post-expansion, the resolution may succeed, but we can't change the
957-
// past and need to report an error.
958-
let msg = format!("cannot determine resolution for the {} `{}`",
959-
kind.descr(), ident);
960-
let msg_note = "import resolution is stuck, try simplifying macro imports";
961-
self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
962-
}
971+
initial_binding.def_ignoring_ambiguity()
972+
});
973+
let def = binding.def_ignoring_ambiguity();
974+
check_consistency(self, &[ident], ident.span, kind, initial_def, def);
963975
}
964976
Err(..) => {
965977
assert!(initial_binding.is_none());

0 commit comments

Comments
 (0)