Skip to content

Commit 4c5d822

Browse files
committed
resolve: Check resolution consistency for import paths and multi-segment macro paths
1 parent 07af4ec commit 4c5d822

20 files changed

+368
-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
@@ -1025,6 +1025,18 @@ enum ModuleOrUniformRoot<'a> {
10251025
UniformRoot(UniformRootKind),
10261026
}
10271027

1028+
impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
1029+
fn eq(&self, other: &Self) -> bool {
1030+
match (*self, *other) {
1031+
(ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
1032+
ptr::eq(lhs, rhs),
1033+
(ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) =>
1034+
lhs == rhs,
1035+
_ => false,
1036+
}
1037+
}
1038+
}
1039+
10281040
#[derive(Clone, Debug)]
10291041
enum PathResult<'a> {
10301042
Module(ModuleOrUniformRoot<'a>),
@@ -1066,9 +1078,10 @@ pub struct ModuleData<'a> {
10661078
normal_ancestor_id: DefId,
10671079

10681080
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
1069-
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1070-
Option<&'a NameBinding<'a>>)>>,
1071-
macro_resolutions: RefCell<Vec<(Vec<Segment>, ParentScope<'a>, Span)>>,
1081+
single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1082+
Option<&'a NameBinding<'a>>)>>,
1083+
multi_segment_macro_resolutions: RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>,
1084+
Option<Def>)>>,
10721085
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
10731086

10741087
// Macro invocations that can expand into items in this module.
@@ -1106,8 +1119,8 @@ impl<'a> ModuleData<'a> {
11061119
kind,
11071120
normal_ancestor_id,
11081121
resolutions: Default::default(),
1109-
legacy_macro_resolutions: RefCell::new(Vec::new()),
1110-
macro_resolutions: RefCell::new(Vec::new()),
1122+
single_segment_macro_resolutions: RefCell::new(Vec::new()),
1123+
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
11111124
builtin_attrs: RefCell::new(Vec::new()),
11121125
unresolved_invocations: Default::default(),
11131126
no_implicit_prelude: false,
@@ -1503,6 +1516,9 @@ pub struct Resolver<'a, 'b: 'a> {
15031516
/// The current self item if inside an ADT (used for better errors).
15041517
current_self_item: Option<NodeId>,
15051518

1519+
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
1520+
last_import_segment: bool,
1521+
15061522
/// The idents for the primitive types.
15071523
primitive_type_table: PrimitiveTypeTable,
15081524

@@ -1852,6 +1868,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18521868
current_trait_ref: None,
18531869
current_self_type: None,
18541870
current_self_item: None,
1871+
last_import_segment: false,
18551872

18561873
primitive_type_table: PrimitiveTypeTable::new(),
18571874

@@ -1953,27 +1970,23 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
19531970
self.arenas.alloc_module(module)
19541971
}
19551972

1956-
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
1957-
-> bool /* true if an error was reported */ {
1973+
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>) {
19581974
match binding.kind {
1959-
NameBindingKind::Import { directive, binding, ref used }
1960-
if !used.get() => {
1975+
NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
19611976
used.set(true);
19621977
directive.used.set(true);
19631978
self.used_imports.insert((directive.id, ns));
19641979
self.add_to_glob_map(directive.id, ident);
1965-
self.record_use(ident, ns, binding)
1980+
self.record_use(ident, ns, binding);
19661981
}
1967-
NameBindingKind::Import { .. } => false,
19681982
NameBindingKind::Ambiguity { kind, b1, b2 } => {
19691983
self.ambiguity_errors.push(AmbiguityError {
19701984
kind, ident, b1, b2,
19711985
misc1: AmbiguityErrorMisc::None,
19721986
misc2: AmbiguityErrorMisc::None,
19731987
});
1974-
true
19751988
}
1976-
_ => false
1989+
_ => {}
19771990
}
19781991
}
19791992

@@ -4801,7 +4814,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
48014814

48024815
fn report_errors(&mut self, krate: &Crate) {
48034816
self.report_with_use_injections(krate);
4804-
let mut reported_spans = FxHashSet::default();
48054817

48064818
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
48074819
let msg = "macro-expanded `macro_export` macros from the current crate \
@@ -4815,11 +4827,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
48154827
}
48164828

48174829
for ambiguity_error in &self.ambiguity_errors {
4818-
if reported_spans.insert(ambiguity_error.ident.span) {
4819-
self.report_ambiguity_error(ambiguity_error);
4820-
}
4830+
self.report_ambiguity_error(ambiguity_error);
48214831
}
48224832

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

src/librustc_resolve/macros.rs

Lines changed: 61 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};
@@ -480,29 +481,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
480481
if path.len() > 1 {
481482
let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
482483
false, path_span, CrateLint::No) {
483-
PathResult::NonModule(path_res) => match path_res.base_def() {
484-
Def::Err => Err(Determinacy::Determined),
485-
def @ _ => {
486-
if path_res.unresolved_segments() > 0 {
487-
self.found_unresolved_macro = true;
488-
self.session.span_err(path_span,
489-
"fail to resolve non-ident macro path");
490-
Err(Determinacy::Determined)
491-
} else {
492-
Ok(def)
493-
}
494-
}
495-
},
496-
PathResult::Module(..) => unreachable!(),
484+
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
485+
Ok(path_res.base_def())
486+
}
497487
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
498-
_ => {
488+
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
499489
self.found_unresolved_macro = true;
500490
Err(Determinacy::Determined)
501-
},
491+
}
492+
PathResult::Module(..) => unreachable!(),
502493
};
503494

504-
parent_scope.module.macro_resolutions.borrow_mut()
505-
.push((path, parent_scope.clone(), path_span));
495+
parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
496+
.push((path, path_span, kind, parent_scope.clone(), def.ok()));
506497

507498
def
508499
} else {
@@ -515,7 +506,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
515506
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
516507
}
517508

518-
parent_scope.module.legacy_macro_resolutions.borrow_mut()
509+
parent_scope.module.single_segment_macro_resolutions.borrow_mut()
519510
.push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
520511

521512
binding.map(|binding| binding.def_ignoring_ambiguity())
@@ -922,50 +913,68 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
922913
pub fn finalize_current_module_macro_resolutions(&mut self) {
923914
let module = self.current_module;
924915

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

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

0 commit comments

Comments
 (0)