resolve: Check resolution consistency for import paths and multi-segment macro paths
This commit is contained in:
parent
07af4ec7a2
commit
4c5d822a8b
@ -330,6 +330,7 @@ pub fn article(&self) -> &'static str {
|
||||
match *self {
|
||||
Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::AssociatedExistential(..) |
|
||||
Def::Enum(..) | Def::Existential(..) | Def::Err => "an",
|
||||
Def::Macro(.., macro_kind) => macro_kind.article(),
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
|
@ -225,8 +225,8 @@ pub struct DefId {
|
||||
|
||||
impl fmt::Debug for DefId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "DefId({:?}/{}:{}",
|
||||
self.krate.index(),
|
||||
write!(f, "DefId({}/{}:{}",
|
||||
self.krate,
|
||||
self.index.address_space().index(),
|
||||
self.index.as_array_index())?;
|
||||
|
||||
|
@ -1025,6 +1025,18 @@ enum ModuleOrUniformRoot<'a> {
|
||||
UniformRoot(UniformRootKind),
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (*self, *other) {
|
||||
(ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
|
||||
ptr::eq(lhs, rhs),
|
||||
(ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) =>
|
||||
lhs == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum PathResult<'a> {
|
||||
Module(ModuleOrUniformRoot<'a>),
|
||||
@ -1066,9 +1078,10 @@ pub struct ModuleData<'a> {
|
||||
normal_ancestor_id: DefId,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
|
||||
Option<&'a NameBinding<'a>>)>>,
|
||||
macro_resolutions: RefCell<Vec<(Vec<Segment>, ParentScope<'a>, Span)>>,
|
||||
single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
|
||||
Option<&'a NameBinding<'a>>)>>,
|
||||
multi_segment_macro_resolutions: RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>,
|
||||
Option<Def>)>>,
|
||||
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
@ -1106,8 +1119,8 @@ fn new(parent: Option<Module<'a>>,
|
||||
kind,
|
||||
normal_ancestor_id,
|
||||
resolutions: Default::default(),
|
||||
legacy_macro_resolutions: RefCell::new(Vec::new()),
|
||||
macro_resolutions: RefCell::new(Vec::new()),
|
||||
single_segment_macro_resolutions: RefCell::new(Vec::new()),
|
||||
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
|
||||
builtin_attrs: RefCell::new(Vec::new()),
|
||||
unresolved_invocations: Default::default(),
|
||||
no_implicit_prelude: false,
|
||||
@ -1503,6 +1516,9 @@ pub struct Resolver<'a, 'b: 'a> {
|
||||
/// The current self item if inside an ADT (used for better errors).
|
||||
current_self_item: Option<NodeId>,
|
||||
|
||||
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
|
||||
last_import_segment: bool,
|
||||
|
||||
/// The idents for the primitive types.
|
||||
primitive_type_table: PrimitiveTypeTable,
|
||||
|
||||
@ -1852,6 +1868,7 @@ pub fn new(session: &'a Session,
|
||||
current_trait_ref: None,
|
||||
current_self_type: None,
|
||||
current_self_item: None,
|
||||
last_import_segment: false,
|
||||
|
||||
primitive_type_table: PrimitiveTypeTable::new(),
|
||||
|
||||
@ -1953,27 +1970,23 @@ fn new_module(
|
||||
self.arenas.alloc_module(module)
|
||||
}
|
||||
|
||||
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
|
||||
-> bool /* true if an error was reported */ {
|
||||
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>) {
|
||||
match binding.kind {
|
||||
NameBindingKind::Import { directive, binding, ref used }
|
||||
if !used.get() => {
|
||||
NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
|
||||
used.set(true);
|
||||
directive.used.set(true);
|
||||
self.used_imports.insert((directive.id, ns));
|
||||
self.add_to_glob_map(directive.id, ident);
|
||||
self.record_use(ident, ns, binding)
|
||||
self.record_use(ident, ns, binding);
|
||||
}
|
||||
NameBindingKind::Import { .. } => false,
|
||||
NameBindingKind::Ambiguity { kind, b1, b2 } => {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
kind, ident, b1, b2,
|
||||
misc1: AmbiguityErrorMisc::None,
|
||||
misc2: AmbiguityErrorMisc::None,
|
||||
});
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4801,7 +4814,6 @@ fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError) {
|
||||
|
||||
fn report_errors(&mut self, krate: &Crate) {
|
||||
self.report_with_use_injections(krate);
|
||||
let mut reported_spans = FxHashSet::default();
|
||||
|
||||
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
|
||||
let msg = "macro-expanded `macro_export` macros from the current crate \
|
||||
@ -4815,11 +4827,10 @@ fn report_errors(&mut self, krate: &Crate) {
|
||||
}
|
||||
|
||||
for ambiguity_error in &self.ambiguity_errors {
|
||||
if reported_spans.insert(ambiguity_error.ident.span) {
|
||||
self.report_ambiguity_error(ambiguity_error);
|
||||
}
|
||||
self.report_ambiguity_error(ambiguity_error);
|
||||
}
|
||||
|
||||
let mut reported_spans = FxHashSet::default();
|
||||
for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
|
||||
if reported_spans.insert(dedup_span) {
|
||||
span_err!(self.session, ident.span, E0603, "{} `{}` is private",
|
||||
|
@ -9,8 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
|
||||
use {CrateLint, DeterminacyExt, Resolver, ResolutionError, is_known_tool, resolve_error};
|
||||
use {CrateLint, DeterminacyExt, Resolver, ResolutionError};
|
||||
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
|
||||
use {is_known_tool, names_to_string, resolve_error};
|
||||
use ModuleOrUniformRoot;
|
||||
use Namespace::{self, *};
|
||||
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
|
||||
@ -480,29 +481,19 @@ pub fn resolve_macro_to_def_inner(
|
||||
if path.len() > 1 {
|
||||
let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
|
||||
false, path_span, CrateLint::No) {
|
||||
PathResult::NonModule(path_res) => match path_res.base_def() {
|
||||
Def::Err => Err(Determinacy::Determined),
|
||||
def @ _ => {
|
||||
if path_res.unresolved_segments() > 0 {
|
||||
self.found_unresolved_macro = true;
|
||||
self.session.span_err(path_span,
|
||||
"fail to resolve non-ident macro path");
|
||||
Err(Determinacy::Determined)
|
||||
} else {
|
||||
Ok(def)
|
||||
}
|
||||
}
|
||||
},
|
||||
PathResult::Module(..) => unreachable!(),
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
Ok(path_res.base_def())
|
||||
}
|
||||
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
||||
_ => {
|
||||
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
|
||||
self.found_unresolved_macro = true;
|
||||
Err(Determinacy::Determined)
|
||||
},
|
||||
}
|
||||
PathResult::Module(..) => unreachable!(),
|
||||
};
|
||||
|
||||
parent_scope.module.macro_resolutions.borrow_mut()
|
||||
.push((path, parent_scope.clone(), path_span));
|
||||
parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
|
||||
.push((path, path_span, kind, parent_scope.clone(), def.ok()));
|
||||
|
||||
def
|
||||
} else {
|
||||
@ -515,7 +506,7 @@ pub fn resolve_macro_to_def_inner(
|
||||
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
|
||||
}
|
||||
|
||||
parent_scope.module.legacy_macro_resolutions.borrow_mut()
|
||||
parent_scope.module.single_segment_macro_resolutions.borrow_mut()
|
||||
.push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
|
||||
|
||||
binding.map(|binding| binding.def_ignoring_ambiguity())
|
||||
@ -922,50 +913,68 @@ struct Flags: u8 {
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
let module = self.current_module;
|
||||
|
||||
let check_consistency = |this: &mut Self, path: &[Ident], span,
|
||||
kind: MacroKind, initial_def, def| {
|
||||
if let Some(initial_def) = initial_def {
|
||||
if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() {
|
||||
// Make sure compilation does not succeed if preferred macro resolution
|
||||
// has changed after the macro had been expanded. In theory all such
|
||||
// situations should be reported as ambiguity errors, so this is a bug.
|
||||
span_bug!(span, "inconsistent resolution for a macro");
|
||||
}
|
||||
} else {
|
||||
// It's possible that the macro was unresolved (indeterminate) and silently
|
||||
// expanded into a dummy fragment for recovery during expansion.
|
||||
// Now, post-expansion, the resolution may succeed, but we can't change the
|
||||
// past and need to report an error.
|
||||
// However, non-speculative `resolve_path` can successfully return private items
|
||||
// even if speculative `resolve_path` returned nothing previously, so we skip this
|
||||
// less informative error if the privacy error is reported elsewhere.
|
||||
if this.privacy_errors.is_empty() {
|
||||
let msg = format!("cannot determine resolution for the {} `{}`",
|
||||
kind.descr(), names_to_string(path));
|
||||
let msg_note = "import resolution is stuck, try simplifying macro imports";
|
||||
this.session.struct_span_err(span, &msg).note(msg_note).emit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let macro_resolutions =
|
||||
mem::replace(&mut *module.macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (mut path, parent_scope, path_span) in macro_resolutions {
|
||||
mem::replace(&mut *module.multi_segment_macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (mut path, path_span, kind, parent_scope, initial_def) in macro_resolutions {
|
||||
// FIXME: Path resolution will ICE if segment IDs present.
|
||||
for seg in &mut path { seg.id = None; }
|
||||
match self.resolve_path(&path, Some(MacroNS), &parent_scope,
|
||||
true, path_span, CrateLint::No) {
|
||||
PathResult::NonModule(_) => {},
|
||||
PathResult::Failed(span, msg, _) => {
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
let def = path_res.base_def();
|
||||
check_consistency(self, &path, path_span, kind, initial_def, def);
|
||||
}
|
||||
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => {
|
||||
let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
|
||||
(span, msg)
|
||||
} else {
|
||||
(path_span, format!("partially resolved path in {} {}",
|
||||
kind.article(), kind.descr()))
|
||||
};
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let legacy_macro_resolutions =
|
||||
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
ident, MacroNS, Some(kind), false, &parent_scope, true, true, ident.span
|
||||
);
|
||||
match binding {
|
||||
let macro_resolutions =
|
||||
mem::replace(&mut *module.single_segment_macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
|
||||
match self.early_resolve_ident_in_lexical_scope(ident, MacroNS, Some(kind), false,
|
||||
&parent_scope, true, true, ident.span) {
|
||||
Ok(binding) => {
|
||||
let def = binding.def_ignoring_ambiguity();
|
||||
if let Some(initial_binding) = initial_binding {
|
||||
let initial_def = initial_binding.map(|initial_binding| {
|
||||
self.record_use(ident, MacroNS, initial_binding);
|
||||
let initial_def = initial_binding.def_ignoring_ambiguity();
|
||||
if self.ambiguity_errors.is_empty() &&
|
||||
def != initial_def && def != Def::Err {
|
||||
// Make sure compilation does not succeed if preferred macro resolution
|
||||
// has changed after the macro had been expanded. In theory all such
|
||||
// situations should be reported as ambiguity errors, so this is a bug.
|
||||
span_bug!(ident.span, "inconsistent resolution for a macro");
|
||||
}
|
||||
} else {
|
||||
// It's possible that the macro was unresolved (indeterminate) and silently
|
||||
// expanded into a dummy fragment for recovery during expansion.
|
||||
// Now, post-expansion, the resolution may succeed, but we can't change the
|
||||
// past and need to report an error.
|
||||
let msg = format!("cannot determine resolution for the {} `{}`",
|
||||
kind.descr(), ident);
|
||||
let msg_note = "import resolution is stuck, try simplifying macro imports";
|
||||
self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
|
||||
}
|
||||
initial_binding.def_ignoring_ambiguity()
|
||||
});
|
||||
let def = binding.def_ignoring_ambiguity();
|
||||
check_consistency(self, &[ident], ident.span, kind, initial_def, def);
|
||||
}
|
||||
Err(..) => {
|
||||
assert!(initial_binding.is_none());
|
||||
|
@ -222,40 +222,47 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
if record_used {
|
||||
if let Some(binding) = resolution.binding {
|
||||
if let Some(shadowed_glob) = resolution.shadowed_glob {
|
||||
// Forbid expanded shadowing to avoid time travel.
|
||||
if restricted_shadowing &&
|
||||
binding.expansion != Mark::root() &&
|
||||
binding.def() != shadowed_glob.def() {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
kind: AmbiguityKind::GlobVsExpanded,
|
||||
ident,
|
||||
b1: binding,
|
||||
b2: shadowed_glob,
|
||||
misc1: AmbiguityErrorMisc::None,
|
||||
misc2: AmbiguityErrorMisc::None,
|
||||
});
|
||||
}
|
||||
}
|
||||
if self.record_use(ident, ns, binding) {
|
||||
return Ok(self.dummy_binding);
|
||||
}
|
||||
if !self.is_accessible(binding.vis) {
|
||||
self.privacy_errors.push(PrivacyError(path_span, ident, binding));
|
||||
}
|
||||
}
|
||||
|
||||
return resolution.binding.ok_or(DeterminacyExt::Determined);
|
||||
}
|
||||
|
||||
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
|
||||
// `extern crate` are always usable for backwards compatibility, see issue #37020.
|
||||
// `extern crate` are always usable for backwards compatibility, see issue #37020,
|
||||
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
|
||||
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
|
||||
if usable { Ok(binding) } else { Err(DeterminacyExt::Determined) }
|
||||
};
|
||||
|
||||
if record_used {
|
||||
return resolution.binding.ok_or(DeterminacyExt::Determined).and_then(|binding| {
|
||||
if self.last_import_segment && check_usable(self, binding).is_err() {
|
||||
Err(DeterminacyExt::Determined)
|
||||
} else {
|
||||
self.record_use(ident, ns, binding);
|
||||
|
||||
if let Some(shadowed_glob) = resolution.shadowed_glob {
|
||||
// Forbid expanded shadowing to avoid time travel.
|
||||
if restricted_shadowing &&
|
||||
binding.expansion != Mark::root() &&
|
||||
binding.def() != shadowed_glob.def() {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
kind: AmbiguityKind::GlobVsExpanded,
|
||||
ident,
|
||||
b1: binding,
|
||||
b2: shadowed_glob,
|
||||
misc1: AmbiguityErrorMisc::None,
|
||||
misc2: AmbiguityErrorMisc::None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !self.is_accessible(binding.vis) &&
|
||||
// Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
!(self.last_import_segment && binding.is_extern_crate()) {
|
||||
self.privacy_errors.push(PrivacyError(path_span, ident, binding));
|
||||
}
|
||||
|
||||
Ok(binding)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Items and single imports are not shadowable, if we have one, then it's determined.
|
||||
if let Some(binding) = resolution.binding {
|
||||
if !binding.is_glob_import() {
|
||||
@ -628,8 +635,7 @@ pub fn finalize_imports(&mut self) {
|
||||
let mut prev_root_id: NodeId = NodeId::from_u32(0);
|
||||
for i in 0 .. self.determined_imports.len() {
|
||||
let import = self.determined_imports[i];
|
||||
let error = self.finalize_import(import);
|
||||
if let Some((span, err, note)) = error {
|
||||
if let Some((span, err, note)) = self.finalize_import(import) {
|
||||
errors = true;
|
||||
|
||||
if let SingleImport { source, ref result, .. } = import.subclass {
|
||||
@ -726,7 +732,7 @@ fn throw_unresolved_import_error(
|
||||
/// If successful, the resolved bindings are written into the module.
|
||||
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
|
||||
Segment::names_to_string(&directive.module_path[..]),
|
||||
Segment::names_to_string(&directive.module_path),
|
||||
module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
|
||||
|
||||
self.current_module = directive.parent_scope.module;
|
||||
@ -737,8 +743,8 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
// For better failure detection, pretend that the import will
|
||||
// not define any names while resolving its module path.
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let result = self.resolve_path(
|
||||
&directive.module_path[..],
|
||||
let path_res = self.resolve_path(
|
||||
&directive.module_path,
|
||||
None,
|
||||
&directive.parent_scope,
|
||||
false,
|
||||
@ -747,10 +753,10 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
);
|
||||
directive.vis.set(orig_vis);
|
||||
|
||||
match result {
|
||||
match path_res {
|
||||
PathResult::Module(module) => module,
|
||||
PathResult::Indeterminate => return false,
|
||||
_ => return true,
|
||||
PathResult::NonModule(..) | PathResult::Failed(..) => return true,
|
||||
}
|
||||
};
|
||||
|
||||
@ -817,25 +823,37 @@ fn finalize_import(
|
||||
directive: &'b ImportDirective<'b>
|
||||
) -> Option<(Span, String, Option<String>)> {
|
||||
self.current_module = directive.parent_scope.module;
|
||||
let ImportDirective { ref module_path, span, .. } = *directive;
|
||||
|
||||
let module_result = self.resolve_path(
|
||||
&module_path,
|
||||
None,
|
||||
&directive.parent_scope,
|
||||
true,
|
||||
span,
|
||||
directive.crate_lint(),
|
||||
);
|
||||
let module = match module_result {
|
||||
PathResult::Module(module) => module,
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let path_res = self.resolve_path(&directive.module_path, None, &directive.parent_scope,
|
||||
true, directive.span, directive.crate_lint());
|
||||
directive.vis.set(orig_vis);
|
||||
let module = match path_res {
|
||||
PathResult::Module(module) => {
|
||||
// Consistency checks, analogous to `finalize_current_module_macro_resolutions`.
|
||||
if let Some(initial_module) = directive.imported_module.get() {
|
||||
if module != initial_module && self.ambiguity_errors.is_empty() {
|
||||
span_bug!(directive.span, "inconsistent resolution for an import");
|
||||
}
|
||||
} else {
|
||||
if self.privacy_errors.is_empty() {
|
||||
let msg = "cannot determine resolution for the import";
|
||||
let msg_note = "import resolution is stuck, try simplifying other imports";
|
||||
self.session.struct_span_err(directive.span, msg).note(msg_note).emit();
|
||||
}
|
||||
}
|
||||
|
||||
module
|
||||
}
|
||||
PathResult::Failed(span, msg, false) => {
|
||||
assert!(directive.imported_module.get().is_none());
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
return None;
|
||||
}
|
||||
PathResult::Failed(span, msg, true) => {
|
||||
assert!(directive.imported_module.get().is_none());
|
||||
return if let Some((suggested_path, note)) = self.make_path_suggestion(
|
||||
span, module_path.clone(), &directive.parent_scope
|
||||
span, directive.module_path.clone(), &directive.parent_scope
|
||||
) {
|
||||
Some((
|
||||
span,
|
||||
@ -845,17 +863,22 @@ fn finalize_import(
|
||||
} else {
|
||||
Some((span, msg, None))
|
||||
};
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
PathResult::NonModule(path_res) if path_res.base_def() == Def::Err => {
|
||||
// The error was already reported earlier.
|
||||
assert!(directive.imported_module.get().is_none());
|
||||
return None;
|
||||
}
|
||||
PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(),
|
||||
};
|
||||
|
||||
let (ident, result, type_ns_only) = match directive.subclass {
|
||||
SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
|
||||
GlobImport { is_prelude, ref max_vis } => {
|
||||
if module_path.len() <= 1 {
|
||||
if directive.module_path.len() <= 1 {
|
||||
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
|
||||
// 2 segments, so the `resolve_path` above won't trigger it.
|
||||
let mut full_path = module_path.clone();
|
||||
let mut full_path = directive.module_path.clone();
|
||||
full_path.push(Segment::from_ident(keywords::Invalid.ident()));
|
||||
self.lint_if_path_starts_with_module(
|
||||
directive.crate_lint(),
|
||||
@ -888,20 +911,39 @@ fn finalize_import(
|
||||
|
||||
let mut all_ns_err = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
if let Ok(binding) = result[ns].get() {
|
||||
all_ns_err = false;
|
||||
if this.record_use(ident, ns, binding) {
|
||||
if let ModuleOrUniformRoot::Module(module) = module {
|
||||
this.resolution(module, ident, ns).borrow_mut().binding =
|
||||
Some(this.dummy_binding);
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
|
||||
let binding = this.resolve_ident_in_module(
|
||||
module, ident, ns, Some(&directive.parent_scope), true, directive.span
|
||||
);
|
||||
this.last_import_segment = orig_last_import_segment;
|
||||
directive.vis.set(orig_vis);
|
||||
|
||||
match binding {
|
||||
Ok(binding) => {
|
||||
// Consistency checks, analogous to `finalize_current_module_macro_resolutions`.
|
||||
let initial_def = result[ns].get().map(|initial_binding| {
|
||||
all_ns_err = false;
|
||||
this.record_use(ident, MacroNS, initial_binding);
|
||||
initial_binding.def_ignoring_ambiguity()
|
||||
});
|
||||
let def = binding.def_ignoring_ambiguity();
|
||||
if let Ok(initial_def) = initial_def {
|
||||
if def != initial_def && this.ambiguity_errors.is_empty() {
|
||||
span_bug!(directive.span, "inconsistent resolution for an import");
|
||||
}
|
||||
} else {
|
||||
if def != Def::Err &&
|
||||
this.ambiguity_errors.is_empty() && this.privacy_errors.is_empty() {
|
||||
let msg = "cannot determine resolution for the import";
|
||||
let msg_note =
|
||||
"import resolution is stuck, try simplifying other imports";
|
||||
this.session.struct_span_err(directive.span, msg).note(msg_note).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ns == TypeNS {
|
||||
if let ModuleOrUniformRoot::UniformRoot(..) = module {
|
||||
// Make sure single-segment import is resolved non-speculatively
|
||||
// at least once to report the feature error.
|
||||
this.extern_prelude_get(ident, false, false);
|
||||
}
|
||||
Err(..) => {
|
||||
assert!(result[ns].get().is_err());
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -910,7 +952,7 @@ fn finalize_import(
|
||||
let mut all_ns_failed = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let binding = this.resolve_ident_in_module(
|
||||
module, ident, ns, Some(&directive.parent_scope), true, span
|
||||
module, ident, ns, Some(&directive.parent_scope), true, directive.span
|
||||
);
|
||||
if binding.is_ok() {
|
||||
all_ns_failed = false;
|
||||
@ -969,7 +1011,7 @@ fn finalize_import(
|
||||
}
|
||||
}
|
||||
};
|
||||
Some((span, msg, None))
|
||||
Some((directive.span, msg, None))
|
||||
} else {
|
||||
// `resolve_ident_in_module` reported a privacy error.
|
||||
self.import_dummy_binding(directive);
|
||||
@ -1018,10 +1060,10 @@ fn finalize_import(
|
||||
}
|
||||
}
|
||||
|
||||
if module_path.len() <= 1 {
|
||||
if directive.module_path.len() <= 1 {
|
||||
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
|
||||
// 2 segments, so the `resolve_path` above won't trigger it.
|
||||
let mut full_path = module_path.clone();
|
||||
let mut full_path = directive.module_path.clone();
|
||||
full_path.push(Segment::from_ident(ident));
|
||||
self.per_ns(|this, ns| {
|
||||
if let Ok(binding) = result[ns].get() {
|
||||
|
@ -595,6 +595,13 @@ pub fn descr(self) -> &'static str {
|
||||
MacroKind::ProcMacroStub => "crate-local procedural macro",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn article(self) -> &'static str {
|
||||
match self {
|
||||
MacroKind::Attr => "an",
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum representing the different kinds of syntax extensions.
|
||||
|
2
src/test/ui/extern/extern-macro.rs
vendored
2
src/test/ui/extern/extern-macro.rs
vendored
@ -12,5 +12,5 @@
|
||||
|
||||
fn main() {
|
||||
enum Foo {}
|
||||
let _ = Foo::bar!(); //~ ERROR fail to resolve non-ident macro path
|
||||
let _ = Foo::bar!(); //~ ERROR failed to resolve. partially resolved path in a macro
|
||||
}
|
||||
|
7
src/test/ui/extern/extern-macro.stderr
vendored
7
src/test/ui/extern/extern-macro.stderr
vendored
@ -1,8 +1,9 @@
|
||||
error: fail to resolve non-ident macro path
|
||||
error[E0433]: failed to resolve. partially resolved path in a macro
|
||||
--> $DIR/extern-macro.rs:15:13
|
||||
|
|
||||
LL | let _ = Foo::bar!(); //~ ERROR fail to resolve non-ident macro path
|
||||
| ^^^^^^^^
|
||||
LL | let _ = Foo::bar!(); //~ ERROR failed to resolve. partially resolved path in a macro
|
||||
| ^^^^^^^^ partially resolved path in a macro
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
mod m {
|
||||
fn check() {
|
||||
Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
|
||||
Result::Ok!(); //~ ERROR failed to resolve. partially resolved path in a macro
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
error: fail to resolve non-ident macro path
|
||||
error[E0433]: failed to resolve. partially resolved path in a macro
|
||||
--> $DIR/macro-path-prelude-fail-2.rs:13:9
|
||||
|
|
||||
LL | Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
|
||||
| ^^^^^^^^^^
|
||||
LL | Result::Ok!(); //~ ERROR failed to resolve. partially resolved path in a macro
|
||||
| ^^^^^^^^^^ partially resolved path in a macro
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
|
9
src/test/ui/privacy/decl-macro.rs
Normal file
9
src/test/ui/privacy/decl-macro.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod m {
|
||||
macro mac() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m::mac!(); //~ ERROR macro `mac` is private
|
||||
}
|
9
src/test/ui/privacy/decl-macro.stderr
Normal file
9
src/test/ui/privacy/decl-macro.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0603]: macro `mac` is private
|
||||
--> $DIR/decl-macro.rs:8:8
|
||||
|
|
||||
LL | m::mac!(); //~ ERROR macro `mac` is private
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0603`.
|
@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate`
|
||||
--> $DIR/non-existent-1.rs:13:5
|
||||
|
|
||||
LL | use xcrate::S; //~ ERROR unresolved import `xcrate`
|
||||
| ^^^^^^ Could not find `xcrate` in `{{root}}`
|
||||
| ^^^^^^ Use of undeclared type or module `xcrate`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -16,6 +16,6 @@ fn main() {
|
||||
fn std() {}
|
||||
enum std {}
|
||||
use std as foo;
|
||||
//~^ ERROR `std` import is ambiguous
|
||||
//~| ERROR `std` import is ambiguous
|
||||
//~^ ERROR `std` is ambiguous
|
||||
//~| ERROR `std` is ambiguous
|
||||
}
|
||||
|
@ -1,31 +1,39 @@
|
||||
error: `std` import is ambiguous
|
||||
error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow.rs:18:9
|
||||
|
|
||||
LL | struct std;
|
||||
| ----------- may refer to `self::std` in the future
|
||||
...
|
||||
LL | enum std {}
|
||||
| ----------- shadowed by block-scoped `std`
|
||||
LL | use std as foo;
|
||||
| ^^^ can refer to external crate `::std`
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
= help: write `::std` or `self::std` explicitly instead
|
||||
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||
note: `std` could refer to the enum defined here
|
||||
--> $DIR/block-scoped-shadow.rs:17:5
|
||||
|
|
||||
LL | enum std {}
|
||||
| ^^^^^^^^^^^
|
||||
note: `std` could also refer to the struct defined here
|
||||
--> $DIR/block-scoped-shadow.rs:13:1
|
||||
|
|
||||
LL | struct std;
|
||||
| ^^^^^^^^^^^
|
||||
= help: use `self::std` to refer to the struct unambiguously
|
||||
|
||||
error: `std` import is ambiguous
|
||||
error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow.rs:18:9
|
||||
|
|
||||
LL | struct std;
|
||||
| ----------- may refer to `self::std` in the future
|
||||
...
|
||||
LL | fn std() {}
|
||||
| ----------- shadowed by block-scoped `std`
|
||||
LL | enum std {}
|
||||
LL | use std as foo;
|
||||
| ^^^
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
= help: write `self::std` explicitly instead
|
||||
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||
note: `std` could refer to the function defined here
|
||||
--> $DIR/block-scoped-shadow.rs:16:5
|
||||
|
|
||||
LL | fn std() {}
|
||||
| ^^^^^^^^^^^
|
||||
note: `std` could also refer to the unit struct defined here
|
||||
--> $DIR/block-scoped-shadow.rs:13:1
|
||||
|
|
||||
LL | struct std;
|
||||
| ^^^^^^^^^^^
|
||||
= help: use `self::std` to refer to the unit struct unambiguously
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
||||
|
@ -0,0 +1,20 @@
|
||||
// edition:2018
|
||||
|
||||
mod my {
|
||||
pub mod sub {
|
||||
pub fn bar() {}
|
||||
}
|
||||
}
|
||||
|
||||
mod sub {
|
||||
pub fn bar() {}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
use my::sub;
|
||||
{
|
||||
use sub::bar; //~ ERROR `sub` is ambiguous
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,23 @@
|
||||
error[E0659]: `sub` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow-nested.rs:16:13
|
||||
|
|
||||
LL | use sub::bar; //~ ERROR `sub` is ambiguous
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
note: `sub` could refer to the module imported here
|
||||
--> $DIR/block-scoped-shadow-nested.rs:14:9
|
||||
|
|
||||
LL | use my::sub;
|
||||
| ^^^^^^^
|
||||
note: `sub` could also refer to the module defined here
|
||||
--> $DIR/block-scoped-shadow-nested.rs:9:1
|
||||
|
|
||||
LL | / mod sub {
|
||||
LL | | pub fn bar() {}
|
||||
LL | | }
|
||||
| |_^
|
||||
= help: use `self::sub` to refer to the module unambiguously
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
@ -12,20 +12,20 @@
|
||||
|
||||
#![feature(uniform_paths)]
|
||||
|
||||
enum Foo { A, B }
|
||||
enum Foo {}
|
||||
|
||||
struct std;
|
||||
|
||||
fn main() {
|
||||
enum Foo {}
|
||||
enum Foo { A, B }
|
||||
use Foo::*;
|
||||
//~^ ERROR `Foo` import is ambiguous
|
||||
//~^ ERROR `Foo` is ambiguous
|
||||
|
||||
let _ = (A, B);
|
||||
|
||||
fn std() {}
|
||||
enum std {}
|
||||
use std as foo;
|
||||
//~^ ERROR `std` import is ambiguous
|
||||
//~| ERROR `std` import is ambiguous
|
||||
//~^ ERROR `std` is ambiguous
|
||||
//~| ERROR `std` is ambiguous
|
||||
}
|
||||
|
@ -1,45 +1,57 @@
|
||||
error: `Foo` import is ambiguous
|
||||
error[E0659]: `Foo` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow.rs:21:9
|
||||
|
|
||||
LL | enum Foo { A, B }
|
||||
| ----------------- can refer to `self::Foo`
|
||||
...
|
||||
LL | enum Foo {}
|
||||
| ----------- shadowed by block-scoped `Foo`
|
||||
LL | use Foo::*;
|
||||
| ^^^
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
= help: write `self::Foo` explicitly instead
|
||||
= note: relative `use` paths enabled by `#![feature(uniform_paths)]`
|
||||
note: `Foo` could refer to the enum defined here
|
||||
--> $DIR/block-scoped-shadow.rs:20:5
|
||||
|
|
||||
LL | enum Foo { A, B }
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: `Foo` could also refer to the enum defined here
|
||||
--> $DIR/block-scoped-shadow.rs:15:1
|
||||
|
|
||||
LL | enum Foo {}
|
||||
| ^^^^^^^^^^^
|
||||
= help: use `self::Foo` to refer to the enum unambiguously
|
||||
|
||||
error: `std` import is ambiguous
|
||||
error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow.rs:28:9
|
||||
|
|
||||
LL | struct std;
|
||||
| ----------- can refer to `self::std`
|
||||
...
|
||||
LL | enum std {}
|
||||
| ----------- shadowed by block-scoped `std`
|
||||
LL | use std as foo;
|
||||
| ^^^ can refer to external crate `::std`
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
= help: write `::std` or `self::std` explicitly instead
|
||||
= note: relative `use` paths enabled by `#![feature(uniform_paths)]`
|
||||
|
||||
error: `std` import is ambiguous
|
||||
--> $DIR/block-scoped-shadow.rs:28:9
|
||||
note: `std` could refer to the enum defined here
|
||||
--> $DIR/block-scoped-shadow.rs:27:5
|
||||
|
|
||||
LL | enum std {}
|
||||
| ^^^^^^^^^^^
|
||||
note: `std` could also refer to the struct defined here
|
||||
--> $DIR/block-scoped-shadow.rs:17:1
|
||||
|
|
||||
LL | struct std;
|
||||
| ----------- can refer to `self::std`
|
||||
...
|
||||
| ^^^^^^^^^^^
|
||||
= help: use `self::std` to refer to the struct unambiguously
|
||||
|
||||
error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
|
||||
--> $DIR/block-scoped-shadow.rs:28:9
|
||||
|
|
||||
LL | use std as foo;
|
||||
| ^^^ ambiguous name
|
||||
|
|
||||
note: `std` could refer to the function defined here
|
||||
--> $DIR/block-scoped-shadow.rs:26:5
|
||||
|
|
||||
LL | fn std() {}
|
||||
| ----------- shadowed by block-scoped `std`
|
||||
LL | enum std {}
|
||||
LL | use std as foo;
|
||||
| ^^^
|
||||
| ^^^^^^^^^^^
|
||||
note: `std` could also refer to the unit struct defined here
|
||||
--> $DIR/block-scoped-shadow.rs:17:1
|
||||
|
|
||||
= help: write `self::std` explicitly instead
|
||||
= note: relative `use` paths enabled by `#![feature(uniform_paths)]`
|
||||
LL | struct std;
|
||||
| ^^^^^^^^^^^
|
||||
= help: use `self::std` to refer to the unit struct unambiguously
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
||||
|
13
src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs
Normal file
13
src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// compile-pass
|
||||
// edition:2018
|
||||
|
||||
fn main() {
|
||||
enum E { A, B, C }
|
||||
|
||||
use E::*;
|
||||
match A {
|
||||
A => {}
|
||||
B => {}
|
||||
C => {}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user