diff options
| author | Camille GILLOT <gillot.camille@gmail.com> | 2022-03-26 20:59:09 +0100 |
|---|---|---|
| committer | Camille GILLOT <gillot.camille@gmail.com> | 2022-04-12 19:49:02 +0200 |
| commit | e9a52c27d2bca3b39742dcc89c2b5ee643660fec (patch) | |
| tree | 115bdd23565361d71d7467b55595bd0b0731b6c7 | |
| parent | 341883d051ebbfaa6daa456b198d557fa0272b71 (diff) | |
| download | rust-e9a52c27d2bca3b39742dcc89c2b5ee643660fec.tar.gz rust-e9a52c27d2bca3b39742dcc89c2b5ee643660fec.zip | |
Move ident resolution to a dedicated module.
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 1645 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 289 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 1005 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 372 |
4 files changed, 1668 insertions, 1643 deletions
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs new file mode 100644 index 00000000000..0111ab506c5 --- /dev/null +++ b/compiler/rustc_resolve/src/ident.rs @@ -0,0 +1,1645 @@ +use rustc_ast::{self as ast, NodeId}; +use rustc_ast_pretty::pprust; +use rustc_errors::Applicability; +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, sym, 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, NameBinding, +}; +use crate::{ + NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, + ScopeSet, Segment, +}; +use crate::{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<T>( + &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<T>, + ) -> Option<T> { + // 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<NodeId>, + ) -> Option<(Module<'a>, Option<NodeId>)> { + 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. + crate fn resolve_ident_in_lexical_scope( + &mut self, + mut ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize_full: Finalize, + ribs: &[Rib<'a>], + ) -> Option<LexicalScopeBinding<'a>> { + 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) + } + + /// 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<Span>, + 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 resolve_ident_in_module( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize: Option<Span>, + ) -> 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<Span>, + ) -> 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_ident_in_module_unadjusted( + &mut self, + module: ModuleOrUniformRoot<'a>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'a>, + finalize: Option<Span>, + ) -> 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. + 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<Span>, + ) -> 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)) + } + + /// Validate a local resolution (from ribs). + fn validate_res_from_ribs( + &mut self, + rib_index: usize, + rib_ident: Ident, + mut res: Res, + finalize: Option<Span>, + 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 + } + + crate fn resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option<Namespace>, // `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) + } + + crate fn resolve_path_with_ribs( + &mut self, + path: &[Segment], + opt_ns: Option<Namespace>, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, + finalize_full: Finalize, + ribs: Option<&PerNS<Vec<Rib<'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>), + 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() { + 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), + }) + } +} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 02abdbaa983..3d199afb13d 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<Interned<'a, Import<'a>>>, + pub single_imports: FxHashSet<Interned<'a, Import<'a>>>, /// 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<Span>, - ) -> 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<Span>, - ) -> 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( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a09a225a2b5..f4a650e8d26 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -26,8 +26,6 @@ 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; @@ -37,7 +35,6 @@ use rustc_ast::{Crate, CRATE_NODE_ID}; use rustc_ast::{Expr, ExprKind, LitKind}; use rustc_ast::{ItemKind, ModKind, 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; @@ -46,7 +43,7 @@ use rustc_errors::{ }; 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 +52,15 @@ 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::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}; @@ -78,7 +74,7 @@ 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 +86,7 @@ mod build_reduced_graph; mod check_unused; mod def_collector; mod diagnostics; +mod ident; mod imports; mod late; mod macros; @@ -1731,387 +1728,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<T>( - &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<T>, - ) -> Option<T> { - // 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<LexicalScopeBinding<'a>> { - 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<NodeId>, - ) -> Option<(Module<'a>, Option<NodeId>)> { - 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<Span>, - ) -> 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<Span>, - ) -> 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,384 +1810,6 @@ impl<'a> Resolver<'a> { module } - fn resolve_path( - &mut self, - path: &[Segment], - opt_ns: Option<Namespace>, // `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<Namespace>, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, - finalize_full: Finalize, - ribs: Option<&PerNS<Vec<Rib<'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>), - 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::<NodeId>::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, @@ -2631,239 +1869,6 @@ impl<'a> Resolver<'a> { ); } - // Validate a local resolution (from ribs). - fn validate_res_from_ribs( - &mut self, - rib_index: usize, - rib_ident: Ident, - mut res: Res, - finalize: Option<Span>, - 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) { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 3a90908c0df..71795ef1633 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<NodeId>; @@ -73,10 +70,10 @@ pub enum MacroRulesScope<'a> { /// in a module (including derives) and hurt performance. pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>; -// 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<MacroKind>, requirement: Option<MacroKind>) -> 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<MacroKind>, requirement: Option<MacroKind>) -> bool { #[derive(PartialEq)] enum SubNS { Bang, @@ -630,355 +627,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<Span>, - 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], |
