diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 07d261da8132f..54e8c03156d55 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -297,6 +297,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Some(TypeNS), parent_scope, if finalize { Finalize::SimplePath(id, path.span) } else { Finalize::No }, + None, ) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => { let res = module.res().expect("visibility resolved to unnamed block"); @@ -1124,12 +1125,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }); } else { for ident in single_imports.iter().cloned() { - let result = self.r.resolve_ident_in_module( + let result = self.r.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, &self.parent_scope, - None, ); if let Ok(binding) = result { let import = macro_use_import(self, ident.span); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 609dbd1fe1b4e..1a03a65c18dcf 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,19 +1,24 @@ use std::ptr; -use rustc_ast::{self as ast, Path}; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self, Visitor}; +use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::struct_span_err; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}; +use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_middle::bug; use rustc_middle::ty::DefIdTree; +use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE; +use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::Session; +use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; @@ -22,11 +27,13 @@ use rustc_span::{BytePos, Span}; use tracing::debug; use crate::imports::{Import, ImportKind, ImportResolver}; +use crate::late::Rib; use crate::path_names_to_string; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; -use crate::{BindingError, HasGenericParams, MacroRulesScope, Module, ModuleOrUniformRoot}; -use crate::{Finalize, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; -use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; +use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; +use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet}; +use crate::{Segment, UseError}; type Res = def::Res; @@ -82,6 +89,390 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span { } impl<'a> Resolver<'a> { + crate fn report_errors(&mut self, krate: &Crate) { + self.report_with_use_injections(krate); + + for &(span_use, span_def) in &self.macro_expanded_macro_export_errors { + let msg = "macro-expanded `macro_export` macros from the current crate \ + cannot be referred to by absolute paths"; + self.lint_buffer.buffer_lint_with_diagnostic( + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + CRATE_NODE_ID, + span_use, + msg, + BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def), + ); + } + + for ambiguity_error in &self.ambiguity_errors { + self.report_ambiguity_error(ambiguity_error); + } + + let mut reported_spans = FxHashSet::default(); + for error in &self.privacy_errors { + if reported_spans.insert(error.dedup_span) { + self.report_privacy_error(error); + } + } + } + + fn report_with_use_injections(&mut self, krate: &Crate) { + for UseError { mut err, candidates, def_id, instead, suggestion } in + self.use_injections.drain(..) + { + let (span, found_use) = if let Some(def_id) = def_id.as_local() { + UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id]) + } else { + (None, false) + }; + if !candidates.is_empty() { + show_candidates( + &self.definitions, + self.session, + &mut err, + span, + &candidates, + instead, + found_use, + ); + } else if let Some((span, msg, sugg, appl)) = suggestion { + err.span_suggestion(span, msg, sugg, appl); + } + err.emit(); + } + } + + crate fn report_conflict<'b>( + &mut self, + parent: Module<'_>, + ident: Ident, + ns: Namespace, + new_binding: &NameBinding<'b>, + old_binding: &NameBinding<'b>, + ) { + // Error on the second of two conflicting names + if old_binding.span.lo() > new_binding.span.lo() { + return self.report_conflict(parent, ident, ns, old_binding, new_binding); + } + + let container = match parent.kind { + ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), + ModuleKind::Block(..) => "block", + }; + + let old_noun = match old_binding.is_import() { + true => "import", + false => "definition", + }; + + let new_participle = match new_binding.is_import() { + true => "imported", + false => "defined", + }; + + let (name, span) = + (ident.name, self.session.source_map().guess_head_span(new_binding.span)); + + if let Some(s) = self.name_already_seen.get(&name) { + if s == &span { + return; + } + } + + let old_kind = match (ns, old_binding.module()) { + (ValueNS, _) => "value", + (MacroNS, _) => "macro", + (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", + (TypeNS, Some(module)) if module.is_normal() => "module", + (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, _) => "type", + }; + + let msg = format!("the name `{}` is defined multiple times", name); + + let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { + (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg), + (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() { + true => struct_span_err!(self.session, span, E0254, "{}", msg), + false => struct_span_err!(self.session, span, E0260, "{}", msg), + }, + _ => match (old_binding.is_import(), new_binding.is_import()) { + (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), + (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg), + _ => struct_span_err!(self.session, span, E0255, "{}", msg), + }, + }; + + err.note(&format!( + "`{}` must be defined only once in the {} namespace of this {}", + name, + ns.descr(), + container + )); + + err.span_label(span, format!("`{}` re{} here", name, new_participle)); + err.span_label( + self.session.source_map().guess_head_span(old_binding.span), + format!("previous {} of the {} `{}` here", old_noun, old_kind, name), + ); + + // See https://github.com/rust-lang/rust/issues/32354 + use NameBindingKind::Import; + let import = match (&new_binding.kind, &old_binding.kind) { + // If there are two imports where one or both have attributes then prefer removing the + // import without attributes. + (Import { import: new, .. }, Import { import: old, .. }) + if { + !new_binding.span.is_dummy() + && !old_binding.span.is_dummy() + && (new.has_attributes || old.has_attributes) + } => + { + if old.has_attributes { + Some((new, new_binding.span, true)) + } else { + Some((old, old_binding.span, true)) + } + } + // Otherwise prioritize the new binding. + (Import { import, .. }, other) if !new_binding.span.is_dummy() => { + Some((import, new_binding.span, other.is_import())) + } + (other, Import { import, .. }) if !old_binding.span.is_dummy() => { + Some((import, old_binding.span, other.is_import())) + } + _ => None, + }; + + // Check if the target of the use for both bindings is the same. + let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); + let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); + let from_item = + self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); + // Only suggest removing an import if both bindings are to the same def, if both spans + // aren't dummy spans. Further, if both bindings are imports, then the ident must have + // been introduced by an item. + let should_remove_import = duplicate + && !has_dummy_span + && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item); + + match import { + Some((import, span, true)) if should_remove_import && import.is_nested() => { + self.add_suggestion_for_duplicate_nested_use(&mut err, import, span) + } + Some((import, _, true)) if should_remove_import && !import.is_glob() => { + // Simple case - remove the entire import. Due to the above match arm, this can + // only be a single use so just remove it entirely. + err.tool_only_span_suggestion( + import.use_span_with_attributes, + "remove unnecessary import", + String::new(), + Applicability::MaybeIncorrect, + ); + } + Some((import, span, _)) => { + self.add_suggestion_for_rename_of_use(&mut err, name, import, span) + } + _ => {} + } + + err.emit(); + self.name_already_seen.insert(name, span); + } + + /// This function adds a suggestion to change the binding name of a new import that conflicts + /// with an existing import. + /// + /// ```text,ignore (diagnostic) + /// help: you can use `as` to change the binding name of the import + /// | + /// LL | use foo::bar as other_bar; + /// | ^^^^^^^^^^^^^^^^^^^^^ + /// ``` + fn add_suggestion_for_rename_of_use( + &self, + err: &mut Diagnostic, + name: Symbol, + import: &Import<'_>, + binding_span: Span, + ) { + let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { + format!("Other{}", name) + } else { + format!("other_{}", name) + }; + + let mut suggestion = None; + match import.kind { + ImportKind::Single { type_ns_only: true, .. } => { + suggestion = Some(format!("self as {}", suggested_name)) + } + ImportKind::Single { source, .. } => { + if let Some(pos) = + source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) + { + if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) { + if pos <= snippet.len() { + suggestion = Some(format!( + "{} as {}{}", + &snippet[..pos], + suggested_name, + if snippet.ends_with(';') { ";" } else { "" } + )) + } + } + } + } + ImportKind::ExternCrate { source, target } => { + suggestion = Some(format!( + "extern crate {} as {};", + source.unwrap_or(target.name), + suggested_name, + )) + } + _ => unreachable!(), + } + + let rename_msg = "you can use `as` to change the binding name of the import"; + if let Some(suggestion) = suggestion { + err.span_suggestion( + binding_span, + rename_msg, + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(binding_span, rename_msg); + } + } + + /// This function adds a suggestion to remove an unnecessary binding from an import that is + /// nested. In the following example, this function will be invoked to remove the `a` binding + /// in the second use statement: + /// + /// ```ignore (diagnostic) + /// use issue_52891::a; + /// use issue_52891::{d, a, e}; + /// ``` + /// + /// The following suggestion will be added: + /// + /// ```ignore (diagnostic) + /// use issue_52891::{d, a, e}; + /// ^-- help: remove unnecessary import + /// ``` + /// + /// If the nested use contains only one import then the suggestion will remove the entire + /// line. + /// + /// It is expected that the provided import is nested - this isn't checked by the + /// function. If this invariant is not upheld, this function's behaviour will be unexpected + /// as characters expected by span manipulations won't be present. + fn add_suggestion_for_duplicate_nested_use( + &self, + err: &mut Diagnostic, + import: &Import<'_>, + binding_span: Span, + ) { + assert!(import.is_nested()); + let message = "remove unnecessary import"; + + // Two examples will be used to illustrate the span manipulations we're doing: + // + // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is + // `a` and `import.use_span` is `issue_52891::{d, a, e};`. + // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is + // `a` and `import.use_span` is `issue_52891::{d, e, a};`. + + let (found_closing_brace, span) = + find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span); + + // If there was a closing brace then identify the span to remove any trailing commas from + // previous imports. + if found_closing_brace { + if let Some(span) = extend_span_to_previous_binding(self.session, span) { + err.tool_only_span_suggestion( + span, + message, + String::new(), + Applicability::MaybeIncorrect, + ); + } else { + // Remove the entire line if we cannot extend the span back, this indicates an + // `issue_52891::{self}` case. + err.span_suggestion( + import.use_span_with_attributes, + message, + String::new(), + Applicability::MaybeIncorrect, + ); + } + + return; + } + + err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable); + } + + crate fn lint_if_path_starts_with_module( + &mut self, + finalize: Finalize, + path: &[Segment], + second_binding: Option<&NameBinding<'_>>, + ) { + let (diag_id, diag_span) = match finalize { + Finalize::No => return, + Finalize::SimplePath(id, path_span) => (id, path_span), + Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span), + Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span), + }; + + let first_name = match path.get(0) { + // In the 2018 edition this lint is a hard error, so nothing to do + Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name, + _ => return, + }; + + // We're only interested in `use` paths which should start with + // `{{root}}` currently. + if first_name != kw::PathRoot { + return; + } + + match path.get(1) { + // If this import looks like `crate::...` it's already good + Some(Segment { ident, .. }) if ident.name == kw::Crate => return, + // Otherwise go below to see if it's an extern crate + Some(_) => {} + // If the path has length one (and it's `PathRoot` most likely) + // then we don't know whether we're gonna be importing a crate or an + // item in our crate. Defer this lint to elsewhere + None => return, + } + + // If the first element of our path was actually resolved to an + // `ExternCrate` (also used for `crate::...`) then no need to issue a + // warning, this looks all good! + if let Some(binding) = second_binding { + if let NameBindingKind::Import { import, .. } = binding.kind { + // Careful: we still want to rewrite paths from renamed extern crates. + if let ImportKind::ExternCrate { source: None, .. } = import.kind { + return; + } + } + } + + let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span); + self.lint_buffer.buffer_lint_with_diagnostic( + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + diag_id, + diag_span, + "absolute paths must start with `self`, `super`, \ + `crate`, or an external crate name in the 2018 edition", + diag, + ); + } + crate fn add_module_candidates( &mut self, module: Module<'a>, @@ -1076,6 +1467,8 @@ impl<'a> Resolver<'a> { &parent_scope, None, false, + false, + None, ) { let desc = match binding.res() { Res::Def(DefKind::Macro(MacroKind::Bang), _) => { @@ -1223,7 +1616,7 @@ impl<'a> Resolver<'a> { } } - crate fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) { + fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) { let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. @@ -1289,7 +1682,7 @@ impl<'a> Resolver<'a> { None } - crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { + fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { let PrivacyError { ident, binding, .. } = *privacy_error; let res = binding.res(); @@ -1375,6 +1768,188 @@ impl<'a> Resolver<'a> { sugg => sugg, } } + + crate fn report_path_resolution_error( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, + ribs: Option<&PerNS>>>, + unusable_binding: Option<&'a NameBinding<'a>>, + module: Option>, + i: usize, + ident: Ident, + ) -> (String, Option) { + let is_last = i == path.len() - 1; + let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; + let module_res = match module { + Some(ModuleOrUniformRoot::Module(module)) => module.res(), + _ => None, + }; + if module_res == self.graph_root.res() { + let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _)); + let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); + candidates + .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path))); + if let Some(candidate) = candidates.get(0) { + ( + String::from("unresolved import"), + Some(( + vec![(ident.span, pprust::path_to_string(&candidate.path))], + String::from("a similar path exists"), + Applicability::MaybeIncorrect, + )), + ) + } else if self.session.edition() == Edition::Edition2015 { + (format!("maybe a missing crate `{}`?", ident), None) + } else { + (format!("could not find `{}` in the crate root", ident), None) + } + } else if i > 0 { + let parent = path[i - 1].ident.name; + let parent = match parent { + // ::foo is mounted at the crate root for 2015, and is the extern + // prelude for 2018+ + kw::PathRoot if self.session.edition() > Edition::Edition2015 => { + "the list of imported crates".to_owned() + } + kw::PathRoot | kw::Crate => "the crate root".to_owned(), + _ => format!("`{}`", parent), + }; + + let mut msg = format!("could not find `{}` in {}", ident, parent); + if ns == TypeNS || ns == ValueNS { + let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; + let binding = if let Some(module) = module { + self.resolve_ident_in_module( + module, + ident, + ns_to_try, + parent_scope, + None, + false, + unusable_binding, + ).ok() + } else if let Some(ribs) = ribs + && let Some(TypeNS | ValueNS) = opt_ns + { + match self.resolve_ident_in_lexical_scope( + ident, + ns_to_try, + parent_scope, + Finalize::No, + &ribs[ns_to_try], + unusable_binding, + ) { + // we found a locally-imported or available item/module + Some(LexicalScopeBinding::Item(binding)) => Some(binding), + _ => None, + } + } else { + let scopes = ScopeSet::All(ns_to_try, opt_ns.is_none()); + self.early_resolve_ident_in_lexical_scope( + ident, + scopes, + parent_scope, + None, + false, + false, + unusable_binding, + ).ok() + }; + if let Some(binding) = binding { + let mut found = |what| { + msg = format!( + "expected {}, found {} `{}` in {}", + ns.descr(), + what, + ident, + parent + ) + }; + if binding.module().is_some() { + found("module") + } else { + match binding.res() { + Res::Def(kind, id) => found(kind.descr(id)), + _ => found(ns_to_try.descr()), + } + } + }; + } + (msg, None) + } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) { + // Check whether the name refers to an item in the value namespace. + let binding = if let Some(ribs) = ribs { + self.resolve_ident_in_lexical_scope( + ident, + ValueNS, + parent_scope, + Finalize::No, + &ribs[ValueNS], + unusable_binding, + ) + } else { + None + }; + let match_span = match binding { + // Name matches a local variable. For example: + // ``` + // fn f() { + // let Foo: &str = ""; + // println!("{}", Foo::Bar); // Name refers to local + // // variable `Foo`. + // } + // ``` + Some(LexicalScopeBinding::Res(Res::Local(id))) => { + Some(*self.pat_span_map.get(&id).unwrap()) + } + // Name matches item from a local name binding + // created by `use` declaration. For example: + // ``` + // pub Foo: &str = ""; + // + // mod submod { + // use super::Foo; + // println!("{}", Foo::Bar); // Name refers to local + // // binding `Foo`. + // } + // ``` + Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span), + _ => None, + }; + let suggestion = if let Some(span) = match_span { + Some(( + vec![(span, String::from(""))], + format!("`{}` is defined here, but is not a type", ident), + Applicability::MaybeIncorrect, + )) + } else { + None + }; + + (format!("use of undeclared type `{}`", ident), suggestion) + } else { + let suggestion = if ident.name == sym::alloc { + Some(( + vec![], + String::from("add `extern crate alloc` to use the `alloc` crate"), + Applicability::MaybeIncorrect, + )) + } else { + self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map( + |sugg| { + ( + vec![(ident.span, sugg.to_string())], + String::from("there is a crate or module with a similar name"), + Applicability::MaybeIncorrect, + ) + }, + ) + }; + (format!("use of undeclared crate or module `{}`", ident), suggestion) + } + } } impl<'a, 'b> ImportResolver<'a, 'b> { @@ -1422,7 +1997,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No); + let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None } } @@ -1441,7 +2016,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No); + let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some(( @@ -1472,7 +2047,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No); + let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None } } @@ -1506,7 +2081,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No); + let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!( "make_external_crate_suggestion: name={:?} path={:?} result={:?}", name, path, result @@ -1673,7 +2248,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// use foo::{a, b, c}; /// ^^^ /// ``` -pub(crate) fn find_span_of_binding_until_next_binding( +fn find_span_of_binding_until_next_binding( sess: &Session, binding_span: Span, use_span: Span, @@ -1724,7 +2299,7 @@ pub(crate) fn find_span_of_binding_until_next_binding( /// use foo::{a, b, c}; /// --- binding span /// ``` -pub(crate) fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option { +fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option { let source_map = sess.source_map(); // `prev_source` will contain all of the source that came before the span. @@ -1812,7 +2387,7 @@ fn find_span_immediately_after_crate_name( /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way -crate fn show_candidates( +fn show_candidates( definitions: &rustc_hir::definitions::Definitions, session: &Session, err: &mut Diagnostic, @@ -1947,3 +2522,70 @@ crate fn show_candidates( } } } + +#[derive(Debug)] +struct UsePlacementFinder { + target_module: NodeId, + first_legal_span: Option, + first_use_span: Option, +} + +impl UsePlacementFinder { + fn check(krate: &Crate, target_module: NodeId) -> (Option, bool) { + let mut finder = + UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None }; + finder.visit_crate(krate); + if let Some(use_span) = finder.first_use_span { + (Some(use_span), true) + } else { + (finder.first_legal_span, false) + } + } +} + +impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { + fn visit_crate(&mut self, c: &Crate) { + if self.target_module == CRATE_NODE_ID { + let inject = c.spans.inject_use_span; + if is_span_suitable_for_use_injection(inject) { + self.first_legal_span = Some(inject); + } + self.first_use_span = search_for_any_use_in_items(&c.items); + return; + } else { + visit::walk_crate(self, c); + } + } + + fn visit_item(&mut self, item: &'tcx ast::Item) { + if self.target_module == item.id { + if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind { + let inject = mod_spans.inject_use_span; + if is_span_suitable_for_use_injection(inject) { + self.first_legal_span = Some(inject); + } + self.first_use_span = search_for_any_use_in_items(items); + return; + } + } else { + visit::walk_item(self, item); + } + } +} + +fn search_for_any_use_in_items(items: &[P]) -> Option { + for item in items { + if let ItemKind::Use(..) = item.kind { + if is_span_suitable_for_use_injection(item.span) { + return Some(item.span.shrink_to_lo()); + } + } + } + return None; +} + +fn is_span_suitable_for_use_injection(s: Span) -> bool { + // don't suggest placing a use before the prelude + // import or other generated ones + !s.from_expansion() +} diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs new file mode 100644 index 0000000000000..25ab3f7dacf90 --- /dev/null +++ b/compiler/rustc_resolve/src/ident.rs @@ -0,0 +1,1582 @@ +use rustc_ast::{self as ast, NodeId}; +use rustc_feature::is_builtin_attr_name; +use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_hir::PrimTy; +use rustc_middle::bug; +use rustc_middle::ty; +use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; +use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_span::edition::Edition; +use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; +use rustc_span::symbol::{kw, Ident}; +use rustc_span::{Span, DUMMY_SP}; + +use std::ptr; + +use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind}; +use crate::macros::{sub_namespace_match, MacroRulesScope}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; +use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; +use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; + +use Determinacy::*; +use Namespace::*; +use RibKind::*; + +impl<'a> Resolver<'a> { + /// A generic scope visitor. + /// Visits scopes in order to resolve some identifier in them or perform other actions. + /// If the callback returns `Some` result, we stop visiting scopes and return it. + crate fn visit_scopes( + &mut self, + scope_set: ScopeSet<'a>, + parent_scope: &ParentScope<'a>, + ctxt: SyntaxContext, + mut visitor: impl FnMut( + &mut Self, + Scope<'a>, + /*use_prelude*/ bool, + SyntaxContext, + ) -> Option, + ) -> Option { + // General principles: + // 1. Not controlled (user-defined) names should have higher priority than controlled names + // built into the language or standard library. This way we can add new names into the + // language or standard library without breaking user code. + // 2. "Closed set" below means new names cannot appear after the current resolution attempt. + // Places to search (in order of decreasing priority): + // (Type NS) + // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet + // (open set, not controlled). + // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). + // 3. Extern prelude (open, the open part is from macro expansions, not controlled). + // 4. Tool modules (closed, controlled right now, but not in the future). + // 5. Standard library prelude (de-facto closed, controlled). + // 6. Language prelude (closed, controlled). + // (Value NS) + // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet + // (open set, not controlled). + // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). + // 3. Standard library prelude (de-facto closed, controlled). + // (Macro NS) + // 1-3. Derive helpers (open, not controlled). All ambiguities with other names + // are currently reported as errors. They should be higher in priority than preludes + // and probably even names in modules according to the "general principles" above. They + // also should be subject to restricted shadowing because are effectively produced by + // derives (you need to resolve the derive first to add helpers into scope), but they + // should be available before the derive is expanded for compatibility. + // It's mess in general, so we are being conservative for now. + // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher + // priority than prelude macros, but create ambiguities with macros in modules. + // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). Have higher priority than prelude macros, but create + // ambiguities with `macro_rules`. + // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled). + // 4a. User-defined prelude from macro-use + // (open, the open part is from macro expansions, not controlled). + // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled). + // 4c. Standard library prelude (de-facto closed, controlled). + // 6. Language prelude: builtin attributes (closed, controlled). + + let rust_2015 = ctxt.edition() == Edition::Edition2015; + let (ns, macro_kind, is_absolute_path) = match scope_set { + ScopeSet::All(ns, _) => (ns, None, false), + ScopeSet::AbsolutePath(ns) => (ns, None, true), + ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), + }; + let module = match scope_set { + // Start with the specified module. + ScopeSet::Late(_, module, _) => module, + // Jump out of trait or enum modules, they do not act as scopes. + _ => parent_scope.module.nearest_item_scope(), + }; + let mut scope = match ns { + _ if is_absolute_path => Scope::CrateRoot, + TypeNS | ValueNS => Scope::Module(module, None), + MacroNS => Scope::DeriveHelpers(parent_scope.expansion), + }; + let mut ctxt = ctxt.normalize_to_macros_2_0(); + let mut use_prelude = !module.no_implicit_prelude; + + loop { + let visit = match scope { + // Derive helpers are not in scope when resolving derives in the same container. + Scope::DeriveHelpers(expn_id) => { + !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) + } + Scope::DeriveHelpersCompat => true, + Scope::MacroRules(macro_rules_scope) => { + // Use "path compression" on `macro_rules` scope chains. This is an optimization + // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. + // As another consequence of this optimization visitors never observe invocation + // scopes for macros that were already expanded. + while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { + if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { + macro_rules_scope.set(next_scope.get()); + } else { + break; + } + } + true + } + Scope::CrateRoot => true, + Scope::Module(..) => true, + Scope::RegisteredAttrs => use_prelude, + Scope::MacroUsePrelude => use_prelude || rust_2015, + Scope::BuiltinAttrs => true, + Scope::ExternPrelude => use_prelude || is_absolute_path, + Scope::ToolPrelude => use_prelude, + Scope::StdLibPrelude => use_prelude || ns == MacroNS, + Scope::BuiltinTypes => true, + }; + + if visit { + if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { + return break_result; + } + } + + scope = match scope { + Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, + Scope::DeriveHelpers(expn_id) => { + // Derive helpers are not visible to code generated by bang or derive macros. + let expn_data = expn_id.expn_data(); + match expn_data.kind { + ExpnKind::Root + | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { + Scope::DeriveHelpersCompat + } + _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), + } + } + Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), + Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { + MacroRulesScope::Binding(binding) => { + Scope::MacroRules(binding.parent_macro_rules_scope) + } + MacroRulesScope::Invocation(invoc_id) => { + Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) + } + MacroRulesScope::Empty => Scope::Module(module, None), + }, + Scope::CrateRoot => match ns { + TypeNS => { + ctxt.adjust(ExpnId::root()); + Scope::ExternPrelude + } + ValueNS | MacroNS => break, + }, + Scope::Module(module, prev_lint_id) => { + use_prelude = !module.no_implicit_prelude; + let derive_fallback_lint_id = match scope_set { + ScopeSet::Late(.., lint_id) => lint_id, + _ => None, + }; + match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + Some((parent_module, lint_id)) => { + Scope::Module(parent_module, lint_id.or(prev_lint_id)) + } + None => { + ctxt.adjust(ExpnId::root()); + match ns { + TypeNS => Scope::ExternPrelude, + ValueNS => Scope::StdLibPrelude, + MacroNS => Scope::RegisteredAttrs, + } + } + } + } + Scope::RegisteredAttrs => Scope::MacroUsePrelude, + Scope::MacroUsePrelude => Scope::StdLibPrelude, + Scope::BuiltinAttrs => break, // nowhere else to search + Scope::ExternPrelude if is_absolute_path => break, + Scope::ExternPrelude => Scope::ToolPrelude, + Scope::ToolPrelude => Scope::StdLibPrelude, + Scope::StdLibPrelude => match ns { + TypeNS => Scope::BuiltinTypes, + ValueNS => break, // nowhere else to search + MacroNS => Scope::BuiltinAttrs, + }, + Scope::BuiltinTypes => break, // nowhere else to search + }; + } + + None + } + + fn hygienic_lexical_parent( + &mut self, + module: Module<'a>, + ctxt: &mut SyntaxContext, + derive_fallback_lint_id: Option, + ) -> Option<(Module<'a>, Option)> { + if !module.expansion.outer_expn_is_descendant_of(*ctxt) { + return Some((self.expn_def_scope(ctxt.remove_mark()), None)); + } + + if let ModuleKind::Block(..) = module.kind { + return Some((module.parent.unwrap().nearest_item_scope(), None)); + } + + // We need to support the next case under a deprecation warning + // ``` + // struct MyStruct; + // ---- begin: this comes from a proc macro derive + // mod implementation_details { + // // Note that `MyStruct` is not in scope here. + // impl SomeTrait for MyStruct { ... } + // } + // ---- end + // ``` + // So we have to fall back to the module's parent during lexical resolution in this case. + if derive_fallback_lint_id.is_some() { + if let Some(parent) = module.parent { + // Inner module is inside the macro, parent module is outside of the macro. + if module.expansion != parent.expansion + && module.expansion.is_descendant_of(parent.expansion) + { + // The macro is a proc macro derive + if let Some(def_id) = module.expansion.expn_data().macro_def_id { + let ext = self.get_macro_by_def_id(def_id); + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); + } + } + } + } + } + + None + } + + /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. + /// More specifically, we proceed up the hierarchy of scopes and return the binding for + /// `ident` in the first scope that defines it (or None if no scopes define it). + /// + /// A block's items are above its local variables in the scope hierarchy, regardless of where + /// the items are defined in the block. For example, + /// ```rust + /// fn f() { + /// g(); // Since there are no local variables in scope yet, this resolves to the item. + /// let g = || {}; + /// fn g() {} + /// g(); // This resolves to the local variable `g` since it shadows the item. + /// } + /// ``` + /// + /// Invariant: This must only be called during main resolution, not during + /// import resolution. + #[tracing::instrument(level = "debug", skip(self, ribs))] + crate fn resolve_ident_in_lexical_scope( + &mut self, + mut ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize_full: Finalize, + ribs: &[Rib<'a>], + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Option> { + assert!(ns == TypeNS || ns == ValueNS); + let orig_ident = ident; + if ident.name == kw::Empty { + return Some(LexicalScopeBinding::Res(Res::Err)); + } + let (general_span, normalized_span) = if ident.name == kw::SelfUpper { + // FIXME(jseyfried) improve `Self` hygiene + let empty_span = ident.span.with_ctxt(SyntaxContext::root()); + (empty_span, empty_span) + } else if ns == TypeNS { + let normalized_span = ident.span.normalize_to_macros_2_0(); + (normalized_span, normalized_span) + } else { + (ident.span.normalize_to_macro_rules(), ident.span.normalize_to_macros_2_0()) + }; + ident.span = general_span; + let normalized_ident = Ident { span: normalized_span, ..ident }; + + // Walk backwards up the ribs in scope. + let finalize = finalize_full.path_span(); + let mut module = self.graph_root; + for i in (0..ribs.len()).rev() { + debug!("walk rib\n{:?}", ribs[i].bindings); + // Use the rib kind to determine whether we are resolving parameters + // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene). + let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident }; + if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) + { + // The ident resolves to a type parameter or local variable. + return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( + i, + rib_ident, + *res, + finalize, + *original_rib_ident_def, + ribs, + ))); + } + + module = match ribs[i].kind { + ModuleRibKind(module) => module, + MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ident.span.remove_mark(); + continue; + } + _ => continue, + }; + + match module.kind { + ModuleKind::Block(..) => {} // We can see through blocks + _ => break, + } + + let item = self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + finalize, + false, + unusable_binding, + ); + if let Ok(binding) = item { + // The ident resolves to an item. + return Some(LexicalScopeBinding::Item(binding)); + } + } + self.early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, finalize_full.node_id()), + parent_scope, + finalize, + finalize.is_some(), + false, + unusable_binding, + ) + .ok() + .map(LexicalScopeBinding::Item) + } + + /// Resolve an identifier in lexical scope. + /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during + /// expansion and import resolution (perhaps they can be merged in the future). + /// The function is used for resolving initial segments of macro paths (e.g., `foo` in + /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. + #[tracing::instrument(level = "debug", skip(self, scope_set))] + crate fn early_resolve_ident_in_lexical_scope( + &mut self, + orig_ident: Ident, + scope_set: ScopeSet<'a>, + parent_scope: &ParentScope<'a>, + finalize: Option, + force: bool, + last_import_segment: bool, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Result<&'a NameBinding<'a>, Determinacy> { + bitflags::bitflags! { + struct Flags: u8 { + const MACRO_RULES = 1 << 0; + const MODULE = 1 << 1; + const MISC_SUGGEST_CRATE = 1 << 2; + const MISC_SUGGEST_SELF = 1 << 3; + const MISC_FROM_PRELUDE = 1 << 4; + } + } + + assert!(force || !finalize.is_some()); // `finalize` implies `force` + + // Make sure `self`, `super` etc produce an error when passed to here. + if orig_ident.is_path_segment_keyword() { + return Err(Determinacy::Determined); + } + + let (ns, macro_kind, is_import) = match scope_set { + ScopeSet::All(ns, is_import) => (ns, None, is_import), + ScopeSet::AbsolutePath(ns) => (ns, None, false), + ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), + }; + + // This is *the* result, resolution from the scope closest to the resolved identifier. + // However, sometimes this result is "weak" because it comes from a glob import or + // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g. + // mod m { ... } // solution in outer scope + // { + // use prefix::*; // imports another `m` - innermost solution + // // weak, cannot shadow the outer `m`, need to report ambiguity error + // m::mac!(); + // } + // So we have to save the innermost solution and continue searching in outer scopes + // to detect potential ambiguities. + let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None; + let mut determinacy = Determinacy::Determined; + + // Go through all the scopes and try to resolve the name. + let break_result = self.visit_scopes( + scope_set, + parent_scope, + orig_ident.span.ctxt(), + |this, scope, use_prelude, ctxt| { + let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let ok = |res, span, arenas| { + Ok(( + (res, ty::Visibility::Public, span, LocalExpnId::ROOT) + .to_name_binding(arenas), + Flags::empty(), + )) + }; + let result = match scope { + Scope::DeriveHelpers(expn_id) => { + if let Some(attr) = this + .helper_attrs + .get(&expn_id) + .and_then(|attrs| attrs.iter().rfind(|i| ident == **i)) + { + let binding = ( + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), + ty::Visibility::Public, + attr.span, + expn_id, + ) + .to_name_binding(this.arenas); + Ok((binding, Flags::empty())) + } else { + Err(Determinacy::Determined) + } + } + Scope::DeriveHelpersCompat => { + let mut result = Err(Determinacy::Determined); + for derive in parent_scope.derives { + let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; + match this.resolve_macro_path( + derive, + Some(MacroKind::Derive), + parent_scope, + true, + force, + ) { + Ok((Some(ext), _)) => { + if ext.helper_attrs.contains(&ident.name) { + result = ok( + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), + derive.span, + this.arenas, + ); + break; + } + } + Ok(_) | Err(Determinacy::Determined) => {} + Err(Determinacy::Undetermined) => { + result = Err(Determinacy::Undetermined) + } + } + } + result + } + Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { + MacroRulesScope::Binding(macro_rules_binding) + if ident == macro_rules_binding.ident => + { + Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) + } + MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), + _ => Err(Determinacy::Determined), + }, + Scope::CrateRoot => { + let root_ident = Ident::new(kw::PathRoot, ident.span); + let root_module = this.resolve_crate_root(root_ident); + let binding = this.resolve_ident_in_module_ext( + ModuleOrUniformRoot::Module(root_module), + ident, + ns, + parent_scope, + finalize, + last_import_segment, + unusable_binding, + ); + match binding { + Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)), + Err((Determinacy::Undetermined, Weak::No)) => { + return Some(Err(Determinacy::determined(force))); + } + Err((Determinacy::Undetermined, Weak::Yes)) => { + Err(Determinacy::Undetermined) + } + Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), + } + } + Scope::Module(module, derive_fallback_lint_id) => { + let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; + let binding = this.resolve_ident_in_module_unadjusted_ext( + ModuleOrUniformRoot::Module(module), + ident, + ns, + adjusted_parent_scope, + !matches!(scope_set, ScopeSet::Late(..)), + finalize, + last_import_segment, + unusable_binding, + ); + match binding { + Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + this.lint_buffer.buffer_lint_with_diagnostic( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + &format!( + "cannot find {} `{}` in this scope", + ns.descr(), + ident + ), + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( + orig_ident.span, + ), + ); + } + let misc_flags = if ptr::eq(module, this.graph_root) { + Flags::MISC_SUGGEST_CRATE + } else if module.is_normal() { + Flags::MISC_SUGGEST_SELF + } else { + Flags::empty() + }; + Ok((binding, Flags::MODULE | misc_flags)) + } + Err((Determinacy::Undetermined, Weak::No)) => { + return Some(Err(Determinacy::determined(force))); + } + Err((Determinacy::Undetermined, Weak::Yes)) => { + Err(Determinacy::Undetermined) + } + Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), + } + } + Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() { + Some(ident) => ok( + Res::NonMacroAttr(NonMacroAttrKind::Registered), + ident.span, + this.arenas, + ), + None => Err(Determinacy::Determined), + }, + Scope::MacroUsePrelude => { + match this.macro_use_prelude.get(&ident.name).cloned() { + Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), + None => Err(Determinacy::determined( + this.graph_root.unexpanded_invocations.borrow().is_empty(), + )), + } + } + Scope::BuiltinAttrs => { + if is_builtin_attr_name(ident.name) { + ok( + Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)), + DUMMY_SP, + this.arenas, + ) + } else { + Err(Determinacy::Determined) + } + } + Scope::ExternPrelude => { + match this.extern_prelude_get(ident, finalize.is_some()) { + Some(binding) => Ok((binding, Flags::empty())), + None => Err(Determinacy::determined( + this.graph_root.unexpanded_invocations.borrow().is_empty(), + )), + } + } + Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() { + Some(ident) => ok(Res::ToolMod, ident.span, this.arenas), + None => Err(Determinacy::Determined), + }, + Scope::StdLibPrelude => { + let mut result = Err(Determinacy::Determined); + if let Some(prelude) = this.prelude { + if let Ok(binding) = this.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(prelude), + ident, + ns, + parent_scope, + None, + last_import_segment, + unusable_binding, + ) { + if use_prelude || this.is_builtin_macro(binding.res()) { + result = Ok((binding, Flags::MISC_FROM_PRELUDE)); + } + } + } + result + } + Scope::BuiltinTypes => match PrimTy::from_name(ident.name) { + Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas), + None => Err(Determinacy::Determined), + }, + }; + + match result { + Ok((binding, flags)) + if sub_namespace_match(binding.macro_kind(), macro_kind) => + { + if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { + return Some(Ok(binding)); + } + + if let Some((innermost_binding, innermost_flags)) = innermost_result { + // Found another solution, if the first one was "weak", report an error. + let (res, innermost_res) = (binding.res(), innermost_binding.res()); + if res != innermost_res { + let is_builtin = |res| { + matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))) + }; + let derive_helper = + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); + let derive_helper_compat = + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); + + let ambiguity_error_kind = if is_import { + Some(AmbiguityKind::Import) + } else if is_builtin(innermost_res) || is_builtin(res) { + Some(AmbiguityKind::BuiltinAttr) + } else if innermost_res == derive_helper_compat + || res == derive_helper_compat && innermost_res != derive_helper + { + Some(AmbiguityKind::DeriveHelper) + } else if innermost_flags.contains(Flags::MACRO_RULES) + && flags.contains(Flags::MODULE) + && !this.disambiguate_macro_rules_vs_modularized( + innermost_binding, + binding, + ) + || flags.contains(Flags::MACRO_RULES) + && innermost_flags.contains(Flags::MODULE) + && !this.disambiguate_macro_rules_vs_modularized( + binding, + innermost_binding, + ) + { + Some(AmbiguityKind::MacroRulesVsModularized) + } else if innermost_binding.is_glob_import() { + Some(AmbiguityKind::GlobVsOuter) + } else if innermost_binding + .may_appear_after(parent_scope.expansion, binding) + { + Some(AmbiguityKind::MoreExpandedVsOuter) + } else { + None + }; + if let Some(kind) = ambiguity_error_kind { + let misc = |f: Flags| { + if f.contains(Flags::MISC_SUGGEST_CRATE) { + AmbiguityErrorMisc::SuggestCrate + } else if f.contains(Flags::MISC_SUGGEST_SELF) { + AmbiguityErrorMisc::SuggestSelf + } else if f.contains(Flags::MISC_FROM_PRELUDE) { + AmbiguityErrorMisc::FromPrelude + } else { + AmbiguityErrorMisc::None + } + }; + this.ambiguity_errors.push(AmbiguityError { + kind, + ident: orig_ident, + b1: innermost_binding, + b2: binding, + misc1: misc(innermost_flags), + misc2: misc(flags), + }); + return Some(Ok(innermost_binding)); + } + } + } else { + // Found the first solution. + innermost_result = Some((binding, flags)); + } + } + Ok(..) | Err(Determinacy::Determined) => {} + Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, + } + + None + }, + ); + + if let Some(break_result) = break_result { + return break_result; + } + + // The first found solution was the only one, return it. + if let Some((binding, _)) = innermost_result { + return Ok(binding); + } + + Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) + } + + #[tracing::instrument(level = "debug", skip(self))] + crate fn maybe_resolve_ident_in_module( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + ) -> Result<&'a NameBinding<'a>, Determinacy> { + self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, false, None) + .map_err(|(determinacy, _)| determinacy) + } + + #[tracing::instrument(level = "debug", skip(self))] + crate fn resolve_ident_in_module( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize: Option, + // We are resolving a last import segment during import validation. + last_import_segment: bool, + // This binding should be ignored during in-module resolution, so that we don't get + // "self-confirming" import resolutions during import validation. + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Result<&'a NameBinding<'a>, Determinacy> { + self.resolve_ident_in_module_ext( + module, + ident, + ns, + parent_scope, + finalize, + last_import_segment, + unusable_binding, + ) + .map_err(|(determinacy, _)| determinacy) + } + + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_ident_in_module_ext( + &mut self, + module: ModuleOrUniformRoot<'a>, + mut ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize: Option, + last_import_segment: bool, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { + let tmp_parent_scope; + let mut adjusted_parent_scope = parent_scope; + match module { + ModuleOrUniformRoot::Module(m) => { + if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) { + tmp_parent_scope = + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; + adjusted_parent_scope = &tmp_parent_scope; + } + } + ModuleOrUniformRoot::ExternPrelude => { + ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root()); + } + ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => { + // No adjustments + } + } + self.resolve_ident_in_module_unadjusted_ext( + module, + ident, + ns, + adjusted_parent_scope, + false, + finalize, + last_import_segment, + unusable_binding, + ) + } + + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_ident_in_module_unadjusted( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize: Option, + last_import_segment: bool, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Result<&'a NameBinding<'a>, Determinacy> { + self.resolve_ident_in_module_unadjusted_ext( + module, + ident, + ns, + parent_scope, + false, + finalize, + last_import_segment, + unusable_binding, + ) + .map_err(|(determinacy, _)| determinacy) + } + + /// Attempts to resolve `ident` in namespaces `ns` of `module`. + /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_ident_in_module_unadjusted_ext( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + restricted_shadowing: bool, + finalize: Option, + last_import_segment: bool, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { + let module = match module { + ModuleOrUniformRoot::Module(module) => module, + ModuleOrUniformRoot::CrateRootAndExternPrelude => { + assert!(!restricted_shadowing); + let binding = self.early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::AbsolutePath(ns), + parent_scope, + finalize, + finalize.is_some(), + last_import_segment, + unusable_binding, + ); + return binding.map_err(|determinacy| (determinacy, Weak::No)); + } + ModuleOrUniformRoot::ExternPrelude => { + assert!(!restricted_shadowing); + return if ns != TypeNS { + Err((Determined, Weak::No)) + } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { + Ok(binding) + } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() { + // Macro-expanded `extern crate` items can add names to extern prelude. + Err((Undetermined, Weak::No)) + } else { + Err((Determined, Weak::No)) + }; + } + ModuleOrUniformRoot::CurrentScope => { + assert!(!restricted_shadowing); + if ns == TypeNS { + if ident.name == kw::Crate || ident.name == kw::DollarCrate { + let module = self.resolve_crate_root(ident); + let binding = + (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) + .to_name_binding(self.arenas); + return Ok(binding); + } else if ident.name == kw::Super || ident.name == kw::SelfLower { + // FIXME: Implement these with renaming requirements so that e.g. + // `use super;` doesn't work, but `use super as name;` does. + // Fall through here to get an error from `early_resolve_...`. + } + } + + let scopes = ScopeSet::All(ns, true); + let binding = self.early_resolve_ident_in_lexical_scope( + ident, + scopes, + parent_scope, + finalize, + finalize.is_some(), + last_import_segment, + unusable_binding, + ); + return binding.map_err(|determinacy| (determinacy, Weak::No)); + } + }; + + let key = self.new_key(ident, ns); + let resolution = + self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. + + if let Some(path_span) = finalize { + // If the primary binding is unusable, search further and return the shadowed glob + // binding if it exists. What we really want here is having two separate scopes in + // a module - one for non-globs and one for globs, but until that's done use this + // hack to avoid inconsistent resolution ICEs during import validation. + let binding = [resolution.binding, resolution.shadowed_glob] + .into_iter() + .filter_map(|binding| match (binding, unusable_binding) { + (Some(binding), Some(unusable_binding)) + if ptr::eq(binding, unusable_binding) => + { + None + } + _ => binding, + }) + .next(); + let Some(binding) = binding else { + return Err((Determined, Weak::No)); + }; + + if !self.is_accessible_from(binding.vis, parent_scope.module) { + if last_import_segment { + return Err((Determined, Weak::No)); + } else { + self.privacy_errors.push(PrivacyError { + ident, + binding, + dedup_span: path_span, + }); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = resolution.shadowed_glob + && restricted_shadowing + && binding.expansion != LocalExpnId::ROOT + && binding.res() != shadowed_glob.res() + { + self.ambiguity_errors.push(AmbiguityError { + kind: AmbiguityKind::GlobVsExpanded, + ident, + b1: binding, + b2: shadowed_glob, + misc1: AmbiguityErrorMisc::None, + misc2: AmbiguityErrorMisc::None, + }); + } + + if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { + if let NameBindingKind::Res(_, true) = binding.kind { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + } + + self.record_use(ident, binding, restricted_shadowing); + return Ok(binding); + } + + let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { + if let Some(unusable_binding) = unusable_binding { + if ptr::eq(binding, unusable_binding) { + return Err((Determined, Weak::No)); + } + } + let usable = this.is_accessible_from(binding.vis, parent_scope.module); + if usable { Ok(binding) } else { Err((Determined, Weak::No)) } + }; + + // 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() { + return check_usable(self, binding); + } + } + + // --- From now on we either have a glob resolution or no resolution. --- + + // Check if one of single imports can still define the name, + // if it can then our result is not determined and can be invalidated. + for single_import in &resolution.single_imports { + if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { + continue; + } + let Some(module) = single_import.imported_module.get() else { + return Err((Undetermined, Weak::No)); + }; + let ImportKind::Single { source: ident, .. } = single_import.kind else { + unreachable!(); + }; + match self.resolve_ident_in_module( + module, + ident, + ns, + &single_import.parent_scope, + None, + last_import_segment, + unusable_binding, + ) { + Err(Determined) => continue, + Ok(binding) + if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + { + continue; + } + Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)), + } + } + + // So we have a resolution that's from a glob import. This resolution is determined + // if it cannot be shadowed by some new item/import expanded from a macro. + // This happens either if there are no unexpanded macros, or expanded names cannot + // shadow globs (that happens in macro namespace or with restricted shadowing). + // + // Additionally, any macro in any module can plant names in the root module if it creates + // `macro_export` macros, so the root module effectively has unresolved invocations if any + // module has unresolved invocations. + // However, it causes resolution/expansion to stuck too often (#53144), so, to make + // progress, we have to ignore those potential unresolved invocations from other modules + // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted + // shadowing is enabled, see `macro_expanded_macro_export_errors`). + let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty(); + if let Some(binding) = resolution.binding { + if !unexpanded_macros || ns == MacroNS || restricted_shadowing { + return check_usable(self, binding); + } else { + return Err((Undetermined, Weak::No)); + } + } + + // --- From now on we have no resolution. --- + + // Now we are in situation when new item/import can appear only from a glob or a macro + // expansion. With restricted shadowing names from globs and macro expansions cannot + // shadow names from outer scopes, so we can freely fallback from module search to search + // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer + // scopes we return `Undetermined` with `Weak::Yes`. + + // Check if one of unexpanded macros can still define the name, + // if it can then our "no resolution" result is not determined and can be invalidated. + if unexpanded_macros { + return Err((Undetermined, Weak::Yes)); + } + + // Check if one of glob imports can still define the name, + // if it can then our "no resolution" result is not determined and can be invalidated. + for glob_import in module.globs.borrow().iter() { + if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) { + continue; + } + let module = match glob_import.imported_module.get() { + Some(ModuleOrUniformRoot::Module(module)) => module, + Some(_) => continue, + None => return Err((Undetermined, Weak::Yes)), + }; + let tmp_parent_scope; + let (mut adjusted_parent_scope, mut ident) = + (parent_scope, ident.normalize_to_macros_2_0()); + match ident.span.glob_adjust(module.expansion, glob_import.span) { + Some(Some(def)) => { + tmp_parent_scope = + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; + adjusted_parent_scope = &tmp_parent_scope; + } + Some(None) => {} + None => continue, + }; + let result = self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + adjusted_parent_scope, + None, + last_import_segment, + unusable_binding, + ); + + match result { + Err(Determined) => continue, + Ok(binding) + if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => + { + continue; + } + Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)), + } + } + + // No resolution and no one else can define the name - determinate error. + Err((Determined, Weak::No)) + } + + /// Validate a local resolution (from ribs). + #[tracing::instrument(level = "debug", skip(self, all_ribs))] + fn validate_res_from_ribs( + &mut self, + rib_index: usize, + rib_ident: Ident, + mut res: Res, + finalize: Option, + original_rib_ident_def: Ident, + all_ribs: &[Rib<'a>], + ) -> Res { + const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation"; + debug!("validate_res_from_ribs({:?})", res); + let ribs = &all_ribs[rib_index + 1..]; + + // An invalid forward use of a generic parameter from a previous default. + if let ForwardGenericParamBanRibKind = all_ribs[rib_index].kind { + if let Some(span) = finalize { + let res_error = if rib_ident.name == kw::SelfUpper { + ResolutionError::SelfInGenericParamDefault + } else { + ResolutionError::ForwardDeclaredGenericParam + }; + self.report_error(span, res_error); + } + assert_eq!(res, Res::Err); + return Res::Err; + } + + match res { + Res::Local(_) => { + use ResolutionError::*; + let mut res_err = None; + + for rib in ribs { + match rib.kind { + NormalRibKind + | ClosureOrAsyncRibKind + | ModuleRibKind(..) + | MacroDefinition(..) + | ForwardGenericParamBanRibKind => { + // Nothing to do. Continue. + } + ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + if let Some(span) = finalize { + // We don't immediately trigger a resolve error, because + // we want certain other resolution errors (namely those + // emitted for `ConstantItemRibKind` below) to take + // precedence. + res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem)); + } + } + ConstantItemRibKind(_, item) => { + // Still doesn't deal with upvars + if let Some(span) = finalize { + let (span, resolution_error) = + if let Some((ident, constant_item_kind)) = item { + let kind_str = match constant_item_kind { + ConstantItemKind::Const => "const", + ConstantItemKind::Static => "static", + }; + ( + span, + AttemptToUseNonConstantValueInConstant( + ident, "let", kind_str, + ), + ) + } else { + ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant( + original_rib_ident_def, + "const", + "let", + ), + ) + }; + self.report_error(span, resolution_error); + } + return Res::Err; + } + ConstParamTyRibKind => { + if let Some(span) = finalize { + self.report_error(span, ParamInTyOfConstParam(rib_ident.name)); + } + return Res::Err; + } + } + } + if let Some((span, res_err)) = res_err { + self.report_error(span, res_err); + return Res::Err; + } + } + Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => { + for rib in ribs { + let has_generic_params: HasGenericParams = match rib.kind { + NormalRibKind + | ClosureOrAsyncRibKind + | AssocItemRibKind + | ModuleRibKind(..) + | MacroDefinition(..) + | ForwardGenericParamBanRibKind => { + // Nothing to do. Continue. + continue; + } + + ConstantItemRibKind(trivial, _) => { + let features = self.session.features_untracked(); + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !(trivial || features.generic_const_exprs) { + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res { + res = Res::SelfTy { trait_, alias_to: Some((def, true)) } + } else { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: true, + }, + ); + self.session.delay_span_bug(span, CG_BUG_STR); + } + + return Res::Err; + } + } + + continue; + } + + // This was an attempt to use a type parameter outside its scope. + ItemRibKind(has_generic_params) => has_generic_params, + FnItemRibKind => HasGenericParams::Yes, + ConstParamTyRibKind => { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInTyOfConstParam(rib_ident.name), + ); + } + return Res::Err; + } + }; + + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::GenericParamsFromOuterFunction( + res, + has_generic_params, + ), + ); + } + return Res::Err; + } + } + Res::Def(DefKind::ConstParam, _) => { + let mut ribs = ribs.iter().peekable(); + if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { + // When declaring const parameters inside function signatures, the first rib + // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it + // (spuriously) conflicting with the const param. + ribs.next(); + } + + for rib in ribs { + let has_generic_params = match rib.kind { + NormalRibKind + | ClosureOrAsyncRibKind + | AssocItemRibKind + | ModuleRibKind(..) + | MacroDefinition(..) + | ForwardGenericParamBanRibKind => continue, + + ConstantItemRibKind(trivial, _) => { + let features = self.session.features_untracked(); + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !(trivial || features.generic_const_exprs) { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: false, + }, + ); + self.session.delay_span_bug(span, CG_BUG_STR); + } + + return Res::Err; + } + + continue; + } + + ItemRibKind(has_generic_params) => has_generic_params, + FnItemRibKind => HasGenericParams::Yes, + ConstParamTyRibKind => { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInTyOfConstParam(rib_ident.name), + ); + } + return Res::Err; + } + }; + + // This was an attempt to use a const parameter outside its scope. + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::GenericParamsFromOuterFunction( + res, + has_generic_params, + ), + ); + } + return Res::Err; + } + } + _ => {} + } + res + } + + #[tracing::instrument(level = "debug", skip(self))] + crate fn maybe_resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, + ) -> PathResult<'a> { + self.resolve_path_with_ribs(path, opt_ns, parent_scope, Finalize::No, None, None) + } + + #[tracing::instrument(level = "debug", skip(self))] + crate fn resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, + finalize: Finalize, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> PathResult<'a> { + self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, unusable_binding) + } + + crate fn resolve_path_with_ribs( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, + finalize_full: Finalize, + ribs: Option<&PerNS>>>, + unusable_binding: Option<&'a NameBinding<'a>>, + ) -> PathResult<'a> { + debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full); + + let finalize = finalize_full.path_span(); + let mut module = None; + let mut allow_super = true; + let mut second_binding = None; + + for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() { + debug!("resolve_path ident {} {:?} {:?}", i, ident, id); + let record_segment_res = |this: &mut Self, res| { + if finalize.is_some() { + if let Some(id) = id { + if !this.partial_res_map.contains_key(&id) { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.record_partial_res(id, PartialRes::new(res)); + } + } + } + }; + + let is_last = i == path.len() - 1; + let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; + let name = ident.name; + + allow_super &= ns == TypeNS && (name == kw::SelfLower || name == kw::Super); + + if ns == TypeNS { + if allow_super && name == kw::Super { + let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); + let self_module = match i { + 0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)), + _ => match module { + Some(ModuleOrUniformRoot::Module(module)) => Some(module), + _ => None, + }, + }; + if let Some(self_module) = self_module { + if let Some(parent) = self_module.parent { + module = Some(ModuleOrUniformRoot::Module( + self.resolve_self(&mut ctxt, parent), + )); + continue; + } + } + return PathResult::failed(ident.span, false, finalize.is_some(), || { + ("there are too many leading `super` keywords".to_string(), None) + }); + } + if i == 0 { + if name == kw::SelfLower { + let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); + module = Some(ModuleOrUniformRoot::Module( + self.resolve_self(&mut ctxt, parent_scope.module), + )); + continue; + } + if name == kw::PathRoot && ident.span.rust_2018() { + module = Some(ModuleOrUniformRoot::ExternPrelude); + continue; + } + if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() { + // `::a::b` from 2015 macro on 2018 global edition + module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude); + continue; + } + if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate { + // `::a::b`, `crate::a::b` or `$crate::a::b` + module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident))); + continue; + } + } + } + + // Report special messages for path segment keywords in wrong positions. + if ident.is_path_segment_keyword() && i != 0 { + return PathResult::failed(ident.span, false, finalize.is_some(), || { + let name_str = if name == kw::PathRoot { + "crate root".to_string() + } else { + format!("`{}`", name) + }; + let label = if i == 1 && path[0].ident.name == kw::PathRoot { + format!("global paths cannot start with {}", name_str) + } else { + format!("{} in paths can only be used in start position", name_str) + }; + (label, None) + }); + } + + enum FindBindingResult<'a> { + Binding(Result<&'a NameBinding<'a>, Determinacy>), + Res(Res), + } + let find_binding_in_ns = |this: &mut Self, ns| { + let binding = if let Some(module) = module { + this.resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + false, + unusable_binding, + ) + } else if let Some(ribs) = ribs + && let Some(TypeNS | ValueNS) = opt_ns + { + match this.resolve_ident_in_lexical_scope( + ident, + ns, + parent_scope, + finalize_full, + &ribs[ns], + unusable_binding, + ) { + // we found a locally-imported or available item/module + Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + // we found a local variable or type param + Some(LexicalScopeBinding::Res(res)) => return FindBindingResult::Res(res), + _ => Err(Determinacy::determined(finalize.is_some())), + } + } else { + let scopes = ScopeSet::All(ns, opt_ns.is_none()); + this.early_resolve_ident_in_lexical_scope( + ident, + scopes, + parent_scope, + finalize, + finalize.is_some(), + false, + unusable_binding, + ) + }; + FindBindingResult::Binding(binding) + }; + let binding = match find_binding_in_ns(self, ns) { + FindBindingResult::Res(res) => { + record_segment_res(self, res); + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, + path.len() - 1, + )); + } + FindBindingResult::Binding(binding) => binding, + }; + match binding { + Ok(binding) => { + if i == 1 { + second_binding = Some(binding); + } + let res = binding.res(); + let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); + if let Some(next_module) = binding.module() { + module = Some(ModuleOrUniformRoot::Module(next_module)); + record_segment_res(self, res); + } else if res == Res::ToolMod && i + 1 != path.len() { + if binding.is_import() { + self.session + .struct_span_err( + ident.span, + "cannot use a tool module through an import", + ) + .span_note(binding.span, "the tool module imported here") + .emit(); + } + let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); + return PathResult::NonModule(PartialRes::new(res)); + } else if res == Res::Err { + return PathResult::NonModule(PartialRes::new(Res::Err)); + } else if opt_ns.is_some() && (is_last || maybe_assoc) { + self.lint_if_path_starts_with_module(finalize_full, path, second_binding); + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, + path.len() - i - 1, + )); + } else { + return PathResult::failed(ident.span, is_last, finalize.is_some(), || { + let label = format!( + "`{ident}` is {} {}, not a module", + res.article(), + res.descr() + ); + (label, None) + }); + } + } + Err(Undetermined) => return PathResult::Indeterminate, + Err(Determined) => { + if let Some(ModuleOrUniformRoot::Module(module)) = module { + if opt_ns.is_some() && !module.is_normal() { + return PathResult::NonModule(PartialRes::with_unresolved_segments( + module.res().unwrap(), + path.len() - i, + )); + } + } + + return PathResult::failed(ident.span, is_last, finalize.is_some(), || { + self.report_path_resolution_error( + path, + opt_ns, + parent_scope, + ribs, + unusable_binding, + module, + i, + ident, + ) + }); + } + } + } + + self.lint_if_path_starts_with_module(finalize_full, path, second_binding); + + PathResult::Module(match module { + Some(module) => module, + None if path.is_empty() => ModuleOrUniformRoot::CurrentScope, + _ => bug!("resolve_path: non-empty path `{:?}` has no module", path), + }) + } +} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 02abdbaa98354..aab0c1f97717c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -2,12 +2,11 @@ use crate::diagnostics::Suggestion; use crate::Determinacy::{self, *}; -use crate::Namespace::{self, MacroNS, TypeNS}; +use crate::Namespace::{MacroNS, TypeNS}; use crate::{module_to_string, names_to_string}; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; -use crate::{BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; -use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak}; -use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding}; +use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; +use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; +use crate::{NameBinding, NameBindingKind, PathResult}; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; @@ -125,15 +124,15 @@ impl<'a> Import<'a> { } } -#[derive(Clone, Default, Debug)] /// Records information about the resolution of a name in a namespace of a module. -pub struct NameResolution<'a> { +#[derive(Clone, Default, Debug)] +crate struct NameResolution<'a> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. - single_imports: FxHashSet>>, + pub single_imports: FxHashSet>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, - shadowed_glob: Option<&'a NameBinding<'a>>, + pub shadowed_glob: Option<&'a NameBinding<'a>>, } impl<'a> NameResolution<'a> { @@ -169,278 +168,6 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi } impl<'a> Resolver<'a> { - crate fn resolve_ident_in_module_unadjusted( - &mut self, - module: ModuleOrUniformRoot<'a>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'a>, - finalize: Option, - ) -> Result<&'a NameBinding<'a>, Determinacy> { - self.resolve_ident_in_module_unadjusted_ext( - module, - ident, - ns, - parent_scope, - false, - finalize, - ) - .map_err(|(determinacy, _)| determinacy) - } - - /// Attempts to resolve `ident` in namespaces `ns` of `module`. - /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. - crate fn resolve_ident_in_module_unadjusted_ext( - &mut self, - module: ModuleOrUniformRoot<'a>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'a>, - restricted_shadowing: bool, - finalize: Option, - ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { - let module = match module { - ModuleOrUniformRoot::Module(module) => module, - ModuleOrUniformRoot::CrateRootAndExternPrelude => { - assert!(!restricted_shadowing); - let binding = self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::AbsolutePath(ns), - parent_scope, - finalize, - finalize.is_some(), - ); - return binding.map_err(|determinacy| (determinacy, Weak::No)); - } - ModuleOrUniformRoot::ExternPrelude => { - assert!(!restricted_shadowing); - return if ns != TypeNS { - Err((Determined, Weak::No)) - } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { - Ok(binding) - } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() { - // Macro-expanded `extern crate` items can add names to extern prelude. - Err((Undetermined, Weak::No)) - } else { - Err((Determined, Weak::No)) - }; - } - ModuleOrUniformRoot::CurrentScope => { - assert!(!restricted_shadowing); - if ns == TypeNS { - if ident.name == kw::Crate || ident.name == kw::DollarCrate { - let module = self.resolve_crate_root(ident); - let binding = - (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) - .to_name_binding(self.arenas); - return Ok(binding); - } else if ident.name == kw::Super || ident.name == kw::SelfLower { - // FIXME: Implement these with renaming requirements so that e.g. - // `use super;` doesn't work, but `use super as name;` does. - // Fall through here to get an error from `early_resolve_...`. - } - } - - let scopes = ScopeSet::All(ns, true); - let binding = self.early_resolve_ident_in_lexical_scope( - ident, - scopes, - parent_scope, - finalize, - finalize.is_some(), - ); - return binding.map_err(|determinacy| (determinacy, Weak::No)); - } - }; - - let key = self.new_key(ident, ns); - let resolution = - self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. - - if let Some(binding) = resolution.binding && let Some(path_span) = finalize { - if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Res(_, true) = binding.kind { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); - } - } - } - - let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { - if let Some(unusable_binding) = this.unusable_binding { - if ptr::eq(binding, unusable_binding) { - return Err((Determined, Weak::No)); - } - } - let usable = this.is_accessible_from(binding.vis, parent_scope.module); - if usable { Ok(binding) } else { Err((Determined, Weak::No)) } - }; - - if let Some(path_span) = finalize { - return resolution - .binding - .and_then(|binding| { - // If the primary binding is unusable, search further and return the shadowed glob - // binding if it exists. What we really want here is having two separate scopes in - // a module - one for non-globs and one for globs, but until that's done use this - // hack to avoid inconsistent resolution ICEs during import validation. - if let Some(unusable_binding) = self.unusable_binding { - if ptr::eq(binding, unusable_binding) { - return resolution.shadowed_glob; - } - } - Some(binding) - }) - .ok_or((Determined, Weak::No)) - .and_then(|binding| { - if self.last_import_segment && check_usable(self, binding).is_err() { - Err((Determined, Weak::No)) - } else { - self.record_use(ident, binding, restricted_shadowing); - - if let Some(shadowed_glob) = resolution.shadowed_glob { - // Forbid expanded shadowing to avoid time travel. - if restricted_shadowing - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, - }); - } - } - - if !self.is_accessible_from(binding.vis, parent_scope.module) { - self.privacy_errors.push(PrivacyError { - ident, - binding, - dedup_span: path_span, - }); - } - - 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() { - return check_usable(self, binding); - } - } - - // --- From now on we either have a glob resolution or no resolution. --- - - // Check if one of single imports can still define the name, - // if it can then our result is not determined and can be invalidated. - for single_import in &resolution.single_imports { - if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { - continue; - } - let Some(module) = single_import.imported_module.get() else { - return Err((Undetermined, Weak::No)); - }; - let ImportKind::Single { source: ident, .. } = single_import.kind else { - unreachable!(); - }; - match self.resolve_ident_in_module(module, ident, ns, &single_import.parent_scope, None) - { - Err(Determined) => continue, - Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => - { - continue; - } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)), - } - } - - // So we have a resolution that's from a glob import. This resolution is determined - // if it cannot be shadowed by some new item/import expanded from a macro. - // This happens either if there are no unexpanded macros, or expanded names cannot - // shadow globs (that happens in macro namespace or with restricted shadowing). - // - // Additionally, any macro in any module can plant names in the root module if it creates - // `macro_export` macros, so the root module effectively has unresolved invocations if any - // module has unresolved invocations. - // However, it causes resolution/expansion to stuck too often (#53144), so, to make - // progress, we have to ignore those potential unresolved invocations from other modules - // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted - // shadowing is enabled, see `macro_expanded_macro_export_errors`). - let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty(); - if let Some(binding) = resolution.binding { - if !unexpanded_macros || ns == MacroNS || restricted_shadowing { - return check_usable(self, binding); - } else { - return Err((Undetermined, Weak::No)); - } - } - - // --- From now on we have no resolution. --- - - // Now we are in situation when new item/import can appear only from a glob or a macro - // expansion. With restricted shadowing names from globs and macro expansions cannot - // shadow names from outer scopes, so we can freely fallback from module search to search - // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer - // scopes we return `Undetermined` with `Weak::Yes`. - - // Check if one of unexpanded macros can still define the name, - // if it can then our "no resolution" result is not determined and can be invalidated. - if unexpanded_macros { - return Err((Undetermined, Weak::Yes)); - } - - // Check if one of glob imports can still define the name, - // if it can then our "no resolution" result is not determined and can be invalidated. - for glob_import in module.globs.borrow().iter() { - if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) { - continue; - } - let module = match glob_import.imported_module.get() { - Some(ModuleOrUniformRoot::Module(module)) => module, - Some(_) => continue, - None => return Err((Undetermined, Weak::Yes)), - }; - let tmp_parent_scope; - let (mut adjusted_parent_scope, mut ident) = - (parent_scope, ident.normalize_to_macros_2_0()); - match ident.span.glob_adjust(module.expansion, glob_import.span) { - Some(Some(def)) => { - tmp_parent_scope = - ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; - adjusted_parent_scope = &tmp_parent_scope; - } - Some(None) => {} - None => continue, - }; - let result = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - adjusted_parent_scope, - None, - ); - - match result { - Err(Determined) => continue, - Ok(binding) - if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => - { - continue; - } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)), - } - } - - // No resolution and no one else can define the name - determinate error. - Err((Determined, Weak::No)) - } - // Given a binding and an import that resolves to it, // return the corresponding binding defined by the import. crate fn import( @@ -772,7 +499,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // not define any names while resolving its module path. let orig_vis = import.vis.replace(ty::Visibility::Invisible); let path_res = - self.r.resolve_path(&import.module_path, None, &import.parent_scope, Finalize::No); + self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope); import.vis.set(orig_vis); match path_res { @@ -812,6 +539,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ns, &import.parent_scope, None, + false, + None, ); import.vis.set(orig_vis); source_bindings[ns].set(binding); @@ -857,10 +586,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { let orig_vis = import.vis.replace(ty::Visibility::Invisible); - let orig_unusable_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => { - Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get())) - } + let unusable_binding = match &import.kind { + ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), _ => None, }; let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); @@ -869,12 +596,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { root_span: import.root_span, path_span: import.span, }; - let path_res = - self.r.resolve_path(&import.module_path, None, &import.parent_scope, finalize); + let path_res = self.r.resolve_path( + &import.module_path, + None, + &import.parent_scope, + finalize, + unusable_binding, + ); let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; - if let Some(orig_unusable_binding) = orig_unusable_binding { - self.r.unusable_binding = orig_unusable_binding; - } import.vis.set(orig_vis); if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res { // Consider erroneous imports used to avoid duplicate diagnostics. @@ -987,18 +716,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { let orig_vis = import.vis.replace(ty::Visibility::Invisible); - let orig_unusable_binding = - mem::replace(&mut this.unusable_binding, target_bindings[ns].get()); - let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true); let binding = this.resolve_ident_in_module( module, ident, ns, &import.parent_scope, Some(import.span), + true, + target_bindings[ns].get(), ); - this.last_import_segment = orig_last_import_segment; - this.unusable_binding = orig_unusable_binding; import.vis.set(orig_vis); match binding { @@ -1057,6 +783,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ns, &import.parent_scope, Some(import.span), + false, + None, ); if binding.is_ok() { all_ns_failed = false; @@ -1271,15 +999,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return; } - let orig_unusable_binding = - mem::replace(&mut this.unusable_binding, target_bindings[ns].get()); - match this.early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns, false), &import.parent_scope, None, false, + false, + target_bindings[ns].get(), ) { Ok(other_binding) => { is_redundant[ns] = Some( @@ -1289,8 +1016,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } Err(_) => is_redundant[ns] = Some(false), } - - this.unusable_binding = orig_unusable_binding; } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6fedabc816cff..9084e659ae495 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -8,7 +8,7 @@ use RibKind::*; use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding}; -use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult}; +use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ptr::P; @@ -487,6 +487,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self_ty, TypeNS, Finalize::SimplePath(ty.id, ty.span), + None, ) .map_or(Res::Err, |d| d.res()); self.r.record_partial_res(ty.id, PartialRes::new(res)); @@ -676,12 +677,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // checking. if path.segments.len() == 1 && path.segments[0].args.is_none() { let mut check_ns = |ns| { - self.resolve_ident_in_lexical_scope( - path.segments[0].ident, - ns, - Finalize::No, - ) - .is_some() + self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) + .is_some() }; if !check_ns(TypeNS) && check_ns(ValueNS) { // This must be equivalent to `visit_anon_const`, but we cannot call it @@ -750,11 +747,27 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + fn maybe_resolve_ident_in_lexical_scope( + &mut self, + ident: Ident, + ns: Namespace, + ) -> Option> { + self.r.resolve_ident_in_lexical_scope( + ident, + ns, + &self.parent_scope, + Finalize::No, + &self.ribs[ns], + None, + ) + } + fn resolve_ident_in_lexical_scope( &mut self, ident: Ident, ns: Namespace, finalize: Finalize, + unusable_binding: Option<&'a NameBinding<'a>>, ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, @@ -762,6 +775,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &self.parent_scope, finalize, &self.ribs[ns], + unusable_binding, ) } @@ -771,7 +785,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { opt_ns: Option, // `None` indicates a module path in import finalize: Finalize, ) -> PathResult<'a> { - self.r.resolve_path_with_ribs(path, opt_ns, &self.parent_scope, finalize, Some(&self.ribs)) + self.r.resolve_path_with_ribs( + path, + opt_ns, + &self.parent_scope, + finalize, + Some(&self.ribs), + None, + ) } // AST resolution @@ -934,19 +955,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; for &ns in nss { - match self.resolve_ident_in_lexical_scope(ident, ns, Finalize::No) { + match self.maybe_resolve_ident_in_lexical_scope(ident, ns) { Some(LexicalScopeBinding::Res(..)) => { report_error(self, ns); } Some(LexicalScopeBinding::Item(binding)) => { - let orig_unusable_binding = - replace(&mut self.r.unusable_binding, Some(binding)); - if let Some(LexicalScopeBinding::Res(..)) = - self.resolve_ident_in_lexical_scope(ident, ns, Finalize::No) + if let Some(LexicalScopeBinding::Res(..)) = self + .resolve_ident_in_lexical_scope(ident, ns, Finalize::No, Some(binding)) { report_error(self, ns); } - self.r.unusable_binding = orig_unusable_binding; } None => {} } @@ -1802,7 +1820,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // also be interpreted as a path to e.g. a constant, variant, etc. let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); - let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, Finalize::No)?; + let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { LexicalScopeBinding::Item(binding) if is_syntactic_ambiguity && binding.is_ambiguity() => @@ -2071,17 +2089,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn self_type_is_available(&mut self) -> bool { - let binding = self.resolve_ident_in_lexical_scope( - Ident::with_dummy_span(kw::SelfUpper), - TypeNS, - Finalize::No, - ); + let binding = self + .maybe_resolve_ident_in_lexical_scope(Ident::with_dummy_span(kw::SelfUpper), TypeNS); if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } fn self_value_is_available(&mut self, self_span: Span) -> bool { let ident = Ident::new(kw::SelfLower, self_span); - let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, Finalize::No); + let binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS); if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1e943f0e44abd..eae9e846c8b77 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1271,12 +1271,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref { - if let Ok(binding) = self.r.resolve_ident_in_module( + if let Ok(binding) = self.r.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ns, &self.parent_scope, - None, ) { let res = binding.res(); if filter_fn(res) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a09a225a2b5d7..b2c7a4d18de38 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! This crate is responsible for the part of name resolution that doesn't require type checker. //! //! Module structure of the crate is built here. @@ -26,27 +24,18 @@ extern crate tracing; pub use rustc_hir::def::{Namespace, PerNS}; -use Determinacy::*; - use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; -use rustc_ast::ptr::P; -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId}; -use rustc_ast::{Crate, CRATE_NODE_ID}; -use rustc_ast::{Expr, ExprKind, LitKind}; -use rustc_ast::{ItemKind, ModKind, Path}; +use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; +use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path}; use rustc_ast_lowering::ResolverAstLowering; -use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; -use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; +use rustc_hir::def::{self, CtorOf, DefKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; @@ -55,16 +44,14 @@ use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs}; -use rustc_middle::{bug, span_bug}; use rustc_query_system::ich::StableHashingContext; use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; -use rustc_session::lint; -use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::lint::LintBuffer; use rustc_session::Session; -use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency}; +use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -75,10 +62,9 @@ use std::collections::BTreeSet; use std::{cmp, fmt, mem, ptr}; use tracing::debug; -use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; -use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*}; +use late::{HasGenericParams, PathSource}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::access_levels::AccessLevelsVisitor; @@ -90,6 +76,7 @@ mod build_reduced_graph; mod check_unused; mod def_collector; mod diagnostics; +mod ident; mod imports; mod late; mod macros; @@ -315,73 +302,6 @@ impl<'a> From<&'a ast::PathSegment> for Segment { } } -#[derive(Debug)] -struct UsePlacementFinder { - target_module: NodeId, - first_legal_span: Option, - first_use_span: Option, -} - -impl UsePlacementFinder { - fn check(krate: &Crate, target_module: NodeId) -> (Option, bool) { - let mut finder = - UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None }; - finder.visit_crate(krate); - if let Some(use_span) = finder.first_use_span { - (Some(use_span), true) - } else { - (finder.first_legal_span, false) - } - } -} - -fn is_span_suitable_for_use_injection(s: Span) -> bool { - // don't suggest placing a use before the prelude - // import or other generated ones - !s.from_expansion() -} - -fn search_for_any_use_in_items(items: &[P]) -> Option { - for item in items { - if let ItemKind::Use(..) = item.kind { - if is_span_suitable_for_use_injection(item.span) { - return Some(item.span.shrink_to_lo()); - } - } - } - return None; -} - -impl<'tcx> Visitor<'tcx> for UsePlacementFinder { - fn visit_crate(&mut self, c: &Crate) { - if self.target_module == CRATE_NODE_ID { - let inject = c.spans.inject_use_span; - if is_span_suitable_for_use_injection(inject) { - self.first_legal_span = Some(inject); - } - self.first_use_span = search_for_any_use_in_items(&c.items); - return; - } else { - visit::walk_crate(self, c); - } - } - - fn visit_item(&mut self, item: &'tcx ast::Item) { - if self.target_module == item.id { - if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind { - let inject = mod_spans.inject_use_span; - if is_span_suitable_for_use_injection(inject) { - self.first_legal_span = Some(inject); - } - self.first_use_span = search_for_any_use_in_items(items); - return; - } - } else { - visit::walk_item(self, item); - } - } -} - /// An intermediate resolution result. /// /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that @@ -928,13 +848,6 @@ pub struct Resolver<'a> { /// All non-determined imports. indeterminate_imports: Vec<&'a Import<'a>>, - /// FIXME: Refactor things so that these fields are passed through arguments and not resolver. - /// We are resolving a last import segment during import validation. - last_import_segment: bool, - /// This binding should be ignored during in-module resolution, so that we don't get - /// "self-confirming" import resolutions during import validation. - unusable_binding: Option<&'a NameBinding<'a>>, - // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. pat_span_map: NodeMap, @@ -1342,9 +1255,6 @@ impl<'a> Resolver<'a> { determined_imports: Vec::new(), indeterminate_imports: Vec::new(), - last_import_segment: false, - unusable_binding: None, - pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), @@ -1731,387 +1641,6 @@ impl<'a> Resolver<'a> { } } - /// A generic scope visitor. - /// Visits scopes in order to resolve some identifier in them or perform other actions. - /// If the callback returns `Some` result, we stop visiting scopes and return it. - fn visit_scopes( - &mut self, - scope_set: ScopeSet<'a>, - parent_scope: &ParentScope<'a>, - ctxt: SyntaxContext, - mut visitor: impl FnMut( - &mut Self, - Scope<'a>, - /*use_prelude*/ bool, - SyntaxContext, - ) -> Option, - ) -> Option { - // General principles: - // 1. Not controlled (user-defined) names should have higher priority than controlled names - // built into the language or standard library. This way we can add new names into the - // language or standard library without breaking user code. - // 2. "Closed set" below means new names cannot appear after the current resolution attempt. - // Places to search (in order of decreasing priority): - // (Type NS) - // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet - // (open set, not controlled). - // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). - // 3. Extern prelude (open, the open part is from macro expansions, not controlled). - // 4. Tool modules (closed, controlled right now, but not in the future). - // 5. Standard library prelude (de-facto closed, controlled). - // 6. Language prelude (closed, controlled). - // (Value NS) - // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet - // (open set, not controlled). - // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). - // 3. Standard library prelude (de-facto closed, controlled). - // (Macro NS) - // 1-3. Derive helpers (open, not controlled). All ambiguities with other names - // are currently reported as errors. They should be higher in priority than preludes - // and probably even names in modules according to the "general principles" above. They - // also should be subject to restricted shadowing because are effectively produced by - // derives (you need to resolve the derive first to add helpers into scope), but they - // should be available before the derive is expanded for compatibility. - // It's mess in general, so we are being conservative for now. - // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher - // priority than prelude macros, but create ambiguities with macros in modules. - // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). Have higher priority than prelude macros, but create - // ambiguities with `macro_rules`. - // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled). - // 4a. User-defined prelude from macro-use - // (open, the open part is from macro expansions, not controlled). - // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled). - // 4c. Standard library prelude (de-facto closed, controlled). - // 6. Language prelude: builtin attributes (closed, controlled). - - let rust_2015 = ctxt.edition() == Edition::Edition2015; - let (ns, macro_kind, is_absolute_path) = match scope_set { - ScopeSet::All(ns, _) => (ns, None, false), - ScopeSet::AbsolutePath(ns) => (ns, None, true), - ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), - ScopeSet::Late(ns, ..) => (ns, None, false), - }; - let module = match scope_set { - // Start with the specified module. - ScopeSet::Late(_, module, _) => module, - // Jump out of trait or enum modules, they do not act as scopes. - _ => parent_scope.module.nearest_item_scope(), - }; - let mut scope = match ns { - _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module, None), - MacroNS => Scope::DeriveHelpers(parent_scope.expansion), - }; - let mut ctxt = ctxt.normalize_to_macros_2_0(); - let mut use_prelude = !module.no_implicit_prelude; - - loop { - let visit = match scope { - // Derive helpers are not in scope when resolving derives in the same container. - Scope::DeriveHelpers(expn_id) => { - !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) - } - Scope::DeriveHelpersCompat => true, - Scope::MacroRules(macro_rules_scope) => { - // Use "path compression" on `macro_rules` scope chains. This is an optimization - // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. - // As another consequence of this optimization visitors never observe invocation - // scopes for macros that were already expanded. - while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { - if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { - macro_rules_scope.set(next_scope.get()); - } else { - break; - } - } - true - } - Scope::CrateRoot => true, - Scope::Module(..) => true, - Scope::RegisteredAttrs => use_prelude, - Scope::MacroUsePrelude => use_prelude || rust_2015, - Scope::BuiltinAttrs => true, - Scope::ExternPrelude => use_prelude || is_absolute_path, - Scope::ToolPrelude => use_prelude, - Scope::StdLibPrelude => use_prelude || ns == MacroNS, - Scope::BuiltinTypes => true, - }; - - if visit { - if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { - return break_result; - } - } - - scope = match scope { - Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, - Scope::DeriveHelpers(expn_id) => { - // Derive helpers are not visible to code generated by bang or derive macros. - let expn_data = expn_id.expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { - Scope::DeriveHelpersCompat - } - _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), - } - } - Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), - Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(binding) => { - Scope::MacroRules(binding.parent_macro_rules_scope) - } - MacroRulesScope::Invocation(invoc_id) => { - Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) - } - MacroRulesScope::Empty => Scope::Module(module, None), - }, - Scope::CrateRoot => match ns { - TypeNS => { - ctxt.adjust(ExpnId::root()); - Scope::ExternPrelude - } - ValueNS | MacroNS => break, - }, - Scope::Module(module, prev_lint_id) => { - use_prelude = !module.no_implicit_prelude; - let derive_fallback_lint_id = match scope_set { - ScopeSet::Late(.., lint_id) => lint_id, - _ => None, - }; - match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { - Some((parent_module, lint_id)) => { - Scope::Module(parent_module, lint_id.or(prev_lint_id)) - } - None => { - ctxt.adjust(ExpnId::root()); - match ns { - TypeNS => Scope::ExternPrelude, - ValueNS => Scope::StdLibPrelude, - MacroNS => Scope::RegisteredAttrs, - } - } - } - } - Scope::RegisteredAttrs => Scope::MacroUsePrelude, - Scope::MacroUsePrelude => Scope::StdLibPrelude, - Scope::BuiltinAttrs => break, // nowhere else to search - Scope::ExternPrelude if is_absolute_path => break, - Scope::ExternPrelude => Scope::ToolPrelude, - Scope::ToolPrelude => Scope::StdLibPrelude, - Scope::StdLibPrelude => match ns { - TypeNS => Scope::BuiltinTypes, - ValueNS => break, // nowhere else to search - MacroNS => Scope::BuiltinAttrs, - }, - Scope::BuiltinTypes => break, // nowhere else to search - }; - } - - None - } - - /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. - /// More specifically, we proceed up the hierarchy of scopes and return the binding for - /// `ident` in the first scope that defines it (or None if no scopes define it). - /// - /// A block's items are above its local variables in the scope hierarchy, regardless of where - /// the items are defined in the block. For example, - /// ```rust - /// fn f() { - /// g(); // Since there are no local variables in scope yet, this resolves to the item. - /// let g = || {}; - /// fn g() {} - /// g(); // This resolves to the local variable `g` since it shadows the item. - /// } - /// ``` - /// - /// Invariant: This must only be called during main resolution, not during - /// import resolution. - fn resolve_ident_in_lexical_scope( - &mut self, - mut ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'a>, - finalize_full: Finalize, - ribs: &[Rib<'a>], - ) -> Option> { - assert!(ns == TypeNS || ns == ValueNS); - let orig_ident = ident; - if ident.name == kw::Empty { - return Some(LexicalScopeBinding::Res(Res::Err)); - } - let (general_span, normalized_span) = if ident.name == kw::SelfUpper { - // FIXME(jseyfried) improve `Self` hygiene - let empty_span = ident.span.with_ctxt(SyntaxContext::root()); - (empty_span, empty_span) - } else if ns == TypeNS { - let normalized_span = ident.span.normalize_to_macros_2_0(); - (normalized_span, normalized_span) - } else { - (ident.span.normalize_to_macro_rules(), ident.span.normalize_to_macros_2_0()) - }; - ident.span = general_span; - let normalized_ident = Ident { span: normalized_span, ..ident }; - - // Walk backwards up the ribs in scope. - let finalize = finalize_full.path_span(); - let mut module = self.graph_root; - for i in (0..ribs.len()).rev() { - debug!("walk rib\n{:?}", ribs[i].bindings); - // Use the rib kind to determine whether we are resolving parameters - // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene). - let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident }; - if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) - { - // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( - i, - rib_ident, - *res, - finalize, - *original_rib_ident_def, - ribs, - ))); - } - - module = match ribs[i].kind { - ModuleRibKind(module) => module, - MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { - // If an invocation of this macro created `ident`, give up on `ident` - // and switch to `ident`'s source from the macro definition. - ident.span.remove_mark(); - continue; - } - _ => continue, - }; - - match module.kind { - ModuleKind::Block(..) => {} // We can see through blocks - _ => break, - } - - let item = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - finalize, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); - } - } - self.early_resolve_ident_in_lexical_scope( - orig_ident, - ScopeSet::Late(ns, module, finalize_full.node_id()), - parent_scope, - finalize, - finalize.is_some(), - ) - .ok() - .map(LexicalScopeBinding::Item) - } - - fn hygienic_lexical_parent( - &mut self, - module: Module<'a>, - ctxt: &mut SyntaxContext, - derive_fallback_lint_id: Option, - ) -> Option<(Module<'a>, Option)> { - if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.expn_def_scope(ctxt.remove_mark()), None)); - } - - if let ModuleKind::Block(..) = module.kind { - return Some((module.parent.unwrap().nearest_item_scope(), None)); - } - - // We need to support the next case under a deprecation warning - // ``` - // struct MyStruct; - // ---- begin: this comes from a proc macro derive - // mod implementation_details { - // // Note that `MyStruct` is not in scope here. - // impl SomeTrait for MyStruct { ... } - // } - // ---- end - // ``` - // So we have to fall back to the module's parent during lexical resolution in this case. - if derive_fallback_lint_id.is_some() { - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = self.get_macro_by_def_id(def_id); - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - return Some((parent, derive_fallback_lint_id)); - } - } - } - } - } - - None - } - - fn resolve_ident_in_module( - &mut self, - module: ModuleOrUniformRoot<'a>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'a>, - finalize: Option, - ) -> Result<&'a NameBinding<'a>, Determinacy> { - self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize) - .map_err(|(determinacy, _)| determinacy) - } - - fn resolve_ident_in_module_ext( - &mut self, - module: ModuleOrUniformRoot<'a>, - mut ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'a>, - finalize: Option, - ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { - let tmp_parent_scope; - let mut adjusted_parent_scope = parent_scope; - match module { - ModuleOrUniformRoot::Module(m) => { - if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) { - tmp_parent_scope = - ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; - adjusted_parent_scope = &tmp_parent_scope; - } - } - ModuleOrUniformRoot::ExternPrelude => { - ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root()); - } - ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => { - // No adjustments - } - } - self.resolve_ident_in_module_unadjusted_ext( - module, - ident, - ns, - adjusted_parent_scope, - false, - finalize, - ) - } - fn resolve_crate_root(&mut self, ident: Ident) -> Module<'a> { debug!("resolve_crate_root({:?})", ident); let mut ctxt = ident.span.ctxt(); @@ -2194,676 +1723,6 @@ impl<'a> Resolver<'a> { module } - fn resolve_path( - &mut self, - path: &[Segment], - opt_ns: Option, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, - finalize: Finalize, - ) -> PathResult<'a> { - self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None) - } - - fn resolve_path_with_ribs( - &mut self, - path: &[Segment], - opt_ns: Option, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, - finalize_full: Finalize, - ribs: Option<&PerNS>>>, - ) -> PathResult<'a> { - debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full); - - let finalize = finalize_full.path_span(); - let mut module = None; - let mut allow_super = true; - let mut second_binding = None; - - for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() { - debug!("resolve_path ident {} {:?} {:?}", i, ident, id); - let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() { - if let Some(id) = id { - if !this.partial_res_map.contains_key(&id) { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - } - } - }; - - let is_last = i == path.len() - 1; - let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; - let name = ident.name; - - allow_super &= ns == TypeNS && (name == kw::SelfLower || name == kw::Super); - - if ns == TypeNS { - if allow_super && name == kw::Super { - let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); - let self_module = match i { - 0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)), - _ => match module { - Some(ModuleOrUniformRoot::Module(module)) => Some(module), - _ => None, - }, - }; - if let Some(self_module) = self_module { - if let Some(parent) = self_module.parent { - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent), - )); - continue; - } - } - return PathResult::failed(ident.span, false, finalize.is_some(), || { - ("there are too many leading `super` keywords".to_string(), None) - }); - } - if i == 0 { - if name == kw::SelfLower { - let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent_scope.module), - )); - continue; - } - if name == kw::PathRoot && ident.span.rust_2018() { - module = Some(ModuleOrUniformRoot::ExternPrelude); - continue; - } - if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() { - // `::a::b` from 2015 macro on 2018 global edition - module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude); - continue; - } - if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate { - // `::a::b`, `crate::a::b` or `$crate::a::b` - module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident))); - continue; - } - } - } - - // Report special messages for path segment keywords in wrong positions. - if ident.is_path_segment_keyword() && i != 0 { - return PathResult::failed(ident.span, false, finalize.is_some(), || { - let name_str = if name == kw::PathRoot { - "crate root".to_string() - } else { - format!("`{}`", name) - }; - let label = if i == 1 && path[0].ident.name == kw::PathRoot { - format!("global paths cannot start with {}", name_str) - } else { - format!("{} in paths can only be used in start position", name_str) - }; - (label, None) - }); - } - - enum FindBindingResult<'a> { - Binding(Result<&'a NameBinding<'a>, Determinacy>), - PathResult(PathResult<'a>), - } - let find_binding_in_ns = |this: &mut Self, ns| { - let binding = if let Some(module) = module { - this.resolve_ident_in_module(module, ident, ns, parent_scope, finalize) - } else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) { - let scopes = ScopeSet::All(ns, opt_ns.is_none()); - this.early_resolve_ident_in_lexical_scope( - ident, - scopes, - parent_scope, - finalize, - finalize.is_some(), - ) - } else { - match this.resolve_ident_in_lexical_scope( - ident, - ns, - parent_scope, - finalize_full, - &ribs.unwrap()[ns], - ) { - // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Ok(binding), - // we found a local variable or type param - Some(LexicalScopeBinding::Res(res)) - if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => - { - record_segment_res(this, res); - return FindBindingResult::PathResult(PathResult::NonModule( - PartialRes::with_unresolved_segments(res, path.len() - 1), - )); - } - _ => Err(Determinacy::determined(finalize.is_some())), - } - }; - FindBindingResult::Binding(binding) - }; - let binding = match find_binding_in_ns(self, ns) { - FindBindingResult::PathResult(x) => return x, - FindBindingResult::Binding(binding) => binding, - }; - match binding { - Ok(binding) => { - if i == 1 { - second_binding = Some(binding); - } - let res = binding.res(); - let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - module = Some(ModuleOrUniformRoot::Module(next_module)); - record_segment_res(self, res); - } else if res == Res::ToolMod && i + 1 != path.len() { - if binding.is_import() { - self.session - .struct_span_err( - ident.span, - "cannot use a tool module through an import", - ) - .span_note(binding.span, "the tool module imported here") - .emit(); - } - let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); - return PathResult::NonModule(PartialRes::new(res)); - } else if res == Res::Err { - return PathResult::NonModule(PartialRes::new(Res::Err)); - } else if opt_ns.is_some() && (is_last || maybe_assoc) { - self.lint_if_path_starts_with_module(finalize_full, path, second_binding); - return PathResult::NonModule(PartialRes::with_unresolved_segments( - res, - path.len() - i - 1, - )); - } else { - return PathResult::failed(ident.span, is_last, finalize.is_some(), || { - let label = format!( - "`{ident}` is {} {}, not a module", - res.article(), - res.descr() - ); - (label, None) - }); - } - } - Err(Undetermined) => return PathResult::Indeterminate, - Err(Determined) => { - if let Some(ModuleOrUniformRoot::Module(module)) = module { - if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PartialRes::with_unresolved_segments( - module.res().unwrap(), - path.len() - i, - )); - } - } - - return PathResult::failed(ident.span, is_last, finalize.is_some(), || { - let module_res = match module { - Some(ModuleOrUniformRoot::Module(module)) => module.res(), - _ => None, - }; - if module_res == self.graph_root.res() { - let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _)); - let mut candidates = - self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); - candidates.sort_by_cached_key(|c| { - (c.path.segments.len(), pprust::path_to_string(&c.path)) - }); - if let Some(candidate) = candidates.get(0) { - ( - String::from("unresolved import"), - Some(( - vec![(ident.span, pprust::path_to_string(&candidate.path))], - String::from("a similar path exists"), - Applicability::MaybeIncorrect, - )), - ) - } else if self.session.edition() == Edition::Edition2015 { - (format!("maybe a missing crate `{}`?", ident), None) - } else { - (format!("could not find `{}` in the crate root", ident), None) - } - } else if i == 0 { - if ident - .name - .as_str() - .chars() - .next() - .map_or(false, |c| c.is_ascii_uppercase()) - { - // Check whether the name refers to an item in the value namespace. - let suggestion = if ribs.is_some() { - let match_span = match self.resolve_ident_in_lexical_scope( - ident, - ValueNS, - parent_scope, - Finalize::No, - &ribs.unwrap()[ValueNS], - ) { - // Name matches a local variable. For example: - // ``` - // fn f() { - // let Foo: &str = ""; - // println!("{}", Foo::Bar); // Name refers to local - // // variable `Foo`. - // } - // ``` - Some(LexicalScopeBinding::Res(Res::Local(id))) => { - Some(*self.pat_span_map.get(&id).unwrap()) - } - - // Name matches item from a local name binding - // created by `use` declaration. For example: - // ``` - // pub Foo: &str = ""; - // - // mod submod { - // use super::Foo; - // println!("{}", Foo::Bar); // Name refers to local - // // binding `Foo`. - // } - // ``` - Some(LexicalScopeBinding::Item(name_binding)) => { - Some(name_binding.span) - } - _ => None, - }; - - if let Some(span) = match_span { - Some(( - vec![(span, String::from(""))], - format!( - "`{}` is defined here, but is not a type", - ident - ), - Applicability::MaybeIncorrect, - )) - } else { - None - } - } else { - None - }; - - (format!("use of undeclared type `{}`", ident), suggestion) - } else { - ( - format!("use of undeclared crate or module `{}`", ident), - if ident.name == sym::alloc { - Some(( - vec![], - String::from( - "add `extern crate alloc` to use the `alloc` crate", - ), - Applicability::MaybeIncorrect, - )) - } else { - self.find_similarly_named_module_or_crate( - ident.name, - &parent_scope.module, - ) - .map(|sugg| { - ( - vec![(ident.span, sugg.to_string())], - String::from( - "there is a crate or module with a similar name", - ), - Applicability::MaybeIncorrect, - ) - }) - }, - ) - } - } else { - let parent = path[i - 1].ident.name; - let parent = match parent { - // ::foo is mounted at the crate root for 2015, and is the extern - // prelude for 2018+ - kw::PathRoot if self.session.edition() > Edition::Edition2015 => { - "the list of imported crates".to_owned() - } - kw::PathRoot | kw::Crate => "the crate root".to_owned(), - _ => { - format!("`{}`", parent) - } - }; - - let mut msg = format!("could not find `{}` in {}", ident, parent); - if ns == TypeNS || ns == ValueNS { - let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; - if let FindBindingResult::Binding(Ok(binding)) = - find_binding_in_ns(self, ns_to_try) - { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - def::Res::::Def(kind, id) => { - found(kind.descr(id)) - } - _ => found(ns_to_try.descr()), - } - } - }; - } - (msg, None) - } - }); - } - } - } - - self.lint_if_path_starts_with_module(finalize_full, path, second_binding); - - PathResult::Module(match module { - Some(module) => module, - None if path.is_empty() => ModuleOrUniformRoot::CurrentScope, - _ => bug!("resolve_path: non-empty path `{:?}` has no module", path), - }) - } - - fn lint_if_path_starts_with_module( - &mut self, - finalize: Finalize, - path: &[Segment], - second_binding: Option<&NameBinding<'_>>, - ) { - let (diag_id, diag_span) = match finalize { - Finalize::No => return, - Finalize::SimplePath(id, path_span) => (id, path_span), - Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span), - Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span), - }; - - let first_name = match path.get(0) { - // In the 2018 edition this lint is a hard error, so nothing to do - Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name, - _ => return, - }; - - // We're only interested in `use` paths which should start with - // `{{root}}` currently. - if first_name != kw::PathRoot { - return; - } - - match path.get(1) { - // If this import looks like `crate::...` it's already good - Some(Segment { ident, .. }) if ident.name == kw::Crate => return, - // Otherwise go below to see if it's an extern crate - Some(_) => {} - // If the path has length one (and it's `PathRoot` most likely) - // then we don't know whether we're gonna be importing a crate or an - // item in our crate. Defer this lint to elsewhere - None => return, - } - - // If the first element of our path was actually resolved to an - // `ExternCrate` (also used for `crate::...`) then no need to issue a - // warning, this looks all good! - if let Some(binding) = second_binding { - if let NameBindingKind::Import { import, .. } = binding.kind { - // Careful: we still want to rewrite paths from renamed extern crates. - if let ImportKind::ExternCrate { source: None, .. } = import.kind { - return; - } - } - } - - let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span); - self.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - diag_id, - diag_span, - "absolute paths must start with `self`, `super`, \ - `crate`, or an external crate name in the 2018 edition", - diag, - ); - } - - // Validate a local resolution (from ribs). - fn validate_res_from_ribs( - &mut self, - rib_index: usize, - rib_ident: Ident, - mut res: Res, - finalize: Option, - original_rib_ident_def: Ident, - all_ribs: &[Rib<'a>], - ) -> Res { - const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation"; - debug!("validate_res_from_ribs({:?})", res); - let ribs = &all_ribs[rib_index + 1..]; - - // An invalid forward use of a generic parameter from a previous default. - if let ForwardGenericParamBanRibKind = all_ribs[rib_index].kind { - if let Some(span) = finalize { - let res_error = if rib_ident.name == kw::SelfUpper { - ResolutionError::SelfInGenericParamDefault - } else { - ResolutionError::ForwardDeclaredGenericParam - }; - self.report_error(span, res_error); - } - assert_eq!(res, Res::Err); - return Res::Err; - } - - match res { - Res::Local(_) => { - use ResolutionError::*; - let mut res_err = None; - - for rib in ribs { - match rib.kind { - NormalRibKind - | ClosureOrAsyncRibKind - | ModuleRibKind(..) - | MacroDefinition(..) - | ForwardGenericParamBanRibKind => { - // Nothing to do. Continue. - } - ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { - // This was an attempt to access an upvar inside a - // named function item. This is not allowed, so we - // report an error. - if let Some(span) = finalize { - // We don't immediately trigger a resolve error, because - // we want certain other resolution errors (namely those - // emitted for `ConstantItemRibKind` below) to take - // precedence. - res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem)); - } - } - ConstantItemRibKind(_, item) => { - // Still doesn't deal with upvars - if let Some(span) = finalize { - let (span, resolution_error) = - if let Some((ident, constant_item_kind)) = item { - let kind_str = match constant_item_kind { - ConstantItemKind::Const => "const", - ConstantItemKind::Static => "static", - }; - ( - span, - AttemptToUseNonConstantValueInConstant( - ident, "let", kind_str, - ), - ) - } else { - ( - rib_ident.span, - AttemptToUseNonConstantValueInConstant( - original_rib_ident_def, - "const", - "let", - ), - ) - }; - self.report_error(span, resolution_error); - } - return Res::Err; - } - ConstParamTyRibKind => { - if let Some(span) = finalize { - self.report_error(span, ParamInTyOfConstParam(rib_ident.name)); - } - return Res::Err; - } - } - } - if let Some((span, res_err)) = res_err { - self.report_error(span, res_err); - return Res::Err; - } - } - Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => { - for rib in ribs { - let has_generic_params: HasGenericParams = match rib.kind { - NormalRibKind - | ClosureOrAsyncRibKind - | AssocItemRibKind - | ModuleRibKind(..) - | MacroDefinition(..) - | ForwardGenericParamBanRibKind => { - // Nothing to do. Continue. - continue; - } - - ConstantItemRibKind(trivial, _) => { - let features = self.session.features_untracked(); - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial || features.generic_const_exprs) { - // HACK(min_const_generics): If we encounter `Self` in an anonymous constant - // we can't easily tell if it's generic at this stage, so we instead remember - // this and then enforce the self type to be concrete later on. - if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res { - res = Res::SelfTy { trait_, alias_to: Some((def, true)) } - } else { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst { - name: rib_ident.name, - is_type: true, - }, - ); - self.session.delay_span_bug(span, CG_BUG_STR); - } - - return Res::Err; - } - } - - continue; - } - - // This was an attempt to use a type parameter outside its scope. - ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, - ConstParamTyRibKind => { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInTyOfConstParam(rib_ident.name), - ); - } - return Res::Err; - } - }; - - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::GenericParamsFromOuterFunction( - res, - has_generic_params, - ), - ); - } - return Res::Err; - } - } - Res::Def(DefKind::ConstParam, _) => { - let mut ribs = ribs.iter().peekable(); - if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { - // When declaring const parameters inside function signatures, the first rib - // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it - // (spuriously) conflicting with the const param. - ribs.next(); - } - - for rib in ribs { - let has_generic_params = match rib.kind { - NormalRibKind - | ClosureOrAsyncRibKind - | AssocItemRibKind - | ModuleRibKind(..) - | MacroDefinition(..) - | ForwardGenericParamBanRibKind => continue, - - ConstantItemRibKind(trivial, _) => { - let features = self.session.features_untracked(); - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial || features.generic_const_exprs) { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst { - name: rib_ident.name, - is_type: false, - }, - ); - self.session.delay_span_bug(span, CG_BUG_STR); - } - - return Res::Err; - } - - continue; - } - - ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, - ConstParamTyRibKind => { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInTyOfConstParam(rib_ident.name), - ); - } - return Res::Err; - } - }; - - // This was an attempt to use a const parameter outside its scope. - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::GenericParamsFromOuterFunction( - res, - has_generic_params, - ), - ); - } - return Res::Err; - } - } - _ => {} - } - res - } - fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { debug!("(recording res) recording {:?} for {}", resolution, node_id); if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) { @@ -2910,331 +1769,6 @@ impl<'a> Resolver<'a> { } } - fn report_errors(&mut self, krate: &Crate) { - self.report_with_use_injections(krate); - - for &(span_use, span_def) in &self.macro_expanded_macro_export_errors { - let msg = "macro-expanded `macro_export` macros from the current crate \ - cannot be referred to by absolute paths"; - self.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - CRATE_NODE_ID, - span_use, - msg, - BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def), - ); - } - - for ambiguity_error in &self.ambiguity_errors { - self.report_ambiguity_error(ambiguity_error); - } - - let mut reported_spans = FxHashSet::default(); - for error in &self.privacy_errors { - if reported_spans.insert(error.dedup_span) { - self.report_privacy_error(error); - } - } - } - - fn report_with_use_injections(&mut self, krate: &Crate) { - for UseError { mut err, candidates, def_id, instead, suggestion } in - self.use_injections.drain(..) - { - let (span, found_use) = if let Some(def_id) = def_id.as_local() { - UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id]) - } else { - (None, false) - }; - if !candidates.is_empty() { - diagnostics::show_candidates( - &self.definitions, - self.session, - &mut err, - span, - &candidates, - instead, - found_use, - ); - } else if let Some((span, msg, sugg, appl)) = suggestion { - err.span_suggestion(span, msg, sugg, appl); - } - err.emit(); - } - } - - fn report_conflict<'b>( - &mut self, - parent: Module<'_>, - ident: Ident, - ns: Namespace, - new_binding: &NameBinding<'b>, - old_binding: &NameBinding<'b>, - ) { - // Error on the second of two conflicting names - if old_binding.span.lo() > new_binding.span.lo() { - return self.report_conflict(parent, ident, ns, old_binding, new_binding); - } - - let container = match parent.kind { - ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), - ModuleKind::Block(..) => "block", - }; - - let old_noun = match old_binding.is_import() { - true => "import", - false => "definition", - }; - - let new_participle = match new_binding.is_import() { - true => "imported", - false => "defined", - }; - - let (name, span) = - (ident.name, self.session.source_map().guess_head_span(new_binding.span)); - - if let Some(s) = self.name_already_seen.get(&name) { - if s == &span { - return; - } - } - - let old_kind = match (ns, old_binding.module()) { - (ValueNS, _) => "value", - (MacroNS, _) => "macro", - (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", - (TypeNS, _) => "type", - }; - - let msg = format!("the name `{}` is defined multiple times", name); - - let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { - (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg), - (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() { - true => struct_span_err!(self.session, span, E0254, "{}", msg), - false => struct_span_err!(self.session, span, E0260, "{}", msg), - }, - _ => match (old_binding.is_import(), new_binding.is_import()) { - (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), - (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg), - _ => struct_span_err!(self.session, span, E0255, "{}", msg), - }, - }; - - err.note(&format!( - "`{}` must be defined only once in the {} namespace of this {}", - name, - ns.descr(), - container - )); - - err.span_label(span, format!("`{}` re{} here", name, new_participle)); - err.span_label( - self.session.source_map().guess_head_span(old_binding.span), - format!("previous {} of the {} `{}` here", old_noun, old_kind, name), - ); - - // See https://github.com/rust-lang/rust/issues/32354 - use NameBindingKind::Import; - let import = match (&new_binding.kind, &old_binding.kind) { - // If there are two imports where one or both have attributes then prefer removing the - // import without attributes. - (Import { import: new, .. }, Import { import: old, .. }) - if { - !new_binding.span.is_dummy() - && !old_binding.span.is_dummy() - && (new.has_attributes || old.has_attributes) - } => - { - if old.has_attributes { - Some((new, new_binding.span, true)) - } else { - Some((old, old_binding.span, true)) - } - } - // Otherwise prioritize the new binding. - (Import { import, .. }, other) if !new_binding.span.is_dummy() => { - Some((import, new_binding.span, other.is_import())) - } - (other, Import { import, .. }) if !old_binding.span.is_dummy() => { - Some((import, old_binding.span, other.is_import())) - } - _ => None, - }; - - // Check if the target of the use for both bindings is the same. - let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); - let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); - let from_item = - self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); - // Only suggest removing an import if both bindings are to the same def, if both spans - // aren't dummy spans. Further, if both bindings are imports, then the ident must have - // been introduced by an item. - let should_remove_import = duplicate - && !has_dummy_span - && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item); - - match import { - Some((import, span, true)) if should_remove_import && import.is_nested() => { - self.add_suggestion_for_duplicate_nested_use(&mut err, import, span) - } - Some((import, _, true)) if should_remove_import && !import.is_glob() => { - // Simple case - remove the entire import. Due to the above match arm, this can - // only be a single use so just remove it entirely. - err.tool_only_span_suggestion( - import.use_span_with_attributes, - "remove unnecessary import", - String::new(), - Applicability::MaybeIncorrect, - ); - } - Some((import, span, _)) => { - self.add_suggestion_for_rename_of_use(&mut err, name, import, span) - } - _ => {} - } - - err.emit(); - self.name_already_seen.insert(name, span); - } - - /// This function adds a suggestion to change the binding name of a new import that conflicts - /// with an existing import. - /// - /// ```text,ignore (diagnostic) - /// help: you can use `as` to change the binding name of the import - /// | - /// LL | use foo::bar as other_bar; - /// | ^^^^^^^^^^^^^^^^^^^^^ - /// ``` - fn add_suggestion_for_rename_of_use( - &self, - err: &mut Diagnostic, - name: Symbol, - import: &Import<'_>, - binding_span: Span, - ) { - let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { - format!("Other{}", name) - } else { - format!("other_{}", name) - }; - - let mut suggestion = None; - match import.kind { - ImportKind::Single { type_ns_only: true, .. } => { - suggestion = Some(format!("self as {}", suggested_name)) - } - ImportKind::Single { source, .. } => { - if let Some(pos) = - source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) - { - if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) { - if pos <= snippet.len() { - suggestion = Some(format!( - "{} as {}{}", - &snippet[..pos], - suggested_name, - if snippet.ends_with(';') { ";" } else { "" } - )) - } - } - } - } - ImportKind::ExternCrate { source, target } => { - suggestion = Some(format!( - "extern crate {} as {};", - source.unwrap_or(target.name), - suggested_name, - )) - } - _ => unreachable!(), - } - - let rename_msg = "you can use `as` to change the binding name of the import"; - if let Some(suggestion) = suggestion { - err.span_suggestion( - binding_span, - rename_msg, - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(binding_span, rename_msg); - } - } - - /// This function adds a suggestion to remove an unnecessary binding from an import that is - /// nested. In the following example, this function will be invoked to remove the `a` binding - /// in the second use statement: - /// - /// ```ignore (diagnostic) - /// use issue_52891::a; - /// use issue_52891::{d, a, e}; - /// ``` - /// - /// The following suggestion will be added: - /// - /// ```ignore (diagnostic) - /// use issue_52891::{d, a, e}; - /// ^-- help: remove unnecessary import - /// ``` - /// - /// If the nested use contains only one import then the suggestion will remove the entire - /// line. - /// - /// It is expected that the provided import is nested - this isn't checked by the - /// function. If this invariant is not upheld, this function's behaviour will be unexpected - /// as characters expected by span manipulations won't be present. - fn add_suggestion_for_duplicate_nested_use( - &self, - err: &mut Diagnostic, - import: &Import<'_>, - binding_span: Span, - ) { - assert!(import.is_nested()); - let message = "remove unnecessary import"; - - // Two examples will be used to illustrate the span manipulations we're doing: - // - // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is - // `a` and `import.use_span` is `issue_52891::{d, a, e};`. - // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is - // `a` and `import.use_span` is `issue_52891::{d, e, a};`. - - let (found_closing_brace, span) = - find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span); - - // If there was a closing brace then identify the span to remove any trailing commas from - // previous imports. - if found_closing_brace { - if let Some(span) = extend_span_to_previous_binding(self.session, span) { - err.tool_only_span_suggestion( - span, - message, - String::new(), - Applicability::MaybeIncorrect, - ); - } else { - // Remove the entire line if we cannot extend the span back, this indicates an - // `issue_52891::{self}` case. - err.span_suggestion( - import.use_span_with_attributes, - message, - String::new(), - Applicability::MaybeIncorrect, - ); - } - - return; - } - - err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable); - } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<&'a NameBinding<'a>> { if ident.is_path_segment_keyword() { // Make sure `self`, `super` etc produce an error when passed to here. @@ -3289,12 +1823,7 @@ impl<'a> Resolver<'a> { } let module = self.expect_module(module_id); - match self.resolve_path( - &segments, - Some(ns), - &ParentScope::module(module, self), - Finalize::No, - ) { + match self.maybe_resolve_path(&segments, Some(ns), &ParentScope::module(module, self)) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { Some(path_res.base_res()) @@ -3384,12 +1913,11 @@ impl<'a> Resolver<'a> { let ident = Ident::with_dummy_span(sym::main); let parent_scope = &ParentScope::module(module, self); - let Ok(name_binding) = self.resolve_ident_in_module( + let Ok(name_binding) = self.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ValueNS, parent_scope, - None ) else { return; }; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 3a90908c0df0a..01f0b11f1ac3b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -3,9 +3,9 @@ use crate::imports::ImportResolver; use crate::Namespace::*; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; -use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; -use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; +use crate::{BuiltinMacroState, Determinacy}; +use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; +use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; @@ -18,14 +18,11 @@ use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, Resolver use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion}; -use rustc_feature::is_builtin_attr_name; use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, LocalDefId}; -use rustc_hir::PrimTy; use rustc_middle::middle::stability; -use rustc_middle::ty::{self, RegisteredTools}; -use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK}; -use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; +use rustc_middle::ty::RegisteredTools; +use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -35,7 +32,7 @@ use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; -use std::{mem, ptr}; +use std::mem; type Res = def::Res; @@ -73,10 +70,10 @@ pub enum MacroRulesScope<'a> { /// in a module (including derives) and hurt performance. pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell>>; -// Macro namespace is separated into two sub-namespaces, one for bang macros and -// one for attribute-like macros (attributes, derives). -// We ignore resolutions from one sub-namespace when searching names in scope for another. -fn sub_namespace_match(candidate: Option, requirement: Option) -> bool { +/// Macro namespace is separated into two sub-namespaces, one for bang macros and +/// one for attribute-like macros (attributes, derives). +/// We ignore resolutions from one sub-namespace when searching names in scope for another. +crate fn sub_namespace_match(candidate: Option, requirement: Option) -> bool { #[derive(PartialEq)] enum SubNS { Bang, @@ -415,7 +412,7 @@ impl<'a> ResolverExpand for Resolver<'a> { let mut indeterminate = false; for ns in [TypeNS, ValueNS, MacroNS].iter().copied() { - match self.resolve_path(path, Some(ns), &parent_scope, Finalize::No) { + match self.maybe_resolve_path(path, Some(ns), &parent_scope) { PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { return Ok(true); @@ -575,7 +572,7 @@ impl<'a> Resolver<'a> { } let res = if path.len() > 1 { - let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, Finalize::No) { + let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { Ok(path_res.base_res()) } @@ -607,6 +604,8 @@ impl<'a> Resolver<'a> { parent_scope, None, force, + false, + None, ); if let Err(Determinacy::Undetermined) = binding { return Err(Determinacy::Undetermined); @@ -630,355 +629,6 @@ impl<'a> Resolver<'a> { res.map(|res| (self.get_macro(res), res)) } - // Resolve an identifier in lexical scope. - // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during - // expansion and import resolution (perhaps they can be merged in the future). - // The function is used for resolving initial segments of macro paths (e.g., `foo` in - // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. - crate fn early_resolve_ident_in_lexical_scope( - &mut self, - orig_ident: Ident, - scope_set: ScopeSet<'a>, - parent_scope: &ParentScope<'a>, - finalize: Option, - force: bool, - ) -> Result<&'a NameBinding<'a>, Determinacy> { - bitflags::bitflags! { - struct Flags: u8 { - const MACRO_RULES = 1 << 0; - const MODULE = 1 << 1; - const MISC_SUGGEST_CRATE = 1 << 2; - const MISC_SUGGEST_SELF = 1 << 3; - const MISC_FROM_PRELUDE = 1 << 4; - } - } - - assert!(force || !finalize.is_some()); // `finalize` implies `force` - - // Make sure `self`, `super` etc produce an error when passed to here. - if orig_ident.is_path_segment_keyword() { - return Err(Determinacy::Determined); - } - - let (ns, macro_kind, is_import) = match scope_set { - ScopeSet::All(ns, is_import) => (ns, None, is_import), - ScopeSet::AbsolutePath(ns) => (ns, None, false), - ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), - ScopeSet::Late(ns, ..) => (ns, None, false), - }; - - // This is *the* result, resolution from the scope closest to the resolved identifier. - // However, sometimes this result is "weak" because it comes from a glob import or - // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g. - // mod m { ... } // solution in outer scope - // { - // use prefix::*; // imports another `m` - innermost solution - // // weak, cannot shadow the outer `m`, need to report ambiguity error - // m::mac!(); - // } - // So we have to save the innermost solution and continue searching in outer scopes - // to detect potential ambiguities. - let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None; - let mut determinacy = Determinacy::Determined; - - // Go through all the scopes and try to resolve the name. - let break_result = self.visit_scopes( - scope_set, - parent_scope, - orig_ident.span.ctxt(), - |this, scope, use_prelude, ctxt| { - let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); - let ok = |res, span, arenas| { - Ok(( - (res, ty::Visibility::Public, span, LocalExpnId::ROOT) - .to_name_binding(arenas), - Flags::empty(), - )) - }; - let result = match scope { - Scope::DeriveHelpers(expn_id) => { - if let Some(attr) = this - .helper_attrs - .get(&expn_id) - .and_then(|attrs| attrs.iter().rfind(|i| ident == **i)) - { - let binding = ( - Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), - ty::Visibility::Public, - attr.span, - expn_id, - ) - .to_name_binding(this.arenas); - Ok((binding, Flags::empty())) - } else { - Err(Determinacy::Determined) - } - } - Scope::DeriveHelpersCompat => { - let mut result = Err(Determinacy::Determined); - for derive in parent_scope.derives { - let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - match this.resolve_macro_path( - derive, - Some(MacroKind::Derive), - parent_scope, - true, - force, - ) { - Ok((Some(ext), _)) => { - if ext.helper_attrs.contains(&ident.name) { - result = ok( - Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), - derive.span, - this.arenas, - ); - break; - } - } - Ok(_) | Err(Determinacy::Determined) => {} - Err(Determinacy::Undetermined) => { - result = Err(Determinacy::Undetermined) - } - } - } - result - } - Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(macro_rules_binding) - if ident == macro_rules_binding.ident => - { - Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) - } - MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), - _ => Err(Determinacy::Determined), - }, - Scope::CrateRoot => { - let root_ident = Ident::new(kw::PathRoot, ident.span); - let root_module = this.resolve_crate_root(root_ident); - let binding = this.resolve_ident_in_module_ext( - ModuleOrUniformRoot::Module(root_module), - ident, - ns, - parent_scope, - finalize, - ); - match binding { - Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)), - Err((Determinacy::Undetermined, Weak::No)) => { - return Some(Err(Determinacy::determined(force))); - } - Err((Determinacy::Undetermined, Weak::Yes)) => { - Err(Determinacy::Undetermined) - } - Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), - } - } - Scope::Module(module, derive_fallback_lint_id) => { - let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; - let binding = this.resolve_ident_in_module_unadjusted_ext( - ModuleOrUniformRoot::Module(module), - ident, - ns, - adjusted_parent_scope, - !matches!(scope_set, ScopeSet::Late(..)), - finalize, - ); - match binding { - Ok(binding) => { - if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint_with_diagnostic( - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - lint_id, - orig_ident.span, - &format!( - "cannot find {} `{}` in this scope", - ns.descr(), - ident - ), - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( - orig_ident.span, - ), - ); - } - let misc_flags = if ptr::eq(module, this.graph_root) { - Flags::MISC_SUGGEST_CRATE - } else if module.is_normal() { - Flags::MISC_SUGGEST_SELF - } else { - Flags::empty() - }; - Ok((binding, Flags::MODULE | misc_flags)) - } - Err((Determinacy::Undetermined, Weak::No)) => { - return Some(Err(Determinacy::determined(force))); - } - Err((Determinacy::Undetermined, Weak::Yes)) => { - Err(Determinacy::Undetermined) - } - Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), - } - } - Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() { - Some(ident) => ok( - Res::NonMacroAttr(NonMacroAttrKind::Registered), - ident.span, - this.arenas, - ), - None => Err(Determinacy::Determined), - }, - Scope::MacroUsePrelude => { - match this.macro_use_prelude.get(&ident.name).cloned() { - Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), - None => Err(Determinacy::determined( - this.graph_root.unexpanded_invocations.borrow().is_empty(), - )), - } - } - Scope::BuiltinAttrs => { - if is_builtin_attr_name(ident.name) { - ok( - Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)), - DUMMY_SP, - this.arenas, - ) - } else { - Err(Determinacy::Determined) - } - } - Scope::ExternPrelude => { - match this.extern_prelude_get(ident, finalize.is_some()) { - Some(binding) => Ok((binding, Flags::empty())), - None => Err(Determinacy::determined( - this.graph_root.unexpanded_invocations.borrow().is_empty(), - )), - } - } - Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() { - Some(ident) => ok(Res::ToolMod, ident.span, this.arenas), - None => Err(Determinacy::Determined), - }, - Scope::StdLibPrelude => { - let mut result = Err(Determinacy::Determined); - if let Some(prelude) = this.prelude { - if let Ok(binding) = this.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(prelude), - ident, - ns, - parent_scope, - None, - ) { - if use_prelude || this.is_builtin_macro(binding.res()) { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); - } - } - } - result - } - Scope::BuiltinTypes => match PrimTy::from_name(ident.name) { - Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas), - None => Err(Determinacy::Determined), - }, - }; - - match result { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kind(), macro_kind) => - { - if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { - return Some(Ok(binding)); - } - - if let Some((innermost_binding, innermost_flags)) = innermost_result { - // Found another solution, if the first one was "weak", report an error. - let (res, innermost_res) = (binding.res(), innermost_binding.res()); - if res != innermost_res { - let is_builtin = |res| { - matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))) - }; - let derive_helper = - Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let derive_helper_compat = - Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); - - let ambiguity_error_kind = if is_import { - Some(AmbiguityKind::Import) - } else if is_builtin(innermost_res) || is_builtin(res) { - Some(AmbiguityKind::BuiltinAttr) - } else if innermost_res == derive_helper_compat - || res == derive_helper_compat && innermost_res != derive_helper - { - Some(AmbiguityKind::DeriveHelper) - } else if innermost_flags.contains(Flags::MACRO_RULES) - && flags.contains(Flags::MODULE) - && !this.disambiguate_macro_rules_vs_modularized( - innermost_binding, - binding, - ) - || flags.contains(Flags::MACRO_RULES) - && innermost_flags.contains(Flags::MODULE) - && !this.disambiguate_macro_rules_vs_modularized( - binding, - innermost_binding, - ) - { - Some(AmbiguityKind::MacroRulesVsModularized) - } else if innermost_binding.is_glob_import() { - Some(AmbiguityKind::GlobVsOuter) - } else if innermost_binding - .may_appear_after(parent_scope.expansion, binding) - { - Some(AmbiguityKind::MoreExpandedVsOuter) - } else { - None - }; - if let Some(kind) = ambiguity_error_kind { - let misc = |f: Flags| { - if f.contains(Flags::MISC_SUGGEST_CRATE) { - AmbiguityErrorMisc::SuggestCrate - } else if f.contains(Flags::MISC_SUGGEST_SELF) { - AmbiguityErrorMisc::SuggestSelf - } else if f.contains(Flags::MISC_FROM_PRELUDE) { - AmbiguityErrorMisc::FromPrelude - } else { - AmbiguityErrorMisc::None - } - }; - this.ambiguity_errors.push(AmbiguityError { - kind, - ident: orig_ident, - b1: innermost_binding, - b2: binding, - misc1: misc(innermost_flags), - misc2: misc(flags), - }); - return Some(Ok(innermost_binding)); - } - } - } else { - // Found the first solution. - innermost_result = Some((binding, flags)); - } - } - Ok(..) | Err(Determinacy::Determined) => {} - Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, - } - - None - }, - ); - - if let Some(break_result) = break_result { - return break_result; - } - - // The first found solution was the only one, return it. - if let Some((binding, _)) = innermost_result { - return Ok(binding); - } - - Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) - } - crate fn finalize_macro_resolutions(&mut self) { let check_consistency = |this: &mut Self, path: &[Segment], @@ -1024,6 +674,7 @@ impl<'a> Resolver<'a> { Some(MacroNS), &parent_scope, Finalize::SimplePath(ast::CRATE_NODE_ID, path_span), + None, ) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { let res = path_res.base_res(); @@ -1059,6 +710,8 @@ impl<'a> Resolver<'a> { &parent_scope, Some(ident.span), true, + false, + None, ) { Ok(binding) => { let initial_res = initial_binding.map(|initial_binding| { @@ -1100,6 +753,8 @@ impl<'a> Resolver<'a> { &parent_scope, Some(ident.span), true, + false, + None, ); } }