diff --git a/Cargo.lock b/Cargo.lock index 9e4b2915feff9..a1625311d292f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4574,7 +4574,6 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags", "indexmap", "itertools", "pulldown-cmark", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index eb98a6e85c06b..dd15e879c6440 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" indexmap = "2.4.0" itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b0cdfe8ab87dc..8f20b5fe5745f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -44,7 +44,7 @@ use crate::errors::{ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize, + AmbiguityError, AmbiguityKind, BindingError, BindingKey, Finalize, ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, @@ -1968,23 +1968,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { + fn binding_description(&self, b: NameBinding<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { - // These already contain the "built-in" prefix or look bad with it. - let add_built_in = - !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); - let (built_in, from) = if from_prelude { - ("", " from prelude") - } else if b.is_extern_crate() - && !b.is_import() - && self.tcx.sess.opts.externs.get(ident.as_str()).is_some() - { - ("", " passed with `--extern`") - } else if add_built_in { - (" built-in", "") - } else { - ("", "") + let (built_in, from) = match scope { + Scope::StdLibPrelude | Scope::MacroUsePrelude => ("", " from prelude"), + Scope::ExternPreludeFlags + if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() => + { + ("", " passed with `--extern`") + } + _ => { + if matches!(res, Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod) { + // These already contain the "built-in" prefix or look bad with it. + ("", "") + } else { + (" built-in", "") + } + } }; let a = if built_in.is_empty() { res.article() } else { "a" }; @@ -1996,22 +1997,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity { - let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; + let AmbiguityError { kind, ident, b1, b2, scope1, scope2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { - self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { - entry.item_binding.map(|(b, _)| b) == Some(b1) - && entry.flag_binding.as_ref().and_then(|pb| pb.get().0.binding()) == Some(b2) - }) + // Note: b1 may come from a module scope, as an extern crate item in module. + matches!(scope2, Scope::ExternPreludeFlags) + && self + .extern_prelude + .get(&Macros20NormalizedIdent::new(ident)) + .is_some_and(|entry| entry.item_binding.map(|(b, _)| b) == Some(b1)) }; - let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { + let (b1, b2, scope1, scope2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. - (b2, b1, misc2, misc1, true) + (b2, b1, scope2, scope1, true) } else { - (b1, b2, misc1, misc2, false) + (b1, b2, scope1, scope2, false) }; - let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { - let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); + let could_refer_to = |b: NameBinding<'_>, scope: Scope<'ra>, also: &str| { + let what = self.binding_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); let thing = b.res().descr(); @@ -2029,12 +2032,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } - match misc { - AmbiguityErrorMisc::SuggestCrate => help_msgs - .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")), - AmbiguityErrorMisc::SuggestSelf => help_msgs - .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")), - AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {} + + if let Scope::Module(module, _) = scope { + if module == self.graph_root { + help_msgs.push(format!( + "use `crate::{ident}` to refer to this {thing} unambiguously" + )); + } else if module != self.empty_module && module.is_normal() { + help_msgs.push(format!( + "use `self::{ident}` to refer to this {thing} unambiguously" + )); + } } ( @@ -2049,8 +2057,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::>(), ) }; - let (b1_note, b1_help_msgs) = could_refer_to(b1, misc1, ""); - let (b2_note, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + let (b1_note, b1_help_msgs) = could_refer_to(b1, scope1, ""); + let (b2_note, b2_help_msgs) = could_refer_to(b2, scope2, " also"); errors::Ambiguity { ident, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f4a594a4731d2..669f045681b7d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,10 +19,10 @@ use crate::late::{ }; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, - Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, - Resolver, Scope, ScopeSet, Segment, Stage, Used, errors, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportKind, + LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, + ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, + Segment, Stage, Used, errors, }; #[derive(Copy, Clone)] @@ -43,17 +43,6 @@ enum Shadowing { Unrestricted, } -bitflags::bitflags! { - #[derive(Clone, Copy)] - 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; - } -} - impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -430,10 +419,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // 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 innermost_results: Vec<(NameBinding<'_>, Scope<'_>)> = Vec::new(); let mut determinacy = Determinacy::Determined; - let mut extern_prelude_item_binding = None; - let mut extern_prelude_flag_binding = None; // Go through all the scopes and try to resolve the name. let break_result = self.visit_scopes( @@ -454,16 +441,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { scope_set, parent_scope, // Shadowed bindings don't need to be marked as used or non-speculatively loaded. - if innermost_result.is_none() { finalize } else { None }, + if innermost_results.is_empty() { finalize } else { None }, force, ignore_binding, ignore_import, - &mut extern_prelude_item_binding, - &mut extern_prelude_flag_binding, )? { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kinds(), macro_kind) => - { + Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, // or in late resolution when everything is already imported and expanded @@ -472,25 +455,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return ControlFlow::Break(Ok(binding)); } - if let Some((innermost_binding, innermost_flags)) = innermost_result { + if let Some(&(innermost_binding, _)) = innermost_results.first() { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, parent_scope, binding, - innermost_binding, - flags, - innermost_flags, - extern_prelude_item_binding, - extern_prelude_flag_binding, + scope, + &innermost_results, ) { // No need to search for more potential ambiguities, one is enough. return ControlFlow::Break(Ok(innermost_binding)); } - } else { - // Found the first solution. - innermost_result = Some((binding, flags)); } + + innermost_results.push((binding, scope)); } Ok(_) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, @@ -506,8 +485,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Scope visiting walked all the scopes and maybe found something in one of them. - match innermost_result { - Some((binding, _)) => Ok(binding), + match innermost_results.first() { + Some(&(binding, ..)) => Ok(binding), None => Err(Determinacy::determined(determinacy == Determinacy::Determined || force)), } } @@ -525,19 +504,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, ignore_binding: Option>, ignore_import: Option>, - extern_prelude_item_binding: &mut Option>, - extern_prelude_flag_binding: &mut Option>, - ) -> ControlFlow< - Result, Determinacy>, - Result<(NameBinding<'ra>, Flags), Determinacy>, - > { + ) -> ControlFlow, Determinacy>, Result, Determinacy>> + { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(binding) = self.helper_attrs.get(&expn_id).and_then(|attrs| { attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, binding)| *binding) }) { - Ok((binding, Flags::empty())) + Ok(binding) } else { Err(Determinacy::Determined) } @@ -559,7 +534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { derive.span, LocalExpnId::ROOT, ); - result = Ok((binding, Flags::empty())); + result = Ok(binding); break; } } @@ -573,7 +548,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Binding(macro_rules_binding) if ident == macro_rules_binding.ident => { - Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) + Ok(macro_rules_binding.binding) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), @@ -612,14 +587,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - let misc_flags = if module == self.graph_root { - Flags::MISC_SUGGEST_CRATE - } else if module.is_normal() { - Flags::MISC_SUGGEST_SELF - } else { - Flags::empty() - }; - Ok((binding, Flags::MODULE | misc_flags)) + Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(Determinacy::Undetermined)) => { @@ -630,21 +598,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { - Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), + Some(binding) => Ok(binding), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, Scope::BuiltinAttrs => match self.builtin_attrs_bindings.get(&ident.name) { - Some(binding) => Ok((*binding, Flags::empty())), + Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { match self.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { - Some(binding) => { - *extern_prelude_item_binding = Some(binding); - Ok((binding, Flags::empty())) - } + Some(binding) => Ok(binding), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), @@ -652,15 +617,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeFlags => { match self.extern_prelude_get_flag(ident, finalize.is_some()) { - Some(binding) => { - *extern_prelude_flag_binding = Some(binding); - Ok((binding, Flags::empty())) - } + Some(binding) => Ok(binding), None => Err(Determinacy::Determined), } } Scope::ToolPrelude => match self.registered_tool_bindings.get(&ident) { - Some(binding) => Ok((*binding, Flags::empty())), + Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, Scope::StdLibPrelude => { @@ -679,7 +641,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && (matches!(use_prelude, UsePrelude::Yes) || self.is_builtin_macro(binding.res())) { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); + result = Ok(binding) } result @@ -712,7 +674,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - Ok((*binding, Flags::empty())) + Ok(*binding) } None => Err(Determinacy::Determined), }, @@ -726,17 +688,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident: Ident, parent_scope: &ParentScope<'ra>, binding: NameBinding<'ra>, - innermost_binding: NameBinding<'ra>, - flags: Flags, - innermost_flags: Flags, - extern_prelude_item_binding: Option>, - extern_prelude_flag_binding: Option>, + scope: Scope<'ra>, + innermost_results: &[(NameBinding<'ra>, Scope<'ra>)], ) -> bool { + let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res == innermost_res { return false; } + // FIXME: Use `scope` instead of `res` to detect built-in attrs and derive helpers, + // it will exclude imports, make slightly more code legal, and will require lang approval. 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); @@ -747,12 +709,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(AmbiguityKind::DeriveHelper) } else if res == derive_helper_compat && innermost_res != derive_helper { span_bug!(orig_ident.span, "impossible inner resolution kind") - } else if innermost_flags.contains(Flags::MACRO_RULES) - && flags.contains(Flags::MODULE) + } else if matches!(innermost_scope, Scope::MacroRules(_)) + && matches!(scope, Scope::Module(..)) && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) { Some(AmbiguityKind::MacroRulesVsModularized) - } else if flags.contains(Flags::MACRO_RULES) && innermost_flags.contains(Flags::MODULE) { + } else if matches!(scope, Scope::MacroRules(_)) + && matches!(innermost_scope, Scope::Module(..)) + { // should be impossible because of visitation order in // visit_scopes // @@ -774,32 +738,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Skip ambiguity errors for extern flag bindings "overridden" // by extern item bindings. // FIXME: Remove with lang team approval. - let issue_145575_hack = Some(binding) == extern_prelude_flag_binding - && extern_prelude_item_binding.is_some() - && extern_prelude_item_binding != Some(innermost_binding); + let issue_145575_hack = matches!(scope, Scope::ExternPreludeFlags) + && innermost_results[1..].iter().any(|(b, s)| { + matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding + }); if issue_145575_hack { self.issue_145575_hack_applied = true; } else { - 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 - } - }; self.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, b2: binding, + scope1: innermost_scope, + scope2: scope, warning: false, - misc1: misc(innermost_flags), - misc2: misc(flags), }); return true; } @@ -1216,9 +1170,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: binding, b2: shadowed_glob, + scope1: Scope::Module(self.empty_module, None), + scope2: Scope::Module(self.empty_module, None), warning: false, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ec030ecf8e13f..7cbf2088efce5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -903,22 +903,14 @@ impl AmbiguityKind { } } -/// Miscellaneous bits of metadata for better ambiguity error reporting. -#[derive(Clone, Copy, PartialEq)] -enum AmbiguityErrorMisc { - SuggestCrate, - SuggestSelf, - FromPrelude, - None, -} - struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, b1: NameBinding<'ra>, b2: NameBinding<'ra>, - misc1: AmbiguityErrorMisc, - misc2: AmbiguityErrorMisc, + // `empty_module` in module scope serves as an unknown module here. + scope1: Scope<'ra>, + scope2: Scope<'ra>, warning: bool, } @@ -2045,8 +2037,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && ambiguity_error.ident.span == ambi.ident.span && ambiguity_error.b1.span == ambi.b1.span && ambiguity_error.b2.span == ambi.b2.span - && ambiguity_error.misc1 == ambi.misc1 - && ambiguity_error.misc2 == ambi.misc2 { return true; } @@ -2071,8 +2061,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: used_binding, b2, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, + scope1: Scope::Module(self.empty_module, None), + scope2: Scope::Module(self.empty_module, None), warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) {