diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 61ee467f595..389f3ccf72a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1982,73 +1982,6 @@ declare_lint! { }; } -declare_lint! { - /// The `proc_macro_derive_resolution_fallback` lint detects proc macro - /// derives using inaccessible names from parent modules. - /// - /// ### Example - /// - /// ```rust,ignore (proc-macro) - /// // foo.rs - /// #![crate_type = "proc-macro"] - /// - /// extern crate proc_macro; - /// - /// use proc_macro::*; - /// - /// #[proc_macro_derive(Foo)] - /// pub fn foo1(a: TokenStream) -> TokenStream { - /// drop(a); - /// "mod __bar { static mut BAR: Option = None; }".parse().unwrap() - /// } - /// ``` - /// - /// ```rust,ignore (needs-dependency) - /// // bar.rs - /// #[macro_use] - /// extern crate foo; - /// - /// struct Something; - /// - /// #[derive(Foo)] - /// struct Another; - /// - /// fn main() {} - /// ``` - /// - /// This will produce: - /// - /// ```text - /// warning: cannot find type `Something` in this scope - /// --> src/main.rs:8:10 - /// | - /// 8 | #[derive(Foo)] - /// | ^^^ names from parent modules are not accessible without an explicit import - /// | - /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #50504 - /// ``` - /// - /// ### Explanation - /// - /// If a proc-macro generates a module, the compiler unintentionally - /// allowed items in that module to refer to items in the crate root - /// without importing them. This is a [future-incompatible] lint to - /// transition this to a hard error in the future. See [issue #50504] for - /// more details. - /// - /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - Deny, - "detects proc macro derives using inaccessible names from parent modules", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #83583 ", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, - }; -} - declare_lint! { /// The `macro_use_extern_crate` lint detects the use of the /// [`macro_use` attribute]. @@ -3287,7 +3220,6 @@ declare_lint_pass! { UNSTABLE_NAME_COLLISIONS, IRREFUTABLE_LET_PATTERNS, WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, ILL_FORMED_ATTRIBUTE_INPUT, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a17793ecd99..423c5727533 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -56,21 +56,7 @@ impl<'a, Id: Into> ToNameBinding<'a> impl<'a, Id: Into> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, false), - ambiguity: None, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - -struct IsMacroExport; - -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { - arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, true), + kind: NameBindingKind::Res(self.0), ambiguity: None, vis: self.1.to_def_id(), span: self.2, @@ -364,7 +350,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { module_path: Vec, kind: ImportKind<'a>, span: Span, - id: NodeId, item: &ast::Item, root_span: Span, root_id: NodeId, @@ -377,7 +362,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { module_path, imported_module: Cell::new(None), span, - id, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), @@ -574,27 +558,20 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }, type_ns_only, nested, + id, additional_ids: (id1, id2), }; - self.add_import( - module_path, - kind, - use_tree.span, - id, - item, - root_span, - item.id, - vis, - ); + self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), + id, }; self.r.visibilities.insert(self.r.local_def_id(id), vis); - self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis); + self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Nested(ref items) => { // Ensure there is at most one `self` in the list @@ -881,9 +858,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }) .unwrap_or((true, None, self.r.dummy_binding)); let import = self.r.arenas.alloc_import(Import { - kind: ImportKind::ExternCrate { source: orig_name, target: ident }, + kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, - id: item.id, parent_scope: self.parent_scope, imported_module: Cell::new(module), has_attributes: !item.attrs.is_empty(), @@ -1118,7 +1094,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { this.r.arenas.alloc_import(Import { kind: ImportKind::MacroUse, root_id: item.id, - id: item.id, parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), @@ -1278,8 +1253,22 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); if is_macro_export { - let module = self.r.graph_root; - self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); + let import = self.r.arenas.alloc_import(Import { + kind: ImportKind::MacroExport, + root_id: item.id, + parent_scope: self.parent_scope, + imported_module: Cell::new(None), + has_attributes: false, + use_span_with_attributes: span, + use_span: span, + root_span: span, + span: span, + module_path: Vec::new(), + vis: Cell::new(Some(vis)), + used: Cell::new(true), + }); + let import_binding = self.r.import(binding, import); + self.r.define(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id, &rule_spans); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 01c3801f223..32fb5e18276 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -234,7 +234,7 @@ impl Resolver<'_> { if !import.span.is_dummy() { self.lint_buffer.buffer_lint( MACRO_USE_EXTERN_CRATE, - import.id, + import.root_id, import.span, "deprecated `#[macro_use]` attribute used to \ import macros should be replaced at use sites \ @@ -244,13 +244,13 @@ impl Resolver<'_> { } } } - ImportKind::ExternCrate { .. } => { - let def_id = self.local_def_id(import.id); + ImportKind::ExternCrate { id, .. } => { + let def_id = self.local_def_id(id); self.maybe_unused_extern_crates.push((def_id, import.span)); } ImportKind::MacroUse => { let msg = "unused `#[macro_use]` import"; - self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg); } _ => {} } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5029c339963..7961e3f1194 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -190,12 +190,12 @@ impl<'a> Resolver<'a> { ModuleKind::Block => "block", }; - let old_noun = match old_binding.is_import() { + let old_noun = match old_binding.is_import_user_facing() { true => "import", false => "definition", }; - let new_participle = match new_binding.is_import() { + let new_participle = match new_binding.is_import_user_facing() { true => "imported", false => "defined", }; @@ -226,7 +226,7 @@ impl<'a> Resolver<'a> { true => struct_span_err!(self.session, span, E0254, "{}", msg), false => struct_span_err!(self.session, span, E0260, "{}", msg), }, - _ => match (old_binding.is_import(), new_binding.is_import()) { + _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg), _ => struct_span_err!(self.session, span, E0255, "{}", msg), @@ -248,14 +248,18 @@ impl<'a> Resolver<'a> { // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; + let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| { + !binding.span.is_dummy() + && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport) + }; let import = match (&new_binding.kind, &old_binding.kind) { // If there are two imports where one or both have attributes then prefer removing the // import without attributes. (Import { import: new, .. }, Import { import: old, .. }) if { - !new_binding.span.is_dummy() - && !old_binding.span.is_dummy() - && (new.has_attributes || old.has_attributes) + (new.has_attributes || old.has_attributes) + && can_suggest(old_binding, old) + && can_suggest(new_binding, new) } => { if old.has_attributes { @@ -265,10 +269,10 @@ impl<'a> Resolver<'a> { } } // Otherwise prioritize the new binding. - (Import { import, .. }, other) if !new_binding.span.is_dummy() => { + (Import { import, .. }, other) if can_suggest(new_binding, import) => { Some((import, new_binding.span, other.is_import())) } - (other, Import { import, .. }) if !old_binding.span.is_dummy() => { + (other, Import { import, .. }) if can_suggest(old_binding, import) => { Some((import, old_binding.span, other.is_import())) } _ => None, @@ -353,7 +357,7 @@ impl<'a> Resolver<'a> { } } } - ImportKind::ExternCrate { source, target } => { + ImportKind::ExternCrate { source, target, .. } => { suggestion = Some(format!( "extern crate {} as {};", source.unwrap_or(target.name), @@ -1202,7 +1206,7 @@ impl<'a> Resolver<'a> { let root_module = this.resolve_crate_root(root_ident); this.add_module_candidates(root_module, &mut suggestions, filter_fn, None); } - Scope::Module(module, _) => { + Scope::Module(module) => { this.add_module_candidates(module, &mut suggestions, filter_fn, None); } Scope::MacroUsePrelude => { @@ -1683,7 +1687,7 @@ impl<'a> Resolver<'a> { let a = if built_in.is_empty() { res.article() } else { "a" }; format!("{a}{built_in} {thing}{from}", thing = res.descr()) } else { - let introduced = if b.is_import() { "imported" } else { "defined" }; + let introduced = if b.is_import_user_facing() { "imported" } else { "defined" }; format!("the {thing} {introduced} here", thing = res.descr()) } } @@ -1742,10 +1746,10 @@ impl<'a> Resolver<'a> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option { - if let NameBindingKind::Res( - Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id), - _, - ) = binding.kind + if let NameBindingKind::Res(Res::Def( + DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), + ctor_def_id, + )) = binding.kind { let def_id = self.parent(ctor_def_id); let fields = self.field_names.get(&def_id)?; @@ -1789,7 +1793,9 @@ impl<'a> Resolver<'a> { next_ident = source; Some(binding) } - ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding), + ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => { + Some(binding) + } ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index c40669ac95b..17ce854cb43 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -57,26 +57,45 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { while let NameBindingKind::Import { binding: nested_binding, import, .. } = binding.kind { - let mut update = |node_id| self.update( - self.r.local_def_id(node_id), - binding.vis.expect_local(), - prev_parent_id, - level, - ); - // In theory all the import IDs have individual visibilities and effective - // visibilities, but in practice these IDs go straigth to HIR where all - // their few uses assume that their (effective) visibility applies to the - // whole syntactic `use` item. So we update them all to the maximum value - // among the potential individual effective visibilities. Maybe HIR for - // imports shouldn't use three IDs at all. - update(import.id); - if let ImportKind::Single { additional_ids, .. } = import.kind { - update(additional_ids.0); - update(additional_ids.1); + let mut update = |node_id| { + self.update( + self.r.local_def_id(node_id), + binding.vis.expect_local(), + prev_parent_id, + level, + ) + }; + match import.kind { + ImportKind::Single { id, additional_ids, .. } => { + // In theory all the import IDs have individual visibilities and + // effective visibilities, but in practice these IDs go straigth to + // HIR where all their few uses assume that their (effective) + // visibility applies to the whole syntactic `use` item. So we + // update them all to the maximum value among the potential + // individual effective visibilities. Maybe HIR for imports + // shouldn't use three IDs at all. + update(id); + update(additional_ids.0); + update(additional_ids.1); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => { + update(id); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::MacroUse => { + // In theory we should reset the parent id to something private + // here, but `macro_use` imports always refer to external items, + // so it doesn't matter and we can just do nothing. + } + ImportKind::MacroExport => { + // In theory we should reset the parent id to something public + // here, but it has the same effect as leaving the previous parent, + // so we can just do nothing. + } } level = Level::Reexported; - prev_parent_id = self.r.local_def_id(import.id); binding = nested_binding; } } @@ -138,13 +157,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> { self.update(def_id, Visibility::Public, parent_id, Level::Direct); } - // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { - let parent_id = self.r.local_parent(def_id); - let vis = self.r.visibilities[&def_id]; - self.update(def_id, vis, parent_id, Level::Direct); - } - ast::ItemKind::Mod(..) => { self.set_bindings_effective_visibilities(def_id); visit::walk_item(self, item); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0542d5479f..0c4b35b8833 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1,11 +1,9 @@ -use rustc_ast::{self as ast, NodeId}; +use rustc_ast as ast; 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::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; @@ -19,7 +17,7 @@ use crate::late::{ }; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; -use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -101,7 +99,7 @@ impl<'a> Resolver<'a> { }; let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module, None), + TypeNS | ValueNS => Scope::Module(module), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -165,7 +163,7 @@ impl<'a> Resolver<'a> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module, None), + MacroRulesScope::Empty => Scope::Module(module), }, Scope::CrateRoot => match ns { TypeNS => { @@ -174,16 +172,10 @@ impl<'a> Resolver<'a> { } ValueNS | MacroNS => break, }, - Scope::Module(module, prev_lint_id) => { + Scope::Module(module) => { 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)) - } + match self.hygienic_lexical_parent(module, &mut ctxt) { + Some(parent_module) => Scope::Module(parent_module), None => { ctxt.adjust(ExpnId::root()); match ns { @@ -215,45 +207,13 @@ impl<'a> Resolver<'a> { &mut self, module: Module<'a>, ctxt: &mut SyntaxContext, - derive_fallback_lint_id: Option, - ) -> Option<(Module<'a>, Option)> { + ) -> Option> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.expn_def_scope(ctxt.remove_mark()), None)); + return Some(self.expn_def_scope(ctxt.remove_mark())); } 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).ext; - 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)); - } - } - } - } + return Some(module.parent.unwrap().nearest_item_scope()); } None @@ -510,7 +470,7 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::Module(module, derive_fallback_lint_id) => { + Scope::Module(module) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), @@ -523,21 +483,6 @@ impl<'a> Resolver<'a> { ); 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() { @@ -915,7 +860,11 @@ impl<'a> Resolver<'a> { } if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Res(_, true) = binding.kind { + if let NameBindingKind::Import { + import: Import { kind: ImportKind::MacroExport, .. }, + .. + } = binding.kind + { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f2cc50c199f..bdb852548b8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -44,20 +44,36 @@ pub enum ImportKind<'a> { type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` nested: bool, + /// The ID of the `UseTree` that imported this `Import`. + /// + /// In the case where the `Import` was expanded from a "nested" use tree, + /// this id is the ID of the leaf tree. For example: + /// + /// ```ignore (pacify the merciless tidy) + /// use foo::bar::{a, b} + /// ``` + /// + /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` + /// for `a` in this field. + id: NodeId, /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement /// (eg. implicit struct constructors) additional_ids: (NodeId, NodeId), }, Glob { is_prelude: bool, - max_vis: Cell>, // The visibility of the greatest re-export. - // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + // The visibility of the greatest re-export. + // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + max_vis: Cell>, + id: NodeId, }, ExternCrate { source: Option, target: Ident, + id: NodeId, }, MacroUse, + MacroExport, } /// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` @@ -71,6 +87,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { ref target, ref type_ns_only, ref nested, + ref id, ref additional_ids, // Ignore the following to avoid an infinite loop while printing. source_bindings: _, @@ -81,19 +98,23 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { .field("target", target) .field("type_ns_only", type_ns_only) .field("nested", nested) + .field("id", id) .field("additional_ids", additional_ids) .finish_non_exhaustive(), - Glob { ref is_prelude, ref max_vis } => f + Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) .field("max_vis", max_vis) + .field("id", id) .finish(), - ExternCrate { ref source, ref target } => f + ExternCrate { ref source, ref target, ref id } => f .debug_struct("ExternCrate") .field("source", source) .field("target", target) + .field("id", id) .finish(), MacroUse => f.debug_struct("MacroUse").finish(), + MacroExport => f.debug_struct("MacroExport").finish(), } } } @@ -103,24 +124,15 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { pub(crate) struct Import<'a> { pub kind: ImportKind<'a>, - /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`. - /// - /// In the case where the `Import` was expanded from a "nested" use tree, - /// this id is the ID of the leaf tree. For example: - /// - /// ```ignore (pacify the merciless tidy) + /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id` + /// (if it exists) except in the case of "nested" use trees, in which case + /// it will be the ID of the root use tree. e.g., in the example + /// ```ignore (incomplete code) /// use foo::bar::{a, b} /// ``` - /// - /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` - /// for `a` in this field. - pub id: NodeId, - - /// The `id` of the "root" use-kind -- this is always the same as - /// `id` except in the case of "nested" use trees, in which case - /// it will be the `id` of the root use tree. e.g., in the example - /// from `id`, this would be the ID of the `use foo::bar` - /// `UseTree` node. + /// this would be the ID of the `use foo::bar` `UseTree` node. + /// In case of imports without their own node ID it's the closest node that can be used, + /// for example, for reporting lints. pub root_id: NodeId, /// Span of the entire use statement. @@ -161,6 +173,15 @@ impl<'a> Import<'a> { pub(crate) fn expect_vis(&self) -> ty::Visibility { self.vis.get().expect("encountered cleared import visibility") } + + pub(crate) fn id(&self) -> Option { + match self.kind { + ImportKind::Single { id, .. } + | ImportKind::Glob { id, .. } + | ImportKind::ExternCrate { id, .. } => Some(id), + ImportKind::MacroUse | ImportKind::MacroExport => None, + } + } } /// Records information about the resolution of a name in a namespace of a module. @@ -368,7 +389,9 @@ impl<'a> Resolver<'a> { self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } } } } @@ -718,47 +741,51 @@ impl<'a, 'b> ImportResolver<'a, 'b> { PathResult::Indeterminate => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), - ImportKind::Glob { is_prelude, ref max_vis } => { - if import.module_path.len() <= 1 { - // HACK(eddyb) `lint_if_path_starts_with_module` needs at least - // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::empty())); - self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); - } - - if let ModuleOrUniformRoot::Module(module) = module { - if ptr::eq(module, import.parent_scope.module) { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from("cannot glob-import a module into itself")), - note: None, - suggestion: None, - candidate: None, - }); + let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) = + match import.kind { + ImportKind::Single { + source, + target, + ref source_bindings, + ref target_bindings, + type_ns_only, + id, + .. + } => (source, target, source_bindings, target_bindings, type_ns_only, id), + ImportKind::Glob { is_prelude, ref max_vis, id } => { + if import.module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = import.module_path.clone(); + full_path.push(Segment::from_ident(Ident::empty())); + self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } - } - if !is_prelude + + if let ModuleOrUniformRoot::Module(module) = module { + if ptr::eq(module, import.parent_scope.module) { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from( + "cannot glob-import a module into itself", + )), + note: None, + suggestion: None, + candidate: None, + }); + } + } + if !is_prelude && let Some(max_vis) = max_vis.get() && !max_vis.is_at_least(import.expect_vis(), &*self.r) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; - self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg); } - return None; - } - _ => unreachable!(), - }; + return None; + } + _ => unreachable!(), + }; let mut all_ns_err = true; self.r.per_ns(|this, ns| { @@ -858,7 +885,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { match binding.kind { // Never suggest the name that has binding error // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err, _) => None, + NameBindingKind::Res(Res::Err) => None, _ => Some(i.name), } } @@ -960,7 +987,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ); self.r.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, - import.id, + import_id, import.span, &msg, ); @@ -989,7 +1016,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut err = struct_span_err!(self.r.session, import.span, E0364, "{error_msg}"); match binding.kind { - NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _) + NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id)) // exclude decl_macro if self.r.get_macro_by_def_id(def_id).macro_rules => { @@ -1029,7 +1056,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // purposes it's good enough to just favor one over the other. self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res()); + this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1047,6 +1074,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { target_bindings: &PerNS>>>, target: Ident, ) { + // This function is only called for single imports. + let ImportKind::Single { id, .. } = import.kind else { unreachable!() }; + // Skip if the import was produced by a macro. if import.parent_scope.expansion != LocalExpnId::ROOT { return; @@ -1094,7 +1124,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { redundant_spans.dedup(); self.r.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, - import.id, + id, import.span, &format!("the item `{}` is imported redundantly", ident), BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), @@ -1103,6 +1133,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } fn resolve_glob_import(&mut self, import: &'b Import<'b>) { + // This function is only called for glob imports. + let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; + let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { self.r.session.span_err(import.span, "cannot glob-import all possible crates"); return; @@ -1113,7 +1146,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return; } else if ptr::eq(module, import.parent_scope.module) { return; - } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { + } else if is_prelude { self.r.prelude = Some(module); return; } @@ -1145,7 +1178,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } // Record the destination of this import - self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap())); + self.r.record_partial_res(id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1204,5 +1237,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String { ImportKind::Glob { .. } => "*".to_string(), ImportKind::ExternCrate { .. } => "".to_string(), ImportKind::MacroUse => "#[macro_use]".to_string(), + ImportKind::MacroExport => "#[macro_export]".to_string(), } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 11b70a38da5..ee1c97d5ad2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -104,9 +104,7 @@ enum Scope<'a> { DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, - // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` - // lint if it should be reported. - Module(Module<'a>, Option), + Module(Module<'a>), MacroUsePrelude, BuiltinAttrs, ExternPrelude, @@ -646,7 +644,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { #[derive(Clone, Debug)] enum NameBindingKind<'a> { - Res(Res, /* is_macro_export */ bool), + Res(Res), Module(Module<'a>), Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell }, } @@ -745,7 +743,7 @@ impl<'a> NameBinding<'a> { fn res(&self) -> Res { match self.kind { - NameBindingKind::Res(res, _) => res, + NameBindingKind::Res(res) => res, NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } @@ -762,10 +760,10 @@ impl<'a> NameBinding<'a> { fn is_possibly_imported_variant(&self) -> bool { match self.kind { NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), - NameBindingKind::Res( - Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _), + NameBindingKind::Res(Res::Def( + DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, - ) => true, + )) => true, NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, } } @@ -788,6 +786,13 @@ impl<'a> NameBinding<'a> { matches!(self.kind, NameBindingKind::Import { .. }) } + /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might + /// not be perceived as such by users, so treat it as a non-import in some diagnostics. + fn is_import_user_facing(&self) -> bool { + matches!(self.kind, NameBindingKind::Import { import, .. } + if !matches!(import.kind, ImportKind::MacroExport)) + } + fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { import, .. } => import.is_glob(), @@ -1283,7 +1288,7 @@ impl<'a> Resolver<'a> { arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(Res::Err, false), + kind: NameBindingKind::Res(Res::Err), ambiguity: None, expansion: LocalExpnId::ROOT, span: DUMMY_SP, @@ -1551,7 +1556,7 @@ impl<'a> Resolver<'a> { self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { match scope { - Scope::Module(module, _) => { + Scope::Module(module) => { this.traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { @@ -1613,10 +1618,12 @@ impl<'a> Resolver<'a> { ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { - let id = self.local_def_id(import.id); - self.maybe_unused_trait_imports.insert(id); + if let Some(node_id) = import.id() { + let def_id = self.local_def_id(node_id); + self.maybe_unused_trait_imports.insert(def_id); + import_ids.push(def_id); + } self.add_to_glob_map(&import, trait_name); - import_ids.push(id); kind = &binding.kind; } import_ids @@ -1683,7 +1690,9 @@ impl<'a> Resolver<'a> { } used.set(true); import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } self.add_to_glob_map(&import, ident); self.record_use(ident, binding, false); } @@ -1691,8 +1700,8 @@ impl<'a> Resolver<'a> { #[inline] fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { - if import.is_glob() { - let def_id = self.local_def_id(import.id); + if let ImportKind::Glob { id, .. } = import.kind { + let def_id = self.local_def_id(id); self.glob_map.entry(def_id).or_default().insert(ident.name); } } @@ -1994,11 +2003,7 @@ impl<'a> Resolver<'a> { // Items that go to reexport table encoded to metadata and visible through it to other crates. fn is_reexport(&self, binding: &NameBinding<'a>) -> Option> { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { + if binding.is_import() { let res = binding.res().expect_non_local(); // Ambiguous imports are treated as errors at this point and are // not exposed to other crates (see #36837 for more details). diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 28136cc48d6..cd8c8c463b1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -362,7 +362,7 @@ impl Class { match self { Class::Comment => "comment", Class::DocComment => "doccomment", - Class::Attribute => "attribute", + Class::Attribute => "attr", Class::KeyWord => "kw", Class::RefKeyWord => "kw-2", Class::Self_(_) => "self", diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index 4a5a3cf609c..fced2eacd9e 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -3,16 +3,16 @@ .kw { color: #8959A8; } .kw-2, .prelude-ty { color: #4271AE; } .number, .string { color: #718C00; } -.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; } +.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; } .macro, .macro-nonterminal { color: #3E999F; } .lifetime { color: #B76514; } .question-mark { color: #ff9011; } -
#![crate_type = "lib"]
+
#![crate_type = "lib"]
 
 use std::path::{Path, PathBuf};
 
-#[cfg(target_os = "linux")]
+#[cfg(target_os = "linux")]
 #[cfg(target_os = "windows")]
 fn main() -> () {
     let foo = true && false || true;
@@ -23,7 +23,7 @@
     mac!(foo, &mut bar);
     assert!(self.length < N && index <= self.length);
     ::std::env::var("gateau").is_ok();
-    #[rustfmt::skip]
+    #[rustfmt::skip]
     let s:std::path::PathBuf = std::path::PathBuf::new();
     let mut s = String::new();
 
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index a5e633df434..2c93b9a097f 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -9,7 +9,7 @@ const STYLE: &str = r#"
 .kw { color: #8959A8; }
 .kw-2, .prelude-ty { color: #4271AE; }
 .number, .string { color: #718C00; }
-.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; }
+.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; }
 .macro, .macro-nonterminal { color: #3E999F; }
 .lifetime { color: #B76514; }
 .question-mark { color: #ff9011; }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 30dc8450924..219d1b4ed53 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -880,8 +880,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 
 .search-results.active {
 	display: block;
-	/* prevent overhanging tabs from moving the first result */
-	clear: both;
 }
 
 .search-results .desc > span {
@@ -1092,7 +1090,7 @@ pre.rust .bool-val {
 pre.rust .self {
 	color: var(--code-highlight-self-color);
 }
-pre.rust .attribute {
+pre.rust .attr {
 	color: var(--code-highlight-attribute-color);
 }
 pre.rust .macro,
diff --git a/src/test/rustdoc-gui/highlight-colors.goml b/src/test/rustdoc-gui/highlight-colors.goml
index 51693314e85..ff1be389dcb 100644
--- a/src/test/rustdoc-gui/highlight-colors.goml
+++ b/src/test/rustdoc-gui/highlight-colors.goml
@@ -15,7 +15,7 @@ define-function: (
         string,
         bool_val,
         self,
-        attribute,
+        attr,
         macro,
         question_mark,
         comment,
@@ -33,7 +33,7 @@ define-function: (
         ("assert-css", ("pre.rust .string", {"color": |string|}, ALL)),
         ("assert-css", ("pre.rust .bool-val", {"color": |bool_val|}, ALL)),
         ("assert-css", ("pre.rust .self", {"color": |self|}, ALL)),
-        ("assert-css", ("pre.rust .attribute", {"color": |attribute|}, ALL)),
+        ("assert-css", ("pre.rust .attr", {"color": |attr|}, ALL)),
         ("assert-css", ("pre.rust .macro", {"color": |macro|}, ALL)),
         ("assert-css", ("pre.rust .question-mark", {"color": |question_mark|}, ALL)),
         ("assert-css", ("pre.rust .comment", {"color": |comment|}, ALL)),
@@ -52,7 +52,7 @@ call-function: ("check-colors", {
     "string": "rgb(184, 204, 82)",
     "bool_val": "rgb(255, 119, 51)",
     "self": "rgb(54, 163, 217)",
-    "attribute": "rgb(230, 225, 207)",
+    "attr": "rgb(230, 225, 207)",
     "macro": "rgb(163, 122, 204)",
     "question_mark": "rgb(255, 144, 17)",
     "comment": "rgb(120, 135, 151)",
@@ -69,7 +69,7 @@ call-function: ("check-colors", {
     "string": "rgb(131, 163, 0)",
     "bool_val": "rgb(238, 104, 104)",
     "self": "rgb(238, 104, 104)",
-    "attribute": "rgb(238, 104, 104)",
+    "attr": "rgb(238, 104, 104)",
     "macro": "rgb(62, 153, 159)",
     "question_mark": "rgb(255, 144, 17)",
     "comment": "rgb(141, 141, 139)",
@@ -86,7 +86,7 @@ call-function: ("check-colors", {
     "string": "rgb(113, 140, 0)",
     "bool_val": "rgb(200, 40, 41)",
     "self": "rgb(200, 40, 41)",
-    "attribute": "rgb(200, 40, 41)",
+    "attr": "rgb(200, 40, 41)",
     "macro": "rgb(62, 153, 159)",
     "question_mark": "rgb(255, 144, 17)",
     "comment": "rgb(142, 144, 140)",
diff --git a/src/test/rustdoc/issue-41783.codeblock.html b/src/test/rustdoc/issue-41783.codeblock.html
index 89987491d1b..3bca4536cd5 100644
--- a/src/test/rustdoc/issue-41783.codeblock.html
+++ b/src/test/rustdoc/issue-41783.codeblock.html
@@ -1,5 +1,5 @@
 # single
 ## double
 ### triple
-#[outer]
+#[outer]
 #![inner]
diff --git a/src/test/rustdoc/issue-41783.rs b/src/test/rustdoc/issue-41783.rs
index 87267a750c6..769f984a274 100644
--- a/src/test/rustdoc/issue-41783.rs
+++ b/src/test/rustdoc/issue-41783.rs
@@ -1,10 +1,10 @@
 // @has issue_41783/struct.Foo.html
 // @!hasraw - 'space'
 // @!hasraw - 'comment'
-// @hasraw - '#[outer]'
-// @!hasraw - '#[outer]'
+// @hasraw - '#[outer]'
+// @!hasraw - '#[outer]'
 // @hasraw - '#![inner]'
-// @!hasraw - '#![inner]'
+// @!hasraw - '#![inner]'
 // @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
 
 /// ```no_run
diff --git a/src/test/ui/macros/issue-38715.rs b/src/test/ui/macros/issue-38715.rs
index 9a9a501cae1..85ed97663e8 100644
--- a/src/test/ui/macros/issue-38715.rs
+++ b/src/test/ui/macros/issue-38715.rs
@@ -1,7 +1,17 @@
 #[macro_export]
-macro_rules! foo { ($i:ident) => {} }
+macro_rules! foo { () => {} }
 
 #[macro_export]
 macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
 
+mod inner1 {
+    #[macro_export]
+    macro_rules! bar { () => {} }
+}
+
+mod inner2 {
+    #[macro_export]
+    macro_rules! bar { () => {} } //~ ERROR the name `bar` is defined multiple times
+}
+
 fn main() {}
diff --git a/src/test/ui/macros/issue-38715.stderr b/src/test/ui/macros/issue-38715.stderr
index c87d9f7360b..828a7f45930 100644
--- a/src/test/ui/macros/issue-38715.stderr
+++ b/src/test/ui/macros/issue-38715.stderr
@@ -1,7 +1,7 @@
 error[E0428]: the name `foo` is defined multiple times
   --> $DIR/issue-38715.rs:5:1
    |
-LL | macro_rules! foo { ($i:ident) => {} }
+LL | macro_rules! foo { () => {} }
    | ---------------- previous definition of the macro `foo` here
 ...
 LL | macro_rules! foo { () => {} }
@@ -9,6 +9,17 @@ LL | macro_rules! foo { () => {} }
    |
    = note: `foo` must be defined only once in the macro namespace of this module
 
-error: aborting due to previous error
+error[E0428]: the name `bar` is defined multiple times
+  --> $DIR/issue-38715.rs:14:5
+   |
+LL |     macro_rules! bar { () => {} }
+   |     ---------------- previous definition of the macro `bar` here
+...
+LL |     macro_rules! bar { () => {} }
+   |     ^^^^^^^^^^^^^^^^ `bar` redefined here
+   |
+   = note: `bar` must be defined only once in the macro namespace of this module
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui/privacy/effective_visibilities.rs b/src/test/ui/privacy/effective_visibilities.rs
index 1d806a1d1d1..c1f9ee8dfdf 100644
--- a/src/test/ui/privacy/effective_visibilities.rs
+++ b/src/test/ui/privacy/effective_visibilities.rs
@@ -38,13 +38,13 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
     }
 
     #[rustc_effective_visibility]
-    macro_rules! none_macro { //~ Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+    macro_rules! none_macro { //~ ERROR not in the table
         () => {};
     }
 
     #[macro_export]
     #[rustc_effective_visibility]
-    macro_rules! public_macro { //~ Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+    macro_rules! public_macro { //~ ERROR Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
         () => {};
     }
 
diff --git a/src/test/ui/privacy/effective_visibilities.stderr b/src/test/ui/privacy/effective_visibilities.stderr
index 1c6201600b6..5a8f7db38fc 100644
--- a/src/test/ui/privacy/effective_visibilities.stderr
+++ b/src/test/ui/privacy/effective_visibilities.stderr
@@ -64,13 +64,13 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |                 PubUnion,
    |                 ^^^^^^^^
 
-error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+error: not in the table
   --> $DIR/effective_visibilities.rs:41:5
    |
 LL |     macro_rules! none_macro {
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
   --> $DIR/effective_visibilities.rs:47:5
    |
 LL |     macro_rules! public_macro {
diff --git a/src/test/ui/proc-macro/generate-mod.rs b/src/test/ui/proc-macro/generate-mod.rs
index 471f317edf9..9eea630c310 100644
--- a/src/test/ui/proc-macro/generate-mod.rs
+++ b/src/test/ui/proc-macro/generate-mod.rs
@@ -15,19 +15,16 @@ struct S;
 
 #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
                                      //~| ERROR cannot find type `OuterDerive` in this scope
-                                     //~| WARN this was previously accepted
-                                     //~| WARN this was previously accepted
 struct Z;
 
 fn inner_block() {
     #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
                                         //~| ERROR cannot find type `OuterDerive` in this scope
-                                        //~| WARN this was previously accepted
-                                        //~| WARN this was previously accepted
     struct InnerZ;
 }
 
-#[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+#[derive(generate_mod::CheckDeriveLint)] //~  ERROR cannot find type `OuterDeriveLint` in this scope
+                                         //~| ERROR cannot find type `FromOutside` in this scope
 struct W;
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr
index 39bf28dba96..64042ca0ecd 100644
--- a/src/test/ui/proc-macro/generate-mod.stderr
+++ b/src/test/ui/proc-macro/generate-mod.stderr
@@ -38,127 +38,66 @@ LL | #[generate_mod::check_attr]
            OuterAttr
    = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: cannot find type `FromOutside` in this scope
+error[E0412]: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: consider importing this struct:
+           FromOutside
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: cannot find type `OuterDerive` in this scope
+error[E0412]: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
+   = note: consider importing this struct:
+           OuterDerive
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:23:14
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:21:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
+   = note: consider importing this struct:
+           FromOutside
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: cannot find type `OuterDerive` in this scope
-  --> $DIR/generate-mod.rs:23:14
+error[E0412]: cannot find type `OuterDerive` in this scope
+  --> $DIR/generate-mod.rs:21:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
+   = note: consider importing this struct:
+           OuterDerive
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:26:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: consider importing this struct:
+           FromOutside
+   = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0412]: cannot find type `OuterDeriveLint` in this scope
+  --> $DIR/generate-mod.rs:26:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: consider importing this struct:
+           OuterDeriveLint
+   = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
-Future incompatibility report: Future breakage diagnostic:
-error: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:16:10
-   |
-LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
-   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: cannot find type `OuterDerive` in this scope
-  --> $DIR/generate-mod.rs:16:10
-   |
-LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
-   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:23:14
-   |
-LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
-   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: cannot find type `OuterDerive` in this scope
-  --> $DIR/generate-mod.rs:23:14
-   |
-LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
-   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-note: the lint level is defined here
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-warning: cannot find type `OuterDeriveLint` in this scope
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #83583 
-note: the lint level is defined here
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
-
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 0ddea2f728d..8931c17bbdc 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -872,9 +872,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.93.1"
+version = "0.93.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734"
+checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51"
 dependencies = [
  "bitflags",
  "serde",
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index 73c3a48b4c5..8a91d606661 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -295,7 +295,9 @@ impl FlycheckActor {
             } => {
                 let mut cmd = Command::new(toolchain::cargo());
                 cmd.arg(command);
-                cmd.args(&["--workspace", "--message-format=json"]);
+                cmd.current_dir(&self.root);
+                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
+                    .arg(self.root.join("Cargo.toml").as_os_str());
 
                 if let Some(target) = target_triple {
                     cmd.args(&["--target", target.as_str()]);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 077a1b619dd..79249757d9e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -662,8 +662,12 @@ fn desugar_future_path(orig: TypeRef) -> Path {
     let mut generic_args: Vec<_> =
         std::iter::repeat(None).take(path.segments().len() - 1).collect();
     let mut last = GenericArgs::empty();
-    let binding =
-        AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
+    let binding = AssociatedTypeBinding {
+        name: name![Output],
+        args: None,
+        type_ref: Some(orig),
+        bounds: Vec::new(),
+    };
     last.bindings.push(binding);
     generic_args.push(Some(Interned::new(last)));
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 2f13a9fbf0e..592223f7d85 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -68,6 +68,9 @@ pub struct GenericArgs {
 pub struct AssociatedTypeBinding {
     /// The name of the associated type.
     pub name: Name,
+    /// The generic arguments to the associated type. e.g. For `Trait = &'a T>`, this
+    /// would be `['a, T]`.
+    pub args: Option>,
     /// The type bound to this associated type (in `Item = T`, this would be the
     /// `T`). This can be `None` if there are bounds instead.
     pub type_ref: Option,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 0428f1a398b..cfa3a6baaf8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -163,6 +163,10 @@ pub(super) fn lower_generic_args(
             ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
                 if let Some(name_ref) = assoc_type_arg.name_ref() {
                     let name = name_ref.as_name();
+                    let args = assoc_type_arg
+                        .generic_arg_list()
+                        .and_then(|args| lower_generic_args(lower_ctx, args))
+                        .map(Interned::new);
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
                         l.bounds()
@@ -171,7 +175,7 @@ pub(super) fn lower_generic_args(
                     } else {
                         Vec::new()
                     };
-                    bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
+                    bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
                 }
             }
             ast::GenericArg::LifetimeArg(lifetime_arg) => {
@@ -214,6 +218,7 @@ fn lower_generic_args_from_fn_path(
         let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
         bindings.push(AssociatedTypeBinding {
             name: name![Output],
+            args: None,
             type_ref: Some(type_ref),
             bounds: Vec::new(),
         });
@@ -222,6 +227,7 @@ fn lower_generic_args_from_fn_path(
         let type_ref = TypeRef::Tuple(Vec::new());
         bindings.push(AssociatedTypeBinding {
             name: name![Output],
+            args: None,
             type_ref: Some(type_ref),
             bounds: Vec::new(),
         });
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index e2099d7e509..996b42f5bd8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -11,9 +11,9 @@ use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
-    CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
-    Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
+    from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
+    CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
+    QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
 };
 
 pub trait TyExt {
@@ -338,10 +338,13 @@ pub trait ProjectionTyExt {
 
 impl ProjectionTyExt for ProjectionTy {
     fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
-        TraitRef {
-            trait_id: to_chalk_trait_id(self.trait_(db)),
-            substitution: self.substitution.clone(),
-        }
+        // FIXME: something like `Split` trait from chalk-solve might be nice.
+        let generics = generics(db.upcast(), from_assoc_type_id(self.associated_ty_id).into());
+        let substitution = Substitution::from_iter(
+            Interner,
+            self.substitution.iter(Interner).skip(generics.len_self()),
+        );
+        TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
     }
 
     fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 0221f922feb..5ad66132635 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -289,16 +289,18 @@ impl HirDisplay for ProjectionTy {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        let trait_ = f.db.trait_data(self.trait_(f.db));
+        let trait_ref = self.trait_ref(f.db);
         write!(f, "<")?;
-        self.self_type_parameter(f.db).hir_fmt(f)?;
-        write!(f, " as {}", trait_.name)?;
-        if self.substitution.len(Interner) > 1 {
+        fmt_trait_ref(&trait_ref, f, true)?;
+        write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
+        let proj_params_count =
+            self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
+        let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
+        if !proj_params.is_empty() {
             write!(f, "<")?;
-            f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
+            f.write_joined(proj_params, ", ")?;
             write!(f, ">")?;
         }
-        write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
         Ok(())
     }
 }
@@ -641,9 +643,12 @@ impl HirDisplay for Ty {
                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
                 if f.display_target.is_test() {
                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
+                    // Note that the generic args for the associated type come before those for the
+                    // trait (including the self type).
+                    // FIXME: reconsider the generic args order upon formatting?
                     if parameters.len(Interner) > 0 {
                         write!(f, "<")?;
-                        f.write_joined(&*parameters.as_slice(Interner), ", ")?;
+                        f.write_joined(parameters.as_slice(Interner), ", ")?;
                         write!(f, ">")?;
                     }
                 } else {
@@ -972,9 +977,20 @@ fn write_bounds_like_dyn_trait(
                     angle_open = true;
                 }
                 if let AliasTy::Projection(proj) = alias {
-                    let type_alias =
-                        f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
-                    write!(f, "{} = ", type_alias.name)?;
+                    let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
+                    let type_alias = f.db.type_alias_data(assoc_ty_id);
+                    write!(f, "{}", type_alias.name)?;
+
+                    let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
+                    if proj_arg_count > 0 {
+                        write!(f, "<")?;
+                        f.write_joined(
+                            &proj.substitution.as_slice(Interner)[..proj_arg_count],
+                            ", ",
+                        )?;
+                        write!(f, ">")?;
+                    }
+                    write!(f, " = ")?;
                 }
                 ty.hir_fmt(f)?;
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 7a4754cdc7b..ebe9d6fb5e0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -157,7 +157,7 @@ impl<'a> InferenceContext<'a> {
                     remaining_segments_for_ty,
                     true,
                 );
-                if let TyKind::Error = ty.kind(Interner) {
+                if ty.is_unknown() {
                     return None;
                 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index b00e3216b2d..12f45f00f9c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -340,8 +340,8 @@ impl<'a> InferenceTable<'a> {
         self.resolve_with_fallback(t, &|_, _, d, _| d)
     }
 
-    /// Unify two types and register new trait goals that arise from that.
-    pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
+    /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
+    pub(crate) fn unify>(&mut self, ty1: &T, ty2: &T) -> bool {
         let result = match self.try_unify(ty1, ty2) {
             Ok(r) => r,
             Err(_) => return false,
@@ -350,9 +350,13 @@ impl<'a> InferenceTable<'a> {
         true
     }
 
-    /// Unify two types and return new trait goals arising from it, so the
+    /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
     /// caller needs to deal with them.
-    pub(crate) fn try_unify>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
+    pub(crate) fn try_unify>(
+        &mut self,
+        t1: &T,
+        t2: &T,
+    ) -> InferResult<()> {
         match self.var_unification_table.relate(
             Interner,
             &self.db,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index c4b700cbce6..42c3b58d5ad 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -81,7 +81,20 @@ pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
 pub type VariableKind = chalk_ir::VariableKind;
 pub type VariableKinds = chalk_ir::VariableKinds;
 pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds;
+/// Represents generic parameters and an item bound by them. When the item has parent, the binders
+/// also contain the generic parameters for its parent. See chalk's documentation for details.
+///
+/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
+/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
+/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
+/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
+/// motivation in detail.
 pub type Binders = chalk_ir::Binders;
+/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
+/// it contains generic arguments for both its parent and itself. See chalk's documentation for
+/// details.
+///
+/// See `Binders` for the constraint on the ordering.
 pub type Substitution = chalk_ir::Substitution;
 pub type GenericArg = chalk_ir::GenericArg;
 pub type GenericArgData = chalk_ir::GenericArgData;
@@ -124,14 +137,6 @@ pub type ConstrainedSubst = chalk_ir::ConstrainedSubst;
 pub type Guidance = chalk_solve::Guidance;
 pub type WhereClause = chalk_ir::WhereClause;
 
-// FIXME: get rid of this
-pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
-    Substitution::from_iter(
-        Interner,
-        s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(),
-    )
-}
-
 /// Return an index of a parameter in the generic type parameter list by it's id.
 pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option {
     generics(db.upcast(), id.parent).param_idx(id)
@@ -382,7 +387,6 @@ pub(crate) fn fold_tys_and_consts + TypeFold
 pub fn replace_errors_with_variables(t: &T) -> Canonical
 where
     T: HasInterner + TypeFoldable + Clone,
-    T: HasInterner,
 {
     use chalk_ir::{
         fold::{FallibleTypeFolder, TypeSuperFoldable},
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 223d705b157..22a85cf1545 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -447,12 +447,31 @@ impl<'a> TyLoweringContext<'a> {
                             .db
                             .trait_data(trait_ref.hir_trait_id())
                             .associated_type_by_name(segment.name);
+
                         match found {
                             Some(associated_ty) => {
-                                // FIXME handle type parameters on the segment
+                                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                                // that method to optionally take parent `Substitution` as we already know them at
+                                // this point (`trait_ref.substitution`).
+                                let substitution = self.substs_from_path_segment(
+                                    segment,
+                                    Some(associated_ty.into()),
+                                    false,
+                                    None,
+                                );
+                                let len_self =
+                                    generics(self.db.upcast(), associated_ty.into()).len_self();
+                                let substitution = Substitution::from_iter(
+                                    Interner,
+                                    substitution
+                                        .iter(Interner)
+                                        .take(len_self)
+                                        .chain(trait_ref.substitution.iter(Interner)),
+                                );
                                 TyKind::Alias(AliasTy::Projection(ProjectionTy {
                                     associated_ty_id: to_assoc_type_id(associated_ty),
-                                    substitution: trait_ref.substitution,
+                                    substitution,
                                 }))
                                 .intern(Interner)
                             }
@@ -590,36 +609,48 @@ impl<'a> TyLoweringContext<'a> {
             res,
             Some(segment.name.clone()),
             move |name, t, associated_ty| {
-                if name == segment.name {
-                    let substs = match self.type_param_mode {
-                        ParamLoweringMode::Placeholder => {
-                            // if we're lowering to placeholders, we have to put
-                            // them in now
-                            let generics = generics(
-                                self.db.upcast(),
-                                self.resolver
-                                    .generic_def()
-                                    .expect("there should be generics if there's a generic param"),
-                            );
-                            let s = generics.placeholder_subst(self.db);
-                            s.apply(t.substitution.clone(), Interner)
-                        }
-                        ParamLoweringMode::Variable => t.substitution.clone(),
-                    };
-                    // We need to shift in the bound vars, since
-                    // associated_type_shorthand_candidates does not do that
-                    let substs = substs.shifted_in_from(Interner, self.in_binders);
-                    // FIXME handle type parameters on the segment
-                    Some(
-                        TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                            associated_ty_id: to_assoc_type_id(associated_ty),
-                            substitution: substs,
-                        }))
-                        .intern(Interner),
-                    )
-                } else {
-                    None
+                if name != segment.name {
+                    return None;
                 }
+
+                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                // that method to optionally take parent `Substitution` as we already know them at
+                // this point (`t.substitution`).
+                let substs = self.substs_from_path_segment(
+                    segment.clone(),
+                    Some(associated_ty.into()),
+                    false,
+                    None,
+                );
+
+                let len_self = generics(self.db.upcast(), associated_ty.into()).len_self();
+
+                let substs = Substitution::from_iter(
+                    Interner,
+                    substs.iter(Interner).take(len_self).chain(t.substitution.iter(Interner)),
+                );
+
+                let substs = match self.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        // if we're lowering to placeholders, we have to put
+                        // them in now
+                        let generics = generics(self.db.upcast(), def);
+                        let s = generics.placeholder_subst(self.db);
+                        s.apply(substs, Interner)
+                    }
+                    ParamLoweringMode::Variable => substs,
+                };
+                // We need to shift in the bound vars, since
+                // associated_type_shorthand_candidates does not do that
+                let substs = substs.shifted_in_from(Interner, self.in_binders);
+                Some(
+                    TyKind::Alias(AliasTy::Projection(ProjectionTy {
+                        associated_ty_id: to_assoc_type_id(associated_ty),
+                        substitution: substs,
+                    }))
+                    .intern(Interner),
+                )
             },
         );
 
@@ -777,7 +808,15 @@ impl<'a> TyLoweringContext<'a> {
         // handle defaults. In expression or pattern path segments without
         // explicitly specified type arguments, missing type arguments are inferred
         // (i.e. defaults aren't used).
-        if !infer_args || had_explicit_args {
+        // Generic parameters for associated types are not supposed to have defaults, so we just
+        // ignore them.
+        let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
+            let container = id.lookup(self.db.upcast()).container;
+            matches!(container, ItemContainerId::TraitId(_))
+        } else {
+            false
+        };
+        if !is_assoc_ty && (!infer_args || had_explicit_args) {
             let defaults = self.db.generic_defaults(def);
             assert_eq!(total_len, defaults.len());
             let parent_from = item_len - substs.len();
@@ -966,9 +1005,28 @@ impl<'a> TyLoweringContext<'a> {
                     None => return SmallVec::new(),
                     Some(t) => t,
                 };
+                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                // that method to optionally take parent `Substitution` as we already know them at
+                // this point (`super_trait_ref.substitution`).
+                let substitution = self.substs_from_path_segment(
+                    // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
+                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+                    Some(associated_ty.into()),
+                    false, // this is not relevant
+                    Some(super_trait_ref.self_type_parameter(Interner)),
+                );
+                let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
+                let substitution = Substitution::from_iter(
+                    Interner,
+                    substitution
+                        .iter(Interner)
+                        .take(self_params)
+                        .chain(super_trait_ref.substitution.iter(Interner)),
+                );
                 let projection_ty = ProjectionTy {
                     associated_ty_id: to_assoc_type_id(associated_ty),
-                    substitution: super_trait_ref.substitution,
+                    substitution,
                 };
                 let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 3a1a3f4fdeb..50859475e1d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -22,10 +22,10 @@ use crate::{
     from_foreign_def_id,
     infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
     primitive::{FloatTy, IntTy, UintTy},
-    static_lifetime,
+    static_lifetime, to_chalk_trait_id,
     utils::all_super_traits,
     AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
-    Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+    Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
 };
 
 /// This is used as a key for indexing impls.
@@ -624,52 +624,76 @@ pub(crate) fn iterate_method_candidates(
     slot
 }
 
+/// Looks up the impl method that actually runs for the trait method `func`.
+///
+/// Returns `func` if it's not a method defined in a trait or the lookup failed.
 pub fn lookup_impl_method(
-    self_ty: &Ty,
     db: &dyn HirDatabase,
     env: Arc,
-    trait_: TraitId,
+    func: FunctionId,
+    fn_subst: Substitution,
+) -> FunctionId {
+    let trait_id = match func.lookup(db.upcast()).container {
+        ItemContainerId::TraitId(id) => id,
+        _ => return func,
+    };
+    let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+    let fn_params = fn_subst.len(Interner) - trait_params;
+    let trait_ref = TraitRef {
+        trait_id: to_chalk_trait_id(trait_id),
+        substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)),
+    };
+
+    let name = &db.function_data(func).name;
+    lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
+}
+
+fn lookup_impl_method_for_trait_ref(
+    trait_ref: TraitRef,
+    db: &dyn HirDatabase,
+    env: Arc,
     name: &Name,
 ) -> Option {
-    let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
-    let trait_impls = db.trait_impls_in_deps(env.krate);
-    let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
-    let mut table = InferenceTable::new(db, env.clone());
-    find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
-        data.items.iter().find_map(|it| match it {
-            AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
-            _ => None,
-        })
+    let self_ty = trait_ref.self_type_parameter(Interner);
+    let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
+    let impls = db.trait_impls_in_deps(env.krate);
+    let impls = impls.for_trait_and_self_ty(trait_ref.hir_trait_id(), self_ty_fp);
+
+    let table = InferenceTable::new(db, env);
+
+    let impl_data = find_matching_impl(impls, table, trait_ref)?;
+    impl_data.items.iter().find_map(|it| match it {
+        AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
+        _ => None,
     })
 }
 
 fn find_matching_impl(
     mut impls: impl Iterator,
-    table: &mut InferenceTable<'_>,
-    self_ty: &Ty,
+    mut table: InferenceTable<'_>,
+    actual_trait_ref: TraitRef,
 ) -> Option> {
     let db = table.db;
     loop {
         let impl_ = impls.next()?;
         let r = table.run_in_snapshot(|table| {
             let impl_data = db.impl_data(impl_);
-            let substs =
+            let impl_substs =
                 TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
-            let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
+            let trait_ref = db
+                .impl_trait(impl_)
+                .expect("non-trait method in find_matching_impl")
+                .substitute(Interner, &impl_substs);
 
-            table
-                .unify(self_ty, &impl_ty)
-                .then(|| {
-                    let wh_goals =
-                        crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
-                            .into_iter()
-                            .map(|b| b.cast(Interner));
+            if !table.unify(&trait_ref, &actual_trait_ref) {
+                return None;
+            }
 
-                    let goal = crate::Goal::all(Interner, wh_goals);
-
-                    table.try_obligation(goal).map(|_| impl_data)
-                })
-                .flatten()
+            let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs)
+                .into_iter()
+                .map(|b| b.cast(Interner));
+            let goal = crate::Goal::all(Interner, wcs);
+            table.try_obligation(goal).map(|_| impl_data)
         });
         if r.is_some() {
             break r;
@@ -1214,7 +1238,7 @@ fn is_valid_fn_candidate(
             let expected_receiver =
                 sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
 
-            check_that!(table.unify(&receiver_ty, &expected_receiver));
+            check_that!(table.unify(receiver_ty, &expected_receiver));
         }
 
         if let ItemContainerId::ImplId(impl_id) = container {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index 8a8ff08cfe8..425432479e8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -196,3 +196,34 @@ fn test(
 "#,
     );
 }
+
+#[test]
+fn projection_type_correct_arguments_order() {
+    check_types_source_code(
+        r#"
+trait Foo {
+    type Assoc;
+}
+fn f>(a: T::Assoc) {
+    a;
+  //^ >::Assoc
+}
+"#,
+    );
+}
+
+#[test]
+fn generic_associated_type_binding_in_impl_trait() {
+    check_types_source_code(
+        r#"
+//- minicore: sized
+trait Foo {
+    type Assoc;
+}
+fn f(a: impl Foo = i32>) {
+    a;
+  //^ impl Foo = i32>
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 555b6972fb7..7d42b8b9bc8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -3963,3 +3963,124 @@ fn g(t: &(dyn T + Send)) {
         "#,
     );
 }
+
+#[test]
+fn gats_in_path() {
+    check_types(
+        r#"
+//- minicore: deref
+use core::ops::Deref;
+trait PointerFamily {
+    type Pointer: Deref;
+}
+
+fn f(p: P::Pointer) {
+    let a = *p;
+      //^ i32
+}
+fn g(p: 

::Pointer) { + let a = *p; + //^ i32 +} + "#, + ); +} + +#[test] +fn gats_with_impl_trait() { + // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot + // specify the same associated type multiple times even if their arguments are different (c.f. + // `fn h()`, which is valid). Reconsider how to treat these invalid types. + check_types( + r#" +//- minicore: deref +use core::ops::Deref; + +trait Trait { + type Assoc: Deref; + fn get(&self) -> Self::Assoc; +} + +fn f(v: impl Trait) { + let a = v.get::().deref(); + //^ &i32 + let a = v.get::().deref(); + //^ &T +} +fn g<'a, T: 'a>(v: impl Trait = &'a T>) { + let a = v.get::(); + //^ &T + let a = v.get::<()>(); + //^ Trait::Assoc<(), impl Trait = &T>> +} +fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { + let a = v.get::(); + //^ &i32 + let a = v.get::(); + //^ &i64 +} +fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { + let a = v.get::(); + //^ &i32 + let a = v.get::(); + //^ &i64 +} + "#, + ); +} + +#[test] +fn gats_with_dyn() { + // This test is here to keep track of how we infer things despite traits with GATs being not + // object-safe currently. + // FIXME: reconsider how to treat these invalid types. + check_infer_with_mismatches( + r#" +//- minicore: deref +use core::ops::Deref; + +trait Trait { + type Assoc: Deref; + fn get(&self) -> Self::Assoc; +} + +fn f<'a>(v: &dyn Trait = &'a i32>) { + v.get::().deref(); +} + "#, + expect![[r#" + 90..94 'self': &Self + 127..128 'v': &(dyn Trait = &i32>) + 164..195 '{ ...f(); }': () + 170..171 'v': &(dyn Trait = &i32>) + 170..184 'v.get::()': &i32 + 170..192 'v.get:...eref()': &i32 + "#]], + ); +} + +#[test] +fn gats_in_associated_type_binding() { + check_types( + r#" +trait Trait { + type Assoc; + fn get(&self) -> Self::Assoc; +} + +fn f(t: T) +where + T: Trait = u32>, + T: Trait = usize>, +{ + let a = t.get::(); + //^ u32 + let a = t.get::(); + //^ usize + let a = t.get::<()>(); + //^ Trait::Assoc<(), T> +} + + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs index 547850b021c..92711a24fe3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use crate::{ chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk, - CallableDefId, Interner, + CallableDefId, Interner, ProjectionTyExt, }; use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId}; @@ -63,17 +63,31 @@ impl DebugContext<'_> { ItemContainerId::TraitId(t) => t, _ => panic!("associated type not in trait"), }; - let trait_data = self.0.trait_data(trait_); - let params = projection_ty.substitution.as_slice(Interner); - write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?; - if params.len() > 1 { + let trait_name = &self.0.trait_data(trait_).name; + let trait_ref = projection_ty.trait_ref(self.0); + let trait_params = trait_ref.substitution.as_slice(Interner); + let self_ty = trait_ref.self_type_parameter(Interner); + write!(fmt, "<{:?} as {}", self_ty, trait_name)?; + if trait_params.len() > 1 { write!( fmt, "<{}>", - ¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), + trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), )?; } - write!(fmt, ">::{}", type_alias_data.name) + write!(fmt, ">::{}", type_alias_data.name)?; + + let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len(); + let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count]; + if !proj_params.is_empty() { + write!( + fmt, + "<{}>", + proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), + )?; + } + + Ok(()) } pub(crate) fn debug_fn_def_id( diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 07bae2b38c7..f86c5710053 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -270,7 +270,7 @@ impl SourceAnalyzer { let expr_id = self.expr_id(db, &call.clone().into())?; let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; - Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)) } pub(crate) fn resolve_await_to_poll( @@ -311,7 +311,7 @@ impl SourceAnalyzer { // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself // doesn't have any generic parameters, so we skip building another subst for `poll()`. let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build(); - Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs)) } pub(crate) fn resolve_prefix_expr( @@ -331,7 +331,7 @@ impl SourceAnalyzer { // don't have any generic parameters, so we skip building another subst for the methods. let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); - Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } pub(crate) fn resolve_index_expr( @@ -351,7 +351,7 @@ impl SourceAnalyzer { .push(base_ty.clone()) .push(index_ty.clone()) .build(); - Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } pub(crate) fn resolve_bin_expr( @@ -372,7 +372,7 @@ impl SourceAnalyzer { .push(rhs.clone()) .build(); - Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } pub(crate) fn resolve_try_expr( @@ -392,7 +392,7 @@ impl SourceAnalyzer { // doesn't have any generic parameters, so we skip building another subst for `branch()`. let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); - Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } pub(crate) fn resolve_field( @@ -487,9 +487,9 @@ impl SourceAnalyzer { let mut prefer_value_ns = false; let resolved = (|| { + let infer = self.infer.as_deref()?; if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) { let expr_id = self.expr_id(db, &path_expr.into())?; - let infer = self.infer.as_ref()?; if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) { let assoc = match assoc { AssocItemId::FunctionId(f_in_trait) => { @@ -497,9 +497,12 @@ impl SourceAnalyzer { None => assoc, Some(func_ty) => { if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) { - self.resolve_impl_method(db, f_in_trait, subs) - .map(AssocItemId::FunctionId) - .unwrap_or(assoc) + self.resolve_impl_method_or_trait_def( + db, + f_in_trait, + subs.clone(), + ) + .into() } else { assoc } @@ -520,18 +523,18 @@ impl SourceAnalyzer { prefer_value_ns = true; } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) { let pat_id = self.pat_id(&path_pat.into())?; - if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { + if let Some(assoc) = infer.assoc_resolutions_for_pat(pat_id) { return Some(PathResolution::Def(AssocItem::from(assoc).into())); } if let Some(VariantId::EnumVariantId(variant)) = - self.infer.as_ref()?.variant_resolution_for_pat(pat_id) + infer.variant_resolution_for_pat(pat_id) { return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); } } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) { let expr_id = self.expr_id(db, &rec_lit.into())?; if let Some(VariantId::EnumVariantId(variant)) = - self.infer.as_ref()?.variant_resolution_for_expr(expr_id) + infer.variant_resolution_for_expr(expr_id) { return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); } @@ -541,8 +544,7 @@ impl SourceAnalyzer { || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from); if let Some(pat) = record_pat.or_else(tuple_struct_pat) { let pat_id = self.pat_id(&pat)?; - let variant_res_for_pat = - self.infer.as_ref()?.variant_resolution_for_pat(pat_id); + let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id); if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat { return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); } @@ -780,37 +782,22 @@ impl SourceAnalyzer { false } - fn resolve_impl_method( - &self, - db: &dyn HirDatabase, - func: FunctionId, - substs: &Substitution, - ) -> Option { - let impled_trait = match func.lookup(db.upcast()).container { - ItemContainerId::TraitId(trait_id) => trait_id, - _ => return None, - }; - if substs.is_empty(Interner) { - return None; - } - let self_ty = substs.at(Interner, 0).ty(Interner)?; - let krate = self.resolver.krate(); - let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); - - let fun_data = db.function_data(func); - method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name) - } - fn resolve_impl_method_or_trait_def( &self, db: &dyn HirDatabase, func: FunctionId, - substs: &Substitution, + substs: Substitution, ) -> FunctionId { - self.resolve_impl_method(db, func, substs).unwrap_or(func) + let krate = self.resolver.krate(); + let owner = match self.resolver.body_owner() { + Some(it) => it, + None => return func, + }; + let env = owner.as_generic_def_id().map_or_else( + || Arc::new(hir_ty::TraitEnvironment::empty(krate)), + |d| db.trait_environment(d), + ); + method_resolution::lookup_impl_method(db, env, func, substs) } fn lang_trait_fn( diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index d0be1b3f404..f97c67b144a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -1834,4 +1834,86 @@ fn f() { "#, ); } + + #[test] + fn goto_bin_op_multiple_impl() { + check( + r#" +//- minicore: add +struct S; +impl core::ops::Add for S { + fn add( + //^^^ + ) {} +} +impl core::ops::Add for S { + fn add( + ) {} +} + +fn f() { + S +$0 S +} +"#, + ); + + check( + r#" +//- minicore: add +struct S; +impl core::ops::Add for S { + fn add( + ) {} +} +impl core::ops::Add for S { + fn add( + //^^^ + ) {} +} + +fn f() { + S +$0 0usize +} +"#, + ); + } + + #[test] + fn path_call_multiple_trait_impl() { + check( + r#" +trait Trait { + fn f(_: T); +} +impl Trait for usize { + fn f(_: i32) {} + //^ +} +impl Trait for usize { + fn f(_: i64) {} +} +fn main() { + usize::f$0(0i32); +} +"#, + ); + + check( + r#" +trait Trait { + fn f(_: T); +} +impl Trait for usize { + fn f(_: i32) {} +} +impl Trait for usize { + fn f(_: i64) {} + //^ +} +fn main() { + usize::f$0(0i64); +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 5445028536c..7ae5324ab05 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -23,7 +23,7 @@ crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.5" scip = "0.1.1" -lsp-types = { version = "0.93.1", features = ["proposed"] } +lsp-types = { version = "=0.93.2", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.3.0" oorandom = "11.1.3" diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index eabfcf1944d..7bf595d2a45 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -11,7 +11,7 @@ use std::{env, fs, path::Path, process}; use lsp_server::Connection; use project_model::ProjectManifest; -use rust_analyzer::{cli::flags, config::Config, from_json, lsp_ext::supports_utf8, Result}; +use rust_analyzer::{cli::flags, config::Config, from_json, Result}; use vfs::AbsPathBuf; #[cfg(all(feature = "mimalloc"))] @@ -191,11 +191,7 @@ fn run_server() -> Result<()> { name: String::from("rust-analyzer"), version: Some(rust_analyzer::version().to_string()), }), - offset_encoding: if supports_utf8(config.caps()) { - Some("utf-8".to_string()) - } else { - None - }, + offset_encoding: None, }; let initialize_result = serde_json::to_value(initialize_result).unwrap(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs index cda95cd8626..723b888d9ab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs @@ -6,19 +6,25 @@ use lsp_types::{ FileOperationFilter, FileOperationPattern, FileOperationPatternKind, FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability, ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf, - RenameOptions, SaveOptions, SelectionRangeProviderCapability, SemanticTokensFullOptions, - SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, - TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, - TypeDefinitionProviderCapability, WorkDoneProgressOptions, + PositionEncodingKind, RenameOptions, SaveOptions, SelectionRangeProviderCapability, + SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, + SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, + TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities, WorkspaceServerCapabilities, }; use serde_json::json; use crate::config::{Config, RustfmtConfig}; +use crate::lsp_ext::supports_utf8; use crate::semantic_tokens; pub fn server_capabilities(config: &Config) -> ServerCapabilities { ServerCapabilities { + position_encoding: if supports_utf8(config.caps()) { + Some(PositionEncodingKind::UTF8) + } else { + None + }, text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { open_close: Some(true), change: Some(TextDocumentSyncKind::INCREMENTAL), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index 748306ea57d..5ff347b9bd7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -20,7 +20,7 @@ use crate::cli::{ load_cargo::{load_workspace, LoadCargoConfig}, Result, }; -use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; +use crate::line_index::{LineEndings, LineIndex, PositionEncoding}; use crate::to_proto; use crate::version::version; @@ -126,7 +126,7 @@ impl LsifManager<'_> { let line_index = self.db.line_index(file_id); let line_index = LineIndex { index: line_index, - encoding: OffsetEncoding::Utf16, + encoding: PositionEncoding::Utf16, endings: LineEndings::Unix, }; let range_id = self.add_vertex(lsif::Vertex::Range { @@ -248,7 +248,7 @@ impl LsifManager<'_> { let line_index = self.db.line_index(file_id); let line_index = LineIndex { index: line_index, - encoding: OffsetEncoding::Utf16, + encoding: PositionEncoding::Utf16, endings: LineEndings::Unix, }; let result = folds diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 8b77ccde0ee..16298862b50 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -5,7 +5,7 @@ use std::{ time::Instant, }; -use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; +use crate::line_index::{LineEndings, LineIndex, PositionEncoding}; use hir::Name; use ide::{ LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId, @@ -91,7 +91,7 @@ impl flags::Scip { let line_index = LineIndex { index: db.line_index(file_id), - encoding: OffsetEncoding::Utf8, + encoding: PositionEncoding::Utf8, endings: LineEndings::Unix, }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 85322f12a83..1ed8f2bb5f3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -32,7 +32,7 @@ use vfs::AbsPathBuf; use crate::{ caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig, - line_index::OffsetEncoding, + line_index::PositionEncoding, lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope}, }; @@ -948,11 +948,11 @@ impl Config { .is_some() } - pub fn offset_encoding(&self) -> OffsetEncoding { + pub fn position_encoding(&self) -> PositionEncoding { if supports_utf8(&self.caps) { - OffsetEncoding::Utf8 + PositionEncoding::Utf8 } else { - OffsetEncoding::Utf16 + PositionEncoding::Utf16 } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs index 74689fd8757..189ac2fbf53 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -8,7 +8,7 @@ use stdx::format_to; use vfs::{AbsPath, AbsPathBuf}; use crate::{ - global_state::GlobalStateSnapshot, line_index::OffsetEncoding, lsp_ext, + global_state::GlobalStateSnapshot, line_index::PositionEncoding, lsp_ext, to_proto::url_from_abs_path, }; @@ -66,17 +66,17 @@ fn location( let uri = url_from_abs_path(&file_name); let range = { - let offset_encoding = snap.config.offset_encoding(); + let position_encoding = snap.config.position_encoding(); lsp_types::Range::new( - position(&offset_encoding, span, span.line_start, span.column_start), - position(&offset_encoding, span, span.line_end, span.column_end), + position(&position_encoding, span, span.line_start, span.column_start), + position(&position_encoding, span, span.line_end, span.column_end), ) }; lsp_types::Location::new(uri, range) } fn position( - offset_encoding: &OffsetEncoding, + position_encoding: &PositionEncoding, span: &DiagnosticSpan, line_offset: usize, column_offset: usize, @@ -93,9 +93,9 @@ fn position( }; } let mut char_offset = 0; - let len_func = match offset_encoding { - OffsetEncoding::Utf8 => char::len_utf8, - OffsetEncoding::Utf16 => char::len_utf16, + let len_func = match position_encoding { + PositionEncoding::Utf8 => char::len_utf8, + PositionEncoding::Utf16 => char::len_utf16, }; for c in line.text.chars() { char_offset += 1; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs index f2db9a27334..936957bab48 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs @@ -8,7 +8,7 @@ use vfs::AbsPathBuf; use crate::{ from_json, global_state::GlobalStateSnapshot, - line_index::{LineIndex, OffsetEncoding}, + line_index::{LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, Result, @@ -25,10 +25,10 @@ pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result { pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result { let line_col = match line_index.encoding { - OffsetEncoding::Utf8 => { + PositionEncoding::Utf8 => { LineCol { line: position.line as u32, col: position.character as u32 } } - OffsetEncoding::Utf16 => { + PositionEncoding::Utf16 => { let line_col = LineColUtf16 { line: position.line as u32, col: position.character as u32 }; line_index.index.to_utf8(line_col) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 3fb06c31f7c..74277ff2e57 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -383,7 +383,7 @@ impl GlobalStateSnapshot { pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable { let endings = self.vfs.read().1[&file_id]; let index = self.analysis.file_line_index(file_id)?; - let res = LineIndex { index, endings, encoding: self.config.offset_encoding() }; + let res = LineIndex { index, endings, encoding: self.config.position_encoding() }; Ok(res) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs index c116414da01..0d424b91570 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs @@ -7,7 +7,7 @@ use std::sync::Arc; -pub enum OffsetEncoding { +pub enum PositionEncoding { Utf8, Utf16, } @@ -15,7 +15,7 @@ pub enum OffsetEncoding { pub(crate) struct LineIndex { pub(crate) index: Arc, pub(crate) endings: LineEndings, - pub(crate) encoding: OffsetEncoding, + pub(crate) encoding: PositionEncoding, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs index e61c8b643d2..8cc5648f3ce 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; +use lsp_types::PositionEncodingKind; use lsp_types::{ notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, @@ -455,7 +456,15 @@ pub(crate) enum CodeLensResolveData { } pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool { - caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8") + match &caps.general { + Some(general) => general + .position_encodings + .as_deref() + .unwrap_or_default() + .iter() + .any(|it| it == &PositionEncodingKind::UTF8), + _ => false, + } } pub enum MoveItem {} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs index b3cea64d417..c6a4db9a453 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs @@ -6,7 +6,7 @@ use lsp_server::Notification; use crate::{ from_proto, global_state::GlobalState, - line_index::{LineEndings, LineIndex, OffsetEncoding}, + line_index::{LineEndings, LineIndex, PositionEncoding}, LspError, }; @@ -140,7 +140,7 @@ pub(crate) fn apply_document_changes( index: Arc::new(ide::LineIndex::new(old_text)), // We don't care about line endings or offset encoding here. endings: LineEndings::Unix, - encoding: OffsetEncoding::Utf16, + encoding: PositionEncoding::Utf16, }; // The changes we got must be applied sequentially, but can cross lines so we diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 2c928a58040..7d10dc5d15b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -607,30 +607,34 @@ impl GlobalState { /// Handles a request. fn on_request(&mut self, req: Request) { - if self.shutdown_requested { - self.respond(lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::InvalidRequest as i32, - "Shutdown already requested.".to_owned(), - )); - return; + let mut dispatcher = RequestDispatcher { req: Some(req), global_state: self }; + dispatcher.on_sync_mut::(|s, ()| { + s.shutdown_requested = true; + Ok(()) + }); + + if let RequestDispatcher { req: Some(req), global_state: this } = &mut dispatcher { + if this.shutdown_requested { + this.respond(lsp_server::Response::new_err( + req.id.clone(), + lsp_server::ErrorCode::InvalidRequest as i32, + "Shutdown already requested.".to_owned(), + )); + return; + } + + // Avoid flashing a bunch of unresolved references during initial load. + if this.workspaces.is_empty() && !this.is_quiescent() { + this.respond(lsp_server::Response::new_err( + req.id.clone(), + lsp_server::ErrorCode::ContentModified as i32, + "waiting for cargo metadata or cargo check".to_owned(), + )); + return; + } } - // Avoid flashing a bunch of unresolved references during initial load. - if self.workspaces.is_empty() && !self.is_quiescent() { - self.respond(lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::ContentModified as i32, - "waiting for cargo metadata or cargo check".to_owned(), - )); - return; - } - - RequestDispatcher { req: Some(req), global_state: self } - .on_sync_mut::(|s, ()| { - s.shutdown_requested = true; - Ok(()) - }) + dispatcher .on_sync_mut::(handlers::handle_workspace_reload) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs index 5936454a7c5..6c84a2069cd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs @@ -21,7 +21,7 @@ use crate::{ cargo_target_spec::CargoTargetSpec, config::{CallInfoConfig, Config}, global_state::GlobalStateSnapshot, - line_index::{LineEndings, LineIndex, OffsetEncoding}, + line_index::{LineEndings, LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, semantic_tokens, Result, @@ -30,8 +30,8 @@ use crate::{ pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { let line_col = line_index.index.line_col(offset); match line_index.encoding { - OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), - OffsetEncoding::Utf16 => { + PositionEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), + PositionEncoding::Utf16 => { let line_col = line_index.index.to_utf16(line_col); lsp_types::Position::new(line_col.line, line_col.col) } @@ -1394,7 +1394,7 @@ fn main() { let line_index = LineIndex { index: Arc::new(ide::LineIndex::new(text)), endings: LineEndings::Unix, - encoding: OffsetEncoding::Utf16, + encoding: PositionEncoding::Utf16, }; let converted: Vec = folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect(); diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 89479543545..5379732ac6c 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -51,7 +51,7 @@ TypeArg = Type AssocTypeArg = - NameRef GenericParamList? (':' TypeBoundList | ('=' Type | ConstArg)) + NameRef GenericArgList? (':' TypeBoundList | ('=' Type | ConstArg)) LifetimeArg = Lifetime diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 449402e5f5b..6cfb98d92fc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -120,7 +120,7 @@ pub struct AssocTypeArg { impl ast::HasTypeBounds for AssocTypeArg {} impl AssocTypeArg { pub fn name_ref(&self) -> Option { support::child(&self.syntax) } - pub fn generic_param_list(&self) -> Option { support::child(&self.syntax) } + pub fn generic_arg_list(&self) -> Option { support::child(&self.syntax) } pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn const_arg(&self) -> Option { support::child(&self.syntax) } @@ -142,16 +142,6 @@ impl ConstArg { pub fn expr(&self) -> Option { support::child(&self.syntax) } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericParamList { - pub(crate) syntax: SyntaxNode, -} -impl GenericParamList { - pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TypeBoundList { pub(crate) syntax: SyntaxNode, @@ -527,6 +517,16 @@ impl Abi { pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericParamList { + pub(crate) syntax: SyntaxNode, +} +impl GenericParamList { + pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct WhereClause { pub(crate) syntax: SyntaxNode, @@ -1834,17 +1834,6 @@ impl AstNode for ConstArg { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } -impl AstNode for GenericParamList { - fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST } - fn cast(syntax: SyntaxNode) -> Option { - if Self::can_cast(syntax.kind()) { - Some(Self { syntax }) - } else { - None - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} impl AstNode for TypeBoundList { fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST } fn cast(syntax: SyntaxNode) -> Option { @@ -2153,6 +2142,17 @@ impl AstNode for Abi { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for GenericParamList { + fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for WhereClause { fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE } fn cast(syntax: SyntaxNode) -> Option { @@ -4263,11 +4263,6 @@ impl std::fmt::Display for ConstArg { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for GenericParamList { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for TypeBoundList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -4408,6 +4403,11 @@ impl std::fmt::Display for Abi { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for GenericParamList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for WhereClause { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md index c173a239fea..e3a4fdfda90 100644 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ b/src/tools/rust-analyzer/docs/dev/architecture.md @@ -479,7 +479,9 @@ It is not cheap enough to enable in prod, and this is a bug which should be fixe ### Configurability rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet. +The rule of thumb is to enable most features by default unless they are buggy or degrade performance too much. There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience. +Enabling them by default is a matter of discoverability, as many users end up don't know about some features even though they are presented in the manual. Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should. ### Serialization diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 6d2c7d7b063..fe316fcae9b 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@