Unnamed repository; edit this file 'description' to name the repository.
269 files changed, 5280 insertions, 3369 deletions
diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml index f975bbaa51..9cc18fc69e 100644 --- a/.github/workflows/rustdoc.yaml +++ b/.github/workflows/rustdoc.yaml @@ -8,6 +8,7 @@ env: CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 RUSTFLAGS: "-D warnings -W unreachable-pub" + RUSTDOCFLAGS: "-D warnings" RUSTUP_MAX_RETRIES: 10 jobs: diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index ea06fd9c48..55dfcbc7e5 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -31,5 +31,9 @@ vfs.workspace = true span.workspace = true intern.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 9793892410..aa06cdefe6 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -1,5 +1,10 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + pub use salsa; pub use salsa_macros; @@ -59,6 +64,28 @@ macro_rules! impl_intern_key { }; } +/// # SAFETY +/// +/// `old_pointer` must be valid for unique writes +pub unsafe fn unsafe_update_eq<T>(old_pointer: *mut T, new_value: T) -> bool +where + T: PartialEq, +{ + // SAFETY: Caller obligation + let old_ref: &mut T = unsafe { &mut *old_pointer }; + + if *old_ref != new_value { + *old_ref = new_value; + true + } else { + // Subtle but important: Eq impls can be buggy or define equality + // in surprising ways. If it says that the value has not changed, + // we do not modify the existing value, and thus do not have to + // update the revision, as downstream code will not see the new value. + false + } +} + pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16; pub const DEFAULT_PARSE_LRU_CAP: u16 = 128; pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024; diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index 9e2a95dbf3..7207cfcf7d 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml @@ -33,5 +33,9 @@ syntax.workspace = true # tt is needed for testing cfg = { path = ".", default-features = false, features = ["tt"] } +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index b1ec4c273a..3e3d67cb4a 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -1,5 +1,10 @@ //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod cfg_expr; mod dnf; #[cfg(test)] diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs index ab36b707f2..febc794b5a 100644 --- a/crates/hir-def/src/attrs.rs +++ b/crates/hir-def/src/attrs.rs @@ -45,8 +45,8 @@ use syntax::{ use tt::{TextRange, TextSize}; use crate::{ - AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, InternedModuleId, - LifetimeParamId, LocalFieldId, MacroId, TypeOrConstParamId, VariantId, + AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, LifetimeParamId, + LocalFieldId, MacroId, ModuleId, TypeOrConstParamId, VariantId, db::DefDatabase, hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::ModuleOrigin, @@ -155,6 +155,9 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal "rustc_skip_during_method_dispatch" => { extract_rustc_skip_during_method_dispatch(attr_flags, tt) } + "rustc_deprecated_safe_2024" => { + attr_flags.insert(AttrFlags::RUSTC_DEPRECATED_SAFE_2024) + } _ => {} }, 2 => match path.segments[0].text() { @@ -295,9 +298,8 @@ fn attrs_source( ) -> (InFile<ast::AnyHasAttrs>, Option<InFile<ast::Module>>, Crate) { let (owner, krate) = match owner { AttrDefId::ModuleId(id) => { - let id = id.loc(db); let def_map = id.def_map(db); - let (definition, declaration) = match def_map[id.local_id].origin { + let (definition, declaration) = match def_map[id].origin { ModuleOrigin::CrateRoot { definition } => { let file = db.parse(definition).tree(); (InFile::new(definition.into(), ast::AnyHasAttrs::from(file)), None) @@ -318,7 +320,7 @@ fn attrs_source( (block.with_value(definition.into()), None) } }; - return (definition, declaration, id.krate); + return (definition, declaration, def_map.krate()); } AttrDefId::AdtId(AdtId::StructId(it)) => attrs_from_ast_id_loc(db, it), AttrDefId::AdtId(AdtId::UnionId(it)) => attrs_from_ast_id_loc(db, it), @@ -1201,14 +1203,14 @@ impl AttrFlags { } #[inline] - pub fn doc_keyword(db: &dyn DefDatabase, owner: InternedModuleId) -> Option<Symbol> { + pub fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option<Symbol> { if !AttrFlags::query(db, AttrDefId::ModuleId(owner)).contains(AttrFlags::HAS_DOC_KEYWORD) { return None; } return doc_keyword(db, owner); #[salsa::tracked] - fn doc_keyword(db: &dyn DefDatabase, owner: InternedModuleId) -> Option<Symbol> { + fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option<Symbol> { collect_attrs(db, AttrDefId::ModuleId(owner), |attr| { if let Meta::TokenTree { path, tt } = attr && path.is1("doc") diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index cc311a41db..ccd4bc9be8 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -8,13 +8,12 @@ use la_arena::ArenaMap; use triomphe::Arc; use crate::{ - AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, CrateRootModuleId, DefWithBodyId, - EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, - ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, HasModule, ImplId, ImplLoc, - InternedModuleId, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, - MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, - StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, - VariantId, + AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, + EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, + FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, + MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, + ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, + TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attrs::AttrFlags, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, @@ -276,8 +275,8 @@ fn include_macro_invoc( } fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { - let root_module = CrateRootModuleId::from(crate_id).module(db); - let attrs = AttrFlags::query(db, AttrDefId::ModuleId(InternedModuleId::new(db, root_module))); + let root_module = crate_def_map(db, crate_id).root_module_id(); + let attrs = AttrFlags::query(db, AttrDefId::ModuleId(root_module)); attrs.contains(AttrFlags::IS_NO_STD) } @@ -298,7 +297,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let loc: Macro2Loc = it.lookup(db); MacroDefId { - krate: loc.container.krate, + krate: loc.container.krate(db), kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, @@ -309,7 +308,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let loc: MacroRulesLoc = it.lookup(db); MacroDefId { - krate: loc.container.krate, + krate: loc.container.krate(db), kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc @@ -322,7 +321,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let loc = it.lookup(db); MacroDefId { - krate: loc.container.krate, + krate: loc.container.krate(db), kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), local_inner: false, allow_internal_unsafe: false, diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 5695ab7ed0..66f7e25ffa 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -43,7 +43,7 @@ pub use self::lower::{ hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment, }; -/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. +/// A wrapper around [`span::SyntaxContext`] that is intended only for comparisons. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct HygieneId(span::SyntaxContext); diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 26a50b5325..42b076abb2 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -2,6 +2,7 @@ //! representation. mod asm; +mod format_args; mod generics; mod path; @@ -19,7 +20,7 @@ use intern::{Symbol, sym}; use rustc_hash::FxHashMap; use stdx::never; use syntax::{ - AstNode, AstPtr, AstToken as _, SyntaxNodePtr, + AstNode, AstPtr, SyntaxNodePtr, ast::{ self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, @@ -34,7 +35,6 @@ use crate::{ AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, attrs::AttrFlags, - builtin_type::BuiltinUint, db::DefDatabase, expr_store::{ Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder, @@ -47,13 +47,7 @@ use crate::{ hir::{ Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId, - RecordFieldPat, RecordLitField, Statement, - format_args::{ - self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, - FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, - FormatPlaceholder, FormatSign, FormatTrait, - }, - generics::GenericParams, + RecordFieldPat, RecordLitField, Statement, generics::GenericParams, }, item_scope::BuiltinShadowMode, item_tree::FieldsShape, @@ -434,9 +428,12 @@ pub struct ExprCollector<'db> { current_try_block_label: Option<LabelId>, label_ribs: Vec<LabelRib>, - current_binding_owner: Option<ExprId>, + unowned_bindings: Vec<BindingId>, awaitable_context: Option<Awaitable>, + krate: base_db::Crate, + + name_generator_index: usize, } #[derive(Clone, Debug)] @@ -524,9 +521,10 @@ impl<'db> ExprCollector<'db> { ) -> ExprCollector<'_> { let (def_map, local_def_map) = module.local_def_map(db); let expander = Expander::new(db, current_file_id, def_map); + let krate = module.krate(db); ExprCollector { db, - cfg_options: module.krate().cfg_options(db), + cfg_options: krate.cfg_options(db), module, def_map, local_def_map, @@ -536,16 +534,24 @@ impl<'db> ExprCollector<'db> { current_try_block_label: None, is_lowering_coroutine: false, label_ribs: Vec::new(), - current_binding_owner: None, + unowned_bindings: Vec::new(), awaitable_context: None, current_block_legacy_macro_defs_count: FxHashMap::default(), outer_impl_trait: false, + krate, + name_generator_index: 0, } } + fn generate_new_name(&mut self) -> Name { + let index = self.name_generator_index; + self.name_generator_index += 1; + Name::generate_new_name(index) + } + #[inline] pub(crate) fn lang_items(&self) -> &'db LangItems { - self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.module.krate)) + self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate())) } #[inline] @@ -946,7 +952,8 @@ impl<'db> ExprCollector<'db> { node: ast::TypeBound, impl_trait_lower_fn: ImplTraitLowerFn<'_>, ) -> TypeBound { - match node.kind() { + let Some(kind) = node.kind() else { return TypeBound::Error }; + match kind { ast::TypeBoundKind::PathType(binder, path_type) => { let binder = match binder.and_then(|it| it.generic_param_list()) { Some(gpl) => gpl @@ -1062,12 +1069,10 @@ impl<'db> ExprCollector<'db> { Some(ast::BlockModifier::Const(_)) => { self.with_label_rib(RibKind::Constant, |this| { this.with_awaitable_block(Awaitable::No("constant block"), |this| { - let (result_expr_id, prev_binding_owner) = - this.initialize_binding_owner(syntax_ptr); - let inner_expr = this.collect_block(e); - this.store.exprs[result_expr_id] = Expr::Const(inner_expr); - this.current_binding_owner = prev_binding_owner; - result_expr_id + this.with_binding_owner(|this| { + let inner_expr = this.collect_block(e); + this.alloc_expr(Expr::Const(inner_expr), syntax_ptr) + }) }) }) } @@ -1278,64 +1283,65 @@ impl<'db> ExprCollector<'db> { } } ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| { - let (result_expr_id, prev_binding_owner) = - this.initialize_binding_owner(syntax_ptr); - let mut args = Vec::new(); - let mut arg_types = Vec::new(); - if let Some(pl) = e.param_list() { - let num_params = pl.params().count(); - args.reserve_exact(num_params); - arg_types.reserve_exact(num_params); - for param in pl.params() { - let pat = this.collect_pat_top(param.pat()); - let type_ref = - param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it)); - args.push(pat); - arg_types.push(type_ref); + this.with_binding_owner(|this| { + let mut args = Vec::new(); + let mut arg_types = Vec::new(); + if let Some(pl) = e.param_list() { + let num_params = pl.params().count(); + args.reserve_exact(num_params); + arg_types.reserve_exact(num_params); + for param in pl.params() { + let pat = this.collect_pat_top(param.pat()); + let type_ref = + param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it)); + args.push(pat); + arg_types.push(type_ref); + } } - } - let ret_type = e - .ret_type() - .and_then(|r| r.ty()) - .map(|it| this.lower_type_ref_disallow_impl_trait(it)); + let ret_type = e + .ret_type() + .and_then(|r| r.ty()) + .map(|it| this.lower_type_ref_disallow_impl_trait(it)); - let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); - let prev_try_block_label = this.current_try_block_label.take(); + let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); + let prev_try_block_label = this.current_try_block_label.take(); - let awaitable = if e.async_token().is_some() { - Awaitable::Yes - } else { - Awaitable::No("non-async closure") - }; - let body = - this.with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body())); + let awaitable = if e.async_token().is_some() { + Awaitable::Yes + } else { + Awaitable::No("non-async closure") + }; + let body = this + .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body())); - let closure_kind = if this.is_lowering_coroutine { - let movability = if e.static_token().is_some() { - Movability::Static + let closure_kind = if this.is_lowering_coroutine { + let movability = if e.static_token().is_some() { + Movability::Static + } else { + Movability::Movable + }; + ClosureKind::Coroutine(movability) + } else if e.async_token().is_some() { + ClosureKind::Async } else { - Movability::Movable + ClosureKind::Closure }; - ClosureKind::Coroutine(movability) - } else if e.async_token().is_some() { - ClosureKind::Async - } else { - ClosureKind::Closure - }; - let capture_by = - if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; - this.is_lowering_coroutine = prev_is_lowering_coroutine; - this.current_binding_owner = prev_binding_owner; - this.current_try_block_label = prev_try_block_label; - this.store.exprs[result_expr_id] = Expr::Closure { - args: args.into(), - arg_types: arg_types.into(), - ret_type, - body, - closure_kind, - capture_by, - }; - result_expr_id + let capture_by = + if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; + this.is_lowering_coroutine = prev_is_lowering_coroutine; + this.current_try_block_label = prev_try_block_label; + this.alloc_expr( + Expr::Closure { + args: args.into(), + arg_types: arg_types.into(), + ret_type, + body, + closure_kind, + capture_by, + }, + syntax_ptr, + ) + }) }), ast::Expr::BinExpr(e) => { let op = e.op_kind(); @@ -1371,11 +1377,7 @@ impl<'db> ExprCollector<'db> { let initializer = self.collect_expr_opt(initializer); let repeat = self.with_label_rib(RibKind::Constant, |this| { if let Some(repeat) = repeat { - let syntax_ptr = AstPtr::new(&repeat); - this.collect_as_a_binding_owner_bad( - |this| this.collect_expr(repeat), - syntax_ptr, - ) + this.with_binding_owner(|this| this.collect_expr(repeat)) } else { this.missing_expr() } @@ -1632,31 +1634,13 @@ impl<'db> ExprCollector<'db> { } } - fn initialize_binding_owner( - &mut self, - syntax_ptr: AstPtr<ast::Expr>, - ) -> (ExprId, Option<ExprId>) { - let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr); - let prev_binding_owner = self.current_binding_owner.take(); - self.current_binding_owner = Some(result_expr_id); - - (result_expr_id, prev_binding_owner) - } - - /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently - /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have - /// their own body. Don't add more usage for this function so that we can remove this function after - /// separating those bodies. - fn collect_as_a_binding_owner_bad( - &mut self, - job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId, - syntax_ptr: AstPtr<ast::Expr>, - ) -> ExprId { - let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr); - let tmp = job(self); - self.store.exprs[id] = mem::replace(&mut self.store.exprs[tmp], Expr::Missing); - self.current_binding_owner = prev_owner; - id + fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId { + let prev_unowned_bindings_len = self.unowned_bindings.len(); + let expr_id = create_expr(self); + for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) { + self.store.binding_owners.insert(binding, expr_id); + } + expr_id } /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`, @@ -1664,9 +1648,8 @@ impl<'db> ExprCollector<'db> { /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator. fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput); - let label = self.alloc_label_desugared(Label { - name: Name::generate_new_name(self.store.labels.len()), - }); + let label = self.generate_new_name(); + let label = self.alloc_label_desugared(Label { name: label }); let old_label = self.current_try_block_label.replace(label); let ptr = AstPtr::new(&e).upcast(); @@ -1794,7 +1777,7 @@ impl<'db> ExprCollector<'db> { this.collect_expr_opt(e.loop_body().map(|it| it.into())) }), }; - let iter_name = Name::generate_new_name(self.store.exprs.len()); + let iter_name = self.generate_new_name(); let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr); let iter_expr_mut = self.alloc_expr( Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut }, @@ -1855,7 +1838,7 @@ impl<'db> ExprCollector<'db> { let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr); let expr = self .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr); - let continue_name = Name::generate_new_name(self.store.bindings.len()); + let continue_name = self.generate_new_name(); let continue_binding = self.alloc_binding( continue_name.clone(), BindingAnnotation::Unannotated, @@ -1873,7 +1856,7 @@ impl<'db> ExprCollector<'db> { guard: None, expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr), }; - let break_name = Name::generate_new_name(self.store.bindings.len()); + let break_name = self.generate_new_name(); let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated, HygieneId::ROOT); let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); @@ -1915,9 +1898,8 @@ impl<'db> ExprCollector<'db> { T: ast::AstNode, { let macro_call_ptr = self.expander.in_file(syntax_ptr); - let module = self.module.local_id; - let block_call = self.def_map.modules[self.module.local_id].scope.macro_invoc( + let block_call = self.def_map.modules[self.module].scope.macro_invoc( self.expander.in_file(self.expander.ast_id_map().ast_id_for_ptr(syntax_ptr)), ); let res = match block_call { @@ -1929,7 +1911,7 @@ impl<'db> ExprCollector<'db> { .resolve_path( self.local_def_map, self.db, - module, + self.module, path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), @@ -1940,7 +1922,7 @@ impl<'db> ExprCollector<'db> { self.expander.enter_expand( self.db, mcall, - self.module.krate(), + self.krate, resolver, &mut |ptr, call| { _ = self.store.expansions.insert(ptr.map(|(it, _)| it), call); @@ -2058,7 +2040,8 @@ impl<'db> ExprCollector<'db> { return; }; let name = name.as_name(); - let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros(); + let macro_id = + self.def_map.modules[self.def_map.root].scope.get(&name).take_macros(); self.collect_macro_def(statements, macro_id); } ast::Stmt::Item(ast::Item::MacroRules(macro_)) => { @@ -2072,7 +2055,7 @@ impl<'db> ExprCollector<'db> { let name = name.as_name(); let macro_defs_count = self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0); - let macro_id = self.def_map.modules[DefMap::ROOT] + let macro_id = self.def_map.modules[self.def_map.root] .scope .get_legacy_macro(&name) .and_then(|it| it.get(*macro_defs_count)) @@ -2118,7 +2101,7 @@ impl<'db> ExprCollector<'db> { match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) { Some((def_map, block_id)) => { self.store.block_scopes.push(block_id); - (def_map.module_id(DefMap::ROOT), def_map) + (def_map.root_module_id(), def_map) } None => (self.module, self.def_map), }; @@ -2201,7 +2184,7 @@ impl<'db> ExprCollector<'db> { let (resolved, _) = self.def_map.resolve_path( self.local_def_map, self.db, - self.module.local_id, + self.module, &name.clone().into(), BuiltinShadowMode::Other, None, @@ -2368,11 +2351,7 @@ impl<'db> ExprCollector<'db> { ast::Pat::ConstBlockPat(const_block_pat) => { if let Some(block) = const_block_pat.block_expr() { let expr_id = self.with_label_rib(RibKind::Constant, |this| { - let syntax_ptr = AstPtr::new(&block.clone().into()); - this.collect_as_a_binding_owner_bad( - |this| this.collect_block(block), - syntax_ptr, - ) + this.with_binding_owner(|this| this.collect_block(block)) }); Pat::ConstBlock(expr_id) } else { @@ -2632,7 +2611,6 @@ impl<'db> ExprCollector<'db> { } // endregion: labels - // region: format fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> { let m = match expr { ast::Expr::MacroExpr(m) => m, @@ -2652,676 +2630,6 @@ impl<'db> ExprCollector<'db> { Some((exp, false)) } - fn collect_format_args( - &mut self, - f: ast::FormatArgsExpr, - syntax_ptr: AstPtr<ast::Expr>, - ) -> ExprId { - let mut args = FormatArgumentsCollector::default(); - f.args().for_each(|arg| { - args.add(FormatArgument { - kind: match arg.name() { - Some(name) => FormatArgumentKind::Named(name.as_name()), - None => FormatArgumentKind::Normal, - }, - expr: self.collect_expr_opt(arg.expr()), - }); - }); - let template = f.template(); - let fmt_snippet = template.as_ref().and_then(|it| match it { - ast::Expr::Literal(literal) => match literal.kind() { - ast::LiteralKind::String(s) => Some(s.text().to_owned()), - _ => None, - }, - _ => None, - }); - let mut mappings = vec![]; - let (fmt, hygiene) = match template.and_then(|template| { - self.expand_macros_to_string(template.clone()).map(|it| (it, template)) - }) { - Some(((s, is_direct_literal), template)) => { - let call_ctx = self.expander.call_syntax_ctx(); - let hygiene = self.hygiene_id_for(s.syntax().text_range()); - let fmt = format_args::parse( - &s, - fmt_snippet, - args, - is_direct_literal, - |name, range| { - let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name))); - if let Some(range) = range { - self.store - .template_map - .get_or_insert_with(Default::default) - .implicit_capture_to_source - .insert( - expr_id, - self.expander.in_file((AstPtr::new(&template), range)), - ); - } - if !hygiene.is_root() { - self.store.ident_hygiene.insert(expr_id.into(), hygiene); - } - expr_id - }, - |name, span| { - if let Some(span) = span { - mappings.push((span, name)) - } - }, - call_ctx, - ); - (fmt, hygiene) - } - None => ( - FormatArgs { - template: Default::default(), - arguments: args.finish(), - orphans: Default::default(), - }, - HygieneId::ROOT, - ), - }; - - // Create a list of all _unique_ (argument, format trait) combinations. - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexSet::default(); - for piece in fmt.template.iter() { - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; - if let Ok(index) = placeholder.argument.index { - argmap.insert((index, ArgumentType::Format(placeholder.format_trait))); - } - } - - let lit_pieces = fmt - .template - .iter() - .enumerate() - .filter_map(|(i, piece)| { - match piece { - FormatArgsPiece::Literal(s) => { - Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone())))) - } - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) - { - Some(self.alloc_expr_desugared(Expr::Literal(Literal::String( - Symbol::empty(), - )))) - } else { - None - } - } - } - }) - .collect(); - let lit_pieces = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces })); - let lit_pieces = self.alloc_expr_desugared(Expr::Ref { - expr: lit_pieces, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - let format_options = { - // Generate: - // &[format_spec_0, format_spec_1, format_spec_2] - let elements = fmt - .template - .iter() - .filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(self.make_format_spec(placeholder, &mut argmap)) - }) - .collect(); - let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements })); - self.alloc_expr_desugared(Expr::Ref { - expr: array, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }; - - // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists - // but `format_unsafe_arg` does not - let lang_items = self.lang_items(); - let fmt_args = lang_items.FormatArguments; - let fmt_unsafe_arg = lang_items.FormatUnsafeArg; - let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none(); - - let idx = if use_format_args_since_1_89_0 { - self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options) - } else { - self.collect_format_args_before_1_89_0_impl( - syntax_ptr, - fmt, - argmap, - lit_pieces, - format_options, - ) - }; - - self.store - .template_map - .get_or_insert_with(Default::default) - .format_args_to_captures - .insert(idx, (hygiene, mappings)); - idx - } - - /// `format_args!` expansion implementation for rustc versions < `1.89.0` - fn collect_format_args_before_1_89_0_impl( - &mut self, - syntax_ptr: AstPtr<ast::Expr>, - fmt: FormatArgs, - argmap: FxIndexSet<(usize, ArgumentType)>, - lit_pieces: ExprId, - format_options: ExprId, - ) -> ExprId { - let arguments = &*fmt.arguments.arguments; - - let args = if arguments.is_empty() { - let expr = self - .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() })); - self.alloc_expr_desugared(Expr::Ref { - expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - } else { - // Generate: - // &match (&arg0, &arg1, &…) { - // args => [ - // <core::fmt::Argument>::new_display(args.0), - // <core::fmt::Argument>::new_lower_hex(args.1), - // <core::fmt::Argument>::new_debug(args.0), - // … - // ] - // } - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let arg = self.alloc_expr_desugared(Expr::Ref { - expr: arguments[arg_index].expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - self.make_argument(arg, ty) - }) - .collect(); - let array = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - self.alloc_expr_desugared(Expr::Ref { - expr: array, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }; - - // Generate: - // <core::fmt::Arguments>::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) - - let lang_items = self.lang_items(); - let new_v1_formatted = self.ty_rel_lang_path( - lang_items.FormatArguments, - Name::new_symbol_root(sym::new_v1_formatted), - ); - let unsafe_arg_new = - self.ty_rel_lang_path(lang_items.FormatUnsafeArg, Name::new_symbol_root(sym::new)); - let new_v1_formatted = - self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path)); - - let unsafe_arg_new = - self.alloc_expr_desugared(unsafe_arg_new.map_or(Expr::Missing, Expr::Path)); - let unsafe_arg_new = - self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() }); - let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe { - id: None, - statements: Box::new([]), - tail: Some(unsafe_arg_new), - }); - if !fmt.orphans.is_empty() { - unsafe_arg_new = self.alloc_expr_desugared(Expr::Block { - id: None, - // We collect the unused expressions here so that we still infer them instead of - // dropping them out of the expression tree. We cannot store them in the `Unsafe` - // block because then unsafe blocks within them will get a false "unused unsafe" - // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't). - statements: fmt - .orphans - .into_iter() - .map(|expr| Statement::Expr { expr, has_semi: true }) - .collect(), - tail: Some(unsafe_arg_new), - label: None, - }); - } - - self.alloc_expr( - Expr::Call { - callee: new_v1_formatted, - args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), - }, - syntax_ptr, - ) - } - - /// `format_args!` expansion implementation for rustc versions >= `1.89.0`, - /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748) - fn collect_format_args_impl( - &mut self, - syntax_ptr: AstPtr<ast::Expr>, - fmt: FormatArgs, - argmap: FxIndexSet<(usize, ArgumentType)>, - lit_pieces: ExprId, - format_options: ExprId, - ) -> ExprId { - let arguments = &*fmt.arguments.arguments; - - let (let_stmts, args) = if arguments.is_empty() { - ( - // Generate: - // [] - vec![], - self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements: Box::default(), - })), - ) - } else if argmap.len() == 1 && arguments.len() == 1 { - // Only one argument, so we don't need to make the `args` tuple. - // - // Generate: - // super let args = [<core::fmt::Arguments>::new_display(&arg)]; - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let ref_arg = self.alloc_expr_desugared(Expr::Ref { - expr: arguments[arg_index].expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - self.make_argument(ref_arg, ty) - }) - .collect(); - let args = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - let args_name = Name::new_symbol_root(sym::args); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - // TODO: We don't have `super let` yet. - let let_stmt = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(args), - else_branch: None, - }; - (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into()))) - } else { - // Generate: - // super let args = (&arg0, &arg1, &...); - let args_name = Name::new_symbol_root(sym::args); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - let elements = arguments - .iter() - .map(|arg| { - self.alloc_expr_desugared(Expr::Ref { - expr: arg.expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }) - .collect(); - let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); - // TODO: We don't have `super let` yet - let let_stmt1 = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(args_tuple), - else_branch: None, - }; - - // Generate: - // super let args = [ - // <core::fmt::Argument>::new_display(args.0), - // <core::fmt::Argument>::new_lower_hex(args.1), - // <core::fmt::Argument>::new_debug(args.0), - // … - // ]; - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let args_ident_expr = - self.alloc_expr_desugared(Expr::Path(args_name.clone().into())); - let arg = self.alloc_expr_desugared(Expr::Field { - expr: args_ident_expr, - name: Name::new_tuple_field(arg_index), - }); - self.make_argument(arg, ty) - }) - .collect(); - let array = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - let let_stmt2 = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(array), - else_branch: None, - }; - (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into()))) - }; - - // Generate: - // &args - let args = self.alloc_expr_desugared(Expr::Ref { - expr: args, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - - let call_block = { - // Generate: - // unsafe { - // <core::fmt::Arguments>::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // ) - // } - - let new_v1_formatted = self.ty_rel_lang_path( - self.lang_items().FormatArguments, - Name::new_symbol_root(sym::new_v1_formatted), - ); - let new_v1_formatted = - self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path)); - let args = [lit_pieces, args, format_options]; - let call = self - .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() }); - - Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) } - }; - - if !let_stmts.is_empty() { - // Generate: - // { - // super let … - // super let … - // <core::fmt::Arguments>::new_…(…) - // } - let call = self.alloc_expr_desugared(call_block); - self.alloc_expr( - Expr::Block { - id: None, - statements: let_stmts.into(), - tail: Some(call), - label: None, - }, - syntax_ptr, - ) - } else { - self.alloc_expr(call_block, syntax_ptr) - } - } - - /// Generate a hir expression for a format_args placeholder specification. - /// - /// Generates - /// - /// ```text - /// <core::fmt::rt::Placeholder::new( - /// …usize, // position - /// '…', // fill - /// <core::fmt::rt::Alignment>::…, // alignment - /// …u32, // flags - /// <core::fmt::rt::Count::…>, // width - /// <core::fmt::rt::Count::…>, // precision - /// ) - /// ``` - fn make_format_spec( - &mut self, - placeholder: &FormatPlaceholder, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, - ) -> ExprId { - let lang_items = self.lang_items(); - let position = match placeholder.argument.index { - Ok(arg_index) => { - let (i, _) = - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); - self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))) - } - Err(_) => self.missing_expr(), - }; - let &FormatOptions { - ref width, - ref precision, - alignment, - fill, - sign, - alternate, - zero_pad, - debug_hex, - } = &placeholder.format_options; - - let precision_expr = self.make_count(precision, argmap); - let width_expr = self.make_count(width, argmap); - - if self.module.krate().workspace_data(self.db).is_atleast_187() { - // These need to match the constants in library/core/src/fmt/rt.rs. - let align = match alignment { - Some(FormatAlignment::Left) => 0, - Some(FormatAlignment::Right) => 1, - Some(FormatAlignment::Center) => 2, - None => 3, - }; - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags = fill.unwrap_or(' ') as u32 - | ((sign == Some(FormatSign::Plus)) as u32) << 21 - | ((sign == Some(FormatSign::Minus)) as u32) << 22 - | (alternate as u32) << 23 - | (zero_pad as u32) << 24 - | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 - | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 - | (width.is_some() as u32) << 27 - | (precision.is_some() as u32) << 28 - | align << 29 - | 1 << 31; // Highest bit always set. - let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - flags as u128, - Some(BuiltinUint::U32), - ))); - - let position = - RecordLitField { name: Name::new_symbol_root(sym::position), expr: position }; - let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags }; - let precision = RecordLitField { - name: Name::new_symbol_root(sym::precision), - expr: precision_expr, - }; - let width = - RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr }; - self.alloc_expr_desugared(Expr::RecordLit { - path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new), - fields: Box::new([position, flags, precision, width]), - spread: None, - }) - } else { - let format_placeholder_new = { - let format_placeholder_new = self.ty_rel_lang_path( - lang_items.FormatPlaceholder, - Name::new_symbol_root(sym::new), - ); - match format_placeholder_new { - Some(path) => self.alloc_expr_desugared(Expr::Path(path)), - None => self.missing_expr(), - } - }; - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | (((sign == Some(FormatSign::Minus)) as u32) << 1) - | ((alternate as u32) << 2) - | ((zero_pad as u32) << 3) - | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4) - | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5); - let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - flags as u128, - Some(BuiltinUint::U32), - ))); - let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' ')))); - let align = { - let align = self.ty_rel_lang_path( - lang_items.FormatAlignment, - match alignment { - Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left), - Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right), - Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center), - None => Name::new_symbol_root(sym::Unknown), - }, - ); - match align { - Some(path) => self.alloc_expr_desugared(Expr::Path(path)), - None => self.missing_expr(), - } - }; - self.alloc_expr_desugared(Expr::Call { - callee: format_placeholder_new, - args: Box::new([position, fill, align, flags, precision_expr, width_expr]), - }) - } - } - - /// Generate a hir expression for a format_args Count. - /// - /// Generates: - /// - /// ```text - /// <core::fmt::rt::Count>::Is(…) - /// ``` - /// - /// or - /// - /// ```text - /// <core::fmt::rt::Count>::Param(…) - /// ``` - /// - /// or - /// - /// ```text - /// <core::fmt::rt::Count>::Implied - /// ``` - fn make_count( - &mut self, - count: &Option<FormatCount>, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, - ) -> ExprId { - let lang_items = self.lang_items(); - match count { - Some(FormatCount::Literal(n)) => { - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - *n as u128, - // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88 - None, - ))); - let count_is = match self - .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Is)) - { - Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), - None => self.missing_expr(), - }; - self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) }) - } - Some(FormatCount::Argument(arg)) => { - if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))); - let count_param = match self - .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Param)) - { - Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), - None => self.missing_expr(), - }; - self.alloc_expr_desugared(Expr::Call { - callee: count_param, - args: Box::new([args]), - }) - } else { - // FIXME: This drops arg causing it to potentially not be resolved/type checked - // when typing? - self.missing_expr() - } - } - None => match self - .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Implied)) - { - Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), - None => self.missing_expr(), - }, - } - } - - /// Generate a hir expression representing an argument to a format_args invocation. - /// - /// Generates: - /// - /// ```text - /// <core::fmt::Argument>::new_…(arg) - /// ``` - fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId { - use ArgumentType::*; - use FormatTrait::*; - - let new_fn = match self.ty_rel_lang_path( - self.lang_items().FormatArgument, - Name::new_symbol_root(match ty { - Format(Display) => sym::new_display, - Format(Debug) => sym::new_debug, - Format(LowerExp) => sym::new_lower_exp, - Format(UpperExp) => sym::new_upper_exp, - Format(Octal) => sym::new_octal, - Format(Pointer) => sym::new_pointer, - Format(Binary) => sym::new_binary, - Format(LowerHex) => sym::new_lower_hex, - Format(UpperHex) => sym::new_upper_hex, - Usize => sym::from_usize, - }), - ) { - Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), - None => self.missing_expr(), - }; - self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) }) - } - - // endregion: format - fn lang_path(&self, lang: Option<impl Into<LangItemTarget>>) -> Option<Path> { Some(Path::LangItem(lang?.into(), None)) } @@ -3329,9 +2637,17 @@ impl<'db> ExprCollector<'db> { fn ty_rel_lang_path( &self, lang: Option<impl Into<LangItemTarget>>, - relative_name: Name, + relative_name: Symbol, ) -> Option<Path> { - Some(Path::LangItem(lang?.into(), Some(relative_name))) + Some(Path::LangItem(lang?.into(), Some(Name::new_symbol_root(relative_name)))) + } + + fn ty_rel_lang_path_expr( + &self, + lang: Option<impl Into<LangItemTarget>>, + relative_name: Symbol, + ) -> Expr { + self.ty_rel_lang_path(lang, relative_name).map_or(Expr::Missing, Expr::Path) } } @@ -3376,9 +2692,7 @@ impl ExprCollector<'_> { hygiene: HygieneId, ) -> BindingId { let binding = self.store.bindings.alloc(Binding { name, mode, problems: None, hygiene }); - if let Some(owner) = self.current_binding_owner { - self.store.binding_owners.insert(binding, owner); - } + self.unowned_bindings.push(binding); binding } @@ -3450,12 +2764,6 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool { .is_some_and(|it| it.kind() == syntax::T![,]) } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -enum ArgumentType { - Format(FormatTrait), - Usize, -} - /// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR. pub fn hir_assoc_type_binding_to_ast( segment_args: &ast::GenericArgList, diff --git a/crates/hir-def/src/expr_store/lower/format_args.rs b/crates/hir-def/src/expr_store/lower/format_args.rs new file mode 100644 index 0000000000..4bbfc5b144 --- /dev/null +++ b/crates/hir-def/src/expr_store/lower/format_args.rs @@ -0,0 +1,1012 @@ +//! Lowering of `format_args!()`. + +use base_db::FxIndexSet; +use hir_expand::name::{AsName, Name}; +use intern::{Symbol, sym}; +use syntax::{ + AstPtr, AstToken as _, + ast::{self, HasName}, +}; + +use crate::{ + builtin_type::BuiltinUint, + expr_store::{HygieneId, lower::ExprCollector, path::Path}, + hir::{ + Array, BindingAnnotation, Expr, ExprId, Literal, Pat, RecordLitField, Statement, + format_args::{ + self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, + FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, + FormatPlaceholder, FormatSign, FormatTrait, + }, + }, + lang_item::LangItemTarget, + type_ref::{Mutability, Rawness}, +}; + +impl<'db> ExprCollector<'db> { + pub(super) fn collect_format_args( + &mut self, + f: ast::FormatArgsExpr, + syntax_ptr: AstPtr<ast::Expr>, + ) -> ExprId { + let mut args = FormatArgumentsCollector::default(); + f.args().for_each(|arg| { + args.add(FormatArgument { + kind: match arg.name() { + Some(name) => FormatArgumentKind::Named(name.as_name()), + None => FormatArgumentKind::Normal, + }, + expr: self.collect_expr_opt(arg.expr()), + }); + }); + let template = f.template(); + let fmt_snippet = template.as_ref().and_then(|it| match it { + ast::Expr::Literal(literal) => match literal.kind() { + ast::LiteralKind::String(s) => Some(s.text().to_owned()), + _ => None, + }, + _ => None, + }); + let mut mappings = vec![]; + let (fmt, hygiene) = match template.and_then(|template| { + self.expand_macros_to_string(template.clone()).map(|it| (it, template)) + }) { + Some(((s, is_direct_literal), template)) => { + let call_ctx = self.expander.call_syntax_ctx(); + let hygiene = self.hygiene_id_for(s.syntax().text_range()); + let fmt = format_args::parse( + &s, + fmt_snippet, + args, + is_direct_literal, + |name, range| { + let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name))); + if let Some(range) = range { + self.store + .template_map + .get_or_insert_with(Default::default) + .implicit_capture_to_source + .insert( + expr_id, + self.expander.in_file((AstPtr::new(&template), range)), + ); + } + if !hygiene.is_root() { + self.store.ident_hygiene.insert(expr_id.into(), hygiene); + } + expr_id + }, + |name, span| { + if let Some(span) = span { + mappings.push((span, name)) + } + }, + call_ctx, + ); + (fmt, hygiene) + } + None => ( + FormatArgs { + template: Default::default(), + arguments: args.finish(), + orphans: Default::default(), + }, + HygieneId::ROOT, + ), + }; + + let idx = if self.lang_items().FormatCount.is_none() { + self.collect_format_args_after_1_93_0_impl(syntax_ptr, fmt) + } else { + self.collect_format_args_before_1_93_0_impl(syntax_ptr, fmt) + }; + + self.store + .template_map + .get_or_insert_with(Default::default) + .format_args_to_captures + .insert(idx, (hygiene, mappings)); + idx + } + + fn collect_format_args_after_1_93_0_impl( + &mut self, + syntax_ptr: AstPtr<ast::Expr>, + fmt: FormatArgs, + ) -> ExprId { + let lang_items = self.lang_items(); + + // Create a list of all _unique_ (argument, format trait) combinations. + // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] + // + // We use usize::MAX for arguments that don't exist, because that can never be a valid index + // into the arguments array. + let mut argmap = FxIndexSet::default(); + + let mut incomplete_lit = String::new(); + + let mut implicit_arg_index = 0; + + let mut bytecode = Vec::new(); + + let template = if fmt.template.is_empty() { + // Treat empty templates as a single literal piece (with an empty string), + // so we produce `from_str("")` for those. + &[FormatArgsPiece::Literal(sym::__empty)][..] + } else { + &fmt.template[..] + }; + + // See library/core/src/fmt/mod.rs for the format string encoding format. + + for (i, piece) in template.iter().enumerate() { + match piece { + FormatArgsPiece::Literal(sym) => { + // Coalesce adjacent literal pieces. + if let Some(FormatArgsPiece::Literal(_)) = template.get(i + 1) { + incomplete_lit.push_str(sym.as_str()); + continue; + } + let mut s = if incomplete_lit.is_empty() { + sym.as_str() + } else { + incomplete_lit.push_str(sym.as_str()); + &incomplete_lit + }; + + // If this is the last piece and was the only piece, that means + // there are no placeholders and the entire format string is just a literal. + // + // In that case, we can just use `from_str`. + if i + 1 == template.len() && bytecode.is_empty() { + // Generate: + // <core::fmt::Arguments>::from_str("meow") + let from_str = self.ty_rel_lang_path_desugared_expr( + lang_items.FormatArguments, + sym::from_str, + ); + let sym = + if incomplete_lit.is_empty() { sym.clone() } else { Symbol::intern(s) }; + let s = self.alloc_expr_desugared(Expr::Literal(Literal::String(sym))); + let from_str = self.alloc_expr( + Expr::Call { callee: from_str, args: Box::new([s]) }, + syntax_ptr, + ); + return if !fmt.arguments.arguments.is_empty() { + // With an incomplete format string (e.g. only an opening `{`), it's possible for `arguments` + // to be non-empty when reaching this code path. + self.alloc_expr( + Expr::Block { + id: None, + statements: fmt + .arguments + .arguments + .iter() + .map(|arg| Statement::Expr { + expr: arg.expr, + has_semi: true, + }) + .collect(), + tail: Some(from_str), + label: None, + }, + syntax_ptr, + ) + } else { + from_str + }; + } + + // Encode the literal in chunks of up to u16::MAX bytes, split at utf-8 boundaries. + while !s.is_empty() { + let len = s.floor_char_boundary(usize::from(u16::MAX)); + if len < 0x80 { + bytecode.push(len as u8); + } else { + bytecode.push(0x80); + bytecode.extend_from_slice(&(len as u16).to_le_bytes()); + } + bytecode.extend(&s.as_bytes()[..len]); + s = &s[len..]; + } + + incomplete_lit.clear(); + } + FormatArgsPiece::Placeholder(p) => { + // Push the start byte and remember its index so we can set the option bits later. + let i = bytecode.len(); + bytecode.push(0xC0); + + let position = match &p.argument.index { + &Ok(it) => it, + Err(_) => usize::MAX, + }; + let position = argmap + .insert_full((position, ArgumentType::Format(p.format_trait))) + .0 as u64; + + // This needs to match the constants in library/core/src/fmt/mod.rs. + let o = &p.format_options; + let align = match o.alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + let default_flags = 0x6000_0020; + let flags: u32 = o.fill.unwrap_or(' ') as u32 + | ((o.sign == Some(FormatSign::Plus)) as u32) << 21 + | ((o.sign == Some(FormatSign::Minus)) as u32) << 22 + | (o.alternate as u32) << 23 + | (o.zero_pad as u32) << 24 + | ((o.debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((o.debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (o.width.is_some() as u32) << 27 + | (o.precision.is_some() as u32) << 28 + | align << 29; + if flags != default_flags { + bytecode[i] |= 1; + bytecode.extend_from_slice(&flags.to_le_bytes()); + if let Some(val) = &o.width { + let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap); + // Only encode if nonzero; zero is the default. + if indirect || val != 0 { + bytecode[i] |= 1 << 1 | (indirect as u8) << 4; + bytecode.extend_from_slice(&val.to_le_bytes()); + } + } + if let Some(val) = &o.precision { + let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap); + // Only encode if nonzero; zero is the default. + if indirect || val != 0 { + bytecode[i] |= 1 << 2 | (indirect as u8) << 5; + bytecode.extend_from_slice(&val.to_le_bytes()); + } + } + } + if implicit_arg_index != position { + bytecode[i] |= 1 << 3; + bytecode.extend_from_slice(&(position as u16).to_le_bytes()); + } + implicit_arg_index = position + 1; + } + } + } + + assert!(incomplete_lit.is_empty()); + + // Zero terminator. + bytecode.push(0); + + // Ensure all argument indexes actually fit in 16 bits, as we truncated them to 16 bits before. + if argmap.len() > u16::MAX as usize { + // FIXME: Emit an error. + // ctx.dcx().span_err(macsp, "too many format arguments"); + } + + let arguments = &fmt.arguments.arguments[..]; + + let (mut statements, args) = if arguments.is_empty() { + // Generate: + // [] + ( + Vec::new(), + self.alloc_expr_desugared(Expr::Array(Array::ElementList { + elements: Box::new([]), + })), + ) + } else { + // Generate: + // super let args = (&arg0, &arg1, &…); + let args_name = self.generate_new_name(); + let args_path = Path::from(args_name.clone()); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let elements = arguments + .iter() + .map(|arg| { + self.alloc_expr_desugared(Expr::Ref { + expr: arg.expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }) + .collect(); + let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); + // FIXME: Make this a `super let` when we have this statement. + let let_statement_1 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args_tuple), + else_branch: None, + }; + + // Generate: + // super let args = [ + // <core::fmt::Argument>::new_display(args.0), + // <core::fmt::Argument>::new_lower_hex(args.1), + // <core::fmt::Argument>::new_debug(args.0), + // … + // ]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let args_ident_expr = self.alloc_expr_desugared(Expr::Path(args_path.clone())); + let arg = self.alloc_expr_desugared(Expr::Field { + expr: args_ident_expr, + name: Name::new_tuple_field(arg_index), + }); + self.make_argument(arg, ty) + }) + .collect(); + let args = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_binding = + self.alloc_binding(args_name, BindingAnnotation::Unannotated, HygieneId::ROOT); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + // FIXME: Make this a `super let` when we have this statement. + let let_statement_2 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args), + else_branch: None, + }; + ( + vec![let_statement_1, let_statement_2], + self.alloc_expr_desugared(Expr::Path(args_path)), + ) + }; + + // Generate: + // unsafe { + // <core::fmt::Arguments>::new(b"…", &args) + // } + let template = self + .alloc_expr_desugared(Expr::Literal(Literal::ByteString(bytecode.into_boxed_slice()))); + let call = { + let new = self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new); + let args = self.alloc_expr_desugared(Expr::Ref { + expr: args, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + self.alloc_expr_desugared(Expr::Call { callee: new, args: Box::new([template, args]) }) + }; + let call = self.alloc_expr( + Expr::Unsafe { id: None, statements: Box::new([]), tail: Some(call) }, + syntax_ptr, + ); + + // We collect the unused expressions here so that we still infer them instead of + // dropping them out of the expression tree. We cannot store them in the `Unsafe` + // block because then unsafe blocks within them will get a false "unused unsafe" + // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't). + statements + .extend(fmt.orphans.into_iter().map(|expr| Statement::Expr { expr, has_semi: true })); + + if !statements.is_empty() { + // Generate: + // { + // super let … + // super let … + // <core::fmt::Arguments>::new(…) + // } + self.alloc_expr( + Expr::Block { + id: None, + statements: statements.into_boxed_slice(), + tail: Some(call), + label: None, + }, + syntax_ptr, + ) + } else { + call + } + } + + /// Get the value for a `width` or `precision` field. + /// + /// Returns the value and whether it is indirect (an indexed argument) or not. + fn make_count_after_1_93_0( + &self, + count: &FormatCount, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, + ) -> (bool, u16) { + match count { + FormatCount::Literal(n) => (false, *n), + FormatCount::Argument(arg) => { + let index = match &arg.index { + &Ok(it) => it, + Err(_) => usize::MAX, + }; + (true, argmap.insert_full((index, ArgumentType::Usize)).0 as u16) + } + } + } + + fn collect_format_args_before_1_93_0_impl( + &mut self, + syntax_ptr: AstPtr<ast::Expr>, + fmt: FormatArgs, + ) -> ExprId { + // Create a list of all _unique_ (argument, format trait) combinations. + // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] + let mut argmap = FxIndexSet::default(); + for piece in fmt.template.iter() { + let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; + if let Ok(index) = placeholder.argument.index { + argmap.insert((index, ArgumentType::Format(placeholder.format_trait))); + } + } + + let lit_pieces = fmt + .template + .iter() + .enumerate() + .filter_map(|(i, piece)| { + match piece { + FormatArgsPiece::Literal(s) => { + Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone())))) + } + &FormatArgsPiece::Placeholder(_) => { + // Inject empty string before placeholders when not already preceded by a literal piece. + if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) + { + Some(self.alloc_expr_desugared(Expr::Literal(Literal::String( + Symbol::empty(), + )))) + } else { + None + } + } + } + }) + .collect(); + let lit_pieces = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces })); + let lit_pieces = self.alloc_expr_desugared(Expr::Ref { + expr: lit_pieces, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + let format_options = { + // Generate: + // &[format_spec_0, format_spec_1, format_spec_2] + let elements = fmt + .template + .iter() + .filter_map(|piece| { + let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; + Some(self.make_format_spec(placeholder, &mut argmap)) + }) + .collect(); + let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements })); + self.alloc_expr_desugared(Expr::Ref { + expr: array, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }; + + // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists + // but `format_unsafe_arg` does not + let lang_items = self.lang_items(); + let fmt_args = lang_items.FormatArguments; + let fmt_unsafe_arg = lang_items.FormatUnsafeArg; + let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none(); + + if use_format_args_since_1_89_0 { + self.collect_format_args_after_1_89_0_impl( + syntax_ptr, + fmt, + argmap, + lit_pieces, + format_options, + ) + } else { + self.collect_format_args_before_1_89_0_impl( + syntax_ptr, + fmt, + argmap, + lit_pieces, + format_options, + ) + } + } + + /// `format_args!` expansion implementation for rustc versions < `1.89.0` + fn collect_format_args_before_1_89_0_impl( + &mut self, + syntax_ptr: AstPtr<ast::Expr>, + fmt: FormatArgs, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { + let arguments = &*fmt.arguments.arguments; + + let args = if arguments.is_empty() { + let expr = self + .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() })); + self.alloc_expr_desugared(Expr::Ref { + expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + } else { + // Generate: + // &match (&arg0, &arg1, &…) { + // args => [ + // <core::fmt::Argument>::new_display(args.0), + // <core::fmt::Argument>::new_lower_hex(args.1), + // <core::fmt::Argument>::new_debug(args.0), + // … + // ] + // } + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let arg = self.alloc_expr_desugared(Expr::Ref { + expr: arguments[arg_index].expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + self.make_argument(arg, ty) + }) + .collect(); + let array = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + self.alloc_expr_desugared(Expr::Ref { + expr: array, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }; + + // Generate: + // <core::fmt::Arguments>::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // unsafe { ::core::fmt::UnsafeArg::new() } + // ) + + let lang_items = self.lang_items(); + let new_v1_formatted = + self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new_v1_formatted); + let unsafe_arg_new = + self.ty_rel_lang_path_desugared_expr(lang_items.FormatUnsafeArg, sym::new); + let unsafe_arg_new = + self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() }); + let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe { + id: None, + statements: Box::new([]), + tail: Some(unsafe_arg_new), + }); + if !fmt.orphans.is_empty() { + unsafe_arg_new = self.alloc_expr_desugared(Expr::Block { + id: None, + // We collect the unused expressions here so that we still infer them instead of + // dropping them out of the expression tree. We cannot store them in the `Unsafe` + // block because then unsafe blocks within them will get a false "unused unsafe" + // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't). + statements: fmt + .orphans + .into_iter() + .map(|expr| Statement::Expr { expr, has_semi: true }) + .collect(), + tail: Some(unsafe_arg_new), + label: None, + }); + } + + self.alloc_expr( + Expr::Call { + callee: new_v1_formatted, + args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), + }, + syntax_ptr, + ) + } + + /// `format_args!` expansion implementation for rustc versions >= `1.89.0`, + /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748) + fn collect_format_args_after_1_89_0_impl( + &mut self, + syntax_ptr: AstPtr<ast::Expr>, + fmt: FormatArgs, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { + let arguments = &*fmt.arguments.arguments; + + let (let_stmts, args) = if arguments.is_empty() { + ( + // Generate: + // [] + vec![], + self.alloc_expr_desugared(Expr::Array(Array::ElementList { + elements: Box::default(), + })), + ) + } else if argmap.len() == 1 && arguments.len() == 1 { + // Only one argument, so we don't need to make the `args` tuple. + // + // Generate: + // super let args = [<core::fmt::Arguments>::new_display(&arg)]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let ref_arg = self.alloc_expr_desugared(Expr::Ref { + expr: arguments[arg_index].expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + self.make_argument(ref_arg, ty) + }) + .collect(); + let args = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_name = self.generate_new_name(); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + // TODO: We don't have `super let` yet. + let let_stmt = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args), + else_branch: None, + }; + (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into()))) + } else { + // Generate: + // super let args = (&arg0, &arg1, &...); + let args_name = self.generate_new_name(); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let elements = arguments + .iter() + .map(|arg| { + self.alloc_expr_desugared(Expr::Ref { + expr: arg.expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }) + .collect(); + let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); + // TODO: We don't have `super let` yet + let let_stmt1 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args_tuple), + else_branch: None, + }; + + // Generate: + // super let args = [ + // <core::fmt::Argument>::new_display(args.0), + // <core::fmt::Argument>::new_lower_hex(args.1), + // <core::fmt::Argument>::new_debug(args.0), + // … + // ]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let args_ident_expr = + self.alloc_expr_desugared(Expr::Path(args_name.clone().into())); + let arg = self.alloc_expr_desugared(Expr::Field { + expr: args_ident_expr, + name: Name::new_tuple_field(arg_index), + }); + self.make_argument(arg, ty) + }) + .collect(); + let array = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let let_stmt2 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(array), + else_branch: None, + }; + (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into()))) + }; + + // Generate: + // &args + let args = self.alloc_expr_desugared(Expr::Ref { + expr: args, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + + let call_block = { + // Generate: + // unsafe { + // <core::fmt::Arguments>::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // ) + // } + + let new_v1_formatted = self.ty_rel_lang_path_desugared_expr( + self.lang_items().FormatArguments, + sym::new_v1_formatted, + ); + let args = [lit_pieces, args, format_options]; + let call = self + .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() }); + + Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) } + }; + + if !let_stmts.is_empty() { + // Generate: + // { + // super let … + // super let … + // <core::fmt::Arguments>::new_…(…) + // } + let call = self.alloc_expr_desugared(call_block); + self.alloc_expr( + Expr::Block { + id: None, + statements: let_stmts.into(), + tail: Some(call), + label: None, + }, + syntax_ptr, + ) + } else { + self.alloc_expr(call_block, syntax_ptr) + } + } + + /// Generate a hir expression for a format_args placeholder specification. + /// + /// Generates + /// + /// ```text + /// <core::fmt::rt::Placeholder::new( + /// …usize, // position + /// '…', // fill + /// <core::fmt::rt::Alignment>::…, // alignment + /// …u32, // flags + /// <core::fmt::rt::Count::…>, // width + /// <core::fmt::rt::Count::…>, // precision + /// ) + /// ``` + fn make_format_spec( + &mut self, + placeholder: &FormatPlaceholder, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, + ) -> ExprId { + let lang_items = self.lang_items(); + let position = match placeholder.argument.index { + Ok(arg_index) => { + let (i, _) = + argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); + self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + i as u128, + Some(BuiltinUint::Usize), + ))) + } + Err(_) => self.missing_expr(), + }; + let &FormatOptions { + ref width, + ref precision, + alignment, + fill, + sign, + alternate, + zero_pad, + debug_hex, + } = &placeholder.format_options; + + let precision_expr = self.make_count_before_1_93_0(precision, argmap); + let width_expr = self.make_count_before_1_93_0(width, argmap); + + if self.krate.workspace_data(self.db).is_atleast_187() { + // These need to match the constants in library/core/src/fmt/rt.rs. + let align = match alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + // This needs to match `Flag` in library/core/src/fmt/rt.rs. + let flags = fill.unwrap_or(' ') as u32 + | ((sign == Some(FormatSign::Plus)) as u32) << 21 + | ((sign == Some(FormatSign::Minus)) as u32) << 22 + | (alternate as u32) << 23 + | (zero_pad as u32) << 24 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (width.is_some() as u32) << 27 + | (precision.is_some() as u32) << 28 + | align << 29 + | 1 << 31; // Highest bit always set. + let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + flags as u128, + Some(BuiltinUint::U32), + ))); + + let position = + RecordLitField { name: Name::new_symbol_root(sym::position), expr: position }; + let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags }; + let precision = RecordLitField { + name: Name::new_symbol_root(sym::precision), + expr: precision_expr, + }; + let width = + RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr }; + self.alloc_expr_desugared(Expr::RecordLit { + path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new), + fields: Box::new([position, flags, precision, width]), + spread: None, + }) + } else { + let format_placeholder_new = + self.ty_rel_lang_path_desugared_expr(lang_items.FormatPlaceholder, sym::new); + // This needs to match `Flag` in library/core/src/fmt/rt.rs. + let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) + | (((sign == Some(FormatSign::Minus)) as u32) << 1) + | ((alternate as u32) << 2) + | ((zero_pad as u32) << 3) + | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4) + | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5); + let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + flags as u128, + Some(BuiltinUint::U32), + ))); + let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' ')))); + let align = self.ty_rel_lang_path_desugared_expr( + lang_items.FormatAlignment, + match alignment { + Some(FormatAlignment::Left) => sym::Left, + Some(FormatAlignment::Right) => sym::Right, + Some(FormatAlignment::Center) => sym::Center, + None => sym::Unknown, + }, + ); + self.alloc_expr_desugared(Expr::Call { + callee: format_placeholder_new, + args: Box::new([position, fill, align, flags, precision_expr, width_expr]), + }) + } + } + + /// Generate a hir expression for a format_args Count. + /// + /// Generates: + /// + /// ```text + /// <core::fmt::rt::Count>::Is(…) + /// ``` + /// + /// or + /// + /// ```text + /// <core::fmt::rt::Count>::Param(…) + /// ``` + /// + /// or + /// + /// ```text + /// <core::fmt::rt::Count>::Implied + /// ``` + fn make_count_before_1_93_0( + &mut self, + count: &Option<FormatCount>, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, + ) -> ExprId { + let lang_items = self.lang_items(); + match count { + Some(FormatCount::Literal(n)) => { + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + *n as u128, + // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88 + None, + ))); + let count_is = + self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Is); + self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) }) + } + Some(FormatCount::Argument(arg)) => { + if let Ok(arg_index) = arg.index { + let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); + + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + i as u128, + Some(BuiltinUint::Usize), + ))); + let count_param = + self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Param); + self.alloc_expr_desugared(Expr::Call { + callee: count_param, + args: Box::new([args]), + }) + } else { + // FIXME: This drops arg causing it to potentially not be resolved/type checked + // when typing? + self.missing_expr() + } + } + None => match self.ty_rel_lang_path(lang_items.FormatCount, sym::Implied) { + Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), + None => self.missing_expr(), + }, + } + } + + /// Generate a hir expression representing an argument to a format_args invocation. + /// + /// Generates: + /// + /// ```text + /// <core::fmt::Argument>::new_…(arg) + /// ``` + fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId { + use ArgumentType::*; + use FormatTrait::*; + + let new_fn = self.ty_rel_lang_path_desugared_expr( + self.lang_items().FormatArgument, + match ty { + Format(Display) => sym::new_display, + Format(Debug) => sym::new_debug, + Format(LowerExp) => sym::new_lower_exp, + Format(UpperExp) => sym::new_upper_exp, + Format(Octal) => sym::new_octal, + Format(Pointer) => sym::new_pointer, + Format(Binary) => sym::new_binary, + Format(LowerHex) => sym::new_lower_hex, + Format(UpperHex) => sym::new_upper_hex, + Usize => sym::from_usize, + }, + ); + self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) }) + } + + fn ty_rel_lang_path_desugared_expr( + &mut self, + lang: Option<impl Into<LangItemTarget>>, + relative_name: Symbol, + ) -> ExprId { + self.alloc_expr_desugared(self.ty_rel_lang_path_expr(lang, relative_name)) + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum ArgumentType { + Format(FormatTrait), + Usize, +} diff --git a/crates/hir-def/src/expr_store/tests/body.rs b/crates/hir-def/src/expr_store/tests/body.rs index 4a775568bc..504c310684 100644 --- a/crates/hir-def/src/expr_store/tests/body.rs +++ b/crates/hir-def/src/expr_store/tests/body.rs @@ -32,14 +32,14 @@ fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { let (db, position) = TestDB::with_position(ra_fixture); let module = db.module_at_position(position); - module.def_map(&db).dump(&db) + salsa::plumbing::attach(&db, || module.def_map(&db).dump(&db)) } fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, position) = TestDB::with_position(ra_fixture); let module = db.module_at_position(position); - let actual = module.def_map(&db).dump_block_scopes(&db); + let actual = salsa::plumbing::attach(&db, || format!("{module:#?}")); expect.assert_eq(&actual); } @@ -161,9 +161,9 @@ fn main() { match builtin#lang(into_iter)( 0..10, ) { - mut <ra@gennew>11 => loop { + mut <ra@gennew>0 => loop { match builtin#lang(next)( - &mut <ra@gennew>11, + &mut <ra@gennew>0, ) { builtin#lang(None) => break, builtin#lang(Some)(ident) => { @@ -261,10 +261,10 @@ fn main() { } #[test] -fn desugar_builtin_format_args() { +fn desugar_builtin_format_args_before_1_93_0() { let (db, body, def) = lower( r#" -//- minicore: fmt +//- minicore: fmt_before_1_93_0 fn main() { let are = "are"; let count = 10; @@ -278,16 +278,16 @@ fn main() { let are = "are"; let count = 10; { - let args = (&"fancy", &(), &"!", &count, &are, ); - let args = [ + let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, ); + let <ra@gennew>0 = [ builtin#lang(Argument::new_display)( - args.3, + <ra@gennew>0.3, ), builtin#lang(Argument::new_display)( - args.0, + <ra@gennew>0.0, ), builtin#lang(Argument::new_debug)( - args.4, + <ra@gennew>0.4, ), builtin#lang(Argument::new_display)( - args.2, + <ra@gennew>0.2, ), ]; unsafe { @@ -295,7 +295,7 @@ fn main() { &[ "\u{1b}hello ", " ", " friends, we ", " ", "", ], - &args, + &<ra@gennew>0, &[ builtin#lang(Placeholder::new)( 0usize, @@ -344,6 +344,59 @@ fn main() { } #[test] +fn desugar_builtin_format_args() { + let (db, body, def) = lower( + r#" +//- minicore: fmt +fn main() { + let are = "are"; + let count = 10; + builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); + builtin#format_args("hello world"); + builtin#format_args("hello world", orphan = ()); +} +"#, + ); + + expect![[r#" + fn main() { + let are = "are"; + let count = 10; + { + let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, ); + let <ra@gennew>0 = [ + builtin#lang(Argument::new_display)( + <ra@gennew>0.3, + ), builtin#lang(Argument::new_display)( + <ra@gennew>0.0, + ), builtin#lang(Argument::new_debug)( + <ra@gennew>0.4, + ), builtin#lang(Argument::new_display)( + <ra@gennew>0.2, + ), + ]; + (); + unsafe { + builtin#lang(Arguments::new)( + "\x07\x1bhello \xc3 \x00\x00i\x02\x00\x01 \xc0\r friends, we \xc0\x01 \xc8\x01\x00\xc8\x03\x00\x00", + &<ra@gennew>0, + ) + } + }; + builtin#lang(Arguments::from_str)( + "hello world", + ); + { + (); + builtin#lang(Arguments::from_str)( + "hello world", + ) + }; + }"#]] + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) +} + +#[test] fn test_macro_hygiene() { let (db, body, def) = lower( r##" @@ -382,27 +435,16 @@ impl SsrError { fn main() { _ = ra_test_fixture::error::SsrError::new( { - let args = [ + let <ra@gennew>0 = (&node.text(), ); + let <ra@gennew>0 = [ builtin#lang(Argument::new_display)( - &node.text(), + <ra@gennew>0.0, ), ]; unsafe { - builtin#lang(Arguments::new_v1_formatted)( - &[ - "Failed to resolve path `", "`", - ], - &args, - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], + builtin#lang(Arguments::new)( + "\x18Failed to resolve path `\xc0\x01`\x00", + &<ra@gennew>0, ) } }, diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs index 4501ff4df5..836a079e77 100644 --- a/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/crates/hir-def/src/expr_store/tests/body/block.rs @@ -189,10 +189,17 @@ fn f() { } "#, expect![[r#" - BlockId(3801) in BlockRelativeModuleId { block: Some(BlockId(3800)), local_id: Idx::<ModuleData>(1) } - BlockId(3800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) } - crate scope - "#]], + ModuleIdLt { + [salsa id]: Id(3003), + krate: Crate( + Id(1c00), + ), + block: Some( + BlockId( + 3c01, + ), + ), + }"#]], ); } @@ -460,7 +467,7 @@ fn foo() { } #[test] -fn is_visible_from_same_def_map() { +fn is_visible_from_same_def_map_regression_9481() { // Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481 check_at( r#" @@ -478,7 +485,6 @@ fn outer() { - tests : type (block scope)::tests - - name : _ - outer : value (glob) crate diff --git a/crates/hir-def/src/expr_store/tests/signatures.rs b/crates/hir-def/src/expr_store/tests/signatures.rs index 2dac4e7fc8..f1db00cf6a 100644 --- a/crates/hir-def/src/expr_store/tests/signatures.rs +++ b/crates/hir-def/src/expr_store/tests/signatures.rs @@ -197,3 +197,15 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} "#]], ); } + +#[test] +fn regression_21138() { + lower_and_print( + r#" +fn foo(v: for<'a> Trait1 + Trait2) {} + "#, + expect![[r#" + fn foo(dyn for<'a> Trait1 + Trait2) {...} + "#]], + ); +} diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index e8a6ebcffa..5d1cac8e93 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -39,20 +39,23 @@ pub fn find_path( // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so // default to plain paths. let item_module = item.module(db)?; - if item_module.is_within_block() { + if item_module.block(db).is_some() { prefix_kind = PrefixKind::Plain; } - cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate()); + cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate(db)); + let from_def_map = from.def_map(db); find_path_inner( &FindPathCtx { db, prefix: prefix_kind, cfg, ignore_local_imports, - is_std_item: item_module.krate().data(db).origin.is_lang(), + is_std_item: item_module.krate(db).data(db).origin.is_lang(), from, - from_def_map: from.def_map(db), + from_crate: from.krate(db), + crate_root: from_def_map.crate_root(db), + from_def_map, fuel: Cell::new(FIND_PATH_FUEL), }, item, @@ -100,6 +103,8 @@ struct FindPathCtx<'db> { ignore_local_imports: bool, is_std_item: bool, from: ModuleId, + from_crate: Crate, + crate_root: ModuleId, from_def_map: &'db DefMap, fuel: Cell<usize>, } @@ -116,7 +121,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => ctx.from.is_crate_root(), + PrefixKind::ByCrate => ctx.crate_root == ctx.from, }; if may_be_in_scope { // - if the item is already in scope, return the name under which it is @@ -163,8 +168,9 @@ fn find_path_for_module( // recursive base case, we can't find a path of length 0 return None; } - if let Some(crate_root) = module_id.as_crate_root() { - if !maybe_extern || crate_root == ctx.from.derive_crate_root() { + let module_crate_root = module_id.def_map(ctx.db).crate_root(ctx.db); + if module_crate_root == module_id { + if !maybe_extern || module_crate_root == ctx.crate_root { // - if the item is the crate root, return `crate` return Some(Choice { path: ModPath::from_segments(PathKind::Crate, None), @@ -175,19 +181,19 @@ fn find_path_for_module( } // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude - let root_local_def_map = ctx.from.derive_crate_root().local_def_map(ctx.db).1; + let root_local_def_map = ctx.crate_root.local_def_map(ctx.db).1; // rev here so we prefer looking at renamed extern decls first for (name, (def_id, _extern_crate)) in root_local_def_map.extern_prelude().rev() { - if crate_root != def_id { + if module_crate_root != def_id { continue; } let name_already_occupied_in_type_ns = ctx .from_def_map - .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| { + .with_ancestor_maps(ctx.db, ctx.from, &mut |def_map, local_id| { def_map[local_id] .scope .type_(name) - .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into())) + .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id)) }) .is_some(); let kind = if name_already_occupied_in_type_ns { @@ -204,7 +210,7 @@ fn find_path_for_module( let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => ctx.from.is_crate_root(), + PrefixKind::ByCrate => ctx.crate_root == ctx.from, }; if may_be_in_scope { let scope_name = find_in_scope( @@ -226,7 +232,7 @@ fn find_path_for_module( } // - if the module can be referenced as self, super or crate, do that - if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) + if let Some(kind) = is_kw_kind_relative_to_from(ctx.db, ctx.from_def_map, module_id, ctx.from) && (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate) { return Some(Choice { @@ -259,7 +265,7 @@ fn find_in_scope( ignore_local_imports: bool, ) -> Option<Name> { // FIXME: We could have multiple applicable names here, but we currently only return the first - def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| { def_map[local_id].scope.names_of(item, |name, _, declared| { (declared || !ignore_local_imports).then(|| name.clone()) }) @@ -276,7 +282,7 @@ fn find_in_prelude( ) -> Option<Choice> { let (prelude_module, _) = local_def_map.prelude()?; let prelude_def_map = prelude_module.def_map(db); - let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; + let prelude_scope = &prelude_def_map[prelude_module].scope; let (name, vis, _declared) = prelude_scope.name_of(item)?; if !vis.is_visible_from(db, from) { return None; @@ -284,7 +290,7 @@ fn find_in_prelude( // Check if the name is in current scope and it points to the same def. let found_and_same_def = - local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + local_def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| { let per_ns = def_map[local_id].scope.get(name); let same_def = match item { ItemInNs::Types(it) => per_ns.take_types()? == it, @@ -302,22 +308,21 @@ fn find_in_prelude( } fn is_kw_kind_relative_to_from( + db: &dyn DefDatabase, def_map: &DefMap, item: ModuleId, from: ModuleId, ) -> Option<PathKind> { - if item.krate != from.krate || item.is_within_block() || from.is_within_block() { + if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() { return None; } - let item = item.local_id; - let from = from.local_id; if item == from { // - if the item is the module we're in, use `self` Some(PathKind::SELF) } else if let Some(parent_id) = def_map[from].parent { if item == parent_id { // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) - Some(if parent_id == DefMap::ROOT { PathKind::Crate } else { PathKind::Super(1) }) + Some(if parent_id == def_map.root { PathKind::Crate } else { PathKind::Super(1) }) } else { None } @@ -340,13 +345,13 @@ fn calculate_best_path( tracing::warn!( "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}", item.krate(ctx.db), - ctx.from.krate() + ctx.from_crate ); return; } ctx.fuel.set(fuel - 1); - if item.krate(ctx.db) == Some(ctx.from.krate) { + if item.krate(ctx.db) == Some(ctx.from_crate) { // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice) @@ -361,7 +366,7 @@ fn calculate_best_path( // too (unless we can't name it at all). It could *also* be (re)exported by the same crate // that wants to import it here, but we always prefer to use the external path here. - ctx.from.krate.data(ctx.db).dependencies.iter().for_each(|dep| { + ctx.from_crate.data(ctx.db).dependencies.iter().for_each(|dep| { find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id) }); } @@ -374,7 +379,7 @@ fn find_in_sysroot( max_len: usize, best_choice: &mut Option<Choice>, ) { - let dependencies = &ctx.from.krate.data(ctx.db).dependencies; + let dependencies = &ctx.from_crate.data(ctx.db).dependencies; let mut search = |lang, best_choice: &mut _| { if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| { match dep.crate_id.data(ctx.db).origin { @@ -464,26 +469,19 @@ fn calculate_best_path_local( best_choice: &mut Option<Choice>, ) { // FIXME: cache the `find_local_import_locations` output? - find_local_import_locations( - ctx.db, - item, - ctx.from, - ctx.from_def_map, - visited_modules, - |visited_modules, name, module_id| { - // we are looking for paths of length up to best_path_len, any longer will make it be - // less optimal. The -1 is due to us pushing name onto it afterwards. - if let Some(choice) = find_path_for_module( - ctx, - visited_modules, - module_id, - false, - best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1, - ) { - Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone()); - } - }, - ); + find_local_import_locations(ctx, item, visited_modules, |visited_modules, name, module_id| { + // we are looking for paths of length up to best_path_len, any longer will make it be + // less optimal. The -1 is due to us pushing name onto it afterwards. + if let Some(choice) = find_path_for_module( + ctx, + visited_modules, + module_id, + false, + best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1, + ) { + Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone()); + } + }); } #[derive(Debug)] @@ -561,14 +559,13 @@ fn path_kind_len(kind: PathKind) -> usize { /// Finds locations in `from.krate` from which `item` can be imported by `from`. fn find_local_import_locations( - db: &dyn DefDatabase, + ctx: &FindPathCtx<'_>, item: ItemInNs, - from: ModuleId, - def_map: &DefMap, visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId), ) { let _p = tracing::info_span!("find_local_import_locations").entered(); + let db = ctx.db; // `from` can import anything below `from` with visibility of at least `from`, and anything // above `from` with any visibility. That means we do not need to descend into private siblings @@ -576,15 +573,16 @@ fn find_local_import_locations( // Compute the initial worklist. We start with all direct child modules of `from` as well as all // of its (recursive) parent modules. - let mut worklist = def_map[from.local_id] + let mut worklist = ctx.from_def_map[ctx.from] .children .values() - .map(|&child| def_map.module_id(child)) - .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db))) + .copied() + .chain(iter::successors(ctx.from.containing_module(db), |m| m.containing_module(db))) .zip(iter::repeat(false)) .collect::<Vec<_>>(); - let def_map = def_map.crate_root().def_map(db); + let def_map = + if ctx.crate_root == ctx.from { ctx.from_def_map } else { ctx.crate_root.def_map(db) }; let mut block_def_map; let mut cursor = 0; @@ -595,17 +593,17 @@ fn find_local_import_locations( continue; } *processed = true; - let data = if module.block.is_some() { + let data = if module.block(db).is_some() { // Re-query the block's DefMap block_def_map = module.def_map(db); - &block_def_map[module.local_id] + &block_def_map[module] } else { // Reuse the root DefMap - &def_map[module.local_id] + &def_map[module] }; if let Some((name, vis, declared)) = data.scope.name_of(item) - && vis.is_visible_from(db, from) + && vis.is_visible_from(db, ctx.from) { let is_pub_or_explicit = match vis { Visibility::Module(_, VisibilityExplicitness::Explicit) => { @@ -632,7 +630,7 @@ fn find_local_import_locations( // Descend into all modules visible from `from`. for (module, vis) in data.scope.modules_in_scope() { - if module.krate != from.krate { + if module.krate(db) != ctx.from.krate(db) { // We don't need to look at modules from other crates as our item has to be in the // current crate continue; @@ -641,7 +639,7 @@ fn find_local_import_locations( continue; } - if vis.is_visible_from(db, from) { + if vis.is_visible_from(db, ctx.from) { worklist.push((module, false)); } } @@ -694,7 +692,7 @@ mod tests { .resolve_path( local_def_map, &db, - module.local_id, + module, &mod_path, crate::item_scope::BuiltinShadowMode::Module, None, diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs index 60cd66bf6b..1a2d5ebba4 100644 --- a/crates/hir-def/src/hir/generics.rs +++ b/crates/hir-def/src/hir/generics.rs @@ -20,7 +20,7 @@ pub type LocalLifetimeParamId = Idx<LifetimeParamData>; /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { - /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just + /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just /// make it always be a value, giving impl trait a special name. pub name: Option<Name>, pub default: Option<TypeRefId>, diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 67cf466276..6c5d226cac 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -13,11 +13,11 @@ use stdx::format_to; use triomphe::Arc; use crate::{ - AssocItemId, AttrDefId, Complete, FxIndexMap, InternedModuleId, ModuleDefId, ModuleId, TraitId, + AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId, attrs::AttrFlags, db::DefDatabase, item_scope::{ImportOrExternCrate, ItemInNs}, - nameres::{DefMap, assoc::TraitItems, crate_def_map}, + nameres::{assoc::TraitItems, crate_def_map}, visibility::Visibility, }; @@ -134,7 +134,7 @@ impl ImportMap { let mut map = FxIndexMap::default(); // We look only into modules that are public(ly reexported), starting with the crate root. - let root = def_map.module_id(DefMap::ROOT); + let root = def_map.root_module_id(); let mut worklist = vec![root]; let mut visited = FxHashSet::default(); @@ -142,13 +142,11 @@ impl ImportMap { if !visited.insert(module) { continue; } - let ext_def_map; - let mod_data = if module.krate == krate { - &def_map[module.local_id] + let mod_data = if module.krate(db) == krate { + &def_map[module] } else { // The crate might reexport a module defined in another crate. - ext_def_map = module.def_map(db); - &ext_def_map[module.local_id] + &module.def_map(db)[module] }; let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { @@ -167,9 +165,7 @@ impl ImportMap { } else { match item { ItemInNs::Types(id) | ItemInNs::Values(id) => match id { - ModuleDefId::ModuleId(it) => { - Some(AttrDefId::ModuleId(InternedModuleId::new(db, it))) - } + ModuleDefId::ModuleId(it) => Some(AttrDefId::ModuleId(it)), ModuleDefId::FunctionId(it) => Some(it.into()), ModuleDefId::AdtId(it) => Some(it.into()), ModuleDefId::EnumVariantId(it) => Some(it.into()), @@ -640,9 +636,8 @@ mod tests { assert!(def_map.block_id().is_none(), "block local items should not be in `ImportMap`"); while let Some(parent) = module.containing_module(db) { - let parent_data = &def_map[parent.local_id]; - let (name, _) = - parent_data.children.iter().find(|(_, id)| **id == module.local_id).unwrap(); + let parent_data = &def_map[parent]; + let (name, _) = parent_data.children.iter().find(|(_, id)| **id == module).unwrap(); segments.push(name); module = parent; } diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 1bfe649ebd..3ffeebfaf2 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -17,7 +17,7 @@ use thin_vec::ThinVec; use crate::{ AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId, - LocalModuleId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId, + Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId, db::DefDatabase, per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem}, visibility::Visibility, @@ -25,9 +25,9 @@ use crate::{ #[derive(Debug, Default)] pub struct PerNsGlobImports { - types: FxHashSet<(LocalModuleId, Name)>, - values: FxHashSet<(LocalModuleId, Name)>, - macros: FxHashSet<(LocalModuleId, Name)>, + types: FxHashSet<(ModuleId, Name)>, + values: FxHashSet<(ModuleId, Name)>, + macros: FxHashSet<(ModuleId, Name)>, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -133,13 +133,13 @@ pub struct GlobId { } impl PerNsGlobImports { - pub(crate) fn contains_type(&self, module_id: LocalModuleId, name: Name) -> bool { + pub(crate) fn contains_type(&self, module_id: ModuleId, name: Name) -> bool { self.types.contains(&(module_id, name)) } - pub(crate) fn contains_value(&self, module_id: LocalModuleId, name: Name) -> bool { + pub(crate) fn contains_value(&self, module_id: ModuleId, name: Name) -> bool { self.values.contains(&(module_id, name)) } - pub(crate) fn contains_macro(&self, module_id: LocalModuleId, name: Name) -> bool { + pub(crate) fn contains_macro(&self, module_id: ModuleId, name: Name) -> bool { self.macros.contains(&(module_id, name)) } } @@ -261,14 +261,12 @@ impl ItemScope { pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs { let mut res = PerNs::none(); - let mut def_map; let mut scope = self; while let Some(&m) = scope.use_imports_macros.get(&ImportOrExternCrate::Import(import)) { match m { ImportOrDef::Import(i) => { let module_id = i.use_.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; + scope = &module_id.def_map(db)[module_id].scope; import = i; } ImportOrDef::Def(ModuleDefId::MacroId(def)) => { @@ -283,8 +281,7 @@ impl ItemScope { match m { ImportOrDef::Import(i) => { let module_id = i.use_.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; + scope = &module_id.def_map(db)[module_id].scope; import = i; } ImportOrDef::Def(def) => { @@ -299,8 +296,7 @@ impl ItemScope { match m { ImportOrDef::Import(i) => { let module_id = i.use_.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; + scope = &module_id.def_map(db)[module_id].scope; import = i; } ImportOrDef::Def(def) => { @@ -578,7 +574,7 @@ impl ItemScope { pub(crate) fn push_res_with_import( &mut self, glob_imports: &mut PerNsGlobImports, - lookup: (LocalModuleId, Name), + lookup: (ModuleId, Name), def: PerNs, import: Option<ImportOrExternCrate>, ) -> bool { @@ -922,10 +918,7 @@ impl ItemInNs { /// Returns the crate defining this item (or `None` if `self` is built-in). pub fn krate(&self, db: &dyn DefDatabase) -> Option<Crate> { - match self { - ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate), - ItemInNs::Macros(id) => Some(id.module(db).krate), - } + self.module(db).map(|module_id| module_id.krate(db)) } pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> { diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 3f2cf09e21..9fdfb5f5b3 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -111,11 +111,12 @@ pub fn lang_items(db: &dyn DefDatabase, start_crate: Crate) -> LangItems { // while nameres. // // See https://github.com/rust-lang/rust-analyzer/pull/20475 for details. - for (_, (krate, _)) in crate_local_def_map(db, start_crate).local(db).extern_prelude() { + for (_, (module, _)) in crate_local_def_map(db, start_crate).local(db).extern_prelude() { // Some crates declares themselves as extern crate like `extern crate self as core`. // Ignore these to prevent cycles. - if krate.krate != start_crate { - result.merge_prefer_self(lang_items(db, krate.krate)); + let krate = module.krate(db); + if krate != start_crate { + result.merge_prefer_self(lang_items(db, krate)); } } @@ -238,7 +239,7 @@ language_item_table! { LangItems => Clone, sym::clone, clone_trait, TraitId, GenericRequirement::None; Sync, sym::sync, sync_trait, TraitId, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, TraitId, GenericRequirement::None; - /// The associated item of the [`DiscriminantKind`] trait. + /// The associated item of the `DiscriminantKind` trait. Discriminant, sym::discriminant_type, discriminant_type, TypeAliasId, GenericRequirement::None; PointeeTrait, sym::pointee_trait, pointee_trait, TraitId, GenericRequirement::None; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index ad247e0d68..97af8ad93d 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -71,7 +71,6 @@ use hir_expand::{ name::Name, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, }; -use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; @@ -412,14 +411,14 @@ pub enum MacroExpander { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProcMacroLoc { - pub container: CrateRootModuleId, + pub container: ModuleId, pub id: AstId<ast::Fn>, pub expander: CustomProcMacroExpander, pub kind: ProcMacroKind, pub edition: Edition, } impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro); -impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId); +impl_loc!(ProcMacroLoc, id: Fn, container: ModuleId); #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct BlockLoc { @@ -429,164 +428,75 @@ pub struct BlockLoc { } impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); -/// A `ModuleId` that is always a crate's root module. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct CrateRootModuleId { - krate: Crate, -} - -impl CrateRootModuleId { - pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap { - crate_def_map(db, self.krate) - } - - pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) { - let def_map = crate_local_def_map(db, self.krate); - (def_map.def_map(db), def_map.local(db)) - } - - pub fn krate(self) -> Crate { - self.krate - } -} - -impl HasModule for CrateRootModuleId { - #[inline] - fn module(&self, _db: &dyn DefDatabase) -> ModuleId { - ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } - } - - #[inline] - fn krate(&self, _db: &dyn DefDatabase) -> Crate { - self.krate - } -} - -impl PartialEq<ModuleId> for CrateRootModuleId { - fn eq(&self, other: &ModuleId) -> bool { - other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate - } -} -impl PartialEq<CrateRootModuleId> for ModuleId { - fn eq(&self, other: &CrateRootModuleId) -> bool { - other == self - } -} - -impl From<CrateRootModuleId> for ModuleId { - fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { - ModuleId { krate, block: None, local_id: DefMap::ROOT } - } -} - -impl From<CrateRootModuleId> for ModuleDefId { - fn from(value: CrateRootModuleId) -> Self { - ModuleDefId::ModuleId(value.into()) - } -} - -impl From<Crate> for CrateRootModuleId { - fn from(krate: Crate) -> Self { - CrateRootModuleId { krate } - } -} - -impl TryFrom<ModuleId> for CrateRootModuleId { - type Error = (); - - fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result<Self, Self::Error> { - if block.is_none() && local_id == DefMap::ROOT { - Ok(CrateRootModuleId { krate }) - } else { - Err(()) - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ModuleId { - krate: Crate, +#[salsa_macros::tracked(debug)] +#[derive(PartialOrd, Ord)] +pub struct ModuleIdLt<'db> { + /// The crate this module belongs to. + pub krate: Crate, /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the /// `BlockId` of that block expression. If `None`, this module is part of the crate-level /// `DefMap` of `krate`. - block: Option<BlockId>, - /// The module's ID in its originating `DefMap`. - pub local_id: LocalModuleId, + pub block: Option<BlockId>, } +pub type ModuleId = ModuleIdLt<'static>; +impl ModuleIdLt<'_> { + /// # Safety + /// + /// The caller must ensure that the `ModuleId` is not leaked outside of query computations. + pub unsafe fn to_static(self) -> ModuleId { + unsafe { std::mem::transmute(self) } + } +} impl ModuleId { + /// # Safety + /// + /// The caller must ensure that the `ModuleId` comes from the given database. + pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> { + unsafe { std::mem::transmute(self) } + } + pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap { - match self.block { + match self.block(db) { Some(block) => block_def_map(db, block), - None => crate_def_map(db, self.krate), + None => crate_def_map(db, self.krate(db)), } } pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) { - match self.block { + match self.block(db) { Some(block) => (block_def_map(db, block), self.only_local_def_map(db)), None => { - let def_map = crate_local_def_map(db, self.krate); + let def_map = crate_local_def_map(db, self.krate(db)); (def_map.def_map(db), def_map.local(db)) } } } pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap { - crate_local_def_map(db, self.krate).local(db) + crate_local_def_map(db, self.krate(db)).local(db) } pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap { - crate_def_map(db, self.krate) - } - - pub fn krate(self) -> Crate { - self.krate + crate_def_map(db, self.krate(db)) } pub fn name(self, db: &dyn DefDatabase) -> Option<Name> { let def_map = self.def_map(db); - let parent = def_map[self.local_id].parent?; + let parent = def_map[self].parent?; def_map[parent].children.iter().find_map(|(name, module_id)| { - if *module_id == self.local_id { Some(name.clone()) } else { None } + if *module_id == self { Some(name.clone()) } else { None } }) } /// Returns the module containing `self`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. pub fn containing_module(self, db: &dyn DefDatabase) -> Option<ModuleId> { - self.def_map(db).containing_module(self.local_id) - } - - pub fn containing_block(self) -> Option<BlockId> { - self.block - } - - pub fn is_block_module(self) -> bool { - self.block.is_some() && self.local_id == DefMap::ROOT + self.def_map(db).containing_module(self) } - pub fn is_within_block(self) -> bool { - self.block.is_some() - } - - /// Returns the [`CrateRootModuleId`] for this module if it is the crate root module. - pub fn as_crate_root(&self) -> Option<CrateRootModuleId> { - if self.local_id == DefMap::ROOT && self.block.is_none() { - Some(CrateRootModuleId { krate: self.krate }) - } else { - None - } - } - - /// Returns the [`CrateRootModuleId`] for this module. - pub fn derive_crate_root(&self) -> CrateRootModuleId { - CrateRootModuleId { krate: self.krate } - } - - /// Whether this module represents the crate root module - pub fn is_crate_root(&self) -> bool { - self.local_id == DefMap::ROOT && self.block.is_none() + pub fn is_block_module(self, db: &dyn DefDatabase) -> bool { + self.block(db).is_some() && self.def_map(db).root_module_id() == self } } @@ -597,9 +507,6 @@ impl HasModule for ModuleId { } } -/// An ID of a module, **local** to a `DefMap`. -pub type LocalModuleId = Idx<nameres::ModuleData>; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] pub struct FieldId { // FIXME: Store this as an erased `salsa::Id` to save space @@ -682,7 +589,7 @@ pub struct LifetimeParamId { pub local_id: LocalLifetimeParamId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum ItemContainerId { ExternBlockId(ExternBlockId), ModuleId(ModuleId), @@ -956,16 +863,9 @@ impl CallableDefId { } } -// FIXME: We probably should use this in more places. -/// This is used to avoid interning the whole `AttrDefId`, so we intern just modules and not everything. -#[salsa_macros::interned(debug, no_lifetime)] -pub struct InternedModuleId { - pub loc: ModuleId, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum AttrDefId { - ModuleId(InternedModuleId), + ModuleId(ModuleId), AdtId(AdtId), FunctionId(FunctionId), EnumVariantId(EnumVariantId), @@ -1058,7 +958,7 @@ pub trait HasModule { #[inline] #[doc(alias = "crate")] fn krate(&self, db: &dyn DefDatabase) -> Crate { - self.module(db).krate + self.module(db).krate(db) } } @@ -1162,7 +1062,7 @@ impl HasModule for Macro2Id { impl HasModule for ProcMacroId { #[inline] fn module(&self, db: &dyn DefDatabase) -> ModuleId { - self.lookup(db).container.into() + self.lookup(db).container } } @@ -1235,7 +1135,7 @@ impl HasModule for GenericDefId { impl HasModule for AttrDefId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { - AttrDefId::ModuleId(it) => it.loc(db), + AttrDefId::ModuleId(it) => *it, AttrDefId::AdtId(it) => it.module(db), AttrDefId::FunctionId(it) => it.module(db), AttrDefId::EnumVariantId(it) => it.module(db), diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 947a54f888..a12674f353 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -35,9 +35,9 @@ macro_rules! f { }; } -struct#0:MacroRules[BE8F, 0]@58..64#14336# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#14336# - map#0:MacroRules[BE8F, 0]@86..89#14336#:#0:MacroRules[BE8F, 0]@89..90#14336# #0:MacroRules[BE8F, 0]@89..90#14336#::#0:MacroRules[BE8F, 0]@91..93#14336#std#0:MacroRules[BE8F, 0]@93..96#14336#::#0:MacroRules[BE8F, 0]@96..98#14336#collections#0:MacroRules[BE8F, 0]@98..109#14336#::#0:MacroRules[BE8F, 0]@109..111#14336#HashSet#0:MacroRules[BE8F, 0]@111..118#14336#<#0:MacroRules[BE8F, 0]@118..119#14336#(#0:MacroRules[BE8F, 0]@119..120#14336#)#0:MacroRules[BE8F, 0]@120..121#14336#>#0:MacroRules[BE8F, 0]@121..122#14336#,#0:MacroRules[BE8F, 0]@122..123#14336# -}#0:MacroRules[BE8F, 0]@132..133#14336# +struct#0:MacroRules[BE8F, 0]@58..64#15360# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#15360# + map#0:MacroRules[BE8F, 0]@86..89#15360#:#0:MacroRules[BE8F, 0]@89..90#15360# #0:MacroRules[BE8F, 0]@89..90#15360#::#0:MacroRules[BE8F, 0]@91..93#15360#std#0:MacroRules[BE8F, 0]@93..96#15360#::#0:MacroRules[BE8F, 0]@96..98#15360#collections#0:MacroRules[BE8F, 0]@98..109#15360#::#0:MacroRules[BE8F, 0]@109..111#15360#HashSet#0:MacroRules[BE8F, 0]@111..118#15360#<#0:MacroRules[BE8F, 0]@118..119#15360#(#0:MacroRules[BE8F, 0]@119..120#15360#)#0:MacroRules[BE8F, 0]@120..121#15360#>#0:MacroRules[BE8F, 0]@121..122#15360#,#0:MacroRules[BE8F, 0]@122..123#15360# +}#0:MacroRules[BE8F, 0]@132..133#15360# "#]], ); } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1:MacroRules[DB0C, 0]@59..65#14336# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#14336#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#14336#;#1:MacroRules[DB0C, 0]@75..76#14336# +struct#1:MacroRules[DB0C, 0]@59..65#15360# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#15360#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#15360#;#1:MacroRules[DB0C, 0]@75..76#15360# "#]], ); } @@ -423,10 +423,10 @@ m! { foo, bar } macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } -impl#\14336# Bar#\14336# {#\14336# - fn#\14336# foo#\ROOT2024#(#\14336#)#\14336# {#\14336#}#\14336# - fn#\14336# bar#\ROOT2024#(#\14336#)#\14336# {#\14336#}#\14336# -}#\14336# +impl#\15360# Bar#\15360# {#\15360# + fn#\15360# foo#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360# + fn#\15360# bar#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360# +}#\15360# "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index 98b3115814..78af976e1b 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -131,8 +131,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); let krate = db.fetch_test_crate(); let def_map = crate_def_map(&db, krate); - let local_id = DefMap::ROOT; - let source = def_map[local_id].definition_source(&db); + let source = def_map[def_map.root].definition_source(&db); let source_file = match source.value { ModuleSource::SourceFile(it) => it, ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), @@ -209,7 +208,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream expanded_text.replace_range(range, &text); } - for decl_id in def_map[local_id].scope.declarations() { + for decl_id in def_map[def_map.root].scope.declarations() { // FIXME: I'm sure there's already better way to do this let src = match decl_id { ModuleDefId::AdtId(AdtId::StructId(struct_id)) => { @@ -260,7 +259,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } } - for impl_id in def_map[local_id].scope.impls() { + for impl_id in def_map[def_map.root].scope.impls() { let src = impl_id.lookup(&db).source(&db); if let Some(macro_file) = src.file_id.macro_file() && let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db) diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 5216246910..6f30ca04af 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -341,3 +341,22 @@ struct Foo; #[helper_should_be_ignored] struct Foo;"#]], ); } + +#[test] +fn attribute_macro_stripping_with_cfg() { + check( + r#" +//- proc_macros: generate_suffixed_type +#[cfg(all())] +#[proc_macros::generate_suffixed_type] +struct S; +"#, + expect![[r#" +#[cfg(all())] +#[proc_macros::generate_suffixed_type] +struct S; + +struct S; +struct SSuffix;"#]], + ); +} diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 5f45e188e0..3f29619bcb 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -58,7 +58,7 @@ pub mod proc_macro; #[cfg(test)] mod tests; -use std::ops::Deref; +use std::ops::{Deref, DerefMut, Index, IndexMut}; use base_db::Crate; use hir_expand::{ @@ -67,7 +67,6 @@ use hir_expand::{ }; use intern::Symbol; use itertools::Itertools; -use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID}; use stdx::format_to; @@ -76,8 +75,8 @@ use triomphe::Arc; use tt::TextRange; use crate::{ - AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap, - LocalModuleId, Lookup, MacroCallStyles, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, + AstId, BlockId, BlockLoc, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles, + MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId, db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, item_tree::TreeId, @@ -109,7 +108,7 @@ pub struct LocalDefMap { // FIXME: There are probably some other things that could be here, but this is less severe and you // need to be careful with things that block def maps also have. /// The extern prelude which contains all root modules of external crates that are in scope. - extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>, + extern_prelude: FxIndexMap<Name, (ModuleId, Option<ExternCrateId>)>, } impl std::hash::Hash for LocalDefMap { @@ -135,8 +134,7 @@ impl LocalDefMap { pub(crate) fn extern_prelude( &self, - ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ - { + ) -> impl DoubleEndedIterator<Item = (&Name, (ModuleId, Option<ExternCrateId>))> + '_ { self.extern_prelude.iter().map(|(name, &def)| (name, def)) } } @@ -157,8 +155,9 @@ pub struct DefMap { /// When this is a block def map, this will hold the block id of the block and module that /// contains this block. block: Option<BlockInfo>, + pub root: ModuleId, /// The modules and their data declared in this crate. - pub modules: Arena<ModuleData>, + pub modules: ModulesMap, /// The prelude module for this crate. This either comes from an import /// marked with the `prelude_import` attribute, or (in the normal case) from /// a dependency (`std` or `core`). @@ -245,33 +244,22 @@ struct BlockInfo { /// The `BlockId` this `DefMap` was created from. block: BlockId, /// The containing module. - parent: BlockRelativeModuleId, + parent: ModuleId, } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -struct BlockRelativeModuleId { - block: Option<BlockId>, - local_id: LocalModuleId, -} - -impl BlockRelativeModuleId { - fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap { - self.into_module(krate).def_map(db) - } - - fn into_module(self, krate: Crate) -> ModuleId { - ModuleId { krate, block: self.block, local_id: self.local_id } - } +impl std::ops::Index<ModuleId> for DefMap { + type Output = ModuleData; - fn is_block_module(self) -> bool { - self.block.is_some() && self.local_id == DefMap::ROOT + fn index(&self, id: ModuleId) -> &ModuleData { + self.modules + .get(&id) + .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap {:#?}: {id:#?}", self.root)) } } -impl std::ops::Index<LocalModuleId> for DefMap { - type Output = ModuleData; - fn index(&self, id: LocalModuleId) -> &ModuleData { - &self.modules[id] +impl std::ops::IndexMut<ModuleId> for DefMap { + fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData { + &mut self.modules[id] } } @@ -358,8 +346,8 @@ pub struct ModuleData { /// Parent module in the same `DefMap`. /// /// [`None`] for block modules because they are always its `DefMap`'s root. - pub parent: Option<LocalModuleId>, - pub children: FxIndexMap<Name, LocalModuleId>, + pub parent: Option<ModuleId>, + pub children: FxIndexMap<Name, ModuleId>, pub scope: ItemScope, } @@ -392,11 +380,19 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM .entered(); let root_file_id = crate_id.root_file_id(db); - let module_data = - ModuleData::new(ModuleOrigin::CrateRoot { definition: root_file_id }, Visibility::Public); + let module_data = ModuleData::new( + ModuleOrigin::CrateRoot { definition: root_file_id }, + Visibility::Public, + None, + ); - let def_map = - DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None); + let def_map = DefMap::empty( + db, + crate_id, + Arc::new(DefMapCrateData::new(krate.edition)), + module_data, + None, + ); let (def_map, local_def_map) = collector::collect_defs(db, def_map, TreeId::new(root_file_id.into(), None), None); @@ -407,22 +403,18 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { let BlockLoc { ast_id, module } = block_id.lookup(db); - let visibility = Visibility::Module( - ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block }, - VisibilityExplicitness::Implicit, - ); + let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit); let module_data = - ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility); + ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility, None); - let local_def_map = crate_local_def_map(db, module.krate); + let krate = module.krate(db); + let local_def_map = crate_local_def_map(db, krate); let def_map = DefMap::empty( - module.krate, + db, + krate, local_def_map.def_map(db).data.clone(), module_data, - Some(BlockInfo { - block: block_id, - parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id }, - }), + Some(BlockInfo { block: block_id, parent: module }), ); let (def_map, _) = collector::collect_defs( @@ -435,25 +427,24 @@ pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { } impl DefMap { - /// The module id of a crate or block root. - pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); - pub fn edition(&self) -> Edition { self.data.edition } fn empty( + db: &dyn DefDatabase, krate: Crate, crate_data: Arc<DefMapCrateData>, module_data: ModuleData, block: Option<BlockInfo>, ) -> DefMap { - let mut modules: Arena<ModuleData> = Arena::default(); - let root = modules.alloc(module_data); - assert_eq!(root, Self::ROOT); + let mut modules = ModulesMap::new(); + let root = unsafe { ModuleIdLt::new(db, krate, block.map(|it| it.block)).to_static() }; + modules.insert(root, module_data); DefMap { block, + root, modules, krate, prelude: None, @@ -471,6 +462,7 @@ impl DefMap { diagnostics, modules, derive_helpers_in_scope, + root: _, block: _, krate: _, prelude: _, @@ -495,7 +487,7 @@ impl DefMap { &'a self, db: &'a dyn DefDatabase, file_id: FileId, - ) -> impl Iterator<Item = LocalModuleId> + 'a { + ) -> impl Iterator<Item = ModuleId> + 'a { self.modules .iter() .filter(move |(_id, data)| { @@ -504,7 +496,7 @@ impl DefMap { .map(|(id, _data)| id) } - pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ { + pub fn modules(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ { self.modules.iter() } @@ -543,40 +535,32 @@ impl DefMap { self.krate } - pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { - let block = self.block.map(|b| b.block); - ModuleId { krate: self.krate, local_id, block } - } - - pub fn crate_root(&self) -> CrateRootModuleId { - CrateRootModuleId { krate: self.krate } + #[inline] + pub fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { + match self.block { + Some(_) => crate_def_map(db, self.krate()).root, + None => self.root, + } } /// This is the same as [`Self::crate_root`] for crate def maps, but for block def maps, it /// returns the root block module. pub fn root_module_id(&self) -> ModuleId { - self.module_id(Self::ROOT) + self.root } /// If this `DefMap` is for a block expression, returns the module containing the block (which /// might again be a block, or a module inside a block). pub fn parent(&self) -> Option<ModuleId> { - let BlockRelativeModuleId { block, local_id } = self.block?.parent; - Some(ModuleId { krate: self.krate, block, local_id }) + Some(self.block?.parent) } /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. - pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { + pub fn containing_module(&self, local_mod: ModuleId) -> Option<ModuleId> { match self[local_mod].parent { - Some(parent) => Some(self.module_id(parent)), - None => { - self.block.map( - |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| { - ModuleId { krate: self.krate, block, local_id } - }, - ) - } + Some(parent) => Some(parent), + None => self.block.map(|BlockInfo { parent, .. }| parent), } } @@ -594,30 +578,21 @@ impl DefMap { // even), as this should be a great debugging aid. pub fn dump(&self, db: &dyn DefDatabase) -> String { let mut buf = String::new(); - let mut arc; let mut current_map = self; while let Some(block) = current_map.block { - go(&mut buf, db, current_map, "(block scope)", Self::ROOT); + go(&mut buf, db, current_map, "(block scope)", current_map.root); buf.push('\n'); - arc = block.parent.def_map(db, self.krate); - current_map = arc; + current_map = block.parent.def_map(db); } - go(&mut buf, db, current_map, "crate", Self::ROOT); + go(&mut buf, db, current_map, "crate", current_map.root); return buf; - fn go( - buf: &mut String, - db: &dyn DefDatabase, - map: &DefMap, - path: &str, - module: LocalModuleId, - ) { + fn go(buf: &mut String, db: &dyn DefDatabase, map: &DefMap, path: &str, module: ModuleId) { format_to!(buf, "{}\n", path); - map.modules[module].scope.dump(db, buf); + map[module].scope.dump(db, buf); - for (name, child) in - map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) + for (name, child) in map[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) { let path = format!("{path}::{}", name.display(db, Edition::LATEST)); buf.push('\n'); @@ -625,20 +600,6 @@ impl DefMap { } } } - - pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String { - let mut buf = String::new(); - let mut arc; - let mut current_map = self; - while let Some(block) = current_map.block { - format_to!(buf, "{:?} in {:?}\n", block.block, block.parent); - arc = block.parent.def_map(db, self.krate); - current_map = arc; - } - - format_to!(buf, "crate scope\n"); - buf - } } impl DefMap { @@ -658,7 +619,7 @@ impl DefMap { &self, local_def_map: &LocalDefMap, db: &dyn DefDatabase, - original_module: LocalModuleId, + original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, expected_macro_subns: Option<MacroSubNs>, @@ -681,7 +642,7 @@ impl DefMap { &self, local_def_map: &LocalDefMap, db: &dyn DefDatabase, - original_module: LocalModuleId, + original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, ) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) { @@ -704,16 +665,16 @@ impl DefMap { pub(crate) fn with_ancestor_maps<T>( &self, db: &dyn DefDatabase, - local_mod: LocalModuleId, - f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>, + local_mod: ModuleId, + f: &mut dyn FnMut(&DefMap, ModuleId) -> Option<T>, ) -> Option<T> { if let Some(it) = f(self, local_mod) { return Some(it); } let mut block = self.block; while let Some(block_info) = block { - let parent = block_info.parent.def_map(db, self.krate); - if let Some(it) = f(parent, block_info.parent.local_id) { + let parent = block_info.parent.def_map(db); + if let Some(it) = f(parent, block_info.parent) { return Some(it); } block = parent.block; @@ -724,11 +685,15 @@ impl DefMap { } impl ModuleData { - pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self { + pub(crate) fn new( + origin: ModuleOrigin, + visibility: Visibility, + parent: Option<ModuleId>, + ) -> Self { ModuleData { origin, visibility, - parent: None, + parent, children: Default::default(), scope: ItemScope::default(), } @@ -739,7 +704,7 @@ impl ModuleData { self.origin.definition_source(db) } - /// Same as [`definition_source`] but only returns the file id to prevent parsing the ASt. + /// Same as [`ModuleData::definition_source`] but only returns the file id to prevent parsing the ASt. pub fn definition_source_file_id(&self) -> HirFileId { match self.origin { ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { @@ -852,3 +817,53 @@ fn sub_namespace_match( None => true, } } + +/// A newtype wrapper around `FxHashMap<ModuleId, ModuleData>` that implements `IndexMut`. +#[derive(Debug, PartialEq, Eq)] +pub struct ModulesMap { + inner: FxIndexMap<ModuleId, ModuleData>, +} + +impl ModulesMap { + fn new() -> Self { + Self { inner: FxIndexMap::default() } + } + + fn iter(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ { + self.inner.iter().map(|(&k, v)| (k, v)) + } + + fn iter_mut(&mut self) -> impl Iterator<Item = (ModuleId, &mut ModuleData)> + '_ { + self.inner.iter_mut().map(|(&k, v)| (k, v)) + } +} + +impl Deref for ModulesMap { + type Target = FxIndexMap<ModuleId, ModuleData>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ModulesMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Index<ModuleId> for ModulesMap { + type Output = ModuleData; + + fn index(&self, id: ModuleId) -> &ModuleData { + self.inner.get(&id).unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}")) + } +} + +impl IndexMut<ModuleId> for ModulesMap { + fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData { + self.inner + .get_mut(&id) + .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}")) + } +} diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs index b67853347b..9d2b2109fb 100644 --- a/crates/hir-def/src/nameres/assoc.rs +++ b/crates/hir-def/src/nameres/assoc.rs @@ -165,7 +165,7 @@ impl<'a> AssocItemCollector<'a> { local_def_map, ast_id_map: db.ast_id_map(file_id), span_map: db.span_map(file_id), - cfg_options: module_id.krate.cfg_options(db), + cfg_options: module_id.krate(db).cfg_options(db), file_id, container, items: Vec::new(), @@ -197,7 +197,7 @@ impl<'a> AssocItemCollector<'a> { AttrsOrCfg::Enabled { attrs } => attrs, AttrsOrCfg::CfgDisabled(cfg) => { self.diagnostics.push(DefDiagnostic::unconfigured_code( - self.module_id.local_id, + self.module_id, InFile::new(self.file_id, ast_id.erase()), cfg.0, self.cfg_options.clone(), @@ -213,7 +213,7 @@ impl<'a> AssocItemCollector<'a> { match self.def_map.resolve_attr_macro( self.local_def_map, self.db, - self.module_id.local_id, + self.module_id, ast_id_with_path, attr, attr_id, @@ -226,9 +226,9 @@ impl<'a> AssocItemCollector<'a> { // crate failed), skip expansion like we would if it was // disabled. This is analogous to the handling in // `DefCollector::collect_macros`. - if let Some(err) = exp.as_expand_error(self.module_id.krate) { + if let Some(err) = exp.as_expand_error(self.module_id.krate(self.db)) { self.diagnostics.push(DefDiagnostic::macro_error( - self.module_id.local_id, + self.module_id, ast_id, (*attr.path).clone(), err, @@ -244,7 +244,7 @@ impl<'a> AssocItemCollector<'a> { Ok(_) => (), Err(_) => { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( - self.module_id.local_id, + self.module_id, MacroCallKind::Attr { ast_id, attr_args: None, @@ -307,7 +307,7 @@ impl<'a> AssocItemCollector<'a> { .resolve_path( self.local_def_map, self.db, - self.module_id.local_id, + self.module_id, path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), @@ -322,7 +322,7 @@ impl<'a> AssocItemCollector<'a> { &path, ctxt, ExpandTo::Items, - self.module_id.krate(), + self.module_id.krate(self.db), resolver, &mut |ptr, call_id| { self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id)) @@ -338,7 +338,7 @@ impl<'a> AssocItemCollector<'a> { }, Err(_) => { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( - self.module_id.local_id, + self.module_id, MacroCallKind::FnLike { ast_id, expand_to: ExpandTo::Items, diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index fb755026c3..ec05c02bd6 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -12,7 +12,7 @@ use syntax::ast; use triomphe::Arc; use crate::{ - AstIdWithPath, LocalModuleId, MacroId, UnresolvedMacro, + AstIdWithPath, MacroId, ModuleId, UnresolvedMacro, db::DefDatabase, item_scope::BuiltinShadowMode, nameres::{LocalDefMap, path_resolution::ResolveMode}, @@ -33,7 +33,7 @@ impl DefMap { &self, local_def_map: &LocalDefMap, db: &dyn DefDatabase, - original_module: LocalModuleId, + original_module: ModuleId, ast_id: AstIdWithPath<ast::Item>, attr: &Attr, attr_id: AttrId, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 9aa7febdfd..08edf41c56 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -3,7 +3,7 @@ //! `DefCollector::collect` contains the fixed-point iteration loop which //! resolves imports and expands macros. -use std::{cmp::Ordering, iter, mem}; +use std::{iter, mem}; use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; use cfg::{CfgAtom, CfgExpr, CfgOptions}; @@ -27,12 +27,11 @@ use syntax::ast; use triomphe::Arc; use crate::{ - AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc, - ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, - ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, - MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, - ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, - UseLoc, + AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, EnumLoc, ExternBlockLoc, ExternCrateId, + ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, ItemContainerId, Lookup, + Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, + ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, + UnionLoc, UnresolvedMacro, UseId, UseLoc, db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ @@ -177,14 +176,14 @@ impl Import { #[derive(Debug, Eq, PartialEq)] struct ImportDirective { /// The module this import directive is in. - module_id: LocalModuleId, + module_id: ModuleId, import: Import, status: PartialResolvedImport, } #[derive(Clone, Debug, Eq, PartialEq)] struct MacroDirective<'db> { - module_id: LocalModuleId, + module_id: ModuleId, depth: usize, kind: MacroDirectiveKind<'db>, container: ItemContainerId, @@ -224,7 +223,7 @@ struct DefCollector<'db> { crate_local_def_map: Option<&'db LocalDefMap>, // The dependencies of the current crate, including optional deps like `test`. deps: FxIndexMap<Name, BuiltDependency>, - glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>, + glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, Visibility, GlobId)>>, unresolved_imports: Vec<ImportDirective>, indeterminate_imports: Vec<(ImportDirective, PerNs)>, unresolved_macros: Vec<MacroDirective<'db>>, @@ -232,7 +231,7 @@ struct DefCollector<'db> { // resolve. When we emit diagnostics for unresolved imports, we only do so if the import // doesn't start with an unresolved crate's name. unresolved_extern_crates: FxHashSet<Name>, - mod_dirs: FxHashMap<LocalModuleId, ModDir>, + mod_dirs: FxHashMap<ModuleId, ModDir>, cfg_options: &'db CfgOptions, /// List of procedural macros defined by this crate. This is read from the dynamic library /// built by the build system, and is the list of proc-macros we can actually expand. It is @@ -337,9 +336,14 @@ impl<'db> DefCollector<'db> { continue; } - self.local_def_map - .extern_prelude - .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None)); + // This eagerly draws a dependency edge between the crate def maps even if the + // things the crates are not used. This is not great, but at the same time we would + // like to compute our dependency def maps in parallel here anyways in the future + // which will have the same effect. + self.local_def_map.extern_prelude.insert( + name.clone(), + (crate_def_map(self.db, dep.crate_id).root_module_id(), None), + ); } } @@ -349,10 +353,11 @@ impl<'db> DefCollector<'db> { return; } + let module_id = self.def_map.root; ModCollector { def_collector: self, macro_depth: 0, - module_id: DefMap::ROOT, + module_id, tree_id: TreeId::new(file_id.into(), None), item_tree, mod_dir: ModDir::root(), @@ -367,10 +372,11 @@ impl<'db> DefCollector<'db> { if is_cfg_enabled { self.inject_prelude(); + let module_id = self.def_map.root; ModCollector { def_collector: self, macro_depth: 0, - module_id: DefMap::ROOT, + module_id, tree_id, item_tree, mod_dir: ModDir::root(), @@ -433,7 +439,8 @@ impl<'db> DefCollector<'db> { // Additionally, while the proc macro entry points must be `pub`, they are not publicly // exported in type/value namespace. This function reduces the visibility of all items // in the crate root that aren't proc macros. - let root = &mut self.def_map.modules[DefMap::ROOT]; + let module_id = self.def_map.root_module_id(); + let root = &mut self.def_map.modules[module_id]; root.scope.censor_non_proc_macros(self.def_map.krate); } } @@ -537,7 +544,7 @@ impl<'db> DefCollector<'db> { let (per_ns, _) = self.def_map.resolve_path( self.crate_local_def_map.unwrap_or(&self.local_def_map), self.db, - DefMap::ROOT, + self.def_map.root_module_id(), &path, BuiltinShadowMode::Other, None, @@ -592,7 +599,7 @@ impl<'db> DefCollector<'db> { }; let proc_macro_id = ProcMacroLoc { - container: self.def_map.crate_root(), + container: self.def_map.root_module_id(), id: ast_id, expander, kind, @@ -636,7 +643,7 @@ impl<'db> DefCollector<'db> { /// ``` fn define_macro_rules( &mut self, - module_id: LocalModuleId, + module_id: ModuleId, name: Name, macro_: MacroRulesId, export: bool, @@ -648,7 +655,7 @@ impl<'db> DefCollector<'db> { // In Rust, `#[macro_export]` macros are unconditionally visible at the // crate root, even if the parent modules is **not** visible. if export { - let module_id = DefMap::ROOT; + let module_id = self.def_map.root; self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, @@ -666,7 +673,7 @@ impl<'db> DefCollector<'db> { /// the definition of current module. /// And also, `macro_use` on a module will import all legacy macros visible inside to /// current legacy scope, with possible shadowing. - fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) { + fn define_legacy_macro(&mut self, module_id: ModuleId, name: Name, mac: MacroId) { // Always shadowing self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); } @@ -676,7 +683,7 @@ impl<'db> DefCollector<'db> { /// The scoped of macro 2.0 macro is equal to normal function fn define_macro_def( &mut self, - module_id: LocalModuleId, + module_id: ModuleId, name: Name, macro_: Macro2Id, vis: &RawVisibility, @@ -705,7 +712,7 @@ impl<'db> DefCollector<'db> { /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. /// And unconditionally exported. fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) { - let module_id = DefMap::ROOT; + let module_id = self.def_map.root; self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, @@ -730,7 +737,7 @@ impl<'db> DefCollector<'db> { let def_map = crate_def_map(self.db, krate); // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!` // macros. - let root_scope = &def_map[DefMap::ROOT].scope; + let root_scope = &def_map[def_map.root].scope; match names { Some(names) => { for name in names { @@ -803,7 +810,7 @@ impl<'db> DefCollector<'db> { res } - fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { + fn resolve_import(&self, module_id: ModuleId, import: &Import) -> PartialResolvedImport { let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db, Edition::LATEST)) .entered(); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); @@ -916,11 +923,10 @@ impl<'db> DefCollector<'db> { // implementation seems to work the same though. cov_mark::hit!(std_prelude); self.def_map.prelude = Some((m, Some(id))); - } else if m.krate != self.def_map.krate { + } else if m.krate(self.db) != self.def_map.krate { cov_mark::hit!(glob_across_crates); // glob import from other crate => we can just import everything once - let item_map = m.def_map(self.db); - let scope = &item_map[m.local_id].scope; + let scope = &m.def_map(self.db)[m].scope; // Module scoped macros is included let items = scope @@ -942,12 +948,10 @@ impl<'db> DefCollector<'db> { // glob import from same crate => we do an initial // import, and then need to propagate any further // additions - let def_map; - let scope = if m.block == self.def_map.block_id() { - &self.def_map[m.local_id].scope + let scope = if m.block(self.db) == self.def_map.block_id() { + &self.def_map[m].scope } else { - def_map = m.def_map(self.db); - &def_map[m.local_id].scope + &m.def_map(self.db)[m].scope }; // Module scoped macros is included @@ -976,11 +980,12 @@ impl<'db> DefCollector<'db> { Some(ImportOrExternCrate::Glob(glob)), ); // record the glob import in case we add further items - let glob_imports = self.glob_imports.entry(m.local_id).or_default(); + let glob_imports = self.glob_imports.entry(m).or_default(); match glob_imports.iter_mut().find(|(mid, _, _)| *mid == module_id) { None => glob_imports.push((module_id, vis, glob)), Some((_, old_vis, _)) => { - if let Some(new_vis) = old_vis.max(vis, &self.def_map) { + if let Some(new_vis) = old_vis.max(self.db, vis, &self.def_map) + { *old_vis = new_vis; } } @@ -1056,20 +1061,19 @@ impl<'db> DefCollector<'db> { fn update( &mut self, // The module for which `resolutions` have been resolve - module_id: LocalModuleId, + module_id: ModuleId, resolutions: &[(Option<Name>, PerNs)], // Visibility this import will have vis: Visibility, import: Option<ImportOrExternCrate>, ) { - self.db.unwind_if_revision_cancelled(); self.update_recursive(module_id, resolutions, vis, import, 0) } fn update_recursive( &mut self, // The module for which `resolutions` have been resolved. - module_id: LocalModuleId, + module_id: ModuleId, resolutions: &[(Option<Name>, PerNs)], // All resolutions are imported with this visibility; the visibilities in // the `PerNs` values are ignored and overwritten @@ -1104,7 +1108,7 @@ impl<'db> DefCollector<'db> { let should_update = match old_vis { None => true, Some(old_vis) => { - let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| { + let max_vis = old_vis.max(self.db, vis, &self.def_map).unwrap_or_else(|| { panic!("`Tr as _` imports with unrelated visibilities {old_vis:?} and {vis:?} (trait {tr:?})"); }); @@ -1146,7 +1150,7 @@ impl<'db> DefCollector<'db> { .collect::<Vec<_>>(); for (glob_importing_module, glob_import_vis, glob) in glob_imports { - let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis); + let vis = glob_import_vis.min(self.db, vis, &self.def_map).unwrap_or(glob_import_vis); self.update_recursive( glob_importing_module, resolutions, @@ -1159,20 +1163,20 @@ impl<'db> DefCollector<'db> { fn push_res_and_update_glob_vis( &mut self, - module_id: LocalModuleId, + module_id: ModuleId, name: &Name, mut defs: PerNs, vis: Visibility, def_import_type: Option<ImportOrExternCrate>, ) -> bool { if let Some(def) = defs.types.as_mut() { - def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); + def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis); } if let Some(def) = defs.values.as_mut() { - def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); + def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis); } if let Some(def) = defs.macros.as_mut() { - def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); + def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis); } let mut changed = false; @@ -1188,7 +1192,7 @@ impl<'db> DefCollector<'db> { && def.def == prev_def.def && self.from_glob_import.contains_type(module_id, name.clone()) && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) { changed = true; // This import is being handled here, don't pass it down to @@ -1202,7 +1206,7 @@ impl<'db> DefCollector<'db> { && def.def == prev_def.def && self.from_glob_import.contains_value(module_id, name.clone()) && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) { changed = true; // See comment above. @@ -1215,7 +1219,7 @@ impl<'db> DefCollector<'db> { && def.def == prev_def.def && self.from_glob_import.contains_macro(module_id, name.clone()) && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) { changed = true; // See comment above. @@ -1555,7 +1559,7 @@ impl<'db> DefCollector<'db> { fn collect_macro_expansion( &mut self, - module_id: LocalModuleId, + module_id: ModuleId, macro_call_id: MacroCallId, depth: usize, container: ItemContainerId, @@ -1713,7 +1717,7 @@ impl<'db> DefCollector<'db> { struct ModCollector<'a, 'db> { def_collector: &'a mut DefCollector<'db>, macro_depth: usize, - module_id: LocalModuleId, + module_id: ModuleId, tree_id: TreeId, item_tree: &'db ItemTree, mod_dir: ModDir, @@ -1721,14 +1725,13 @@ struct ModCollector<'a, 'db> { impl ModCollector<'_, '_> { fn collect_in_top_module(&mut self, items: &[ModItemId]) { - let module = self.def_collector.def_map.module_id(self.module_id); - self.collect(items, module.into()) + self.collect(items, self.module_id.into()) } fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) { let krate = self.def_collector.def_map.krate; - let is_crate_root = - self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none(); + let is_crate_root = self.module_id == self.def_collector.def_map.root + && self.def_collector.def_map.block.is_none(); // Note: don't assert that inserted value is fresh: it's simply not true // for macros. @@ -1737,10 +1740,10 @@ impl ModCollector<'_, '_> { // Prelude module is always considered to be `#[macro_use]`. if let Some((prelude_module, _use)) = self.def_collector.def_map.prelude { // Don't insert macros from the prelude into blocks, as they can be shadowed by other macros. - if prelude_module.krate != krate && is_crate_root { + if is_crate_root && prelude_module.krate(self.def_collector.db) != krate { cov_mark::hit!(prelude_is_macro_use); self.def_collector.import_macros_from_extern_crate( - prelude_module.krate, + prelude_module.krate(self.def_collector.db), None, None, ); @@ -1781,7 +1784,6 @@ impl ModCollector<'_, '_> { return; } - let module = self.def_collector.def_map.module_id(module_id); let def_map = &mut self.def_collector.def_map; let local_def_map = self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map); @@ -1789,9 +1791,11 @@ impl ModCollector<'_, '_> { match item { ModItemId::Mod(m) => self.collect_module(m, attrs), ModItemId::Use(item_tree_id) => { - let id = - UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) } - .intern(db); + let id = UseLoc { + container: module_id, + id: InFile::new(self.file_id(), item_tree_id), + } + .intern(db); let is_prelude = attrs.by_key(sym::prelude_import).exists(); Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| { self.def_collector.unresolved_imports.push(ImportDirective { @@ -1806,7 +1810,7 @@ impl ModCollector<'_, '_> { &self.item_tree[item_tree_id]; let id = ExternCrateLoc { - container: module, + container: module_id, id: InFile::new(self.tree_id.file_id(), item_tree_id), } .intern(db); @@ -1815,12 +1819,12 @@ impl ModCollector<'_, '_> { let is_self = *name == sym::self_; let resolved = if is_self { cov_mark::hit!(extern_crate_self_as); - Some(def_map.crate_root()) + Some(def_map.crate_root(db)) } else { self.def_collector .deps .get(name) - .map(|dep| CrateRootModuleId { krate: dep.crate_id }) + .map(|dep| crate_def_map(db, dep.crate_id).root_module_id()) }; let name = match alias { @@ -1845,7 +1849,7 @@ impl ModCollector<'_, '_> { self.process_macro_use_extern_crate( id, attrs.by_key(sym::macro_use).attrs(), - resolved.krate, + resolved.krate(self.def_collector.db), ); } } @@ -1877,7 +1881,7 @@ impl ModCollector<'_, '_> { } ModItemId::ExternBlock(block) => { let extern_block_id = ExternBlockLoc { - container: module, + container: module_id, id: InFile::new(self.file_id(), block), } .intern(db); @@ -1890,11 +1894,11 @@ impl ModCollector<'_, '_> { ) } ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container), - ModItemId::MacroRules(id) => self.collect_macro_rules(id, module), - ModItemId::Macro2(id) => self.collect_macro_def(id, module), + ModItemId::MacroRules(id) => self.collect_macro_rules(id, module_id), + ModItemId::Macro2(id) => self.collect_macro_def(id, module_id), ModItemId::Impl(imp) => { let impl_id = - ImplLoc { container: module, id: InFile::new(self.file_id(), imp) } + ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) } .intern(db); self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) } @@ -1908,7 +1912,7 @@ impl ModCollector<'_, '_> { if self.def_collector.def_map.block.is_none() && self.def_collector.is_proc_macro - && self.module_id == DefMap::ROOT + && self.module_id == self.def_collector.def_map.root && let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( @@ -1926,7 +1930,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - StructLoc { container: module, id: InFile::new(self.file_id(), id) } + StructLoc { container: module_id, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1940,7 +1944,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - UnionLoc { container: module, id: InFile::new(self.file_id(), id) } + UnionLoc { container: module_id, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1950,9 +1954,11 @@ impl ModCollector<'_, '_> { } ModItemId::Enum(id) => { let it = &self.item_tree[id]; - let enum_ = - EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) } - .intern(db); + let enum_ = EnumLoc { + container: module_id, + id: InFile::new(self.tree_id.file_id(), id), + } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def(self.def_collector, enum_.into(), &it.name, vis, false); @@ -1997,7 +2003,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TraitLoc { container: module, id: InFile::new(self.file_id(), id) } + TraitLoc { container: module_id, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -2172,9 +2178,10 @@ impl ModCollector<'_, '_> { declaration: FileAstId<ast::Module>, definition: Option<(EditionedFileId, bool)>, visibility: &crate::visibility::RawVisibility, - ) -> LocalModuleId { - let def_map = &mut self.def_collector.def_map; - let vis = def_map + ) -> ModuleId { + let vis = self + .def_collector + .def_map .resolve_visibility( self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map), self.def_collector.db, @@ -2195,21 +2202,25 @@ impl ModCollector<'_, '_> { }, }; + let module = unsafe { + crate::ModuleIdLt::new( + self.def_collector.db, + self.def_collector.def_map.krate, + self.def_collector.def_map.block_id(), + ) + .to_static() + }; + let def_map = &mut self.def_collector.def_map; let modules = &mut def_map.modules; - let res = modules.alloc(ModuleData::new(origin, vis)); - modules[res].parent = Some(self.module_id); - - if let Some((target, source)) = Self::borrow_modules(modules.as_mut(), res, self.module_id) - { - for (name, macs) in source.scope.legacy_macros() { - for &mac in macs { - target.scope.define_legacy_macro(name.clone(), mac); - } + let mut data = ModuleData::new(origin, vis, Some(self.module_id)); + for (name, macs) in modules[self.module_id].scope.legacy_macros() { + for &mac in macs { + data.scope.define_legacy_macro(name.clone(), mac); } } - modules[self.module_id].children.insert(name.clone(), res); + modules[self.module_id].children.insert(name.clone(), module); + modules.insert(module, data); - let module = def_map.module_id(res); let def = ModuleDefId::from(module); def_map.modules[self.module_id].scope.declare(def); @@ -2219,7 +2230,7 @@ impl ModCollector<'_, '_> { vis, None, ); - res + module } /// Resolves attributes on an item. @@ -2516,12 +2527,10 @@ impl ModCollector<'_, '_> { }); } - fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let Some((source, target)) = Self::borrow_modules( - self.def_collector.def_map.modules.as_mut(), - module_id, - self.module_id, - ) else { + fn import_all_legacy_macros(&mut self, module_id: ModuleId) { + let [Some(source), Some(target)] = + self.def_collector.def_map.modules.get_disjoint_mut([&module_id, &self.module_id]) + else { return; }; @@ -2532,29 +2541,6 @@ impl ModCollector<'_, '_> { } } - /// Mutably borrow two modules at once, retu - fn borrow_modules( - modules: &mut [ModuleData], - a: LocalModuleId, - b: LocalModuleId, - ) -> Option<(&mut ModuleData, &mut ModuleData)> { - let a = a.into_raw().into_u32() as usize; - let b = b.into_raw().into_u32() as usize; - - let (a, b) = match a.cmp(&b) { - Ordering::Equal => return None, - Ordering::Less => { - let (prefix, b) = modules.split_at_mut(b); - (&mut prefix[a], &mut b[0]) - } - Ordering::Greater => { - let (prefix, a) = modules.split_at_mut(a); - (&mut a[0], &mut prefix[b]) - } - }; - Some((a, b)) - } - fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) { self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, @@ -2574,48 +2560,15 @@ impl ModCollector<'_, '_> { mod tests { use test_fixture::WithFixture; - use crate::{nameres::DefMapCrateData, test_db::TestDB}; + use crate::test_db::TestDB; use super::*; - fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap { - let mut collector = DefCollector { - db, - def_map, - local_def_map: LocalDefMap::default(), - crate_local_def_map: None, - deps: FxIndexMap::default(), - glob_imports: FxHashMap::default(), - unresolved_imports: Vec::new(), - indeterminate_imports: Vec::new(), - unresolved_macros: Vec::new(), - mod_dirs: FxHashMap::default(), - cfg_options: &CfgOptions::default(), - proc_macros: Default::default(), - from_glob_import: Default::default(), - skip_attrs: Default::default(), - prev_active_attrs: Default::default(), - is_proc_macro: false, - unresolved_extern_crates: Default::default(), - }; - collector.seed_with_top_level(); - collector.collect(); - collector.def_map - } - - fn do_resolve(not_ra_fixture: &str) -> DefMap { - let (db, file_id) = TestDB::with_single_file(not_ra_fixture); + fn do_resolve(not_ra_fixture: &str) { + let (db, _) = TestDB::with_single_file(not_ra_fixture); let krate = db.test_crate(); - let edition = krate.data(&db).edition; - let module_origin = ModuleOrigin::CrateRoot { definition: file_id }; - let def_map = DefMap::empty( - krate, - Arc::new(DefMapCrateData::new(edition)), - ModuleData::new(module_origin, Visibility::Public), - None, - ); - do_collect_defs(&db, def_map) + crate_def_map(&db, krate); } #[test] diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 6a07c56aee..be28e08509 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -7,7 +7,7 @@ use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod use la_arena::Idx; use syntax::ast; -use crate::{AstId, nameres::LocalModuleId}; +use crate::{AstId, nameres::ModuleId}; #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { @@ -43,13 +43,13 @@ impl DefDiagnostics { #[derive(Debug, PartialEq, Eq)] pub struct DefDiagnostic { - pub in_module: LocalModuleId, + pub in_module: ModuleId, pub kind: DefDiagnosticKind, } impl DefDiagnostic { pub(super) fn unresolved_module( - container: LocalModuleId, + container: ModuleId, declaration: AstId<ast::Module>, candidates: Box<[String]>, ) -> Self { @@ -60,7 +60,7 @@ impl DefDiagnostic { } pub(super) fn unresolved_extern_crate( - container: LocalModuleId, + container: ModuleId, declaration: AstId<ast::ExternCrate>, ) -> Self { Self { @@ -70,7 +70,7 @@ impl DefDiagnostic { } pub(super) fn unresolved_import( - container: LocalModuleId, + container: ModuleId, id: AstId<ast::Use>, index: Idx<ast::UseTree>, ) -> Self { @@ -78,7 +78,7 @@ impl DefDiagnostic { } pub fn macro_error( - container: LocalModuleId, + container: ModuleId, ast: AstId<ast::Item>, path: ModPath, err: ExpandErrorKind, @@ -87,7 +87,7 @@ impl DefDiagnostic { } pub fn unconfigured_code( - container: LocalModuleId, + container: ModuleId, ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions, @@ -100,33 +100,26 @@ impl DefDiagnostic { // FIXME: Whats the difference between this and unresolved_proc_macro pub(crate) fn unresolved_macro_call( - container: LocalModuleId, + container: ModuleId, ast: MacroCallKind, path: ModPath, ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } } - pub(super) fn unimplemented_builtin_macro( - container: LocalModuleId, - ast: AstId<ast::Macro>, - ) -> Self { + pub(super) fn unimplemented_builtin_macro(container: ModuleId, ast: AstId<ast::Macro>) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } } } pub(super) fn invalid_derive_target( - container: LocalModuleId, + container: ModuleId, ast: AstId<ast::Item>, id: AttrId, ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id } } } - pub(super) fn malformed_derive( - container: LocalModuleId, - ast: AstId<ast::Adt>, - id: AttrId, - ) -> Self { + pub(super) fn malformed_derive(container: ModuleId, ast: AstId<ast::Adt>, id: AttrId) -> Self { Self { in_module: container, kind: DefDiagnosticKind::MalformedDerive { ast, id } } } } diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 184a57410d..e4b1d2a987 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -19,7 +19,7 @@ use span::Edition; use stdx::TupleExt; use crate::{ - AdtId, LocalModuleId, ModuleDefId, + AdtId, ModuleDefId, ModuleId, db::DefDatabase, item_scope::{BUILTIN_SCOPE, ImportOrExternCrate}, item_tree::FieldsShape, @@ -97,7 +97,7 @@ impl DefMap { local_def_map: &LocalDefMap, db: &dyn DefDatabase, // module to import to - original_module: LocalModuleId, + original_module: ModuleId, // pub(path) // ^^^^ this visibility: &RawVisibility, @@ -130,8 +130,8 @@ impl DefMap { // DefMap they're written in, so we restrict them when that happens. if let Visibility::Module(m, mv) = vis { // ...unless we're resolving visibility for an associated item in an impl. - if self.block_id() != m.block && !within_impl { - vis = Visibility::Module(self.module_id(Self::ROOT), mv); + if self.block_id() != m.block(db) && !within_impl { + vis = Visibility::Module(self.root, mv); tracing::debug!( "visibility {:?} points outside DefMap, adjusting to {:?}", m, @@ -142,7 +142,7 @@ impl DefMap { vis } RawVisibility::PubSelf(explicitness) => { - Visibility::Module(self.module_id(original_module), *explicitness) + Visibility::Module(original_module, *explicitness) } RawVisibility::Public => Visibility::Public, RawVisibility::PubCrate => Visibility::PubCrate(self.krate), @@ -158,7 +158,7 @@ impl DefMap { db: &dyn DefDatabase, mode: ResolveMode, // module to import to - mut original_module: LocalModuleId, + mut original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're @@ -198,17 +198,17 @@ impl DefMap { loop { match current_map.block { - Some(block) if original_module == Self::ROOT => { + Some(block) if original_module == current_map.root => { // Block modules "inherit" names from its parent module. - original_module = block.parent.local_id; - current_map = block.parent.def_map(db, current_map.krate); + original_module = block.parent; + current_map = block.parent.def_map(db); } // Proper (non-block) modules, including those in block `DefMap`s, don't. _ => { - if original_module != Self::ROOT && current_map.block.is_some() { + if original_module != current_map.root && current_map.block.is_some() { // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get // the prelude items (which are not inserted into blocks because they can be overridden there). - original_module = Self::ROOT; + original_module = current_map.root; current_map = crate_def_map(db, self.krate); let new = current_map.resolve_path_fp_in_all_preludes( @@ -245,7 +245,7 @@ impl DefMap { local_def_map: &LocalDefMap, db: &dyn DefDatabase, mode: ResolveMode, - original_module: LocalModuleId, + original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, expected_macro_subns: Option<MacroSubNs>, @@ -255,15 +255,15 @@ impl DefMap { PathKind::DollarCrate(krate) => { if krate == self.krate { cov_mark::hit!(macro_dollar_crate_self); - PerNs::types(self.crate_root().into(), Visibility::Public, None) + PerNs::types(self.crate_root(db).into(), Visibility::Public, None) } else { let def_map = crate_def_map(db, krate); - let module = def_map.module_id(Self::ROOT); + let module = def_map.root; cov_mark::hit!(macro_dollar_crate_other); PerNs::types(module.into(), Visibility::Public, None) } } - PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public, None), + PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public, None), // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) @@ -310,14 +310,10 @@ impl DefMap { } PathKind::Super(lvl) => { let mut local_id = original_module; - let mut ext; let mut def_map = self; // Adjust `local_id` to `self`, i.e. the nearest non-block module. - if def_map.module_id(local_id).is_block_module() { - (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id); - def_map = ext; - } + (def_map, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id); // Go up the module tree but skip block modules as `super` always refers to the // nearest non-block module. @@ -325,12 +321,8 @@ impl DefMap { // Loop invariant: at the beginning of each loop, `local_id` must refer to a // non-block module. if let Some(parent) = def_map.modules[local_id].parent { - local_id = parent; - if def_map.module_id(local_id).is_block_module() { - (ext, local_id) = - adjust_to_nearest_non_block_module(db, def_map, local_id); - def_map = ext; - } + (def_map, local_id) = + adjust_to_nearest_non_block_module(db, def_map, parent); } else { stdx::always!(def_map.block.is_none()); tracing::debug!("super path in root module"); @@ -338,9 +330,6 @@ impl DefMap { } } - let module = def_map.module_id(local_id); - stdx::never!(module.is_block_module()); - if self.block != def_map.block { // If we have a different `DefMap` from `self` (the original `DefMap` we started // with), resolve the remaining path segments in that `DefMap`. @@ -358,7 +347,7 @@ impl DefMap { ); } - PerNs::types(module.into(), Visibility::Public, None) + PerNs::types(local_id.into(), Visibility::Public, None) } PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) { Either::Left(it) => it, @@ -385,7 +374,7 @@ impl DefMap { local_def_map: &LocalDefMap, db: &dyn DefDatabase, mode: ResolveMode, - original_module: LocalModuleId, + original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, ) -> ResolvePathResult { @@ -467,7 +456,7 @@ impl DefMap { mut curr_per_ns: PerNs, path: &ModPath, shadow: BuiltinShadowMode, - original_module: LocalModuleId, + original_module: ModuleId, ) -> ResolvePathResult { while let Some((i, segment)) = segments.next() { let curr = match curr_per_ns.take_types_full() { @@ -485,7 +474,7 @@ impl DefMap { curr_per_ns = match curr.def { ModuleDefId::ModuleId(module) => { - if module.krate != self.krate { + if module.krate(db) != self.krate { // FIXME: Inefficient let path = ModPath::from_segments( PathKind::SELF, @@ -501,7 +490,7 @@ impl DefMap { LocalDefMap::EMPTY, db, mode, - module.local_id, + module, &path, shadow, None, @@ -518,11 +507,11 @@ impl DefMap { } let def_map; - let module_data = if module.block == self.block_id() { - &self[module.local_id] + let module_data = if module.block(db) == self.block_id() { + &self[module] } else { def_map = module.def_map(db); - &def_map[module.local_id] + &def_map[module] }; // Since it is a qualified path here, it should not contains legacy macros @@ -649,7 +638,7 @@ impl DefMap { &self, local_def_map: &LocalDefMap, db: &dyn DefDatabase, - module: LocalModuleId, + module: ModuleId, name: &Name, shadow: BuiltinShadowMode, expected_macro_subns: Option<MacroSubNs>, @@ -684,7 +673,7 @@ impl DefMap { }; let extern_prelude = || { - if self.block.is_some() && module == DefMap::ROOT { + if self.block.is_some() && module == self.root { // Don't resolve extern prelude in pseudo-modules of blocks, because // they might been shadowed by local names. return PerNs::none(); @@ -693,7 +682,7 @@ impl DefMap { }; let macro_use_prelude = || self.resolve_in_macro_use_prelude(name); let prelude = || { - if self.block.is_some() && module == DefMap::ROOT { + if self.block.is_some() && module == self.root { return PerNs::none(); } self.resolve_in_prelude(db, name) @@ -746,18 +735,18 @@ impl DefMap { &self, local_def_map: &LocalDefMap, db: &dyn DefDatabase, - module: LocalModuleId, + module: ModuleId, name: &Name, ) -> PerNs { let from_crate_root = match self.block { Some(_) => { - let def_map = self.crate_root().def_map(db); - def_map[Self::ROOT].scope.get(name) + let def_map = self.crate_root(db).def_map(db); + def_map[def_map.root].scope.get(name) } - None => self[Self::ROOT].scope.get(name), + None => self[self.root].scope.get(name), }; let from_extern_prelude = || { - if self.block.is_some() && module == DefMap::ROOT { + if self.block.is_some() && module == self.root { // Don't resolve extern prelude in pseudo-module of a block. return PerNs::none(); } @@ -770,14 +759,14 @@ impl DefMap { fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { if let Some((prelude, _use)) = self.prelude { let keep; - let def_map = if prelude.krate == self.krate { + let def_map = if prelude.krate(db) == self.krate { self } else { // Extend lifetime keep = prelude.def_map(db); keep }; - def_map[prelude.local_id].scope.get(name) + def_map[prelude].scope.get(name) } else { PerNs::none() } @@ -785,23 +774,23 @@ impl DefMap { } /// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to. +#[inline] fn adjust_to_nearest_non_block_module<'db>( db: &'db dyn DefDatabase, - def_map: &'db DefMap, - mut local_id: LocalModuleId, -) -> (&'db DefMap, LocalModuleId) { - // INVARIANT: `local_id` in `def_map` must be a block module. - stdx::always!(def_map.module_id(local_id).is_block_module()); - - // This needs to be a local variable due to our mighty lifetime. - let mut def_map = def_map; - loop { - let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module"); - - def_map = parent.def_map(db, def_map.krate); - local_id = parent.local_id; - if !parent.is_block_module() { + mut def_map: &'db DefMap, + mut local_id: ModuleId, +) -> (&'db DefMap, ModuleId) { + if def_map.root_module_id() != local_id { + // if we aren't the root, we are either not a block module, or a non-block module inside a + // block def map. + return (def_map, local_id); + } + while let Some(BlockInfo { parent, .. }) = def_map.block { + def_map = parent.def_map(db); + local_id = parent; + if def_map.root_module_id() != local_id { return (def_map, local_id); } } + (def_map, local_id) } diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 40283f67cc..5724334601 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -63,7 +63,7 @@ pub const BAZ: u32 = 0; let all_crates_before = db.all_crates(); { - // Add a dependency a -> b. + // Add dependencies: c -> b, b -> a. let mut new_crate_graph = CrateGraphBuilder::default(); let mut add_crate = |crate_name, root_file_idx: usize| { @@ -111,10 +111,13 @@ pub const BAZ: u32 = 0; crate_def_map(&db, krate); } }, - &[("crate_local_def_map", 1)], + // `c` gets invalidated as its dependency `b` changed + // `b` gets invalidated due to its new dependency edge to `a` + &[("crate_local_def_map", 2)], expect![[r#" [ "crate_local_def_map", + "crate_local_def_map", ] "#]], ); @@ -280,6 +283,8 @@ fn f() { foo } "ast_id_map_shim", "parse_shim", "real_span_map_shim", + "crate_local_def_map", + "proc_macros_for_crate_shim", "file_item_tree_query", "ast_id_map_shim", "parse_shim", @@ -288,8 +293,6 @@ fn f() { foo } "ast_id_map_shim", "parse_shim", "real_span_map_shim", - "crate_local_def_map", - "proc_macros_for_crate_shim", "file_item_tree_query", "ast_id_map_shim", "parse_shim", @@ -404,6 +407,12 @@ pub struct S {} "ast_id_map_shim", "parse_shim", "real_span_map_shim", + "crate_local_def_map", + "proc_macros_for_crate_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", "ast_id_map_shim", @@ -424,12 +433,6 @@ pub struct S {} "ast_id_map_shim", "parse_macro_expansion_shim", "macro_arg_shim", - "crate_local_def_map", - "proc_macros_for_crate_shim", - "file_item_tree_query", - "ast_id_map_shim", - "parse_shim", - "real_span_map_shim", "macro_def_shim", "file_item_tree_query", "ast_id_map_shim", @@ -509,7 +512,8 @@ m!(Z); &db, || { let crate_def_map = crate_def_map(&db, krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + let module_data = &crate_def_map + [crate_def_map.modules_for_file(&db, pos.file_id.file_id(&db)).next().unwrap()]; assert_eq!(module_data.scope.resolutions().count(), 4); }, &[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)], @@ -558,7 +562,8 @@ m!(Z); &db, || { let crate_def_map = crate_def_map(&db, krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + let module_data = &crate_def_map + [crate_def_map.modules_for_file(&db, pos.file_id.file_id(&db)).next().unwrap()]; assert_eq!(module_data.scope.resolutions().count(), 4); }, &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)], diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index a5fd0488e7..c8eb968b35 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -784,7 +784,7 @@ macro_rules! foo { pub use core::clone::Clone; "#, - |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1), + |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1), ); } @@ -806,7 +806,7 @@ pub macro Copy {} #[rustc_builtin_macro] pub macro Clone {} "#, - |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2), + |map| assert_eq!(map.modules[map.root].scope.impls().len(), 2), ); } @@ -849,7 +849,7 @@ pub macro derive($item:item) {} #[rustc_builtin_macro] pub macro Clone {} "#, - |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1), + |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1), ); } @@ -1502,7 +1502,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } let krate = *db.all_crates().last().expect("no crate graph present"); let def_map = crate_def_map(&db, krate); - let root_module = &def_map[DefMap::ROOT].scope; + let root_module = &def_map[def_map.root].scope; assert!( root_module.legacy_macros().count() == 0, "`#[macro_use]` shouldn't bring macros into textual macro scope", @@ -1609,7 +1609,7 @@ macro_rules! derive { () => {} } #[derive(Clone)] struct S; "#, - |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1), + |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1), ); } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index ccea043739..263f603a0b 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -16,11 +16,11 @@ use syntax::ast::HasName; use triomphe::Arc; use crate::{ - AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, - EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, - GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, - Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, + ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, + ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, + ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, + TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -55,7 +55,7 @@ pub struct Resolver<'db> { struct ModuleItemMap<'db> { def_map: &'db DefMap, local_def_map: &'db LocalDefMap, - module_id: LocalModuleId, + module_id: ModuleId, } impl fmt::Debug for ModuleItemMap<'_> { @@ -608,14 +608,14 @@ impl<'db> Resolver<'db> { }, ); local_def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| { - res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into()))); + res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); }); BUILTIN_SCOPE.iter().for_each(|(name, &def)| { res.add_per_ns(name, def); }); if let Some((prelude, _use)) = def_map.prelude() { let prelude_def_map = prelude.def_map(db); - for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { + for (name, def) in prelude_def_map[prelude].scope.entries() { res.add_per_ns(name, def) } } @@ -647,7 +647,7 @@ impl<'db> Resolver<'db> { self.module_scope .local_def_map .extern_prelude() - .map(|(name, module_id)| (name.clone(), module_id.0.into())) + .map(|(name, module_id)| (name.clone(), module_id.0)) } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> { @@ -674,7 +674,7 @@ impl<'db> Resolver<'db> { // Fill in the prelude traits if let Some((prelude, _use)) = self.module_scope.def_map.prelude() { let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + traits.extend(prelude_def_map[prelude].scope.traits()); } // Fill in module visible traits traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits()); @@ -691,8 +691,7 @@ impl<'db> Resolver<'db> { } pub fn module(&self) -> ModuleId { - let (def_map, _, local_id) = self.item_scope_(); - def_map.module_id(local_id) + self.item_scope_().2 } pub fn item_scope(&self) -> &ItemScope { @@ -886,7 +885,7 @@ impl<'db> Resolver<'db> { resolver.scopes.push(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, - module_id: DefMap::ROOT, + module_id: def_map.root, })); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the @@ -985,7 +984,7 @@ impl<'db> Resolver<'db> { } /// The innermost block scope that contains items or the module scope that contains this resolver. - fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) { + fn item_scope_(&self) -> (&DefMap, &LocalDefMap, ModuleId) { self.scopes() .find_map(|scope| match scope { Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)), @@ -1091,7 +1090,7 @@ fn resolver_for_scope_<'db>( let local_def_map = block.lookup(db).module.only_local_def_map(db); // Using `DefMap::ROOT` is okay here since inside modules other than the root, // there can't directly be expressions. - r = r.push_block_scope(def_map, local_def_map, DefMap::ROOT); + r = r.push_block_scope(def_map, local_def_map, def_map.root); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? @@ -1124,7 +1123,7 @@ impl<'db> Resolver<'db> { self, def_map: &'db DefMap, local_def_map: &'db LocalDefMap, - module_id: LocalModuleId, + module_id: ModuleId, ) -> Resolver<'db> { self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, module_id })) } @@ -1284,9 +1283,9 @@ pub trait HasResolver: Copy { impl HasResolver for ModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { let (mut def_map, local_def_map) = self.local_def_map(db); - let mut module_id = self.local_id; + let mut module_id = self; - if !self.is_within_block() { + if self.block(db).is_none() { return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, local_def_map, module_id }, @@ -1296,9 +1295,9 @@ impl HasResolver for ModuleId { let mut modules: SmallVec<[_; 1]> = smallvec![]; while let Some(parent) = def_map.parent() { let block_def_map = mem::replace(&mut def_map, parent.def_map(db)); - let block_module_id = mem::replace(&mut module_id, parent.local_id); + let block_module_id = mem::replace(&mut module_id, parent); modules.push((block_def_map, block_module_id)); - if !parent.is_within_block() { + if parent.block(db).is_none() { break; } } @@ -1313,16 +1312,6 @@ impl HasResolver for ModuleId { } } -impl HasResolver for CrateRootModuleId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { - let (def_map, local_def_map) = self.local_def_map(db); - Resolver { - scopes: vec![], - module_scope: ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT }, - } - } -} - impl HasResolver for TraitId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index e8ccf56059..a13ef484ba 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -860,7 +860,7 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>( mut field_name: impl FnMut(usize, &Field) -> Name, override_visibility: Option<Option<ast::Visibility>>, ) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> { - let cfg_options = module.krate.cfg_options(db); + let cfg_options = module.krate(db).cfg_options(db); let mut col = ExprCollector::new(db, module, fields.file_id); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { @@ -938,7 +938,7 @@ impl EnumVariants { let ast_id_map = db.ast_id_map(source.file_id); let mut diagnostics = ThinVec::new(); - let cfg_options = loc.container.krate.cfg_options(db); + let cfg_options = loc.container.krate(db).cfg_options(db); let mut index = 0; let Some(variants) = source.value.variant_list() else { return (EnumVariants { variants: Box::default() }, None); diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index 153fd195f0..6fe016f1e6 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -148,7 +148,7 @@ impl HasChildSource<LocalFieldId> for VariantId { let mut map = ArenaMap::new(); match &src.value { ast::StructKind::Tuple(fl) => { - let cfg_options = container.krate.cfg_options(db); + let cfg_options = container.krate(db).cfg_options(db); let mut idx = 0; for fd in fl.fields() { let enabled = AttrFlags::is_cfg_enabled_for(&fd, cfg_options).is_ok(); @@ -163,7 +163,7 @@ impl HasChildSource<LocalFieldId> for VariantId { } } ast::StructKind::Record(fl) => { - let cfg_options = container.krate.cfg_options(db); + let cfg_options = container.krate(db).cfg_options(db); let mut idx = 0; for fd in fl.fields() { let enabled = AttrFlags::is_cfg_enabled_for(&fd, cfg_options).is_ok(); diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs index 3bb9c361b3..cdb49b2970 100644 --- a/crates/hir-def/src/test_db.rs +++ b/crates/hir-def/src/test_db.rs @@ -13,7 +13,7 @@ use syntax::{AstNode, algo, ast}; use triomphe::Arc; use crate::{ - LocalModuleId, Lookup, ModuleDefId, ModuleId, + Lookup, ModuleDefId, ModuleId, db::DefDatabase, nameres::{DefMap, ModuleSource, block_def_map, crate_def_map}, src::HasSource, @@ -154,7 +154,7 @@ impl TestDB { let crate_def_map = crate_def_map(self, krate); for (local_id, data) in crate_def_map.modules() { if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) { - return crate_def_map.module_id(local_id); + return local_id; } } } @@ -168,7 +168,7 @@ impl TestDB { def_map = match self.block_at_position(def_map, position) { Some(it) => it, - None => return def_map.module_id(module), + None => return module, }; loop { let new_map = self.block_at_position(def_map, position); @@ -178,16 +178,16 @@ impl TestDB { } _ => { // FIXME: handle `mod` inside block expression - return def_map.module_id(DefMap::ROOT); + return def_map.root; } } } } /// Finds the smallest/innermost module in `def_map` containing `position`. - fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId { + fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> ModuleId { let mut size = None; - let mut res = DefMap::ROOT; + let mut res = def_map.root; for (module, data) in def_map.modules() { let src = data.definition_source(self); // We're not comparing the `base_db::EditionedFileId`, but rather the VFS `FileId`, because diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 948f6ed8c3..a1645de6ec 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -9,8 +9,8 @@ use syntax::ast::{self, HasVisibility}; use triomphe::Arc; use crate::{ - AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId, - VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, + AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId, + db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -44,7 +44,7 @@ impl Visibility { pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { let to_module = match self { Visibility::Module(m, _) => m, - Visibility::PubCrate(krate) => return from_module.krate == krate, + Visibility::PubCrate(krate) => return from_module.krate(db) == krate, Visibility::Public => return true, }; if from_module == to_module { @@ -52,30 +52,37 @@ impl Visibility { return true; } // if they're not in the same crate, it can't be visible - if from_module.krate != to_module.krate { + if from_module.krate(db) != to_module.krate(db) { return false; } let def_map = from_module.def_map(db); - Self::is_visible_from_def_map_(db, def_map, to_module, from_module.local_id) + Self::is_visible_from_def_map_(db, def_map, to_module, from_module) } pub(crate) fn is_visible_from_def_map( self, db: &dyn DefDatabase, def_map: &DefMap, - from_module: LocalModuleId, + from_module: ModuleId, ) -> bool { + if cfg!(debug_assertions) { + _ = def_map.modules[from_module]; + } let to_module = match self { Visibility::Module(m, _) => m, - Visibility::PubCrate(krate) => return def_map.krate() == krate, + Visibility::PubCrate(krate) => return from_module.krate(db) == krate, Visibility::Public => return true, }; + if from_module == to_module { + // if the modules are the same, visibility is trivially satisfied + return true; + } // if they're not in the same crate, it can't be visible - if def_map.krate() != to_module.krate { + if def_map.krate() != to_module.krate(db) { return false; } - if from_module == to_module.local_id && def_map.block_id() == to_module.block { + if from_module == to_module && def_map.block_id() == to_module.block(db) { // if the modules are the same, visibility is trivially satisfied return true; } @@ -86,9 +93,9 @@ impl Visibility { db: &dyn DefDatabase, def_map: &DefMap, mut to_module: ModuleId, - mut from_module: LocalModuleId, + mut from_module: ModuleId, ) -> bool { - debug_assert_eq!(to_module.krate, def_map.krate()); + debug_assert_eq!(to_module.krate(db), def_map.krate()); // `to_module` might be the root module of a block expression. Those have the same // visibility as the containing module (even though no items are directly nameable from // there, getting this right is important for method resolution). @@ -98,7 +105,7 @@ impl Visibility { // currently computing, so we must not call the `def_map` query for it. let def_map_block = def_map.block_id(); loop { - match (to_module.block, def_map_block) { + match (to_module.block(db), def_map_block) { // `to_module` is not a block, so there is no parent def map to use. (None, _) => (), // `to_module` is at `def_map`'s block, no need to move further. @@ -117,7 +124,7 @@ impl Visibility { let mut def_map = def_map; let mut parent_arc; loop { - if def_map.module_id(from_module) == to_module { + if from_module == to_module { return true; } match def_map[from_module].parent { @@ -127,7 +134,7 @@ impl Visibility { Some(module) => { parent_arc = module.def_map(db); def_map = parent_arc; - from_module = module.local_id; + from_module = module; } // Reached the root module, nothing left to check. None => return false, @@ -141,7 +148,12 @@ impl Visibility { /// /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only /// visible in unrelated modules). - pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { + pub(crate) fn max( + self, + db: &dyn DefDatabase, + other: Visibility, + def_map: &DefMap, + ) -> Option<Visibility> { match (self, other) { (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public), (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { @@ -153,11 +165,7 @@ impl Visibility { } (Visibility::Module(mod_, _), Visibility::PubCrate(krate)) | (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => { - if mod_.krate == krate { - Some(Visibility::PubCrate(krate)) - } else { - None - } + if mod_.krate(db) == krate { Some(Visibility::PubCrate(krate)) } else { None } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { if mod_a == mod_b { @@ -175,26 +183,24 @@ impl Visibility { )); } - if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { + if mod_a.krate(db) != def_map.krate() || mod_b.krate(db) != def_map.krate() { return None; } let def_block = def_map.block_id(); - if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { + if mod_a.block(db) != def_block || mod_b.block(db) != def_block { return None; } - let mut a_ancestors = - iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); + let mut a_ancestors = iter::successors(Some(mod_a), |&m| def_map[m].parent); - if a_ancestors.any(|m| m == mod_b.local_id) { + if a_ancestors.any(|m| m == mod_b) { // B is above A return Some(Visibility::Module(mod_b, expl_b)); } - let mut b_ancestors = - iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); - if b_ancestors.any(|m| m == mod_a.local_id) { + let mut b_ancestors = iter::successors(Some(mod_b), |&m| def_map[m].parent); + if b_ancestors.any(|m| m == mod_a) { // A is above B return Some(Visibility::Module(mod_a, expl_a)); } @@ -208,7 +214,12 @@ impl Visibility { /// /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only /// visible in unrelated modules). - pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { + pub(crate) fn min( + self, + db: &dyn DefDatabase, + other: Visibility, + def_map: &DefMap, + ) -> Option<Visibility> { match (self, other) { (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis), (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { @@ -220,10 +231,10 @@ impl Visibility { } (Visibility::Module(mod_, exp), Visibility::PubCrate(krate)) | (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => { - if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None } + if mod_.krate(db) == krate { Some(Visibility::Module(mod_, exp)) } else { None } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a == mod_b { + if mod_a.krate(db) != mod_b.krate(db) { // Most module visibilities are `pub(self)`, and assuming no errors // this will be the common and thus fast path. return Some(Visibility::Module( @@ -238,26 +249,24 @@ impl Visibility { )); } - if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { + if mod_a.krate(db) != def_map.krate() || mod_b.krate(db) != def_map.krate() { return None; } let def_block = def_map.block_id(); - if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { + if mod_a.block(db) != def_block || mod_b.block(db) != def_block { return None; } - let mut a_ancestors = - iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); + let mut a_ancestors = iter::successors(Some(mod_a), |&m| def_map[m].parent); - if a_ancestors.any(|m| m == mod_b.local_id) { + if a_ancestors.any(|m| m == mod_b) { // B is above A return Some(Visibility::Module(mod_a, expl_a)); } - let mut b_ancestors = - iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); - if b_ancestors.any(|m| m == mod_a.local_id) { + let mut b_ancestors = iter::successors(Some(mod_b), |&m| def_map[m].parent); + if b_ancestors.any(|m| m == mod_a) { // A is above B return Some(Visibility::Module(mod_b, expl_b)); } diff --git a/crates/hir-expand/src/builtin/attr_macro.rs b/crates/hir-expand/src/builtin/attr_macro.rs index 25dd933f26..06b9b5418e 100644 --- a/crates/hir-expand/src/builtin/attr_macro.rs +++ b/crates/hir-expand/src/builtin/attr_macro.rs @@ -7,7 +7,7 @@ use crate::{ExpandResult, MacroCallId, MacroCallKind, db::ExpandDatabase, name, use super::quote; macro_rules! register_builtin { - ($(($name:ident, $variant:ident) => $expand:ident),* ) => { + ($(($name:ident, $variant:ident) => $expand:ident),* $(,)? ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinAttrExpander { $($variant),* @@ -65,7 +65,8 @@ register_builtin! { (derive_const, DeriveConst) => derive_expand, (global_allocator, GlobalAllocator) => dummy_attr_expand, (test, Test) => dummy_gate_test_expand, - (test_case, TestCase) => dummy_gate_test_expand + (test_case, TestCase) => dummy_gate_test_expand, + (define_opaque, DefineOpaque) => dummy_attr_expand, } pub fn find_builtin_attr(ident: &name::Name) -> Option<BuiltinAttrExpander> { diff --git a/crates/hir-expand/src/cfg_process.rs b/crates/hir-expand/src/cfg_process.rs index 227a62ff9f..a0de36548e 100644 --- a/crates/hir-expand/src/cfg_process.rs +++ b/crates/hir-expand/src/cfg_process.rs @@ -162,25 +162,19 @@ fn macro_input_callback( } } Meta::TokenTree { path, tt } => { - if path.segments.len() != 1 + if path.is1("cfg") { + let cfg_expr = CfgExpr::parse_from_ast( + &mut TokenTreeChildren::new(&tt).peekable(), + ); + if cfg_options().check(&cfg_expr) == Some(false) { + return ControlFlow::Break(ItemIsCfgedOut); + } + strip_current_attr = true; + } else if path.segments.len() != 1 || !is_item_tree_filtered_attr(path.segments[0].text()) { strip_current_attr = should_strip_attr(); } - - if path.segments.len() == 1 { - let name = path.segments[0].text(); - - if name == "cfg" { - let cfg_expr = CfgExpr::parse_from_ast( - &mut TokenTreeChildren::new(&tt).peekable(), - ); - if cfg_options().check(&cfg_expr) == Some(false) { - return ControlFlow::Break(ItemIsCfgedOut); - } - strip_current_attr = true; - } - } } Meta::Path { path } => { if path.segments.len() != 1 diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs index fe557d6802..fce92c8a3e 100644 --- a/crates/hir-expand/src/files.rs +++ b/crates/hir-expand/src/files.rs @@ -295,7 +295,7 @@ impl<SN: Borrow<SyntaxNode>> InFile<SN> { /// Falls back to the macro call range if the node cannot be mapped up fully. /// /// For attributes and derives, this will point back to the attribute only. - /// For the entire item use [`InFile::original_file_range_full`]. + /// For the entire item use `InFile::original_file_range_full`. pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange { self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db) } diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs index 28800c6fab..bd6f7e4f2b 100644 --- a/crates/hir-expand/src/hygiene.rs +++ b/crates/hir-expand/src/hygiene.rs @@ -8,9 +8,9 @@ //! //! # The Expansion Order Hierarchy //! -//! `ExpnData` in rustc, rust-analyzer's version is [`MacroCallLoc`]. Traversing the hierarchy -//! upwards can be achieved by walking up [`MacroCallLoc::kind`]'s contained file id, as -//! [`MacroFile`]s are interned [`MacroCallLoc`]s. +//! `ExpnData` in rustc, rust-analyzer's version is `MacroCallLoc`. Traversing the hierarchy +//! upwards can be achieved by walking up `MacroCallLoc::kind`'s contained file id, as +//! `MacroFile`s are interned `MacroCallLoc`s. //! //! # The Macro Definition Hierarchy //! @@ -18,7 +18,7 @@ //! //! # The Call-site Hierarchy //! -//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer. +//! `ExpnData::call_site` in rustc, `MacroCallLoc::call_site` in rust-analyzer. // FIXME: Move this into the span crate? Not quite possible today as that depends on `MacroCallLoc` // which contains a bunch of unrelated things diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 157a5310bd..c92e41f507 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -4,6 +4,8 @@ //! tree originates not from the text of some `FileId`, but from some macro //! expansion. #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] pub use intern; @@ -860,7 +862,7 @@ impl ExpansionInfo { } /// Maps the passed in file range down into a macro expansion if it is the input to a macro call. - /// Unlike [`map_range_down_exact`], this will consider spans that contain the given span. + /// Unlike [`ExpansionInfo::map_range_down_exact`], this will consider spans that contain the given span. /// /// Note this does a linear search through the entire backing vector of the spanmap. pub fn map_range_down( diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 0a36c0e726..abab3bfb25 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -8,10 +8,9 @@ use std::fmt; use hir_def::{TraitId, TypeAliasId}; use rustc_type_ir::inherent::{IntoKind, Ty as _}; use tracing::debug; -use triomphe::Arc; use crate::{ - TraitEnvironment, + ParamEnvAndCrate, db::HirDatabase, infer::InferenceContext, next_solver::{ @@ -35,13 +34,13 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20; /// detects a cycle in the deref chain. pub fn autoderef<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ty: Canonical<'db, Ty<'db>>, ) -> impl Iterator<Item = Ty<'db>> + use<'db> { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let (ty, _) = infcx.instantiate_canonical(&ty); - let autoderef = Autoderef::new(&infcx, &env, ty); + let autoderef = Autoderef::new(&infcx, env.param_env, ty); let mut v = Vec::new(); for (ty, _steps) in autoderef { // `ty` may contain unresolved inference variables. Since there's no chance they would be @@ -111,12 +110,12 @@ struct AutoderefTraits { // borrows it. pub(crate) trait AutoderefCtx<'db> { fn infcx(&self) -> &InferCtxt<'db>; - fn env(&self) -> &TraitEnvironment<'db>; + fn param_env(&self) -> ParamEnv<'db>; } pub(crate) struct DefaultAutoderefCtx<'a, 'db> { infcx: &'a InferCtxt<'db>, - env: &'a TraitEnvironment<'db>, + param_env: ParamEnv<'db>, } impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> { #[inline] @@ -124,8 +123,8 @@ impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> { self.infcx } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - self.env + fn param_env(&self) -> ParamEnv<'db> { + self.param_env } } @@ -136,8 +135,8 @@ impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, '_, 'db> { &self.0.table.infer_ctxt } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - &self.0.table.trait_env + fn param_env(&self) -> ParamEnv<'db> { + self.0.table.param_env } } @@ -201,7 +200,7 @@ where // autoderef expect this type to have been structurally normalized. if let TyKind::Alias(..) = ty.kind() { let (normalized_ty, obligations) = - structurally_normalize_ty(self.infcx(), self.env().env, ty)?; + structurally_normalize_ty(self.infcx(), self.param_env(), ty)?; self.state.obligations.extend(obligations); (AutoderefKind::Builtin, normalized_ty) } else { @@ -231,10 +230,10 @@ impl<'a, 'db> Autoderef<'a, 'db> { #[inline] pub(crate) fn new_with_tracking( infcx: &'a InferCtxt<'db>, - env: &'a TraitEnvironment<'db>, + param_env: ParamEnv<'db>, base_ty: Ty<'db>, ) -> Self { - Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty) + Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty) } } @@ -257,10 +256,10 @@ impl<'a, 'db> Autoderef<'a, 'db, usize> { #[inline] pub(crate) fn new( infcx: &'a InferCtxt<'db>, - env: &'a TraitEnvironment<'db>, + param_env: ParamEnv<'db>, base_ty: Ty<'db>, ) -> Self { - Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty) + Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty) } } @@ -292,8 +291,8 @@ where } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - self.ctx.env() + fn param_env(&self) -> ParamEnv<'db> { + self.ctx.param_env() } #[inline] @@ -339,7 +338,7 @@ where let trait_ref = TraitRef::new(interner, trait_.into(), [ty]); let obligation = - Obligation::new(interner, ObligationCause::new(), self.env().env, trait_ref); + Obligation::new(interner, ObligationCause::new(), self.param_env(), trait_ref); // We detect whether the self type implements `Deref` before trying to // structurally normalize. We use `predicate_may_hold_opaque_types_jank` // to support not-yet-defined opaque types. It will succeed for `impl Deref` @@ -351,7 +350,7 @@ where let (normalized_ty, obligations) = structurally_normalize_ty( self.infcx(), - self.env().env, + self.param_env(), Ty::new_projection(interner, trait_target.into(), [ty]), )?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 65250f94c2..012632aa55 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -5,7 +5,7 @@ mod tests; use base_db::Crate; use hir_def::{ - ConstId, EnumVariantId, GeneralConstId, StaticId, + ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, attrs::AttrFlags, expr_store::Body, hir::{Expr, ExprId}, @@ -16,14 +16,14 @@ use rustc_type_ir::inherent::IntoKind; use triomphe::Arc; use crate::{ - LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext, + LifetimeElisionKind, MemoryMap, ParamEnvAndCrate, TyLoweringContext, db::HirDatabase, display::DisplayTarget, infer::InferenceContext, mir::{MirEvalError, MirLowerError}, next_solver::{ - Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Ty, - ValueConst, + Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + ParamEnv, Ty, ValueConst, }, }; @@ -85,7 +85,7 @@ pub fn intern_const_ref<'a>( krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_no_crate(db); - let layout = db.layout_of_ty(ty, TraitEnvironment::empty(krate)); + let layout = db.layout_of_ty(ty, ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }); let kind = match value { LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. @@ -207,7 +207,7 @@ pub(crate) fn const_eval_discriminant_variant<'db>( let mir_body = db.monomorphized_mir_body( def, GenericArgs::new_from_iter(interner, []), - db.trait_environment_for_body(def), + ParamEnvAndCrate { param_env: db.trait_environment_for_body(def), krate: def.krate(db) }, )?; let c = interpret_mir(db, mir_body, false, None)?.0?; let c = if is_signed { @@ -259,7 +259,7 @@ pub(crate) fn const_eval_cycle_result<'db>( _: &'db dyn HirDatabase, _: ConstId, _: GenericArgs<'db>, - _: Option<Arc<TraitEnvironment<'db>>>, + _: Option<ParamEnvAndCrate<'db>>, ) -> Result<Const<'db>, ConstEvalError<'db>> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -282,9 +282,13 @@ pub(crate) fn const_eval_query<'db>( db: &'db dyn HirDatabase, def: ConstId, subst: GenericArgs<'db>, - trait_env: Option<Arc<TraitEnvironment<'db>>>, + trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<Const<'db>, ConstEvalError<'db>> { - let body = db.monomorphized_mir_body(def.into(), subst, db.trait_environment(def.into()))?; + let body = db.monomorphized_mir_body( + def.into(), + subst, + ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) }, + )?; let c = interpret_mir(db, body, false, trait_env)?.0?; Ok(c) } @@ -297,7 +301,10 @@ pub(crate) fn const_eval_static_query<'db>( let body = db.monomorphized_mir_body( def.into(), GenericArgs::new_from_iter(interner, []), - db.trait_environment_for_body(def.into()), + ParamEnvAndCrate { + param_env: db.trait_environment_for_body(def.into()), + krate: def.krate(db), + }, )?; let c = interpret_mir(db, body, false, None)?.0?; Ok(c) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index f25147622f..2dc937d760 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -126,7 +126,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const<'_>, ConstEv let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; let const_id = scope .declarations() .find_map(|x| match x { diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index df058711a6..f9523e7168 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -12,13 +12,16 @@ use salsa::plumbing::AsId; use triomphe::Arc; use crate::{ - ImplTraitId, TraitEnvironment, TyDefId, ValueTyDefId, + ImplTraitId, TyDefId, ValueTyDefId, consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{Diagnostics, GenericDefaults}, mir::{BorrowckResult, MirBody, MirLowerError}, - next_solver::{Const, EarlyBinder, GenericArgs, PolyFnSig, TraitRef, Ty, VariancesOf}, + next_solver::{ + Const, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, TraitRef, Ty, VariancesOf, + }, + traits::ParamEnvAndCrate, }; #[query_group::query_group] @@ -46,7 +49,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: DefWithBodyId, subst: GenericArgs<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] @@ -54,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: InternedClosureId, subst: GenericArgs<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::borrowck_query)] @@ -70,7 +73,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: ConstId, subst: GenericArgs<'db>, - trait_env: Option<Arc<TraitEnvironment<'db>>>, + trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<Const<'db>, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_static_query)] @@ -88,7 +91,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::transparent] fn lookup_impl_method<'db>( &'db self, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, ) -> (FunctionId, GenericArgs<'db>); @@ -101,7 +104,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: AdtId, args: GenericArgs<'db>, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError>; #[salsa::invoke(crate::layout::layout_of_ty_query)] @@ -109,7 +112,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn layout_of_ty<'db>( &'db self, ty: Ty<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] @@ -186,11 +189,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] - fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) - -> Arc<TraitEnvironment<'db>>; + fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> ParamEnv<'db>; #[salsa::invoke(crate::lower::trait_environment_query)] - fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>; + fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 79dc6e3672..a6852b87f6 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -164,7 +164,7 @@ impl<'a> DeclValidator<'a> { else { return; }; - let module_data = &module_id.def_map(self.db)[module_id.local_id]; + let module_data = &module_id.def_map(self.db)[module_id]; let Some(module_src) = module_data.declaration_source(self.db) else { return; }; diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index ffbcea4d25..0de7fab8d1 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -25,7 +25,7 @@ use triomphe::Arc; use typed_arena::Arena; use crate::{ - Adjust, InferenceResult, TraitEnvironment, + Adjust, InferenceResult, db::HirDatabase, diagnostics::match_check::{ self, @@ -33,7 +33,7 @@ use crate::{ }, display::{DisplayTarget, HirDisplay}, next_solver::{ - DbInterner, Ty, TyKind, TypingMode, + DbInterner, ParamEnv, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, }; @@ -79,7 +79,7 @@ impl BodyValidationDiagnostic { let infer = InferenceResult::for_body(db, owner); let body = db.body(owner); let env = db.trait_environment_for_body(owner); - let interner = DbInterner::new_with(db, env.krate); + let interner = DbInterner::new_with(db, owner.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into())); let mut validator = ExprValidator { @@ -100,7 +100,7 @@ struct ExprValidator<'db> { owner: DefWithBodyId, body: Arc<Body>, infer: &'db InferenceResult<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, diagnostics: Vec<BodyValidationDiagnostic>, validate_lints: bool, infcx: InferCtxt<'db>, @@ -210,7 +210,7 @@ impl<'db> ExprValidator<'db> { return; } - let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone()); + let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env); let pattern_arena = Arena::new(); let mut m_arms = Vec::with_capacity(arms.len()); @@ -332,7 +332,7 @@ impl<'db> ExprValidator<'db> { return; }; let pattern_arena = Arena::new(); - let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone()); + let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env); for stmt in &**statements { let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { continue; diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index c70c6b6119..91448d5806 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -14,14 +14,12 @@ use rustc_pattern_analysis::{ use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use stdx::never; -use triomphe::Arc; use crate::{ - TraitEnvironment, db::HirDatabase, inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from}, next_solver::{ - Ty, TyKind, + ParamEnv, Ty, TyKind, infer::{InferCtxt, traits::ObligationCause}, }, }; @@ -76,16 +74,12 @@ pub(crate) struct MatchCheckCtx<'a, 'db> { module: ModuleId, pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, infcx: &'a InferCtxt<'db>, } impl<'a, 'db> MatchCheckCtx<'a, 'db> { - pub(crate) fn new( - module: ModuleId, - infcx: &'a InferCtxt<'db>, - env: Arc<TraitEnvironment<'db>>, - ) -> Self { + pub(crate) fn new(module: ModuleId, infcx: &'a InferCtxt<'db>, env: ParamEnv<'db>) -> Self { let db = infcx.interner.db; let def_map = module.crate_def_map(db); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); @@ -114,12 +108,12 @@ impl<'a, 'db> MatchCheckCtx<'a, 'db> { } fn is_uninhabited(&self, ty: Ty<'db>) -> bool { - is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone()) + is_ty_uninhabited_from(self.infcx, ty, self.module, self.env) } /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`. fn is_foreign_non_exhaustive(&self, adt: hir_def::AdtId) -> bool { - let is_local = adt.krate(self.db) == self.module.krate(); + let is_local = adt.krate(self.db) == self.module.krate(self.db); !is_local && AttrFlags::query(self.db, adt.into()).contains(AttrFlags::NON_EXHAUSTIVE) } @@ -159,7 +153,7 @@ impl<'a, 'db> MatchCheckCtx<'a, 'db> { let ty = field_tys[fid].instantiate(self.infcx.interner, substs); let ty = self .infcx - .at(&ObligationCause::dummy(), self.env.env) + .at(&ObligationCause::dummy(), self.env) .deeply_normalize(ty) .unwrap_or(ty); (fid, ty) @@ -446,11 +440,7 @@ impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); for &(variant, _, _) in enum_data.variants.iter() { let is_uninhabited = is_enum_variant_uninhabited_from( - cx.infcx, - variant, - subst, - cx.module, - self.env.clone(), + cx.infcx, variant, subst, cx.module, self.env, ); let visibility = if is_uninhabited { VariantVisibility::Empty diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 6160962e3b..bbc381ba5d 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -165,7 +165,7 @@ impl<'db> UnsafeVisitor<'db> { DefWithBodyId::FunctionId(func) => TargetFeatures::from_fn(db, func), _ => TargetFeatures::default(), }; - let krate = resolver.module().krate(); + let krate = resolver.krate(); let edition = krate.data(db).edition; let target_feature_is_safe = match &krate.workspace_data(db).target { Ok(target) => target_feature_is_safe_in_target(target), diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index c76b8dc5f0..e1d62a9c7a 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -18,7 +18,6 @@ use hir_def::{ item_scope::ItemInNs, item_tree::FieldsShape, lang_item::LangItems, - nameres::DefMap, signatures::VariantFields, type_ref::{ ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, @@ -44,10 +43,9 @@ use rustc_type_ir::{ use smallvec::SmallVec; use span::Edition; use stdx::never; -use triomphe::Arc; use crate::{ - CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, TraitEnvironment, consteval, + CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval, db::{HirDatabase, InternedClosure, InternedCoroutine}, generics::generics, layout::Layout, @@ -55,8 +53,8 @@ use crate::{ mir::pad16, next_solver::{ AliasTy, Clause, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder, - ExistentialPredicate, FnSig, GenericArg, GenericArgs, PolyFnSig, Region, SolverDefId, Term, - TraitRef, Ty, TyKind, TypingMode, + ExistentialPredicate, FnSig, GenericArg, GenericArgs, ParamEnv, PolyFnSig, Region, + SolverDefId, Term, TraitRef, Ty, TyKind, TypingMode, abi::Safety, infer::{DbInternerInferExt, traits::ObligationCause}, }, @@ -64,6 +62,8 @@ use crate::{ utils::{detect_variant_from_bytes, fn_traits}, }; +pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>; + pub trait HirWrite: fmt::Write { fn start_location_link(&mut self, _location: ModuleDefId) {} fn end_location_link(&mut self) {} @@ -191,7 +191,7 @@ impl<'db> HirFormatter<'_, 'db> { } pub trait HirDisplay<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>; + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result; /// Returns a `Display`able type that is human-readable. fn into_displayable<'a>( @@ -309,7 +309,7 @@ pub trait HirDisplay<'db> { allow_opaque: bool, ) -> Result<String, DisplaySourceCodeError> { let mut result = String::new(); - let interner = DbInterner::new_with(db, module_id.krate()); + let interner = DbInterner::new_with(db, module_id.krate(db)); match self.hir_fmt(&mut HirFormatter { db, interner, @@ -320,7 +320,7 @@ pub trait HirDisplay<'db> { entity_limit: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, - display_target: DisplayTarget::from_crate(db, module_id.krate()), + display_target: DisplayTarget::from_crate(db, module_id.krate(db)), display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque }, show_container_bounds: false, display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, @@ -400,7 +400,7 @@ impl<'db> HirFormatter<'_, 'db> { &mut self, iter: impl IntoIterator<Item = T>, sep: &str, - ) -> Result<(), HirDisplayError> { + ) -> Result { let mut first = true; for e in iter { if !first { @@ -419,7 +419,7 @@ impl<'db> HirFormatter<'_, 'db> { } /// This allows using the `write!` macro directly with a `HirFormatter`. - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> { + pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result { // We write to a buffer first to track output size self.buf.clear(); fmt::write(&mut self.buf, args)?; @@ -429,12 +429,12 @@ impl<'db> HirFormatter<'_, 'db> { self.fmt.write_str(&self.buf).map_err(HirDisplayError::from) } - pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> { + pub fn write_str(&mut self, s: &str) -> Result { self.fmt.write_str(s)?; Ok(()) } - pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> { + pub fn write_char(&mut self, c: char) -> Result { self.fmt.write_char(c)?; Ok(()) } @@ -542,7 +542,7 @@ pub enum ClosureStyle { } impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> { - pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> { + pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result { let krate = self.display_target.krate; let interner = DbInterner::new_with(self.db, krate); self.t.hir_fmt(&mut HirFormatter { @@ -595,21 +595,18 @@ where const TYPE_HINT_TRUNCATION: &str = "…"; impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { HirDisplay::hir_fmt(*self, f) } } impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { HirDisplay::hir_fmt(self.as_ref(), f) } } -fn write_projection<'db>( - f: &mut HirFormatter<'_, 'db>, - alias: &AliasTy<'db>, -) -> Result<(), HirDisplayError> { +fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) -> Result { if f.should_truncate() { return write!(f, "{TYPE_HINT_TRUNCATION}"); } @@ -666,7 +663,7 @@ fn write_projection<'db>( } impl<'db> HirDisplay<'db> for GenericArg<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self { GenericArg::Ty(ty) => ty.hir_fmt(f), GenericArg::Lifetime(lt) => lt.hir_fmt(f), @@ -676,7 +673,7 @@ impl<'db> HirDisplay<'db> for GenericArg<'db> { } impl<'db> HirDisplay<'db> for Const<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.kind() { ConstKind::Placeholder(_) => write!(f, "<placeholder>"), ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => { @@ -715,11 +712,11 @@ fn render_const_scalar<'db>( b: &[u8], memory_map: &MemoryMap<'db>, ty: Ty<'db>, -) -> Result<(), HirDisplayError> { - let trait_env = TraitEnvironment::empty(f.krate()); +) -> Result { + let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty); - render_const_scalar_inner(f, b, memory_map, ty, trait_env) + let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty); + render_const_scalar_inner(f, b, memory_map, ty, param_env) } fn render_const_scalar_inner<'db>( @@ -727,9 +724,10 @@ fn render_const_scalar_inner<'db>( b: &[u8], memory_map: &MemoryMap<'db>, ty: Ty<'db>, - trait_env: Arc<TraitEnvironment<'db>>, -) -> Result<(), HirDisplayError> { + param_env: ParamEnv<'db>, +) -> Result { use TyKind; + let param_env = ParamEnvAndCrate { param_env, krate: f.krate() }; match ty.kind() { TyKind::Bool => write!(f, "{}", b[0] != 0), TyKind::Char => { @@ -792,7 +790,7 @@ fn render_const_scalar_inner<'db>( TyKind::Slice(ty) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); - let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(ty, param_env) else { return f.write_str("<layout-error>"); }; let size_one = layout.size.bytes_usize(); @@ -826,7 +824,7 @@ fn render_const_scalar_inner<'db>( let Ok(t) = memory_map.vtable_ty(ty_id) else { return f.write_str("<ty-missing-in-vtable-map>"); }; - let Ok(layout) = f.db.layout_of_ty(t, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(t, param_env) else { return f.write_str("<layout-error>"); }; let size = layout.size.bytes_usize(); @@ -856,7 +854,7 @@ fn render_const_scalar_inner<'db>( return f.write_str("<layout-error>"); } }); - let Ok(layout) = f.db.layout_of_ty(t, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(t, param_env) else { return f.write_str("<layout-error>"); }; let size = layout.size.bytes_usize(); @@ -868,7 +866,7 @@ fn render_const_scalar_inner<'db>( } }, TyKind::Tuple(tys) => { - let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty, param_env) else { return f.write_str("<layout-error>"); }; f.write_str("(")?; @@ -880,7 +878,7 @@ fn render_const_scalar_inner<'db>( f.write_str(", ")?; } let offset = layout.fields.offset(id).bytes_usize(); - let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty, param_env) else { f.write_str("<layout-error>")?; continue; }; @@ -891,7 +889,7 @@ fn render_const_scalar_inner<'db>( } TyKind::Adt(def, args) => { let def = def.def_id().0; - let Ok(layout) = f.db.layout_of_adt(def, args, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_adt(def, args, param_env) else { return f.write_str("<layout-error>"); }; match def { @@ -914,7 +912,7 @@ fn render_const_scalar_inner<'db>( write!(f, "{}", f.db.union_signature(u).name.display(f.db, f.edition())) } hir_def::AdtId::EnumId(e) => { - let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else { + let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else { return f.write_str("<target-layout-not-available>"); }; let Some((var_id, var_layout)) = @@ -954,7 +952,7 @@ fn render_const_scalar_inner<'db>( let Some(len) = consteval::try_const_usize(f.db, len) else { return f.write_str("<unknown-array-len>"); }; - let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(ty, param_env) else { return f.write_str("<layout-error>"); }; let size_one = layout.size.bytes_usize(); @@ -995,18 +993,19 @@ fn render_variant_after_name<'db>( data: &VariantFields, f: &mut HirFormatter<'_, 'db>, field_types: &ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>, - trait_env: Arc<TraitEnvironment<'db>>, + param_env: ParamEnv<'db>, layout: &Layout, args: GenericArgs<'db>, b: &[u8], memory_map: &MemoryMap<'db>, -) -> Result<(), HirDisplayError> { +) -> Result { + let param_env = ParamEnvAndCrate { param_env, krate: f.krate() }; match data.shape { FieldsShape::Record | FieldsShape::Tuple => { let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| { let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); let ty = field_types[id].instantiate(f.interner, args); - let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty, param_env) else { return f.write_str("<layout-error>"); }; let size = layout.size.bytes_usize(); @@ -1043,10 +1042,7 @@ fn render_variant_after_name<'db>( } impl<'db> HirDisplay<'db> for Ty<'db> { - fn hir_fmt( - &self, - f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) -> Result { let interner = f.interner; if f.should_truncate() { return write!(f, "{TYPE_HINT_TRUNCATION}"); @@ -1519,7 +1515,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { _ => false, }) .collect::<Vec<_>>(); - let krate = param.id.parent().module(db).krate(); + let krate = param.id.parent().module(db).krate(db); write_bounds_like_dyn_trait_with_prefix( f, "impl", @@ -1649,7 +1645,7 @@ fn hir_fmt_generics<'db>( parameters: &[GenericArg<'db>], generic_def: Option<hir_def::GenericDefId>, self_: Option<Ty<'db>>, -) -> Result<(), HirDisplayError> { +) -> Result { if parameters.is_empty() { return Ok(()); } @@ -1699,7 +1695,7 @@ fn hir_fmt_generic_args<'db>( parameters: &[GenericArg<'db>], generic_def: Option<hir_def::GenericDefId>, self_: Option<Ty<'db>>, -) -> Result<(), HirDisplayError> { +) -> Result { if parameters.is_empty() { return Ok(()); } @@ -1719,7 +1715,7 @@ fn hir_fmt_generic_arguments<'db>( f: &mut HirFormatter<'_, 'db>, parameters: &[GenericArg<'db>], self_: Option<Ty<'db>>, -) -> Result<(), HirDisplayError> { +) -> Result { let mut first = true; let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some()); @@ -1743,7 +1739,7 @@ fn hir_fmt_tys<'db>( f: &mut HirFormatter<'_, 'db>, tys: &[Ty<'db>], self_: Option<Ty<'db>>, -) -> Result<(), HirDisplayError> { +) -> Result { let mut first = true; for ty in tys { @@ -1759,7 +1755,7 @@ fn hir_fmt_tys<'db>( } impl<'db> HirDisplay<'db> for PolyFnSig<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder(); if let Safety::Unsafe = safety { write!(f, "unsafe ")?; @@ -1790,7 +1786,7 @@ impl<'db> HirDisplay<'db> for PolyFnSig<'db> { } impl<'db> HirDisplay<'db> for Term<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self { Term::Ty(it) => it.hir_fmt(f), Term::Const(it) => it.hir_fmt(f), @@ -1822,7 +1818,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix<'db>( this: Either<Ty<'db>, Region<'db>>, predicates: &[Clause<'db>], default_sized: SizedByDefault, -) -> Result<(), HirDisplayError> { +) -> Result { write!(f, "{prefix}")?; if !predicates.is_empty() || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. }) @@ -1839,7 +1835,7 @@ fn write_bounds_like_dyn_trait<'db>( this: Either<Ty<'db>, Region<'db>>, predicates: &[Clause<'db>], default_sized: SizedByDefault, -) -> Result<(), HirDisplayError> { +) -> Result { // Note: This code is written to produce nice results (i.e. // corresponding to surface Rust) for types that can occur in // actual Rust. It will have weird results if the predicates @@ -1983,7 +1979,7 @@ fn write_bounds_like_dyn_trait<'db>( } impl<'db> HirDisplay<'db> for TraitRef<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let trait_ = self.def_id.0; f.start_location_link(trait_.into()); write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; @@ -1994,7 +1990,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> { } impl<'db> HirDisplay<'db> for Region<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.kind() { RegionKind::ReEarlyParam(param) => { let generics = generics(f.db, param.id.parent); @@ -2028,19 +2024,20 @@ pub fn write_visibility<'db>( module_id: ModuleId, vis: Visibility, f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +) -> Result { match vis { Visibility::Public => write!(f, "pub "), Visibility::PubCrate(_) => write!(f, "pub(crate) "), Visibility::Module(vis_id, _) => { let def_map = module_id.def_map(f.db); - let root_module_id = def_map.module_id(DefMap::ROOT); + let root_module_id = def_map.root_module_id(); if vis_id == module_id { // pub(self) or omitted Ok(()) - } else if root_module_id == vis_id && !root_module_id.is_within_block() { + } else if root_module_id == vis_id && root_module_id.block(f.db).is_none() { write!(f, "pub(crate) ") - } else if module_id.containing_module(f.db) == Some(vis_id) && !vis_id.is_block_module() + } else if module_id.containing_module(f.db) == Some(vis_id) + && !vis_id.is_block_module(f.db) { write!(f, "pub(super) ") } else { @@ -2051,21 +2048,13 @@ pub fn write_visibility<'db>( } pub trait HirDisplayWithExpressionStore<'db> { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError>; + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result; } impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db> for &'_ T { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { T::hir_fmt(&**self, f, store) } } @@ -2086,16 +2075,12 @@ impl<'a, T> ExpressionStoreAdapter<'a, T> { } impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { T::hir_fmt(&self.0, f, self.1) } } impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { match &store[*self] { LifetimeRef::Named(name) => write!(f, "{}", name.display(f.db, f.edition())), LifetimeRef::Static => write!(f, "'static"), @@ -2114,11 +2099,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId { } impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { match &store[*self] { TypeRef::Never => write!(f, "!")?, TypeRef::TypeParam(param) => { @@ -2243,11 +2224,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { } impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - _store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, _store: &ExpressionStore) -> Result { // FIXME write!(f, "{{const}}")?; @@ -2256,11 +2233,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef { } impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { match self { &TypeBound::Path(path, modifier) => { match modifier { @@ -2300,11 +2273,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { } impl<'db> HirDisplayWithExpressionStore<'db> for Path { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { match (self.type_anchor(), self.kind()) { (Some(anchor), _) => { write!(f, "<")?; @@ -2452,11 +2421,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { } impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg { - fn hir_fmt( - &self, - f: &mut HirFormatter<'_, 'db>, - store: &ExpressionStore, - ) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { match self { hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, store), hir_def::expr_store::path::GenericArg::Const(_c) => { diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index d76de4b8ca..3ae6451d69 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -4,13 +4,12 @@ use hir_def::{AdtId, signatures::StructFlags}; use rustc_hash::FxHashSet; use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use stdx::never; -use triomphe::Arc; use crate::{ - InferenceResult, TraitEnvironment, consteval, + InferenceResult, consteval, method_resolution::TraitImpls, next_solver::{ - DbInterner, SimplifiedType, Ty, TyKind, + DbInterner, ParamEnv, SimplifiedType, Ty, TyKind, infer::{InferCtxt, traits::ObligationCause}, obligation_ctxt::ObligationCtxt, }, @@ -26,12 +25,12 @@ fn has_destructor(interner: DbInterner<'_>, adt: AdtId) -> bool { let Some(drop_trait) = interner.lang_items().Drop else { return false; }; - let impls = match module.containing_block() { + let impls = match module.block(db) { Some(block) => match TraitImpls::for_block(db, block) { Some(it) => &**it, None => return false, }, - None => TraitImpls::for_crate(db, module.krate()), + None => TraitImpls::for_crate(db, module.krate(db)), }; !impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty() } @@ -47,22 +46,18 @@ pub enum DropGlue { HasDropGlue, } -pub fn has_drop_glue<'db>( - infcx: &InferCtxt<'db>, - ty: Ty<'db>, - env: Arc<TraitEnvironment<'db>>, -) -> DropGlue { +pub fn has_drop_glue<'db>(infcx: &InferCtxt<'db>, ty: Ty<'db>, env: ParamEnv<'db>) -> DropGlue { has_drop_glue_impl(infcx, ty, env, &mut FxHashSet::default()) } fn has_drop_glue_impl<'db>( infcx: &InferCtxt<'db>, ty: Ty<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, visited: &mut FxHashSet<Ty<'db>>, ) -> DropGlue { let mut ocx = ObligationCtxt::new(infcx); - let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); + let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, ty).unwrap_or(ty); if !visited.insert(ty) { // Recursive type. @@ -91,7 +86,7 @@ fn has_drop_glue_impl<'db>( has_drop_glue_impl( infcx, field_ty.instantiate(infcx.interner, subst), - env.clone(), + env, visited, ) }) @@ -111,7 +106,7 @@ fn has_drop_glue_impl<'db>( has_drop_glue_impl( infcx, field_ty.instantiate(infcx.interner, subst), - env.clone(), + env, visited, ) }) @@ -124,7 +119,7 @@ fn has_drop_glue_impl<'db>( } TyKind::Tuple(tys) => tys .iter() - .map(|ty| has_drop_glue_impl(infcx, ty, env.clone(), visited)) + .map(|ty| has_drop_glue_impl(infcx, ty, env, visited)) .max() .unwrap_or(DropGlue::None), TyKind::Array(ty, len) => { @@ -142,9 +137,7 @@ fn has_drop_glue_impl<'db>( let env = db.trait_environment_for_body(owner); captures .iter() - .map(|capture| { - has_drop_glue_impl(infcx, capture.ty(db, subst), env.clone(), visited) - }) + .map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited)) .max() .unwrap_or(DropGlue::None) } @@ -169,14 +162,14 @@ fn has_drop_glue_impl<'db>( | TyKind::Placeholder(..) => DropGlue::None, TyKind::Dynamic(..) => DropGlue::HasDropGlue, TyKind::Alias(..) => { - if infcx.type_is_copy_modulo_regions(env.env, ty) { + if infcx.type_is_copy_modulo_regions(env, ty) { DropGlue::None } else { DropGlue::HasDropGlue } } TyKind::Param(_) => { - if infcx.type_is_copy_modulo_regions(env.env, ty) { + if infcx.type_is_copy_modulo_regions(env, ty) { DropGlue::None } else { DropGlue::DependOnParams diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index 4c1590a450..64b15eb017 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -3,9 +3,9 @@ use std::ops::ControlFlow; use hir_def::{ - AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, - TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, - signatures::TraitFlags, + AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, + TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, + nameres::crate_def_map, signatures::TraitFlags, }; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -130,7 +130,7 @@ pub fn dyn_compatibility_of_trait_query( } pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { - let krate = def.module(db).krate(); + let krate = def.module(db).krate(db); let interner = DbInterner::new_with(db, krate); let Some(sized) = interner.lang_items().Sized else { return false; @@ -295,7 +295,7 @@ where }) } AssocItemId::TypeAliasId(it) => { - let def_map = CrateRootModuleId::from(trait_.krate(db)).def_map(db); + let def_map = crate_def_map(db, trait_.krate(db)); if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) { ControlFlow::Continue(()) } else { @@ -402,7 +402,7 @@ fn receiver_is_dispatchable<'db>( let sig = sig.instantiate_identity(); let module = trait_.module(db); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); let self_param_id = TypeParamId::from_unchecked(TypeOrConstParamId { parent: trait_.into(), local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), @@ -427,9 +427,14 @@ fn receiver_is_dispatchable<'db>( }; let meta_sized_did = lang_items.MetaSized; - let Some(meta_sized_did) = meta_sized_did else { - return false; - }; + + // TODO: This is for supporting dyn compatibility for toolchains doesn't contain `MetaSized` + // trait. Uncomment and short circuit here once `MINIMUM_SUPPORTED_TOOLCHAIN_VERSION` + // become > 1.88.0 + // + // let Some(meta_sized_did) = meta_sized_did else { + // return false; + // }; // Type `U` // FIXME: That seems problematic to fake a generic param like that? @@ -450,17 +455,16 @@ fn receiver_is_dispatchable<'db>( }); let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); - let meta_sized_predicate = - TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]); + let meta_sized_predicate = meta_sized_did + .map(|did| TraitRef::new(interner, did.into(), [unsized_self_ty]).upcast(interner)); ParamEnv { clauses: Clauses::new_from_iter( interner, - generic_predicates.iter_identity_copied().chain([ - unsize_predicate.upcast(interner), - trait_predicate.upcast(interner), - meta_sized_predicate.upcast(interner), - ]), + generic_predicates + .iter_identity_copied() + .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)]) + .chain(meta_sized_predicate), ), } }; diff --git a/crates/hir-ty/src/dyn_compatibility/tests.rs b/crates/hir-ty/src/dyn_compatibility/tests.rs index f90cd608e9..5c9b06e39a 100644 --- a/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -35,7 +35,7 @@ fn check_dyn_compatibility<'a>( for (trait_id, name) in file_ids.into_iter().flat_map(|file_id| { let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; scope .declarations() .filter_map(|def| { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index ab173799bc..70868e4b95 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -653,19 +653,16 @@ impl<'db> InferenceResult<'db> { } pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<Ty<'db>> { match self.expr_adjustments.get(&id).and_then(|adjustments| { - adjustments - .iter() - .filter(|adj| { - // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140 - !matches!( - adj, - Adjustment { - kind: Adjust::NeverToAny, - target, - } if target.is_never() - ) - }) - .next_back() + adjustments.iter().rfind(|adj| { + // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140 + !matches!( + adj, + Adjustment { + kind: Adjust::NeverToAny, + target, + } if target.is_never() + ) + }) }) { Some(adjustment) => Some(adjustment.target), None => self.type_of_expr.get(id).copied(), @@ -944,7 +941,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { resolver: Resolver<'db>, ) -> Self { let trait_env = db.trait_environment_for_body(owner); - let table = unify::InferenceTable::new(db, trait_env, Some(owner)); + let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); let types = InternedStandardTypes::new(table.interner()); InferenceContext { result: InferenceResult::new(types.error), diff --git a/crates/hir-ty/src/infer/autoderef.rs b/crates/hir-ty/src/infer/autoderef.rs index 1af102af23..b54a6cdee2 100644 --- a/crates/hir-ty/src/infer/autoderef.rs +++ b/crates/hir-ty/src/infer/autoderef.rs @@ -16,11 +16,11 @@ use crate::{ impl<'db> InferenceTable<'db> { pub(crate) fn autoderef(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db, usize> { - Autoderef::new(&self.infer_ctxt, &self.trait_env, base_ty) + Autoderef::new(&self.infer_ctxt, self.param_env, base_ty) } pub(crate) fn autoderef_with_tracking(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db> { - Autoderef::new_with_tracking(&self.infer_ctxt, &self.trait_env, base_ty) + Autoderef::new_with_tracking(&self.infer_ctxt, self.param_env, base_ty) } } diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 89ebd2b21d..14b0c9076c 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -367,7 +367,7 @@ impl<'db> InferenceContext<'_, 'db> { _ = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.trait_env.env) + .at(&ObligationCause::new(), self.table.param_env) .eq(inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); @@ -749,19 +749,18 @@ impl<'db> InferenceContext<'_, 'db> { { // Check that E' = S'. let cause = ObligationCause::new(); - let InferOk { value: (), obligations } = table - .infer_ctxt - .at(&cause, table.trait_env.env) - .eq(expected_ty, supplied_ty)?; + let InferOk { value: (), obligations } = + table.infer_ctxt.at(&cause, table.param_env).eq(expected_ty, supplied_ty)?; all_obligations.extend(obligations); } let supplied_output_ty = supplied_sig.output(); let cause = ObligationCause::new(); - let InferOk { value: (), obligations } = table - .infer_ctxt - .at(&cause, table.trait_env.env) - .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; + let InferOk { value: (), obligations } = + table + .infer_ctxt + .at(&cause, table.param_env) + .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; all_obligations.extend(obligations); let inputs = supplied_sig diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index 251e7f7cf6..308c01865a 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -43,11 +43,12 @@ impl<'db> HirPlace<'db> { for p in &self.projections { ty = p.projected_ty( &ctx.table.infer_ctxt, + ctx.table.param_env, ty, |_, _, _| { unreachable!("Closure field only happens in MIR"); }, - ctx.owner.module(ctx.db).krate(), + ctx.owner.module(ctx.db).krate(ctx.db), ); } ty @@ -149,7 +150,7 @@ impl<'db> CapturedItem<'db> { } } } - if is_raw_identifier(&result, owner.module(db).krate().data(db).edition) { + if is_raw_identifier(&result, owner.module(db).krate(db).data(db).edition) { result.insert_str(0, "r#"); } result @@ -839,11 +840,12 @@ impl<'db> InferenceContext<'_, 'db> { for (i, p) in capture.place.projections.iter().enumerate() { ty = p.projected_ty( &self.table.infer_ctxt, + self.table.param_env, ty, |_, _, _| { unreachable!("Closure field only happens in MIR"); }, - self.owner.module(self.db).krate(), + self.owner.module(self.db).krate(self.db), ); if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index df24148920..77c7155550 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -50,10 +50,9 @@ use rustc_type_ir::{ }; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; -use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, PointerCast, TargetFeatures, TraitEnvironment, + Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures, autoderef::Autoderef, db::{HirDatabase, InternedClosureId}, infer::{ @@ -62,7 +61,7 @@ use crate::{ next_solver::{ Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper, Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed, - GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind, + GenericArgs, ParamEnv, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind, TypingMode, infer::{ DbInternerInferExt, InferCtxt, InferOk, InferResult, @@ -77,7 +76,7 @@ use crate::{ trait CoerceDelegate<'db> { fn infcx(&self) -> &InferCtxt<'db>; - fn env(&self) -> &TraitEnvironment<'db>; + fn param_env(&self) -> ParamEnv<'db>; fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget); fn set_diverging(&mut self, diverging_ty: Ty<'db>); @@ -137,8 +136,8 @@ where } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - self.delegate.env() + fn param_env(&self) -> ParamEnv<'db> { + self.delegate.param_env() } #[inline] @@ -169,7 +168,7 @@ where fn unify_raw(&self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.infcx().commit_if_ok(|_| { - let at = self.infcx().at(&self.cause, self.env().env); + let at = self.infcx().at(&self.cause, self.param_env()); let res = if self.use_lub { at.lub(b, a) @@ -329,7 +328,7 @@ where obligations.push(Obligation::new( self.interner(), self.cause.clone(), - self.env().env, + self.param_env(), Binder::dummy(PredicateKind::Coerce(CoercePredicate { a: source_ty, b: target_ty, @@ -381,7 +380,7 @@ where let mut first_error = None; let mut r_borrow_var = None; - let mut autoderef = Autoderef::new_with_tracking(self.infcx(), self.env(), a); + let mut autoderef = Autoderef::new_with_tracking(self.infcx(), self.param_env(), a); let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { @@ -684,7 +683,7 @@ where let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new( self.interner(), cause, - self.env().env, + self.param_env(), TraitRef::new( self.interner(), coerce_unsized_did.into(), @@ -975,8 +974,8 @@ impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> { &self.0.table.infer_ctxt } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - &self.0.table.trait_env + fn param_env(&self) -> ParamEnv<'db> { + self.0.table.param_env } #[inline] @@ -1104,12 +1103,8 @@ impl<'db> InferenceContext<'_, 'db> { match self.table.commit_if_ok(|table| { // We need to eagerly handle nested obligations due to lazy norm. let mut ocx = ObligationCtxt::new(&table.infer_ctxt); - let value = ocx.lub( - &ObligationCause::new(), - table.trait_env.env, - prev_ty, - new_ty, - )?; + let value = + ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?; if ocx.try_evaluate_obligations().is_empty() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { @@ -1152,7 +1147,7 @@ impl<'db> InferenceContext<'_, 'db> { let sig = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.trait_env.env) + .at(&ObligationCause::new(), self.table.param_env) .lub(a_sig, b_sig) .map(|ok| self.table.register_infer_ok(ok))?; @@ -1231,7 +1226,7 @@ impl<'db> InferenceContext<'_, 'db> { .commit_if_ok(|table| { table .infer_ctxt - .at(&ObligationCause::new(), table.trait_env.env) + .at(&ObligationCause::new(), table.param_env) .lub(prev_ty, new_ty) }) .unwrap_err()) @@ -1483,7 +1478,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { // // Another example is `break` with no argument expression. assert!(expression_ty.is_unit(), "if let hack without unit type"); - icx.table.infer_ctxt.at(cause, icx.table.trait_env.env).eq(expected, found).map( + icx.table.infer_ctxt.at(cause, icx.table.param_env).eq(expected, found).map( |infer_ok| { icx.table.register_infer_ok(infer_ok); expression_ty @@ -1540,7 +1535,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { pub fn could_coerce<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { coerce(db, env, tys).is_ok() @@ -1548,7 +1543,7 @@ pub fn could_coerce<'db>( struct HirCoercionDelegate<'a, 'db> { infcx: &'a InferCtxt<'db>, - env: &'a TraitEnvironment<'db>, + param_env: ParamEnv<'db>, target_features: &'a TargetFeatures<'db>, } @@ -1558,8 +1553,8 @@ impl<'db> CoerceDelegate<'db> for HirCoercionDelegate<'_, 'db> { self.infcx } #[inline] - fn env(&self) -> &TraitEnvironment<'db> { - self.env + fn param_env(&self) -> ParamEnv<'db> { + self.param_env } fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) { (self.target_features, TargetFeatureIsSafeInTarget::No) @@ -1573,7 +1568,7 @@ impl<'db> CoerceDelegate<'db> for HirCoercionDelegate<'_, 'db> { fn coerce<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> Result<(Vec<Adjustment<'db>>, Ty<'db>), TypeError<DbInterner<'db>>> { let interner = DbInterner::new_with(db, env.krate); @@ -1586,7 +1581,7 @@ fn coerce<'db>( let mut coerce = Coerce { delegate: HirCoercionDelegate { infcx: &infcx, - env: &env, + param_env: env.param_env, target_features: &target_features, }, cause, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 01508b0f9b..4e1711e48e 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -4,7 +4,7 @@ use std::{iter::repeat_with, mem}; use either::Either; use hir_def::{ - BlockId, FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId, + FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId, expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, @@ -23,7 +23,7 @@ use syntax::ast::RangeOp; use tracing::debug; use crate::{ - Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness, TraitEnvironment, + Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness, autoderef::InferenceContextAutoderef, consteval, db::InternedCoroutine, @@ -377,11 +377,11 @@ impl<'db> InferenceContext<'_, 'db> { ); self.types.bool } - Expr::Block { statements, tail, label, id } => { - self.infer_block(tgt_expr, *id, statements, *tail, *label, expected) + Expr::Block { statements, tail, label, id: _ } => { + self.infer_block(tgt_expr, statements, *tail, *label, expected) } - Expr::Unsafe { id, statements, tail } => { - self.infer_block(tgt_expr, *id, statements, *tail, None, expected) + Expr::Unsafe { id: _, statements, tail } => { + self.infer_block(tgt_expr, statements, *tail, None, expected) } Expr::Const(id) => { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { @@ -389,8 +389,8 @@ impl<'db> InferenceContext<'_, 'db> { }) .1 } - Expr::Async { id, statements, tail } => { - self.infer_async_block(tgt_expr, id, statements, tail) + Expr::Async { id: _, statements, tail } => { + self.infer_async_block(tgt_expr, statements, tail) } &Expr::Loop { body, label } => { // FIXME: should be: @@ -1167,7 +1167,6 @@ impl<'db> InferenceContext<'_, 'db> { fn infer_async_block( &mut self, tgt_expr: ExprId, - id: &Option<BlockId>, statements: &[Statement], tail: &Option<ExprId>, ) -> Ty<'db> { @@ -1179,7 +1178,7 @@ impl<'db> InferenceContext<'_, 'db> { // FIXME: We should handle async blocks like we handle closures let expected = &Expectation::has_type(ret_ty); let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - let ty = this.infer_block(tgt_expr, *id, statements, *tail, None, expected); + let ty = this.infer_block(tgt_expr, statements, *tail, None, expected); if let Some(target) = expected.only_has_type(&mut this.table) { match this.coerce(tgt_expr.into(), ty, target, AllowTwoPhase::No, ExprIsRead::Yes) { Ok(res) => res, @@ -1447,7 +1446,6 @@ impl<'db> InferenceContext<'_, 'db> { fn infer_block( &mut self, expr: ExprId, - block_id: Option<BlockId>, statements: &[Statement], tail: Option<ExprId>, label: Option<LabelId>, @@ -1455,11 +1453,6 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let coerce_ty = expected.coercion_target_type(&mut self.table); let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr); - let prev_env = block_id.map(|block_id| { - let prev_env = self.table.trait_env.clone(); - TraitEnvironment::with_block(&mut self.table.trait_env, block_id); - prev_env - }); let (break_ty, ty) = self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| { @@ -1566,9 +1559,6 @@ impl<'db> InferenceContext<'_, 'db> { } }); self.resolver.reset_to_guard(g); - if let Some(prev_env) = prev_env { - self.table.trait_env = prev_env; - } break_ty.unwrap_or(ty) } @@ -1974,7 +1964,7 @@ impl<'db> InferenceContext<'_, 'db> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = ObligationCause::new(); - ocx.sup(&origin, self.table.trait_env.env, expected_output, formal_output)?; + ocx.sup(&origin, self.table.param_env, expected_output, formal_output)?; if !ocx.try_evaluate_obligations().is_empty() { return Err(TypeError::Mismatch); } @@ -2066,7 +2056,7 @@ impl<'db> InferenceContext<'_, 'db> { let formal_ty_error = this .table .infer_ctxt - .at(&ObligationCause::new(), this.table.trait_env.env) + .at(&ObligationCause::new(), this.table.param_env) .eq(formal_input_ty, coerced_ty); // If neither check failed, the types are compatible @@ -2143,7 +2133,7 @@ impl<'db> InferenceContext<'_, 'db> { self.db, GenericDefId::from_callable(self.db, fn_def.0), ); - let param_env = self.table.trait_env.env; + let param_env = self.table.param_env; self.table.register_predicates(clauses_as_obligations( generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()), ObligationCause::new(), @@ -2162,7 +2152,7 @@ impl<'db> InferenceContext<'_, 'db> { self.table.register_predicate(Obligation::new( self.interner(), ObligationCause::new(), - self.table.trait_env.env, + self.table.param_env, TraitRef::new(self.interner(), trait_.into(), substs), )); } diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs index 6fbac8f5ae..8236de167f 100644 --- a/crates/hir-ty/src/infer/op.rs +++ b/crates/hir-ty/src/infer/op.rs @@ -343,7 +343,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let obligation = Obligation::new( self.interner(), cause, - self.table.trait_env.env, + self.table.param_env, TraitRef::new_from_args(self.interner(), trait_did.into(), args), ); let mut ocx = ObligationCtxt::new(self.infcx()); diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs index ba4b53a0d7..ce4597f83d 100644 --- a/crates/hir-ty/src/infer/opaques.rs +++ b/crates/hir-ty/src/infer/opaques.rs @@ -136,7 +136,7 @@ impl<'db> InferenceContext<'_, 'db> { } let cause = ObligationCause::new(); - let at = self.table.infer_ctxt.at(&cause, self.table.trait_env.env); + let at = self.table.infer_ctxt.at(&cause, self.table.param_env); let hidden_type = match at.deeply_normalize(hidden_type) { Ok(hidden_type) => hidden_type, Err(_errors) => OpaqueHiddenType { ty: self.types.error }, diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 6e3d15893f..301cbf462c 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -224,7 +224,7 @@ impl<'db> InferenceContext<'_, 'db> { ) { let interner = self.interner(); let predicates = GenericPredicates::query_all(self.db, def); - let param_env = self.table.trait_env.env; + let param_env = self.table.param_env; self.table.register_predicates(clauses_as_obligations( predicates.iter_instantiated_copied(interner, subst.as_slice()), ObligationCause::new(), @@ -343,7 +343,7 @@ impl<'db> InferenceContext<'_, 'db> { self.table.register_predicate(Obligation::new( self.interner(), ObligationCause::new(), - self.table.trait_env.env, + self.table.param_env, trait_ref, )); args diff --git a/crates/hir-ty/src/infer/place_op.rs b/crates/hir-ty/src/infer/place_op.rs index 9544fb449f..3ef5e5870a 100644 --- a/crates/hir-ty/src/infer/place_op.rs +++ b/crates/hir-ty/src/infer/place_op.rs @@ -124,7 +124,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { ctx.table.register_predicate(Obligation::new( ctx.interner(), ObligationCause::new(), - ctx.table.trait_env.env, + ctx.table.param_env, ClauseKind::ConstArgHasType(ct, ctx.types.usize), )); self_ty = Ty::new_slice(ctx.interner(), element_ty); diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index bc3c46341c..a5060416a1 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -2,6 +2,7 @@ use std::fmt; +use base_db::Crate; use hir_def::{AdtId, DefWithBodyId, GenericParamId}; use hir_expand::name::Name; use intern::sym; @@ -12,15 +13,13 @@ use rustc_type_ir::{ solve::Certainty, }; use smallvec::SmallVec; -use triomphe::Arc; use crate::{ - TraitEnvironment, db::HirDatabase, next_solver::{ AliasTy, Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, - GenericArgs, Goal, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, - TyKind, TypingMode, + GenericArgs, Goal, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, + Ty, TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ DbInternerInferExt, InferCtxt, InferOk, InferResult, @@ -32,7 +31,8 @@ use crate::{ obligation_ctxt::ObligationCtxt, }, traits::{ - FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, + FnTrait, NextTraitSolveResult, ParamEnvAndCrate, next_trait_solve_canonical_in_ctxt, + next_trait_solve_in_ctxt, }, }; @@ -89,7 +89,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { /// unresolved goal `T = U`. pub fn could_unify<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { could_unify_impl(db, env, tys, |ctxt| ctxt.try_evaluate_obligations()) @@ -101,7 +101,7 @@ pub fn could_unify<'db>( /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U` pub fn could_unify_deeply<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { could_unify_impl(db, env, tys, |ctxt| ctxt.evaluate_obligations_error_on_ambiguity()) @@ -109,14 +109,14 @@ pub fn could_unify_deeply<'db>( fn could_unify_impl<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, select: for<'a> fn(&mut ObligationCtxt<'a, 'db>) -> Vec<NextSolverError<'db>>, ) -> bool { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); - let at = infcx.at(&cause, env.env); + let at = infcx.at(&cause, env.param_env); let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys); let mut ctxt = ObligationCtxt::new(&infcx); let can_unify = at @@ -129,7 +129,7 @@ fn could_unify_impl<'db>( #[derive(Clone)] pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) trait_env: Arc<TraitEnvironment<'db>>, + pub(crate) param_env: ParamEnv<'db>, pub(crate) infer_ctxt: InferCtxt<'db>, pub(super) fulfillment_cx: FulfillmentCtxt<'db>, pub(super) diverging_type_vars: FxHashSet<Ty<'db>>, @@ -145,10 +145,11 @@ impl<'db> InferenceTable<'db> { /// Outside it, always pass `owner = None`. pub(crate) fn new( db: &'db dyn HirDatabase, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnv<'db>, + krate: Crate, owner: Option<DefWithBodyId>, ) -> Self { - let interner = DbInterner::new_with(db, trait_env.krate); + let interner = DbInterner::new_with(db, krate); let typing_mode = match owner { Some(owner) => TypingMode::typeck_for_body(interner, owner.into()), // IDE things wants to reveal opaque types. @@ -157,7 +158,7 @@ impl<'db> InferenceTable<'db> { let infer_ctxt = interner.infer_ctxt().build(typing_mode); InferenceTable { db, - trait_env, + param_env: trait_env, fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), infer_ctxt, diverging_type_vars: FxHashSet::default(), @@ -170,7 +171,7 @@ impl<'db> InferenceTable<'db> { } pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'db>) -> bool { - self.infer_ctxt.type_is_copy_modulo_regions(self.trait_env.env, ty) + self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty) } pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool { @@ -272,7 +273,7 @@ impl<'db> InferenceTable<'db> { pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> { self.infer_ctxt - .at(&ObligationCause::new(), self.trait_env.env) + .at(&ObligationCause::new(), self.param_env) .structurally_normalize_ty(alias, &mut self.fulfillment_cx) .unwrap_or(alias) } @@ -332,7 +333,7 @@ impl<'db> InferenceTable<'db> { } pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> { - self.infer_ctxt.at(cause, self.trait_env.env) + self.infer_ctxt.at(cause, self.param_env) } pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { @@ -374,7 +375,7 @@ impl<'db> InferenceTable<'db> { // in a reentrant borrow, causing an ICE. let result = self .infer_ctxt - .at(&ObligationCause::misc(), self.trait_env.env) + .at(&ObligationCause::misc(), self.param_env) .structurally_normalize_ty(ty, &mut self.fulfillment_cx); match result { Ok(normalized_ty) => normalized_ty, @@ -422,14 +423,14 @@ impl<'db> InferenceTable<'db> { /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { - let goal = Goal { param_env: self.trait_env.env, predicate }; + let goal = Goal { param_env: self.param_env, predicate }; let canonicalized = self.canonicalize(goal); next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = Goal { param_env: self.trait_env.env, predicate }; + let goal = Goal { param_env: self.param_env, predicate }; self.register_obligation_in_env(goal) } @@ -486,7 +487,7 @@ impl<'db> InferenceTable<'db> { self.register_predicate(Obligation::new( self.interner(), cause, - self.trait_env.env, + self.param_env, ClauseKind::WellFormed(term), )); } diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index 5e742bba3e..075a7066db 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -7,14 +7,12 @@ use rustc_type_ir::{ TypeSuperVisitable, TypeVisitable, TypeVisitor, inherent::{AdtDef, IntoKind}, }; -use triomphe::Arc; use crate::{ - TraitEnvironment, consteval::try_const_usize, db::HirDatabase, next_solver::{ - DbInterner, EarlyBinder, GenericArgs, Ty, TyKind, + DbInterner, EarlyBinder, GenericArgs, ParamEnv, Ty, TyKind, infer::{InferCtxt, traits::ObligationCause}, obligation_ctxt::ObligationCtxt, }, @@ -26,7 +24,7 @@ pub(crate) fn is_ty_uninhabited_from<'db>( infcx: &InferCtxt<'db>, ty: Ty<'db>, target_mod: ModuleId, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, ) -> bool { let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env); @@ -41,7 +39,7 @@ pub(crate) fn is_enum_variant_uninhabited_from<'db>( variant: EnumVariantId, subst: GenericArgs<'db>, target_mod: ModuleId, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, ) -> bool { let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); @@ -56,7 +54,7 @@ struct UninhabitedFrom<'a, 'db> { // guard for preventing stack overflow in non trivial non terminating types max_depth: usize, infcx: &'a InferCtxt<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, } const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(()); @@ -78,7 +76,7 @@ impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> { if matches!(ty.kind(), TyKind::Alias(..)) { let mut ocx = ObligationCtxt::new(self.infcx); - match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env.env, ty) { + match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env, ty) { Ok(it) => ty = it, Err(_) => return CONTINUE_OPAQUELY_INHABITED, } @@ -101,11 +99,7 @@ impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> { } impl<'a, 'db> UninhabitedFrom<'a, 'db> { - fn new( - infcx: &'a InferCtxt<'db>, - target_mod: ModuleId, - env: Arc<TraitEnvironment<'db>>, - ) -> Self { + fn new(infcx: &'a InferCtxt<'db>, target_mod: ModuleId, env: ParamEnv<'db>) -> Self { Self { target_mod, recursive_ty: FxHashSet::default(), max_depth: 500, infcx, env } } diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 97660a67ef..4b20d6eb32 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -21,11 +21,11 @@ use rustc_type_ir::{ use triomphe::Arc; use crate::{ - InferenceResult, TraitEnvironment, + InferenceResult, ParamEnvAndCrate, consteval::try_const_usize, db::HirDatabase, next_solver::{ - DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, + DbInterner, GenericArgs, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, }, }; @@ -131,7 +131,7 @@ fn layout_of_simd_ty<'db>( id: StructId, repr_packed: bool, args: &GenericArgs<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, dl: &TargetDataLayout, ) -> Result<Arc<Layout>, LayoutError> { // Supported SIMD vectors are homogeneous ADTs with exactly one array field: @@ -159,7 +159,7 @@ fn layout_of_simd_ty<'db>( pub fn layout_of_ty_query<'db>( db: &'db dyn HirDatabase, ty: Ty<'db>, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError> { let krate = trait_env.krate; let interner = DbInterner::new_with(db, krate); @@ -170,7 +170,7 @@ pub fn layout_of_ty_query<'db>( let cx = LayoutCx::new(dl); let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); - let ty = infer_ctxt.at(&cause, ParamEnv::empty()).deeply_normalize(ty).unwrap_or(ty); + let ty = infer_ctxt.at(&cause, trait_env.param_env).deeply_normalize(ty).unwrap_or(ty); let result = match ty.kind() { TyKind::Adt(def, args) => { match def.inner().id { @@ -248,10 +248,8 @@ pub fn layout_of_ty_query<'db>( let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - let fields = tys - .iter() - .map(|k| db.layout_of_ty(k, trait_env.clone())) - .collect::<Result<Vec<_>, _>>()?; + let fields = + tys.iter().map(|k| db.layout_of_ty(k, trait_env)).collect::<Result<Vec<_>, _>>()?; let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); let fields = fields.iter().collect::<IndexVec<_, _>>(); cx.calc.univariant(&fields, &ReprOptions::default(), kind)? @@ -329,7 +327,7 @@ pub fn layout_of_ty_query<'db>( .map(|it| { let ty = it.ty.instantiate(interner, args.split_closure_args_untupled().parent_args); - db.layout_of_ty(ty, trait_env.clone()) + db.layout_of_ty(ty, trait_env) }) .collect::<Result<Vec<_>, _>>()?; let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); @@ -362,7 +360,7 @@ pub fn layout_of_ty_query<'db>( pub(crate) fn layout_of_ty_cycle_result<'db>( _: &dyn HirDatabase, _: Ty<'db>, - _: Arc<TraitEnvironment<'db>>, + _: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError> { Err(LayoutError::RecursiveTypeWithoutIndirection) } diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index ecebf7935d..cf2d0989fd 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -13,7 +13,7 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - TraitEnvironment, + ParamEnvAndCrate, db::HirDatabase, layout::{Layout, LayoutCx, LayoutError, field_ty}, next_solver::GenericArgs, @@ -23,7 +23,7 @@ pub fn layout_of_adt_query<'db>( db: &'db dyn HirDatabase, def: AdtId, args: GenericArgs<'db>, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError> { let krate = trait_env.krate; let Ok(target) = db.target_data_layout(krate) else { @@ -34,7 +34,7 @@ pub fn layout_of_adt_query<'db>( let handle_variant = |def: VariantId, var: &VariantFields| { var.fields() .iter() - .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &args), trait_env.clone())) + .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &args), trait_env)) .collect::<Result<Vec<_>, _>>() }; let (variants, repr, is_special_no_niche) = match def { @@ -99,7 +99,7 @@ pub(crate) fn layout_of_adt_cycle_result<'db>( _: &'db dyn HirDatabase, _def: AdtId, _args: GenericArgs<'db>, - _trait_env: Arc<TraitEnvironment<'db>>, + _trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<Layout>, LayoutError> { Err(LayoutError::RecursiveTypeWithoutIndirection) } diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 878813a696..be6a76478a 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -1,6 +1,6 @@ use base_db::target::TargetData; use either::Either; -use hir_def::db::DefDatabase; +use hir_def::{HasModule, db::DefDatabase}; use project_model::{Sysroot, toolchain_info::QueryConfig}; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::GenericArgs as _; @@ -9,7 +9,7 @@ use test_fixture::WithFixture; use triomphe::Arc; use crate::{ - InferenceResult, + InferenceResult, ParamEnvAndCrate, db::HirDatabase, layout::{Layout, LayoutError}, next_solver::{DbInterner, GenericArgs}, @@ -45,7 +45,7 @@ fn eval_goal( .find_map(|file_id| { let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { @@ -90,13 +90,15 @@ fn eval_goal( ), Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(), }; - db.layout_of_ty( - goal_ty, - db.trait_environment(match adt_or_type_alias_id { - Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), - Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), - }), - ) + let param_env = db.trait_environment(match adt_or_type_alias_id { + Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), + Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), + }); + let krate = match adt_or_type_alias_id { + Either::Left(it) => it.krate(&db), + Either::Right(it) => it.krate(&db), + }; + db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate }) }) } @@ -116,7 +118,7 @@ fn eval_expr( crate::attach_db(&db, || { let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; let function_id = scope .declarations() .find_map(|x| match x { @@ -139,7 +141,9 @@ fn eval_expr( .0; let infer = InferenceResult::for_body(&db, function_id.into()); let goal_ty = infer.type_of_binding[b]; - db.layout_of_ty(goal_ty, db.trait_environment(function_id.into())) + let param_env = db.trait_environment(function_id.into()); + let krate = function_id.krate(&db); + db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate }) }) } diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 6d3adec6a8..5ebe87c5d5 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -2,6 +2,8 @@ //! information and various assists. #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] // FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but // temporarily switched to crates.io versions due to hardships that working on them from rustc @@ -67,7 +69,6 @@ use rustc_type_ir::{ }; use syntax::ast::{ConstArg, make}; use traits::FnTrait; -use triomphe::Arc; use crate::{ db::HirDatabase, @@ -94,7 +95,7 @@ pub use lower::{ }; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; -pub use traits::{TraitEnvironment, check_orphan_rules}; +pub use traits::{ParamEnvAndCrate, check_orphan_rules}; pub use utils::{ TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call, target_feature_is_safe_in_target, @@ -474,10 +475,10 @@ where /// To be used from `hir` only. pub fn callable_sig_from_fn_trait<'db>( self_ty: Ty<'db>, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, db: &'db dyn HirDatabase, ) -> Option<(FnTrait, PolyFnSig<'db>)> { - let mut table = InferenceTable::new(db, trait_env.clone(), None); + let mut table = InferenceTable::new(db, trait_env.param_env, trait_env.krate, None); let lang_items = table.interner().lang_items(); let fn_once_trait = FnTrait::FnOnce.get_id(lang_items)?; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index cfd2a06b2a..dd34bbe2fd 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -53,7 +53,7 @@ use tracing::debug; use triomphe::{Arc, ThinArc}; use crate::{ - FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, consteval::intern_const_ref, db::{HirDatabase, InternedOpaqueTyId}, generics::{Generics, generics, trait_self_param_idx}, @@ -1743,10 +1743,9 @@ impl<'db> GenericPredicates<'db> { pub(crate) fn trait_environment_for_body_query( db: &dyn HirDatabase, def: DefWithBodyId, -) -> Arc<TraitEnvironment<'_>> { +) -> ParamEnv<'_> { let Some(def) = def.as_generic_def_id(db) else { - let krate = def.module(db).krate(); - return TraitEnvironment::empty(krate); + return ParamEnv::empty(); }; db.trait_environment(def) } @@ -1754,24 +1753,15 @@ pub(crate) fn trait_environment_for_body_query( pub(crate) fn trait_environment_query<'db>( db: &'db dyn HirDatabase, def: GenericDefId, -) -> Arc<TraitEnvironment<'db>> { +) -> ParamEnv<'db> { let module = def.module(db); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); let predicates = GenericPredicates::query_all(db, def); - let traits_in_scope = predicates - .iter_identity_copied() - .filter_map(|pred| match pred.kind().skip_binder() { - ClauseKind::Trait(tr) => Some((tr.self_ty(), tr.def_id().0)), - _ => None, - }) - .collect(); let clauses = rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied()); let clauses = Clauses::new_from_iter(interner, clauses); - let env = ParamEnv { clauses }; // FIXME: We should normalize projections here, like rustc does. - - TraitEnvironment::new(module.krate(), module.containing_block(), traits_in_scope, env) + ParamEnv { clauses } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -2289,7 +2279,7 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>( name: &Name, ) -> Option<(TraitRef<'db>, TypeAliasId)> { let module = trait_ref.def_id.0.module(db); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { let trait_id = t.as_ref().skip_binder().def_id.0; let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 9a6adedb99..868ae00329 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -32,13 +32,13 @@ use stdx::impl_from; use triomphe::Arc; use crate::{ - TraitEnvironment, all_super_traits, + all_super_traits, db::HirDatabase, infer::{InferenceContext, unify::InferenceTable}, lower::GenericPredicates, next_solver::{ - Binder, ClauseKind, DbInterner, FnSig, GenericArgs, PredicateKind, SimplifiedType, - SolverDefId, TraitRef, Ty, TyKind, TypingMode, + Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind, + SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode, infer::{ BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk, select::ImplSource, @@ -47,6 +47,7 @@ use crate::{ obligation_ctxt::ObligationCtxt, util::clauses_as_obligations, }, + traits::ParamEnvAndCrate, }; pub use self::probe::{ @@ -75,7 +76,7 @@ impl MethodResolutionUnstableFeatures { pub struct MethodResolutionContext<'a, 'db> { pub infcx: &'a InferCtxt<'db>, pub resolver: &'a Resolver<'db>, - pub env: &'a TraitEnvironment<'db>, + pub param_env: ParamEnv<'db>, pub traits_in_scope: &'a FxHashSet<TraitId>, pub edition: Edition, pub unstable_features: &'a MethodResolutionUnstableFeatures, @@ -194,7 +195,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let ctx = MethodResolutionContext { infcx: &self.table.infer_ctxt, resolver: &self.resolver, - env: &self.table.trait_env, + param_env: self.table.param_env, traits_in_scope, edition: self.edition, unstable_features: &self.unstable_features, @@ -264,7 +265,7 @@ impl<'db> InferenceTable<'db> { let obligation = Obligation::new( self.interner(), cause, - self.trait_env.env, + self.param_env, TraitRef::new_from_args(self.interner(), trait_def_id.into(), args), ); @@ -322,7 +323,7 @@ impl<'db> InferenceTable<'db> { let bounds = clauses_as_obligations( bounds.iter_instantiated_copied(interner, args.as_slice()), ObligationCause::new(), - self.trait_env.env, + self.param_env, ); obligations.extend(bounds); @@ -336,7 +337,7 @@ impl<'db> InferenceTable<'db> { obligations.push(Obligation::new( interner, obligation.cause.clone(), - self.trait_env.env, + self.param_env, Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(ty.into()))), )); } @@ -350,7 +351,7 @@ impl<'db> InferenceTable<'db> { pub fn lookup_impl_const<'db>( infcx: &InferCtxt<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, const_id: ConstId, subs: GenericArgs<'db>, ) -> (ConstId, GenericArgs<'db>) { @@ -380,7 +381,7 @@ pub fn lookup_impl_const<'db>( /// call the method using the vtable. pub fn is_dyn_method<'db>( interner: DbInterner<'db>, - _env: Arc<TraitEnvironment<'db>>, + _env: ParamEnv<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, ) -> Option<usize> { @@ -415,7 +416,7 @@ pub fn is_dyn_method<'db>( /// Returns `func` if it's not a method defined in a trait or the lookup failed. pub(crate) fn lookup_impl_method_query<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, ) -> (FunctionId, GenericArgs<'db>) { @@ -433,11 +434,15 @@ pub(crate) fn lookup_impl_method_query<'db>( ); let name = &db.function_signature(func).name; - let Some((impl_fn, impl_subst)) = - lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env, name).and_then(|assoc| { - if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None } - }) - else { + let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref( + &infcx, + trait_ref, + env.param_env, + name, + ) + .and_then(|assoc| { + if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None } + }) else { return (func, fn_subst); }; @@ -453,10 +458,10 @@ pub(crate) fn lookup_impl_method_query<'db>( fn lookup_impl_assoc_item_for_trait_ref<'db>( infcx: &InferCtxt<'db>, trait_ref: TraitRef<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, name: &Name, ) -> Option<(AssocItemId, GenericArgs<'db>)> { - let (impl_id, impl_subst) = find_matching_impl(infcx, &env, trait_ref)?; + let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?; let item = impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it { AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)), @@ -468,13 +473,12 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>( pub(crate) fn find_matching_impl<'db>( infcx: &InferCtxt<'db>, - env: &TraitEnvironment<'db>, + env: ParamEnv<'db>, trait_ref: TraitRef<'db>, ) -> Option<(ImplId, GenericArgs<'db>)> { - let trait_ref = - infcx.at(&ObligationCause::dummy(), env.env).deeply_normalize(trait_ref).ok()?; + let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?; - let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env.env, trait_ref); + let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref); let selection = infcx.select(&obligation).ok()??; @@ -629,7 +633,7 @@ impl InherentImpls { block: Option<BlockId>, for_each: &mut dyn FnMut(&InherentImpls), ) { - let blocks = std::iter::successors(block, |block| block.loc(db).module.containing_block()); + let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); for_each(Self::for_crate(db, krate)); } @@ -794,7 +798,7 @@ impl TraitImpls { block: Option<BlockId>, for_each: &mut dyn FnMut(&TraitImpls), ) { - let blocks = std::iter::successors(block, |block| block.loc(db).module.containing_block()); + let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each); } @@ -816,7 +820,7 @@ impl TraitImpls { // This breaks when they are equal (both will stop immediately), therefore we handle this case // specifically. let blocks_iter = |block: Option<BlockId>| { - std::iter::successors(block, |block| block.loc(db).module.containing_block()) + std::iter::successors(block, |block| block.loc(db).module.block(db)) }; let for_each_block = |current_block: Option<BlockId>, other_block: Option<BlockId>| { blocks_iter(current_block) diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs index 570dd63a50..6d6515a457 100644 --- a/crates/hir-ty/src/method_resolution/confirm.rs +++ b/crates/hir-ty/src/method_resolution/confirm.rs @@ -507,7 +507,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { GenericPredicates::query_all(self.db(), def_id.into()) .iter_instantiated_copied(self.interner(), all_args), ObligationCause::new(), - self.ctx.table.trait_env.env, + self.ctx.table.param_env, ); let sig = diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs index adc144ce11..6af47ab68b 100644 --- a/crates/hir-ty/src/method_resolution/probe.rs +++ b/crates/hir-ty/src/method_resolution/probe.rs @@ -334,7 +334,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { .infcx .instantiate_query_response_and_region_obligations( &ObligationCause::new(), - self.env.env, + self.param_env, &orig_values, ty, ) @@ -394,7 +394,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { // converted to, in order to find out which of those methods might actually // be callable. let mut autoderef_via_deref = - Autoderef::new(infcx, self.env, self_ty).include_raw_pointers(); + Autoderef::new(infcx, self.param_env, self_ty).include_raw_pointers(); let mut reached_raw_pointer = false; let arbitrary_self_types_enabled = self.unstable_features.arbitrary_self_types @@ -403,7 +403,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { let reachable_via_deref = autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false)); - let mut autoderef_via_receiver = Autoderef::new(infcx, self.env, self_ty) + let mut autoderef_via_receiver = Autoderef::new(infcx, self.param_env, self_ty) .include_raw_pointers() .use_receiver_trait(); let steps = autoderef_via_receiver @@ -835,7 +835,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { #[inline] fn param_env(&self) -> ParamEnv<'db> { - self.ctx.env.env + self.ctx.param_env } /// When we're looking up a method by path (UFCS), we relate the receiver @@ -980,8 +980,8 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { }; InherentImpls::for_each_crate_and_block( self.db(), - module.krate(), - module.containing_block(), + module.krate(self.db()), + module.block(self.db()), &mut |impls| { for &impl_def_id in impls.for_self_ty(self_ty) { self.assemble_inherent_impl_probe(impl_def_id, receiver_steps); diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index f47e3b7a30..836c20a433 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -157,6 +157,7 @@ impl<'db, V: PartialEq> ProjectionElem<'db, V> { pub fn projected_ty( &self, infcx: &InferCtxt<'db>, + env: ParamEnv<'db>, mut base: Ty<'db>, closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>, krate: Crate, @@ -173,8 +174,6 @@ impl<'db, V: PartialEq> ProjectionElem<'db, V> { if matches!(base.kind(), TyKind::Alias(..)) { let mut ocx = ObligationCtxt::new(infcx); - // FIXME: we should get this from caller - let env = ParamEnv::empty(); match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) { Ok(it) => base = it, Err(_) => return Ty::new_error(interner, ErrorGuaranteed), @@ -977,15 +976,13 @@ pub enum Rvalue<'db> { UnaryOp(UnOp, Operand<'db>), /// Computes the discriminant of the place, returning it as an integer of type - /// [`discriminant_ty`]. Returns zero for types without discriminant. + /// `discriminant_ty`. Returns zero for types without discriminant. /// /// The validity requirements for the underlying value are undecided for this rvalue, see /// [#91095]. Note too that the value of the discriminant is not the same thing as the - /// variant index; use [`discriminant_for_variant`] to convert. + /// variant index; use `discriminant_for_variant` to convert. /// - /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty /// [#91095]: https://github.com/rust-lang/rust/issues/91095 - /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant Discriminant(Place<'db>), /// Creates an aggregate value, like a tuple or struct. diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index 2d2fc03dcc..b39c9bc065 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -12,12 +12,12 @@ use stdx::never; use triomphe::Arc; use crate::{ - InferenceResult, TraitEnvironment, + InferenceResult, db::{HirDatabase, InternedClosure, InternedClosureId}, display::DisplayTarget, mir::OperandKind, next_solver::{ - DbInterner, GenericArgs, Ty, TypingMode, + DbInterner, GenericArgs, ParamEnv, Ty, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, }; @@ -97,7 +97,7 @@ pub fn borrowck_query<'db>( ) -> Result<Arc<[BorrowckResult<'db>]>, MirLowerError<'db>> { let _p = tracing::info_span!("borrowck_query").entered(); let module = def.module(db); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); let env = db.trait_environment_for_body(def); let mut res = vec![]; // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`. @@ -106,9 +106,9 @@ pub fn borrowck_query<'db>( // FIXME(next-solver): Opaques. let infcx = interner.infer_ctxt().build(typing_mode); res.push(BorrowckResult { - mutability_of_locals: mutability_of_locals(&infcx, &body), - moved_out_of_ref: moved_out_of_ref(&infcx, &env, &body), - partially_moved: partially_moved(&infcx, &env, &body), + mutability_of_locals: mutability_of_locals(&infcx, env, &body), + moved_out_of_ref: moved_out_of_ref(&infcx, env, &body), + partially_moved: partially_moved(&infcx, env, &body), borrow_regions: borrow_regions(db, &body), mir_body: body, }); @@ -131,7 +131,7 @@ fn make_fetch_closure_field<'db>( fn moved_out_of_ref<'db>( infcx: &InferCtxt<'db>, - env: &TraitEnvironment<'db>, + env: ParamEnv<'db>, body: &MirBody<'db>, ) -> Vec<MovedOutOfRef<'db>> { let db = infcx.interner.db; @@ -146,13 +146,14 @@ fn moved_out_of_ref<'db>( } ty = proj.projected_ty( infcx, + env, ty, make_fetch_closure_field(db), - body.owner.module(db).krate(), + body.owner.module(db).krate(db), ); } if is_dereference_of_ref - && !infcx.type_is_copy_modulo_regions(env.env, ty) + && !infcx.type_is_copy_modulo_regions(env, ty) && !ty.references_non_lt_error() { result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty }); @@ -231,7 +232,7 @@ fn moved_out_of_ref<'db>( fn partially_moved<'db>( infcx: &InferCtxt<'db>, - env: &TraitEnvironment<'db>, + env: ParamEnv<'db>, body: &MirBody<'db>, ) -> Vec<PartiallyMoved<'db>> { let db = infcx.interner.db; @@ -242,12 +243,13 @@ fn partially_moved<'db>( for proj in p.projection.lookup(&body.projection_store) { ty = proj.projected_ty( infcx, + env, ty, make_fetch_closure_field(db), - body.owner.module(db).krate(), + body.owner.module(db).krate(db), ); } - if !infcx.type_is_copy_modulo_regions(env.env, ty) && !ty.references_non_lt_error() { + if !infcx.type_is_copy_modulo_regions(env, ty) && !ty.references_non_lt_error() { result.push(PartiallyMoved { span, ty, local: p.local }); } } @@ -374,6 +376,7 @@ enum ProjectionCase { fn place_case<'db>( infcx: &InferCtxt<'db>, + env: ParamEnv<'db>, body: &MirBody<'db>, lvalue: &Place<'db>, ) -> ProjectionCase { @@ -395,9 +398,10 @@ fn place_case<'db>( } ty = proj.projected_ty( infcx, + env, ty, make_fetch_closure_field(db), - body.owner.module(db).krate(), + body.owner.module(db).krate(db), ); } if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct } @@ -535,6 +539,7 @@ fn record_usage_for_operand<'db>( fn mutability_of_locals<'db>( infcx: &InferCtxt<'db>, + env: ParamEnv<'db>, body: &MirBody<'db>, ) -> ArenaMap<LocalId<'db>, MutabilityReason> { let db = infcx.interner.db; @@ -547,7 +552,7 @@ fn mutability_of_locals<'db>( for statement in &block.statements { match &statement.kind { StatementKind::Assign(place, value) => { - match place_case(infcx, body, place) { + match place_case(infcx, env, body, place) { ProjectionCase::Direct => { if ever_init_map.get(place.local).copied().unwrap_or_default() { push_mut_span(place.local, statement.span, &mut result); @@ -596,7 +601,7 @@ fn mutability_of_locals<'db>( }, p, ) = value - && place_case(infcx, body, p) != ProjectionCase::Indirect + && place_case(infcx, env, body, p) != ProjectionCase::Indirect { push_mut_span(p.local, statement.span, &mut result); } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 3418689027..3b4913cae3 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -34,7 +34,7 @@ use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{ - CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, TraitEnvironment, + CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval::{self, ConstEvalError, try_const_usize}, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, @@ -165,7 +165,7 @@ enum MirOrDynIndex<'db> { pub struct Evaluator<'db> { db: &'db dyn HirDatabase, - trait_env: Arc<TraitEnvironment<'db>>, + param_env: ParamEnvAndCrate<'db>, target_data_layout: Arc<TargetDataLayout>, stack: Vec<u8>, heap: Vec<u8>, @@ -594,7 +594,7 @@ pub fn interpret_mir<'db>( // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, - trait_env: Option<Arc<TraitEnvironment<'db>>>, + trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<'db, (Result<'db, Const<'db>>, MirOutput)> { let ty = body.locals[return_slot()].ty; let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?; @@ -632,10 +632,10 @@ impl<'db> Evaluator<'db> { db: &'db dyn HirDatabase, owner: DefWithBodyId, assert_placeholder_ty_is_unused: bool, - trait_env: Option<Arc<TraitEnvironment<'db>>>, + trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<'db, Evaluator<'db>> { let module = owner.module(db); - let crate_id = module.krate(); + let crate_id = module.krate(db); let target_data_layout = match db.target_data_layout(crate_id) { Ok(target_data_layout) => target_data_layout, Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)), @@ -654,7 +654,10 @@ impl<'db> Evaluator<'db> { static_locations: Default::default(), db, random_state: oorandom::Rand64::new(0), - trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)), + param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate { + param_env: db.trait_environment_for_body(owner), + krate: crate_id, + }), crate_id, stdout: vec![], stderr: vec![], @@ -719,6 +722,7 @@ impl<'db> Evaluator<'db> { let (ty, proj) = pair; let r = proj.projected_ty( &self.infcx, + self.param_env.param_env, ty, |c, subst, f| { let InternedClosure(def, _) = self.db.lookup_intern_closure(c); @@ -864,7 +868,7 @@ impl<'db> Evaluator<'db> { } let r = self .db - .layout_of_ty(ty, self.trait_env.clone()) + .layout_of_ty(ty, self.param_env) .map_err(|e| MirEvalError::LayoutError(e, ty))?; self.layout_cache.borrow_mut().insert(ty, r.clone()); Ok(r) @@ -1927,18 +1931,17 @@ impl<'db> Evaluator<'db> { let mut id = const_id.0; let mut subst = subst; if let hir_def::GeneralConstId::ConstId(c) = id { - let (c, s) = lookup_impl_const(&self.infcx, self.trait_env.clone(), c, subst); + let (c, s) = lookup_impl_const(&self.infcx, self.param_env.param_env, c, subst); id = hir_def::GeneralConstId::ConstId(c); subst = s; } result_owner = match id { - GeneralConstId::ConstId(const_id) => self - .db - .const_eval(const_id, subst, Some(self.trait_env.clone())) - .map_err(|e| { + GeneralConstId::ConstId(const_id) => { + self.db.const_eval(const_id, subst, Some(self.param_env)).map_err(|e| { let name = id.name(self.db); MirEvalError::ConstEvalError(name, Box::new(e)) - })?, + })? + } GeneralConstId::StaticId(static_id) => { self.db.const_eval_static(static_id).map_err(|e| { let name = id.name(self.db); @@ -2331,7 +2334,7 @@ impl<'db> Evaluator<'db> { let ty = ocx .structurally_normalize_ty( &ObligationCause::dummy(), - this.trait_env.env, + this.param_env.param_env, ty, ) .map_err(|_| MirEvalError::NotSupported("couldn't normalize".to_owned()))?; @@ -2510,7 +2513,7 @@ impl<'db> Evaluator<'db> { ) -> Result<'db, Option<StackFrame<'db>>> { let mir_body = self .db - .monomorphized_mir_body_for_closure(closure, generic_args, self.trait_env.clone()) + .monomorphized_mir_body_for_closure(closure, generic_args, self.param_env) .map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?; let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some() { @@ -2606,16 +2609,19 @@ impl<'db> Evaluator<'db> { } let (def, generic_args) = pair; let r = if let Some(self_ty_idx) = - is_dyn_method(self.interner(), self.trait_env.clone(), def, generic_args) + is_dyn_method(self.interner(), self.param_env.param_env, def, generic_args) { MirOrDynIndex::Dyn(self_ty_idx) } else { - let (imp, generic_args) = - self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args); + let (imp, generic_args) = self.db.lookup_impl_method( + ParamEnvAndCrate { param_env: self.param_env.param_env, krate: self.crate_id }, + def, + generic_args, + ); let mir_body = self .db - .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone()) + .monomorphized_mir_body(imp.into(), generic_args, self.param_env) .map_err(|e| { MirEvalError::InFunction( Box::new(MirEvalError::MirLowerError(imp, e)), diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 591c12ec24..42c11113ee 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -840,7 +840,7 @@ impl<'db> Evaluator<'db> { "size_of generic arg is not provided".into(), )); }; - let result = match has_drop_glue(&self.infcx, ty, self.trait_env.clone()) { + let result = match has_drop_glue(&self.infcx, ty, self.param_env.param_env) { DropGlue::HasDropGlue => true, DropGlue::None => false, DropGlue::DependOnParams => { diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index bb2afb2f00..c13b76c125 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -1,4 +1,4 @@ -use hir_def::db::DefDatabase; +use hir_def::{HasModule, db::DefDatabase}; use hir_expand::EditionedFileId; use span::Edition; use syntax::{TextRange, TextSize}; @@ -20,7 +20,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; let func_id = scope .declarations() .find_map(|x| match x { @@ -40,7 +40,10 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), .monomorphized_mir_body( func_id.into(), GenericArgs::new_from_iter(interner, []), - db.trait_environment(func_id.into()), + crate::ParamEnvAndCrate { + param_env: db.trait_environment(func_id.into()), + krate: func_id.krate(db), + }, ) .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; @@ -87,7 +90,7 @@ fn check_pass_and_stdio( line_index(range.end()) ) }; - let krate = db.module_for_file(file_id.file_id(&db)).krate(); + let krate = db.module_for_file(file_id.file_id(&db)).krate(&db); e.pretty_print( &mut err, &db, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 190b2f99cc..5bce4222a4 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -25,7 +25,7 @@ use syntax::TextRange; use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, + Adjust, Adjustment, AutoBorrow, CallableDefId, ParamEnvAndCrate, consteval::ConstEvalError, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{DisplayTarget, HirDisplay, hir_display_with_store}, @@ -42,7 +42,7 @@ use crate::{ TupleFieldId, Ty, UnOp, VariantId, return_slot, }, next_solver::{ - Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst, + Const, DbInterner, ParamConst, ParamEnv, Region, TyKind, TypingMode, UnevaluatedConst, infer::{DbInternerInferExt, InferCtxt}, }, traits::FnTrait, @@ -81,7 +81,7 @@ struct MirLowerCtx<'a, 'db> { infer: &'a InferenceResult<'db>, resolver: Resolver<'db>, drop_scopes: Vec<DropScope<'db>>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, infcx: InferCtxt<'db>, } @@ -302,7 +302,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; let resolver = owner.resolver(db); let env = db.trait_environment_for_body(owner); - let interner = DbInterner::new_with(db, env.krate); + let interner = DbInterner::new_with(db, resolver.krate()); // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -1462,7 +1462,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } fn lower_literal_to_operand(&mut self, ty: Ty<'db>, l: &Literal) -> Result<'db, Operand<'db>> { - let size = || self.db.layout_of_ty(ty, self.env.clone()).map(|it| it.size.bytes_usize()); + let size = || { + self.db + .layout_of_ty(ty, ParamEnvAndCrate { param_env: self.env, krate: self.krate() }) + .map(|it| it.size.bytes_usize()) + }; const USIZE_SIZE: usize = size_of::<usize>(); let bytes: Box<[_]> = match l { hir_def::hir::Literal::String(b) => { @@ -1799,7 +1803,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { &self.infcx, self.infer[expr_id], self.owner.module(self.db), - self.env.clone(), + self.env, ) } @@ -2070,7 +2074,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { span: MirSpan, ) { for &l in scope.locals.iter().rev() { - if !self.infcx.type_is_copy_modulo_regions(self.env.env, self.result.locals[l].ty) { + if !self.infcx.type_is_copy_modulo_regions(self.env, self.result.locals[l].ty) { let prev = std::mem::replace(current, self.new_basic_block()); self.set_terminator( prev, diff --git a/crates/hir-ty/src/mir/lower/tests.rs b/crates/hir-ty/src/mir/lower/tests.rs index 38fc7ad78a..73399dab7f 100644 --- a/crates/hir-ty/src/mir/lower/tests.rs +++ b/crates/hir-ty/src/mir/lower/tests.rs @@ -1,3 +1,4 @@ +use hir_def::DefWithBodyId; use test_fixture::WithFixture; use crate::{db::HirDatabase, setup_tracing, test_db::TestDB}; @@ -9,7 +10,7 @@ fn lower_mir(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let file_id = *file_ids.last().unwrap(); let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; let funcs = scope.declarations().filter_map(|x| match x { hir_def::ModuleDefId::FunctionId(it) => Some(it), _ => None, @@ -49,3 +50,61 @@ fn foo() { "#, ); } + +fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + let _tracing = setup_tracing(); + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + crate::attach_db(&db, || { + let file_id = *file_ids.last().unwrap(); + let module_id = db.module_for_file(file_id.file_id(&db)); + let def_map = module_id.def_map(&db); + let scope = &def_map[module_id].scope; + + let mut bodies: Vec<DefWithBodyId> = Vec::new(); + + for decl in scope.declarations() { + if let hir_def::ModuleDefId::FunctionId(f) = decl { + bodies.push(f.into()); + } + } + + for impl_id in scope.impls() { + let impl_items = impl_id.impl_items(&db); + for (_, item) in impl_items.items.iter() { + if let hir_def::AssocItemId::FunctionId(f) = item { + bodies.push((*f).into()); + } + } + } + + for body in bodies { + let _ = db.borrowck(body); + } + }) +} + +#[test] +fn regression_21173_const_generic_impl_with_assoc_type() { + check_borrowck( + r#" +pub trait Tr { + type Assoc; + fn f(&self, handle: Self::Assoc) -> i32; +} + +pub struct ConstGeneric<const N: usize>; + +impl<const N: usize> Tr for &ConstGeneric<N> { + type Assoc = AssocTy; + + fn f(&self, a: Self::Assoc) -> i32 { + a.x + } +} + +pub struct AssocTy { + x: i32, +} + "#, + ); +} diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs index 1f73d5cd31..b67365c344 100644 --- a/crates/hir-ty/src/mir/monomorphization.rs +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -14,9 +14,11 @@ use rustc_type_ir::{ }; use triomphe::Arc; -use crate::next_solver::{Const, ConstKind, Region, RegionKind}; use crate::{ - TraitEnvironment, + ParamEnvAndCrate, + next_solver::{Const, ConstKind, Region, RegionKind}, +}; +use crate::{ db::{HirDatabase, InternedClosureId}, next_solver::{ DbInterner, GenericArgs, Ty, TyKind, TypingMode, @@ -30,7 +32,7 @@ use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, struct Filler<'db> { infcx: InferCtxt<'db>, - trait_env: Arc<TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>, } @@ -53,7 +55,11 @@ impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> { let mut ocx = ObligationCtxt::new(&self.infcx); let ty = ocx - .structurally_normalize_ty(&ObligationCause::dummy(), self.trait_env.env, ty) + .structurally_normalize_ty( + &ObligationCause::dummy(), + self.trait_env.param_env, + ty, + ) .map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?; ty.try_super_fold_with(self) } @@ -93,11 +99,7 @@ impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> { } impl<'db> Filler<'db> { - fn new( - db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, - subst: GenericArgs<'db>, - ) -> Self { + fn new(db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>) -> Self { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); Self { infcx, trait_env: env, subst } @@ -210,7 +212,7 @@ pub fn monomorphized_mir_body_query<'db>( db: &'db dyn HirDatabase, owner: DefWithBodyId, subst: GenericArgs<'db>, - trait_env: Arc<crate::TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> { let mut filler = Filler::new(db, trait_env, subst); let body = db.mir_body(owner)?; @@ -223,7 +225,7 @@ pub(crate) fn monomorphized_mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _: DefWithBodyId, _: GenericArgs<'db>, - _: Arc<crate::TraitEnvironment<'db>>, + _: ParamEnvAndCrate<'db>, ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> { Err(MirLowerError::Loop) } @@ -232,7 +234,7 @@ pub fn monomorphized_mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId, subst: GenericArgs<'db>, - trait_env: Arc<crate::TraitEnvironment<'db>>, + trait_env: ParamEnvAndCrate<'db>, ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> { let mut filler = Filler::new(db, trait_env, subst); let body = db.mir_body_for_closure(closure)?; diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index 443191423a..14b8a61088 100644 --- a/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/mod.rs @@ -402,7 +402,7 @@ impl<'db> InferCtxt<'db> { self.evaluate_obligation(obligation).may_apply() } - /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank) + /// See the comment on `GeneralAutoderef::overloaded_deref_ty` /// for more details. pub fn predicate_may_hold_opaque_types_jank( &self, @@ -532,7 +532,7 @@ impl<'db> InferCtxt<'db> { }) } - /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank) + /// See the comment on `GeneralAutoderef::overloaded_deref_ty` /// for more details. pub fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'db, Predicate<'db>>) -> bool { <&SolverContext<'db>>::from(self).root_goal_may_hold_opaque_types_jank(goal) diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs index 4f000c24cc..3409de17a1 100644 --- a/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/crates/hir-ty/src/next_solver/infer/traits.rs @@ -36,10 +36,6 @@ pub struct ObligationCause { } impl ObligationCause { - #[expect( - clippy::new_without_default, - reason = "`new` is temporary, eventually we will provide span etc. here" - )] #[inline] pub fn new() -> ObligationCause { ObligationCause { _private: () } diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 2e52dcea6c..8b24a20a5b 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -690,15 +690,10 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef { interner: DbInterner<'db>, sizedness: SizedTraitKind, ) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> { - if self.is_struct() { - let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; - - let constraint_ty = sizedness_constraint_for_ty(interner, sizedness, tail_ty)?; - - Some(EarlyBinder::bind(constraint_ty)) - } else { - None - } + let tail_ty = self.struct_tail_ty(interner)?; + tail_ty + .map_bound(|tail_ty| sizedness_constraint_for_ty(interner, sizedness, tail_ty)) + .transpose() } fn destructor( @@ -1109,14 +1104,7 @@ impl<'db> Interner for DbInterner<'db> { fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> { match def_id { - SolverDefId::TypeAliasId(id) => { - use hir_def::Lookup; - match id.lookup(self.db()).container { - ItemContainerId::ImplId(it) => it, - _ => panic!("assoc ty value should be in impl"), - }; - self.db().ty(id.into()) - } + SolverDefId::TypeAliasId(id) => self.db().ty(id.into()), SolverDefId::AdtId(id) => self.db().ty(id.into()), // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. // @@ -1694,7 +1682,7 @@ impl<'db> Interner for DbInterner<'db> { mut f: impl FnMut(Self::ImplId), ) { let krate = self.krate.expect("trait solving requires setting `DbInterner::krate`"); - let trait_block = trait_def_id.0.loc(self.db).container.containing_block(); + let trait_block = trait_def_id.0.loc(self.db).container.block(self.db); let mut consider_impls_for_simplified_type = |simp: SimplifiedType| { let type_block = simp.def().and_then(|def_id| { let module = match def_id { @@ -1713,7 +1701,7 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::EnumVariantId(_) | SolverDefId::Ctor(_) => return None, }; - module.containing_block() + module.block(self.db) }); TraitImpls::for_each_crate_and_block_trait_and_type( self.db, @@ -1828,7 +1816,7 @@ impl<'db> Interner for DbInterner<'db> { fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, mut f: impl FnMut(Self::ImplId)) { let Some(krate) = self.krate else { return }; - let block = trait_def_id.0.loc(self.db).container.containing_block(); + let block = trait_def_id.0.loc(self.db).container.block(self.db); TraitImpls::for_each_crate_and_block(self.db, krate, block, &mut |impls| { for &impl_ in impls.blanket_impls(trait_def_id.0) { diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs index 7cc3af748a..783966ee1e 100644 --- a/crates/hir-ty/src/next_solver/predicate.rs +++ b/crates/hir-ty/src/next_solver/predicate.rs @@ -427,6 +427,10 @@ impl<'db> ParamEnv<'db> { pub fn empty() -> Self { ParamEnv { clauses: Clauses::new_from_iter(DbInterner::conjure(), []) } } + + pub fn clauses(self) -> Clauses<'db> { + self.clauses + } } impl<'db> rustc_type_ir::inherent::ParamEnv<DbInterner<'db>> for ParamEnv<'db> { diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs index b5ed770e16..40a3f17cf1 100644 --- a/crates/hir-ty/src/next_solver/solver.rs +++ b/crates/hir-ty/src/next_solver/solver.rs @@ -177,45 +177,52 @@ impl<'db> SolverDelegate for SolverContext<'db> { impl_id: ImplIdWrapper, ) -> Result<Option<SolverDefId>, ErrorGuaranteed> { let impl_items = impl_id.0.impl_items(self.0.interner.db()); - let id = match trait_assoc_def_id { - SolverDefId::TypeAliasId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id - && *impl_assoc_name == trait_assoc_data.name - { - Some(impl_assoc_id) - } else { - None - } - }) - .map(SolverDefId::TypeAliasId) - } - SolverDefId::ConstId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id); - let trait_assoc_name = trait_assoc_data - .name - .as_ref() - .expect("unnamed consts should not get passed to the solver"); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id - && impl_assoc_name == trait_assoc_name - { - Some(impl_assoc_id) - } else { - None - } - }) - .map(SolverDefId::ConstId) - } - _ => panic!("Unexpected SolverDefId"), - }; + let id = + match trait_assoc_def_id { + SolverDefId::TypeAliasId(trait_assoc_id) => { + let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id + && *impl_assoc_name == trait_assoc_data.name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else(|| { + if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None } + }) + .map(SolverDefId::TypeAliasId) + } + SolverDefId::ConstId(trait_assoc_id) => { + let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id); + let trait_assoc_name = trait_assoc_data + .name + .as_ref() + .expect("unnamed consts should not get passed to the solver"); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id + && impl_assoc_name == trait_assoc_name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else(|| { + if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None } + }) + .map(SolverDefId::ConstId) + } + _ => panic!("Unexpected SolverDefId"), + }; Ok(id) } @@ -225,7 +232,9 @@ impl<'db> SolverDelegate for SolverContext<'db> { _src: Ty<'db>, _assume: <Self::Interner as rustc_type_ir::Interner>::Const, ) -> Result<Certainty, NoSolution> { - unimplemented!() + // It's better to return some value while not fully implement + // then panic in the mean time + Ok(Certainty::Yes) } fn evaluate_const( diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs index c0a7c9adc4..ff89f8e059 100644 --- a/crates/hir-ty/src/next_solver/ty.rs +++ b/crates/hir-ty/src/next_solver/ty.rs @@ -656,7 +656,7 @@ impl<'db> Ty<'db> { } TyKind::Coroutine(coroutine_id, _args) => { let InternedCoroutine(owner, _) = coroutine_id.0.loc(db); - let krate = owner.module(db).krate(); + let krate = owner.module(db).krate(db); if let Some(future_trait) = hir_def::lang_item::lang_items(db, krate).Future { // This is only used by type walking. // Parameters will be walked outside, and projection predicate is not used. diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs index 972c8e2da7..bc4b5fdbfc 100644 --- a/crates/hir-ty/src/next_solver/util.rs +++ b/crates/hir-ty/src/next_solver/util.rs @@ -422,12 +422,10 @@ pub fn sizedness_constraint_for_ty<'db>( .next_back() .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)), - Adt(adt, args) => { - let tail_ty = - EarlyBinder::bind(adt.all_field_tys(interner).skip_binder().into_iter().last()?) - .instantiate(interner, args); + Adt(adt, args) => adt.struct_tail_ty(interner).and_then(|tail_ty| { + let tail_ty = tail_ty.instantiate(interner, args); sizedness_constraint_for_ty(interner, sizedness, tail_ty) - } + }), Placeholder(..) | Bound(..) | Infer(..) => { panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty") diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index 0b84ce13a3..4c6b585016 100644 --- a/crates/hir-ty/src/opaques.rs +++ b/crates/hir-ty/src/opaques.rs @@ -118,11 +118,11 @@ pub(crate) fn tait_hidden_types<'db>( let loc = type_alias.loc(db); let module = loc.module(db); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); - let param_env = db.trait_environment(type_alias.into()).env; + let param_env = db.trait_environment(type_alias.into()); let defining_bodies = tait_defining_bodies(db, &loc); diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs index 0241751e82..9ae9a8e2a9 100644 --- a/crates/hir-ty/src/specialization.rs +++ b/crates/hir-ty/src/specialization.rs @@ -1,6 +1,6 @@ //! Impl specialization related things -use hir_def::{ImplId, nameres::crate_def_map}; +use hir_def::{HasModule, ImplId, nameres::crate_def_map}; use intern::sym; use rustc_type_ir::inherent::SliceLike; use tracing::debug; @@ -46,7 +46,7 @@ fn specializes_query( parent_impl_def_id: ImplId, ) -> bool { let trait_env = db.trait_environment(specializing_impl_def_id.into()); - let interner = DbInterner::new_with(db, trait_env.krate); + let interner = DbInterner::new_with(db, specializing_impl_def_id.krate(db)); let specializing_impl_signature = db.impl_signature(specializing_impl_def_id); let parent_impl_signature = db.impl_signature(parent_impl_def_id); @@ -70,7 +70,7 @@ fn specializes_query( // create a parameter environment corresponding to an identity instantiation of the specializing impl, // i.e. the most generic instantiation of the specializing impl. - let param_env = trait_env.env; + let param_env = trait_env; // Create an infcx, taking the predicates of the specializing impl as assumptions: let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -148,7 +148,7 @@ pub(crate) fn specializes( // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]` // is an internal feature, std is not using it for specialization nor is likely to // ever use it, and we don't have the span information necessary to replicate that. - let def_map = crate_def_map(db, module.krate()); + let def_map = crate_def_map(db, module.krate(db)); if !def_map.is_unstable_feature_enabled(&sym::specialization) && !def_map.is_unstable_feature_enabled(&sym::min_specialization) { diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs index 7044ca5d23..7bd314cb8e 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ty/src/test_db.rs @@ -138,9 +138,9 @@ impl TestDB { let file_id = file_id.into(); for &krate in self.relevant_crates(file_id).iter() { let crate_def_map = crate_def_map(self, krate); - for (local_id, data) in crate_def_map.modules() { + for (module_id, data) in crate_def_map.modules() { if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) { - return Some(crate_def_map.module_id(local_id)); + return Some(module_id); } } } diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 1acb0b82b1..a31353f1e3 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -16,7 +16,7 @@ mod traits; use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ - AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax, + AssocItemId, DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, SyntheticSyntax, db::DefDatabase, expr_store::{Body, BodySourceMap}, hir::{ExprId, Pat, PatId}, @@ -114,7 +114,7 @@ fn check_impl( None => continue, }; let def_map = module.def_map(&db); - visit_module(&db, def_map, module.local_id, &mut |it| { + visit_module(&db, def_map, module, &mut |it| { let def = match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::EnumVariantId(it) => it.into(), @@ -122,7 +122,7 @@ fn check_impl( ModuleDefId::StaticId(it) => it.into(), _ => return, }; - defs.push((def, module.krate())) + defs.push((def, module.krate(&db))) }); } defs.sort_by_key(|(def, _)| match def { @@ -412,7 +412,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let def_map = module.def_map(&db); let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); - visit_module(&db, def_map, module.local_id, &mut |it| { + visit_module(&db, def_map, module, &mut |it| { let def = match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::EnumVariantId(it) => it.into(), @@ -420,7 +420,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { ModuleDefId::StaticId(it) => it.into(), _ => return, }; - defs.push((def, module.krate())) + defs.push((def, module.krate(&db))) }); defs.sort_by_key(|(def, _)| match def { DefWithBodyId::FunctionId(it) => { @@ -454,7 +454,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { pub(crate) fn visit_module( db: &TestDB, crate_def_map: &DefMap, - module_id: LocalModuleId, + module_id: ModuleId, cb: &mut dyn FnMut(ModuleDefId), ) { visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); @@ -517,7 +517,7 @@ pub(crate) fn visit_module( } } } - ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it.local_id, cb), + ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it, cb), _ => (), } } @@ -593,7 +593,7 @@ fn salsa_bug() { crate::attach_db(&db, || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { InferenceResult::for_body( &db, match def { @@ -637,7 +637,7 @@ fn salsa_bug() { crate::attach_db(&db, || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { InferenceResult::for_body( &db, match def { diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs index ef71681636..ff55ff54ce 100644 --- a/crates/hir-ty/src/tests/closure_captures.rs +++ b/crates/hir-ty/src/tests/closure_captures.rs @@ -24,7 +24,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let def_map = module.def_map(&db); let mut defs = Vec::new(); - visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it)); + visit_module(&db, def_map, module, &mut |it| defs.push(it)); let mut captures_info = Vec::new(); for def in defs { @@ -75,7 +75,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let capture_ty = capture .ty .skip_binder() - .display_test(db, DisplayTarget::from_crate(db, module.krate())) + .display_test(db, DisplayTarget::from_crate(db, module.krate(db))) .to_string(); let spans = capture .spans() diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index fd564a300d..7b0c1d3544 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -22,7 +22,7 @@ fn foo() -> i32 { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { InferenceResult::for_body(&db, it.into()); } @@ -66,7 +66,7 @@ fn foo() -> i32 { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { InferenceResult::for_body(&db, it.into()); } @@ -109,7 +109,7 @@ fn baz() -> i32 { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { InferenceResult::for_body(&db, it.into()); } @@ -178,7 +178,7 @@ fn baz() -> i32 { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { + visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { InferenceResult::for_body(&db, it.into()); } @@ -232,7 +232,7 @@ $0", || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -268,7 +268,7 @@ pub struct NewStruct { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -303,7 +303,7 @@ $0", || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -340,7 +340,7 @@ pub enum SomeEnum { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -375,7 +375,7 @@ $0", || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -409,7 +409,7 @@ fn bar() -> f32 { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -448,7 +448,7 @@ $0", || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -490,7 +490,7 @@ impl SomeStruct { || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); - TraitImpls::for_crate(&db, module.krate()); + TraitImpls::for_crate(&db, module.krate(&db)); }, &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" @@ -546,7 +546,7 @@ fn main() { let module = db.module_for_file(file_id.file_id(&db)); let crate_def_map = module.def_map(&db); let mut defs: Vec<DefWithBodyId> = vec![]; - visit_module(&db, crate_def_map, module.local_id, &mut |it| { + visit_module(&db, crate_def_map, module, &mut |it| { let def = match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::EnumVariantId(it) => it.into(), @@ -643,7 +643,7 @@ fn main() { let crate_def_map = module.def_map(&db); let mut defs: Vec<DefWithBodyId> = vec![]; - visit_module(&db, crate_def_map, module.local_id, &mut |it| { + visit_module(&db, crate_def_map, module, &mut |it| { let def = match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::EnumVariantId(it) => it.into(), diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 274d33a211..c8ed8aa258 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -2229,3 +2229,32 @@ fn test(x: *mut u8) { "#, ); } + +#[test] +fn unsized_struct() { + check_types( + r#" +//- minicore: sized, phantom_data +use core::marker::PhantomData; + +const UI_DEV_CREATE: Ioctl = Ioctl(PhantomData); + +struct Ioctl<T: ?Sized = NoArgs>(PhantomData<T>); + +struct NoArgs([u8]); + +impl<T> Ioctl<T> { + fn ioctl(self) {} +} + +impl Ioctl<NoArgs> { + fn ioctl(self) -> u32 { 0 } +} + +fn main() { + UI_DEV_CREATE.ioctl(); + // ^^^^^^^^^^^^^^^^^^^^^ u32 +} + "#, + ); +} diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs index 5c1f85cb2a..e11cc85e7f 100644 --- a/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/crates/hir-ty/src/tests/regression/new_solver.rs @@ -230,6 +230,62 @@ fn main() { debug(&1); }"#, ); + + // toolchains <= 1.88.0, before sized-hierarchy. + check_no_mismatches( + r#" +#[lang = "sized"] +pub trait Sized {} + +#[lang = "unsize"] +pub trait Unsize<T: ?Sized> {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized<T: ?Sized> {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} + +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} + +#[lang = "dispatch_from_dyn"] +pub trait DispatchFromDyn<T> {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} + +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} + +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {} + +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} + +trait Foo { + fn bar(&self) -> u32 { + 0xCAFE + } +} + +fn debug(_: &dyn Foo) {} + +impl Foo for i32 {} + +fn main() { + debug(&1); +}"#, + ); } #[test] diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 677e35775d..a54c0a799d 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -5079,3 +5079,23 @@ fn foo(base_layer_two: &dyn BaseLayerOne) { "#, ); } + +#[test] +fn default_assoc_types() { + check_types( + r#" +trait Trait<T> { + type Assoc<U> = (T, U); + fn method(self) -> Self::Assoc<i32> { loop {} } +} + +struct Struct<T>(T); +impl<T> Trait<((), T)> for Struct<T> {} + +fn foo(v: Struct<f32>) { + v.method(); + // ^^^^^^^^^^ (((), f32), i32) +} + "#, + ); +} diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 1462f1e317..2f8c31ec60 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -4,7 +4,7 @@ use std::hash::Hash; use base_db::Crate; use hir_def::{ - AdtId, AssocItemId, BlockId, HasModule, ImplId, Lookup, TraitId, + AdtId, AssocItemId, HasModule, ImplId, Lookup, TraitId, lang_item::LangItems, nameres::DefMap, signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags}, @@ -17,7 +17,6 @@ use rustc_type_ir::{ inherent::{AdtDef, BoundExistentialPredicates, IntoKind, Span as _}, solve::Certainty, }; -use triomphe::Arc; use crate::{ db::HirDatabase, @@ -29,60 +28,22 @@ use crate::{ }, }; -/// A set of clauses that we assume to be true. E.g. if we are inside this function: -/// ```rust -/// fn foo<T: Default>(t: T) {} -/// ``` -/// we assume that `T: Default`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TraitEnvironment<'db> { +/// Type for `hir`, because commonly we want both param env and a crate in an exported API. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ParamEnvAndCrate<'db> { + pub param_env: ParamEnv<'db>, pub krate: Crate, - pub block: Option<BlockId>, - // FIXME make this a BTreeMap - traits_from_clauses: Box<[(Ty<'db>, TraitId)]>, - pub env: ParamEnv<'db>, -} - -impl<'db> TraitEnvironment<'db> { - pub fn empty(krate: Crate) -> Arc<Self> { - Arc::new(TraitEnvironment { - krate, - block: None, - traits_from_clauses: Box::default(), - env: ParamEnv::empty(), - }) - } - - pub fn new( - krate: Crate, - block: Option<BlockId>, - traits_from_clauses: Box<[(Ty<'db>, TraitId)]>, - env: ParamEnv<'db>, - ) -> Arc<Self> { - Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) - } - - // pub fn with_block(self: &mut Arc<Self>, block: BlockId) { - pub fn with_block(this: &mut Arc<Self>, block: BlockId) { - Arc::make_mut(this).block = Some(block); - } - - pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator<Item = TraitId> + '_ { - self.traits_from_clauses - .iter() - .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id)) - } } /// This should be used in `hir` only. pub fn structurally_normalize_ty<'db>( infcx: &InferCtxt<'db>, ty: Ty<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnv<'db>, ) -> Ty<'db> { let TyKind::Alias(..) = ty.kind() else { return ty }; let mut ocx = ObligationCtxt::new(infcx); - let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); + let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, ty).unwrap_or(ty); ty.replace_infer_with_error(infcx.interner) } @@ -192,7 +153,7 @@ impl FnTrait { pub fn implements_trait_unique<'db>( ty: Ty<'db>, db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, trait_: TraitId, ) -> bool { implements_trait_unique_impl(db, env, trait_, &mut |infcx| { @@ -203,7 +164,7 @@ pub fn implements_trait_unique<'db>( /// This should not be used in `hir-ty`, only in `hir`. pub fn implements_trait_unique_with_args<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, trait_: TraitId, args: GenericArgs<'db>, ) -> bool { @@ -212,7 +173,7 @@ pub fn implements_trait_unique_with_args<'db>( fn implements_trait_unique_impl<'db>( db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, trait_: TraitId, create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>, ) -> bool { @@ -222,7 +183,7 @@ fn implements_trait_unique_impl<'db>( let args = create_args(&infcx); let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); - let goal = Goal::new(interner, env.env, trait_ref); + let goal = Goal::new(interner, env.param_env, trait_ref); let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal); matches!(result, Ok((_, Certainty::Yes))) @@ -246,10 +207,10 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id | TyKind::Uint(_) | TyKind::Float(_) => def_map.is_rustc_coherence_is_core(), - TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate() == def_map.krate(), + TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate(db) == def_map.krate(), TyKind::Dynamic(it, _) => it .principal_def_id() - .is_some_and(|trait_id| trait_id.0.module(db).krate() == def_map.krate()), + .is_some_and(|trait_id| trait_id.0.module(db).krate(db) == def_map.krate()), _ => true, }; @@ -322,12 +283,12 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool return true; }; - let local_crate = impl_.lookup(db).container.krate(); + let local_crate = impl_.lookup(db).container.krate(db); let is_local = |tgt_crate| tgt_crate == local_crate; let trait_ref = impl_trait.instantiate_identity(); let trait_id = trait_ref.def_id.0; - if is_local(trait_id.module(db).krate()) { + if is_local(trait_id.module(db).krate(db)) { // trait to be implemented is local return true; } @@ -361,10 +322,10 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool // FIXME: param coverage // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) let is_not_orphan = trait_ref.args.types().any(|ty| match unwrap_fundamental(ty).kind() { - TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate()), + TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate(db)), TyKind::Error(_) => true, TyKind::Dynamic(it, _) => { - it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate())) + it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate(db))) } _ => false, }); diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index df9d53f3e5..5c0af6dafb 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -874,7 +874,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V); let mut defs: Vec<GenericDefId> = Vec::new(); let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap(); let def_map = module.def_map(&db); - crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| { + crate::tests::visit_module(&db, def_map, module, &mut |it| { defs.push(match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::AdtId(it) => it.into(), diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 5e716c6df1..d1056f31e1 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -3,8 +3,7 @@ use cfg::CfgExpr; use either::Either; use hir_def::{ - AssocItemId, AttrDefId, FieldId, InternedModuleId, LifetimeParamId, ModuleDefId, - TypeOrConstParamId, + AssocItemId, AttrDefId, FieldId, LifetimeParamId, ModuleDefId, TypeOrConstParamId, attrs::{AttrFlags, Docs, IsInnerDoc}, expr_store::path::Path, item_scope::ItemInNs, @@ -213,8 +212,8 @@ impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; impl HasAttrs for Module { #[inline] - fn attr_id(self, db: &dyn HirDatabase) -> AttrsOwner { - AttrsOwner::AttrDef(AttrDefId::ModuleId(InternedModuleId::new(db, self.id))) + fn attr_id(self, _: &dyn HirDatabase) -> AttrsOwner { + AttrsOwner::AttrDef(AttrDefId::ModuleId(self.id)) } } @@ -243,7 +242,7 @@ impl HasAttrs for AssocItem { impl HasAttrs for crate::Crate { #[inline] fn attr_id(self, db: &dyn HirDatabase) -> AttrsOwner { - self.root_module().attr_id(db) + self.root_module(db).attr_id(db) } } @@ -274,7 +273,6 @@ fn resolve_doc_path_on_( ) -> Option<DocLinkDef> { let resolver = match attr_id { AttrsOwner::AttrDef(AttrDefId::ModuleId(it)) => { - let it = it.loc(db); if is_inner_doc.yes() { it.resolver(db) } else if let Some(parent) = Module::from(it).parent(db) { @@ -412,9 +410,7 @@ fn resolve_impl_trait_item<'db>( ns: Option<Namespace>, ) -> Option<DocLinkDef> { let krate = ty.krate(db); - let environment = resolver - .generic_def() - .map_or_else(|| crate::TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); + let environment = crate::param_env_from_resolver(db, &resolver); let traits_in_scope = resolver.traits_in_scope(db); // `ty.iterate_path_candidates()` require a scope, which is not available when resolving @@ -428,7 +424,7 @@ fn resolve_impl_trait_item<'db>( let ctx = MethodResolutionContext { infcx: &infcx, resolver: &resolver, - env: &environment, + param_env: environment.param_env, traits_in_scope: &traits_in_scope, edition: krate.edition(db), unstable_features: &unstable_features, diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 64d97b3f2a..3021ccf402 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -4,42 +4,5 @@ //! //! But we need this for at least LRU caching at the query level. pub use hir_def::db::DefDatabase; -// AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery, -// BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, -// CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, -// DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, -// ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery, -// FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery, -// FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, -// GenericParamsWithSourceMapQuery, ImplItemsWithDiagnosticsQuery, ImportMapQuery, -// IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, -// InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, -// InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, -// InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, -// InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, -// InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery, -// MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery, -// StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitItemsWithDiagnosticsQuery, -// TypeAliasDataQuery, UnionDataWithDiagnosticsQuery, -// }; pub use hir_expand::db::ExpandDatabase; -// AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage, -// ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery, -// ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery, -// RealSpanMapQuery, pub use hir_ty::db::HirDatabase; -// AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery, -// CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery, -// ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery, -// FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery, -// GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage, -// ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery, -// InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery, -// InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery, -// InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery, -// MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery, -// MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery, -// TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery, -// TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, -// TypeAliasImplTraitsQuery, ValueTyQuery, -// }; diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 10a1fa12e0..d0d8c4877d 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -13,7 +13,7 @@ use hir_ty::{ GenericPredicates, db::HirDatabase, display::{ - HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault, + HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault, hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility, }, next_solver::ClauseKind, @@ -29,7 +29,7 @@ use crate::{ }; impl<'db> HirDisplay<'db> for Function { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let db = f.db; let data = db.function_signature(self.id); let container = self.as_assoc_item(db).map(|it| it.container(db)); @@ -185,19 +185,18 @@ impl<'db> HirDisplay<'db> for Function { } } -fn write_impl_header<'db>( - impl_: &Impl, - f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result { let db = f.db; f.write_str("impl")?; let def_id = GenericDefId::ImplId(impl_.id); write_generic_params(def_id, f)?; - if let Some(trait_) = impl_.trait_(db) { - let trait_data = db.trait_signature(trait_.id); - write!(f, " {} for", trait_data.name.display(db, f.edition()))?; + let impl_data = db.impl_signature(impl_.id); + if let Some(target_trait) = &impl_data.target_trait { + f.write_char(' ')?; + hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?; + f.write_str(" for")?; } f.write_char(' ')?; @@ -207,7 +206,7 @@ fn write_impl_header<'db>( } impl<'db> HirDisplay<'db> for SelfParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let data = f.db.function_signature(self.func); let param = *data.params.first().unwrap(); match &data.store[param] { @@ -233,7 +232,7 @@ impl<'db> HirDisplay<'db> for SelfParam { } impl<'db> HirDisplay<'db> for Adt { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self { Adt::Struct(it) => it.hir_fmt(f), Adt::Union(it) => it.hir_fmt(f), @@ -243,7 +242,7 @@ impl<'db> HirDisplay<'db> for Adt { } impl<'db> HirDisplay<'db> for Struct { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let module_id = self.module(f.db).id; // FIXME: Render repr if its set explicitly? write_visibility(module_id, self.visibility(f.db), f)?; @@ -284,7 +283,7 @@ impl<'db> HirDisplay<'db> for Struct { } impl<'db> HirDisplay<'db> for Enum { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("enum ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -301,7 +300,7 @@ impl<'db> HirDisplay<'db> for Enum { } impl<'db> HirDisplay<'db> for Union { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("union ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -322,7 +321,7 @@ fn write_fields<'db>( limit: usize, in_line: bool, f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +) -> Result { let count = fields.len().min(limit); let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; f.write_char(if !has_where_clause { ' ' } else { separator })?; @@ -355,7 +354,7 @@ fn write_variants<'db>( has_where_clause: bool, limit: usize, f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +) -> Result { let count = variants.len().min(limit); f.write_char(if !has_where_clause { ' ' } else { '\n' })?; if count == 0 { @@ -391,7 +390,7 @@ fn write_variants<'db>( } impl<'db> HirDisplay<'db> for Field { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) @@ -399,14 +398,14 @@ impl<'db> HirDisplay<'db> for Field { } impl<'db> HirDisplay<'db> for TupleField { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) } } impl<'db> HirDisplay<'db> for Variant { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; let data = self.id.fields(f.db); match data.shape { @@ -436,19 +435,19 @@ impl<'db> HirDisplay<'db> for Variant { } impl<'db> HirDisplay<'db> for Type<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { self.ty.hir_fmt(f) } } impl<'db> HirDisplay<'db> for TypeNs<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { self.ty.hir_fmt(f) } } impl<'db> HirDisplay<'db> for ExternCrateDecl { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("extern crate ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -460,7 +459,7 @@ impl<'db> HirDisplay<'db> for ExternCrateDecl { } impl<'db> HirDisplay<'db> for GenericParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self { GenericParam::TypeParam(it) => it.hir_fmt(f), GenericParam::ConstParam(it) => it.hir_fmt(f), @@ -470,7 +469,7 @@ impl<'db> HirDisplay<'db> for GenericParam { } impl<'db> HirDisplay<'db> for TypeOrConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.split(f.db) { either::Either::Left(it) => it.hir_fmt(f), either::Either::Right(it) => it.hir_fmt(f), @@ -479,7 +478,7 @@ impl<'db> HirDisplay<'db> for TypeOrConstParam { } impl<'db> HirDisplay<'db> for TypeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let params = f.db.generic_params(self.id.parent()); let param_data = ¶ms[self.id.local_id()]; let krate = self.id.parent().krate(f.db).id; @@ -541,22 +540,19 @@ impl<'db> HirDisplay<'db> for TypeParam { } impl<'db> HirDisplay<'db> for LifetimeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "{}", self.name(f.db).display(f.db, f.edition())) } } impl<'db> HirDisplay<'db> for ConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) } } -fn write_generic_params<'db>( - def: GenericDefId, - f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { let (params, store) = f.db.generic_params_and_store(def); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) @@ -614,10 +610,7 @@ fn write_generic_params<'db>( Ok(()) } -fn write_where_clause<'db>( - def: GenericDefId, - f: &mut HirFormatter<'_, 'db>, -) -> Result<bool, HirDisplayError> { +fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result<bool> { let (params, store) = f.db.generic_params_and_store(def); if !has_disaplayable_predicates(f.db, ¶ms, &store) { return Ok(false); @@ -649,7 +642,7 @@ fn write_where_predicates<'db>( params: &GenericParams, store: &ExpressionStore, f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +) -> Result { use WherePredicate::*; // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. @@ -710,7 +703,7 @@ fn write_where_predicates<'db>( } impl<'db> HirDisplay<'db> for Const { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let db = f.db; let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); @@ -731,7 +724,7 @@ impl<'db> HirDisplay<'db> for Const { } impl<'db> HirDisplay<'db> for Static { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.static_signature(self.id); f.write_str("static ")?; @@ -745,13 +738,13 @@ impl<'db> HirDisplay<'db> for Static { } impl<'db> HirDisplay<'db> for TraitRef<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { self.trait_ref.hir_fmt(f) } } impl<'db> HirDisplay<'db> for Trait { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { // FIXME(trait-alias) needs special handling to print the equal sign write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); @@ -790,10 +783,7 @@ impl<'db> HirDisplay<'db> for Trait { } } -fn write_trait_header<'db>( - trait_: &Trait, - f: &mut HirFormatter<'_, 'db>, -) -> Result<(), HirDisplayError> { +fn write_trait_header<'db>(trait_: &Trait, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; let data = f.db.trait_signature(trait_.id); if data.flags.contains(TraitFlags::UNSAFE) { @@ -808,7 +798,7 @@ fn write_trait_header<'db>( } impl<'db> HirDisplay<'db> for TypeAlias { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.type_alias_signature(self.id); write!(f, "type {}", data.name.display(f.db, f.edition()))?; @@ -831,7 +821,7 @@ impl<'db> HirDisplay<'db> for TypeAlias { } impl<'db> HirDisplay<'db> for Module { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.parent(f.db) { Some(m) => write_visibility(m.id, self.visibility(f.db), f)?, None => { @@ -849,7 +839,7 @@ impl<'db> HirDisplay<'db> for Module { } impl<'db> HirDisplay<'db> for Crate { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.display_name(f.db) { Some(name) => write!(f, "extern crate {name}"), None => f.write_str("extern crate {unknown}"), @@ -858,7 +848,7 @@ impl<'db> HirDisplay<'db> for Crate { } impl<'db> HirDisplay<'db> for Macro { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.id { hir_def::MacroId::Macro2Id(_) => f.write_str("macro"), hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 6f427d728b..1aa7994001 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -20,7 +20,7 @@ use crate::{ pub trait HasSource { type Ast; /// Fetches the definition's source node. - /// Using [`crate::Semantics::source`] is preferred when working with [`crate::Semantics`], + /// Using [`crate::SemanticsImpl::source`] is preferred when working with [`crate::Semantics`], /// as that caches the parsed file in the semantics' cache. /// /// The current some implementations can return `InFile` instead of `Option<InFile>`. @@ -35,23 +35,23 @@ impl Module { /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].definition_source(db) + def_map[self.id].definition_source(db) } /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. pub fn definition_source_range(self, db: &dyn HirDatabase) -> InFile<TextRange> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].definition_source_range(db) + def_map[self.id].definition_source_range(db) } pub fn definition_source_file_id(self, db: &dyn HirDatabase) -> HirFileId { let def_map = self.id.def_map(db); - def_map[self.id.local_id].definition_source_file_id() + def_map[self.id].definition_source_file_id() } pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { let def_map = self.id.def_map(db); - match def_map[self.id.local_id].origin { + match def_map[self.id].origin { ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs, _ => false, } @@ -59,7 +59,7 @@ impl Module { pub fn as_source_file_id(self, db: &dyn HirDatabase) -> Option<EditionedFileId> { let def_map = self.id.def_map(db); - match def_map[self.id.local_id].origin { + match def_map[self.id].origin { ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition, .. } => { Some(definition) } @@ -69,21 +69,21 @@ impl Module { pub fn is_inline(self, db: &dyn HirDatabase) -> bool { let def_map = self.id.def_map(db); - def_map[self.id.local_id].origin.is_inline() + def_map[self.id].origin.is_inline() } /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root. pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].declaration_source(db) + def_map[self.id].declaration_source(db) } /// Returns a text range which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root. pub fn declaration_source_range(self, db: &dyn HirDatabase) -> Option<InFile<TextRange>> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].declaration_source_range(db) + def_map[self.id].declaration_source_range(db) } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2146e4db77..a50a736ccd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -48,11 +48,11 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, - DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - GenericParamId, HasModule, ImplId, InternedModuleId, ItemContainerId, LifetimeParamId, - LocalFieldId, Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, + HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, + TypeParamId, UnionId, attrs::AttrFlags, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ @@ -76,7 +76,7 @@ use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind, }; use hir_ty::{ - GenericPredicates, InferenceResult, TraitEnvironment, TyDefId, TyLoweringDiagnostic, + GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, db::{InternedClosureId, InternedCoroutineId}, @@ -89,7 +89,7 @@ use hir_ty::{ mir::{MutBorrowKind, interpret_mir}, next_solver::{ AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, + ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, traits::{self, is_inherent_impl_coherent, structurally_normalize_ty}, @@ -117,8 +117,8 @@ pub use crate::{ diagnostics::*, has_source::HasSource, semantics::{ - PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, - VisibleTraits, + LintAttr, PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, + TypeInfo, VisibleTraits, }, }; @@ -258,13 +258,13 @@ impl Crate { .flatten() } - pub fn root_module(self) -> Module { - Module { id: CrateRootModuleId::from(self.id).into() } + pub fn root_module(self, db: &dyn HirDatabase) -> Module { + Module { id: crate_def_map(db, self.id).root_module_id() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> { let def_map = crate_def_map(db, self.id); - def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect() + def_map.modules().map(|(id, _)| id.into()).collect() } pub fn root_file(self, db: &dyn HirDatabase) -> FileId { @@ -520,7 +520,7 @@ impl ModuleDef { impl HasCrate for ModuleDef { fn krate(&self, db: &dyn HirDatabase) -> Crate { match self.module(db) { - Some(module) => module.krate(), + Some(module) => module.krate(db), None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()), } } @@ -550,29 +550,29 @@ impl Module { } /// Returns the crate this module is part of. - pub fn krate(self) -> Crate { - Crate { id: self.id.krate() } + pub fn krate(self, db: &dyn HirDatabase) -> Crate { + Crate { id: self.id.krate(db) } } /// Topmost parent of this module. Every module has a `crate_root`, but some /// might be missing `krate`. This can happen if a module's file is not included /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { - let def_map = crate_def_map(db, self.id.krate()); - Module { id: def_map.crate_root().into() } + let def_map = crate_def_map(db, self.id.krate(db)); + Module { id: def_map.crate_root(db) } } - pub fn is_crate_root(self) -> bool { - DefMap::ROOT == self.id.local_id + pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { + self.crate_root(db) == self } /// Iterates over all child modules. pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { let def_map = self.id.def_map(db); - let children = def_map[self.id.local_id] + let children = def_map[self.id] .children .values() - .map(|module_id| Module { id: def_map.module_id(*module_id) }) + .map(|module_id| Module { id: *module_id }) .collect::<Vec<_>>(); children.into_iter() } @@ -580,14 +580,14 @@ impl Module { /// Finds a parent module. pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { let def_map = self.id.def_map(db); - let parent_id = def_map.containing_module(self.id.local_id)?; + let parent_id = def_map.containing_module(self.id)?; Some(Module { id: parent_id }) } /// Finds nearest non-block ancestor `Module` (`self` included). pub fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module { let mut id = self.id; - while id.is_block_module() { + while id.is_block_module(db) { id = id.containing_module(db).expect("block without parent module"); } Module { id } @@ -609,7 +609,7 @@ impl Module { db: &dyn HirDatabase, visible_from: Option<Module>, ) -> Vec<(Name, ScopeDef)> { - self.id.def_map(db)[self.id.local_id] + self.id.def_map(db)[self.id] .scope .entries() .filter_map(|(name, def)| { @@ -646,19 +646,19 @@ impl Module { style_lints: bool, ) { let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered(); - let edition = self.id.krate().data(db).edition; + let edition = self.id.krate(db).data(db).edition; let def_map = self.id.def_map(db); for diag in def_map.diagnostics() { - if diag.in_module != self.id.local_id { + if diag.in_module != self.id { // FIXME: This is accidentally quadratic. continue; } emit_def_diagnostic(db, acc, diag, edition, def_map.krate()); } - if !self.id.is_block_module() { + if !self.id.is_block_module(db) { // These are reported by the body of block modules - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc)); } @@ -666,7 +666,7 @@ impl Module { match def { ModuleDef::Module(m) => { // Only add diagnostics from inline modules - if def_map[m.id.local_id].origin.is_inline() { + if def_map[m.id].origin.is_inline() { m.diagnostics(db, acc, style_lints) } acc.extend(def.diagnostics(db, style_lints)) @@ -765,7 +765,7 @@ impl Module { } self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m)); - let interner = DbInterner::new_with(db, self.id.krate()); + let interner = DbInterner::new_with(db, self.id.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut impl_assoc_items_scratch = vec![]; @@ -790,7 +790,7 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { - emit_def_diagnostic(db, acc, diag, edition, loc.container.krate()); + emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); } if impl_signature.target_trait.is_none() @@ -939,7 +939,7 @@ impl Module { pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { let def_map = self.id.def_map(db); - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope .declarations() .map(ModuleDef::from) @@ -949,13 +949,13 @@ impl Module { pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> { let def_map = self.id.def_map(db); - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| it.into()).collect() } pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].scope.impls().map(Impl::from).collect() + def_map[self.id].scope.impls().map(Impl::from).collect() } /// Finds a path that can be used to refer to the given item from within @@ -990,7 +990,7 @@ impl Module { #[inline] pub fn doc_keyword(self, db: &dyn HirDatabase) -> Option<Symbol> { - AttrFlags::doc_keyword(db, InternedModuleId::new(db, self.id)) + AttrFlags::doc_keyword(db, self.id) } /// Whether it has `#[path = "..."]` attribute. @@ -1196,7 +1196,7 @@ fn precise_macro_call_location( impl HasVisibility for Module { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let def_map = self.id.def_map(db); - let module_data = &def_map[self.id.local_id]; + let module_data = &def_map[self.id]; module_data.visibility } } @@ -1245,7 +1245,7 @@ impl TupleField { .get(self.index as usize) .copied() .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); - Type { env: db.trait_environment_for_body(self.owner), ty } + Type { env: body_param_env_from_has_crate(db, self.owner), ty } } } @@ -1322,13 +1322,16 @@ impl Field { pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { db.layout_of_ty( self.ty(db).ty, - db.trait_environment(match hir_def::VariantId::from(self.parent) { - hir_def::VariantId::EnumVariantId(id) => { - GenericDefId::AdtId(id.lookup(db).parent.into()) - } - hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), - hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), - }), + param_env_from_has_crate( + db, + match hir_def::VariantId::from(self.parent) { + hir_def::VariantId::EnumVariantId(id) => { + GenericDefId::AdtId(id.lookup(db).parent.into()) + } + hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), + hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), + }, + ), ) .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } @@ -1538,7 +1541,7 @@ impl Enum { pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); Type::new_for_crate( - self.id.lookup(db).container.krate(), + self.id.lookup(db).container.krate(db), match EnumSignature::variant_body_type(db, self.id) { layout::IntegerType::Pointer(sign) => match sign { true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), @@ -1745,13 +1748,12 @@ impl Adt { } pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { - let env = db.trait_environment(self.into()); let interner = DbInterner::new_no_crate(db); let adt_id = AdtId::from(self); let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| { GenericArg::error_from_id(interner, id) }); - db.layout_of_adt(adt_id, args, env) + db.layout_of_adt(adt_id, args, param_env_from_has_crate(db, adt_id)) .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) } @@ -1925,7 +1927,7 @@ impl DefWithBody { pub fn debug_mir(self, db: &dyn HirDatabase) -> String { let body = db.mir_body(self.id()); match body { - Ok(body) => body.pretty_print(db, self.module(db).krate().to_display_target(db)), + Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)), Err(e) => format!("error:\n{e:?}"), } } @@ -1936,7 +1938,7 @@ impl DefWithBody { acc: &mut Vec<AnyDiagnostic<'db>>, style_lints: bool, ) { - let krate = self.module(db).id.krate(); + let krate = self.module(db).id.krate(db); let (body, source_map) = db.body_with_source_map(self.into()); let sig_source_map = match self { @@ -1950,7 +1952,7 @@ impl DefWithBody { }; for (_, def_map) in body.blocks(db) { - Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); + Module { id: def_map.root_module_id() }.diagnostics(db, acc, style_lints); } expr_store_diagnostics(db, acc, &source_map); @@ -2276,7 +2278,7 @@ impl Function { } pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { - let environment = db.trait_environment(self.id.into()); + let environment = param_env_from_has_crate(db, self.id); // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); @@ -2285,7 +2287,7 @@ impl Function { .iter() .enumerate() .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; + let ty = Type { env: environment, ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2301,7 +2303,7 @@ impl Function { } pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { - let environment = db.trait_environment(self.id.into()); + let environment = param_env_from_has_crate(db, self.id); // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); @@ -2312,7 +2314,7 @@ impl Function { .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; + let ty = Type { env: environment, ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2324,7 +2326,7 @@ impl Function { db: &'db dyn HirDatabase, generics: impl Iterator<Item = Type<'db>>, ) -> Vec<Param<'db>> { - let environment = db.trait_environment(self.id.into()); + let environment = param_env_from_has_crate(db, self.id); let interner = DbInterner::new_no_crate(db); let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); let callable_sig = @@ -2336,7 +2338,7 @@ impl Function { .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; + let ty = Type { env: environment, ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2396,7 +2398,7 @@ impl Function { /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { self.exported_main(db) - || self.module(db).is_crate_root() && db.function_signature(self.id).name == sym::main + || self.module(db).is_crate_root(db) && db.function_signature(self.id).name == sym::main } /// Is this a function with an `export_name` of `main`? @@ -2471,7 +2473,10 @@ impl Function { let body = db.monomorphized_mir_body( self.id.into(), GenericArgs::new_from_iter(interner, []), - db.trait_environment(self.id.into()), + ParamEnvAndCrate { + param_env: db.trait_environment(self.id.into()), + krate: self.id.module(db).krate(db), + }, )?; let (result, output) = interpret_mir(db, body, false, None)?; let mut text = match result { @@ -2613,7 +2618,7 @@ impl SelfParam { // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let callable_sig = db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); - let environment = db.trait_environment(self.func.into()); + let environment = param_env_from_has_crate(db, self.func); let ty = callable_sig.inputs().as_slice()[0]; Type { env: environment, ty } } @@ -2628,7 +2633,7 @@ impl SelfParam { let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty)); let callable_sig = db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); - let environment = db.trait_environment(self.func.into()); + let environment = param_env_from_has_crate(db, self.func); let ty = callable_sig.inputs().as_slice()[0]; Type { env: environment, ty } } @@ -2652,7 +2657,7 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> { let loc = self.id.lookup(db); - let krate = loc.container.krate(); + let krate = loc.container.krate(db); let name = self.name(db); if name == sym::self_ { Some(krate.into()) @@ -3234,8 +3239,8 @@ impl ItemInNs { /// Returns the crate defining this item (or `None` if `self` is built-in). pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> { match self { - ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()), - ItemInNs::Macros(id) => Some(id.module(db).krate()), + ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate(db)), + ItemInNs::Macros(id) => Some(id.module(db).krate(db)), } } @@ -3687,11 +3692,11 @@ impl GenericDef { pub struct GenericSubstitution<'db> { def: GenericDefId, subst: GenericArgs<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, env: Arc<TraitEnvironment<'db>>) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, env: ParamEnvAndCrate<'db>) -> Self { Self { def, subst, env } } @@ -3737,9 +3742,7 @@ impl<'db> GenericSubstitution<'db> { .zip(type_params); container_params .chain(self_params) - .filter_map(|(ty, name)| { - Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) - }) + .filter_map(|(ty, name)| Some((name?.symbol().clone(), Type { ty, env: self.env }))) .collect() } } @@ -4320,7 +4323,7 @@ impl Impl { } pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec<Impl> { - module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect() + module.id.def_map(db)[module.id].scope.impls().map(Into::into).collect() } /// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type", @@ -4345,15 +4348,13 @@ impl Impl { if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) { InherentImpls::for_each_crate_and_block( db, - module.krate(), - module.containing_block(), + module.krate(db), + module.block(db), &mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)), ); - std::iter::successors(module.containing_block(), |block| { - block.loc(db).module.containing_block() - }) - .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) - .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); + std::iter::successors(module.block(db), |block| block.loc(db).module.block(db)) + .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) + .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); for &krate in &**db.all_crates() { TraitImpls::for_crate(db, krate) .for_self_ty(&simplified_ty, &mut extend_with_impls); @@ -4373,10 +4374,10 @@ impl Impl { let mut handle_impls = |impls: &TraitImpls| { impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from))); }; - for krate in module.krate().transitive_rev_deps(db) { + for krate in module.krate(db).transitive_rev_deps(db) { handle_impls(TraitImpls::for_crate(db, krate)); } - if let Some(block) = module.containing_block() + if let Some(block) = module.block(db) && let Some(impls) = TraitImpls::for_block(db, block) { handle_impls(impls); @@ -4428,7 +4429,7 @@ impl Impl { MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { let module_id = self.id.lookup(db).container; ( - crate_def_map(db, module_id.krate())[module_id.local_id] + module_id.def_map(db)[module_id] .scope .derive_macro_invoc(ast_id, derive_attr_index)?, derive_index, @@ -4459,7 +4460,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4469,9 +4470,7 @@ impl<'db> TraitRef<'db> { resolver: &Resolver<'_>, trait_ref: hir_ty::next_solver::TraitRef<'db>, ) -> Self { - let env = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let env = param_env_from_resolver(db, resolver); TraitRef { env, trait_ref } } @@ -4481,7 +4480,7 @@ impl<'db> TraitRef<'db> { pub fn self_ty(&self) -> TypeNs<'_> { let ty = self.trait_ref.self_ty(); - TypeNs { env: self.env.clone(), ty } + TypeNs { env: self.env, ty } } /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the @@ -4492,7 +4491,7 @@ impl<'db> TraitRef<'db> { .as_slice() .get(idx) .and_then(|arg| arg.ty()) - .map(|ty| TypeNs { env: self.env.clone(), ty }) + .map(|ty| TypeNs { env: self.env, ty }) } } @@ -4556,11 +4555,8 @@ impl<'db> Closure<'db> { let owner = db.lookup_intern_closure(id).0; let infer = InferenceResult::for_body(db, owner); let (captures, _) = infer.closure_info(id); - let env = db.trait_environment_for_body(owner); - captures - .iter() - .map(|capture| Type { env: env.clone(), ty: capture.ty(db, self.subst) }) - .collect() + let env = body_param_env_from_has_crate(db, owner); + captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect() } pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { @@ -4768,7 +4764,7 @@ impl CaptureUsageSource { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ty: Ty<'db>, } @@ -4786,21 +4782,17 @@ impl<'db> Type<'db> { resolver: &Resolver<'_>, ty: Ty<'db>, ) -> Self { - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, resolver); Type { env: environment, ty } } pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty<'db>) -> Self { - Type { env: TraitEnvironment::empty(krate), ty } + Type { env: empty_param_env(krate), ty } } fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { let resolver = lexical_env.resolver(db); - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, &resolver); Type { env: environment, ty } } @@ -4856,7 +4848,7 @@ impl<'db> Type<'db> { pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self { let tys = tys.iter().map(|it| it.ty); let interner = DbInterner::conjure(); - Type { env: TraitEnvironment::empty(krate), ty: Ty::new_tup_from_iter(interner, tys) } + Type { env: empty_param_env(krate), ty: Ty::new_tup_from_iter(interner, tys) } } pub fn is_unit(&self) -> bool { @@ -5046,7 +5038,7 @@ impl<'db> Type<'db> { }) .or(lang_items.Future)?; - if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { return None; } @@ -5077,7 +5069,7 @@ impl<'db> Type<'db> { let Some(iterator_trait) = lang_items.Iterator else { return false; }; - traits::implements_trait_unique(self.ty, db, self.env.clone(), iterator_trait) + traits::implements_trait_unique(self.ty, db, self.env, iterator_trait) } /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type @@ -5089,7 +5081,7 @@ impl<'db> Type<'db> { Some(into_iter_trait.id) })?; - if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { return None; } @@ -5110,7 +5102,7 @@ impl<'db> Type<'db> { None => return false, }; - traits::implements_trait_unique(self.ty, db, self.env.clone(), fnonce_trait) + traits::implements_trait_unique(self.ty, db, self.env, fnonce_trait) } // FIXME: Find better API that also handles const generics @@ -5121,7 +5113,7 @@ impl<'db> Type<'db> { trait_.id.into(), std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)), ); - traits::implements_trait_unique_with_args(db, self.env.clone(), trait_.id, args) + traits::implements_trait_unique_with_args(db, self.env, trait_.id, args) } pub fn normalize_trait_assoc_type( @@ -5144,7 +5136,7 @@ impl<'db> Type<'db> { ); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = structurally_normalize_ty(&infcx, projection, self.env.clone()); + let ty = structurally_normalize_ty(&infcx, projection, self.env.param_env); if ty.is_ty_error() { None } else { Some(self.derived(ty)) } } @@ -5166,8 +5158,7 @@ impl<'db> Type<'db> { // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db), _ => { - let (fn_trait, sig) = - hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?; + let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(self.ty, self.env, db)?; return Some(Callable { ty: self.clone(), sig, @@ -5291,7 +5282,7 @@ impl<'db> Type<'db> { let interner = DbInterner::new_no_crate(db); // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); - autoderef(db, self.env.clone(), canonical) + autoderef(db, self.env, canonical) } // This would be nicer if it just returned an iterator, but that runs into @@ -5336,8 +5327,8 @@ impl<'db> Type<'db> { if let Some(module) = method_resolution::simplified_type_module(db, &simplified_type) { InherentImpls::for_each_crate_and_block( db, - module.krate(), - module.containing_block(), + module.krate(db), + module.block(db), &mut |impls| { handle_impls(impls.for_self_ty(&simplified_type)); }, @@ -5473,17 +5464,15 @@ impl<'db> Type<'db> { f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R, ) -> R { let module = resolver.module(); - let interner = DbInterner::new_with(db, module.krate()); + let interner = DbInterner::new_with(db, module.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let unstable_features = MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map()); - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(module.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, resolver); let ctx = MethodResolutionContext { infcx: &infcx, resolver, - env: &environment, + param_env: environment.param_env, traits_in_scope, edition: resolver.krate().data(db).edition, unstable_features: &unstable_features, @@ -5704,7 +5693,13 @@ impl<'db> Type<'db> { .filter(|ty| matches!(ty.kind(), TyKind::Param(_))) .flat_map(|ty| { self.env - .traits_in_scope_from_clauses(ty) + .param_env + .clauses() + .iter() + .filter_map(move |pred| match pred.kind().skip_binder() { + ClauseKind::Trait(tr) if tr.self_ty() == ty => Some(tr.def_id().0), + _ => None, + }) .flat_map(|t| hir_ty::all_super_traits(db, t)) }) .map(Trait::from) @@ -5728,7 +5723,7 @@ impl<'db> Type<'db> { } fn derived(&self, ty: Ty<'db>) -> Self { - Type { env: self.env.clone(), ty } + Type { env: self.env, ty } } /// Visits every type, including generic arguments, in this type. `callback` is called with type @@ -5736,7 +5731,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, callback: F, visited: FxHashSet<Ty<'db>>, } @@ -5751,7 +5746,7 @@ impl<'db> Type<'db> { return; } - (self.callback)(Type { env: self.env.clone(), ty }); + (self.callback)(Type { env: self.env, ty }); if let Some(bounds) = ty.impl_trait_bounds(self.db) { bounds.visit_with(self); @@ -5761,8 +5756,7 @@ impl<'db> Type<'db> { } } - let mut visitor = - Visitor { db, env: self.env.clone(), callback, visited: FxHashSet::default() }; + let mut visitor = Visitor { db, env: self.env, callback, visited: FxHashSet::default() }; self.ty.visit_with(&mut visitor); } /// Check if type unifies with another type. @@ -5772,7 +5766,7 @@ impl<'db> Type<'db> { pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); - hir_ty::could_unify(db, self.env.clone(), &tys) + hir_ty::could_unify(db, self.env, &tys) } /// Check if type unifies with another type eagerly making sure there are no unresolved goals. @@ -5782,13 +5776,13 @@ impl<'db> Type<'db> { pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); - hir_ty::could_unify_deeply(db, self.env.clone(), &tys) + hir_ty::could_unify_deeply(db, self.env, &tys) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, to.ty)); - hir_ty::could_coerce(db, self.env.clone(), &tys) + hir_ty::could_coerce(db, self.env, &tys) } pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option<TypeParam> { @@ -5807,34 +5801,32 @@ impl<'db> Type<'db> { } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> { - db.layout_of_ty(self.ty, self.env.clone()) + db.layout_of_ty(self.ty, self.env) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { let interner = DbInterner::new_with(db, self.env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.clone()) + hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.param_env) } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeNs<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ty: Ty<'db>, } impl<'db> TypeNs<'db> { fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { let resolver = lexical_env.resolver(db); - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, &resolver); TypeNs { env: environment, ty } } pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> { - Type { env: self.env.clone(), ty: self.ty } + Type { env: self.env, ty: self.ty } } // FIXME: Find better API that also handles const generics @@ -6146,12 +6138,12 @@ impl ScopeDef { pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> { match self { - ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()), - ScopeDef::GenericParam(it) => Some(it.module(db).krate()), + ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate(db)), + ScopeDef::GenericParam(it) => Some(it.module(db).krate(db)), ScopeDef::ImplSelfType(_) => None, - ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()), - ScopeDef::Local(it) => Some(it.module(db).krate()), - ScopeDef::Label(it) => Some(it.module(db).krate()), + ScopeDef::AdtSelfType(it) => Some(it.module(db).krate(db)), + ScopeDef::Local(it) => Some(it.module(db).krate(db)), + ScopeDef::Label(it) => Some(it.module(db).krate(db)), ScopeDef::Unknown => None, } } @@ -6211,61 +6203,61 @@ pub trait HasCrate { impl<T: hir_def::HasModule> HasCrate for T { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate().into() + self.module(db).krate(db).into() } } impl HasCrate for AssocItem { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Struct { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Union { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Enum { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Field { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.parent_def(db).module(db).krate() + self.parent_def(db).module(db).krate(db) } } impl HasCrate for Variant { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Function { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Const { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for TypeAlias { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } @@ -6277,37 +6269,37 @@ impl HasCrate for Type<'_> { impl HasCrate for Macro { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Trait { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Static { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Adt { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Impl { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Module { - fn krate(&self, _: &dyn HirDatabase) -> Crate { - Module::krate(*self) + fn krate(&self, db: &dyn HirDatabase) -> Crate { + Module::krate(*self, db) } } @@ -6325,8 +6317,8 @@ impl HasContainer for Module { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { // FIXME: handle block expressions as modules (their parent is in a different DefMap) let def_map = self.id.def_map(db); - match def_map[self.id.local_id].parent { - Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }), + match def_map[self.id].parent { + Some(parent_id) => ItemContainer::Module(Module { id: parent_id }), None => ItemContainer::Crate(def_map.krate().into()), } } @@ -6485,7 +6477,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( .filter_map(|&krate| { let segments = segments.clone(); let mut def_map = crate_def_map(db, krate); - let mut module = &def_map[DefMap::ROOT]; + let mut module = &def_map[def_map.root_module_id()]; let mut segments = segments.with_position().peekable(); while let Some((_, segment)) = segments.next_if(|&(position, _)| { !matches!(position, itertools::Position::Last | itertools::Position::Only) @@ -6499,7 +6491,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( _ => None, })?; def_map = res.def_map(db); - module = &def_map[res.local_id]; + module = &def_map[res]; } let (_, item_name) = segments.next()?; let res = module.scope.get(&Name::new_symbol_root(item_name)); @@ -6546,5 +6538,35 @@ fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) }) } +fn param_env_from_resolver<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'_>, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { + param_env: resolver + .generic_def() + .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def)), + krate: resolver.krate(), + } +} + +fn param_env_from_has_crate<'db>( + db: &'db dyn HirDatabase, + id: impl hir_def::HasModule + Into<GenericDefId> + Copy, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } +} + +fn body_param_env_from_has_crate<'db>( + db: &'db dyn HirDatabase, + id: impl hir_def::HasModule + Into<DefWithBodyId> + Copy, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: db.trait_environment_for_body(id.into()), krate: id.krate(db) } +} + +fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: ParamEnv::empty(), krate } +} + pub use hir_ty::next_solver; pub use hir_ty::setup_tracing; diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 82e60bff5e..b15e642daa 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -39,8 +39,8 @@ use smallvec::{SmallVec, smallvec}; use span::{FileId, SyntaxContext}; use stdx::{TupleExt, always}; use syntax::{ - AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, - TextSize, + AstNode, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind, SyntaxNode, + SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize, algo::skip_trivia_token, ast::{self, HasAttrs as _, HasGenericParams}, }; @@ -174,6 +174,15 @@ impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum LintAttr { + Allow, + Expect, + Warn, + Deny, + Forbid, +} + // Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not // find actual use within the rust-analyzer project itself, it exists to enable the use // within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`. @@ -254,6 +263,59 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> { .filter_map(ast::NameLike::cast) } + pub fn lint_attrs( + &self, + krate: Crate, + item: ast::AnyHasAttrs, + ) -> impl DoubleEndedIterator<Item = (LintAttr, SmolStr)> { + let mut cfg_options = None; + let cfg_options = || *cfg_options.get_or_insert_with(|| krate.id.cfg_options(self.db)); + let mut result = Vec::new(); + hir_expand::attrs::expand_cfg_attr::<Infallible>( + ast::attrs_including_inner(&item), + cfg_options, + |attr, _, _, _| { + let hir_expand::attrs::Meta::TokenTree { path, tt } = attr else { + return ControlFlow::Continue(()); + }; + if path.segments.len() != 1 { + return ControlFlow::Continue(()); + } + let lint_attr = match path.segments[0].text() { + "allow" => LintAttr::Allow, + "expect" => LintAttr::Expect, + "warn" => LintAttr::Warn, + "deny" => LintAttr::Deny, + "forbid" => LintAttr::Forbid, + _ => return ControlFlow::Continue(()), + }; + let mut lint = SmolStrBuilder::new(); + for token in + tt.syntax().children_with_tokens().filter_map(SyntaxElement::into_token) + { + match token.kind() { + T![:] | T![::] => lint.push_str(token.text()), + kind if kind.is_any_identifier() => lint.push_str(token.text()), + T![,] => { + let lint = mem::replace(&mut lint, SmolStrBuilder::new()).finish(); + if !lint.is_empty() { + result.push((lint_attr, lint)); + } + } + _ => {} + } + } + let lint = lint.finish(); + if !lint.is_empty() { + result.push((lint_attr, lint)); + } + + ControlFlow::Continue(()) + }, + ); + result.into_iter() + } + pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> { self.imp.resolve_range_pat(range_pat).map(Struct::from) } @@ -380,13 +442,13 @@ impl<'db> SemanticsImpl<'db> { /// If not crate is found for the file, try to return the last crate in topological order. pub fn first_crate(&self, file: FileId) -> Option<Crate> { match self.file_to_module_defs(file).next() { - Some(module) => Some(module.krate()), + Some(module) => Some(module.krate(self.db)), None => self.db.all_crates().last().copied().map(Into::into), } } pub fn attach_first_edition_opt(&self, file: FileId) -> Option<EditionedFileId> { - let krate = self.file_to_module_defs(file).next()?.krate(); + let krate = self.file_to_module_defs(file).next()?.krate(self.db); Some(EditionedFileId::new(self.db, file, krate.edition(self.db), krate.id)) } @@ -416,8 +478,8 @@ impl<'db> SemanticsImpl<'db> { match file_id { HirFileId::FileId(file_id) => { let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?; - let def_map = crate_def_map(self.db, module.krate().id); - match def_map[module.id.local_id].origin { + let def_map = crate_def_map(self.db, module.krate(self.db).id); + match def_map[module.id].origin { ModuleOrigin::CrateRoot { .. } => None, ModuleOrigin::File { declaration, declaration_tree_id, .. } => { let file_id = declaration_tree_id.file_id(); @@ -443,7 +505,7 @@ impl<'db> SemanticsImpl<'db> { /// the `SyntaxNode` of the *definition* file, not of the *declaration*. pub fn module_definition_node(&self, module: Module) -> InFile<SyntaxNode> { let def_map = module.id.def_map(self.db); - let definition = def_map[module.id.local_id].origin.definition_source(self.db); + let definition = def_map[module.id].origin.definition_source(self.db); let definition = definition.map(|it| it.node()); let root_node = find_root(&definition.value); self.cache(root_node, definition.file_id); @@ -472,7 +534,7 @@ impl<'db> SemanticsImpl<'db> { let file_id = self.find_file(attr.syntax()).file_id; let krate = match file_id { HirFileId::FileId(file_id) => { - self.file_to_module_defs(file_id.file_id(self.db)).next()?.krate().id + self.file_to_module_defs(file_id.file_id(self.db)).next()?.krate(self.db).id } HirFileId::MacroFile(macro_file) => self.db.lookup_intern_macro_call(macro_file).krate, }; diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs index 165ac7e4a0..c1f72debe5 100644 --- a/crates/hir/src/semantics/child_by_source.rs +++ b/crates/hir/src/semantics/child_by_source.rs @@ -20,7 +20,6 @@ use hir_def::{ }, hir::generics::GenericParams, item_scope::ItemScope, - nameres::DefMap, src::{HasChildSource, HasSource}, }; @@ -87,7 +86,7 @@ impl ChildBySource for ImplId { impl ChildBySource for ModuleId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let def_map = self.def_map(db); - let module_data = &def_map[self.local_id]; + let module_data = &def_map[*self]; module_data.scope.child_by_source_to(db, res, file_id); } } @@ -226,7 +225,7 @@ impl ChildBySource for DefWithBodyId { for (block, def_map) in body.blocks(db) { // All block expressions are merged into the same map, because they logically all add // inner items to the containing `DefWithBodyId`. - def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id); + def_map[def_map.root].scope.child_by_source_to(db, res, file_id); res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db), block); } } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 44df4d8fc8..2574059927 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -183,11 +183,7 @@ impl SourceToDefCtx<'_, '_> { // Note: `mod` declarations in block modules cannot be supported here let crate_def_map = crate_def_map(self.db, crate_id); let n_mods = mods.len(); - let modules = |file| { - crate_def_map - .modules_for_file(self.db, file) - .map(|local_id| crate_def_map.module_id(local_id)) - }; + let modules = |file| crate_def_map.modules_for_file(self.db, file); mods.extend(modules(file)); if mods.len() == n_mods { mods.extend( @@ -239,8 +235,8 @@ impl SourceToDefCtx<'_, '_> { let child_name = src.value.name()?.as_name(); let def_map = parent_module.def_map(self.db); - let &child_id = def_map[parent_module.local_id].children.get(&child_name)?; - Some(def_map.module_id(child_id)) + let &child_id = def_map[parent_module].children.get(&child_name)?; + Some(child_id) } pub(super) fn source_file_to_def(&mut self, src: InFile<&ast::SourceFile>) -> Option<ModuleId> { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 8144b2f737..901c9e1575 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -29,7 +29,7 @@ use hir_expand::{ name::{AsName, Name}, }; use hir_ty::{ - Adjustment, InferenceResult, LifetimeElisionKind, TraitEnvironment, TyLoweringContext, + Adjustment, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -37,7 +37,8 @@ use hir_ty::{ lang_items::lang_items_for_bin_op, method_resolution::{self, CandidateId}, next_solver::{ - DbInterner, ErrorGuaranteed, GenericArgs, Ty, TyKind, TypingMode, infer::DbInternerInferExt, + DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, + infer::DbInternerInferExt, }, traits::structurally_normalize_ty, }; @@ -227,10 +228,15 @@ impl<'db> SourceAnalyzer<'db> { }) } - fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment<'db>> { - self.body_().map(|(def, ..)| def).map_or_else( - || TraitEnvironment::empty(self.resolver.krate()), - |def| db.trait_environment_for_body(def), + fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> { + ParamEnvAndCrate { param_env, krate: self.resolver.krate() } + } + + fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { + self.param_and( + self.body_() + .map(|(def, ..)| def) + .map_or_else(ParamEnv::empty, |def| db.trait_environment_for_body(def)), ) } @@ -827,7 +833,7 @@ impl<'db> SourceAnalyzer<'db> { let mut container = Either::Right(container.ty); for field_name in offset_of_expr.fields() { if let Either::Right(container) = &mut container { - *container = structurally_normalize_ty(&infcx, *container, trait_env.clone()); + *container = structurally_normalize_ty(&infcx, *container, trait_env.param_env); } let handle_variants = |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| { @@ -1412,7 +1418,7 @@ impl<'db> SourceAnalyzer<'db> { Some(it) => it, None => return (func, substs), }; - let env = db.trait_environment_for_body(owner); + let env = self.param_and(db.trait_environment_for_body(owner)); db.lookup_impl_method(env, func, substs) } @@ -1426,10 +1432,10 @@ impl<'db> SourceAnalyzer<'db> { Some(it) => it, None => return (const_id, subs), }; - let env = db.trait_environment_for_body(owner); + let env = self.param_and(db.trait_environment_for_body(owner)); let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - method_resolution::lookup_impl_const(&infcx, env, const_id, subs) + method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs) } fn lang_items<'a>(&self, db: &'a dyn HirDatabase) -> &'a LangItems { diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 1530e697a3..073142670d 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -1,5 +1,7 @@ //! File symbol extraction. +use std::marker::PhantomData; + use base_db::FxIndexSet; use either::Either; use hir_def::{ @@ -25,7 +27,7 @@ use crate::{HasCrate, Module, ModuleDef, Semantics}; /// The actual data that is stored in the index. It should be as compact as /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FileSymbol { +pub struct FileSymbol<'db> { pub name: Symbol, pub def: ModuleDef, pub loc: DeclarationLocation, @@ -35,6 +37,7 @@ pub struct FileSymbol { pub is_assoc: bool, pub is_import: bool, pub do_not_complete: Complete, + _marker: PhantomData<&'db ()>, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -61,9 +64,9 @@ struct SymbolCollectorWork { parent: Option<Name>, } -pub struct SymbolCollector<'a> { - db: &'a dyn HirDatabase, - symbols: FxIndexSet<FileSymbol>, +pub struct SymbolCollector<'db> { + db: &'db dyn HirDatabase, + symbols: FxIndexSet<FileSymbol<'db>>, work: Vec<SymbolCollectorWork>, current_container_name: Option<Symbol>, collect_pub_only: bool, @@ -83,10 +86,10 @@ impl<'a> SymbolCollector<'a> { } pub fn new_module( - db: &dyn HirDatabase, + db: &'a dyn HirDatabase, module: Module, collect_pub_only: bool, - ) -> Box<[FileSymbol]> { + ) -> Box<[FileSymbol<'a>]> { let mut symbol_collector = SymbolCollector::new(db, collect_pub_only); symbol_collector.collect(module); symbol_collector.finish() @@ -105,7 +108,7 @@ impl<'a> SymbolCollector<'a> { } } - pub fn finish(self) -> Box<[FileSymbol]> { + pub fn finish(self) -> Box<[FileSymbol<'a>]> { self.symbols.into_iter().collect() } @@ -217,6 +220,7 @@ impl<'a> SymbolCollector<'a> { is_assoc: false, is_import: true, do_not_complete: Complete::Yes, + _marker: PhantomData, }); }; @@ -251,11 +255,12 @@ impl<'a> SymbolCollector<'a> { is_assoc: false, is_import: false, do_not_complete: Complete::Yes, + _marker: PhantomData, }); }; let def_map = module_id.def_map(self.db); - let scope = &def_map[module_id.local_id].scope; + let scope = &def_map[module_id].scope; for impl_id in scope.impls() { self.collect_from_impl(impl_id); @@ -329,10 +334,7 @@ impl<'a> SymbolCollector<'a> { // Descend into the blocks and enqueue collection of all modules within. for (_, def_map) in body.blocks(self.db) { for (id, _) in def_map.modules() { - self.work.push(SymbolCollectorWork { - module_id: def_map.module_id(id), - parent: name.clone(), - }); + self.work.push(SymbolCollectorWork { module_id: id, parent: name.clone() }); } } } @@ -431,6 +433,7 @@ impl<'a> SymbolCollector<'a> { is_assoc, is_import: false, do_not_complete, + _marker: PhantomData, }); } } @@ -444,6 +447,7 @@ impl<'a> SymbolCollector<'a> { is_assoc, is_import: false, do_not_complete, + _marker: PhantomData, }); do_not_complete @@ -451,7 +455,7 @@ impl<'a> SymbolCollector<'a> { fn push_module(&mut self, module_id: ModuleId, name: &Name) { let def_map = module_id.def_map(self.db); - let module_data = &def_map[module_id.local_id]; + let module_data = &def_map[module_id]; let Some(declaration) = module_data.origin.declaration() else { return }; let module = declaration.to_node(self.db); let Some(name_node) = module.name() else { return }; @@ -477,6 +481,7 @@ impl<'a> SymbolCollector<'a> { is_assoc: false, is_import: false, do_not_complete, + _marker: PhantomData, }); } } @@ -490,6 +495,7 @@ impl<'a> SymbolCollector<'a> { is_assoc: false, is_import: false, do_not_complete, + _marker: PhantomData, }); } } diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index 979ec8c49f..05a89e7652 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -762,7 +762,7 @@ pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( .filter(|_| should_continue()) .map(|params| { let tys: Vec<Type<'_>> = params.iter().map(|it| it.ty(db)).collect(); - let tuple_ty = Type::new_tuple(module.krate().into(), &tys); + let tuple_ty = Type::new_tuple(module.krate(db).into(), &tys); let expr = Expr::Tuple { ty: tuple_ty.clone(), params }; lookup.insert(tuple_ty, iter::once(expr.clone())); diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index e970bb7167..65ca1ceae1 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -130,7 +130,7 @@ fn add_missing_impl_members_inner( if let IgnoreAssocItems::DocHiddenAttrPresent = ignore_items { // Relax condition for local crates. let db = ctx.db(); - if trait_.module(db).krate().origin(db).is_local() { + if trait_.module(db).krate(db).origin(db).is_local() { ign_item = IgnoreAssocItems::No; } } diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 248ce2ad61..10c3ff0e4d 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -92,24 +92,25 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) bool, bool, ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) { - let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); + let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db())); let variants = enum_def.variants(ctx.db()); - let has_hidden_variants = - variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let has_hidden_variants = variants + .iter() + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db()))); let missing_pats = variants .into_iter() .filter_map(|variant| { Some(( build_pat(ctx, &make, module, variant, cfg)?, - variant.should_be_hidden(ctx.db(), module.krate()), + variant.should_be_hidden(ctx.db(), module.krate(ctx.db())), )) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option(); + let option_enum = FamousDefs(&ctx.sema, module.krate(ctx.db())).core_option_Option(); let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum) { // Match `Some` variant first. @@ -120,8 +121,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) }; (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants) } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) { - let is_non_exhaustive = - enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate())); + let is_non_exhaustive = enum_defs + .iter() + .any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db()))); let mut n_arms = 1; let variants_of_enums: Vec<Vec<ExtendedVariant>> = enum_defs @@ -145,7 +147,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let has_hidden_variants = variants_of_enums .iter() .flatten() - .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db()))); let missing_pats = variants_of_enums .into_iter() @@ -154,7 +156,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .map(|variants| { let is_hidden = variants .iter() - .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db()))); let patterns = variants .into_iter() .filter_map(|variant| build_pat(ctx, &make, module, variant, cfg)); @@ -170,15 +172,16 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) { - let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); + let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db())); let variants = enum_def.variants(ctx.db()); if len.pow(variants.len() as u32) > 256 { return None; } - let has_hidden_variants = - variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let has_hidden_variants = variants + .iter() + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db()))); let variants_of_enums = vec![variants; len]; @@ -189,7 +192,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .map(|variants| { let is_hidden = variants .iter() - .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db()))); let patterns = variants .into_iter() .filter_map(|variant| build_pat(ctx, &make, module, variant, cfg)); @@ -401,7 +404,7 @@ impl ExtendedVariant { fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool { match self { ExtendedVariant::Variant { variant: var, .. } => { - var.attrs(db).is_doc_hidden() && var.module(db).krate() != krate + var.attrs(db).is_doc_hidden() && var.module(db).krate(db) != krate } _ => false, } @@ -424,7 +427,7 @@ impl ExtendedEnum { fn is_non_exhaustive(&self, db: &RootDatabase, krate: Crate) -> bool { match self { ExtendedEnum::Enum { enum_: e, .. } => { - e.attrs(db).is_non_exhaustive() && e.module(db).krate() != krate + e.attrs(db).is_non_exhaustive() && e.module(db).krate(db) != krate } _ => false, } @@ -502,7 +505,7 @@ fn build_pat( let db = ctx.db(); match var { ExtendedVariant::Variant { variant: var, use_self } => { - let edition = module.krate().edition(db); + let edition = module.krate(db).edition(db); let path = if use_self { make::path_from_segments( [ diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs index 3281adbcc3..d193e8a9d8 100644 --- a/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -260,7 +260,7 @@ fn validate_method_call_expr( let receiver = method_call.receiver()?; let it_type = sema.type_of_expr(&receiver)?.adjusted(); let module = sema.scope(receiver.syntax())?.module(); - let krate = module.krate(); + let krate = module.krate(ctx.db()); let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; it_type.impls_trait(sema.db, iter_trait, &[]).then_some((name_ref, arg_expr)) diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index bb6a10d40b..cc2bf81749 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -114,7 +114,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< proposed_imports.sort_by_key(|import| { Reverse(relevance_score(ctx, import, expected.as_ref(), current_module.as_ref())) }); - let edition = current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT); + let edition = + current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT); let group_label = group_label(import_assets.import_candidate()); for import in proposed_imports { @@ -316,11 +317,11 @@ fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Modu let distinct_length = current_path.len() + item_path.len() - 2 * prefix_length; // cost of importing from another crate - let crate_boundary_cost = if current.krate() == item.krate() { + let crate_boundary_cost = if current.krate(db) == item.krate(db) { 0 - } else if item.krate().origin(db).is_local() { + } else if item.krate(db).origin(db).is_local() { 2 - } else if item.krate().is_builtin(db) { + } else if item.krate(db).is_builtin(db) { 3 } else { 4 diff --git a/crates/ide-assists/src/handlers/bind_unused_param.rs b/crates/ide-assists/src/handlers/bind_unused_param.rs index 1b24f7fe7f..771e80bb92 100644 --- a/crates/ide-assists/src/handlers/bind_unused_param.rs +++ b/crates/ide-assists/src/handlers/bind_unused_param.rs @@ -33,7 +33,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O return None; } - let func = param.syntax().ancestors().find_map(ast::Fn::cast)?; + let func = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?; let stmt_list = func.body()?.stmt_list()?; let l_curly_range = stmt_list.l_curly_token()?.text_range(); let r_curly_range = stmt_list.r_curly_token()?.text_range(); @@ -179,4 +179,16 @@ fn foo($0_x: i32, y: i32) {} "#, ); } + + #[test] + fn not_applicable_closure() { + check_assist_not_applicable( + bind_unused_param, + r#" +fn foo() { + let _ = |$0x| 2; +} +"#, + ); + } } diff --git a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 2ad1336237..1ae5f64917 100644 --- a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -329,7 +329,7 @@ fn augment_references_with_imports( ) -> Vec<FileReferenceWithImport> { let mut visited_modules = FxHashSet::default(); - let edition = target_module.krate().edition(ctx.db()); + let edition = target_module.krate(ctx.db()).edition(ctx.db()); references .into_iter() .filter_map(|FileReference { range, name, .. }| { @@ -345,8 +345,9 @@ fn augment_references_with_imports( ImportScope::find_insert_use_container(name.syntax(), &ctx.sema).and_then( |import_scope| { - let cfg = - ctx.config.find_path_config(ctx.sema.is_nightly(target_module.krate())); + let cfg = ctx.config.find_path_config( + ctx.sema.is_nightly(target_module.krate(ctx.sema.db)), + ); let path = ref_module .find_use_path( ctx.sema.db, diff --git a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs index 156286d564..d64e9ceda2 100644 --- a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs +++ b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs @@ -1,11 +1,8 @@ -use hir::{ - Name, - sym::{self}, -}; +use hir::{Name, sym}; use ide_db::{famous_defs::FamousDefs, syntax_helpers::suggest_name}; use syntax::{ AstNode, - ast::{self, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory}, + ast::{self, HasAttrs, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory}, syntax_editor::Position, }; @@ -82,6 +79,18 @@ pub(crate) fn convert_for_loop_to_while_let( Some(iterable), ); let indent = IndentLevel::from_node(for_loop.syntax()); + + if let Some(label) = for_loop.label() { + let label = label.syntax().clone_for_update(); + editor.insert(Position::before(for_loop.syntax()), make.whitespace(" ")); + editor.insert(Position::before(for_loop.syntax()), label); + } + crate::utils::insert_attributes( + for_loop.syntax(), + &mut editor, + for_loop.attrs().map(|it| it.clone_for_update()), + ); + editor.insert( Position::before(for_loop.syntax()), make::tokens::whitespace(format!("\n{indent}").as_str()), @@ -150,7 +159,7 @@ fn impls_core_iter(sema: &hir::Semantics<'_, ide_db::RootDatabase>, iterable: &a let module = sema.scope(iterable.syntax())?.module(); - let krate = module.krate(); + let krate = module.krate(sema.db); let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; cov_mark::hit!(test_already_impls_iterator); Some(it_typ.impls_trait(sema.db, iter_trait, &[])) @@ -187,6 +196,56 @@ fn main() { } #[test] + fn each_to_for_with_label() { + check_assist( + convert_for_loop_to_while_let, + r" +fn main() { + let mut x = vec![1, 2, 3]; + 'a: for $0v in x { + v *= 2; + break 'a; + }; +}", + r" +fn main() { + let mut x = vec![1, 2, 3]; + let mut tmp = x.into_iter(); + 'a: while let Some(v) = tmp.next() { + v *= 2; + break 'a; + }; +}", + ) + } + + #[test] + fn each_to_for_with_attributes() { + check_assist( + convert_for_loop_to_while_let, + r" +fn main() { + let mut x = vec![1, 2, 3]; + #[allow(unused)] + #[deny(unsafe_code)] + for $0v in x { + v *= 2; + }; +}", + r" +fn main() { + let mut x = vec![1, 2, 3]; + let mut tmp = x.into_iter(); + #[allow(unused)] + #[deny(unsafe_code)] + while let Some(v) = tmp.next() { + v *= 2; + }; +}", + ) + } + + #[test] fn each_to_for_for_in_range() { check_assist( convert_for_loop_to_while_let, diff --git a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 7d8b763d8b..6a74d21451 100644 --- a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -64,7 +64,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> let tail_expr = from_fn.body()?.tail_expr()?; if resolve_target_trait(&ctx.sema, &impl_)? - != FamousDefs(&ctx.sema, module.krate()).core_convert_From()? + != FamousDefs(&ctx.sema, module.krate(ctx.db())).core_convert_From()? { return None; } diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs index 8f02d28b82..e330102423 100644 --- a/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -39,11 +39,11 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - let module = ctx.sema.scope(impl_.syntax())?.module(); let trait_ = resolve_target_trait(&ctx.sema, &impl_)?; - if trait_ != FamousDefs(&ctx.sema, module.krate()).core_convert_Into()? { + if trait_ != FamousDefs(&ctx.sema, module.krate(ctx.db())).core_convert_Into()? { return None; } - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); let src_type_path = { let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?; @@ -53,7 +53,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - }; mod_path_to_ast( &module.find_path(ctx.db(), src_type_def, cfg)?, - module.krate().edition(ctx.db()), + module.krate(ctx.db()).edition(ctx.db()), ) }; diff --git a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs index c8a244b213..2eea4f71ed 100644 --- a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs @@ -3,7 +3,7 @@ use ide_db::famous_defs::FamousDefs; use stdx::format_to; use syntax::{ AstNode, - ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, make}, + ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, syntax_factory::SyntaxFactory}, }; use crate::{AssistContext, AssistId, Assists}; @@ -57,18 +57,22 @@ pub(crate) fn convert_iter_for_each_to_for( "Replace this `Iterator::for_each` with a for loop", range, |builder| { + let make = SyntaxFactory::with_mappings(); let indent = stmt.as_ref().map_or_else(|| method.indent_level(), ast::ExprStmt::indent_level); let block = match body { - ast::Expr::BlockExpr(block) => block, - _ => make::block_expr(Vec::new(), Some(body)), - } - .clone_for_update(); + ast::Expr::BlockExpr(block) => block.clone_for_update(), + _ => make.block_expr(Vec::new(), Some(body)), + }; block.reindent_to(indent); - let expr_for_loop = make::expr_for_loop(param, receiver, block); - builder.replace(range, expr_for_loop.to_string()) + let expr_for_loop = make.expr_for_loop(param, receiver, block); + + let target_node = stmt.as_ref().map_or(method.syntax(), AstNode::syntax); + let mut editor = builder.make_editor(target_node); + editor.replace(target_node, expr_for_loop.syntax()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } @@ -186,7 +190,7 @@ fn impls_core_iter(sema: &hir::Semantics<'_, ide_db::RootDatabase>, iterable: &a let module = sema.scope(iterable.syntax())?.module(); - let krate = module.krate(); + let krate = module.krate(sema.db); let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; cov_mark::hit!(test_already_impls_iterator); Some(it_typ.impls_trait(sema.db, iter_trait, &[])) @@ -214,7 +218,7 @@ fn validate_method_call_expr( let it_type = sema.type_of_expr(&receiver)?.adjusted(); let module = sema.scope(receiver.syntax())?.module(); - let krate = module.krate(); + let krate = module.krate(ctx.db()); let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; it_type.impls_trait(sema.db, iter_trait, &[]).then_some((expr, receiver)) diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 9876e14203..0e5e6185d0 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -199,7 +199,8 @@ fn augment_references_with_imports( { visited_modules.insert(ref_module); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(ref_module.krate())); + let cfg = + ctx.config.find_path_config(ctx.sema.is_nightly(ref_module.krate(ctx.sema.db))); let import_scope = ImportScope::find_insert_use_container(new_name.syntax(), &ctx.sema); let path = ref_module @@ -211,7 +212,10 @@ fn augment_references_with_imports( ) .map(|mod_path| { make::path_concat( - mod_path_to_ast(&mod_path, target_module.krate().edition(ctx.db())), + mod_path_to_ast( + &mod_path, + target_module.krate(ctx.db()).edition(ctx.db()), + ), make::path_from_text(struct_name), ) }); diff --git a/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/crates/ide-assists/src/handlers/convert_while_to_loop.rs index dbe3ee0ed6..9fd8b4b315 100644 --- a/crates/ide-assists/src/handlers/convert_while_to_loop.rs +++ b/crates/ide-assists/src/handlers/convert_while_to_loop.rs @@ -1,6 +1,5 @@ use std::iter; -use either::Either; use ide_db::syntax_helpers::node_ext::is_pattern_cond; use syntax::{ AstNode, T, @@ -9,6 +8,7 @@ use syntax::{ edit::{AstNodeEdit, IndentLevel}, make, }, + syntax_editor::{Element, Position}, }; use crate::{ @@ -44,43 +44,53 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?; let while_body = while_expr.loop_body()?; let while_cond = while_expr.condition()?; + let l_curly = while_body.stmt_list()?.l_curly_token()?; let target = while_expr.syntax().text_range(); acc.add( AssistId::refactor_rewrite("convert_while_to_loop"), "Convert while to loop", target, - |edit| { + |builder| { + let mut edit = builder.make_editor(while_expr.syntax()); let while_indent_level = IndentLevel::from_node(while_expr.syntax()); let break_block = make::block_expr( iter::once(make::expr_stmt(make::expr_break(None, None)).into()), None, ) - .indent(while_indent_level); - let block_expr = if is_pattern_cond(while_cond.clone()) { - let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into())); + .indent(IndentLevel(1)); + + edit.replace_all( + while_kw.syntax_element()..=while_cond.syntax().syntax_element(), + vec![make::token(T![loop]).syntax_element()], + ); + + if is_pattern_cond(while_cond.clone()) { + let then_branch = while_body.reset_indent().indent(IndentLevel(1)); + let if_expr = make::expr_if(while_cond, then_branch, Some(break_block.into())); let stmts = iter::once(make::expr_stmt(if_expr.into()).into()); - make::block_expr(stmts, None) + let block_expr = make::block_expr(stmts, None); + edit.replace(while_body.syntax(), block_expr.indent(while_indent_level).syntax()); } else { let if_cond = invert_boolean_expression_legacy(while_cond); - let if_expr = make::expr_if(if_cond, break_block, None).syntax().clone().into(); - let elements = while_body.stmt_list().map_or_else( - || Either::Left(iter::empty()), - |stmts| { - Either::Right(stmts.syntax().children_with_tokens().filter(|node_or_tok| { - // Filter out the trailing expr - !node_or_tok - .as_node() - .is_some_and(|node| ast::Expr::can_cast(node.kind())) - })) - }, + let if_expr = make::expr_if(if_cond, break_block, None).indent(while_indent_level); + if !while_body.syntax().text().contains_char('\n') { + edit.insert( + Position::after(&l_curly), + make::tokens::whitespace(&format!("\n{while_indent_level}")), + ); + } + edit.insert_all( + Position::after(&l_curly), + vec![ + make::tokens::whitespace(&format!("\n{}", while_indent_level + 1)).into(), + if_expr.syntax().syntax_element(), + ], ); - make::hacky_block_expr(iter::once(if_expr).chain(elements), while_body.tail_expr()) }; - let replacement = make::expr_loop(block_expr.indent(while_indent_level)); - edit.replace(target, replacement.syntax().text()) + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } @@ -116,6 +126,110 @@ fn main() { } #[test] + fn convert_with_label() { + check_assist( + convert_while_to_loop, + r#" +fn main() { + 'x: while$0 cond { + foo(); + break 'x + } +} +"#, + r#" +fn main() { + 'x: loop { + if !cond { + break; + } + foo(); + break 'x + } +} +"#, + ); + + check_assist( + convert_while_to_loop, + r#" +fn main() { + 'x: while$0 let Some(x) = cond { + foo(); + break 'x + } +} +"#, + r#" +fn main() { + 'x: loop { + if let Some(x) = cond { + foo(); + break 'x + } else { + break; + } + } +} +"#, + ); + } + + #[test] + fn convert_with_attributes() { + check_assist( + convert_while_to_loop, + r#" +fn main() { + #[allow(unused)] + while$0 cond { + foo(); + break 'x + } +} +"#, + r#" +fn main() { + #[allow(unused)] + loop { + if !cond { + break; + } + foo(); + break 'x + } +} +"#, + ); + + check_assist( + convert_while_to_loop, + r#" +fn main() { + #[allow(unused)] + #[deny(unsafe_code)] + while$0 let Some(x) = cond { + foo(); + } +} +"#, + r#" +fn main() { + #[allow(unused)] + #[deny(unsafe_code)] + loop { + if let Some(x) = cond { + foo(); + } else { + break; + } + } +} +"#, + ); + } + + #[test] fn convert_busy_wait() { check_assist( convert_while_to_loop, @@ -186,6 +300,76 @@ fn main() { } #[test] + fn indentation() { + check_assist( + convert_while_to_loop, + r#" +fn main() { + { + { + while$0 cond { + foo( + "xxx", + ); + } + } + } +} +"#, + r#" +fn main() { + { + { + loop { + if !cond { + break; + } + foo( + "xxx", + ); + } + } + } +} +"#, + ); + + check_assist( + convert_while_to_loop, + r#" +fn main() { + { + { + while$0 let Some(_) = foo() { + bar( + "xxx", + ); + } + } + } +} +"#, + r#" +fn main() { + { + { + loop { + if let Some(_) = foo() { + bar( + "xxx", + ); + } else { + break; + } + } + } + } +} +"#, + ); + } + + #[test] fn ignore_cursor_in_body() { check_assist_not_applicable( convert_while_to_loop, diff --git a/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 46f210804d..bb5d112210 100644 --- a/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -88,13 +88,14 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None }; let module = ctx.sema.scope(ident_pat.syntax())?.module(); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db()))); let struct_def = hir::ModuleDef::from(struct_type); let kind = struct_type.kind(ctx.db()); let struct_def_path = module.find_path(ctx.db(), struct_def, cfg)?; let is_non_exhaustive = struct_def.attrs(ctx.db())?.is_non_exhaustive(); - let is_foreign_crate = struct_def.module(ctx.db()).is_some_and(|m| m.krate() != module.krate()); + let is_foreign_crate = + struct_def.module(ctx.db()).is_some_and(|m| m.krate(ctx.db()) != module.krate(ctx.db())); let fields = struct_type.fields(ctx.db()); let n_fields = fields.len(); @@ -148,7 +149,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str names_in_scope, need_record_field_name, is_ref, - edition: module.krate().edition(ctx.db()), + edition: module.krate(ctx.db()).edition(ctx.db()), }) } diff --git a/crates/ide-assists/src/handlers/expand_glob_import.rs b/crates/ide-assists/src/handlers/expand_glob_import.rs index 4b6d0b3785..7eca4d3f2a 100644 --- a/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -152,8 +152,10 @@ fn build_expanded_import( (false, current_module) } else { match get_export_visibility_kind(&use_item) { - VisibilityKind::Pub => (true, current_module.krate().root_module()), - VisibilityKind::PubCrate => (false, current_module.krate().root_module()), + VisibilityKind::Pub => (true, current_module.krate(ctx.db()).root_module(ctx.db())), + VisibilityKind::PubCrate => { + (false, current_module.krate(ctx.db()).root_module(ctx.db())) + } _ => (false, current_module), } }; @@ -167,7 +169,7 @@ fn build_expanded_import( let names_to_import = find_names_to_import(filtered_defs, imported_defs); let expanded = make::use_tree_list(names_to_import.iter().map(|n| { let path = make::ext::ident_path( - &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(), + &n.display(ctx.db(), current_module.krate(ctx.db()).edition(ctx.db())).to_string(), ); make::use_tree(path, None, None, false) })) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 44d020a1b4..4b7314be46 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -206,10 +206,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op { let scope = builder.make_import_scope_mut(scope); let control_flow_enum = - FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow(); + FamousDefs(&ctx.sema, module.krate(ctx.db())).core_ops_ControlFlow(); if let Some(control_flow_enum) = control_flow_enum { - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = + ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); let mod_path = module.find_use_path( ctx.sema.db, ModuleDef::from(control_flow_enum), diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 2cec3296c8..386652a422 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -400,7 +400,8 @@ fn process_references( let segment = builder.make_mut(segment); let scope_node = builder.make_syntax_mut(scope_node); if !visited_modules.contains(&module) { - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = + ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); let mod_path = module.find_use_path( ctx.sema.db, *enum_module_def, diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs index 55de537deb..0fd8057a39 100644 --- a/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/crates/ide-assists/src/handlers/fix_visibility.rs @@ -59,7 +59,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) let (vis_owner, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?; - let missing_visibility = if current_module.krate() == target_module.krate() { + let missing_visibility = if current_module.krate(ctx.db()) == target_module.krate(ctx.db()) { make::visibility_pub_crate() } else { make::visibility_pub() @@ -70,7 +70,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) Some(name) => { format!( "Change visibility of {} to {missing_visibility}", - name.display(ctx.db(), current_module.krate().edition(ctx.db())) + name.display(ctx.db(), current_module.krate(ctx.db()).edition(ctx.db())) ) } }; diff --git a/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs index 056edb00b6..b4a17c376a 100644 --- a/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs @@ -75,7 +75,7 @@ fn existing_default_impl( ) -> Option<()> { let variant = sema.to_def(variant)?; let enum_ = variant.parent_enum(sema.db); - let krate = enum_.module(sema.db).krate(); + let krate = enum_.module(sema.db).krate(sema.db); let default_trait = FamousDefs(sema, krate).core_default_Default()?; let enum_type = enum_.ty(sema.db); diff --git a/crates/ide-assists/src/handlers/generate_default_from_new.rs b/crates/ide-assists/src/handlers/generate_default_from_new.rs index 47233fb399..48400d436a 100644 --- a/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -137,7 +137,7 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool { }; let ty = impl_def.self_ty(db); - let krate = impl_def.module(db).krate(); + let krate = impl_def.module(db).krate(ctx.db()); let default = FamousDefs(&ctx.sema, krate).core_default_Default(); let default_trait = match default { Some(value) => value, diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index b2e791abf7..c1eb1a74ec 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -57,7 +57,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let strukt = ctx.find_node_at_offset::<ast::Struct>()?; let strukt_name = strukt.name()?; let current_module = ctx.sema.scope(strukt.syntax())?.module(); - let current_edition = current_module.krate().edition(ctx.db()); + let current_edition = current_module.krate(ctx.db()).edition(ctx.db()); let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() { Some(field) => { diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs index e87dde5b8e..921f04f2a5 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -14,15 +14,15 @@ use ide_db::{ }; use itertools::Itertools; use syntax::{ - AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr, + AstNode, Edition, SmolStr, SyntaxElement, SyntaxKind, ToSmolStr, ast::{ self, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path, WherePred, edit::{self, AstNodeEdit}, - make, + syntax_factory::SyntaxFactory, }, - ted::{self, Position}, + syntax_editor::SyntaxEditor, }; // Assist: generate_delegate_trait @@ -124,7 +124,7 @@ impl Field { let db = ctx.sema.db; let module = ctx.sema.file_to_module_def(ctx.vfs_file_id())?; - let edition = module.krate().edition(ctx.db()); + let edition = module.krate(ctx.db()).edition(ctx.db()); let (name, range, ty) = match f { Either::Left(f) => { @@ -169,10 +169,15 @@ enum Delegee { } impl Delegee { + fn trait_(&self) -> &hir::Trait { + match self { + Delegee::Bound(it) | Delegee::Impls(it, _) => it, + } + } + fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String { let mut s = String::new(); - - let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self; + let it = self.trait_(); for m in it.module(db).path_to_root(db).iter().rev() { if let Some(name) = m.name(db) { @@ -201,15 +206,12 @@ impl Struct { let db = ctx.db(); for (index, delegee) in field.impls.iter().enumerate() { - let trait_ = match delegee { - Delegee::Bound(b) => b, - Delegee::Impls(i, _) => i, - }; + let trait_ = delegee.trait_(); // Skip trait that has `Self` type, which cannot be delegated // // See [`test_self_ty`] - if has_self_type(*trait_, ctx).is_some() { + if has_self_type(*trait_, ctx) { continue; } @@ -254,9 +256,10 @@ fn generate_impl( delegee: &Delegee, edition: Edition, ) -> Option<ast::Impl> { + let make = SyntaxFactory::without_mappings(); let db = ctx.db(); let ast_strukt = &strukt.strukt; - let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string())); + let strukt_ty = make.ty_path(make.ident_path(&strukt.name.to_string())).into(); let strukt_params = ast_strukt.generic_param_list(); match delegee { @@ -264,7 +267,7 @@ fn generate_impl( let bound_def = ctx.sema.source(delegee.to_owned())?.value; let bound_params = bound_def.generic_param_list(); - let delegate = make::impl_trait( + let delegate = make.impl_trait( None, delegee.is_unsafe(db), bound_params.clone(), @@ -272,33 +275,28 @@ fn generate_impl( strukt_params.clone(), strukt_params.map(|params| params.to_generic_args()), delegee.is_auto(db), - make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()), + make.ty(&delegee.name(db).display_no_db(edition).to_smolstr()), strukt_ty, bound_def.where_clause(), ast_strukt.where_clause(), None, - ) - .clone_for_update(); + ); // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths let qualified_path_type = - make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); + make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); - let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); - if let Some(ai) = bound_def.assoc_item_list() { + // Collect assoc items + let assoc_items: Option<Vec<ast::AssocItem>> = bound_def.assoc_item_list().map(|ai| { ai.assoc_items() .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) - .for_each(|item| { - let assoc = process_assoc_item( - item.clone_for_update(), - qualified_path_type.clone(), - field_name, - ); - if let Some(assoc) = assoc { - delegate_assoc_items.add_item(assoc); - } - }); - }; + .filter_map(|item| { + process_assoc_item(item, qualified_path_type.clone(), field_name) + }) + .collect() + }); + + let delegate = finalize_delegate(&make, &delegate, assoc_items, false)?; let target_scope = ctx.sema.scope(strukt.strukt.syntax())?; let source_scope = ctx.sema.scope(bound_def.syntax())?; @@ -324,7 +322,7 @@ fn generate_impl( .and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args)); (field_ty, where_clause) } - None => (field_ty.clone_for_update(), None), + None => (field_ty.clone(), None), }; // 2) Handle instantiated generics in `field_ty`. @@ -347,38 +345,38 @@ fn generate_impl( ); // 2.2) Generate generic args applied on impl. - let transform_args = generate_args_for_impl( + let (transform_args, trait_gen_params) = generate_args_for_impl( old_impl_params, &old_impl.self_ty()?, &field_ty, - &trait_gen_params, + trait_gen_params, &old_impl_trait_args, ); // 2.3) Instantiate generics with `transform_impl`, this step also // remove unused params. - let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| { - let trait_args = &mut trait_args.clone_for_update(); - if let Some(new_args) = transform_impl( - ctx, - ast_strukt, - &old_impl, - &transform_args, - trait_args.clone_subtree(), - ) { - *trait_args = new_args.clone_subtree(); - Some(new_args) - } else { - None - } - }); + let trait_gen_args = + old_impl.trait_()?.generic_arg_list().and_then(|mut trait_args| { + let trait_args = &mut trait_args; + if let Some(new_args) = transform_impl( + ctx, + ast_strukt, + &old_impl, + &transform_args, + trait_args.clone_subtree(), + ) { + *trait_args = new_args.clone_subtree(); + Some(new_args) + } else { + None + } + }); let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args()); - let path_type = - make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update(); + let path_type = make.ty(&trait_.name(db).display_no_db(edition).to_smolstr()); let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?; // 3) Generate delegate trait impl - let delegate = make::impl_trait( + let delegate = make.impl_trait( None, trait_.is_unsafe(db), trait_gen_params, @@ -388,34 +386,27 @@ fn generate_impl( trait_.is_auto(db), path_type, strukt_ty, - old_impl.where_clause().map(|wc| wc.clone_for_update()), + old_impl.where_clause(), ty_where_clause, None, - ) - .clone_for_update(); + ); // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths let qualified_path_type = - make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); - - // 4) Transform associated items in delegte trait impl - let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); - for item in old_impl - .get_or_create_assoc_item_list() - .assoc_items() - .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) - { - let item = item.clone_for_update(); - let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?; - - let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?; - delegate_assoc_items.add_item(assoc); - } + make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); - // 5) Remove useless where clauses - if let Some(wc) = delegate.where_clause() { - remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc); - } - Some(delegate) + // 4) Transform associated items in delegate trait impl + let assoc_items: Option<Vec<ast::AssocItem>> = old_impl.assoc_item_list().map(|ail| { + ail.assoc_items() + .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) + .filter_map(|item| { + let item = + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?; + process_assoc_item(item, qualified_path_type.clone(), field_name) + }) + .collect() + }); + + finalize_delegate(&make, &delegate, assoc_items, true) } } } @@ -446,6 +437,35 @@ fn transform_impl<N: ast::AstNode>( N::cast(transform.apply(syntax.syntax())) } +/// Extracts the name from a generic parameter. +fn generic_param_name(param: &ast::GenericParam) -> Option<String> { + match param { + ast::GenericParam::TypeParam(t) => t.name().map(|n| n.to_string()), + ast::GenericParam::ConstParam(c) => c.name().map(|n| n.to_string()), + ast::GenericParam::LifetimeParam(l) => l.lifetime().map(|lt| lt.to_string()), + } +} + +/// Filters generic params, keeping only those whose names are not in `names_to_remove`. +fn filter_generic_params( + gpl: ast::GenericParamList, + names_to_remove: &FxHashSet<String>, +) -> Option<ast::GenericParamList> { + let remaining_params: Vec<_> = gpl + .generic_params() + .filter(|param| { + generic_param_name(param).is_none_or(|name| !names_to_remove.contains(&name)) + }) + .collect(); + + if remaining_params.is_empty() { + None + } else { + let make = SyntaxFactory::without_mappings(); + Some(make.generic_param_list(remaining_params)) + } +} + fn remove_instantiated_params( self_ty: &ast::Type, old_impl_params: Option<GenericParamList>, @@ -454,10 +474,8 @@ fn remove_instantiated_params( match self_ty { ast::Type::PathType(path_type) => { old_impl_params.and_then(|gpl| { - // Remove generic parameters in field_ty (which is instantiated). - let new_gpl = gpl.clone_for_update(); - - path_type + // Collect generic args that should be removed (instantiated params) + let args_to_remove: FxHashSet<String> = path_type .path()? .segments() .filter_map(|seg| seg.generic_arg_list()) @@ -466,16 +484,25 @@ fn remove_instantiated_params( // it shouldn't be removed now, which will be instantiated in // later `path_transform` .filter(|arg| !old_trait_args.contains(&arg.to_string())) - .for_each(|arg| new_gpl.remove_generic_arg(&arg)); - (new_gpl.generic_params().count() > 0).then_some(new_gpl) + .map(|arg| arg.to_string()) + .collect(); + + filter_generic_params(gpl, &args_to_remove) }) } _ => old_impl_params, } } -fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: ast::WhereClause) { - let live_generics = [trait_ty, self_ty] +fn remove_useless_where_clauses(editor: &mut SyntaxEditor, delegate: &ast::Impl) { + let Some(wc) = delegate.where_clause() else { + return; + }; + let (Some(trait_ty), Some(self_ty)) = (delegate.trait_(), delegate.self_ty()) else { + return; + }; + + let live_generics = [&trait_ty, &self_ty] .into_iter() .flat_map(|ty| ty.generic_arg_list()) .flat_map(|gal| gal.generic_args()) @@ -484,34 +511,76 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a // Keep where-clauses that have generics after substitution, and remove the // rest. - let has_live_generics = |pred: &WherePred| { + let has_no_live_generics = |pred: &WherePred| { pred.syntax() .descendants_with_tokens() .filter_map(|e| e.into_token()) .any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string())) .not() }; - wc.predicates().filter(has_live_generics).for_each(|pred| wc.remove_predicate(pred)); - - if wc.predicates().count() == 0 { - // Remove useless whitespaces - [syntax::Direction::Prev, syntax::Direction::Next] - .into_iter() - .flat_map(|dir| { - wc.syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE) - }) - .for_each(ted::remove); - ted::insert( - ted::Position::after(wc.syntax()), - NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)), - ); - // Remove where clause - ted::remove(wc.syntax()); + let predicates_to_remove: Vec<_> = wc.predicates().filter(has_no_live_generics).collect(); + let remaining_predicates = wc.predicates().count() - predicates_to_remove.len(); + + if remaining_predicates == 0 { + // Remove the entire where clause + editor.delete(wc.syntax().clone()); + } else { + // Remove only the useless predicates + for pred in predicates_to_remove { + // Also remove the comma before or after the predicate + if let Some(previous) = pred.syntax().prev_sibling() { + // Remove from after previous sibling to predicate (inclusive) + if let Some(start) = previous.next_sibling_or_token() { + let end: SyntaxElement = pred.syntax().clone().into(); + editor.delete_all(start..=end); + } + } else if let Some(next) = pred.syntax().next_sibling() { + // Remove from predicate to before next sibling (exclusive) + if let Some(end) = next.prev_sibling_or_token() { + let start: SyntaxElement = pred.syntax().clone().into(); + editor.delete_all(start..=end); + } + } else { + editor.delete(pred.syntax().clone()); + } + } + } +} + +/// Finalize the delegate impl by: +/// 1. Replacing the assoc_item_list with new items (if any) +/// 2. Removing useless where clauses +fn finalize_delegate( + make: &SyntaxFactory, + delegate: &ast::Impl, + assoc_items: Option<Vec<ast::AssocItem>>, + remove_where_clauses: bool, +) -> Option<ast::Impl> { + let has_items = assoc_items.as_ref().is_some_and(|items| !items.is_empty()); + + if !has_items && !remove_where_clauses { + return Some(delegate.clone()); } + + let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree()); + + // 1. Replace assoc_item_list if we have new items + if let Some(items) = assoc_items + && !items.is_empty() + { + let new_assoc_item_list = make.assoc_item_list(items); + if let Some(old_list) = delegate.assoc_item_list() { + editor.replace(old_list.syntax(), new_assoc_item_list.syntax()); + } + } + + // 2. Remove useless where clauses + if remove_where_clauses { + remove_useless_where_clauses(&mut editor, delegate); + } + + ast::Impl::cast(editor.finish().new_root().clone()) } // Generate generic args that should be apply to current impl. @@ -524,10 +593,13 @@ fn generate_args_for_impl( old_impl_gpl: Option<GenericParamList>, self_ty: &ast::Type, field_ty: &ast::Type, - trait_params: &Option<GenericParamList>, + trait_params: Option<GenericParamList>, old_trait_args: &FxHashSet<String>, -) -> Option<ast::GenericArgList> { - let old_impl_args = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args())?; +) -> (Option<ast::GenericArgList>, Option<GenericParamList>) { + let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else { + return (None, trait_params); + }; + // Create pairs of the args of `self_ty` and corresponding `field_ty` to // form the substitution list let mut arg_substs = FxHashMap::default(); @@ -542,6 +614,8 @@ fn generate_args_for_impl( } } + let mut params_to_remove = FxHashSet::default(); + let args = old_impl_args .map(|old_arg| { arg_substs.get(&old_arg.to_string()).map_or_else( @@ -549,14 +623,18 @@ fn generate_args_for_impl( |replace_with| { // The old_arg will be replaced, so it becomes redundant if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) { - trait_params.as_ref().unwrap().remove_generic_arg(&old_arg) + params_to_remove.insert(old_arg.to_string()); } replace_with.clone() }, ) }) .collect_vec(); - args.is_empty().not().then(|| make::generic_arg_list(args)) + + let make = SyntaxFactory::without_mappings(); + let result = args.is_empty().not().then(|| make.generic_arg_list(args, false)); + let trait_params = trait_params.and_then(|gpl| filter_generic_params(gpl, ¶ms_to_remove)); + (result, trait_params) } fn rename_strukt_args<N>( @@ -570,41 +648,37 @@ where { let hir_strukt = ctx.sema.to_struct_def(strukt)?; let hir_adt = hir::Adt::from(hir_strukt); - - let item = item.clone_for_update(); let scope = ctx.sema.scope(item.syntax())?; let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone()); N::cast(transform.apply(item.syntax())) } -fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> { - let trait_source = ctx.sema.source(trait_)?.value; - trait_source - .syntax() - .descendants_with_tokens() - .filter_map(|e| e.into_token()) - .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW) - .map(|_| ()) +fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> bool { + ctx.sema + .source(trait_) + .and_then(|src| { + src.value + .syntax() + .descendants_with_tokens() + .filter_map(|e| e.into_token()) + .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW) + }) + .is_some() } fn resolve_name_conflicts( strukt_params: Option<ast::GenericParamList>, old_impl_params: &Option<ast::GenericParamList>, ) -> Option<ast::GenericParamList> { + let make = SyntaxFactory::without_mappings(); match (strukt_params, old_impl_params) { (Some(old_strukt_params), Some(old_impl_params)) => { - let params = make::generic_param_list(std::iter::empty()).clone_for_update(); + let mut new_params: Vec<ast::GenericParam> = Vec::new(); for old_strukt_param in old_strukt_params.generic_params() { // Get old name from `strukt` - let name = SmolStr::from(match &old_strukt_param { - ast::GenericParam::ConstParam(c) => c.name()?.to_string(), - ast::GenericParam::LifetimeParam(l) => { - l.lifetime()?.lifetime_ident_token()?.to_string() - } - ast::GenericParam::TypeParam(t) => t.name()?.to_string(), - }); + let name = SmolStr::from(generic_param_name(&old_strukt_param)?); // The new name cannot be conflicted with generics in trait, and the renamed names. let param_list_to_names = |param_list: &GenericParamList| { @@ -613,8 +687,9 @@ fn resolve_name_conflicts( p => Some(p.to_string()), }) }; + let new_params_list = make.generic_param_list(new_params.clone()); let existing_names = param_list_to_names(old_impl_params) - .chain(param_list_to_names(¶ms)) + .chain(param_list_to_names(&new_params_list)) .collect_vec(); let mut name_generator = suggest_name::NameGenerator::new_with_names( existing_names.iter().map(|s| s.as_str()), @@ -623,25 +698,21 @@ fn resolve_name_conflicts( match old_strukt_param { ast::GenericParam::ConstParam(c) => { if let Some(const_ty) = c.ty() { - let const_param = make::const_param(make::name(&name), const_ty); - params.add_generic_param(ast::GenericParam::ConstParam( - const_param.clone_for_update(), - )); + let const_param = make.const_param(make.name(&name), const_ty); + new_params.push(ast::GenericParam::ConstParam(const_param)); } } p @ ast::GenericParam::LifetimeParam(_) => { - params.add_generic_param(p.clone_for_update()); + new_params.push(p.clone_for_update()); } ast::GenericParam::TypeParam(t) => { let type_bounds = t.type_bound_list(); - let type_param = make::type_param(make::name(&name), type_bounds); - params.add_generic_param(ast::GenericParam::TypeParam( - type_param.clone_for_update(), - )); + let type_param = make.type_param(make.name(&name), type_bounds); + new_params.push(ast::GenericParam::TypeParam(type_param)); } } } - Some(params) + Some(make.generic_param_list(new_params)) } (Some(old_strukt_gpl), None) => Some(old_strukt_gpl), _ => None, @@ -666,7 +737,8 @@ fn process_assoc_item( } fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> { - let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); + let make = SyntaxFactory::without_mappings(); + let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str()); // We want rhs of the const assignment to be a qualified path // The general case for const assignment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`) @@ -674,15 +746,14 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option // <Base as Trait<GenArgs>>::ConstName; // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it. // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap()); - let qualified_path = qualified_path(qual_path_ty, path_expr_segment); - let inner = make::item_const( + let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}")); + let inner = make.item_const( item.attrs(), item.visibility(), item.name()?, item.ty()?, - make::expr_path(qualified_path), - ) - .clone_for_update(); + make.expr_path(qualified_path), + ); Some(AssocItem::Const(inner)) } @@ -692,59 +763,46 @@ fn func_assoc_item( qual_path_ty: Path, base_name: &str, ) -> Option<AssocItem> { - let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); - let qualified_path = qualified_path(qual_path_ty, path_expr_segment); + let make = SyntaxFactory::without_mappings(); + let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str()); + let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}")); let call = match item.param_list() { // Methods and funcs should be handled separately. // We ask if the func has a `self` param. Some(l) => match l.self_param() { Some(slf) => { - let mut self_kw = make::expr_path(make::path_from_text("self")); - self_kw = make::expr_field(self_kw, base_name); + let self_kw = make.expr_path(make.path_from_text("self")); + let self_kw = make.expr_field(self_kw, base_name).into(); let tail_expr_self = match slf.kind() { ast::SelfParamKind::Owned => self_kw, - ast::SelfParamKind::Ref => make::expr_ref(self_kw, false), - ast::SelfParamKind::MutRef => make::expr_ref(self_kw, true), + ast::SelfParamKind::Ref => make.expr_ref(self_kw, false), + ast::SelfParamKind::MutRef => make.expr_ref(self_kw, true), }; - let param_count = l.params().count(); - let args = convert_param_list_to_arg_list(l).clone_for_update(); - let pos_after_l_paren = Position::after(args.l_paren_token()?); - if param_count > 0 { - // Add SelfParam and a TOKEN::COMMA - ted::insert_all_raw( - pos_after_l_paren, - vec![ - NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), - NodeOrToken::Token(make::token(SyntaxKind::COMMA)), - NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)), - ], - ); - } else { - // Add SelfParam only - ted::insert_raw( - pos_after_l_paren, - NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), - ); - } + // Build argument list with self expression prepended + let other_args = convert_param_list_to_arg_list(l); + let all_args: Vec<ast::Expr> = + std::iter::once(tail_expr_self).chain(other_args.args()).collect(); + let args = make.arg_list(all_args); - make::expr_call(make::expr_path(qualified_path), args) - } - None => { - make::expr_call(make::expr_path(qualified_path), convert_param_list_to_arg_list(l)) + make.expr_call(make.expr_path(qualified_path), args).into() } + None => make + .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l)) + .into(), }, - None => make::expr_call( - make::expr_path(qualified_path), - convert_param_list_to_arg_list(make::param_list(None, Vec::new())), - ), - } - .clone_for_update(); + None => make + .expr_call( + make.expr_path(qualified_path), + convert_param_list_to_arg_list(make.param_list(None, Vec::new())), + ) + .into(), + }; - let body = make::block_expr(vec![], Some(call.into())).clone_for_update(); - let func = make::fn_( + let body = make.block_expr(vec![], Some(call)); + let func = make.fn_( item.attrs(), item.visibility(), item.name()?, @@ -757,35 +815,32 @@ fn func_assoc_item( item.const_token().is_some(), item.unsafe_token().is_some(), item.gen_token().is_some(), - ) - .clone_for_update(); + ); Some(AssocItem::Fn(func.indent(edit::IndentLevel(1)))) } fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> { - let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); - let qualified_path = qualified_path(qual_path_ty, path_expr_segment); - let ty = make::ty_path(qualified_path); + let make = SyntaxFactory::without_mappings(); + let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str()); + let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}")); + let ty = make.ty_path(qualified_path).into(); let ident = item.name()?.to_string(); - let alias = make::ty_alias( - item.attrs(), - ident.as_str(), - item.generic_param_list(), - None, - item.where_clause(), - Some((ty, None)), - ) - .indent(edit::IndentLevel(1)); + let alias = make + .ty_alias( + item.attrs(), + ident.as_str(), + item.generic_param_list(), + None, + item.where_clause(), + Some((ty, None)), + ) + .indent(edit::IndentLevel(1)); Some(AssocItem::TypeAlias(alias)) } -fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path { - make::path_from_text(&format!("{qual_path_ty}::{path_expr_seg}")) -} - #[cfg(test)] mod test { diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs index b02e3e435c..494c87e6d1 100644 --- a/crates/ide-assists/src/handlers/generate_deref.rs +++ b/crates/ide-assists/src/handlers/generate_deref.rs @@ -57,8 +57,8 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( }; let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); - let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db()))); + let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate(ctx.db()))?; let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?; let field_type = field.ty()?; @@ -77,7 +77,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( field_name.syntax(), deref_type_to_generate, trait_path, - module.krate().edition(ctx.db()), + module.krate(ctx.db()).edition(ctx.db()), ) }, ) @@ -99,8 +99,8 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() }; let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); - let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); + let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate(ctx.db()))?; let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?; let field_type = field.ty()?; @@ -118,7 +118,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() field_list_index, deref_type_to_generate, trait_path, - module.krate().edition(ctx.db()), + module.krate(ctx.db()).edition(ctx.db()), ) }, ) @@ -163,7 +163,7 @@ fn existing_deref_impl( strukt: &ast::Struct, ) -> Option<DerefType> { let strukt = sema.to_def(strukt)?; - let krate = strukt.module(sema.db).krate(); + let krate = strukt.module(sema.db).krate(sema.db); let deref_trait = FamousDefs(sema, krate).core_ops_Deref()?; let deref_mut_trait = FamousDefs(sema, krate).core_ops_DerefMut()?; diff --git a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs index 0b7eca2290..7fd94b4bed 100644 --- a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs +++ b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -270,6 +270,22 @@ fn foo<A: Trait, B: Trait>(a: A, b: B) -> i32 { return 42; } } #[test] + fn generate_fn_alias_unnamed_complex_types() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(x: Vec<i32>) {} +"#, + r#" +type ${0:FooFn} = fn(Vec<i32>); + +fn foo(x: Vec<i32>) {} +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] fn generate_fn_alias_unnamed_self() { check_assist_by_label( generate_fn_type_alias, @@ -406,6 +422,22 @@ fn foo<A: Trait, B: Trait>(a: A, b: B) -> i32 { return 42; } } #[test] + fn generate_fn_alias_named_complex_types() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(x: Vec<i32>) {} +"#, + r#" +type ${0:FooFn} = fn(x: Vec<i32>); + +fn foo(x: Vec<i32>) {} +"#, + ParamStyle::Named.label(), + ); + } + + #[test] fn generate_fn_alias_named_self() { check_assist_by_label( generate_fn_type_alias, diff --git a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index 199c85d98d..24f271ded8 100644 --- a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -121,7 +121,7 @@ fn existing_from_impl( ) -> Option<()> { let db = sema.db; let variant = sema.to_def(variant)?; - let krate = variant.module(db).krate(); + let krate = variant.module(db).krate(db); let from_trait = FamousDefs(sema, krate).core_convert_From()?; let interner = DbInterner::new_with(db, krate.base()); use hir::next_solver::infer::DbInternerInferExt; diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index a9cf2c1bae..bd66c02b41 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -71,7 +71,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { fn_target_info(ctx, path, &call, fn_name)?; if let Some(m) = target_module - && !is_editable_crate(m.krate(), ctx.db()) + && !is_editable_crate(m.krate(ctx.db()), ctx.db()) { return None; } @@ -143,7 +143,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let adt = receiver_ty.as_adt()?; let target_module = adt.module(ctx.sema.db); - if !is_editable_crate(target_module.krate(), ctx.db()) { + if !is_editable_crate(target_module.krate(ctx.db()), ctx.db()) { return None; } @@ -241,7 +241,7 @@ impl FunctionBuilder { ) -> Option<Self> { let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?; - let target_edition = target_module.krate().edition(ctx.db()); + let target_edition = target_module.krate(ctx.db()).edition(ctx.db()); let current_module = ctx.sema.scope(call.syntax())?.module(); let visibility = calculate_necessary_visibility(current_module, target_module, ctx); @@ -311,7 +311,7 @@ impl FunctionBuilder { target_module: Module, target: GeneratedFunctionTarget, ) -> Option<Self> { - let target_edition = target_module.krate().edition(ctx.db()); + let target_edition = target_module.krate(ctx.db()).edition(ctx.db()); let current_module = ctx.sema.scope(call.syntax())?.module(); let visibility = calculate_necessary_visibility(current_module, target_module, ctx); @@ -546,7 +546,7 @@ fn assoc_fn_target_info( let current_module = ctx.sema.scope(call.syntax())?.module(); let module = adt.module(ctx.sema.db); let target_module = if current_module == module { None } else { Some(module) }; - if current_module.krate() != module.krate() { + if current_module.krate(ctx.db()) != module.krate(ctx.db()) { return None; } let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; @@ -1149,7 +1149,10 @@ fn fn_arg_type( convert_reference_type(ty.strip_references(), ctx.db(), famous_defs) .map(|conversion| { conversion - .convert_type(ctx.db(), target_module.krate().to_display_target(ctx.db())) + .convert_type( + ctx.db(), + target_module.krate(ctx.db()).to_display_target(ctx.db()), + ) .to_string() }) .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok()) @@ -1235,7 +1238,7 @@ fn calculate_necessary_visibility( let current_module = current_module.nearest_non_block_module(db); let target_module = target_module.nearest_non_block_module(db); - if target_module.krate() != current_module.krate() { + if target_module.krate(ctx.db()) != current_module.krate(ctx.db()) { Visibility::Pub } else if current_module.path_to_root(db).contains(&target_module) { Visibility::None diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index cd968b9710..4b923ab556 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -77,14 +77,16 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?)); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate())); + let cfg = ctx + .config + .find_path_config(ctx.sema.is_nightly(current_module.krate(ctx.sema.db))); let type_path = current_module.find_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, cfg, )?; - let edition = current_module.krate().edition(ctx.db()); + let edition = current_module.krate(ctx.db()).edition(ctx.db()); let expr = use_trivial_constructor( ctx.sema.db, diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index bdb42f9c1f..d3022ceda3 100644 --- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -178,7 +178,7 @@ fn make_constructors( types: &[ast::Type], ) -> Vec<Option<ast::Expr>> { let (db, sema) = (ctx.db(), &ctx.sema); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); types .iter() .map(|ty| { @@ -187,7 +187,7 @@ fn make_constructors( return Some(make::expr_tuple([]).into()); } let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into(); - let edition = module.krate().edition(db); + let edition = module.krate(db).edition(db); let ty_path = module.find_path(db, item_for_path_search(db, item_in_ns)?, cfg)?; diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 5367350052..fa4f2a78c8 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -110,7 +110,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> let mut inline_refs_for_file = |file_id: EditionedFileId, refs: Vec<FileReference>| { let file_id = file_id.file_id(ctx.db()); builder.edit_file(file_id); - let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate()); + let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate(ctx.db())); let count = refs.len(); // The collects are required as we are otherwise iterating while mutating 🙅♀️🙅♂️ let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some); @@ -196,7 +196,7 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< let name_ref: ast::NameRef = ctx.find_node_at_offset()?; let call_info = CallInfo::from_name_ref( name_ref.clone(), - ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate().into(), + ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(), )?; let (function, label) = match &call_info.node { ast::CallableExpr::Call(call) => { diff --git a/crates/ide-assists/src/handlers/inline_macro.rs b/crates/ide-assists/src/handlers/inline_macro.rs index b09bef36ae..280bd7f2ca 100644 --- a/crates/ide-assists/src/handlers/inline_macro.rs +++ b/crates/ide-assists/src/handlers/inline_macro.rs @@ -38,7 +38,7 @@ use crate::{AssistContext, AssistId, Assists}; pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?; let macro_call = ctx.sema.to_def(&unexpanded)?; - let target_crate_id = ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate().into(); + let target_crate_id = ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(); let text_range = unexpanded.syntax().text_range(); acc.add( diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs index d8dbefd59e..495a84d62b 100644 --- a/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -42,10 +42,10 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> let resolved_call = ctx.sema.resolve_method_call(&call)?; let current_module = ctx.sema.scope(call.syntax())?.module(); - let current_edition = current_module.krate().edition(ctx.db()); + let current_edition = current_module.krate(ctx.db()).edition(ctx.db()); let target_module_def = ModuleDef::from(resolved_call); let item_in_ns = ItemInNs::from(target_module_def); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate(ctx.sema.db))); let receiver_path = current_module.find_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs index 8834ad9765..b3cf296965 100644 --- a/crates/ide-assists/src/handlers/qualify_path.rs +++ b/crates/ide-assists/src/handlers/qualify_path.rs @@ -82,7 +82,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option proposed_imports.dedup_by(|a, b| a.import_path == b.import_path); let current_edition = - current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT); + current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT); // prioritize more relevant imports proposed_imports.sort_by_key(|import| { Reverse(super::auto_import::relevance_score( diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 2bf4406cc6..11b3fd22fa 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -69,7 +69,7 @@ pub(crate) fn replace_derive_with_manual_impl( let args = attr.token_tree()?; let current_module = ctx.sema.scope(adt.syntax())?.module(); - let current_crate = current_module.krate(); + let current_crate = current_module.krate(ctx.db()); let current_edition = current_crate.edition(ctx.db()); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_crate)); @@ -193,7 +193,7 @@ fn impl_def_from_trait( let target_scope = sema.scope(annotated_name.syntax())?; // Keep assoc items of local crates even if they have #[doc(hidden)] attr. - let ignore_items = if trait_.module(sema.db).krate().origin(sema.db).is_local() { + let ignore_items = if trait_.module(sema.db).krate(sema.db).origin(sema.db).is_local() { IgnoreAssocItems::No } else { IgnoreAssocItems::DocHiddenAttrPresent diff --git a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index c85ec734c0..6ca3e26ca0 100644 --- a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -1,4 +1,5 @@ -use ide_db::assists::AssistId; +use hir::Semantics; +use ide_db::{RootDatabase, assists::AssistId, defs::Definition}; use syntax::{ AstNode, ast::{self, Expr, HasArgList, make}, @@ -60,8 +61,8 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_ format!("Replace {method_name} with {method_name_lazy}"), call.syntax().text_range(), |builder| { + let closured = into_closure(&last_arg, &method_name_lazy); builder.replace(method_name.syntax().text_range(), method_name_lazy); - let closured = into_closure(&last_arg); builder.replace_ast(last_arg, closured); }, ) @@ -79,7 +80,7 @@ fn lazy_method_name(name: &str) -> String { } } -fn into_closure(param: &Expr) -> Expr { +fn into_closure(param: &Expr, name_lazy: &str) -> Expr { (|| { if let ast::Expr::CallExpr(call) = param { if call.arg_list()?.args().count() == 0 { Some(call.expr()?) } else { None } @@ -87,7 +88,11 @@ fn into_closure(param: &Expr) -> Expr { None } })() - .unwrap_or_else(|| make::expr_closure(None, param.clone()).into()) + .unwrap_or_else(|| { + let pats = (name_lazy == "and_then") + .then(|| make::untyped_param(make::ext::simple_ident_pat(make::name("it")).into())); + make::expr_closure(pats, param.clone()).into() + }) } // Assist: replace_with_eager_method @@ -146,21 +151,39 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<' call.syntax().text_range(), |builder| { builder.replace(method_name.syntax().text_range(), method_name_eager); - let called = into_call(&last_arg); + let called = into_call(&last_arg, &ctx.sema); builder.replace_ast(last_arg, called); }, ) } -fn into_call(param: &Expr) -> Expr { +fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr { (|| { if let ast::Expr::ClosureExpr(closure) = param { - if closure.param_list()?.params().count() == 0 { Some(closure.body()?) } else { None } + let mut params = closure.param_list()?.params(); + match params.next() { + Some(_) if params.next().is_none() => { + let params = sema.resolve_expr_as_callable(param)?.params(); + let used_param = Definition::Local(params.first()?.as_local(sema.db)?) + .usages(sema) + .at_least_one(); + if used_param { None } else { Some(closure.body()?) } + } + None => Some(closure.body()?), + Some(_) => None, + } } else { None } })() - .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())).into()) + .unwrap_or_else(|| { + let callable = if needs_parens_in_call(param) { + make::expr_paren(param.clone()).into() + } else { + param.clone() + }; + make::expr_call(callable, make::arg_list(Vec::new())).into() + }) } fn eager_method_name(name: &str) -> Option<&str> { @@ -177,6 +200,12 @@ fn ends_is(name: &str, end: &str) -> bool { name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_')) } +fn needs_parens_in_call(param: &Expr) -> bool { + let call = make::expr_call(make::ext::expr_unit(), make::arg_list(Vec::new())); + let callable = call.expr().expect("invalid make call"); + param.needs_parens_in_place_of(call.syntax(), callable.syntax()) +} + #[cfg(test)] mod tests { use crate::tests::check_assist; @@ -333,7 +362,7 @@ fn foo() { r#" fn foo() { let foo = Some("foo"); - return foo.and_then(|| Some("bar")); + return foo.and_then(|it| Some("bar")); } "#, ) @@ -347,7 +376,7 @@ fn foo() { //- minicore: option, fn fn foo() { let foo = Some("foo"); - return foo.and_then$0(|| Some("bar")); + return foo.and_then$0(|it| Some("bar")); } "#, r#" @@ -360,6 +389,26 @@ fn foo() { } #[test] + fn replace_and_then_with_and_used_param() { + check_assist( + replace_with_eager_method, + r#" +//- minicore: option, fn +fn foo() { + let foo = Some("foo"); + return foo.and_then$0(|it| Some(it.strip_suffix("bar"))); +} +"#, + r#" +fn foo() { + let foo = Some("foo"); + return foo.and((|it| Some(it.strip_suffix("bar")))()); +} +"#, + ) + } + + #[test] fn replace_then_some_with_then() { check_assist( replace_with_lazy_method, @@ -398,4 +447,28 @@ fn foo() { "#, ) } + + #[test] + fn replace_then_with_then_some_needs_parens() { + check_assist( + replace_with_eager_method, + r#" +//- minicore: option, fn, bool_impl +struct Func { f: fn() -> i32 } +fn foo() { + let foo = true; + let func = Func { f: || 2 }; + let x = foo.then$0(func.f); +} +"#, + r#" +struct Func { f: fn() -> i32 } +fn foo() { + let foo = true; + let func = Func { f: || 2 }; + let x = foo.then_some((func.f)()); +} +"#, + ) + } } diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index e9f0e190d4..009fc077ce 100644 --- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -58,7 +58,7 @@ pub(crate) fn replace_qualified_name_with_use( let path_to_qualifier = starts_with_name_ref .then(|| { let mod_ = ctx.sema.scope(original_path.syntax())?.module(); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(mod_.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(mod_.krate(ctx.sema.db))); mod_.find_use_path(ctx.sema.db, module, ctx.config.insert_use.prefix_kind, cfg) }) .flatten(); diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs index d64a76eb8b..849dfa49dd 100644 --- a/crates/ide-assists/src/handlers/term_search.rs +++ b/crates/ide-assists/src/handlers/term_search.rs @@ -55,7 +55,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< path.gen_source_code( &scope, &mut formatter, - ctx.config.find_path_config(ctx.sema.is_nightly(scope.module().krate())), + ctx.config.find_path_config(ctx.sema.is_nightly(scope.module().krate(ctx.sema.db))), scope.krate().to_display_target(ctx.db()), ) .ok() diff --git a/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/crates/ide-assists/src/handlers/toggle_async_sugar.rs index fa6fca8150..fa6ccb9a5f 100644 --- a/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -132,7 +132,7 @@ pub(crate) fn desugar_async_into_impl_future( let scope = ctx.sema.scope(function.syntax())?; let module = scope.module(); - let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); let future_trait = FamousDefs(&ctx.sema, scope.krate()).core_future_Future()?; let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(future_trait), cfg)?; let edition = scope.krate().edition(ctx.db()); diff --git a/crates/ide-assists/src/handlers/toggle_ignore.rs b/crates/ide-assists/src/handlers/toggle_ignore.rs index 386625b86b..a088fb178d 100644 --- a/crates/ide-assists/src/handlers/toggle_ignore.rs +++ b/crates/ide-assists/src/handlers/toggle_ignore.rs @@ -1,6 +1,6 @@ use syntax::{ AstNode, AstToken, - ast::{self, HasAttrs}, + ast::{self, HasAttrs, edit::AstNodeEdit}, }; use crate::{AssistContext, AssistId, Assists, utils::test_related_attribute_syn}; @@ -27,13 +27,16 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let attr: ast::Attr = ctx.find_node_at_offset()?; let func = attr.syntax().parent().and_then(ast::Fn::cast)?; let attr = test_related_attribute_syn(&func)?; + let indent = attr.indent_level(); match has_ignore_attribute(&func) { None => acc.add( AssistId::refactor("toggle_ignore"), "Ignore this test", attr.syntax().text_range(), - |builder| builder.insert(attr.syntax().text_range().end(), "\n#[ignore]"), + |builder| { + builder.insert(attr.syntax().text_range().end(), format!("\n{indent}#[ignore]")) + }, ), Some(ignore_attr) => acc.add( AssistId::refactor("toggle_ignore"), @@ -69,13 +72,17 @@ mod tests { check_assist( toggle_ignore, r#" - #[test$0] - fn test() {} + mod indent { + #[test$0] + fn test() {} + } "#, r#" - #[test] - #[ignore] - fn test() {} + mod indent { + #[test] + #[ignore] + fn test() {} + } "#, ) } @@ -85,13 +92,17 @@ mod tests { check_assist( toggle_ignore, r#" - #[test$0] - #[ignore] - fn test() {} + mod indent { + #[test$0] + #[ignore] + fn test() {} + } "#, r#" - #[test] - fn test() {} + mod indent { + #[test] + fn test() {} + } "#, ) } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 0b5dae6bc4..47cb4c8e74 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -59,6 +59,8 @@ //! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html> #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] mod assist_config; mod assist_context; @@ -245,7 +247,6 @@ mod handlers { add_label_to_loop::add_label_to_loop, add_lifetime_to_type::add_lifetime_to_type, add_missing_match_arms::add_missing_match_arms, - add_return_type::add_return_type, add_turbo_fish::add_turbo_fish, apply_demorgan::apply_demorgan_iterator, apply_demorgan::apply_demorgan, @@ -390,6 +391,7 @@ mod handlers { // used as a tie-breaker. add_missing_impl_members::add_missing_impl_members, add_missing_impl_members::add_missing_default_members, + add_return_type::add_return_type, // replace_string_with_char::replace_string_with_char, replace_string_with_char::replace_char_with_string, diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index de8c4b6bca..9a96374c00 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -27,7 +27,7 @@ use syntax::{ make, syntax_factory::SyntaxFactory, }, - syntax_editor::{Removable, SyntaxEditor}, + syntax_editor::{Element, Removable, SyntaxEditor}, }; use crate::{ @@ -384,6 +384,28 @@ fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> { } } +pub(crate) fn insert_attributes( + before: impl Element, + edit: &mut SyntaxEditor, + attrs: impl IntoIterator<Item = ast::Attr>, +) { + let mut attrs = attrs.into_iter().peekable(); + if attrs.peek().is_none() { + return; + } + let elem = before.syntax_element(); + let indent = IndentLevel::from_element(&elem); + let whitespace = format!("\n{indent}"); + edit.insert_all( + syntax::syntax_editor::Position::before(elem), + attrs + .flat_map(|attr| { + [attr.syntax().clone().into(), make::tokens::whitespace(&whitespace).into()] + }) + .collect(), + ); +} + pub(crate) fn next_prev() -> impl Iterator<Item = Direction> { [Direction::Next, Direction::Prev].into_iter() } diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml index 277d5dfa49..6abc009241 100644 --- a/crates/ide-completion/Cargo.toml +++ b/crates/ide-completion/Cargo.toml @@ -37,5 +37,9 @@ expect-test = "1.5.1" test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index abae3cb368..b28764f6fc 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -190,7 +190,7 @@ impl Completions { path_ctx: &PathCompletionCtx<'_>, ) { ctx.process_all_names(&mut |name, res, doc_aliases| match res { - ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => { + ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => { self.add_module(ctx, path_ctx, m, name, doc_aliases); } _ => (), diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs index 267d92b6c0..57ea609a40 100644 --- a/crates/ide-completion/src/completions/attribute/derive.rs +++ b/crates/ide-completion/src/completions/attribute/derive.rs @@ -56,7 +56,7 @@ pub(crate) fn complete_derive_path( _ => return, }; - match (core, mac.module(ctx.db).krate()) { + match (core, mac.module(ctx.db).krate(ctx.db)) { // show derive dependencies for `core`/`std` derives (Some(core), mac_krate) if core == mac_krate => {} _ => return acc.add_macro(ctx, path_ctx, mac, name), diff --git a/crates/ide-completion/src/completions/attribute/macro_use.rs b/crates/ide-completion/src/completions/attribute/macro_use.rs index 0641a4f6c3..136315c61f 100644 --- a/crates/ide-completion/src/completions/attribute/macro_use.rs +++ b/crates/ide-completion/src/completions/attribute/macro_use.rs @@ -15,7 +15,7 @@ pub(super) fn complete_macro_use( let Some(extern_crate) = ctx.sema.to_def(extern_crate) else { return }; let Some(krate) = extern_crate.resolved_crate(ctx.db) else { return }; - for mod_def in krate.root_module().declarations(ctx.db) { + for mod_def in krate.root_module(ctx.db).declarations(ctx.db) { if let ModuleDef::Macro(mac) = mod_def { let mac_name = mac.name(ctx.db); let mac_name = mac_name.as_str(); diff --git a/crates/ide-completion/src/completions/format_string.rs b/crates/ide-completion/src/completions/format_string.rs index 5ae65b05bc..eaacd8d1a8 100644 --- a/crates/ide-completion/src/completions/format_string.rs +++ b/crates/ide-completion/src/completions/format_string.rs @@ -22,13 +22,8 @@ pub(crate) fn format_string( let cursor_in_lit = cursor - lit_start; let prefix = &original.text()[..cursor_in_lit.into()]; - let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple(); - let brace_offset = match braces { - // escaped brace - Some(((_, '{'), (_, '{'))) => return, - Some(((idx, '{'), _)) => lit_start + TextSize::from(idx as u32 + 1), - _ => return, - }; + let Some(brace_offset) = unescaped_brace(prefix) else { return }; + let brace_offset = lit_start + brace_offset + TextSize::of('{'); let source_range = TextRange::new(brace_offset, cursor); ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| { @@ -59,6 +54,15 @@ pub(crate) fn format_string( }); } +fn unescaped_brace(prefix: &str) -> Option<TextSize> { + let is_ident_char = |ch: char| ch.is_alphanumeric() || ch == '_'; + prefix + .trim_end_matches(is_ident_char) + .strip_suffix('{') + .filter(|it| it.chars().rev().take_while(|&ch| ch == '{').count() % 2 == 0) + .map(|s| TextSize::new(s.len() as u32)) +} + #[cfg(test)] mod tests { use expect_test::expect; @@ -97,6 +101,82 @@ fn main() { } #[test] + fn no_completion_after_escaped() { + check_no_kw( + r#" +//- minicore: fmt +fn main() { + let foobar = 1; + format_args!("{{f$0"); +} +"#, + expect![[]], + ); + check_no_kw( + r#" +//- minicore: fmt +fn main() { + let foobar = 1; + format_args!("some text {{{{f$0"); +} +"#, + expect![[]], + ); + } + + #[test] + fn completes_unescaped_after_escaped() { + check_edit( + "foobar", + r#" +//- minicore: fmt +fn main() { + let foobar = 1; + format_args!("{{{f$0"); +} +"#, + r#" +fn main() { + let foobar = 1; + format_args!("{{{foobar"); +} +"#, + ); + check_edit( + "foobar", + r#" +//- minicore: fmt +fn main() { + let foobar = 1; + format_args!("{{{{{f$0"); +} +"#, + r#" +fn main() { + let foobar = 1; + format_args!("{{{{{foobar"); +} +"#, + ); + check_edit( + "foobar", + r#" +//- minicore: fmt +fn main() { + let foobar = 1; + format_args!("}}{f$0"); +} +"#, + r#" +fn main() { + let foobar = 1; + format_args!("}}{foobar"); +} +"#, + ); + } + + #[test] fn completes_locals() { check_edit( "foobar", diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index cdd77e79b5..4072f05a41 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -344,7 +344,13 @@ fn get_transformed_fn( } _ => None, })?; - ted::replace(ty.syntax(), output.syntax()); + if let ast::Type::TupleType(ty) = &output + && ty.fields().next().is_none() + { + ted::remove(fn_.ret_type()?.syntax()); + } else { + ted::replace(ty.syntax(), output.syntax()); + } } _ => (), } @@ -1619,6 +1625,35 @@ impl DesugaredAsyncTrait for () { } "#, ); + + check_edit( + "async fn foo", + r#" +//- minicore: future, send, sized +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future<Output = ()> + Send; +} + +impl DesugaredAsyncTrait for () { + $0 +} +"#, + r#" +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future<Output = ()> + Send; +} + +impl DesugaredAsyncTrait for () { + async fn foo(&self) { + $0 +} +} +"#, + ); } #[test] diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index eab2b9063f..fbb3cde968 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -344,6 +344,60 @@ fn main() { } "#, ); + + check_edit( + "loop", + r#" +fn main() { + let x = &$0 + bar(); +} +"#, + r#" +fn main() { + let x = &loop { + $0 +}; + bar(); +} +"#, + ); + + check_edit( + "loop", + r#" +fn main() { + let x = -$0 + bar(); +} +"#, + r#" +fn main() { + let x = -loop { + $0 +}; + bar(); +} +"#, + ); + + check_edit( + "loop", + r#" +fn main() { + let x = 2 + $0 + bar(); +} +"#, + r#" +fn main() { + let x = 2 + loop { + $0 +}; + bar(); +} +"#, + ); } #[test] diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index e761da7152..add637a16f 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1321,9 +1321,8 @@ fn classify_name_ref<'db>( let incomplete_expr_stmt = it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none()); let before_else_kw = before_else_kw(it); - let incomplete_let = it - .parent() - .and_then(ast::LetStmt::cast) + let incomplete_let = left_ancestors(it.parent()) + .find_map(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()) || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw; let in_value = is_in_value(it); @@ -1882,6 +1881,13 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { Some((use_tree.path()?, true)) } +fn left_ancestors(node: Option<SyntaxNode>) -> impl Iterator<Item = SyntaxNode> { + node.into_iter().flat_map(|node| { + let end = node.text_range().end(); + node.ancestors().take_while(move |it| it.text_range().end() == end) + }) +} + fn is_in_token_of_for_loop(path: &ast::Path) -> bool { // oh my ... (|| { diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index c526c7f070..71d32da747 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -23,7 +23,7 @@ use crate::{ /// editor pop-up. /// /// It is basically a POD with various properties. To construct a [`CompletionItem`], -/// use [`Builder::new`] method and the [`Builder`] struct. +/// use the [`Builder`] struct. #[derive(Clone, UpmapFromRaFixture)] #[non_exhaustive] pub struct CompletionItem { diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index f7a118db50..33ab43fa61 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -1,5 +1,12 @@ //! `completions` crate provides utilities for generating completions of user input. +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod completions; mod config; mod context; @@ -283,7 +290,7 @@ pub fn resolve_completion_edits( let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?; let current_module = sema.scope(position_for_import)?.module(); - let current_crate = current_module.krate(); + let current_crate = current_module.krate(db); let current_edition = current_crate.edition(db); let new_ast = scope.clone_for_update(); let mut import_insert = TextEdit::builder(); diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index cfd6340f1e..ce35ab135f 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -106,7 +106,7 @@ pub(crate) fn visible_fields( .collect::<Vec<_>>(); let has_invisible_field = n_fields - fields.len() > 0; let is_foreign_non_exhaustive = - item.attrs(ctx.db).is_non_exhaustive() && item.krate(ctx.db) != module.krate(); + item.attrs(ctx.db).is_non_exhaustive() && item.krate(ctx.db) != module.krate(ctx.db); let fields_omitted = has_invisible_field || is_foreign_non_exhaustive; Some((fields, fields_omitted)) } diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs index 9ff490f904..3701416dfc 100644 --- a/crates/ide-completion/src/tests/attribute.rs +++ b/crates/ide-completion/src/tests/attribute.rs @@ -1508,3 +1508,55 @@ extern crate dep; ) } } + +#[test] +fn builtin_macro_completed_only_as_its_kind() { + check( + r#" +#[rustc_builtin_macro] +pub macro define_opaque($($tt:tt)*) { + /* compiler built-in */ +} + +fn foo() { + def$0 +} + "#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs index 94530bf51d..cf86618de6 100644 --- a/crates/ide-completion/src/tests/flyimport.rs +++ b/crates/ide-completion/src/tests/flyimport.rs @@ -780,9 +780,9 @@ fn main() { } "#, expect![[r#" - me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED + me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); } diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index f1f9d85cf9..fca06b69d1 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -52,5 +52,9 @@ line-index.workspace = true [dev-dependencies] expect-test = "1.5.1" +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 9ce85b2bf3..788f9b73fa 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -64,9 +64,9 @@ impl Definition { pub fn krate(&self, db: &RootDatabase) -> Option<Crate> { Some(match self { - Definition::Module(m) => m.krate(), + Definition::Module(m) => m.krate(db), &Definition::Crate(it) => it, - _ => self.module(db)?.krate(), + _ => self.module(db)?.krate(db), }) } @@ -93,7 +93,7 @@ impl Definition { Definition::ExternCrateDecl(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), Definition::InlineAsmOperand(it) => it.parent(db).module(db), - Definition::ToolModule(t) => t.krate().root_module(), + Definition::ToolModule(t) => t.krate().root_module(db), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) @@ -374,7 +374,7 @@ pub fn find_std_module( ) -> Option<hir::Module> { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; - let std_root_module = std_crate.root_module(); + let std_root_module = std_crate.root_module(famous_defs.0.db); std_root_module.children(db).find(|module| { module.name(db).is_some_and(|module| module.display(db, edition).to_string() == name) }) diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs index 8eea2b81ba..f28ce53e91 100644 --- a/crates/ide-db/src/famous_defs.rs +++ b/crates/ide-db/src/famous_defs.rs @@ -232,7 +232,7 @@ impl FamousDefs<'_, '_> { lang_crate => lang_crate, }; let std_crate = self.find_lang_crate(lang_crate)?; - let mut module = std_crate.root_module(); + let mut module = std_crate.root_module(db); for segment in path { module = module.children(db).find_map(|child| { let name = child.name(db)?; diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs index 1e54058dd1..08cf1eeed3 100644 --- a/crates/ide-db/src/helpers.rs +++ b/crates/ide-db/src/helpers.rs @@ -80,7 +80,7 @@ pub fn visit_file_defs( } module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); - let is_root = module.is_crate_root(); + let is_root = module.is_crate_root(db); module .legacy_macros(db) .into_iter() diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index c49ade2350..90e3bb61f4 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -315,7 +315,7 @@ impl<'db> ImportAssets<'db> { allow_unstable: sema.is_nightly(scope.krate()), }; let db = sema.db; - let krate = self.module_with_candidate.krate(); + let krate = self.module_with_candidate.krate(sema.db); let scope_definitions = self.scope_definitions(sema); let mod_path = |item| { get_mod_path( diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 0301b50208..338c423254 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -2,6 +2,11 @@ //! //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + extern crate self as ide_db; mod apply_change; diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index bc5958ec58..48305c2082 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -152,7 +152,7 @@ impl<'a> PathTransform<'a> { db, node, &db.expansion_span_map(file_id), - self.target_scope.module().krate().into(), + self.target_scope.module().krate(db).into(), ) } } @@ -174,7 +174,7 @@ impl<'a> PathTransform<'a> { let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default(); let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default(); let mut defaulted_params: Vec<DefaultedParam> = Default::default(); - let target_edition = target_module.krate().edition(self.source_scope.db); + let target_edition = target_module.krate(db).edition(self.source_scope.db); self.generic_def .into_iter() .flat_map(|it| it.type_or_const_params(db)) @@ -219,7 +219,7 @@ impl<'a> PathTransform<'a> { } (Either::Left(k), None) => { if let Some(default) = - k.default(db, target_module.krate().to_display_target(db)) + k.default(db, target_module.krate(db).to_display_target(db)) && let Some(default) = default.expr() { const_substs.insert(k, default.syntax().clone_for_update()); diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index a8800c142a..82eee69f0d 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -246,7 +246,7 @@ fn rename_mod( ) -> Result<SourceChange> { let mut source_change = SourceChange::default(); - if module.is_crate_root() { + if module.is_crate_root(sema.db) { return Ok(source_change); } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index f52b345007..a48438cfa8 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -294,9 +294,9 @@ impl Definition { // def is crate root if let &Definition::Module(module) = self - && module.is_crate_root() + && module.is_crate_root(db) { - return SearchScope::reverse_dependencies(db, module.krate()); + return SearchScope::reverse_dependencies(db, module.krate(db)); } let module = match self.module(db) { @@ -367,22 +367,22 @@ impl Definition { return match macro_def.kind(db) { hir::MacroKind::Declarative => { if macro_def.attrs(db).is_macro_export() { - SearchScope::reverse_dependencies(db, module.krate()) + SearchScope::reverse_dependencies(db, module.krate(db)) } else { - SearchScope::krate(db, module.krate()) + SearchScope::krate(db, module.krate(db)) } } hir::MacroKind::AttrBuiltIn | hir::MacroKind::DeriveBuiltIn | hir::MacroKind::DeclarativeBuiltIn => SearchScope::crate_graph(db), hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => { - SearchScope::reverse_dependencies(db, module.krate()) + SearchScope::reverse_dependencies(db, module.krate(db)) } }; } if let Definition::DeriveHelper(_) = self { - return SearchScope::reverse_dependencies(db, module.krate()); + return SearchScope::reverse_dependencies(db, module.krate(db)); } if let Some(vis) = self.visibility(db) { @@ -391,7 +391,7 @@ impl Definition { SearchScope::module_and_children(db, module.into()) } Visibility::PubCrate(krate) => SearchScope::krate(db, krate.into()), - Visibility::Public => SearchScope::reverse_dependencies(db, module.krate()), + Visibility::Public => SearchScope::reverse_dependencies(db, module.krate(db)), }; } @@ -907,13 +907,13 @@ impl<'a> FindUsages<'a> { } } // special case crate modules as these do not have a proper name - (_, Definition::Module(module)) if module.is_crate_root() => { + (_, Definition::Module(module)) if module.is_crate_root(self.sema.db) => { // FIXME: This assumes the crate name is always equal to its display name when it // really isn't // we should instead look at the dependency edge name and recursively search our way // up the ancestors module - .krate() + .krate(self.sema.db) .display_name(self.sema.db) .map(|crate_name| crate_name.crate_name().symbol().as_str().into()) } @@ -1002,7 +1002,7 @@ impl<'a> FindUsages<'a> { let scope = search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module)); - let is_crate_root = module.is_crate_root().then(|| Finder::new("crate")); + let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); let finder = &Finder::new("super"); for (text, file_id, search_range) in Self::scope_files(sema.db, &scope) { diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index ef67fbf6fe..e15d0b33bb 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -37,6 +37,7 @@ use hir::{ }; use rayon::prelude::*; use rustc_hash::FxHashSet; +use salsa::Update; use crate::RootDatabase; @@ -118,7 +119,7 @@ pub struct LocalRoots { } /// The symbol indices of modules that make up a given crate. -pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> { +pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_>]> { let _p = tracing::info_span!("crate_symbols").entered(); krate.modules(db).into_iter().map(|module| SymbolIndex::module_symbols(db, module)).collect() } @@ -148,7 +149,7 @@ pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> // | Editor | Shortcut | // |---------|-----------| // | VS Code | <kbd>Ctrl+T</kbd> -pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { +pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol<'_>> { let _p = tracing::info_span!("world_symbols", query = ?query.query).entered(); let indices: Vec<_> = if query.libs { @@ -170,9 +171,7 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { crates .par_iter() .for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into())); - let indices: Vec<_> = - crates.into_iter().map(|krate| crate_symbols(db, krate.into())).collect(); - indices.iter().flat_map(|indices| indices.iter().cloned()).collect() + crates.into_iter().flat_map(|krate| Vec::from(crate_symbols(db, krate.into()))).collect() }; let mut res = vec![]; @@ -184,24 +183,27 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { } #[derive(Default)] -pub struct SymbolIndex { - symbols: Box<[FileSymbol]>, +pub struct SymbolIndex<'db> { + symbols: Box<[FileSymbol<'db>]>, map: fst::Map<Vec<u8>>, } -impl SymbolIndex { +impl<'db> SymbolIndex<'db> { /// The symbol index for a given source root within library_roots. - pub fn library_symbols(db: &dyn HirDatabase, source_root_id: SourceRootId) -> &SymbolIndex { + pub fn library_symbols( + db: &'db dyn HirDatabase, + source_root_id: SourceRootId, + ) -> &'db SymbolIndex<'db> { // FIXME: #[salsa::interned] struct InternedSourceRootId { id: SourceRootId, } #[salsa::tracked(returns(ref))] - fn library_symbols( - db: &dyn HirDatabase, - source_root_id: InternedSourceRootId<'_>, - ) -> SymbolIndex { + fn library_symbols<'db>( + db: &'db dyn HirDatabase, + source_root_id: InternedSourceRootId<'db>, + ) -> SymbolIndex<'db> { let _p = tracing::info_span!("library_symbols").entered(); // We call this without attaching because this runs in parallel, so we need to attach here. @@ -224,7 +226,7 @@ impl SymbolIndex { /// The symbol index for a given module. These modules should only be in source roots that /// are inside local_roots. - pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex { + pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex<'_> { // FIXME: #[salsa::interned] struct InternedModuleId { @@ -232,7 +234,10 @@ impl SymbolIndex { } #[salsa::tracked(returns(ref))] - fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolIndex { + fn module_symbols<'db>( + db: &'db dyn HirDatabase, + module: InternedModuleId<'db>, + ) -> SymbolIndex<'db> { let _p = tracing::info_span!("module_symbols").entered(); // We call this without attaching because this runs in parallel, so we need to attach here. @@ -241,7 +246,7 @@ impl SymbolIndex { SymbolIndex::new(SymbolCollector::new_module( db, module, - !module.krate().origin(db).is_local(), + !module.krate(db).origin(db).is_local(), )) }) } @@ -250,29 +255,41 @@ impl SymbolIndex { } } -impl fmt::Debug for SymbolIndex { +impl fmt::Debug for SymbolIndex<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish() } } -impl PartialEq for SymbolIndex { - fn eq(&self, other: &SymbolIndex) -> bool { +impl PartialEq for SymbolIndex<'_> { + fn eq(&self, other: &SymbolIndex<'_>) -> bool { self.symbols == other.symbols } } -impl Eq for SymbolIndex {} +impl Eq for SymbolIndex<'_> {} -impl Hash for SymbolIndex { +impl Hash for SymbolIndex<'_> { fn hash<H: Hasher>(&self, hasher: &mut H) { self.symbols.hash(hasher) } } -impl SymbolIndex { - fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex { - fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering { +unsafe impl Update for SymbolIndex<'_> { + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + let this = unsafe { &mut *old_pointer }; + if *this == new_value { + false + } else { + *this = new_value; + true + } + } +} + +impl<'db> SymbolIndex<'db> { + fn new(mut symbols: Box<[FileSymbol<'db>]>) -> SymbolIndex<'db> { + fn cmp(lhs: &FileSymbol<'_>, rhs: &FileSymbol<'_>) -> Ordering { let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase()); let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase()); lhs_chars.cmp(rhs_chars) @@ -318,7 +335,7 @@ impl SymbolIndex { } pub fn memory_size(&self) -> usize { - self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol>() + self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol<'_>>() } fn range_to_map_value(start: usize, end: usize) -> u64 { @@ -336,10 +353,10 @@ impl SymbolIndex { } impl Query { - pub(crate) fn search<'sym, T>( + pub(crate) fn search<'db, T>( self, - indices: &'sym [&SymbolIndex], - cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>, + indices: &[&'db SymbolIndex<'db>], + cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>, ) -> Option<T> { let _p = tracing::info_span!("symbol_index::Query::search").entered(); let mut op = fst::map::OpBuilder::new(); @@ -371,11 +388,11 @@ impl Query { } } - fn search_maps<'sym, T>( + fn search_maps<'db, T>( &self, - indices: &'sym [&SymbolIndex], + indices: &[&'db SymbolIndex<'db>], mut stream: fst::map::Union<'_>, - mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>, + mut cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>, ) -> Option<T> { let ignore_underscore_prefixed = !self.query.starts_with("__"); while let Some((_, indexed_values)) = stream.next() { diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt index 427a510559..5783d97564 100644 --- a/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -1,12 +1,8 @@ [ ( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(0), + id: ModuleIdLt { + [salsa id]: Id(3800), }, }, [ @@ -16,7 +12,7 @@ Struct( Struct { id: StructId( - 3801, + 3c01, ), }, ), @@ -43,6 +39,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -50,7 +47,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -77,6 +74,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "mul1", @@ -84,7 +82,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -111,6 +109,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "mul2", @@ -118,7 +117,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -145,6 +144,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -152,7 +152,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -179,6 +179,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -186,7 +187,7 @@ Struct( Struct { id: StructId( - 3801, + 3c01, ), }, ), @@ -213,6 +214,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "s2", @@ -220,7 +222,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -247,6 +249,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ], ), diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index cc130194cb..953bc73da9 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -1,12 +1,8 @@ [ ( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(0), + id: ModuleIdLt { + [salsa id]: Id(3800), }, }, [ @@ -15,7 +11,7 @@ def: Variant( Variant { id: EnumVariantId( - 7800, + 7c00, ), }, ), @@ -43,13 +39,14 @@ is_assoc: true, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Alias", def: TypeAlias( TypeAlias { id: TypeAliasId( - 6c00, + 7000, ), }, ), @@ -75,13 +72,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "B", def: Variant( Variant { id: EnumVariantId( - 7801, + 7c01, ), }, ), @@ -109,13 +107,14 @@ is_assoc: true, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "CONST", def: Const( Const { id: ConstId( - 6400, + 6800, ), }, ), @@ -141,13 +140,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "CONST_WITH_INNER", def: Const( Const { id: ConstId( - 6402, + 6802, ), }, ), @@ -173,6 +173,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Enum", @@ -180,7 +181,7 @@ Enum( Enum { id: EnumId( - 5000, + 5400, ), }, ), @@ -207,6 +208,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "ItemLikeMacro", @@ -214,7 +216,7 @@ Macro { id: Macro2Id( Macro2Id( - 4c00, + 5000, ), ), }, @@ -241,6 +243,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Macro", @@ -248,7 +251,7 @@ Macro { id: Macro2Id( Macro2Id( - 4c00, + 5000, ), ), }, @@ -275,13 +278,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "STATIC", def: Static( Static { id: StaticId( - 6800, + 6c00, ), }, ), @@ -307,6 +311,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -314,7 +319,7 @@ Struct( Struct { id: StructId( - 4801, + 4c01, ), }, ), @@ -341,6 +346,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructFromMacro", @@ -348,7 +354,7 @@ Struct( Struct { id: StructId( - 4800, + 4c00, ), }, ), @@ -356,7 +362,7 @@ loc: DeclarationLocation { hir_file_id: MacroFile( MacroCallId( - Id(4000), + Id(4400), ), ), ptr: SyntaxNodePtr { @@ -375,6 +381,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructInFn", @@ -382,7 +389,7 @@ Struct( Struct { id: StructId( - 4805, + 4c05, ), }, ), @@ -411,6 +418,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructInNamedConst", @@ -418,7 +426,7 @@ Struct( Struct { id: StructId( - 4806, + 4c06, ), }, ), @@ -447,6 +455,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructInUnnamedConst", @@ -454,7 +463,7 @@ Struct( Struct { id: StructId( - 4807, + 4c07, ), }, ), @@ -481,6 +490,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructT", @@ -488,7 +498,7 @@ Struct( Struct { id: StructId( - 4802, + 4c02, ), }, ), @@ -515,13 +525,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", def: Trait( Trait { id: TraitId( - 5c00, + 6000, ), }, ), @@ -547,6 +558,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", @@ -554,7 +566,7 @@ Macro { id: Macro2Id( Macro2Id( - 4c00, + 5000, ), ), }, @@ -581,6 +593,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Union", @@ -588,7 +601,7 @@ Union( Union { id: UnionId( - 5400, + 5800, ), }, ), @@ -615,17 +628,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "a_mod", def: Module( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(1), + id: ModuleIdLt { + [salsa id]: Id(3801), }, }, ), @@ -651,17 +661,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "b_mod", def: Module( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(2), + id: ModuleIdLt { + [salsa id]: Id(3802), }, }, ), @@ -687,6 +694,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "define_struct", @@ -694,7 +702,7 @@ Macro { id: MacroRulesId( MacroRulesId( - 3c01, + 4001, ), ), }, @@ -721,13 +729,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "generic_impl_fn", def: Function( Function { id: FunctionId( - 6002, + 6402, ), }, ), @@ -755,13 +764,14 @@ is_assoc: true, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "impl_fn", def: Function( Function { id: FunctionId( - 6001, + 6401, ), }, ), @@ -789,6 +799,7 @@ is_assoc: true, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "macro_rules_macro", @@ -796,7 +807,7 @@ Macro { id: MacroRulesId( MacroRulesId( - 3c00, + 4000, ), ), }, @@ -823,13 +834,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "main", def: Function( Function { id: FunctionId( - 6000, + 6400, ), }, ), @@ -855,6 +867,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "really_define_struct", @@ -862,7 +875,7 @@ Macro { id: MacroRulesId( MacroRulesId( - 3c01, + 4001, ), ), }, @@ -889,13 +902,14 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "trait_fn", def: Function( Function { id: FunctionId( - 6003, + 6403, ), }, ), @@ -923,17 +937,14 @@ is_assoc: true, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ], ), ( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(1), + id: ModuleIdLt { + [salsa id]: Id(3801), }, }, [ @@ -943,7 +954,7 @@ Struct( Struct { id: StructId( - 4803, + 4c03, ), }, ), @@ -970,17 +981,14 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ], ), ( Module { - id: ModuleId { - krate: Crate( - Id(2c00), - ), - block: None, - local_id: Idx::<ModuleData>(2), + id: ModuleIdLt { + [salsa id]: Id(3802), }, }, [ @@ -989,7 +997,7 @@ def: Trait( Trait { id: TraitId( - 5c00, + 6000, ), }, ), @@ -1015,6 +1023,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "IsThisJustATrait", @@ -1022,7 +1031,7 @@ Macro { id: Macro2Id( Macro2Id( - 4c00, + 5000, ), ), }, @@ -1049,6 +1058,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "StructInModB", @@ -1056,7 +1066,7 @@ Struct( Struct { id: StructId( - 4804, + 4c04, ), }, ), @@ -1083,6 +1093,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "SuperItemLikeMacro", @@ -1090,7 +1101,7 @@ Macro { id: Macro2Id( Macro2Id( - 4c00, + 5000, ), ), }, @@ -1117,6 +1128,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "ThisStruct", @@ -1124,7 +1136,7 @@ Struct( Struct { id: StructId( - 4804, + 4c04, ), }, ), @@ -1151,6 +1163,7 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ], ), diff --git a/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt index 3ab837aa61..6f5f8f889c 100644 --- a/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt +++ b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt @@ -5,7 +5,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -32,5 +32,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ] diff --git a/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/crates/ide-db/src/test_data/test_symbols_with_imports.txt index a6a808d616..5d3fe4d265 100644 --- a/crates/ide-db/src/test_data/test_symbols_with_imports.txt +++ b/crates/ide-db/src/test_data/test_symbols_with_imports.txt @@ -5,7 +5,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -32,6 +32,7 @@ is_assoc: false, is_import: false, do_not_complete: Yes, + _marker: PhantomData<&()>, }, FileSymbol { name: "Foo", @@ -39,7 +40,7 @@ Struct( Struct { id: StructId( - 3800, + 3c00, ), }, ), @@ -66,5 +67,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, + _marker: PhantomData<&()>, }, ] diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs index 7b9fdb1e1c..7200e7fbe5 100644 --- a/crates/ide-db/src/traits.rs +++ b/crates/ide-db/src/traits.rs @@ -34,7 +34,7 @@ pub fn get_missing_assoc_items( // may share the same name as a function or constant. let mut impl_fns_consts = FxHashSet::default(); let mut impl_type = FxHashSet::default(); - let edition = imp.module(sema.db).krate().edition(sema.db); + let edition = imp.module(sema.db).krate(sema.db).edition(sema.db); for item in imp.items(sema.db) { match item { diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index 6f1e66948f..ddf5999036 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -34,5 +34,9 @@ expect-test = "1.5.1" test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index fdc426c32c..4a12c5a26d 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1000,7 +1000,8 @@ mod OtherBadCase; // ^^^^^^^^^^^^ 💡 error: Module `OtherBadCase` should have snake_case name, e.g. `other_bad_case` //- /BAD_CASE/OtherBadCase.rs -#![deny(non_snake_case)] +#![allow(non_snake_case)] +#![deny(non_snake_case)] // The lint level has been overridden. fn FOO() {} // ^^^ 💡 error: Function `FOO` should have snake_case name, e.g. `foo` diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index ab7256d63c..2a251382d4 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -221,8 +221,8 @@ fn get_default_constructor( let krate = ctx .sema .file_to_module_def(d.file.original_file(ctx.sema.db).file_id(ctx.sema.db))? - .krate(); - let module = krate.root_module(); + .krate(ctx.sema.db); + let module = krate.root_module(ctx.sema.db); // Look for a ::new() associated function let has_new_func = ty diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 59215f34a5..1abb50144d 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -296,8 +296,12 @@ fn main() { #[rustc_deprecated_safe_2024] fn set_var() {} +#[rustc_deprecated_safe_2024(audit_that = "something")] +fn set_var2() {} + fn main() { set_var(); + set_var2(); } "#, ); diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 18280a4add..2887a32825 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -995,6 +995,10 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { } "#, ); + // FIXME: There should be no "unused variable" here, and there should be a mutability error, + // but our MIR infra is horribly broken and due to the order in which expressions are lowered + // there is no `StorageLive` for `x` in the closure (in fact, `x` should not even be a variable + // of the closure, the environment should be, but as I said, our MIR infra is horribly broken). check_diagnostics( r#" //- minicore: copy, fn @@ -1003,8 +1007,8 @@ fn f() { || { || { let x = 2; + // ^ 💡 warn: unused variable || { || { x = 5; } } - //^^^^^ 💡 error: cannot mutate immutable variable `x` } } }; diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index 0edab5e0b3..bcfe3a8aa5 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -102,7 +102,8 @@ fn missing_record_expr_field_fixes( let indent = IndentLevel::from_node(last_field_syntax); let mut new_field = new_field.to_string(); - if usage_file_id != def_file_id { + // FIXME: check submodule instead of FileId + if usage_file_id != def_file_id && !matches!(def_id, hir::VariantDef::Variant(_)) { new_field = format!("pub(crate) {new_field}"); } new_field = format!("\n{indent}{new_field}"); @@ -358,6 +359,34 @@ pub struct Foo { } #[test] + fn test_add_enum_variant_field_in_other_file_from_usage() { + check_fix( + r#" +//- /main.rs +mod foo; + +fn main() { + foo::Foo::Variant { bar: 3, $0baz: false}; +} +//- /foo.rs +pub enum Foo { + Variant { + bar: i32 + } +} +"#, + r#" +pub enum Foo { + Variant { + bar: i32, + baz: bool + } +} +"#, + ) + } + + #[test] fn test_tuple_field_on_record_struct() { check_no_fix( r#" diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs index 23f0460075..90c27bdcef 100644 --- a/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/crates/ide-diagnostics/src/handlers/private_field.rs @@ -37,7 +37,7 @@ pub(crate) fn field_is_private_fixes( fix_range: TextRange, ) -> Option<Vec<Assist>> { let def_crate = private_field.krate(sema.db); - let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(); + let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(sema.db); let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " }; let source = private_field.source(sema.db)?; diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index fc2648efb4..cb3aac3717 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -83,7 +83,7 @@ fn quickfix_for_redundant_assoc_item( let root = db.parse_or_expand(d.file_id); // don't modify trait def in outer crate let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate(); - let trait_def_crate = d.trait_.module(db).krate(); + let trait_def_crate = d.trait_.module(db).krate(db); if trait_def_crate != current_crate { return None; } diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index 3a6e480f55..1283a11700 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -3,7 +3,7 @@ use std::iter; use hir::crate_def_map; -use hir::{DefMap, InFile, ModuleSource}; +use hir::{InFile, ModuleSource}; use ide_db::base_db::RootQueryDb; use ide_db::text_edit::TextEdit; use ide_db::{ @@ -106,7 +106,7 @@ fn fixes( // FIXME: This shouldnt need to access the crate def map directly let crate_def_map = crate_def_map(ctx.sema.db, krate); - let root_module = &crate_def_map[DefMap::ROOT]; + let root_module = &crate_def_map[crate_def_map.root_module_id()]; let Some(root_file_id) = root_module.origin.file_id() else { continue }; let Some(crate_root_path) = source_root.path_for_file(&root_file_id.file_id(ctx.sema.db)) else { diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 358e0c43c2..59ec259adf 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -83,7 +83,7 @@ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Opti make::ty("()") }; - if !is_editable_crate(target_module.krate(), ctx.sema.db) + if !is_editable_crate(target_module.krate(ctx.sema.db), ctx.sema.db) || SyntaxKind::from_keyword(field_name, ctx.edition).is_some() { return None; diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs index 84e63acbc0..b7ec8fa53f 100644 --- a/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -183,6 +183,61 @@ fn main2() { } #[test] + fn apply_last_lint_attribute_when_multiple_are_present() { + check_diagnostics( + r#" +#![allow(unused_variables)] +#![warn(unused_variables)] +#![deny(unused_variables)] + +fn main() { + let x = 2; + //^ 💡 error: unused variable + + #[deny(unused_variables)] + #[warn(unused_variables)] + #[allow(unused_variables)] + let y = 0; +} +"#, + ); + } + + #[test] + fn prefer_closest_ancestor_lint_attribute() { + check_diagnostics( + r#" +#![allow(unused_variables)] + +fn main() { + #![warn(unused_variables)] + + #[deny(unused_variables)] + let x = 2; + //^ 💡 error: unused variable +} + +#[warn(unused_variables)] +fn main2() { + #[deny(unused_variables)] + let x = 2; + //^ 💡 error: unused variable +} + +#[warn(unused_variables)] +fn main3() { + let x = 2; + //^ 💡 warn: unused variable +} + +fn main4() { + let x = 2; +} +"#, + ); + } + + #[test] fn fix_unused_variable() { check_fix( r#" diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 41ae854455..2b8474c316 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -23,6 +23,11 @@ //! There are also a couple of ad-hoc diagnostics implemented directly here, we //! don't yet have a great pattern for how to do them properly. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod handlers { pub(crate) mod await_outside_of_async; pub(crate) mod bad_rtn; @@ -83,9 +88,8 @@ mod handlers { #[cfg(test)] mod tests; -use std::{iter, sync::LazyLock}; +use std::sync::LazyLock; -use either::Either; use hir::{ Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic, }; @@ -97,11 +101,9 @@ use ide_db::{ imports::insert_use::InsertUseConfig, label::Label, source_change::SourceChange, - syntax_helpers::node_ext::parse_tt_as_comma_sep_paths, }; -use itertools::Itertools; use syntax::{ - AstPtr, Edition, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, T, TextRange, + AstPtr, Edition, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ast::{self, AstNode}, }; @@ -345,12 +347,12 @@ pub fn semantic_diagnostics( let module = sema.file_to_module_def(file_id); let is_nightly = matches!( - module.and_then(|m| db.toolchain_channel(m.krate().into())), + module.and_then(|m| db.toolchain_channel(m.krate(db).into())), Some(ReleaseChannel::Nightly) | None ); let krate = match module { - Some(module) => module.krate(), + Some(module) => module.krate(db), None => { match db.all_crates().last() { Some(last) => (*last).into(), @@ -483,7 +485,7 @@ pub fn semantic_diagnostics( // The edition isn't accurate (each diagnostics may have its own edition due to macros), // but it's okay as it's only being used for error recovery. - handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db)); + handle_lints(&ctx.sema, krate, &mut lints, editioned_file_id.edition(db)); res.retain(|d| d.severity != Severity::Allow); @@ -591,6 +593,7 @@ fn build_lints_map( fn handle_lints( sema: &Semantics<'_, RootDatabase>, + krate: hir::Crate, diagnostics: &mut [(InFile<SyntaxNode>, &mut Diagnostic)], edition: Edition, ) { @@ -606,10 +609,10 @@ fn handle_lints( } let mut diag_severity = - lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition); + lint_severity_at(sema, krate, node, &lint_groups(&diag.code, edition)); if let outline_diag_severity @ Some(_) = - find_outline_mod_lint_severity(sema, node, diag, edition) + find_outline_mod_lint_severity(sema, krate, node, diag, edition) { diag_severity = outline_diag_severity; } @@ -632,6 +635,7 @@ fn default_lint_severity(lint: &Lint, edition: Edition) -> Severity { fn find_outline_mod_lint_severity( sema: &Semantics<'_, RootDatabase>, + krate: hir::Crate, node: &InFile<SyntaxNode>, diag: &Diagnostic, edition: Edition, @@ -644,123 +648,47 @@ fn find_outline_mod_lint_severity( let mod_def = sema.to_module_def(&mod_node)?; let module_source_file = sema.module_definition_node(mod_def); - let mut result = None; let lint_groups = lint_groups(&diag.code, edition); lint_attrs( sema, - &ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"), - edition, + krate, + ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"), ) - .for_each(|(lint, severity)| { - if lint_groups.contains(&lint) { - result = Some(severity); - } - }); - result + .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity)) } fn lint_severity_at( sema: &Semantics<'_, RootDatabase>, + krate: hir::Crate, node: &InFile<SyntaxNode>, lint_groups: &LintGroups, - edition: Edition, ) -> Option<Severity> { node.value .ancestors() .filter_map(ast::AnyHasAttrs::cast) .find_map(|ancestor| { - lint_attrs(sema, &ancestor, edition) + lint_attrs(sema, krate, ancestor) .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity)) }) .or_else(|| { - lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition) + lint_severity_at(sema, krate, &sema.find_parent_file(node.file_id)?, lint_groups) }) } // FIXME: Switch this to analysis' `expand_cfg_attr`. -fn lint_attrs<'a>( - sema: &'a Semantics<'a, RootDatabase>, - ancestor: &'a ast::AnyHasAttrs, - edition: Edition, -) -> impl Iterator<Item = (SmolStr, Severity)> + 'a { - ast::attrs_including_inner(ancestor) - .filter_map(|attr| { - attr.as_simple_call().and_then(|(name, value)| match &*name { - "allow" | "expect" => Some(Either::Left(iter::once((Severity::Allow, value)))), - "warn" => Some(Either::Left(iter::once((Severity::Warning, value)))), - "forbid" | "deny" => Some(Either::Left(iter::once((Severity::Error, value)))), - "cfg_attr" => { - let mut lint_attrs = Vec::new(); - cfg_attr_lint_attrs(sema, &value, &mut lint_attrs); - Some(Either::Right(lint_attrs.into_iter())) - } - _ => None, - }) - }) - .flatten() - .flat_map(move |(severity, lints)| { - parse_tt_as_comma_sep_paths(lints, edition).into_iter().flat_map(move |lints| { - // Rejoin the idents with `::`, so we have no spaces in between. - lints.into_iter().map(move |lint| { - ( - lint.segments().filter_map(|segment| segment.name_ref()).join("::").into(), - severity, - ) - }) - }) - }) -} - -fn cfg_attr_lint_attrs( +fn lint_attrs( sema: &Semantics<'_, RootDatabase>, - value: &ast::TokenTree, - lint_attrs: &mut Vec<(Severity, ast::TokenTree)>, -) { - let prev_len = lint_attrs.len(); - - let mut iter = value.token_trees_and_tokens().filter(|it| match it { - NodeOrToken::Node(_) => true, - NodeOrToken::Token(it) => !it.kind().is_trivia(), - }); - - // Skip the condition. - for value in &mut iter { - if value.as_token().is_some_and(|it| it.kind() == T![,]) { - break; - } - } - - while let Some(value) = iter.next() { - if let Some(token) = value.as_token() - && token.kind() == SyntaxKind::IDENT - { - let severity = match token.text() { - "allow" | "expect" => Some(Severity::Allow), - "warn" => Some(Severity::Warning), - "forbid" | "deny" => Some(Severity::Error), - "cfg_attr" => { - if let Some(NodeOrToken::Node(value)) = iter.next() { - cfg_attr_lint_attrs(sema, &value, lint_attrs); - } - None - } - _ => None, - }; - if let Some(severity) = severity { - let lints = iter.next(); - if let Some(NodeOrToken::Node(lints)) = lints { - lint_attrs.push((severity, lints)); - } - } - } - } - - if prev_len != lint_attrs.len() - && let Some(false) | None = sema.check_cfg_attr(value) - { - // Discard the attributes when the condition is false. - lint_attrs.truncate(prev_len); - } + krate: hir::Crate, + ancestor: ast::AnyHasAttrs, +) -> impl Iterator<Item = (SmolStr, Severity)> { + sema.lint_attrs(krate, ancestor).rev().map(|(lint_attr, lint)| { + let severity = match lint_attr { + hir::LintAttr::Allow | hir::LintAttr::Expect => Severity::Allow, + hir::LintAttr::Warn => Severity::Warning, + hir::LintAttr::Deny | hir::LintAttr::Forbid => Severity::Error, + }; + (lint, severity) + }) } #[derive(Debug)] diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index 0620bd26fe..1900b069e0 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -30,5 +30,9 @@ triomphe.workspace = true test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index 977dfb7466..958a26324f 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -63,6 +63,11 @@ // // foo($a, $b) ==>> ($a).foo($b) // ``` +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod fragments; mod from_comment; mod matching; diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 9d38a860a0..d43f13b79d 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -28,7 +28,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< let sema = Semantics::new(db); let file_id = sema.attach_first_edition(position.file_id); let file = sema.parse(file_id); - let krate = sema.file_to_module_def(file_id.file_id(db))?.krate().into(); + let krate = sema.file_to_module_def(file_id.file_id(db))?.krate(db).into(); let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 1, diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index e1db370d44..b00aa4d0ca 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -139,7 +139,7 @@ pub(crate) fn goto_definition( if let Definition::ExternCrateDecl(crate_def) = def { return crate_def .resolved_crate(db) - .map(|it| it.root_module().to_nav(sema.db)) + .map(|it| it.root_module(db).to_nav(db)) .into_iter() .flatten() .collect(); @@ -262,7 +262,7 @@ fn try_lookup_macro_def_in_macro_use( let extern_crate = sema.to_def(&extern_crate)?; let krate = extern_crate.resolved_crate(sema.db)?; - for mod_def in krate.root_module().declarations(sema.db) { + for mod_def in krate.root_module(sema.db).declarations(sema.db) { if let ModuleDef::Macro(mac) = mod_def && mac.name(sema.db).as_str() == token.text() && let Some(nav) = mac.try_to_nav(sema) diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index a29da4f258..4bf9b82cc8 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs @@ -384,7 +384,7 @@ trait Bar {} fn test() { #[derive(Copy)] - // ^^^^^^^^^^^^ + // ^^^^ struct Foo$0; impl Foo {} diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index a8929859bc..9dc72a87af 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -464,7 +464,7 @@ pub(super) fn path( item_name: Option<String>, edition: Edition, ) -> String { - let crate_name = module.krate().display_name(db).as_ref().map(|it| it.to_string()); + let crate_name = module.krate(db).display_name(db).as_ref().map(|it| it.to_string()); let module_path = module .path_to_root(db) .into_iter() diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 071eacf660..5330b7eb99 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -11169,3 +11169,60 @@ fn foo() { "#]], ); } + +#[test] +fn hover_trait_impl_shows_generic_args() { + // Single generic arg + check( + r#" +trait Foo<T> { + fn foo(&self) {} +} + +impl<T> Foo<()> for T { + fn fo$0o(&self) {} +} + +fn bar() { + ().foo(); +} +"#, + expect![[r#" + *foo* + + ```rust + ra_test_fixture + ``` + + ```rust + impl<T> Foo<()> for T + fn foo(&self) + ``` + "#]], + ); + + // Multiple generic args + check( + r#" +trait Foo<A, B> { + fn foo(&self) {} +} + +impl<T> Foo<i32, u64> for T { + fn fo$0o(&self) {} +} +"#, + expect![[r#" + *foo* + + ```rust + ra_test_fixture + ``` + + ```rust + impl<T> Foo<i32, u64> for T + fn foo(&self) + ``` + "#]], + ); +} diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index deacc7fafb..03674978d5 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -320,6 +320,7 @@ pub struct InlayHintsConfig<'a> { pub implied_dyn_trait_hints: bool, pub lifetime_elision_hints: LifetimeElisionHints, pub param_names_for_lifetime_elision_hints: bool, + pub hide_inferred_type_hints: bool, pub hide_named_constructor_hints: bool, pub hide_closure_initialization_hints: bool, pub hide_closure_parameter_hints: bool, @@ -810,7 +811,7 @@ fn hint_iterator<'db>( ) -> Option<(hir::Trait, hir::TypeAlias, hir::Type<'db>)> { let db = sema.db; let strukt = ty.strip_references().as_adt()?; - let krate = strukt.module(db).krate(); + let krate = strukt.module(db).krate(db); if krate != famous_defs.core()? { return None; } @@ -900,6 +901,7 @@ mod tests { adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, + hide_inferred_type_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, hide_closure_parameter_hints: false, diff --git a/crates/ide/src/inlay_hints/placeholders.rs b/crates/ide/src/inlay_hints/placeholders.rs index 96d2c17c03..e535b92a57 100644 --- a/crates/ide/src/inlay_hints/placeholders.rs +++ b/crates/ide/src/inlay_hints/placeholders.rs @@ -20,7 +20,7 @@ pub(super) fn type_hints( display_target: DisplayTarget, placeholder: InferType, ) -> Option<()> { - if !config.type_hints { + if !config.type_hints || config.hide_inferred_type_hints { return None; } @@ -73,4 +73,22 @@ fn foo() { "#, ); } + + #[test] + fn hide_inferred_types() { + check_with_config( + InlayHintsConfig { + type_hints: true, + hide_inferred_type_hints: true, + ..DISABLED_CONFIG + }, + r#" +struct S<T>(T); + +fn foo() { + let t: (_, _, [_; _]) = (1_u32, S(2), [false] as _); +} + "#, + ); + } } diff --git a/crates/ide/src/interpret.rs b/crates/ide/src/interpret.rs index 05cd145033..791da00bb6 100644 --- a/crates/ide/src/interpret.rs +++ b/crates/ide/src/interpret.rs @@ -45,7 +45,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura None => format!("file://{path} range {text_range:?}"), } }; - let display_target = def.module(db).krate().to_display_target(db); + let display_target = def.module(db).krate(db).to_display_target(db); let start_time = Instant::now(); let res = match def { DefWithBody::Function(it) => it.eval(db, span_formatter), diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 4aa9eb98a1..1c1389ca7a 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -284,10 +284,10 @@ fn def_to_non_local_moniker( from_crate: Crate, ) -> Option<Moniker> { let module = match definition { - Definition::Module(module) if module.is_crate_root() => module, + Definition::Module(module) if module.is_crate_root(db) => module, _ => definition.module(db)?, }; - let krate = module.krate(); + let krate = module.krate(db); let edition = krate.edition(db); // Add descriptors for this definition and every enclosing definition. @@ -321,7 +321,7 @@ fn def_to_non_local_moniker( }); } else { match def { - Definition::Module(module) if module.is_crate_root() => { + Definition::Module(module) if module.is_crate_root(db) => { // only include `crate` namespace by itself because we prefer // `rust-analyzer cargo foo . bar/` over `rust-analyzer cargo foo . crate/bar/` if reverse_description.is_empty() { @@ -389,7 +389,8 @@ fn display<'db, T: HirDisplay<'db>>(db: &'db RootDatabase, module: hir::Module, Ok(result) => result, // Fallback on display variant that always succeeds Err(_) => { - let fallback_result = it.display(db, module.krate().to_display_target(db)).to_string(); + let fallback_result = + it.display(db, module.krate(db).to_display_target(db)).to_string(); tracing::error!( display = %fallback_result, "`display_source_code` failed; falling back to using display" ); diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 4c4d57f0f4..29530ed02b 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -160,7 +160,7 @@ impl NavigationTarget { ); res.docs = module.docs(db).map(Documentation::into_owned); res.description = Some( - module.display(db, module.krate().to_display_target(db)).to_string(), + module.display(db, module.krate(db).to_display_target(db)).to_string(), ); res }, @@ -225,7 +225,7 @@ impl NavigationTarget { } } -impl TryToNav for FileSymbol { +impl<'db> TryToNav for FileSymbol<'db> { fn try_to_nav( &self, sema: &Semantics<'_, RootDatabase>, @@ -468,7 +468,7 @@ impl ToNav for hir::Module { impl ToNav for hir::Crate { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> { - self.root_module().to_nav(db) + self.root_module(db).to_nav(db) } } @@ -511,7 +511,7 @@ impl TryToNav for hir::ExternCrateDecl { let focus = value .rename() .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right)); - let krate = self.module(db).krate(); + let krate = self.module(db).krate(db); Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map( |(FileRange { file_id, range: full_range }, focus_range)| { @@ -539,7 +539,7 @@ impl TryToNav for hir::Field { ) -> Option<UpmappingResult<NavigationTarget>> { let db = sema.db; let src = self.source(db)?; - let krate = self.parent_def(db).module(db).krate(); + let krate = self.parent_def(db).module(db).krate(db); let field_source = match &src.value { FieldSource::Named(it) => { diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 9e17ab2bab..a61be93ea9 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -372,7 +372,7 @@ pub(crate) fn runnable_mod( .rev() .filter_map(|module| { module.name(sema.db).map(|mod_name| { - mod_name.display(sema.db, module.krate().edition(sema.db)).to_string() + mod_name.display(sema.db, module.krate(sema.db).edition(sema.db)).to_string() }) }) .join("::"); @@ -401,7 +401,7 @@ pub(crate) fn runnable_impl( sema: &Semantics<'_, RootDatabase>, def: &hir::Impl, ) -> Option<Runnable> { - let display_target = def.module(sema.db).krate().to_display_target(sema.db); + let display_target = def.module(sema.db).krate(sema.db).to_display_target(sema.db); let edition = display_target.edition; let attrs = def.attrs(sema.db); if !has_runnable_doc_test(sema.db, &attrs) { @@ -466,7 +466,7 @@ fn runnable_mod_outline_definition( .rev() .filter_map(|module| { module.name(sema.db).map(|mod_name| { - mod_name.display(sema.db, module.krate().edition(sema.db)).to_string() + mod_name.display(sema.db, module.krate(sema.db).edition(sema.db)).to_string() }) }) .join("::"); diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 0cf2e15bc6..7749f8e2f2 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -10,7 +10,7 @@ use ide_db::{ documentation::Documentation, famous_defs::FamousDefs, }; -use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange}; +use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange}; use crate::navigation_target::UpmappingResult; use crate::{ @@ -102,7 +102,7 @@ pub struct StaticIndexedFile { fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); + Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); let mut modules = Vec::new(); while let Some(module) = worklist.pop() { @@ -136,12 +136,12 @@ fn documentation_for_definition( } // FIXME: This is a weird function -fn get_definitions( - sema: &Semantics<'_, RootDatabase>, +fn get_definitions<'db>( + sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option<ArrayVec<Definition, 2>> { +) -> Option<ArrayVec<(Definition, Option<hir::GenericSubstitution<'db>>), 2>> { for token in sema.descend_into_macros_exact(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); if let Some(defs) = def && !defs.is_empty() { @@ -183,6 +183,7 @@ impl StaticIndex<'_> { adjustment_hints_hide_outside_unsafe: false, implicit_drop_hints: false, implied_dyn_trait_hints: false, + hide_inferred_type_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, hide_closure_parameter_hints: false, @@ -225,12 +226,6 @@ impl StaticIndex<'_> { show_drop_glue: true, minicore: MiniCore::default(), }; - let tokens = tokens.filter(|token| { - matches!( - token.kind(), - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] - ) - }); let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] }; let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| { @@ -290,9 +285,9 @@ impl StaticIndex<'_> { let range = token.text_range(); let node = token.parent().unwrap(); match hir::attach_db(self.db, || get_definitions(&sema, token.clone())) { - Some(it) => { - for i in it { - add_token(i, range, &node); + Some(defs) => { + for (def, _) in defs { + add_token(def, range, &node); } } None => continue, diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 8937f8249c..044fd3f5ac 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -501,7 +501,7 @@ pub(super) fn highlight_def( ), Definition::Module(module) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); - if module.is_crate_root() { + if module.is_crate_root(db) { h |= HlMod::CrateRoot; } @@ -747,7 +747,7 @@ fn highlight_method_call( h |= HlMod::Trait; } - let def_crate = func.module(sema.db).krate(); + let def_crate = func.module(sema.db).krate(sema.db); let is_from_other_crate = krate.as_ref().map_or(false, |krate| def_crate != *krate); let is_from_builtin_crate = def_crate.is_builtin(sema.db); let is_public = func.visibility(sema.db) == hir::Visibility::Public; diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html index e3daeef841..982e89dfab 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span> <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span> - <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle"><</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">></span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span> + <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle"><</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">></span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="builtin_type">u32</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span><span class="comma">,</span> <span class="field declaration">field2</span><span class="colon">:</span> <span class="punctuation">&</span><span class="struct">Innerest</span> <span class="brace">}</span> <span class="brace">}</span> <span class="brace">}</span> <span class="brace">}</span> diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index b7510e3aba..89a5e434f9 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -1183,7 +1183,7 @@ fn main() { foo!(Bar); fn func(_: y::Bar) { mod inner { - struct Innerest<const C: usize> { field: [(); {C}] } + struct Innerest<const C: usize> { field: [u32; {C}], field2: &Innerest } } } } diff --git a/crates/ide/src/test_explorer.rs b/crates/ide/src/test_explorer.rs index bd60ffe559..4792566f5f 100644 --- a/crates/ide/src/test_explorer.rs +++ b/crates/ide/src/test_explorer.rs @@ -135,11 +135,11 @@ fn find_module_id_and_test_parents( module: Module, ) -> Option<(Vec<TestItem>, String)> { let Some(parent) = module.parent(sema.db) else { - let name = module.krate().display_name(sema.db)?.to_string(); + let name = module.krate(sema.db).display_name(sema.db)?.to_string(); return Some(( vec![TestItem { id: name.clone(), - kind: TestItemKind::Crate(module.krate().into()), + kind: TestItemKind::Crate(module.krate(sema.db).into()), label: name.clone(), parent: None, file: None, @@ -181,7 +181,7 @@ pub(crate) fn discover_tests_in_crate( let kind = TestItemKind::Crate(crate_id); let crate_test_id = crate_test_id.to_string(); let crate_id: Crate = crate_id.into(); - let module = crate_id.root_module(); + let module = crate_id.root_module(db); let mut r = vec![TestItem { id: crate_test_id.clone(), kind, diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index 37eb3d4101..462f1c69fa 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -524,4 +524,5 @@ define_symbols! { arbitrary_self_types, arbitrary_self_types_pointers, supertrait_item_shadowing, + define_opaque, } diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index a486219efa..28fbfecfde 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -2,6 +2,12 @@ //! for incorporating changes. // Note, don't remove any public api from this. This API is consumed by external tools // to run rust-analyzer as a library. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 3dd2c1f6c4..4478bf4e37 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -3,9 +3,10 @@ //! NOTE: The crate is undergoing refactors, don't believe everything the docs //! say :-) //! -//! The parser doesn't know about concrete representation of tokens and syntax -//! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As -//! a consequence, this crate does not contain a lexer. +//! The parser doesn't know about concrete representation of tokens +//! and syntax trees. Abstract [`Input`] and [`Output`] traits are +//! used to provide tokens instead. As a consequence, this crate does +//! not contain a lexer. //! //! The [`Parser`] struct from the [`parser`] module is a cursor into the //! sequence of tokens. Parsing routines use [`Parser`] to inspect current @@ -23,6 +24,8 @@ #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; +#[cfg(feature = "in-rust-tree")] extern crate rustc_lexer; mod event; diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index 2c6a82bf0c..d6d9ed4676 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -1,5 +1,5 @@ -//! Thin wrappers around [`camino::path`], distinguishing between absolute and -//! relative paths. +//! Thin wrappers around [`camino::Utf8PathBuf`], distinguishing +//! between absolute and relative paths. use std::{ borrow::Borrow, diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 18a2408c40..4de1a3e5dd 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -34,6 +34,8 @@ semver.workspace = true [features] sysroot-abi = ["proc-macro-srv", "proc-macro-srv/sysroot-abi"] +default = [] +in-rust-tree = [] [lints] workspace = true diff --git a/crates/proc-macro-api/src/legacy_protocol/msg.rs b/crates/proc-macro-api/src/legacy_protocol/msg.rs index 680372210a..a6e228d977 100644 --- a/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -17,19 +17,19 @@ pub enum Request { // As such, this is the only request that needs to be supported across all protocol versions // and by keeping it first, we ensure it always has the same discriminant encoding in postcard /// Performs an API version check between the client and the server. - /// Since [`VERSION_CHECK_VERSION`] + /// Since [`crate::version::VERSION_CHECK_VERSION`] ApiVersionCheck {}, /// Retrieves a list of macros from a given dynamic library. - /// Since [`NO_VERSION_CHECK_VERSION`] + /// Since [`crate::version::NO_VERSION_CHECK_VERSION`] ListMacros { dylib_path: Utf8PathBuf }, /// Expands a procedural macro. - /// Since [`NO_VERSION_CHECK_VERSION`] + /// Since [`crate::version::NO_VERSION_CHECK_VERSION`] ExpandMacro(Box<ExpandMacro>), /// Sets server-specific configurations. - /// Since [`RUST_ANALYZER_SPAN_SUPPORT`] + /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`] SetConfig(ServerConfig), } @@ -51,23 +51,23 @@ pub enum Response { // As such, this is the only request that needs to be supported across all protocol versions // and by keeping it first, we ensure it always has the same discriminant encoding in postcard /// Returns the API version supported by the server. - /// Since [`NO_VERSION_CHECK_VERSION`] + /// Since [`crate::version::NO_VERSION_CHECK_VERSION`] ApiVersionCheck(u32), /// Returns a list of available macros in a dynamic library. - /// Since [`NO_VERSION_CHECK_VERSION`] + /// Since [`crate::version::NO_VERSION_CHECK_VERSION`] ListMacros(Result<Vec<(String, ProcMacroKind)>, String>), /// Returns result of a macro expansion. - /// Since [`NO_VERSION_CHECK_VERSION`] + /// Since [`crate::version::NO_VERSION_CHECK_VERSION`] ExpandMacro(Result<FlatTree, PanicMessage>), /// Confirms the application of a configuration update. - /// Since [`RUST_ANALYZER_SPAN_SUPPORT`] + /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`] SetConfig(ServerConfig), /// Returns the result of a macro expansion, including extended span data. - /// Since [`RUST_ANALYZER_SPAN_SUPPORT`] + /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`] ExpandMacroExtended(Result<ExpandMacroExtended, PanicMessage>), } @@ -185,7 +185,7 @@ mod tests { use super::*; - fn fixture_token_tree() -> TopSubtree<Span> { + fn fixture_token_tree_top_many_none() -> TopSubtree<Span> { let anchor = SpanAnchor { file_id: span::EditionedFileId::new( span::FileId::from_raw(0xe4e4e), @@ -201,7 +201,7 @@ mod tests { ctx: SyntaxContext::root(Edition::CURRENT), }, close: Span { - range: TextRange::empty(TextSize::new(19)), + range: TextRange::empty(TextSize::new(0)), anchor, ctx: SyntaxContext::root(Edition::CURRENT), }, @@ -259,10 +259,18 @@ mod tests { ctx: SyntaxContext::root(Edition::CURRENT), }, ); + builder.open( + DelimiterKind::Bracket, + Span { + range: TextRange::at(TextSize::new(15), TextSize::of('[')), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }, + ); builder.push(Leaf::Literal(Literal { symbol: sym::INTEGER_0, span: Span { - range: TextRange::at(TextSize::new(15), TextSize::of("0u32")), + range: TextRange::at(TextSize::new(16), TextSize::of("0u32")), anchor, ctx: SyntaxContext::root(Edition::CURRENT), }, @@ -270,45 +278,140 @@ mod tests { suffix: Some(sym::u32), })); builder.close(Span { - range: TextRange::at(TextSize::new(19), TextSize::of('}')), + range: TextRange::at(TextSize::new(20), TextSize::of(']')), anchor, ctx: SyntaxContext::root(Edition::CURRENT), }); + builder.close(Span { + range: TextRange::at(TextSize::new(21), TextSize::of('}')), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }); + + builder.build() + } + + fn fixture_token_tree_top_empty_none() -> TopSubtree<Span> { + let anchor = SpanAnchor { + file_id: span::EditionedFileId::new( + span::FileId::from_raw(0xe4e4e), + span::Edition::CURRENT, + ), + ast_id: ROOT_ERASED_FILE_AST_ID, + }; + + let builder = TopSubtreeBuilder::new(Delimiter { + open: Span { + range: TextRange::empty(TextSize::new(0)), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }, + close: Span { + range: TextRange::empty(TextSize::new(0)), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }, + kind: DelimiterKind::Invisible, + }); + + builder.build() + } + + fn fixture_token_tree_top_empty_brace() -> TopSubtree<Span> { + let anchor = SpanAnchor { + file_id: span::EditionedFileId::new( + span::FileId::from_raw(0xe4e4e), + span::Edition::CURRENT, + ), + ast_id: ROOT_ERASED_FILE_AST_ID, + }; + + let builder = TopSubtreeBuilder::new(Delimiter { + open: Span { + range: TextRange::empty(TextSize::new(0)), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }, + close: Span { + range: TextRange::empty(TextSize::new(0)), + anchor, + ctx: SyntaxContext::root(Edition::CURRENT), + }, + kind: DelimiterKind::Brace, + }); + builder.build() } #[test] fn test_proc_macro_rpc_works() { - let tt = fixture_token_tree(); - for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION { - let mut span_data_table = Default::default(); - let task = ExpandMacro { - data: ExpandMacroData { - macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table), - macro_name: Default::default(), - attributes: None, - has_global_spans: ExpnGlobals { - serialize: true, - def_site: 0, - call_site: 0, - mixed_site: 0, + for tt in [ + fixture_token_tree_top_many_none, + fixture_token_tree_top_empty_none, + fixture_token_tree_top_empty_brace, + ] { + for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION { + let tt = tt(); + let mut span_data_table = Default::default(); + let task = ExpandMacro { + data: ExpandMacroData { + macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table), + macro_name: Default::default(), + attributes: None, + has_global_spans: ExpnGlobals { + serialize: true, + def_site: 0, + call_site: 0, + mixed_site: 0, + }, + span_data_table: Vec::new(), }, - span_data_table: Vec::new(), - }, - lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), - env: Default::default(), - current_dir: Default::default(), - }; - - let json = serde_json::to_string(&task).unwrap(); - // println!("{}", json); - let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - - assert!( - tt == back.data.macro_body.to_subtree_resolved(v, &span_data_table), - "version: {v}" - ); + lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), + env: Default::default(), + current_dir: Default::default(), + }; + + let json = serde_json::to_string(&task).unwrap(); + // println!("{}", json); + let back: ExpandMacro = serde_json::from_str(&json).unwrap(); + + assert_eq!( + tt, + back.data.macro_body.to_subtree_resolved(v, &span_data_table), + "version: {v}" + ); + } + } + } + + #[test] + #[cfg(feature = "sysroot-abi")] + fn test_proc_macro_rpc_works_ts() { + for tt in [ + fixture_token_tree_top_many_none, + fixture_token_tree_top_empty_none, + fixture_token_tree_top_empty_brace, + ] { + let tt = tt(); + for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION { + let mut span_data_table = Default::default(); + let flat_tree = FlatTree::from_subtree(tt.view(), v, &mut span_data_table); + assert_eq!( + tt, + flat_tree.clone().to_subtree_resolved(v, &span_data_table), + "version: {v}" + ); + let ts = flat_tree.to_tokenstream_resolved(v, &span_data_table, |a, b| a.cover(b)); + let call_site = *span_data_table.first().unwrap(); + let mut span_data_table = Default::default(); + assert_eq!( + tt, + FlatTree::from_tokenstream(ts.clone(), v, call_site, &mut span_data_table) + .to_subtree_resolved(v, &span_data_table), + "version: {v}, ts:\n{ts:#?}" + ); + } } } } diff --git a/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs b/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs index 92e9038554..1ac8cd4006 100644 --- a/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs +++ b/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs @@ -85,7 +85,7 @@ pub fn deserialize_span_data_index_map(map: &[u32]) -> SpanDataIndexMap { .collect() } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct FlatTree { subtree: Vec<u32>, literal: Vec<u32>, @@ -615,14 +615,17 @@ impl<'a, T: SpanTransformer> root: &'a proc_macro_srv::TokenStream<T::Span>, ) { let call_site = self.token_id_of(call_site); - self.subtree.push(SubtreeRepr { - open: call_site, - close: call_site, - kind: tt::DelimiterKind::Invisible, - tt: [!0, !0], - }); - self.work.push_back((0, root.len(), Some(root.iter()))); - + if let Some(group) = root.as_single_group() { + self.enqueue(group); + } else { + self.subtree.push(SubtreeRepr { + open: call_site, + close: call_site, + kind: tt::DelimiterKind::Invisible, + tt: [!0, !0], + }); + self.work.push_back((0, root.len(), Some(root.iter()))); + } while let Some((idx, len, group)) = self.work.pop_front() { self.group(idx, len, group); } @@ -962,6 +965,11 @@ impl<T: SpanTransformer> Reader<'_, T> { }; res[i] = Some(g); } - res[0].take().unwrap().stream.unwrap_or_default() + let group = res[0].take().unwrap(); + if group.delimiter == proc_macro_srv::Delimiter::None { + group.stream.unwrap_or_default() + } else { + TokenStream::new(vec![proc_macro_srv::TokenTree::Group(group)]) + } } } diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index f0c7ce7efd..85b250eddf 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -11,6 +11,10 @@ feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) )] #![allow(internal_features)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; mod codec; mod framing; diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index e31ab86bdd..d6a8d27bfc 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -58,7 +58,9 @@ impl ProcMacroServerProcess { if v.pre.as_str() == "nightly" { *v > VERSION } else { *v >= VERSION } }); - let formats: &[_] = if has_working_format_flag { + let formats: &[_] = if std::env::var_os("RUST_ANALYZER_USE_POSTCARD").is_some() + && has_working_format_flag + { &[ (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }), diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index c3838a8e61..93319df824 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -83,31 +83,10 @@ impl<'env> ProcMacroSrv<'env> { } pub fn join_spans(&self, first: Span, second: Span) -> Option<Span> { - // We can't modify the span range for fixup spans, those are meaningful to fixup, so just - // prefer the non-fixup span. - if first.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER { - return Some(second); - } - if second.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER { - return Some(first); - } - // FIXME: Once we can talk back to the client, implement a "long join" request for anchors - // that differ in [AstId]s as joining those spans requires resolving the AstIds. - if first.anchor != second.anchor { - return None; - } - // Differing context, we can't merge these so prefer the one that's root - if first.ctx != second.ctx { - if first.ctx.is_root() { - return Some(second); - } else if second.ctx.is_root() { - return Some(first); - } - } - Some(Span { - range: first.range.cover(second.range), - anchor: second.anchor, - ctx: second.ctx, + first.join(second, |_, _| { + // FIXME: Once we can talk back to the client, implement a "long join" request for anchors + // that differ in [AstId]s as joining those spans requires resolving the AstIds. + None }) } } diff --git a/crates/proc-macro-srv/src/token_stream.rs b/crates/proc-macro-srv/src/token_stream.rs index e134a47f8c..36827d2561 100644 --- a/crates/proc-macro-srv/src/token_stream.rs +++ b/crates/proc-macro-srv/src/token_stream.rs @@ -40,6 +40,13 @@ impl<S> TokenStream<S> { TokenStreamIter::new(self)
}
+ pub fn as_single_group(&self) -> Option<&Group<S>> {
+ match &**self.0 {
+ [TokenTree::Group(group)] => Some(group),
+ _ => None,
+ }
+ }
+
pub(crate) fn from_str(s: &str, span: S) -> Result<Self, String>
where
S: SpanLike + Copy,
diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 7e0b1f75f7..f825a456de 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -39,5 +39,9 @@ toolchain.workspace = true [dev-dependencies] expect-test = "1.5.1" +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 731104981a..6e1a3f37ff 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -305,7 +305,7 @@ impl TargetKind { /// If this is a valid cargo target, returns the name cargo uses in command line arguments /// and output, otherwise None. - /// https://docs.rs/cargo_metadata/latest/cargo_metadata/enum.TargetKind.html + /// <https://docs.rs/cargo_metadata/latest/cargo_metadata/enum.TargetKind.html> pub fn as_cargo_target(self) -> Option<&'static str> { match self { TargetKind::Bin => Some("bin"), diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index 910bc0a96b..3414b52d45 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -1,7 +1,7 @@ //! In rust-analyzer, we maintain a strict separation between pure abstract //! semantic project model and a concrete model of a particular build system. //! -//! Pure model is represented by the [`base_db::CrateGraph`] from another crate. +//! Pure model is represented by the `base_db::CrateGraph` from another crate. //! //! In this crate, we are concerned with "real world" project models. //! @@ -13,7 +13,14 @@ //! * Project discovery (where's the relevant Cargo.toml for the current dir). //! * Custom build steps (`build.rs` code generation and compilation of //! procedural macros). -//! * Lowering of concrete model to a [`base_db::CrateGraph`] +//! * Lowering of concrete model to a `base_db::CrateGraph` + +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; pub mod project_json; pub mod toolchain_info { diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index d3e1f11d78..041b9accf4 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -1,6 +1,6 @@ //! `rust-project.json` file format. //! -//! This format is spiritually a serialization of [`base_db::CrateGraph`]. The +//! This format is spiritually a serialization of `base_db::CrateGraph`. The //! idea here is that people who do not use Cargo, can instead teach their build //! system to generate `rust-project.json` which can be ingested by //! rust-analyzer. diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index e02891eca2..10abb21ace 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -1044,7 +1044,7 @@ impl ProjectWorkspace { /// Returns `true` if the project workspace is [`Json`]. /// - /// [`Json`]: ProjectWorkspace::Json + /// [`Json`]: ProjectWorkspaceKind::Json #[must_use] pub fn is_json(&self) -> bool { matches!(self.kind, ProjectWorkspaceKind::Json { .. }) diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 2e48c5a5a6..d1283ca59e 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -98,12 +98,16 @@ syntax-bridge.workspace = true jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["stdx/force-always-assert"] in-rust-tree = [ - "syntax/in-rust-tree", - "parser/in-rust-tree", - "hir/in-rust-tree", + "cfg/in-rust-tree", "hir-def/in-rust-tree", "hir-ty/in-rust-tree", + "hir/in-rust-tree", + "ide-ssr/in-rust-tree", + "ide/in-rust-tree", "load-cargo/in-rust-tree", + "parser/in-rust-tree", + "proc-macro-api/in-rust-tree", + "syntax/in-rust-tree", ] dhat = ["dep:dhat"] diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 767672fc2f..f39ab1301f 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -10,8 +10,8 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::{ - Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasSource, HirDisplay, ModuleDef, Name, - crate_lang_items, + Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasCrate, HasSource, HirDisplay, ModuleDef, + Name, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, next_solver::{DbInterner, GenericArgs}, }; @@ -206,7 +206,7 @@ impl flags::AnalysisStats { let mut visited_modules = FxHashSet::default(); let mut visit_queue = Vec::new(); for &krate in &krates { - let module = krate.root_module(); + let module = krate.root_module(db); let file_id = module.definition_source_file_id(db); let file_id = file_id.original_file(db); @@ -391,7 +391,10 @@ impl flags::AnalysisStats { let Err(e) = db.layout_of_adt( hir_def::AdtId::from(a), GenericArgs::new_from_iter(interner, []), - db.trait_environment(a.into()), + hir_ty::ParamEnvAndCrate { + param_env: db.trait_environment(a.into()), + krate: a.krate(db).into(), + }, ) else { continue; }; @@ -766,7 +769,7 @@ impl flags::AnalysisStats { for &body_id in bodies { let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); - let display_target = module.krate().to_display_target(db); + let display_target = module.krate(db).to_display_target(db); if let Some(only_name) = self.only.as_deref() && name.display(db, Edition::LATEST).to_string() != only_name && full_name(db, body_id, module) != only_name @@ -1219,6 +1222,7 @@ impl flags::AnalysisStats { implied_dyn_trait_hints: true, lifetime_elision_hints: ide::LifetimeElisionHints::Always, param_names_for_lifetime_elision_hints: true, + hide_inferred_type_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, hide_closure_parameter_hints: false, @@ -1286,7 +1290,7 @@ impl flags::AnalysisStats { fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> String { module - .krate() + .krate(db) .display_name(db) .map(|it| it.canonical_name().as_str().to_owned()) .into_iter() diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 82590c8e70..776069f155 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -68,8 +68,12 @@ impl flags::Diagnostics { if !visited_files.contains(&file_id) { let message = format!("processing {}", _vfs.file_path(file_id.file_id(db))); bar.set_message(move || message.clone()); - let crate_name = - module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned(); + let crate_name = module + .krate(db) + .display_name(db) + .as_deref() + .unwrap_or(&sym::unknown) + .to_owned(); for diagnostic in analysis .full_diagnostics( &DiagnosticsConfig::test_sample(), @@ -122,7 +126,7 @@ impl flags::Diagnostics { fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); + Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); let mut modules = Vec::new(); while let Some(module) = worklist.pop() { diff --git a/crates/rust-analyzer/src/cli/run_tests.rs b/crates/rust-analyzer/src/cli/run_tests.rs index 60b33f0a30..82ace8c8b3 100644 --- a/crates/rust-analyzer/src/cli/run_tests.rs +++ b/crates/rust-analyzer/src/cli/run_tests.rs @@ -78,7 +78,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = Crate::all(db) .into_iter() .filter(|x| x.origin(db).is_local()) - .map(|krate| krate.root_module()) + .map(|krate| krate.root_module(db)) .collect(); let mut modules = Vec::new(); diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index fbf3082e1b..271d2507bc 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -604,6 +604,29 @@ pub mod example_mod { } #[test] + fn operator_overload() { + check_symbol( + r#" +//- minicore: add +//- /workspace/lib.rs crate:main +use core::ops::AddAssign; + +struct S; + +impl AddAssign for S { + fn add_assign(&mut self, _rhs: Self) {} +} + +fn main() { + let mut s = S; + s +=$0 S; +} +"#, + "rust-analyzer cargo main . impl#[S][`AddAssign<Self>`]add_assign().", + ); + } + + #[test] fn symbol_for_trait() { check_symbol( r#" diff --git a/crates/rust-analyzer/src/cli/unresolved_references.rs b/crates/rust-analyzer/src/cli/unresolved_references.rs index a400f86778..294add682d 100644 --- a/crates/rust-analyzer/src/cli/unresolved_references.rs +++ b/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -64,8 +64,12 @@ impl flags::UnresolvedReferences { let file_id = module.definition_source_file_id(db).original_file(db); let file_id = file_id.file_id(db); if !visited_files.contains(&file_id) { - let crate_name = - module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned(); + let crate_name = module + .krate(db) + .display_name(db) + .as_deref() + .unwrap_or(&sym::unknown) + .to_owned(); let file_path = vfs.file_path(file_id); eprintln!("processing crate: {crate_name}, module: {file_path}",); @@ -93,7 +97,7 @@ impl flags::UnresolvedReferences { fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); + Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); let mut modules = Vec::new(); while let Some(module) = worklist.pop() { diff --git a/crates/rust-analyzer/src/command.rs b/crates/rust-analyzer/src/command.rs index 41055272b1..2f052618cd 100644 --- a/crates/rust-analyzer/src/command.rs +++ b/crates/rust-analyzer/src/command.rs @@ -197,4 +197,22 @@ impl<T: Sized + Send + 'static> CommandHandle<T> { ))) } } + + pub(crate) fn has_exited(&mut self) -> bool { + match self.child.0.try_wait() { + Ok(Some(_exit_code)) => { + // We have an exit code. + true + } + Ok(None) => { + // Hasn't exited yet. + false + } + Err(_) => { + // Couldn't get an exit code. Assume that we've + // exited. + true + } + } + } } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c380621d81..1a2ea97204 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -304,6 +304,9 @@ config_data! { /// Hide inlay parameter type hints for closures. inlayHints_typeHints_hideClosureParameter: bool = false, + /// Hide inlay type hints for inferred types. + inlayHints_typeHints_hideInferredTypes: bool = false, + /// Hide inlay type hints for constructors. inlayHints_typeHints_hideNamedConstructor: bool = false, @@ -1937,6 +1940,7 @@ impl Config { hide_named_constructor_hints: self .inlayHints_typeHints_hideNamedConstructor() .to_owned(), + hide_inferred_type_hints: self.inlayHints_typeHints_hideInferredTypes().to_owned(), hide_closure_initialization_hints: self .inlayHints_typeHints_hideClosureInitialization() .to_owned(), diff --git a/crates/rust-analyzer/src/discover.rs b/crates/rust-analyzer/src/discover.rs index 0e96eff278..4aef5b0b7f 100644 --- a/crates/rust-analyzer/src/discover.rs +++ b/crates/rust-analyzer/src/discover.rs @@ -67,7 +67,7 @@ impl DiscoverCommand { cmd.args(args); Ok(DiscoverHandle { - _handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?, + handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?, span: info_span!("discover_command").entered(), }) } @@ -76,7 +76,7 @@ impl DiscoverCommand { /// A handle to a spawned [Discover]. #[derive(Debug)] pub(crate) struct DiscoverHandle { - _handle: CommandHandle<DiscoverProjectMessage>, + pub(crate) handle: CommandHandle<DiscoverProjectMessage>, #[allow(dead_code)] // not accessed, but used to log on drop. span: EnteredSpan, } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 91f7db7854..7828f50844 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -45,7 +45,7 @@ use crate::{ op_queue::{Cause, OpQueue}, reload, target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec}, - task_pool::{TaskPool, TaskQueue}, + task_pool::{DeferredTaskQueue, TaskPool}, test_runner::{CargoTestHandle, CargoTestMessage}, }; @@ -121,9 +121,10 @@ pub(crate) struct GlobalState { pub(crate) test_run_remaining_jobs: usize, // Project loading - pub(crate) discover_handle: Option<discover::DiscoverHandle>, + pub(crate) discover_handles: Vec<discover::DiscoverHandle>, pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>, pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>, + pub(crate) discover_jobs_active: u32, // Debouncing channel for fetching the workspace // we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle @@ -175,7 +176,6 @@ pub(crate) struct GlobalState { pub(crate) fetch_build_data_queue: OpQueue<(), FetchBuildDataResponse>, pub(crate) fetch_proc_macros_queue: OpQueue<(ChangeWithProcMacros, Vec<ProcMacroPaths>), bool>, pub(crate) prime_caches_queue: OpQueue, - pub(crate) discover_workspace_queue: OpQueue, /// A deferred task queue. /// @@ -186,7 +186,8 @@ pub(crate) struct GlobalState { /// For certain features, such as [`GlobalState::handle_discover_msg`], /// this queue should run only *after* [`GlobalState::process_changes`] has /// been called. - pub(crate) deferred_task_queue: TaskQueue, + pub(crate) deferred_task_queue: DeferredTaskQueue, + /// HACK: Workaround for https://github.com/rust-lang/rust-analyzer/issues/19709 /// This is marked true if we failed to load a crate root file at crate graph creation, /// which will usually end up causing a bunch of incorrect diagnostics on startup. @@ -241,9 +242,9 @@ impl GlobalState { }; let cancellation_pool = thread::Pool::new(1); - let task_queue = { + let deferred_task_queue = { let (sender, receiver) = unbounded(); - TaskQueue { sender, receiver } + DeferredTaskQueue { sender, receiver } }; let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity()); @@ -291,9 +292,10 @@ impl GlobalState { test_run_receiver, test_run_remaining_jobs: 0, - discover_handle: None, + discover_handles: vec![], discover_sender, discover_receiver, + discover_jobs_active: 0, fetch_ws_receiver: None, @@ -312,9 +314,8 @@ impl GlobalState { fetch_proc_macros_queue: OpQueue::default(), prime_caches_queue: OpQueue::default(), - discover_workspace_queue: OpQueue::default(), - deferred_task_queue: task_queue, + deferred_task_queue, incomplete_crate_graph: false, minicore: MiniCoreRustAnalyzerInternalOnly::default(), @@ -540,10 +541,9 @@ impl GlobalState { // didn't find anything (to make up for the lack of precision). { if !matches!(&workspace_structure_change, Some((.., true))) { - _ = self - .deferred_task_queue - .sender - .send(crate::main_loop::QueuedTask::CheckProcMacroSources(modified_rust_files)); + _ = self.deferred_task_queue.sender.send( + crate::main_loop::DeferredTask::CheckProcMacroSources(modified_rust_files), + ); } // FIXME: ideally we should only trigger a workspace fetch for non-library changes // but something's going wrong with the source root business when we add a new local diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index 87be09dcbd..4a6544508f 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -91,7 +91,7 @@ pub(crate) fn handle_did_open_text_document( let _ = state .deferred_task_queue .sender - .send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri)); + .send(crate::main_loop::DeferredTask::CheckIfIndexed(params.text_document.uri)); } } Ok(()) diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 6ae527abb1..971ae2a601 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -9,6 +9,11 @@ //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + extern crate ra_ap_rustc_type_ir as rustc_type_ir; /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. diff --git a/crates/rust-analyzer/src/lsp/capabilities.rs b/crates/rust-analyzer/src/lsp/capabilities.rs index f94e7486ff..d6a694be91 100644 --- a/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/crates/rust-analyzer/src/lsp/capabilities.rs @@ -37,7 +37,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { change: Some(TextDocumentSyncKind::INCREMENTAL), will_save: None, will_save_wait_until: None, - save: Some(SaveOptions::default().into()), + save: if config.caps().did_save_text_document_dynamic_registration() { + None + } else { + Some(SaveOptions::default().into()) + }, })), hover_provider: Some(HoverProviderCapability::Simple(true)), completion_provider: Some(CompletionOptions { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 8b4748ddb3..1a1c0182f8 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -74,7 +74,7 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> { enum Event { Lsp(lsp_server::Message), Task(Task), - QueuedTask(QueuedTask), + DeferredTask(DeferredTask), Vfs(vfs::loader::Message), Flycheck(FlycheckMessage), TestResult(CargoTestMessage), @@ -89,7 +89,7 @@ impl fmt::Display for Event { Event::Task(_) => write!(f, "Event::Task"), Event::Vfs(_) => write!(f, "Event::Vfs"), Event::Flycheck(_) => write!(f, "Event::Flycheck"), - Event::QueuedTask(_) => write!(f, "Event::QueuedTask"), + Event::DeferredTask(_) => write!(f, "Event::DeferredTask"), Event::TestResult(_) => write!(f, "Event::TestResult"), Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"), Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"), @@ -98,7 +98,7 @@ impl fmt::Display for Event { } #[derive(Debug)] -pub(crate) enum QueuedTask { +pub(crate) enum DeferredTask { CheckIfIndexed(lsp_types::Url), CheckProcMacroSources(Vec<FileId>), } @@ -164,7 +164,7 @@ impl fmt::Debug for Event { match self { Event::Lsp(it) => fmt::Debug::fmt(it, f), Event::Task(it) => fmt::Debug::fmt(it, f), - Event::QueuedTask(it) => fmt::Debug::fmt(it, f), + Event::DeferredTask(it) => fmt::Debug::fmt(it, f), Event::Vfs(it) => fmt::Debug::fmt(it, f), Event::Flycheck(it) => fmt::Debug::fmt(it, f), Event::TestResult(it) => fmt::Debug::fmt(it, f), @@ -279,7 +279,7 @@ impl GlobalState { task.map(Event::Task), recv(self.deferred_task_queue.receiver) -> task => - task.map(Event::QueuedTask), + task.map(Event::DeferredTask), recv(self.fmt_pool.receiver) -> task => task.map(Event::Task), @@ -323,12 +323,12 @@ impl GlobalState { lsp_server::Message::Notification(not) => self.on_notification(not), lsp_server::Message::Response(resp) => self.complete_request(resp), }, - Event::QueuedTask(task) => { + Event::DeferredTask(task) => { let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered(); - self.handle_queued_task(task); - // Coalesce multiple task events into one loop turn + self.handle_deferred_task(task); + // Coalesce multiple deferred task events into one loop turn while let Ok(task) = self.deferred_task_queue.receiver.try_recv() { - self.handle_queued_task(task); + self.handle_deferred_task(task); } } Event::Task(task) => { @@ -437,11 +437,17 @@ impl GlobalState { } } Event::Flycheck(message) => { - let _p = tracing::info_span!("GlobalState::handle_event/flycheck").entered(); - self.handle_flycheck_msg(message); + let mut cargo_finished = false; + self.handle_flycheck_msg(message, &mut cargo_finished); // Coalesce many flycheck updates into a single loop turn while let Ok(message) = self.flycheck_receiver.try_recv() { - self.handle_flycheck_msg(message); + self.handle_flycheck_msg(message, &mut cargo_finished); + } + if cargo_finished { + self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>( + (), + |_, _| (), + ); } } Event::TestResult(message) => { @@ -531,6 +537,8 @@ impl GlobalState { } } + self.cleanup_discover_handles(); + if let Some(diagnostic_changes) = self.diagnostics.take_changes() { for file_id in diagnostic_changes { let uri = file_id_to_url(&self.vfs.read().0, file_id); @@ -806,33 +814,34 @@ impl GlobalState { self.report_progress("Fetching", state, msg, None, None); } Task::DiscoverLinkedProjects(arg) => { - if let Some(cfg) = self.config.discover_workspace_config() - && !self.discover_workspace_queue.op_in_progress() - { + if let Some(cfg) = self.config.discover_workspace_config() { // the clone is unfortunately necessary to avoid a borrowck error when // `self.report_progress` is called later let title = &cfg.progress_label.clone(); let command = cfg.command.clone(); let discover = DiscoverCommand::new(self.discover_sender.clone(), command); - self.report_progress(title, Progress::Begin, None, None, None); - self.discover_workspace_queue - .request_op("Discovering workspace".to_owned(), ()); - let _ = self.discover_workspace_queue.should_start_op(); + if self.discover_jobs_active == 0 { + self.report_progress(title, Progress::Begin, None, None, None); + } + self.discover_jobs_active += 1; let arg = match arg { DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it), DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it), }; - let handle = discover.spawn( - arg, - &std::env::current_dir() - .expect("Failed to get cwd during project discovery"), - ); - self.discover_handle = Some(handle.unwrap_or_else(|e| { - panic!("Failed to spawn project discovery command: {e}") - })); + let handle = discover + .spawn( + arg, + &std::env::current_dir() + .expect("Failed to get cwd during project discovery"), + ) + .unwrap_or_else(|e| { + panic!("Failed to spawn project discovery command: {e}") + }); + + self.discover_handles.push(handle); } } Task::FetchBuildData(progress) => { @@ -981,9 +990,9 @@ impl GlobalState { } } - fn handle_queued_task(&mut self, task: QueuedTask) { + fn handle_deferred_task(&mut self, task: DeferredTask) { match task { - QueuedTask::CheckIfIndexed(uri) => { + DeferredTask::CheckIfIndexed(uri) => { let snap = self.snapshot(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { @@ -1007,7 +1016,7 @@ impl GlobalState { } }); } - QueuedTask::CheckProcMacroSources(modified_rust_files) => { + DeferredTask::CheckProcMacroSources(modified_rust_files) => { let analysis = AssertUnwindSafe(self.snapshot().analysis); self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, { move |sender| { @@ -1036,25 +1045,43 @@ impl GlobalState { .expect("No title could be found; this is a bug"); match message { DiscoverProjectMessage::Finished { project, buildfile } => { - self.discover_handle = None; - self.report_progress(&title, Progress::End, None, None, None); - self.discover_workspace_queue.op_completed(()); + self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1); + if self.discover_jobs_active == 0 { + self.report_progress(&title, Progress::End, None, None, None); + } let mut config = Config::clone(&*self.config); config.add_discovered_project_from_command(project, buildfile); self.update_configuration(config); } DiscoverProjectMessage::Progress { message } => { - self.report_progress(&title, Progress::Report, Some(message), None, None) + if self.discover_jobs_active > 0 { + self.report_progress(&title, Progress::Report, Some(message), None, None) + } } DiscoverProjectMessage::Error { error, source } => { - self.discover_handle = None; let message = format!("Project discovery failed: {error}"); - self.discover_workspace_queue.op_completed(()); self.show_and_log_error(message.clone(), source); - self.report_progress(&title, Progress::End, Some(message), None, None) + + self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1); + if self.discover_jobs_active == 0 { + self.report_progress(&title, Progress::End, Some(message), None, None) + } + } + } + } + + /// Drop any discover command processes that have exited, due to + /// finishing or erroring. + fn cleanup_discover_handles(&mut self) { + let mut active_handles = vec![]; + + for mut discover_handle in self.discover_handles.drain(..) { + if !discover_handle.handle.has_exited() { + active_handles.push(discover_handle); } } + self.discover_handles = active_handles; } fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) { @@ -1088,7 +1115,7 @@ impl GlobalState { } } - fn handle_flycheck_msg(&mut self, message: FlycheckMessage) { + fn handle_flycheck_msg(&mut self, message: FlycheckMessage, cargo_finished: &mut bool) { match message { FlycheckMessage::AddDiagnostic { id, @@ -1146,6 +1173,7 @@ impl GlobalState { flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)), flycheck::Progress::DidCancel => { self.last_flycheck_error = None; + *cargo_finished = true; (Progress::End, None) } flycheck::Progress::DidFailToRestart(err) => { @@ -1156,6 +1184,7 @@ impl GlobalState { flycheck::Progress::DidFinish(result) => { self.last_flycheck_error = result.err().map(|err| format!("cargo check failed to start: {err}")); + *cargo_finished = true; (Progress::End, None) } }; diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 8876b850be..317c112365 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -74,7 +74,7 @@ impl GlobalState { && !self.fetch_workspaces_queue.op_in_progress() && !self.fetch_build_data_queue.op_in_progress() && !self.fetch_proc_macros_queue.op_in_progress() - && !self.discover_workspace_queue.op_in_progress() + && self.discover_jobs_active == 0 && self.vfs_progress_config_version >= self.vfs_config_version } @@ -297,7 +297,7 @@ impl GlobalState { .collect(); let cargo_config = self.config.cargo(None); let discover_command = self.config.discover_workspace_config().cloned(); - let is_quiescent = !(self.discover_workspace_queue.op_in_progress() + let is_quiescent = !(self.discover_jobs_active > 0 || self.vfs_progress_config_version < self.vfs_config_version || !self.vfs_done); diff --git a/crates/rust-analyzer/src/task_pool.rs b/crates/rust-analyzer/src/task_pool.rs index c5de69bb9f..ef0feb1796 100644 --- a/crates/rust-analyzer/src/task_pool.rs +++ b/crates/rust-analyzer/src/task_pool.rs @@ -6,7 +6,7 @@ use std::panic::UnwindSafe; use crossbeam_channel::Sender; use stdx::thread::{Pool, ThreadIntent}; -use crate::main_loop::QueuedTask; +use crate::main_loop::DeferredTask; pub(crate) struct TaskPool<T> { sender: Sender<T>, @@ -45,11 +45,11 @@ impl<T> TaskPool<T> { } } -/// `TaskQueue`, like its name suggests, queues tasks. +/// `DeferredTaskQueue` holds deferred tasks. /// -/// This should only be used if a task must run after [`GlobalState::process_changes`] -/// has been called. -pub(crate) struct TaskQueue { - pub(crate) sender: crossbeam_channel::Sender<QueuedTask>, - pub(crate) receiver: crossbeam_channel::Receiver<QueuedTask>, +/// These are tasks that must be run after +/// [`GlobalState::process_changes`] has been called. +pub(crate) struct DeferredTaskQueue { + pub(crate) sender: crossbeam_channel::Sender<DeferredTask>, + pub(crate) receiver: crossbeam_channel::Receiver<DeferredTask>, } diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index 5a4ad6f380..48433342d5 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -9,6 +9,10 @@ //! be sure without a real client anyway. #![allow(clippy::disallowed_types)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; mod cli; mod ratoml; diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index b1b428e706..195ad226ae 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs @@ -48,6 +48,7 @@ impl Project<'_> { "enable": false, }, }, + "checkOnSave": false, "procMacro": { "enable": false, } diff --git a/crates/span/Cargo.toml b/crates/span/Cargo.toml index 966962bab3..cfb319d688 100644 --- a/crates/span/Cargo.toml +++ b/crates/span/Cargo.toml @@ -27,6 +27,7 @@ syntax.workspace = true [features] default = ["salsa"] +in-rust-tree = [] [lints] workspace = true diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index e803747998..bd49e08b10 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -44,6 +44,7 @@ pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = /// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be /// considered fake. +/// Do not modify this, it is used by the proc-macro server. pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32)); @@ -700,7 +701,7 @@ impl AstIdMap { } } - /// The [`AstId`] of the root node + /// The root node. pub fn root(&self) -> SyntaxNodePtr { self.arena[Idx::from_raw(RawIdx::from_u32(0))].0 } diff --git a/crates/span/src/hygiene.rs b/crates/span/src/hygiene.rs index 6c363825aa..6805417177 100644 --- a/crates/span/src/hygiene.rs +++ b/crates/span/src/hygiene.rs @@ -249,7 +249,7 @@ const _: () = { ) } - /// Invariant: Only [`SyntaxContext::ROOT`] has a [`None`] outer expansion. + /// Invariant: Only the root [`SyntaxContext`] has a [`None`] outer expansion. // FIXME: The None case needs to encode the context crate id. We can encode that as the MSB of // MacroCallId is reserved anyways so we can do bit tagging here just fine. // The bigger issue is that this will cause interning to now create completely separate chains @@ -348,7 +348,7 @@ impl SyntaxContext { } } - /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context. + /// The root context, which is the parent of all other contexts. All `FileId`s have this context. #[inline] pub const fn root(edition: Edition) -> Self { let edition = edition as u32; diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs index ae9e038459..c44b0198b7 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -1,4 +1,10 @@ //! File and span related types. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::fmt::{self, Write}; mod ast_id; @@ -28,6 +34,33 @@ impl Span { let range = self.range.cover(other.range); Span { range, ..self } } + + pub fn join( + self, + other: Span, + differing_anchor: impl FnOnce(Span, Span) -> Option<Span>, + ) -> Option<Span> { + // We can't modify the span range for fixup spans, those are meaningful to fixup, so just + // prefer the non-fixup span. + if self.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + return Some(other); + } + if other.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + return Some(self); + } + if self.anchor != other.anchor { + return differing_anchor(self, other); + } + // Differing context, we can't merge these so prefer the one that's root + if self.ctx != other.ctx { + if self.ctx.is_root() { + return Some(other); + } else if other.ctx.is_root() { + return Some(self); + } + } + Some(Span { range: self.range.cover(other.range), anchor: other.anchor, ctx: other.ctx }) + } } /// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs diff --git a/crates/syntax-bridge/src/lib.rs b/crates/syntax-bridge/src/lib.rs index 1ded2b4113..815b4f2799 100644 --- a/crates/syntax-bridge/src/lib.rs +++ b/crates/syntax-bridge/src/lib.rs @@ -1,5 +1,10 @@ //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`]. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{collections::VecDeque, fmt, hash::Hash}; use intern::Symbol; diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 1ee93013e3..8909fb423c 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -33,6 +33,7 @@ rustc_apfloat = "0.2.3" test-utils.workspace = true [features] +default = [] in-rust-tree = [] [lints] diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index dba39204e3..b2904ce3c0 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -658,7 +658,7 @@ pub fn expr_if( }; expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) } -pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr { +pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr { expr_from_text(&format!("for {pat} in {expr} {block}")) } @@ -1016,7 +1016,19 @@ pub fn item_static( } pub fn unnamed_param(ty: ast::Type) -> ast::Param { - ast_from_text(&format!("fn f({ty}) {{ }}")) + quote! { + Param { + #ty + } + } +} + +pub fn untyped_param(pat: ast::Pat) -> ast::Param { + quote! { + Param { + #pat + } + } } pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { @@ -1456,3 +1468,86 @@ pub mod tokens { } } } + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use super::*; + + #[track_caller] + fn check(node: impl AstNode, expect: expect_test::Expect) { + let node_debug = format!("{:#?}", node.syntax()); + expect.assert_eq(&node_debug); + } + + #[test] + fn test_unnamed_param() { + check( + unnamed_param(ty("Vec")), + expect![[r#" + [email protected] "Vec" + "#]], + ); + + check( + unnamed_param(ty("Vec<T>")), + expect![[r#" + [email protected] "Vec" + [email protected] "<" + [email protected] "T" + [email protected] ">" + "#]], + ); + } + + #[test] + fn test_untyped_param() { + check( + untyped_param(path_pat(ext::ident_path("name"))), + expect![[r#" + [email protected] "name" + "#]], + ); + + check( + untyped_param( + range_pat( + Some(path_pat(ext::ident_path("start"))), + Some(path_pat(ext::ident_path("end"))), + ) + .into(), + ), + expect![[r#" + [email protected] "start" + [email protected] ".." + [email protected] "end" + "#]], + ); + } +} diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 901d17bb14..b872221bf7 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -813,13 +813,16 @@ pub enum TypeBoundKind { } impl ast::TypeBound { - pub fn kind(&self) -> TypeBoundKind { + pub fn kind(&self) -> Option<TypeBoundKind> { if let Some(path_type) = support::children(self.syntax()).next() { - TypeBoundKind::PathType(self.for_binder(), path_type) + Some(TypeBoundKind::PathType(self.for_binder(), path_type)) + } else if let Some(for_binder) = support::children::<ast::ForType>(&self.syntax).next() { + let Some(ast::Type::PathType(path_type)) = for_binder.ty() else { return None }; + Some(TypeBoundKind::PathType(for_binder.for_binder(), path_type)) } else if let Some(args) = self.use_bound_generic_args() { - TypeBoundKind::Use(args) + Some(TypeBoundKind::Use(args)) } else if let Some(lifetime) = self.lifetime() { - TypeBoundKind::Lifetime(lifetime) + Some(TypeBoundKind::Lifetime(lifetime)) } else { unreachable!() } diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs index 9695523921..aca6fcfb2e 100644 --- a/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -71,6 +71,188 @@ impl SyntaxFactory { ast } + pub fn path_from_text(&self, text: &str) -> ast::Path { + make::path_from_text(text).clone_for_update() + } + + pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr { + let ast::Expr::FieldExpr(ast) = + make::expr_field(receiver.clone(), field).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(receiver.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn impl_trait( + &self, + attrs: impl IntoIterator<Item = ast::Attr>, + is_unsafe: bool, + trait_gen_params: Option<ast::GenericParamList>, + trait_gen_args: Option<ast::GenericArgList>, + type_gen_params: Option<ast::GenericParamList>, + type_gen_args: Option<ast::GenericArgList>, + is_negative: bool, + path_type: ast::Type, + ty: ast::Type, + trait_where_clause: Option<ast::WhereClause>, + ty_where_clause: Option<ast::WhereClause>, + body: Option<ast::AssocItemList>, + ) -> ast::Impl { + let (attrs, attrs_input) = iterator_input(attrs); + let ast = make::impl_trait( + attrs, + is_unsafe, + trait_gen_params.clone(), + trait_gen_args.clone(), + type_gen_params.clone(), + type_gen_args.clone(), + is_negative, + path_type.clone(), + ty.clone(), + trait_where_clause.clone(), + ty_where_clause.clone(), + body.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone())); + if let Some(trait_gen_params) = trait_gen_params { + builder.map_node( + trait_gen_params.syntax().clone(), + ast.generic_param_list().unwrap().syntax().clone(), + ); + } + builder.map_node(path_type.syntax().clone(), ast.trait_().unwrap().syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.self_ty().unwrap().syntax().clone()); + if let Some(ty_where_clause) = ty_where_clause { + builder.map_node( + ty_where_clause.syntax().clone(), + ast.where_clause().unwrap().syntax().clone(), + ); + } + if let Some(body) = body { + builder.map_node( + body.syntax().clone(), + ast.assoc_item_list().unwrap().syntax().clone(), + ); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn ty_alias( + &self, + attrs: impl IntoIterator<Item = ast::Attr>, + ident: &str, + generic_param_list: Option<ast::GenericParamList>, + type_param_bounds: Option<ast::TypeParam>, + where_clause: Option<ast::WhereClause>, + assignment: Option<(ast::Type, Option<ast::WhereClause>)>, + ) -> ast::TypeAlias { + let (attrs, attrs_input) = iterator_input(attrs); + let ast = make::ty_alias( + attrs, + ident, + generic_param_list.clone(), + type_param_bounds.clone(), + where_clause.clone(), + assignment.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone())); + if let Some(generic_param_list) = generic_param_list { + builder.map_node( + generic_param_list.syntax().clone(), + ast.generic_param_list().unwrap().syntax().clone(), + ); + } + if let Some(type_param_bounds) = type_param_bounds { + builder.map_node( + type_param_bounds.syntax().clone(), + ast.type_bound_list().unwrap().syntax().clone(), + ); + } + if let Some(where_clause) = where_clause { + builder.map_node( + where_clause.syntax().clone(), + ast.where_clause().unwrap().syntax().clone(), + ); + } + if let Some((ty, _)) = assignment { + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn param_list( + &self, + self_param: Option<ast::SelfParam>, + params: impl IntoIterator<Item = ast::Param>, + ) -> ast::ParamList { + let (params, input) = iterator_input(params); + let ast = make::param_list(self_param.clone(), params).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(self_param) = self_param + && let Some(new_self_param) = ast.self_param() + { + builder.map_node(self_param.syntax().clone(), new_self_param.syntax().clone()); + } + builder.map_children(input, ast.params().map(|p| p.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + + pub fn const_param(&self, name: ast::Name, ty: ast::Type) -> ast::ConstParam { + let ast = make::const_param(name.clone(), ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn generic_param_list( + &self, + params: impl IntoIterator<Item = ast::GenericParam>, + ) -> ast::GenericParamList { + let (params, input) = iterator_input(params); + let ast = make::generic_param_list(params).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.generic_params().map(|p| p.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment { let ast = make::path_segment(name_ref.clone()).clone_for_update(); @@ -671,6 +853,26 @@ impl SyntaxFactory { ast } + pub fn expr_for_loop( + &self, + pat: ast::Pat, + iterable: ast::Expr, + body: ast::BlockExpr, + ) -> ast::ForExpr { + let ast = + make::expr_for_loop(pat.clone(), iterable.clone(), body.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.map_node(iterable.syntax().clone(), ast.iterable().unwrap().syntax().clone()); + builder.map_node(body.syntax().clone(), ast.loop_body().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update(); @@ -1272,6 +1474,23 @@ impl SyntaxFactory { ast } + pub fn assoc_item_list( + &self, + items: impl IntoIterator<Item = ast::AssocItem>, + ) -> ast::AssocItemList { + let (items, input) = iterator_input(items); + let items_vec: Vec<_> = items.into_iter().collect(); + let ast = make::assoc_item_list(Some(items_vec)).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.assoc_items().map(|item| item.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr { let ast = make::attr_outer(meta.clone()).clone_for_update(); diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 7346b93192..9e3083066c 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -19,6 +19,11 @@ //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod parsing; mod ptr; mod syntax_error; @@ -282,7 +287,7 @@ fn api_walkthrough() { assert!(parse.errors().is_empty()); // The `tree` method returns an owned syntax node of type `SourceFile`. - // Owned nodes are cheap: inside, they are `Rc` handles to the underling data. + // Owned nodes are cheap: inside, they are `Rc` handles to the underlying data. let file: SourceFile = parse.tree(); // `SourceFile` is the root of the syntax tree. We can iterate file's items. diff --git a/crates/test-fixture/Cargo.toml b/crates/test-fixture/Cargo.toml index 353d4c312d..7760ae7aa0 100644 --- a/crates/test-fixture/Cargo.toml +++ b/crates/test-fixture/Cargo.toml @@ -21,5 +21,9 @@ intern.workspace = true triomphe.workspace = true paths.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 457cd3ac85..5e8b250c24 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs @@ -1,4 +1,10 @@ //! A set of high-level utility fixture methods to use in tests. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{any::TypeId, mem, str::FromStr, sync}; use base_db::target::TargetData; diff --git a/crates/test-utils/src/assert_linear.rs b/crates/test-utils/src/assert_linear.rs index f78bf59a2f..27665a74dc 100644 --- a/crates/test-utils/src/assert_linear.rs +++ b/crates/test-utils/src/assert_linear.rs @@ -11,7 +11,7 @@ //! Ideally, we should use a proper "model selection" to directly compare //! quadratic and linear models, but that sounds rather complicated: //! -//! > https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data +//! > <https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data> //! //! We might get false positives on a VM, but never false negatives. So, if the //! first round fails, we repeat the ordeal three more times and fail only if diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs index 559894ee62..831d2b30c1 100644 --- a/crates/test-utils/src/fixture.rs +++ b/crates/test-utils/src/fixture.rs @@ -96,9 +96,10 @@ pub struct Fixture { /// /// Syntax: `cfg:test,dbg=false,opt_level=2` pub cfgs: Vec<(String, Option<String>)>, - /// Specifies the edition of this crate. This must be used with `crate` meta. If - /// this is not specified, ([`base_db::input::Edition::CURRENT`]) will be used. - /// This must be used with `crate` meta. + /// Specifies the edition of this crate. This must be used with + /// `crate` meta. If this is not specified, + /// `base_db::input::Edition::CURRENT` will be used. This must be + /// used with `crate` meta. /// /// Syntax: `edition:2021` pub edition: Option<String>, @@ -106,8 +107,8 @@ pub struct Fixture { /// /// Syntax: `env:PATH=/bin,RUST_LOG=debug` pub env: FxHashMap<String, String>, - /// Introduces a new [source root](base_db::input::SourceRoot). This file **and - /// the following files** will belong the new source root. This must be used + /// Introduces a new source root. This file **and the following + /// files** will belong the new source root. This must be used /// with `crate` meta. /// /// Use this if you want to test something that uses `SourceRoot::is_library()` @@ -126,7 +127,7 @@ pub struct Fixture { /// This is implied if this file belongs to a library source root. /// /// Use this if you want to test something that checks if a crate is a workspace - /// member via [`CrateOrigin`](base_db::input::CrateOrigin). + /// member via `CrateOrigin`. /// /// Syntax: `library` pub library: bool, diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 0fe17e3075..b7c09391ec 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -34,7 +34,8 @@ //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fmt_before_1_89_0: fmt +//! fmt_before_1_93_0: fmt +//! fmt_before_1_89_0: fmt_before_1_93_0 //! fn: sized, tuple //! from: sized, result //! future: pin @@ -1259,6 +1260,7 @@ pub mod fmt { Unknown, } + // region:fmt_before_1_93_0 #[lang = "format_count"] pub enum Count { Is(usize), @@ -1288,6 +1290,7 @@ pub mod fmt { Placeholder { position, fill, align, flags, precision, width } } } + // endregion:fmt_before_1_93_0 // region:fmt_before_1_89_0 #[lang = "format_unsafe_arg"] @@ -1303,6 +1306,7 @@ pub mod fmt { // endregion:fmt_before_1_89_0 } + // region:fmt_before_1_93_0 #[derive(Copy, Clone)] #[lang = "format_arguments"] pub struct Arguments<'a> { @@ -1341,6 +1345,14 @@ pub mod fmt { } // endregion:!fmt_before_1_89_0 + pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> { + Self::from_str(s) + } + + pub const fn from_str(s: &'static str) -> Arguments<'a> { + Arguments { pieces: &[s], fmt: None, args: &[] } + } + pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), @@ -1349,6 +1361,41 @@ pub mod fmt { } } } + // endregion:fmt_before_1_93_0 + + // region:!fmt_before_1_93_0 + #[lang = "format_arguments"] + #[derive(Copy, Clone)] + pub struct Arguments<'a> { + // This is a non-faithful representation of `core::fmt::Arguments`, because the real one + // is too complex for minicore. + message: Option<&'a str>, + } + + impl<'a> Arguments<'a> { + pub unsafe fn new<const N: usize, const M: usize>( + _template: &'a [u8; N], + _args: &'a [rt::Argument<'a>; M], + ) -> Arguments<'a> { + Arguments { message: None } + } + + pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> { + Arguments { message: Some(s) } + } + + pub const fn from_str(s: &'static str) -> Arguments<'a> { + Arguments { message: Some(s) } + } + + pub fn as_str(&self) -> Option<&'static str> { + match self.message { + Some(s) => unsafe { Some(&*(s as *const str)) }, + None => None, + } + } + } + // endregion:!fmt_before_1_93_0 // region:derive pub(crate) mod derive { @@ -1817,7 +1864,7 @@ mod panicking { #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! { - panic_fmt(crate::fmt::Arguments::new_const(&[expr])) + panic_fmt(crate::fmt::Arguments::from_str(expr)) } } // endregion:panic diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml index 82e7c24668..3183b72a66 100644 --- a/crates/tt/Cargo.toml +++ b/crates/tt/Cargo.toml @@ -21,6 +21,7 @@ intern.workspace = true ra-ap-rustc_lexer.workspace = true [features] +default = [] in-rust-tree = [] [lints] diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index ea0752250d..d6a743c695 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs @@ -5,6 +5,9 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] diff --git a/docs/book/README.md b/docs/book/README.md index 11f7e8f98c..0a3161f3af 100644 --- a/docs/book/README.md +++ b/docs/book/README.md @@ -8,7 +8,6 @@ To run the documentation site locally: ```shell cargo install mdbook -cargo install mdbook-toc cargo xtask codegen cd docs/book mdbook serve diff --git a/docs/book/book.toml b/docs/book/book.toml index c77eabda14..0978851d50 100644 --- a/docs/book/book.toml +++ b/docs/book/book.toml @@ -33,8 +33,3 @@ use-boolean-and = true [output.html.fold] enable = true level = 3 - -[preprocessor.toc] -command = "mdbook-toc" -renderer = ["html"] -max-level = 3 diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index fe1ea57c9b..b36576b4bb 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -1118,6 +1118,13 @@ Default: `false` Hide inlay parameter type hints for closures. +## rust-analyzer.inlayHints.typeHints.hideInferredTypes {#inlayHints.typeHints.hideInferredTypes} + +Default: `false` + +Hide inlay type hints for inferred types. + + ## rust-analyzer.inlayHints.typeHints.hideNamedConstructor {#inlayHints.typeHints.hideNamedConstructor} Default: `false` diff --git a/docs/book/src/contributing/README.md b/docs/book/src/contributing/README.md index ad2816b18a..c95a1dba62 100644 --- a/docs/book/src/contributing/README.md +++ b/docs/book/src/contributing/README.md @@ -26,8 +26,6 @@ Discussion happens in this Zulip stream: <https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer> -<!-- toc --> - # Issue Labels * [good-first-issue](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) diff --git a/docs/book/src/contributing/architecture.md b/docs/book/src/contributing/architecture.md index f2b6c053b0..67653ebd74 100644 --- a/docs/book/src/contributing/architecture.md +++ b/docs/book/src/contributing/architecture.md @@ -20,8 +20,6 @@ For older, by now mostly outdated stuff, see the [guide](./guide.md) and [anothe  -<!-- toc --> - On the highest level, rust-analyzer is a thing which accepts input source code from the client and produces a structured semantic model of the code. More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`. diff --git a/docs/book/src/contributing/guide.md b/docs/book/src/contributing/guide.md index 774eb5b2a5..9e944bfe0f 100644 --- a/docs/book/src/contributing/guide.md +++ b/docs/book/src/contributing/guide.md @@ -12,8 +12,6 @@ however, it's based on an older 2019-01-20 release (git tag [guide-2019-01]): [guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01 [2024-01-01]: https://github.com/rust-lang/rust-analyzer/tree/2024-01-01 -<!-- toc --> - ## The big picture On the highest possible level, rust-analyzer is a stateful component. A client may diff --git a/docs/book/src/contributing/lsp-extensions.md b/docs/book/src/contributing/lsp-extensions.md index 0e91e12612..5922f0b551 100644 --- a/docs/book/src/contributing/lsp-extensions.md +++ b/docs/book/src/contributing/lsp-extensions.md @@ -19,8 +19,6 @@ Requests, which are likely to always remain specific to `rust-analyzer` are unde If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604). -<!-- toc --> - ## Configuration in `initializationOptions` **Upstream Issue:** <https://github.com/microsoft/language-server-protocol/issues/567> diff --git a/docs/book/src/other_editors.md b/docs/book/src/other_editors.md index 896df52af5..f7116fc19a 100644 --- a/docs/book/src/other_editors.md +++ b/docs/book/src/other_editors.md @@ -6,8 +6,6 @@ Protocol](https://microsoft.github.io/language-server-protocol/). This page assumes that you have already [installed the rust-analyzer binary](./rust_analyzer_binary.html). -<!-- toc --> - ## Emacs To use `rust-analyzer`, you need to install and enable one of the two diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index d49d19fbe1..00d83e9068 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1486,6 +1486,7 @@ "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/types": "8.25.0", @@ -1869,6 +1870,7 @@ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2838,6 +2840,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -3319,6 +3322,7 @@ "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -4406,6 +4410,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "license": "MIT", + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -4508,25 +4513,25 @@ } }, "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "dev": true, "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -4544,25 +4549,25 @@ } }, "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "dev": true, "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^2.0.0", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -6673,6 +6678,7 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/editors/code/package.json b/editors/code/package.json index 8475864427..abe85d6c9d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2469,6 +2469,16 @@ { "title": "Inlay Hints", "properties": { + "rust-analyzer.inlayHints.typeHints.hideInferredTypes": { + "markdownDescription": "Hide inlay type hints for inferred types.", + "default": false, + "type": "boolean" + } + } + }, + { + "title": "Inlay Hints", + "properties": { "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { "markdownDescription": "Hide inlay type hints for constructors.", "default": false, diff --git a/rust-version b/rust-version index 7a84872f26..dcf82c94aa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dfe1b8c97bcde283102f706d5dcdc3649e5e12e3 +0208ee09be465f69005a7a12c28d5eccac7d5f34 diff --git a/triagebot.toml b/triagebot.toml index c9862495bc..ac4efd0a24 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -25,6 +25,3 @@ labels = ["has-merge-commits", "S-waiting-on-author"] # Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree [canonicalize-issue-links] - -# Prevents mentions in commits to avoid users being spammed -[no-mentions] |