diff --git a/Cargo.lock b/Cargo.lock index ebc5ce37252c8..2d16515500878 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5575,9 +5575,9 @@ dependencies = [ [[package]] name = "thin-vec" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" +checksum = "79def32ffcd477db1ff26f76dab9e3a91f0bd42a85ca96577089b24623056f9d" [[package]] name = "thiserror" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index c60f666d3bfad..fc9118f593ce5 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 0fefc0d9220a3..f7128e66193a8 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -22,6 +22,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index b33f41eb302c0..690d1cfd6f0f5 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" } [dev-dependencies] # tidy-alphabetical-start -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 2e8c912609b2e..7542cb4bbec26 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -20,5 +20,5 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 360df2e609a8a..ed4e25f009aed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1243,6 +1243,9 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } } else if j == 0 { err.span_label(binding_span, "data moved here"); + } else if j == 5 && binds_to.len() > 6 && !self.infcx.tcx.sess.opts.verbose { + err.note(format!("...and {} other places", binds_to.len() - 5)); + break; } else { err.span_label(binding_span, "...and here"); } diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index f5dbc4a0d7cbe..624f4ffea6ffc 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -29,7 +29,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 51413d3a67a68..7577217401810 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry::*; use rustc_abi::{CanonAbi, X86Call}; use rustc_ast::expand::allocator::{AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; use rustc_data_structures::unord::UnordMap; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; @@ -87,6 +88,11 @@ pub fn reachable_non_generics_helper(tcx: TyCtxt<'_>) -> DefIdMap + { + return None; + } DefKind::Fn | DefKind::Static { .. } => {} DefKind::AssocFn if tcx.impl_of_assoc(def_id.to_def_id()).is_some() => {} _ => return None, diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 6db3a624500a9..f8d26f8773018 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -30,7 +30,7 @@ smallvec = { version = "1.8.1", features = [ ] } stacker = "0.1.17" tempfile = "3.2" -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 068c84da719a3..2b8dc55012616 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -30,6 +30,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } scoped-tls = "1.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 5765163af6e41..0d4a8c73e971e 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -23,6 +23,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 33f7e2f38f765..e9c007f5e1829 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -17,6 +17,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 70f09b1003045..ecf67f0614884 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -529,7 +529,10 @@ impl<'a, 'tcx> ty::TypeFolder> for LowerUniverseFolder<'a, 'tcx> { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { let vid = self.infcx.root_const_var(vid); - let universe = self.infcx.try_resolve_const_var(vid).unwrap_err(); + let universe = match self.infcx.try_resolve_const_var(vid) { + Ok(value) => return value.fold_with(self), + Err(universe) => universe, + }; if self.for_universe.can_name(universe) { c } else { diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 88d0c20b178fa..36eb4c9f59370 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -752,7 +752,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes // path), as doing this new No path breaks some GCE things. I expect GCE to be // ripped out soon so this shouldn't matter soon. - if !tcx.features().generic_const_exprs() { + if self.infcx.next_trait_solver() || !tcx.features().generic_const_exprs() { self.generalize_alias_term(alias_const.into()).map(|v| v.expect_const()) } else { let ty::AliasConst { kind, args, .. } = alias_const; diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 6ead1c5ea46a3..f624fcee78f59 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -33,7 +33,7 @@ rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 220be82574db7..68d6c01f15e92 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1677,6 +1677,15 @@ impl<'v> RootCollector<'_, 'v> { && match self.strategy { MonoItemCollectionStrategy::Eager => { !matches!(self.tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) + // comptime fns can't be codegenned, so we need to prevent collecting them even + // with link-dead-code. Lazy mode prevents them by them not showing up in + // `is_reachable_non_generic` (and `entry_fn` can't be comptime). + && match self.tcx.def_kind(def_id) { + DefKind::Fn | DefKind::AssocFn => { + self.tcx.constness(def_id) != hir::Constness::Const { always: true } + } + _ => true, + } } MonoItemCollectionStrategy::Lazy => { self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 5d54065260888..941c0b78e464d 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -391,12 +391,10 @@ where } let infcx = self.infcx; - // FIXME: make this a debug_assert. - // Currently proof tree evaluation can unify infer vars in original - // vars while not resolving them. - // See `tests/ui/traits/next-solver/transmute-from-async-closure.rs` + // Proof tree evaluation can unify inference variables in the original + // values without eagerly resolving them. let a = infcx.shallow_resolve_const(a); - debug_assert_eq!(b, infcx.shallow_resolve_const(b)); + let b = infcx.shallow_resolve_const(b); match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 768a9546cccd4..f6bff621d7db8 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -17,7 +17,7 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" unicode-normalization = "0.1.25" unicode-width = "0.2.2" diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index a1d61d0d9f2f0..bafff3ec66022 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -26,6 +26,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 4e11d8726c84f..e1b14360f1262 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" indexmap = "2.0.0" rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index ea65baf610b9a..482848578a81b 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,6 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -240,6 +241,10 @@ fn compute_symbol_name<'tcx>( ) -> String { let def_id = instance.def_id(); let args = instance.args; + let def_kind = tcx.def_kind(instance.def_id()); + if let DefKind::Fn | DefKind::AssocFn = def_kind { + debug_assert!(tcx.constness(instance.def_id()) != hir::Constness::Const { always: true }); + } debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); @@ -254,7 +259,7 @@ fn compute_symbol_name<'tcx>( // visibility) symbol. This means that multiple crates may do the same // and we want to be sure to avoid any symbol conflicts here. let is_globally_shared_function = matches!( - tcx.def_kind(instance.def_id()), + def_kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 0cd9128762cbc..ae231c217977d 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -19,6 +19,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 8af061168a865..5f456edb8d7f6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -949,12 +949,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } else if let Some(impl_did) = impl_did.as_local() && let item = self.tcx.hir_expect_item(impl_did) - && let hir::ItemKind::Impl(item) = item.kind - && let Some(of_trait) = item.of_trait + && let hir::ItemKind::Impl(impl_) = item.kind + && impl_.of_trait.is_some() { // trait is const, impl is local and not const diag.span_suggestion_verbose( - of_trait.trait_ref.path.span.shrink_to_lo(), + item.span.shrink_to_lo(), format!("make the `impl` of trait `{trait_name}` `const`"), "const ".to_string(), Applicability::MaybeIncorrect, diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 97cddd857af18..19afebe4e2a07 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -23,7 +23,7 @@ rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = [ "const_generics", ] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index e9875f31fe784..7210d850c864a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -873,7 +873,8 @@ pub const unsafe fn transmute_unchecked(src: Src) -> Dst; #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -pub const fn needs_drop() -> bool; +#[rustc_comptime] +pub fn needs_drop() -> bool; /// Calculates the offset from a pointer. /// @@ -2945,7 +2946,8 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn size_of() -> usize; +#[rustc_comptime] +pub fn size_of() -> usize; /// The minimum alignment of a type. /// @@ -2964,7 +2966,8 @@ pub const fn size_of() -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn align_of() -> usize; +#[rustc_comptime] +pub fn align_of() -> usize; /// The offset of a field inside a type. /// @@ -2984,7 +2987,8 @@ pub const fn align_of() -> usize; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[lang = "offset_of"] -pub const fn offset_of(variant: u32, field: u32) -> usize; +#[rustc_comptime] +pub fn offset_of(variant: u32, field: u32) -> usize; /// The offset of a field queried by its field representing type. /// @@ -2998,7 +3002,8 @@ pub const fn offset_of(variant: u32, field: u32) -> usize; #[rustc_intrinsic] #[unstable(feature = "field_projections", issue = "145383")] #[rustc_const_unstable(feature = "field_projections", issue = "145383")] -pub const fn field_offset() -> usize; +#[rustc_comptime] +pub fn field_offset() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -3012,7 +3017,8 @@ pub const fn field_offset() -> usize; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn variant_count() -> usize; +#[rustc_comptime] +pub fn variant_count() -> usize; /// The size of the referenced value in bytes. /// @@ -3049,20 +3055,15 @@ pub const unsafe fn align_of_val(ptr: *const T) -> usize; pub fn type_id_vtable( _id: crate::any::TypeId, _trait: crate::any::TypeId, -) -> Option> { - panic!( - "`TypeId::trait_info_of` and `trait_info_of_trait_type_id` can only be called at compile-time" - ) -} +) -> Option>; /// Compute the type information of a concrete type. /// It can only be called at compile time, the backends do /// not implement it. #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] -pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { - panic!("`TypeId::info` can only be called at compile-time") -} +#[rustc_comptime] +pub fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type; /// Gets a static string slice containing the name of a type. /// @@ -3075,7 +3076,8 @@ pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_name() -> &'static str; +#[rustc_comptime] +pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This /// function will return the same value for a type regardless of whichever @@ -3114,9 +3116,7 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn size_of_type_id(_id: crate::any::TypeId) -> Option { - panic!("`TypeId::size` can only be called at compile-time") -} +pub fn size_of_type_id(_id: crate::any::TypeId) -> Option; /// Gets the number of variants of the type represented by this `TypeId`. /// @@ -3124,9 +3124,7 @@ pub fn size_of_type_id(_id: crate::any::TypeId) -> Option { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn type_id_variants(_id: crate::any::TypeId) -> usize { - panic!("`TypeId::variants` can only be called at compile-time") -} +pub fn type_id_variants(_id: crate::any::TypeId) -> usize; /// Gets the number of fields at the given `variant_index` represented by this `TypeId`. /// @@ -3134,9 +3132,7 @@ pub fn type_id_variants(_id: crate::any::TypeId) -> usize { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn type_id_fields(_id: crate::any::TypeId, _variant_index: usize) -> usize { - panic!("`TypeId::fields` can only be called at compile-time") -} +pub fn type_id_fields(_id: crate::any::TypeId, _variant_index: usize) -> usize; /// Gets the [`FieldRepresentingType`]'s `TypeId` at the given index of the type represented by this `TypeId`. /// @@ -3150,9 +3146,7 @@ pub fn type_id_field_representing_type( _id: crate::any::TypeId, _variant_index: usize, _field_index: usize, -) -> crate::any::TypeId { - panic!("`TypeId::field` can only be called at compile-time") -} +) -> crate::any::TypeId; /// Gets the actual field `TypeId` of the [`FieldRepresentingType`]'s `TypeId`. /// @@ -3164,9 +3158,7 @@ pub fn type_id_field_representing_type( #[rustc_comptime] pub fn field_representing_type_actual_type_id( _frt_type_id: crate::any::TypeId, -) -> crate::any::TypeId { - panic!("`FieldId::type_id` can only be called at compile-time") -} +) -> crate::any::TypeId; /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7614adbcc532b..75270b2d5b14b 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -37,7 +37,8 @@ impl TypeId { /// It can only be called at compile time. #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] - pub const fn info(self) -> Type { + #[rustc_comptime] + pub fn info(self) -> Type { type_of(self) } } diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs index 3d3ae38788639..db0ec8f2fbb2e 100644 --- a/library/std/src/os/windows/io/mod.rs +++ b/library/std/src/os/windows/io/mod.rs @@ -65,5 +65,114 @@ pub use raw::*; #[stable(feature = "io_safety", since = "1.63.0")] pub use socket::*; +use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; +use crate::ptr; +#[cfg(not(doc))] +use crate::sys::c; + #[cfg(test)] mod tests; + +#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +pub impl(self) trait StdioExt { + /// Sets the stdio console handle to `handle`, or `NULL` if it is `None`. + /// The old handle, if any, will not be closed, i.e. it is leaked because + /// console handles are shared global resources. + /// + /// Rust std::io write buffers (if any) are flushed, but other runtimes + /// (e.g. C stdio) or libraries that acquire a clone of the file handle + /// will not be aware of this change. + /// + /// ``` + /// #![feature(stdio_swap)] + /// use std::io::{self, Read, Write}; + /// use std::os::windows::io::StdioExt; + /// + /// fn main() -> io::Result<()> { + /// let (reader, mut writer) = io::pipe()?; + /// let mut stdin = io::stdin(); + /// stdin.set_handle(Some(reader))?; + /// writer.write_all(b"Hello, world!")?; + /// let mut buffer = vec![0; 13]; + /// assert_eq!(stdin.read(&mut buffer)?, 13); + /// assert_eq!(&buffer, b"Hello, world!"); + /// Ok(()) + /// } + /// ``` + fn set_handle>(&mut self, handle: Option) -> io::Result<()>; + + /// Sets the stdio console handle to `replace_with`. The previous handle is returned, or + /// `None` if it was `NULL`. + /// + /// The returned handle is a `BorrowedHandle<'static>` because console handles are shared global resources + /// and may have been obtained by other functions or threads. + /// Only if you have ensured that no other part of the program has borrowed this handle you can convert it into + /// an `OwnedHandle` and drop that to close it. + /// + /// Like `set_handle()`, Rust std::io write buffers (if any) are flushed. + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>>; + + /// Sets the stdio console handle to `NULL` and returns the old one + /// + /// See [`set_handle()`] for additional details. + /// + /// [`set_handle()`]: StdioExt::set_handle + fn take_handle(&mut self) -> io::Result>>; +} + +macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $handle:path, $writer:literal) { + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_ty { + fn set_handle>(&mut self, handle: Option) -> io::Result<()> { + self.lock().set_handle(handle) + } + + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>> { + self.lock().replace_handle(replace_with) + } + + fn take_handle(&mut self) -> io::Result>> { + self.lock().take_handle() + } + } + + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_lock_ty { + fn set_handle>(&mut self, handle: Option) -> io::Result<()> { + #[cfg($writer)] + self.flush()?; + let raw = handle.map(|h| h.into().into_raw_handle()).unwrap_or(ptr::null_mut()); + unsafe { c::SetStdHandle($handle, raw) }; + Ok(()) + } + + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>> { + let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }; + self.set_handle(Some(replace_with))?; + let handle = if old.as_raw_handle().is_null() { None } else { Some(old) }; + Ok(handle) + } + + fn take_handle(&mut self) -> io::Result>> { + let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }; + #[cfg($writer)] + self.flush()?; + unsafe { c::SetStdHandle($handle, ptr::null_mut()) }; + let handle = if old.as_raw_handle().is_null() { None } else { Some(old) }; + Ok(handle) + } + } +} + +io_ext_impl!(Stdout, StdoutLock<'_>, c::STD_OUTPUT_HANDLE, true); +io_ext_impl!(Stdin, StdinLock<'_>, c::STD_INPUT_HANDLE, false); +io_ext_impl!(Stderr, StderrLock<'_>, c::STD_ERROR_HANDLE, true); diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 0d3f24005f369..d050c28832517 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -142,7 +142,7 @@ impl<'a> AsRawHandle for io::StderrLock<'a> { // Translate a handle returned from `GetStdHandle` into a handle to return to // the user. -fn stdio_handle(raw: RawHandle) -> RawHandle { +pub(super) fn stdio_handle(raw: RawHandle) -> RawHandle { // `GetStdHandle` isn't expected to actually fail, so when it returns // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which // didn't provide us with stdio handles, such as a parent with a detached diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 71379202874ae..a0b2126af9a58 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2394,6 +2394,7 @@ SetFileTime SetHandleInformation SetLastError setsockopt +SetStdHandle SetThreadStackGuarantee SetWaitableTimer shutdown diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 9e867ec9dfae7..9c6f593e1e108 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -101,6 +101,7 @@ windows_link::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, windows_link::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR)); +windows_link::link!("kernel32.dll" "system" fn SetStdHandle(nstdhandle : STD_HANDLE, hhandle : HANDLE) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL); windows_link::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); diff --git a/library/std/src/sys/personality/emcc.rs b/library/std/src/sys/personality/emcc.rs deleted file mode 100644 index d374e3ad4c8f6..0000000000000 --- a/library/std/src/sys/personality/emcc.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward -//! to `__gxx_personality_v0` which is provided by Emscripten. - -use unwind as uw; - -use crate::ffi::c_int; - -// This is required by the compiler to exist (e.g., it's a lang item), but it's -// never actually called by the compiler. Emscripten EH doesn't use a -// personality function at all, it instead uses __cxa_find_matching_catch. -// Wasm error handling would use __gxx_personality_wasm0. -#[lang = "eh_personality"] -unsafe extern "C" fn rust_eh_personality( - _version: c_int, - _actions: uw::_Unwind_Action, - _exception_class: uw::_Unwind_Exception_Class, - _exception_object: *mut uw::_Unwind_Exception, - _context: *mut uw::_Unwind_Context, -) -> uw::_Unwind_Reason_Code { - core::intrinsics::abort() -} diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index eabef92244d01..3b363aa2d024c 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -14,9 +14,6 @@ mod dwarf; #[cfg(not(any(test, doctest)))] cfg_select! { - target_os = "emscripten" => { - mod emcc; - } any(target_env = "msvc", target_family = "wasm", target_os = "motor") => { // This is required by the compiler to exist (e.g., it's a lang item), // but it's never actually called by the compiler because diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index dce3ea8c7e007..3725375a713dc 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -37,8 +37,10 @@ cfg_select! { ) => { mod libunwind; pub use libunwind::*; + mod types; } target_family = "wasm" => { + mod types; mod wasm; pub use wasm::*; } diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index aee03879dd0a6..bfa6b1b33008f 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -8,69 +8,12 @@ pub use unwinding::custom_eh_frame_finder::{ EhFrameFinder, FrameInfo, FrameInfoKind, set_custom_eh_frame_finder, }; -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EHABI -} -pub use _Unwind_Reason_Code::*; +pub use crate::types::*; -pub type _Unwind_Exception_Class = u64; -pub type _Unwind_Word = *const u8; pub type _Unwind_Ptr = *const u8; -pub type _Unwind_Trace_Fn = - extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code; - -pub const unwinder_private_data_size: usize = cfg_select! { - target_arch = "x86" => 5, - all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))) => 2, - all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")) => 6, - all(target_arch = "arm", not(target_vendor = "apple")) => 20, - all(target_arch = "arm", target_vendor = "apple") => 5, - all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")) => 2, - all(target_arch = "aarch64", target_pointer_width = "64", target_os = "windows") => 6, - all(target_arch = "aarch64", target_pointer_width = "32") => 5, - target_arch = "m68k" => 2, - any(target_arch = "mips", target_arch = "mips32r6") => 2, - target_arch = "csky" => 2, - any(target_arch = "mips64", target_arch = "mips64r6") => 2, - any(target_arch = "powerpc", target_arch = "powerpc64") => 2, - target_arch = "s390x" => 2, - any(target_arch = "sparc", target_arch = "sparc64") => 2, - any(target_arch = "riscv64", target_arch = "riscv32") => 2, - all(target_family = "wasm", target_os = "emscripten") => 20, - all(target_arch = "wasm32", any(target_os = "linux", target_os = "wasi")) => 2, - target_arch = "hexagon" => 5, - any(target_arch = "loongarch32", target_arch = "loongarch64") => 2, -}; - -#[repr(C)] -pub struct _Unwind_Exception { - pub exception_class: _Unwind_Exception_Class, - pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, - pub private: [_Unwind_Word; unwinder_private_data_size], -} - -// Check the size of _Unwind_Exception against the source of thruth when using the unwinding crate. -#[cfg(target_os = "xous")] -const _: () = { - assert!(size_of::() == size_of::<_Unwind_Exception>()); -}; pub enum _Unwind_Context {} -pub type _Unwind_Exception_Cleanup_Fn = - Option; - // FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in // the block are reexported in dylib build of std. This is needed when build rustc with // feature `llvm-libunwind`, as no other cdylib will provided those _Unwind_* symbols. @@ -110,10 +53,10 @@ cfg_select! { pub type _Unwind_Action = c_int; pub const _UA_SEARCH_PHASE: c_int = 1; - pub const _UA_CLEANUP_PHASE: c_int = 2; - pub const _UA_HANDLER_FRAME: c_int = 4; + //pub const _UA_CLEANUP_PHASE: c_int = 2; + //pub const _UA_HANDLER_FRAME: c_int = 4; pub const _UA_FORCE_UNWIND: c_int = 8; - pub const _UA_END_OF_STACK: c_int = 16; + //pub const _UA_END_OF_STACK: c_int = 16; #[cfg_attr( all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), @@ -122,11 +65,9 @@ cfg_select! { unsafe extern "C" { pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word; pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word); - pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word; pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word); pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) -> _Unwind_Word; - pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; } } @@ -213,12 +154,6 @@ cfg_select! { (&raw mut value) as *mut c_void); } } - pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) - -> _Unwind_Word { - let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; - val.map_addr(|v| v & !1) - } - pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) { // Propagate thumb bit to instruction pointer @@ -230,47 +165,24 @@ cfg_select! { pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) -> _Unwind_Word { - unsafe { - *ip_before_insn = 0; - _Unwind_GetIP(ctx) - } - } - - // This function also doesn't exist on Android or ARM/Linux, so make it a no-op - pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { - pc + unsafe { *ip_before_insn = 0 }; + let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; + val.map_addr(|v| v & !1) } } } -cfg_select! { - all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm") => { - // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and - // does not provide _Unwind_Backtrace() - unsafe extern "C-unwind" { - pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - } - - pub use _Unwind_SjLj_RaiseException as _Unwind_RaiseException; - } - _ => { - #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), - link(name = "unwind", kind = "static", modifiers = "-bundle") - )] - unsafe extern "C-unwind" { - pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - } - #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), - link(name = "unwind", kind = "static", modifiers = "-bundle") - )] - unsafe extern "C" { - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut c_void) - -> _Unwind_Reason_Code; - } - } +#[cfg_attr( + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + link(name = "unwind", kind = "static", modifiers = "-bundle") +)] +unsafe extern "C-unwind" { + // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj + #[cfg_attr( + all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"), + link_name = "_Unwind_SjLj_RaiseException" + )] + pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } cfg_select! { diff --git a/library/unwind/src/types.rs b/library/unwind/src/types.rs new file mode 100644 index 0000000000000..413cd677fe7e0 --- /dev/null +++ b/library/unwind/src/types.rs @@ -0,0 +1,59 @@ +#![allow(nonstandard_style)] + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EHABI +} +pub use _Unwind_Reason_Code::*; + +pub type _Unwind_Exception_Class = u64; +pub type _Unwind_Word = *const u8; + +pub const unwinder_private_data_size: usize = cfg_select! { + target_arch = "x86" => 5, + all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))) => 2, + all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")) => 6, + all(target_arch = "arm", not(target_vendor = "apple")) => 20, + all(target_arch = "arm", target_vendor = "apple") => 5, + all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")) => 2, + all(target_arch = "aarch64", target_pointer_width = "64", target_os = "windows") => 6, + all(target_arch = "aarch64", target_pointer_width = "32") => 5, + target_arch = "m68k" => 2, + any(target_arch = "mips", target_arch = "mips32r6") => 2, + target_arch = "csky" => 2, + any(target_arch = "mips64", target_arch = "mips64r6") => 2, + any(target_arch = "powerpc", target_arch = "powerpc64") => 2, + target_arch = "s390x" => 2, + any(target_arch = "sparc", target_arch = "sparc64") => 2, + any(target_arch = "riscv64", target_arch = "riscv32") => 2, + all(target_family = "wasm", target_os = "emscripten") => 20, + target_family = "wasm" => 2, + target_arch = "hexagon" => 5, + any(target_arch = "loongarch32", target_arch = "loongarch64") => 2, +}; + +#[repr(C)] +pub struct _Unwind_Exception { + pub exception_class: _Unwind_Exception_Class, + pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, + pub private: [_Unwind_Word; unwinder_private_data_size], +} + +// Check the size of _Unwind_Exception against the source of truth when using the unwinding crate. +#[cfg(target_os = "xous")] +const _: () = { + assert!(size_of::() == size_of::<_Unwind_Exception>()); +}; + +pub type _Unwind_Exception_Cleanup_Fn = + Option; diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index 37d93bdbb67dd..ef961ae6410a4 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -26,36 +26,7 @@ core::arch::global_asm!( "__cpp_exception:", ); -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EHABI -} -pub use _Unwind_Reason_Code::*; - -pub type _Unwind_Exception_Class = u64; -pub type _Unwind_Word = *const u8; - -pub const unwinder_private_data_size: usize = 2; - -#[repr(C)] -pub struct _Unwind_Exception { - pub exception_class: _Unwind_Exception_Class, - pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, - pub private: [_Unwind_Word; unwinder_private_data_size], -} - -pub type _Unwind_Exception_Cleanup_Fn = - Option; +pub use crate::types::*; pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { if let Some(exception_cleanup) = unsafe { (*exception).exception_cleanup } { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index da8449f4f637b..9ddcb32c2e45d 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1239,6 +1239,14 @@ pub fn rustc_cargo( // . cargo.rustflag("-Zon-broken-pipe=kill"); + // /Brepro tells the MSVC linker to omit non-deterministic COFF data + // (namely the PE timestamp) from the produced binary. Only applied when + // building rustc itself via bootstrap. See discussion: + // https://github.com/rust-lang/rust/pull/158873 + if target.is_msvc() { + cargo.rustflag("-Clink-arg=/Brepro"); + } + // Building with protected visibility reduces the number of dynamic relocations needed, giving // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object // with direct references to protected symbols, so for now we only use protected symbols if diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile similarity index 94% rename from src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile rename to src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile index d8bfd6f52cb8b..72e06ff41c2f2 100644 --- a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile @@ -39,5 +39,5 @@ ENV RUST_CONFIGURE_ARGS \ # Tests are still compiled serially at the moment (intended to be changed in follow-ups). # Running compiletest only tests for parallel frontend, then the rest without compiletest-only # options (i.e. `--parallel-frontend-threads=4 --iteration-count=2`) -COPY ./scripts/optional-x86_64-gnu-parallel-frontend.sh /scripts/ +COPY ./scripts/x86_64-gnu-parallel-frontend.sh /scripts/ ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh b/src/ci/docker/scripts/x86_64-gnu-parallel-frontend.sh similarity index 100% rename from src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh rename to src/ci/docker/scripts/x86_64-gnu-parallel-frontend.sh diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index e03ad184842e3..e6e3c1acd853b 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -382,11 +382,10 @@ auto: - name: x86_64-gnu <<: *job-linux-4c - - name: optional-x86_64-gnu-parallel-frontend - # This test can be flaky, so do not cancel CI if it fails, for now. - continue_on_error: true + - name: x86_64-gnu-parallel-frontend + doc_url: https://rustc-dev-guide.rust-lang.org/tests/x86_64-gnu-parallel-frontend.html env: - DOCKER_SCRIPT: optional-x86_64-gnu-parallel-frontend.sh + DOCKER_SCRIPT: x86_64-gnu-parallel-frontend.sh <<: *job-linux-4c # This job ensures commits landing on nightly still pass the full diff --git a/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md b/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md new file mode 100644 index 0000000000000..e8c91044be1d7 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md @@ -0,0 +1,12 @@ +# Parallel frontend testing on CI + +If you see any test failures in `tests/ui` from the CI job `x86_64-gnu-parallel-frontend`, please +add `//@ ignore-parallel-frontend triage` to the failing test, even if your PR is otherwise +entirely unrelated to parallel compiler or its testing. +In some time people from the parallel rustc working group will triage the failing test, make a +tracking issue for it, and try to debug the problem. + +For more context, see: + +* [MCP: Stabilization strategy for rustc parallel frontend](https://github.com/rust-lang/compiler-team/issues/1005) +* Tracking issue: diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a4fa28e13b911..770734195ed89 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -818,7 +818,7 @@ impl<'test> TestCx<'test> { if !unexpected.is_empty() { writeln!( self.stdout, - "\n{prefix}: {n} diagnostics reported in JSON output but not expected in test file", + "\n{prefix}: {n} diagnostics reported in rustc output but not expected in test file", prefix = self.error_prefix(), n = unexpected.len(), ); @@ -853,7 +853,7 @@ impl<'test> TestCx<'test> { if !not_found.is_empty() { writeln!( self.stdout, - "\n{prefix}: {n} diagnostics expected in test file but not reported in JSON output", + "\n{prefix}: {n} diagnostics expected in test file but not reported in rustc output", prefix = self.error_prefix(), n = not_found.len(), ); diff --git a/src/tools/rust-analyzer/CLAUDE.md b/src/tools/rust-analyzer/CLAUDE.md index e8f699d92813a..4e536234ba100 100644 --- a/src/tools/rust-analyzer/CLAUDE.md +++ b/src/tools/rust-analyzer/CLAUDE.md @@ -1,40 +1,60 @@ -**Reminder: All AI usage must be disclosed in commit messages, see -CONTRIBUTING.md for more details.** +## AI Policy -## Build Commands +Follow `AI_POLICY.md`. In particular: -```bash -cargo build # Build all crates -cargo test # Run all tests -cargo test -p # Run tests for a specific crate (e.g., cargo test -p hir-ty) -cargo lint # Run clippy on all targets -cargo xtask codegen # Run code generation -cargo xtask tidy # Run tidy checks -UPDATE_EXPECT=1 cargo test # Update test expectations (snapshot tests) -RUN_SLOW_TESTS=1 cargo test # Run heavy/slow tests -``` +- Do not use AI to author issue/PR comments or replies to maintainers. +- Do not autonomously open issues or pull requests. +- Do not author code for issues labeled both `E-easy` and `E-has-instructions`. +- The human contributor must understand the changes and disclose AI use as required by the policy. -## Key Architectural Invariants -- Typing in a function body never invalidates global derived data -- Parser/syntax tree is built per-file to enable parallel parsing -- The server is stateless (HTTP-like); context must be re-created from request parameters -- Cancellation uses salsa's cancellation mechanism; computations panic with a `Cancelled` payload +## Repository Guides -### Code Generation +- Architecture and crate ownership: `docs/book/src/contributing/architecture.md` +- Rust style: `docs/book/src/contributing/style.md` +- Testing conventions and fixture syntax: `docs/book/src/contributing/testing.md` +- Contributor workflows: `docs/book/src/contributing/README.md` +- AI restrictions: `AI_POLICY.md` -Generated code is committed to the repo. Grammar and AST are generated from `ungrammar`. Run `cargo test -p xtask` after adding inline parser tests (`// test test_name` comments). +Read the relevant sections before making architectural, generated-code, protocol, or test-harness changes. + +## Change Workflow + +- Find the nearest existing implementation and its tests before adding new code. +- Extend existing helpers and test harnesses instead of creating parallel abstractions. +- Keep changes focused and prefer the smallest change that fits the existing design. +- When fixing a bug, add the smallest fixture that reproduces it and test the behavior through the existing interface. + +## Scope and Dependencies + +- Treat new `pub` items, public re-exports, and Cargo dependencies as architectural changes, not routine implementation details. +- Prefer keeping functionality inside the crate that owns the relevant data. +- Be conservative with crates.io dependencies. Reuse existing dependencies or `stdx`; do not add small helper crates without strong justification. + +## Key Invariants + +- User-provided Rust code, malformed syntax, broken builds, and proc-macro failures must not cause ordinary IDE features to panic. +- Assert invariants liberally. For impossible conditions from which the server can recover, prefer `stdx::never!` or `stdx::always!` and return a safe fallback instead of panicking. ## Testing -Tests are snapshot-based using `expect-test`. Test fixtures use a mini-language: -- `$0` marks cursor position -- `// ^^^^` labels attach to the line above -- `//- minicore: sized, fn` includes parts of minicore (minimal core library) -- `//- /path/to/file.rs crate:name deps:dep1,dep2` declares files/crates +- Many feature tests use Rust-code fixtures and `expect-test` snapshots. Follow the nearest existing test helper and fixture convention rather than introducing a new test harness. +- Before planning or writing fixture-based tests, review `docs/book/src/contributing/testing.md` for fixture annotations, `minicore`, and multi-file/multi-crate syntax. +- Keep Rust fixtures minimal; remove syntax unrelated to the behavior under test. +- Use unindented multiline raw strings, matching nearby tests. +- For regressions, first reproduce the failure with a focused test, then implement the fix. + +## Generated Code + +- Generated files are committed. Edit the generator rather than generated output. +- Run `cargo xtask codegen` after changing grammar, generated AST definitions, configuration schemas, or other codegen inputs. +- After adding parser inline tests (`// test name`), run `cargo test -p xtask`, update the relevant expectations, and inspect the generated diff. -## Style Notes +## Validation -- Use `stdx::never!` and `stdx::always!` instead of `assert!` for recoverable invariants -- Use `T![fn]` macro instead of `SyntaxKind::FN_KW` -- Use keyword name mangling over underscore prefixing for identifiers: `crate` → `krate`, `fn` → `func`, `struct` → `strukt`, `type` → `ty` +- Start with the narrowest relevant test: `cargo test -p ` or `cargo test -p `. +- After Rust changes, run the affected crate's tests and `cargo clippy -p --all-targets -- --cap-lints warn`; broaden validation when the change crosses crates. +- Use `cargo lint` to run Clippy on all workspace targets. +- Run `cargo xtask tidy` for repository-wide structural or generated-code changes. +- When updating snapshots with `UPDATE_EXPECT=1`, inspect the expectation diff rather than accepting it blindly. +- Use `RUN_SLOW_TESTS=1 cargo test` when the affected area has slow tests. diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b2dc4ceeddca6..e02b9e157bc5f 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -95,7 +95,6 @@ dependencies = [ "indexmap", "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "query-group-macro", "rustc-hash 2.1.2", "salsa", "salsa-macros", @@ -825,6 +824,7 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ra-ap-rustc_type_ir", "rustc-hash 2.1.2", + "salsa", "serde_json", "smallvec", "span", @@ -863,7 +863,6 @@ dependencies = [ "rustc-hash 2.1.2", "rustc_apfloat", "salsa", - "salsa-macros", "smallvec", "span", "stdx", @@ -892,7 +891,6 @@ dependencies = [ "parser", "rustc-hash 2.1.2", "salsa", - "salsa-macros", "smallvec", "span", "stdx", @@ -925,7 +923,6 @@ dependencies = [ "oorandom", "petgraph", "project-model", - "query-group-macro", "ra-ap-rustc_abi", "ra-ap-rustc_ast_ir", "ra-ap-rustc_index", @@ -935,7 +932,6 @@ dependencies = [ "rustc-hash 2.1.2", "rustc_apfloat", "salsa", - "salsa-macros", "serde", "serde_derive", "smallvec", @@ -1136,7 +1132,6 @@ dependencies = [ "rayon", "rustc-hash 2.1.2", "salsa", - "salsa-macros", "smallvec", "span", "stdx", @@ -2037,18 +2032,6 @@ dependencies = [ "pulldown-cmark", ] -[[package]] -name = "query-group-macro" -version = "0.0.0" -dependencies = [ - "expect-test", - "proc-macro2", - "quote", - "salsa", - "salsa-macros", - "syn", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -2484,6 +2467,7 @@ dependencies = [ "smallvec", "thin-vec", "tracing", + "triomphe", "typeid", ] @@ -3089,6 +3073,10 @@ name = "triomphe" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" +dependencies = [ + "serde", + "stable_deref_trait", +] [[package]] name = "tt" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 96ddbbb5cad9c..2a219c3ea485c 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,6 +131,7 @@ salsa = { version = "0.27.0", default-features = false, features = [ "salsa_unstable", "macros", "inventory", + "triomphe" ] } salsa-macros = "0.27.0" semver = "1.0.26" diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 55dfcbc7e508a..fe0c288441f11 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -17,7 +17,6 @@ la-arena.workspace = true dashmap.workspace = true salsa.workspace = true salsa-macros.workspace = true -query-group.workspace = true rustc-hash.workspace = true triomphe.workspace = true semver.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs index a77b45f8ae68a..f674c5df956d5 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs @@ -16,57 +16,24 @@ pub struct EditionedFileId { field: span::EditionedFileId, } -// Currently does not work due to a salsa bug -// #[salsa::tracked] -// impl EditionedFileId { -// #[salsa::tracked(lru = 128)] -// pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse { -// let _p = tracing::info_span!("parse", ?self).entered(); -// let (file_id, edition) = self.unpack(db); -// let text = db.file_text(file_id).text(db); -// ast::SourceFile::parse(text, edition) -// } - -// // firewall query -// #[salsa::tracked(returns(as_deref))] -// pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option> { -// let errors = self.parse(db).errors(); -// match &*errors { -// [] => None, -// [..] => Some(errors.into()), -// } -// } -// } - +#[salsa::tracked] impl EditionedFileId { + #[salsa::tracked(lru = 128)] pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse { - #[salsa::tracked(lru = 128)] - pub fn parse( - db: &dyn SourceDatabase, - file_id: EditionedFileId, - ) -> syntax::Parse { - let _p = tracing::info_span!("parse", ?file_id).entered(); - let (file_id, edition) = file_id.unpack(db); - let text = db.file_text(file_id).text(db); - ast::SourceFile::parse(text, edition) - } - parse(db, self) + let _p = tracing::info_span!("parse", ?self).entered(); + let (file_id, edition) = self.unpack(db); + let text = db.file_text(file_id).text(db); + ast::SourceFile::parse(text, edition) } // firewall query - pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<&[SyntaxError]> { - #[salsa::tracked(returns(as_deref))] - pub fn parse_errors( - db: &dyn SourceDatabase, - file_id: EditionedFileId, - ) -> Option> { - let errors = file_id.parse(db).errors(); - match &*errors { - [] => None, - [..] => Some(errors.into()), - } + #[salsa::tracked(returns(as_deref))] + pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option> { + let errors = self.parse(db).errors(); + match &*errors { + [] => None, + [..] => Some(errors.into()), } - parse_errors(db, self) } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 38f9c5a5a14c4..1e32ee69804c7 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -447,7 +447,7 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; -#[salsa_macros::input] +#[salsa::input] #[derive(Debug, PartialOrd, Ord)] pub struct Crate { #[returns(ref)] diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 94d9d08e50ff4..4beeae9508652 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,15 +1,48 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. +// FIXME: Rename this crate, base db is non descriptive #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; -pub use salsa; +pub mod salsa { + pub use salsa::*; + + // Adjusted from `salsa::update_fallback` to work with database owned T + /// "Fallback" for maybe-update that is suitable for database owned T + /// that implement `Eq`. In this version, we update only if the new value + /// is not `Eq` to the old one. Note that given `Eq` impls that are not just + /// structurally comparing fields, this may cause us not to update even if + /// the value has changed (presumably because this change is not semantically + /// significant). + /// + /// # Safety + /// + /// See `Update::maybe_update`, additionally, `'db` is required to be `'static` or the lifetime + /// of the database `T` belongs to. + pub unsafe fn update_fallback_db<'db, T>(old_pointer: *mut T, new_value: T) -> bool + where + T: 'db + PartialEq, + { + // SAFETY: Because everything is owned, this ref is simply a valid `&mut` + 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 use salsa_macros; use span::TextSize; -// FIXME: Rename this crate, base db is non descriptive mod change; mod editioned_file_id; mod input; @@ -33,7 +66,6 @@ pub use crate::{ }, }; use dashmap::{DashMap, mapref::entry::Entry}; -pub use query_group; use rustc_hash::{FxHashSet, FxHasher}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; @@ -47,7 +79,7 @@ pub type FxIndexMap = #[macro_export] macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { - #[salsa_macros::interned(no_lifetime, revisions = usize::MAX)] + #[salsa::interned(no_lifetime, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct $id { #[returns(ref)] @@ -65,28 +97,6 @@ macro_rules! impl_intern_key { }; } -/// # SAFETY -/// -/// `old_pointer` must be valid for unique writes -pub unsafe fn unsafe_update_eq(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; @@ -236,25 +246,25 @@ pub struct LocalRoots { pub roots: FxHashSet, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct FileText { #[returns(ref)] pub text: Arc, pub file_id: vfs::FileId, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct FileSourceRootInput { pub source_root_id: SourceRootId, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct SourceRootInput { pub source_root: Arc, } -#[salsa_macros::db] -pub trait SourceDatabase: salsa::Database { +#[salsa::db] +pub trait SourceDatabase: salsa::Database + std::fmt::Debug { /// Text of the file. fn file_text(&self, file_id: vfs::FileId) -> FileText; diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index 038ddecdb5d7d..eb1e774b8f41b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -2,7 +2,7 @@ name = "hir-def" version = "0.0.0" repository.workspace = true -description = "RPC Api for the `proc-macro-srv` crate of rust-analyzer." +description = "Early name and import resolution for rust-analyzer." authors.workspace = true edition.workspace = true @@ -28,7 +28,6 @@ smallvec.workspace = true triomphe.workspace = true rustc_apfloat = "0.2.3" salsa.workspace = true -salsa-macros.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index dec911f7161da..32d16957ae5fa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -30,9 +30,9 @@ use crate::{ AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, expr_store::path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, hir::{ - Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, InlineAsm, Label, - LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, - Statement, + Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, + InlineAsm, Label, LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, + RecordSpread, Statement, }, nameres::{DefMap, block_def_map}, signatures::VariantFields, @@ -127,7 +127,7 @@ struct ExpressionOnlyStore { /// /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer /// to variables and have hygiene (some refer to items, we don't know at this stage). - ident_hygiene: FxHashMap, + ident_hygiene: FxHashMap, /// Maps expression roots to their origin. /// @@ -154,9 +154,6 @@ struct ExpressionOnlyStore { /// and it does not bother us because we use this list for two things: constructing `ExprScopes`, which /// works fine with nested exprs, and retrieving inference results, and we copy the inner const's inference /// into the outer const. - // FIXME: Array repeat is not problematic indeed, but this could still break with exprs in types, - // which we do not visit for `ExprScopes` (they're fine for inference though). We either need to visit them, - // or use a more complicated search. expr_roots: SmallVec<[ExprRoot; 1]>, } @@ -171,10 +168,10 @@ pub struct ExpressionStore { struct ExpressionOnlySourceMap { // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). - expr_map: FxHashMap, + expr_map: FxHashMap, expr_map_back: ArenaMap, - pat_map: FxHashMap, + pat_map: FxHashMap, pat_map_back: ArenaMap, label_map: FxHashMap, @@ -270,15 +267,15 @@ pub struct ExpressionStoreBuilder { pub binding_owners: FxHashMap, pub types: Arena, block_scopes: Vec, - ident_hygiene: FxHashMap, + ident_hygiene: FxHashMap, inference_roots: Option>, // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). - expr_map: FxHashMap, + expr_map: FxHashMap, expr_map_back: ArenaMap, - pat_map: FxHashMap, + pat_map: FxHashMap, pat_map_back: ArenaMap, label_map: FxHashMap, @@ -779,7 +776,6 @@ impl ExpressionStore { | Expr::Await { expr } | Expr::Ref { expr, mutability: _, rawness: _ } | Expr::UnaryOp { expr, op: _ } - | Expr::Box { expr } | Expr::Const(expr) => { visitor.on_expr(*expr); } @@ -874,7 +870,7 @@ impl ExpressionStore { visitor.on_anon_const_expr(*len); } TypeRef::Fn(fn_type) => { - let FnType { params, is_varargs: _, is_unsafe: _, abi: _ } = &**fn_type; + let FnType { params, is_varargs: _, is_unsafe: _, abi: _, binder: _ } = &**fn_type; params.iter().for_each(|(_, param_ty)| visitor.on_type(*param_ty)); } TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { @@ -1175,7 +1171,7 @@ impl ExpressionStoreSourceMap { pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option { let src = node.map(AstPtr::new); - self.expr_only()?.expr_map.get(&src).cloned() + self.expr_only()?.expr_map.get(&src).cloned().map(ExprOrPatIdPacked::unpack) } pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { @@ -1192,7 +1188,11 @@ impl ExpressionStoreSourceMap { } pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { - self.expr_only()?.pat_map.get(&node.map(AstPtr::new)).cloned() + self.expr_only()? + .pat_map + .get(&node.map(AstPtr::new)) + .cloned() + .map(ExprOrPatIdPacked::unpack) } pub fn type_syntax(&self, id: TypeRefId) -> Result { @@ -1226,7 +1226,7 @@ impl ExpressionStoreSourceMap { pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option { let src = node.map(AstPtr::new).map(AstPtr::upcast::).map(AstPtr::upcast); - self.expr_only()?.expr_map.get(&src).copied() + self.expr_only()?.expr_map.get(&src).copied().map(ExprOrPatIdPacked::unpack) } pub fn expansions(&self) -> impl Iterator, &MacroCallId)> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 0320f6b93b973..df4fc6e531466 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -26,7 +26,7 @@ use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, ast::{ - self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs, + self, ArrayExprKind, AstChildren, BlockExpr, ForBinder, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, SlicePatComponents, }, @@ -465,6 +465,8 @@ pub struct ExprCollector<'db> { is_lowering_coroutine: bool, + for_type_binder: Option>, + /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other, /// and we need to find the current definition. So we track the number of definitions we saw. current_block_legacy_macro_defs_count: FxHashMap, @@ -636,6 +638,7 @@ impl<'db> ExprCollector<'db> { krate, name_generator_index: 0, named_lifetime_store: NamedLifetimeStore::default(), + for_type_binder: None, }; result.store.inference_roots = Some(SmallVec::new()); result @@ -758,16 +761,23 @@ impl<'db> ExprCollector<'db> { let abi = inner.abi().map(lower_abi).unwrap_or(ExternAbi::Rust); params.push((None, ret_ty)); + + let binder = self.for_type_binder.take().map(|b| b.into()); TypeRef::Fn(Box::new(FnType { is_varargs, is_unsafe: inner.unsafe_token().is_some(), abi, params: params.into_boxed_slice(), + binder, })) } // for types are close enough for our purposes to the inner type for now... ast::Type::ForType(inner) => { - return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn); + let binder = self.lower_for_binder_opt(inner.for_binder()); + let old_for_binder = self.for_type_binder.replace(binder); + let ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn); + self.for_type_binder = old_for_binder; + return ty; } ast::Type::ImplTraitType(inner) => { if self.outer_impl_trait { @@ -1245,13 +1255,7 @@ impl<'db> ExprCollector<'db> { 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 - .lifetime_params() - .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<.text()))) - .collect(), - None => ThinVec::default(), - }; + let binder = self.lower_for_binder_opt(binder); let m = match node.question_mark_token() { Some(_) => TraitBoundModifier::Maybe, None => TraitBoundModifier::None, @@ -1283,6 +1287,20 @@ impl<'db> ExprCollector<'db> { } } + fn lower_for_binder_opt(&mut self, binder: Option) -> ThinVec { + binder.map(|b| self.lower_for_binder(b)).unwrap_or_default() + } + + fn lower_for_binder(&mut self, binder: ForBinder) -> ThinVec { + match binder.generic_param_list() { + Some(gpl) => gpl + .lifetime_params() + .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<.text()))) + .collect(), + None => ThinVec::default(), + } + } + fn lower_const_arg_opt(&mut self, arg: Option) -> ConstRef { ConstRef { expr: self.with_fresh_binding_expr_root(|this| { @@ -1310,10 +1328,10 @@ impl<'db> ExprCollector<'db> { /// Returns `None` if and only if the expression is `#[cfg]`d out. fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { - let syntax_ptr = AstPtr::new(&expr); if !self.check_cfg(&expr) { return None; } + let syntax_ptr = AstPtr::new(&expr); // FIXME: Move some of these arms out into separate methods for clarity Some(match expr { @@ -1442,23 +1460,13 @@ impl<'db> ExprCollector<'db> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { - // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c - let is_rustc_box = { - let attrs = e.attrs(); - attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") - }; - if is_rustc_box { - let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next())); - self.alloc_expr(Expr::Box { expr }, syntax_ptr) + let callee = self.collect_expr_opt(e.expr()); + let args = if let Some(arg_list) = e.arg_list() { + arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() } else { - let callee = self.collect_expr_opt(e.expr()); - let args = if let Some(arg_list) = e.arg_list() { - arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() - } else { - Box::default() - }; - self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) - } + Box::default() + }; + self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) } ast::Expr::MethodCallExpr(e) => { let receiver = self.collect_expr_opt(e.receiver()); @@ -1589,7 +1597,7 @@ impl<'db> ExprCollector<'db> { }; Expr::RecordLit { path, fields, spread } } else { - Expr::RecordLit { path, fields: Box::default(), spread: RecordSpread::None } + Expr::RecordLit { path, fields: ThinVec::default(), spread: RecordSpread::None } }; self.alloc_expr(record_lit, syntax_ptr) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs index b058ad6d9ab8b..5552213aba55d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs @@ -7,15 +7,12 @@ use span::SyntaxContext; use syntax::{AstPtr, AstToken as _, ast}; use crate::{ - builtin_type::BuiltinUint, expr_store::{HygieneId, lower::ExprCollector, path::Path}, hir::{ - Array, BindingAnnotation, Expr, ExprId, Literal, Pat, RecordLitField, RecordSpread, - Statement, + Array, BindingAnnotation, Expr, ExprId, Literal, Pat, Statement, format_args::{ self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, - FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, - FormatPlaceholder, FormatSign, FormatTrait, + FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatSign, FormatTrait, }, }, lang_item::LangItemTarget, @@ -95,11 +92,7 @@ impl<'db> ExprCollector<'db> { ), }; - 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) - }; + let idx = self.collect_format_args_impl(syntax_ptr, fmt); self.store .template_map @@ -109,7 +102,9 @@ impl<'db> ExprCollector<'db> { idx } - fn collect_format_args_after_1_93_0_impl( + // This is in separate functions because historically, changes in format_args lowering have forced us to change this + // function but not its caller, and for some time support both versions. + fn collect_format_args_impl( &mut self, syntax_ptr: AstPtr, fmt: FormatArgs, @@ -432,548 +427,6 @@ impl<'db> ExprCollector<'db> { } } - fn collect_format_args_before_1_93_0_impl( - &mut self, - syntax_ptr: AstPtr, - 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, - 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 => [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::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, - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, 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: - // ::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, - 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 = [::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, - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, 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 = [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::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), - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, 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 { - // ::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 … - // ::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 - /// ::…, // alignment - /// …u32, // flags - /// , // width - /// , // 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 }; - match self.lang_path(lang_items.FormatPlaceholder) { - Some(path) => self.alloc_expr_desugared(Expr::RecordLit { - path, - fields: Box::new([position, flags, precision, width]), - spread: RecordSpread::None, - }), - None => self.missing_expr(), - } - } 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 - /// ::Is(…) - /// ``` - /// - /// or - /// - /// ```text - /// ::Param(…) - /// ``` - /// - /// or - /// - /// ```text - /// ::Implied - /// ``` - fn make_count_before_1_93_0( - &mut self, - count: &Option, - 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: diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index 2119f19c065d2..ce6e73670cba4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -220,13 +220,10 @@ impl GenericParamsCollector { ); let predicate = match (target, bound) { (_, TypeBound::Error | TypeBound::Use(_)) => return, - (Either::Left(type_ref), bound) => match hrtb_lifetimes { - Some(hrtb_lifetimes) => WherePredicate::ForLifetime { - lifetimes: ThinVec::from_iter(hrtb_lifetimes.iter().cloned()), - target: type_ref, - bound, - }, - None => WherePredicate::TypeBound { target: type_ref, bound }, + (Either::Left(type_ref), bound) => WherePredicate::TypeBound { + lifetimes: hrtb_lifetimes.map(|h| ThinVec::from_iter(h.iter().cloned())), + target: type_ref, + bound, }, (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { WherePredicate::Lifetime { target: lifetime, bound } @@ -257,8 +254,11 @@ impl GenericParamsCollector { })); let type_ref = ec.alloc_type_ref(param_id, ptr); for bound in impl_trait_bounds { - where_predicates - .push(WherePredicate::TypeBound { target: type_ref, bound: bound.clone() }); + where_predicates.push(WherePredicate::TypeBound { + lifetimes: None, + target: type_ref, + bound: bound.clone(), + }); } type_ref } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 0058ddc1e4a44..1c70922467e12 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -338,7 +338,17 @@ fn print_where_clauses( w!(p, ",\n"); } match pred { - WherePredicate::TypeBound { target, bound } => { + WherePredicate::TypeBound { lifetimes, target, bound } => { + if let Some(lifetimes) = lifetimes { + w!(p, "for<"); + for (i, lifetime) in lifetimes.iter().enumerate() { + if i != 0 { + w!(p, ", "); + } + w!(p, "{}", lifetime.display(db, p.edition)); + } + w!(p, "> "); + } p.print_type_ref(*target); w!(p, ": "); p.print_type_bounds(std::slice::from_ref(bound)); @@ -348,19 +358,6 @@ fn print_where_clauses( w!(p, ": "); p.print_lifetime_ref(*bound); } - WherePredicate::ForLifetime { lifetimes, target, bound } => { - w!(p, "for<"); - for (i, lifetime) in lifetimes.iter().enumerate() { - if i != 0 { - w!(p, ", "); - } - w!(p, "{}", lifetime.display(db, p.edition)); - } - w!(p, "> "); - p.print_type_ref(*target); - w!(p, ": "); - p.print_type_bounds(std::slice::from_ref(bound)); - } } } }); @@ -730,10 +727,6 @@ impl Printer<'_> { } self.print_expr_in(prec, *expr); } - Expr::Box { expr } => { - w!(self, "box "); - self.print_expr_in(prec, *expr); - } Expr::UnaryOp { expr, op } => { let op = match op { ast::UnaryOp::Deref => "*", @@ -1331,6 +1324,17 @@ impl Printer<'_> { TypeRef::Fn(fn_) => { let ((_, return_type), args) = fn_.params.split_last().expect("TypeRef::Fn is missing return type"); + if let Some(binder) = &fn_.binder { + w!( + self, + "for<{}> ", + binder + .iter() + .map(|it| it.display(self.db, self.edition)) + .format(", ") + .to_string() + ); + } if fn_.is_unsafe { w!(self, "unsafe "); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index c881a961b14b5..d6568b8cfe6ae 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -5,12 +5,13 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; use crate::{ BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, - expr_store::{Body, ExpressionStore, HygieneId, body::Param}, + expr_store::{Body, ExpressionStore, HygieneId, StoreVisitor, body::Param}, hir::{ Array, Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, generics::GenericParams, }, signatures::VariantFields, + type_ref::TypeRefId, }; pub type ScopeId = Idx; @@ -46,13 +47,18 @@ impl ScopeEntry { #[derive(Debug, PartialEq, Eq)] pub struct ScopeData { parent: Option, - block: Option, - label: Option<(LabelId, Name)>, - // FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters. - macro_def: Option>, + kind: ScopeKind, entries: IdxRange, } +#[derive(Debug, PartialEq, Eq)] +enum ScopeKind { + None, + Block { id: BlockId, label: Option }, + Label(LabelId), + MacroDef(Box), +} + #[salsa::tracked] impl ExprScopes { #[salsa::tracked(returns(ref))] @@ -100,18 +106,28 @@ impl ExprScopes { /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`. pub fn block(&self, scope: ScopeId) -> Option { - self.scopes[scope].block + match self.scopes[scope].kind { + ScopeKind::Block { id, label: _ } => Some(id), + ScopeKind::None | ScopeKind::Label(_) | ScopeKind::MacroDef(_) => None, + } } /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`. #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`. pub fn macro_def(&self, scope: ScopeId) -> Option<&Box> { - self.scopes[scope].macro_def.as_ref() + match &self.scopes[scope].kind { + ScopeKind::MacroDef(macro_def) => Some(macro_def), + ScopeKind::None | ScopeKind::Block { id: _, label: _ } | ScopeKind::Label(_) => None, + } } /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`. - pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> { - self.scopes[scope].label.clone() + pub fn label(&self, scope: ScopeId) -> Option { + match &self.scopes[scope].kind { + &ScopeKind::Block { id: _, label } => label, + &ScopeKind::Label(label) => Some(label), + ScopeKind::None | ScopeKind::MacroDef(_) => None, + } } /// Returns the scopes in ascending order. @@ -174,9 +190,7 @@ impl ExprScopes { fn root_scope(&mut self) -> ScopeId { self.scopes.alloc(ScopeData { parent: None, - block: None, - label: None, - macro_def: None, + kind: ScopeKind::None, entries: empty_entries(self.scope_entries.len()), }) } @@ -184,19 +198,19 @@ impl ExprScopes { fn new_scope(&mut self, parent: ScopeId) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label: None, - macro_def: None, + kind: ScopeKind::None, entries: empty_entries(self.scope_entries.len()), }) } - fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId { + fn new_labeled_scope(&mut self, parent: ScopeId, label: Option) -> ScopeId { + let kind = match label { + Some(label) => ScopeKind::Label(label), + None => ScopeKind::None, + }; self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label, - macro_def: None, + kind, entries: empty_entries(self.scope_entries.len()), }) } @@ -205,13 +219,16 @@ impl ExprScopes { &mut self, parent: ScopeId, block: Option, - label: Option<(LabelId, Name)>, + label: Option, ) -> ScopeId { + let kind = match (block, label) { + (Some(id), label) => ScopeKind::Block { id, label }, + (None, Some(label)) => ScopeKind::Label(label), + (None, None) => ScopeKind::None, + }; self.scopes.alloc(ScopeData { parent: Some(parent), - block, - label, - macro_def: None, + kind, entries: empty_entries(self.scope_entries.len()), }) } @@ -219,9 +236,7 @@ impl ExprScopes { fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label: None, - macro_def: Some(macro_id), + kind: ScopeKind::MacroDef(macro_id), entries: empty_entries(self.scope_entries.len()), }) } @@ -260,6 +275,42 @@ impl ExprScopes { } } +struct ExprScopeVisitor<'a> { + store: &'a ExpressionStore, + scopes: &'a mut ExprScopes, + scope: &'a mut ScopeId, + const_scope: &'a mut ScopeId, +} + +impl StoreVisitor for ExprScopeVisitor<'_> { + fn on_expr(&mut self, expr: ExprId) { + compute_expr_scopes(expr, self.store, self.scopes, self.scope, self.const_scope); + } + + fn on_anon_const_expr(&mut self, expr: ExprId) { + let mut scope = *self.const_scope; + compute_expr_scopes(expr, self.store, self.scopes, &mut scope, self.const_scope); + } + + fn on_pat(&mut self, pat: PatId) { + self.store.visit_pat_children(pat, &mut *self); + } + + fn on_type(&mut self, ty: TypeRefId) { + self.store.visit_type_ref_children(ty, &mut *self); + } +} + +fn compute_type_scopes( + ty: TypeRefId, + store: &ExpressionStore, + scopes: &mut ExprScopes, + const_scope: &mut ScopeId, +) { + let mut scope = *const_scope; + ExprScopeVisitor { store, scopes, scope: &mut scope, const_scope }.on_type(ty); +} + fn compute_block_scopes( statements: &[Statement], tail: Option, @@ -270,7 +321,10 @@ fn compute_block_scopes( ) { for stmt in statements { match stmt { - Statement::Let { pat, initializer, else_branch, .. } => { + Statement::Let { pat, initializer, else_branch, type_ref } => { + if let Some(type_ref) = type_ref { + compute_type_scopes(*type_ref, store, scopes, const_scope); + } if let Some(expr) = initializer { compute_expr_scopes(*expr, store, scopes, scope, const_scope); } @@ -303,8 +357,6 @@ fn compute_expr_scopes( scope: &mut ScopeId, const_scope: &mut ScopeId, ) { - let make_label = |label: Option| label.map(|label| (label, store[label].name.clone())); - let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId, const_scope: &mut ScopeId| { compute_expr_scopes(expr, store, scopes, scope, const_scope) @@ -316,7 +368,7 @@ fn compute_expr_scopes( scopes: &mut ExprScopes, scope: &mut ScopeId, const_scope: &mut ScopeId| { - let mut scope = scopes.new_block_scope(*scope, id, make_label(label)); + let mut scope = scopes.new_block_scope(*scope, id, label); let mut const_scope = if id.is_some() { scopes.new_block_scope(*const_scope, id, None) } else { @@ -347,10 +399,24 @@ fn compute_expr_scopes( handle_block(*id, statements, *tail, None, scopes, scope, const_scope); } Expr::Loop { body: body_expr, label, source: _ } => { - let mut scope = scopes.new_labeled_scope(*scope, make_label(*label)); + let mut scope = scopes.new_labeled_scope(*scope, *label); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } - Expr::Closure { args, body: body_expr, .. } => { + Expr::Closure { + args, + arg_types, + ret_type, + body: body_expr, + capture_by: _, + closure_kind: _, + } => { + arg_types + .iter() + .flatten() + .for_each(|type_ref| compute_type_scopes(*type_ref, store, scopes, const_scope)); + if let Some(type_ref) = ret_type { + compute_type_scopes(*type_ref, store, scopes, const_scope); + } let mut scope = scopes.new_scope(*scope); args.iter().for_each(|arg| scopes.add_pat_bindings(store, scope, *arg)); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); @@ -380,7 +446,9 @@ fn compute_expr_scopes( *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(store, *scope, pat); } - _ => store.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope, const_scope)), + _ => { + store.visit_expr_children(expr, ExprScopeVisitor { store, scopes, scope, const_scope }) + } }; } @@ -452,6 +520,19 @@ mod tests { assert_eq_text!(&expected, &actual); } + #[test] + fn type_anon_const_scope() { + do_check( + r#" +fn f(param: usize) { + let local = 0; + let _: [(); $0] = []; +} +"#, + &["param"], + ); + } + #[test] fn test_lambda_scope() { do_check( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index c7b9edf3939fa..f199ef4f9fdba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -193,168 +193,6 @@ fn main() { ); } -#[test] -fn desugar_builtin_format_args_before_1_89_0() { - pretty_print( - r#" -//- minicore: fmt_before_1_89_0 -fn main() { - let are = "are"; - let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); -} -"#, - expect![[r#" - fn main() { - let are = "are"; - let count = 10; - builtin#lang(Arguments::new_v1_formatted)( - &[ - "\u{1b}hello ", " ", " friends, we ", " ", "", - ], - &[ - builtin#lang(Argument::new_display)( - &count, - ), builtin#lang(Argument::new_display)( - &"fancy", - ), builtin#lang(Argument::new_debug)( - &are, - ), builtin#lang(Argument::new_display)( - &"!", - ), - ], - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 8u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Is)( - 2, - ), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 2usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 3usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], - { - (); - unsafe { - builtin#lang(UnsafeArg::new)() - } - }, - ); - }"#]], - ) -} - -#[test] -fn desugar_builtin_format_args_before_1_93_0() { - pretty_print( - r#" -//- minicore: fmt_before_1_93_0 -fn main() { - let are = "are"; - let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); -} -"#, - expect![[r#" - fn main() { - let are = "are"; - let count = 10; - { - let 0 = (&"fancy", &(), &"!", &count, &are, ); - let 0 = [ - builtin#lang(Argument::new_display)( - 0.3, - ), builtin#lang(Argument::new_display)( - 0.0, - ), builtin#lang(Argument::new_debug)( - 0.4, - ), builtin#lang(Argument::new_display)( - 0.2, - ), - ]; - unsafe { - builtin#lang(Arguments::new_v1_formatted)( - &[ - "\u{1b}hello ", " ", " friends, we ", " ", "", - ], - &0, - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 8u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Is)( - 2, - ), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 2usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 3usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], - ) - } - }; - }"#]], - ) -} - #[test] fn desugar_builtin_format_args() { pretty_print( @@ -464,7 +302,7 @@ impl SsrError { fn regression_10300() { pretty_print( r#" -//- minicore: concat, panic, fmt_before_1_89_0 +//- minicore: concat, panic, fmt mod private { pub use core::concat; } @@ -480,22 +318,15 @@ fn f(a: i32, b: u32) -> String { } "#, expect![[r#" - fn f(a, b) { - { - core::panicking::panic_fmt( - builtin#lang(Arguments::new_v1_formatted)( - &[ + fn f(a, b) { + { + core::panicking::panic_fmt( + builtin#lang(Arguments::from_str)( "cc", - ], - &[], - &[], - unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), - ); - }; - }"#]], + ), + ); + }; + }"#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 2f502e49157c2..daece7fc5d566 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -407,6 +407,10 @@ fn find_in_sysroot<'db>( if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; } + search(LangCrateOrigin::Alloc, best_choice); + if matches!(best_choice, Some(Choice { stability: Stable, .. })) { + return; + } search(LangCrateOrigin::Std, best_choice); if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; @@ -420,6 +424,10 @@ fn find_in_sysroot<'db>( if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; } + search(LangCrateOrigin::Alloc, best_choice); + if matches!(best_choice, Some(Choice { stability: Stable, .. })) { + return; + } } dependencies .iter() @@ -1570,6 +1578,43 @@ pub mod sync { //- /zzz.rs crate:alloc +pub mod sync { + pub struct Arc; +} + "#, + "alloc::sync::Arc", + expect![[r#" + Plain (imports ✔): alloc::sync::Arc + Plain (imports ✖): alloc::sync::Arc + ByCrate(imports ✔): alloc::sync::Arc + ByCrate(imports ✖): alloc::sync::Arc + BySelf (imports ✔): alloc::sync::Arc + BySelf (imports ✖): alloc::sync::Arc + "#]], + ); + } + + #[test] + fn prefer_alloc_paths_over_std_with_extern_crate_std() { + check_found_path( + r#" +//- /main.rs crate:main deps:alloc,std +#![no_std] + +extern crate alloc; + +extern crate std; + +$0 + +//- /std.rs crate:std deps:alloc + +pub mod sync { + pub use alloc::sync::Arc; +} + +//- /zzz.rs crate:alloc + pub mod sync { pub struct Arc; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index a80056904402a..7e56282feb002 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -16,13 +16,14 @@ pub mod format_args; pub mod generics; pub mod type_ref; -use std::fmt; +use std::{fmt, mem}; use hir_expand::{MacroDefId, name::Name}; use intern::Symbol; -use la_arena::Idx; +use la_arena::{Idx, RawIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use syntax::ast; +use thin_vec::ThinVec; use type_ref::TypeRefId; use crate::{ @@ -43,9 +44,7 @@ pub type ExprId = Idx; pub type PatId = Idx; -// FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts -// are local to the body. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum ExprOrPatId { ExprId(ExprId), PatId(PatId), @@ -74,7 +73,83 @@ impl ExprOrPatId { matches!(self, Self::PatId(_)) } } -stdx::impl_from!(ExprId, PatId for ExprOrPatId); + +#[derive(Copy, Clone, Hash, PartialEq, Eq, salsa::Update)] +pub struct ExprOrPatIdPacked(u32); + +const _: () = assert!(mem::size_of::() == mem::size_of::()); + +impl ExprOrPatIdPacked { + const PAT_BIT: u32 = 1 << (u32::BITS - 1); + const INDEX_MASK: u32 = !Self::PAT_BIT; + + pub fn unpack(self) -> ExprOrPatId { + match self.is_expr() { + true => ExprOrPatId::ExprId(ExprId::from_raw(RawIdx::from_u32(self.0))), + false => { + ExprOrPatId::PatId(PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK))) + } + } + } + + #[inline] + pub fn as_expr(self) -> Option { + self.is_expr().then(|| ExprId::from_raw(RawIdx::from_u32(self.0))) + } + + #[inline] + pub fn is_expr(&self) -> bool { + self.0 & Self::PAT_BIT == 0 + } + + #[inline] + pub fn as_pat(self) -> Option { + self.is_pat().then(|| PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK))) + } + + #[inline] + pub fn is_pat(&self) -> bool { + self.0 & Self::PAT_BIT != 0 + } +} + +impl fmt::Debug for ExprOrPatIdPacked { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.unpack() { + ExprOrPatId::ExprId(id) => f.debug_tuple("ExprId").field(&id).finish(), + ExprOrPatId::PatId(id) => f.debug_tuple("PatId").field(&id).finish(), + } + } +} + +impl From for ExprOrPatIdPacked { + fn from(value: ExprId) -> Self { + let value = value.into_raw().into_u32(); + // virtually impossible to have IDs that high + debug_assert_eq!(value & Self::PAT_BIT, 0); + Self(value) + } +} + +impl From for ExprOrPatId { + fn from(value: PatId) -> Self { + ExprOrPatId::PatId(value) + } +} +impl From for ExprOrPatId { + fn from(value: ExprId) -> Self { + ExprOrPatId::ExprId(value) + } +} + +impl From for ExprOrPatIdPacked { + fn from(value: PatId) -> Self { + let value = value.into_raw().into_u32(); + // virtually impossible to have IDs that high + debug_assert_eq!(value & Self::PAT_BIT, 0); + Self(value | Self::PAT_BIT) + } +} #[derive(Debug, Clone, Eq, PartialEq)] pub struct Label { @@ -261,7 +336,7 @@ pub enum Expr { }, RecordLit { path: Path, - fields: Box<[RecordLitField]>, + fields: ThinVec, spread: RecordSpread, }, Field { @@ -280,9 +355,6 @@ pub enum Expr { rawness: Rawness, mutability: Mutability, }, - Box { - expr: ExprId, - }, UnaryOp { expr: ExprId, op: UnaryOp, @@ -326,6 +398,9 @@ pub enum Expr { IncludeBytes, } +#[cfg(target_pointer_width = "64")] +const _: () = assert!(std::mem::size_of::() == 48); + impl Expr { pub fn precedence(&self) -> ast::prec::ExprPrecedence { use ast::prec::ExprPrecedence; @@ -354,9 +429,7 @@ impl Expr { | Expr::Index { .. } | Expr::MethodCall { .. } => ExprPrecedence::Postfix, - Expr::Box { .. } | Expr::Let { .. } | Expr::UnaryOp { .. } | Expr::Ref { .. } => { - ExprPrecedence::Prefix - } + Expr::Let { .. } | Expr::UnaryOp { .. } | Expr::Ref { .. } => ExprPrecedence::Prefix, Expr::Cast { .. } => ExprPrecedence::Cast, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index b6e9fc28207ac..039b229429cf0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -185,9 +185,8 @@ impl ops::Index for GenericParams { /// associated type bindings like `Iterator`. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { - TypeBound { target: TypeRefId, bound: TypeBound }, + TypeBound { lifetimes: Option>, target: TypeRefId, bound: TypeBound }, Lifetime { target: LifetimeRefId, bound: LifetimeRefId }, - ForLifetime { lifetimes: ThinVec, target: TypeRefId, bound: TypeBound }, } static EMPTY: LazyLock = LazyLock::new(|| GenericParams { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 6cd8377b5fc6f..8e29268c1c219 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -94,6 +94,7 @@ pub struct TraitRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FnType { + pub binder: Option>, pub params: Box<[(Option, TypeRefId)]>, pub is_varargs: bool, pub is_unsafe: bool, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index ac1d2fd2a4660..1443d3ea4be4c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -12,7 +12,7 @@ use la_arena::Idx; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use span::Edition; -use stdx::format_to; +use stdx::{format_to, impl_from}; use syntax::ast; use thin_vec::ThinVec; @@ -37,14 +37,7 @@ pub enum ImportOrExternCrate { ExternCrate(ExternCrateId), } -impl From for ImportOrExternCrate { - fn from(value: ImportOrGlob) -> Self { - match value { - ImportOrGlob::Glob(it) => ImportOrExternCrate::Glob(it), - ImportOrGlob::Import(it) => ImportOrExternCrate::Import(it), - } - } -} +impl_from!(ImportOrGlob { Glob, Import } for ImportOrExternCrate); impl ImportOrExternCrate { pub fn import_or_glob(self) -> Option { @@ -101,24 +94,8 @@ pub enum ImportOrDef { Def(ModuleDefId), } -impl From for ImportOrDef { - fn from(value: ImportOrExternCrate) -> Self { - match value { - ImportOrExternCrate::Import(it) => ImportOrDef::Import(it), - ImportOrExternCrate::Glob(it) => ImportOrDef::Glob(it), - ImportOrExternCrate::ExternCrate(it) => ImportOrDef::ExternCrate(it), - } - } -} - -impl From for ImportOrDef { - fn from(value: ImportOrGlob) -> Self { - match value { - ImportOrGlob::Import(it) => ImportOrDef::Import(it), - ImportOrGlob::Glob(it) => ImportOrDef::Glob(it), - } - } -} +impl_from!(ImportOrExternCrate { Import, Glob, ExternCrate } for ImportOrDef); +impl_from!(ImportOrGlob { Import, Glob } for ImportOrDef); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ImportId { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index cb6941aaa4cd4..423ffd5d408d8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -138,7 +138,7 @@ pub fn file_item_tree(db: &dyn SourceDatabase, file_id: HirFileId, krate: Crate) } } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] fn file_item_tree_query( db: &dyn SourceDatabase, file_id: HirFileId, @@ -197,7 +197,7 @@ fn file_item_tree_query( } } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn block_item_tree_query( db: &dyn SourceDatabase, block: BlockId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 14e559200f01c..534a9c31cd531 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -34,7 +34,7 @@ impl_from!( ); /// Salsa query. This will look for lang items in a specific crate. -#[salsa_macros::tracked(returns(as_deref))] +#[salsa::tracked(returns(as_deref))] pub fn crate_lang_items(db: &dyn SourceDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); @@ -112,7 +112,7 @@ pub fn crate_lang_items(db: &dyn SourceDatabase, krate: Crate) -> Option LangItems { let _p = tracing::info_span!("lang_items_query").entered(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 8b93fe5e2f01b..bed38d38e0117 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -492,7 +492,7 @@ mod tracked_struct_token { } } -#[salsa_macros::tracked(constructor = new_)] +#[salsa::tracked(constructor = new_)] #[derive(PartialOrd, Ord)] pub struct BlockIdLt<'db> { pub ast_id: AstId, @@ -534,7 +534,7 @@ impl BlockId { } } -#[salsa_macros::tracked(debug)] +#[salsa::tracked(debug)] #[derive(PartialOrd, Ord)] pub struct ModuleIdLt<'db> { /// The crate this module belongs to. @@ -712,7 +712,13 @@ pub struct LifetimeParamId { pub local_id: LocalLifetimeParamId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HrtbLifetimeParamId { + pub scope: GenericDefId, + pub local_id: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum ItemContainerId { ExternBlockId(ExternBlockId), ModuleId(ModuleId), @@ -722,7 +728,7 @@ pub enum ItemContainerId { impl_from!(ModuleId for ItemContainerId); /// A Data Type -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AdtId { StructId(StructId), UnionId(UnionId), @@ -731,7 +737,7 @@ pub enum AdtId { impl_from!(StructId, UnionId, EnumId for AdtId); /// A macro -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum MacroId { Macro2Id(Macro2Id), MacroRulesId(MacroRulesId), @@ -853,7 +859,7 @@ impl From for ModuleDefId { } /// The defs which have a body. -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum DefWithBodyId { /// A function body. FunctionId(FunctionId), @@ -883,7 +889,7 @@ impl DefWithBodyId { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AssocItemId { FunctionId(FunctionId), ConstId(ConstId), @@ -896,17 +902,16 @@ pub enum AssocItemId { // casting them, and somehow making the constructors private, which would be annoying. impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId); -impl From for ModuleDefId { - fn from(item: AssocItemId) -> Self { - match item { - AssocItemId::FunctionId(f) => f.into(), - AssocItemId::ConstId(c) => c.into(), - AssocItemId::TypeAliasId(t) => t.into(), - } +impl_from!( + AssocItemId { + FunctionId => FunctionId, + ConstId => ConstId, + TypeAliasId => TypeAliasId, } -} + for ModuleDefId +); -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum GenericDefId { AdtId(AdtId), // consts can have type parameters from their parents (i.e. associated consts of traits) @@ -1044,17 +1049,16 @@ impl GenericDefId { } } -impl From for GenericDefId { - fn from(item: AssocItemId) -> Self { - match item { - AssocItemId::FunctionId(f) => f.into(), - AssocItemId::ConstId(c) => c.into(), - AssocItemId::TypeAliasId(t) => t.into(), - } +impl_from!( + AssocItemId { + FunctionId => FunctionId, + ConstId => ConstId, + TypeAliasId => TypeAliasId, } -} + for GenericDefId +); -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum CallableDefId { FunctionId(FunctionId), StructId(StructId), @@ -1062,15 +1066,14 @@ pub enum CallableDefId { } impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); -impl From for ModuleDefId { - fn from(def: CallableDefId) -> ModuleDefId { - match def { - CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f), - CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)), - CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e), - } +impl_from!( + CallableDefId { + FunctionId => FunctionId, + StructId => AdtId, + EnumVariantId => EnumVariantId, } -} + for ModuleDefId +); impl CallableDefId { pub fn krate(self, db: &dyn SourceDatabase) -> Crate { @@ -1082,7 +1085,7 @@ impl CallableDefId { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AttrDefId { ModuleId(ModuleId), AdtId(AdtId), @@ -1114,27 +1117,14 @@ impl_from!( for AttrDefId ); -impl From for AttrDefId { - fn from(assoc: AssocItemId) -> Self { - match assoc { - AssocItemId::FunctionId(it) => AttrDefId::FunctionId(it), - AssocItemId::ConstId(it) => AttrDefId::ConstId(it), - AssocItemId::TypeAliasId(it) => AttrDefId::TypeAliasId(it), - } - } -} -impl From for AttrDefId { - fn from(vid: VariantId) -> Self { - match vid { - VariantId::EnumVariantId(id) => id.into(), - VariantId::StructId(id) => id.into(), - VariantId::UnionId(id) => id.into(), - } - } -} +impl_from!(AssocItemId { FunctionId, ConstId, TypeAliasId } for AttrDefId); +impl_from!( + VariantId { EnumVariantId => EnumVariantId, StructId => AdtId, UnionId => AdtId } + for AttrDefId +); #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa_macros::Supertype, salsa::Update, + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Supertype, salsa::Update, )] pub enum VariantId { EnumVariantId(EnumVariantId), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 4b7856e0c1494..c1daad5b3f6a2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -381,7 +381,7 @@ pub fn crate_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> &DefMap { crate_local_def_map(db, crate_id).def_map(db) } -#[salsa_macros::tracked] +#[salsa::tracked] pub(crate) struct DefMapPair<'db> { #[tracked] #[returns(ref)] @@ -390,7 +390,7 @@ pub(crate) struct DefMapPair<'db> { pub(crate) local: LocalDefMap, } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn crate_local_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> DefMapPair<'_> { let krate = crate_id.data(db); let _p = tracing::info_span!( @@ -424,7 +424,7 @@ pub(crate) fn crate_local_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> D DefMapPair::new(db, def_map, local_def_map) } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub fn block_def_map<'db>(db: &'db dyn SourceDatabase, block_id: BlockIdLt<'db>) -> DefMap { let block_id = unsafe { block_id.to_static() }; let ast_id = block_id.ast_id(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index 49d94b969d06f..5cd70955ab3e6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -167,22 +167,22 @@ fn no() {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "EnumVariants::of_", ] "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -225,16 +225,16 @@ pub struct S {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -245,7 +245,7 @@ pub struct S {} "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -283,21 +283,21 @@ fn f() { foo } "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -310,7 +310,7 @@ fn f() { foo } "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -407,22 +407,22 @@ pub struct S {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -446,7 +446,7 @@ pub struct S {} "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -524,16 +524,16 @@ m!(Z); "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -571,7 +571,7 @@ m!(Z); &[("file_item_tree_query", 1), ("parse_macro_expansion", 0)], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -611,7 +611,7 @@ pub type Ty = (); [ "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", ] "#]], @@ -629,7 +629,7 @@ pub type Ty = (); &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index fc639133d4c27..63ff384de021a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -22,7 +22,7 @@ use crate::{ TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, expr_store::{ - HygieneId, + ExpressionStore, HygieneId, path::Path, scope::{ExprScopes, ScopeId}, }, @@ -1071,8 +1071,11 @@ impl<'db> Scope<'db> { } } Scope::ExprScope(scope) => { - if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { - acc.add(&name, ScopeDef::Label(label)) + if let Some(label) = scope.expr_scopes.label(scope.scope_id) { + acc.add( + &ExpressionStore::of(db, scope.owner)[label].name, + ScopeDef::Label(label), + ) } scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { acc.add_local(e.name(), e.binding()); @@ -1376,7 +1379,7 @@ impl HasResolver for TypeAliasId { impl HasResolver for ImplId { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } @@ -1447,7 +1450,7 @@ impl HasResolver for ExpressionStoreOwnerId { impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { - self.lookup(db).parent.resolver(db) + lookup_resolver(db, self) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 0598ab4a0435c..4433522c1832f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -20,7 +20,7 @@ use crate::{ src::HasSource, }; -#[salsa_macros::db] +#[salsa::db] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, @@ -73,7 +73,7 @@ impl Clone for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for TestDB {} impl fmt::Debug for TestDB { @@ -84,7 +84,7 @@ impl fmt::Debug for TestDB { impl panic::RefUnwindSafe for TestDB {} -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index 9af75a0d8a6c1..fe41d093606e6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -21,7 +21,6 @@ itertools.workspace = true smallvec.workspace = true triomphe.workspace = true salsa.workspace = true -salsa-macros.workspace = true thin-vec.workspace = true # local deps diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 511b94d7418f1..58ab0e537f693 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -1544,7 +1544,7 @@ impl ExpandTo { /// /// We encode macro definitions into ids of macro calls, this what allows us /// to be incremental. -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(no_lifetime, debug, revisions = usize::MAX)] #[doc(alias = "MacroFileId")] pub struct MacroCallId { #[returns(ref)] @@ -1565,7 +1565,7 @@ impl From for span::MacroCallId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum HirFileId { FileId(EditionedFileId), MacroFile(MacroCallId), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs index 7b1a04de732bb..192a3c06e5e2d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs @@ -50,7 +50,7 @@ impl HirFileId { /// This is an implementation detail of [`HirFileId::span_map`]. Outside this crate, use /// `HirFileId::from(file_id).span_map(db)` instead of `real_span_map(db, file_id)`. -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn real_span_map( db: &dyn SourceDatabase, editioned_file_id: base_db::EditionedFileId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index e8eda74e40017..c55ad5bacfe95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -29,9 +29,7 @@ triomphe.workspace = true typed-arena = "2.0.2" indexmap.workspace = true rustc_apfloat = "0.2.3" -query-group.workspace = true salsa.workspace = true -salsa-macros.workspace = true petgraph.workspace = true bitflags.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index c9d3a87e96501..4fab468dfd8e7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -130,8 +130,8 @@ impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> { } } -pub(crate) struct InferenceContextAutoderefCtx<'a, 'b, 'db>(&'a mut InferenceContext<'b, 'db>); -impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, '_, 'db> { +pub(crate) struct InferenceContextAutoderefCtx<'a, 'db>(&'a mut InferenceContext<'db>); +impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, 'db> { #[inline] fn infcx(&self) -> &InferCtxt<'db> { &self.0.table.infer_ctxt @@ -162,8 +162,8 @@ pub(crate) struct GeneralAutoderef<'db, Ctx, Steps = Vec<(Ty<'db>, AutoderefKind pub(crate) type Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = GeneralAutoderef<'db, DefaultAutoderefCtx<'a, 'db>, Steps>; -pub(crate) type InferenceContextAutoderef<'a, 'b, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = - GeneralAutoderef<'db, InferenceContextAutoderefCtx<'a, 'b, 'db>, Steps>; +pub(crate) type InferenceContextAutoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = + GeneralAutoderef<'db, InferenceContextAutoderefCtx<'a, 'db>, Steps>; impl<'db, Ctx, Steps> Iterator for GeneralAutoderef<'db, Ctx, Steps> where @@ -240,10 +240,10 @@ impl<'a, 'db> Autoderef<'a, 'db> { } } -impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> { +impl<'a, 'db> InferenceContextAutoderef<'a, 'db> { #[inline] pub(crate) fn new_from_inference_context( - ctx: &'a mut InferenceContext<'b, 'db>, + ctx: &'a mut InferenceContext<'db>, base_ty: Ty<'db>, span: Span, ) -> Self { @@ -251,7 +251,7 @@ impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> { } #[inline] - pub(crate) fn ctx(&mut self) -> &mut InferenceContext<'b, 'db> { + pub(crate) fn ctx(&mut self) -> &mut InferenceContext<'db> { self.ctx.0 } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index e58a22332cf81..15dd530312067 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -16,6 +16,7 @@ use rustc_abi::Size; use rustc_apfloat::Float; use rustc_ast_ir::Mutability; use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; +use salsa::Update; use stdx::never; use crate::{ @@ -35,13 +36,13 @@ use crate::{ use super::mir::interpret_mir; -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstEvalError { - MirLowerError(MirLowerError), - MirEvalError(MirEvalError), +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub enum ConstEvalError<'db> { + MirLowerError(MirLowerError<'db>), + MirEvalError(MirEvalError<'db>), } -impl ConstEvalError { +impl ConstEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -60,8 +61,8 @@ impl ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirLowerError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirLowerError<'db>) -> Self { match value { MirLowerError::ConstEvalError(_, e) => *e, _ => ConstEvalError::MirLowerError(value), @@ -69,8 +70,8 @@ impl From for ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirEvalError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirEvalError<'db>) -> Self { ConstEvalError::MirEvalError(value) } } @@ -414,10 +415,10 @@ pub(crate) fn create_anon_const<'a, 'db>( } #[salsa::tracked(cycle_result = const_eval_discriminant_cycle_result)] -pub(crate) fn const_eval_discriminant_variant( - db: &dyn HirDatabase, +pub(crate) fn const_eval_discriminant_variant<'db>( + db: &'db dyn HirDatabase, variant_id: EnumVariantId, -) -> Result { +) -> Result> { let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); let body = Body::of(db, def); @@ -450,11 +451,11 @@ pub(crate) fn const_eval_discriminant_variant( Ok(c) } -fn const_eval_discriminant_cycle_result( - _: &dyn HirDatabase, +fn const_eval_discriminant_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: EnumVariantId, -) -> Result { +) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -463,58 +464,58 @@ pub(crate) fn const_eval<'db>( def: ConstId, subst: GenericArgs<'db>, trait_env: Option>, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = const_eval_cycle_result)] - pub(crate) fn const_eval_query( - db: &dyn HirDatabase, + pub(crate) fn const_eval_query<'db>( + db: &'db dyn HirDatabase, def: ConstId, subst: StoredGenericArgs, trait_env: Option, - ) -> Result { + ) -> Result> { let body = db.monomorphized_mir_body( def.into(), subst, ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; - let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; + let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref(db)))?.0?; Ok(c.store()) } - pub(crate) fn const_eval_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn const_eval_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: ConstId, _: StoredGenericArgs, _: Option, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } pub(crate) fn anon_const_eval<'db>( db: &'db dyn HirDatabase, - def: AnonConstId, + def: AnonConstId<'db>, subst: GenericArgs<'db>, trait_env: Option>, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match anon_const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = anon_const_eval_cycle_result)] - pub(crate) fn anon_const_eval_query( - db: &dyn HirDatabase, - def: AnonConstId, + pub(crate) fn anon_const_eval_query<'db>( + db: &'db dyn HirDatabase, + def: AnonConstId<'db>, subst: StoredGenericArgs, trait_env: Option, - ) -> Result { + ) -> Result> { let body = db.monomorphized_mir_body( def.into(), subst, @@ -524,17 +525,17 @@ pub(crate) fn anon_const_eval<'db>( } .store(), )?; - let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; + let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref(db)))?.0?; Ok(c.store()) } - pub(crate) fn anon_const_eval_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn anon_const_eval_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, - _: AnonConstId, + _: AnonConstId<'db>, _: StoredGenericArgs, _: Option, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } @@ -542,17 +543,17 @@ pub(crate) fn anon_const_eval<'db>( pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match const_eval_static_query(db, def) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = const_eval_static_cycle_result)] - pub(crate) fn const_eval_static_query( - db: &dyn HirDatabase, + pub(crate) fn const_eval_static_query<'db>( + db: &'db dyn HirDatabase, def: StaticId, - ) -> Result { + ) -> Result> { let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( def.into(), @@ -564,11 +565,11 @@ pub(crate) fn const_eval_static<'db>( Ok(c.store()) } - pub(crate) fn const_eval_static_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn const_eval_static_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: StaticId, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 546238f9bb309..4eb8c11fac6ba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -26,7 +26,7 @@ use super::{ mod intrinsics; -fn simplify(e: ConstEvalError) -> ConstEvalError { +fn simplify(e: ConstEvalError<'_>) -> ConstEvalError<'_> { match e { ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => { simplify(ConstEvalError::MirEvalError(*e)) @@ -38,7 +38,7 @@ fn simplify(e: ConstEvalError) -> ConstEvalError { #[track_caller] fn check_fail( #[rust_analyzer::rust_fixture] ra_fixture: &str, - error: impl FnOnce(ConstEvalError) -> bool, + error: impl FnOnce(ConstEvalError<'_>) -> bool, ) { let (db, file_id) = TestDB::with_single_file(ra_fixture); crate::attach_db(&db, || match eval_goal(&db, file_id) { @@ -101,7 +101,7 @@ fn check_answer( }); } -fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { +fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); let display_target = @@ -118,7 +118,7 @@ fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { err } -fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError> { +fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError<'_>> { let _tracing = setup_tracing(); let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); @@ -2217,14 +2217,17 @@ fn boxes() { use core::ops::{Deref, DerefMut}; use core::{marker::Unsize, ops::CoerceUnsized}; +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + #[lang = "owned_box"] pub struct Box { inner: *mut T, } impl Box { fn new(t: T) -> Self { - #[rustc_box] - Box::new(t) + box_new(t) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index c74ac51b61028..8e7e55a77b349 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -16,6 +16,7 @@ use hir_def::{ signatures::{ConstSignature, StaticSignature}, }; use la_arena::ArenaMap; +use salsa::Update; use span::Edition; use stdx::impl_from; use triomphe::Arc; @@ -36,248 +37,308 @@ use crate::{ traits::{ParamEnvAndCrate, StoredParamEnvAndCrate}, }; -#[query_group::query_group] -pub trait HirDatabase: SourceDatabase + std::fmt::Debug { +#[salsa::db] +pub trait HirDatabase: SourceDatabase + 'static { + /// Manual implementation of upcasting from `dyn SourceDatabase` to `dyn HirDatabase`. + /// + /// This function is needed because Rust can't perform this upcasting automatically + /// in the general case, as `Self` could be unsized. + fn as_dyn(&self) -> &dyn HirDatabase; + // region:mir // FIXME: Collapse `mir_body_for_closure` into `mir_body` // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body` - #[salsa::transparent] - fn mir_body(&self, def: InferBodyId) -> Result<&MirBody, MirLowerError> { - crate::mir::mir_body_query(self, def).map_err(|err| err.clone()) + fn mir_body<'db>( + &'db self, + def: InferBodyId<'db>, + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { + let db = self.as_dyn(); + crate::mir::mir_body_query(db, def).map_err(|err| err.clone()) } - #[salsa::transparent] - fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<&MirBody, MirLowerError> { - crate::mir::mir_body_for_closure_query(self, def).map_err(|err| err.clone()) + fn mir_body_for_closure<'db>( + &'db self, + def: InternedClosureId<'db>, + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { + let db = self.as_dyn(); + crate::mir::mir_body_for_closure_query(db, def).map_err(|err| err.clone()) } - #[salsa::transparent] - fn monomorphized_mir_body( - &self, - def: InferBodyId, + fn monomorphized_mir_body<'db>( + &'db self, + def: InferBodyId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, - ) -> Result<&MirBody, MirLowerError> { - crate::mir::monomorphized_mir_body_query(self, def, subst, env).map_err(|err| err.clone()) + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { + let db = self.as_dyn(); + crate::mir::monomorphized_mir_body_query(db, def, subst, env).map_err(|err| err.clone()) } - #[salsa::transparent] - fn monomorphized_mir_body_for_closure( - &self, - def: InternedClosureId, + fn monomorphized_mir_body_for_closure<'db>( + &'db self, + def: InternedClosureId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, - ) -> Result<&MirBody, MirLowerError> { - crate::mir::monomorphized_mir_body_for_closure_query(self, def, subst, env) + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { + let db = self.as_dyn(); + crate::mir::monomorphized_mir_body_for_closure_query(db, def, subst, env) .map_err(|err| err.clone()) } - #[salsa::invoke(crate::consteval::const_eval)] - #[salsa::transparent] fn const_eval<'db>( &'db self, def: ConstId, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError>; + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::const_eval(db, def, subst, trait_env) + } - #[salsa::invoke(crate::consteval::anon_const_eval)] - #[salsa::transparent] fn anon_const_eval<'db>( &'db self, - def: AnonConstId, + def: AnonConstId<'db>, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError>; + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::anon_const_eval(db, def, subst, trait_env) + } - #[salsa::invoke(crate::consteval::const_eval_static)] - #[salsa::transparent] - fn const_eval_static<'db>(&'db self, def: StaticId) -> Result, ConstEvalError>; + fn const_eval_static<'db>( + &'db self, + def: StaticId, + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::const_eval_static(db, def) + } - #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] - #[salsa::transparent] - fn const_eval_discriminant(&self, def: EnumVariantId) -> Result; + fn const_eval_discriminant<'db>( + &'db self, + def: EnumVariantId, + ) -> Result> { + let db = self.as_dyn(); + crate::consteval::const_eval_discriminant_variant(db, def) + } - #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] - #[salsa::transparent] fn lookup_impl_method<'db>( &'db self, env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, - ) -> (Either, GenericArgs<'db>); + ) -> (Either, GenericArgs<'db>) + { + let db = self.as_dyn(); + crate::method_resolution::lookup_impl_method_query(db, env, func, fn_subst) + } // endregion:mir - #[salsa::invoke(crate::layout::layout_of_adt_query)] - #[salsa::transparent] fn layout_of_adt( &self, def: AdtId, args: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, - ) -> Result, LayoutError>; + ) -> Result, LayoutError> { + let db = self.as_dyn(); + crate::layout::layout_of_adt_query(db, def, args, trait_env) + } - #[salsa::invoke(crate::layout::layout_of_ty_query)] - #[salsa::transparent] fn layout_of_ty( &self, ty: StoredTy, env: StoredParamEnvAndCrate, - ) -> Result, LayoutError>; + ) -> Result, LayoutError> { + let db = self.as_dyn(); + crate::layout::layout_of_ty_query(db, ty, env) + } - #[salsa::transparent] fn target_data_layout(&self, krate: Crate) -> Result<&TargetDataLayout, TargetLoadError> { - crate::layout::target_data_layout_query(self, krate).map_err(|err| err.clone()) + let db = self.as_dyn(); + crate::layout::target_data_layout_query(db, krate).map_err(|err| err.clone()) } - #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] - fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; + fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option { + let db = self.as_dyn(); + crate::dyn_compatibility::dyn_compatibility_of_trait_query(db, trait_) + } - #[salsa::invoke(crate::lower::ty_query)] - #[salsa::transparent] - fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>>; + fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::ty_query(db, def) + } - #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics)] - #[salsa::transparent] - fn type_for_type_alias_with_diagnostics( - &self, + fn type_for_type_alias_with_diagnostics<'db>( + &'db self, def: TypeAliasId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_type_alias_with_diagnostics(db, def) + } /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. - #[salsa::invoke(crate::lower::value_ty)] - #[salsa::transparent] - fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option>>; + fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option>> { + let db = self.as_dyn(); + crate::lower::value_ty(db, def) + } - #[salsa::invoke(crate::lower::type_for_const)] - #[salsa::transparent] - fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>>; + fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::type_for_const(db, def) + } - #[salsa::invoke(crate::lower::type_for_const_with_diagnostics)] - #[salsa::transparent] - fn type_for_const_with_diagnostics( - &self, + fn type_for_const_with_diagnostics<'db>( + &'db self, def: ConstId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_const_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::type_for_static)] - #[salsa::transparent] - fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>>; + fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::type_for_static(db, def) + } - #[salsa::invoke(crate::lower::type_for_static_with_diagnostics)] - #[salsa::transparent] - fn type_for_static_with_diagnostics( - &self, + fn type_for_static_with_diagnostics<'db>( + &'db self, def: StaticId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_static_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics)] - #[salsa::transparent] - fn impl_self_ty_with_diagnostics( - &self, + fn impl_self_ty_with_diagnostics<'db>( + &'db self, def: ImplId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::impl_self_ty_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::impl_self_ty_query)] - #[salsa::transparent] - fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>; + fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::impl_self_ty_query(db, def) + } - #[salsa::invoke(crate::lower::const_param_types_with_diagnostics)] - #[salsa::transparent] - fn const_param_types_with_diagnostics( - &self, + fn const_param_types_with_diagnostics<'db>( + &'db self, def: GenericDefId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, ArenaMap> { + let db = self.as_dyn(); + crate::lower::const_param_types_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::const_param_types)] - #[salsa::transparent] - fn const_param_types(&self, def: GenericDefId) -> &ArenaMap; + fn const_param_types(&self, def: GenericDefId) -> &ArenaMap { + let db = self.as_dyn(); + crate::lower::const_param_types(db, def) + } - #[salsa::invoke(crate::lower::const_param_ty)] - #[salsa::transparent] - fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db>; + fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db> { + let db = self.as_dyn(); + crate::lower::const_param_ty(db, def) + } - #[salsa::invoke(crate::lower::impl_trait_with_diagnostics)] - #[salsa::transparent] - fn impl_trait_with_diagnostics( - &self, + fn impl_trait_with_diagnostics<'db>( + &'db self, def: ImplId, - ) -> &Option>>; + ) -> &'db Option>> { + let db = self.as_dyn(); + crate::lower::impl_trait_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::impl_trait_query)] - #[salsa::transparent] - fn impl_trait<'db>(&'db self, def: ImplId) -> Option>>; + fn impl_trait<'db>(&'db self, def: ImplId) -> Option>> { + let db = self.as_dyn(); + crate::lower::impl_trait_query(db, def) + } - #[salsa::invoke(crate::lower::field_types_with_diagnostics)] - #[salsa::transparent] - fn field_types_with_diagnostics( - &self, + fn field_types_with_diagnostics<'db>( + &'db self, var: VariantId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, ArenaMap> { + let db = self.as_dyn(); + crate::lower::field_types_with_diagnostics(db, var) + } - #[salsa::invoke(crate::lower::field_types_query)] - #[salsa::transparent] - fn field_types(&self, var: VariantId) -> &ArenaMap; + fn field_types(&self, var: VariantId) -> &ArenaMap { + let db = self.as_dyn(); + crate::lower::field_types_query(db, var) + } - #[salsa::invoke(crate::lower::callable_item_signature)] - #[salsa::transparent] fn callable_item_signature<'db>( &'db self, def: CallableDefId, - ) -> EarlyBinder<'db, PolyFnSig<'db>>; + ) -> EarlyBinder<'db, PolyFnSig<'db>> { + let db = self.as_dyn(); + crate::lower::callable_item_signature(db, def) + } - #[salsa::invoke(crate::lower::callable_item_signature_with_diagnostics)] - #[salsa::transparent] - fn callable_item_signature_with_diagnostics( - &self, + fn callable_item_signature_with_diagnostics<'db>( + &'db self, def: CallableDefId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::callable_item_signature_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::trait_environment)] - #[salsa::transparent] - fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>; + fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db> { + let db = self.as_dyn(); + crate::lower::trait_environment(db, def) + } - #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics)] - #[salsa::transparent] - fn generic_defaults_with_diagnostics( - &self, + fn generic_defaults_with_diagnostics<'db>( + &'db self, def: GenericDefId, - ) -> &TyLoweringResult; + ) -> &'db TyLoweringResult<'db, GenericDefaults> { + let db = self.as_dyn(); + crate::lower::generic_defaults_with_diagnostics(db, def) + } /// This returns an empty list if no parameter has default. /// /// The binders of the returned defaults are only up to (not including) this parameter. - #[salsa::invoke(crate::lower::generic_defaults)] - #[salsa::transparent] - fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_>; + fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_> { + let db = self.as_dyn(); + crate::lower::generic_defaults(db, def) + } - #[salsa::invoke(crate::lower::type_alias_bounds_with_diagnostics)] - #[salsa::transparent] - fn type_alias_bounds_with_diagnostics( - &self, + fn type_alias_bounds_with_diagnostics<'db>( + &'db self, type_alias: TypeAliasId, - ) -> &TyLoweringResult>>; + ) -> &'db TyLoweringResult<'db, TypeAliasBounds>> { + let db = self.as_dyn(); + crate::lower::type_alias_bounds_with_diagnostics(db, type_alias) + } - #[salsa::invoke(crate::lower::type_alias_bounds)] - #[salsa::transparent] fn type_alias_bounds<'db>( &'db self, type_alias: TypeAliasId, - ) -> EarlyBinder<'db, &'db [Clause<'db>]>; + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + let db = self.as_dyn(); + crate::lower::type_alias_bounds(db, type_alias) + } - #[salsa::invoke(crate::lower::type_alias_self_bounds)] - #[salsa::transparent] fn type_alias_self_bounds<'db>( &'db self, type_alias: TypeAliasId, - ) -> EarlyBinder<'db, &'db [Clause<'db>]>; + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + let db = self.as_dyn(); + crate::lower::type_alias_self_bounds(db, type_alias) + } - #[salsa::invoke(crate::variance::variances_of)] - #[salsa::transparent] - fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db>; + fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db> { + let db = self.as_dyn(); + crate::variance::variances_of(db, def) + } +} + +#[salsa::db] +impl HirDatabase for T { + fn as_dyn(&self) -> &dyn HirDatabase { + self + } } #[test] @@ -285,28 +346,28 @@ fn hir_database_is_dyn_compatible() { fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedOpaqueTyId { pub loc: ImplTraitId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedClosure { - pub owner: InferBodyId, +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Update)] +pub struct InternedClosure<'db> { + pub owner: InferBodyId<'db>, pub expr: ExprId, pub kind: ClosureKind, } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedClosureId { - pub loc: InternedClosure, +pub struct InternedClosureId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedClosureId { +impl<'db> InternedClosureId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -326,15 +387,15 @@ impl InternedClosureId { } } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedCoroutineId { - pub loc: InternedClosure, +pub struct InternedCoroutineId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedCoroutineId { +impl<'db> InternedCoroutineId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -355,15 +416,15 @@ impl InternedCoroutineId { } } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedCoroutineClosureId { - pub loc: InternedClosure, +pub struct InternedCoroutineClosureId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedCoroutineClosureId { +impl<'db> InternedCoroutineClosureId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -399,16 +460,16 @@ pub struct AnonConstLoc { pub(crate) allow_using_generic_params: bool, } -#[salsa_macros::interned(debug, no_lifetime, revisions = usize::MAX, constructor = new_)] +#[salsa::interned(debug, revisions = usize::MAX, constructor = new_)] #[derive(PartialOrd, Ord)] pub struct AnonConstId { #[returns(ref)] pub loc: AnonConstLoc, } -impl AnonConstId { +impl<'db> AnonConstId<'db> { pub(crate) fn new( - db: &dyn SourceDatabase, + db: &'db dyn SourceDatabase, loc: AnonConstLoc, token: TrackedStructToken, ) -> Self { @@ -417,23 +478,23 @@ impl AnonConstId { } } -impl HasModule for AnonConstId { +impl HasModule for AnonConstId<'_> { fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.loc(db).owner.module(db) } } -impl HasResolver for AnonConstId { +impl HasResolver for AnonConstId<'_> { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { self.loc(db).owner.resolver(db) } } -impl AnonConstId { +impl<'db> AnonConstId<'db> { pub fn all_from_signature( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: GenericDefId, - ) -> ArrayVec<&[AnonConstId], 5> { + ) -> ArrayVec<&'db [Self], 5> { let mut result = ArrayVec::new(); // Queries common to all generic defs: @@ -469,17 +530,17 @@ impl AnonConstId { /// A constant, which might appears as a const item, an anonymous const block in expressions /// or patterns, or as a constant in types with const generics. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] -pub enum GeneralConstId { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +pub enum GeneralConstId<'db> { ConstId(ConstId), StaticId(StaticId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), } -impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId); +impl_from!(impl<'db> ConstId, StaticId, AnonConstId<'db> for GeneralConstId<'db>); -impl GeneralConstId { - pub fn generic_def(self, db: &dyn HirDatabase) -> Option { +impl<'db> GeneralConstId<'db> { + pub fn generic_def(self, db: &'db dyn HirDatabase) -> Option { match self { GeneralConstId::ConstId(it) => Some(it.into()), GeneralConstId::StaticId(it) => Some(it.into()), @@ -487,7 +548,7 @@ impl GeneralConstId { } } - pub fn name(self, db: &dyn SourceDatabase) -> String { + pub fn name(self, db: &'db dyn SourceDatabase) -> String { match self { GeneralConstId::StaticId(it) => { StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index d04419c5e58b8..0947f456adeae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -104,7 +104,7 @@ impl<'db> BodyValidationDiagnostic<'db> { struct ExprValidator<'db> { owner: DefWithBodyId, body: &'db Body, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, env: ParamEnv<'db>, diagnostics: Vec>, validate_lints: bool, @@ -157,18 +157,6 @@ impl<'db> ExprValidator<'db> { _ => {} } } - - for (id, pat) in body.pats() { - if let Some((variant, missed_fields)) = - record_pattern_missing_fields(db, self.infer, id, pat) - { - self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { - record: Either::Right(id), - variant, - missed_fields, - }); - } - } } fn validate_call( @@ -633,9 +621,9 @@ impl<'db> FilterMapNextChecker<'db> { } } -pub fn record_literal_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn record_literal_missing_fields<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, id: ExprId, expr: &Expr, ) -> Option<(VariantId, Vec)> { @@ -676,9 +664,9 @@ pub fn record_literal_missing_fields( Some((variant_def, missed_fields)) } -pub fn record_pattern_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn record_pattern_missing_fields<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, id: PatId, pat: &Pat, ) -> Option<(VariantId, Vec)> { @@ -713,8 +701,8 @@ pub fn record_pattern_missing_fields( Some((variant_def, missed_fields)) } -fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool { - fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) { +fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult<'_>) -> bool { + fn walk(pat: PatId, body: &Body, infer: &InferenceResult<'_>, has_type_mismatches: &mut bool) { match infer.pat_has_type_mismatch(pat) { true => *has_type_mismatches = true, false if *has_type_mismatches => (), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index 14bff65220702..613912e0901bf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -97,7 +97,7 @@ pub(crate) enum PatKind<'db> { pub(crate) struct PatCtxt<'a, 'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'a Body, pub(crate) errors: Vec, } @@ -105,7 +105,7 @@ pub(crate) struct PatCtxt<'a, 'db> { impl<'a, 'db> PatCtxt<'a, 'db> { pub(crate) fn new( db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'a Body, ) -> Self { Self { db, infer, body, errors: Vec::new() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 88a44d2e6a2f8..3021de68f3fdf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -100,7 +100,7 @@ enum UnsafeDiagnostic { pub fn unsafe_operations_for_body( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, def: DefWithBodyId, body: &Body, callback: &mut dyn FnMut(ExprOrPatId), @@ -119,7 +119,7 @@ pub fn unsafe_operations_for_body( pub fn unsafe_operations( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, def: ExpressionStoreOwnerId, body: &ExpressionStore, current: ExprId, @@ -137,7 +137,7 @@ pub fn unsafe_operations( struct UnsafeVisitor<'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db ExpressionStore, resolver: Resolver<'db>, def: ExpressionStoreOwnerId, @@ -156,7 +156,7 @@ struct UnsafeVisitor<'db> { impl<'db> UnsafeVisitor<'db> { fn new( db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db ExpressionStore, def: ExpressionStoreOwnerId, unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index c5ce3af3a9ac9..dc20eb930e815 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2461,8 +2461,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { .where_predicates() .iter() .filter_map(|it| match it { - WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound } + WherePredicate::TypeBound { lifetimes: _, target, bound } if matches!( store[*target], TypeRef::TypeParam(t) if t == *param @@ -2522,6 +2521,14 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { write!(f, "]")?; } TypeRef::Fn(fn_) => { + if let Some(binder) = &fn_.binder { + let edition = f.edition(); + write!( + f, + "for<{}> ", + binder.iter().map(|it| it.display(f.db, edition)).format(", ") + )?; + } if fn_.is_unsafe { write!(f, "unsafe ")?; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 9ee39b3abe649..bf7970d629d2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -122,6 +122,7 @@ where ControlFlow::Continue(()) } +#[salsa::tracked] pub fn dyn_compatibility_of_trait_query( db: &dyn HirDatabase, trait_: TraitId, @@ -425,15 +426,9 @@ fn receiver_is_dispatchable<'db>( return false; }; - let meta_sized_did = lang_items.MetaSized; - - // 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; - // }; + let Some(meta_sized_did) = lang_items.MetaSized else { + return false; + }; // Type `U` // FIXME: That seems problematic to fake a generic param like that? @@ -454,8 +449,8 @@ fn receiver_is_dispatchable<'db>( }); let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); - let meta_sized_predicate = meta_sized_did - .map(|did| TraitRef::new(interner, did.into(), [unsized_self_ty]).upcast(interner)); + let meta_sized_predicate = + TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]).upcast(interner); ParamEnv { clauses: Clauses::new_from_iter( @@ -464,7 +459,7 @@ fn receiver_is_dispatchable<'db>( .iter_identity() .map(Unnormalized::skip_norm_wip) .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)]) - .chain(meta_sized_predicate), + .chain(std::iter::once(meta_sized_predicate)), ), } }; @@ -497,9 +492,9 @@ fn contains_illegal_impl_trait_in_trait<'db>( db: &'db dyn HirDatabase, sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig>>>, ) -> Option { - struct OpaqueTypeCollector(FxHashSet); + struct OpaqueTypeCollector<'db>(FxHashSet>); - impl<'db> rustc_type_ir::TypeVisitor> for OpaqueTypeCollector { + impl<'db> rustc_type_ir::TypeVisitor> for OpaqueTypeCollector<'db> { type Result = ControlFlow<()>; fn visit_ty( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index ebcc0bd3f6f57..bd00da84cafad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -47,7 +47,7 @@ use hir_def::{ TupleFieldId, TupleId, VariantId, attrs::AttrFlags, expr_store::{Body, ExpressionStore, HygieneId, body::Param, path::Path}, - hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, ExprOrPatIdPacked, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, @@ -65,6 +65,7 @@ use rustc_type_ir::{ AliasTyKind, TypeFoldable, TypeVisitableExt, inherent::{GenericArgs as _, IntoKind, Ty as _}, }; +use salsa::Update; use smallvec::SmallVec; use span::Edition; use stdx::never; @@ -118,7 +119,7 @@ pub use unify::{could_unify, could_unify_deeply}; use cast::{CastCheck, CastError}; /// The entry point of type inference. -fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { +fn infer_query<'db>(db: &'db dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'db> { infer_query_with_inspect(db, def, None, LoweringMode::Analysis) } @@ -127,7 +128,7 @@ pub fn infer_query_with_inspect<'db>( def: DefWithBodyId, inspect: Option>, lowering_mode: LoweringMode, -) -> InferenceResult { +) -> InferenceResult<'db> { let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = Body::of(db, def); @@ -185,7 +186,11 @@ pub fn infer_query_with_inspect<'db>( infer_finalize(ctx) } -fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { +fn infer_cycle_result<'db>( + db: &'db dyn HirDatabase, + _: salsa::Id, + _: DefWithBodyId, +) -> InferenceResult<'db> { InferenceResult { has_errors: true, ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) @@ -193,7 +198,10 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I } /// Infer types for an anonymous const expression. -fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { +fn infer_anon_const_query<'db>( + db: &'db dyn HirDatabase, + def: AnonConstId<'db>, +) -> InferenceResult<'db> { let _p = tracing::info_span!("infer_anon_const_query").entered(); let loc = def.loc(db); let store_owner = loc.owner; @@ -221,18 +229,18 @@ fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceRe infer_finalize(ctx) } -fn infer_anon_const_cycle_result( - db: &dyn HirDatabase, +fn infer_anon_const_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, - _: AnonConstId, -) -> InferenceResult { + _: AnonConstId<'db>, +) -> InferenceResult<'db> { InferenceResult { has_errors: true, ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) } } -fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { +fn infer_finalize<'db>(mut ctx: InferenceContext<'db>) -> InferenceResult<'db> { ctx.handle_opaque_type_uses(); ctx.type_inference_fallback(); @@ -289,7 +297,7 @@ pub enum InferenceTyDiagnosticSource { pub enum InferenceDiagnostic { NoSuchField { #[type_visitable(ignore)] - field: ExprOrPatId, + field: ExprOrPatIdPacked, #[type_visitable(ignore)] private: Option, #[type_visitable(ignore)] @@ -320,7 +328,7 @@ pub enum InferenceDiagnostic { }, DuplicateField { #[type_visitable(ignore)] - field: ExprOrPatId, + field: ExprOrPatIdPacked, #[type_visitable(ignore)] variant: VariantId, }, @@ -332,7 +340,7 @@ pub enum InferenceDiagnostic { }, PrivateAssocItem { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, #[type_visitable(ignore)] item: AssocItemId, }, @@ -358,11 +366,11 @@ pub enum InferenceDiagnostic { }, UnresolvedAssocItem { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, }, UnresolvedIdent { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { @@ -461,7 +469,7 @@ pub enum InferenceDiagnostic { }, PathDiagnostic { #[type_visitable(ignore)] - node: ExprOrPatId, + node: ExprOrPatIdPacked, #[type_visitable(ignore)] diag: PathLoweringDiagnostic, }, @@ -507,7 +515,7 @@ pub enum InferenceDiagnostic { }, TypeMismatch { #[type_visitable(ignore)] - node: ExprOrPatId, + node: ExprOrPatIdPacked, expected: StoredTy, found: StoredTy, }, @@ -530,6 +538,14 @@ pub enum InferenceDiagnostic { #[type_visitable(ignore)] kind: ReturnKind, }, + RecordMissingFields { + #[type_visitable(ignore)] + record: ExprOrPatId, + #[type_visitable(ignore)] + variant: VariantId, + #[type_visitable(ignore)] + missed_fields: Vec, + }, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -541,7 +557,7 @@ pub enum ReturnKind { #[derive(Debug, PartialEq, Eq, Clone)] pub enum ExplicitDropMethodUseKind { MethodCall(ExprId), - Path(ExprOrPatId), + Path(ExprOrPatIdPacked), } /// Represents coercing a value to a different type of value. @@ -736,16 +752,16 @@ pub enum PatAdjust { /// When you add a field that stores types (including `Substitution` and the like), don't forget /// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must /// not appear in the final inference result. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct InferenceResult { +#[derive(Clone, PartialEq, Eq, Debug, Update)] +pub struct InferenceResult<'db> { /// For each method call expr, records the function it resolves to. method_resolutions: FxHashMap, /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap>, /// For each struct literal or pattern, records the variant it resolves to. - variant_resolutions: FxHashMap, + variant_resolutions: FxHashMap, /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, + assoc_resolutions: FxHashMap, /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of /// that which allows us to resolve a [`TupleFieldId`]s type. @@ -759,7 +775,7 @@ pub struct InferenceResult { pub(crate) type_of_pat: ArenaMap, pub(crate) type_of_binding: ArenaMap, pub(crate) type_of_type_placeholder: FxHashMap, - pub(crate) type_of_opaque: FxHashMap, + pub(crate) type_of_opaque: FxHashMap, StoredTy>, /// Whether there are any type-mismatching errors in the result. // FIXME: This isn't as useful as initially thought due to us falling back placeholders to @@ -769,7 +785,7 @@ pub struct InferenceResult { /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. diagnostics: ThinVec, // FIXME: Remove this, change it to be in `InferenceContext`: - nodes_with_type_mismatches: Option>>, + nodes_with_type_mismatches: Option>>, /// Interned `Error` type to return references to. // FIXME: Remove this. @@ -801,7 +817,7 @@ pub struct InferenceResult { pub closures_data: FxHashMap, - defined_anon_consts: ThinVec, + defined_anon_consts: ThinVec>, } #[derive(Clone, PartialEq, Eq, Debug, Default)] @@ -897,9 +913,9 @@ pub struct CaptureSourceStack(CaptureSourceStackRepr); #[derive(Clone)] enum CaptureSourceStackRepr { - One(ExprOrPatId), - Two([ExprOrPatId; 2]), - Many(ThinVec), + One(ExprOrPatIdPacked), + Two([ExprOrPatIdPacked; 2]), + Many(ThinVec), } impl PartialEq for CaptureSourceStack { @@ -916,10 +932,11 @@ impl std::hash::Hash for CaptureSourceStack { } } +#[cfg(target_pointer_width = "64")] const _: () = assert!(size_of::() == 16); impl Deref for CaptureSourceStack { - type Target = [ExprOrPatId]; + type Target = [ExprOrPatIdPacked]; #[inline] fn deref(&self) -> &Self::Target { @@ -948,16 +965,16 @@ impl CaptureSourceStack { } #[inline] - pub(crate) fn from_single(id: ExprOrPatId) -> Self { + pub(crate) fn from_single(id: ExprOrPatIdPacked) -> Self { Self(CaptureSourceStackRepr::One(id)) } #[inline] - pub fn final_source(&self) -> ExprOrPatId { + pub fn final_source(&self) -> ExprOrPatIdPacked { *self.last().expect("should always have a final source") } - pub fn push(&mut self, new_id: ExprOrPatId) { + pub fn push(&mut self, new_id: ExprOrPatIdPacked) { match &mut self.0 { CaptureSourceStackRepr::One(old_id) => { self.0 = CaptureSourceStackRepr::Two([*old_id, new_id]) @@ -1022,24 +1039,32 @@ pub enum UpvarCapture { } #[salsa::tracked] -impl InferenceResult { +impl<'db> InferenceResult<'db> { #[salsa::tracked(returns(ref), cycle_result = infer_cycle_result)] - fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { + fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'_> { infer_query(db, def) } +} +#[salsa::tracked] +impl<'db> InferenceResult<'db> { /// Infer types for all const expressions in an item's signature. /// /// Returns an `InferenceResult` containing type information for array lengths, /// const generic arguments, and other const expressions appearing in type /// positions within the item's signature. #[salsa::tracked(returns(ref), cycle_result = infer_anon_const_cycle_result)] - fn for_anon_const(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + fn for_anon_const(db: &'db dyn HirDatabase, def: AnonConstId<'db>) -> InferenceResult<'db> { infer_anon_const_query(db, def) } +} +impl<'db> InferenceResult<'db> { #[inline] - pub fn of(db: &dyn HirDatabase, def: impl Into) -> &InferenceResult { + pub fn of( + db: &'db dyn HirDatabase, + def: impl Into>, + ) -> &'db InferenceResult<'db> { match def.into() { InferBodyId::DefWithBodyId(it) => InferenceResult::for_body(db, it), InferBodyId::AnonConstId(it) => InferenceResult::for_anon_const(db, it), @@ -1047,7 +1072,7 @@ impl InferenceResult { } } -impl InferenceResult { +impl<'db> InferenceResult<'db> { fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -1074,7 +1099,7 @@ impl InferenceResult { } } - pub fn method_resolution<'db>(&self, expr: ExprId) -> Option<(FunctionId, GenericArgs<'db>)> { + pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, GenericArgs<'db>)> { self.method_resolutions.get(&expr).map(|(func, args)| (*func, args.as_ref())) } pub fn field_resolution(&self, expr: ExprId) -> Option> { @@ -1092,28 +1117,28 @@ impl InferenceResult { ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id), } } - pub fn assoc_resolutions_for_expr<'db>( + pub fn assoc_resolutions_for_expr<'a>( &self, id: ExprId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { self.assoc_resolutions.get(&id.into()).map(|(assoc, args)| (*assoc, args.as_ref())) } - pub fn assoc_resolutions_for_pat<'db>( + pub fn assoc_resolutions_for_pat<'a>( &self, id: PatId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { self.assoc_resolutions.get(&id.into()).map(|(assoc, args)| (*assoc, args.as_ref())) } - pub fn assoc_resolutions_for_expr_or_pat<'db>( + pub fn assoc_resolutions_for_expr_or_pat<'a>( &self, id: ExprOrPatId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { match id { ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id), ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), } } - pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatId) -> bool { + pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatIdPacked) -> bool { self.nodes_with_type_mismatches.as_ref().is_some_and(|it| it.contains(&node)) } pub fn expr_has_type_mismatch(&self, expr: ExprId) -> bool { @@ -1130,19 +1155,19 @@ impl InferenceResult { pub fn has_type_mismatches(&self) -> bool { self.nodes_with_type_mismatches.is_some() } - pub fn placeholder_types<'db>(&self) -> impl Iterator)> { + pub fn placeholder_types<'a>(&self) -> impl Iterator)> { self.type_of_type_placeholder.iter().map(|(&type_ref, ty)| (type_ref, ty.as_ref())) } - pub fn type_of_type_placeholder<'db>(&self, type_ref: TypeRefId) -> Option> { + pub fn type_of_type_placeholder<'a>(&self, type_ref: TypeRefId) -> Option> { self.type_of_type_placeholder.get(&type_ref).map(|ty| ty.as_ref()) } - pub fn type_of_expr_or_pat<'db>(&self, id: ExprOrPatId) -> Option> { + pub fn type_of_expr_or_pat<'a>(&self, id: ExprOrPatId) -> Option> { match id { ExprOrPatId::ExprId(id) => self.type_of_expr.get(id).map(|it| it.as_ref()), ExprOrPatId::PatId(id) => self.type_of_pat.get(id).map(|it| it.as_ref()), } } - pub fn type_of_expr_with_adjust<'db>(&self, id: ExprId) -> Option> { + pub fn type_of_expr_with_adjust<'a>(&self, id: ExprId) -> Option> { match self.expr_adjustments.get(&id).and_then(|adjustments| { adjustments.iter().rfind(|adj| { // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140 @@ -1159,7 +1184,7 @@ impl InferenceResult { None => self.type_of_expr.get(id).map(|it| it.as_ref()), } } - pub fn type_of_pat_with_adjust<'db>(&self, id: PatId) -> Ty<'db> { + pub fn type_of_pat_with_adjust<'a>(&self, id: PatId) -> Ty<'a> { match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { Some(adjusted) => adjusted.source.as_ref(), None => self.pat_ty(id), @@ -1173,7 +1198,7 @@ impl InferenceResult { &self.diagnostics } - pub fn tuple_field_access_type<'db>(&self, id: TupleId) -> Tys<'db> { + pub fn tuple_field_access_type<'a>(&self, id: TupleId) -> Tys<'a> { self.tuple_field_access_types[id.0 as usize].as_ref() } @@ -1190,25 +1215,25 @@ impl InferenceResult { } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn expression_types<'db>(&self) -> impl Iterator)> { + pub fn expression_types<'a>(&self) -> impl Iterator)> { self.type_of_expr.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn pattern_types<'db>(&self) -> impl Iterator)> { + pub fn pattern_types<'a>(&self) -> impl Iterator)> { self.type_of_pat.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn binding_types<'db>(&self) -> impl Iterator)> { + pub fn binding_types<'a>(&self) -> impl Iterator)> { self.type_of_binding.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn return_position_impl_trait_types<'db>( - &'db self, - db: &'db dyn HirDatabase, - ) -> impl Iterator)> { + pub fn return_position_impl_trait_types<'a>( + &'a self, + db: &'a dyn HirDatabase, + ) -> impl Iterator)> { self.type_of_opaque.iter().filter_map(move |(&id, ty)| { let ImplTraitId::ReturnTypeImplTrait(_, rpit_idx) = id.loc(db) else { return None; @@ -1217,24 +1242,24 @@ impl InferenceResult { }) } - pub fn expr_ty<'db>(&self, id: ExprId) -> Ty<'db> { + pub fn expr_ty<'a>(&self, id: ExprId) -> Ty<'a> { self.type_of_expr.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } - pub fn pat_ty<'db>(&self, id: PatId) -> Ty<'db> { + pub fn pat_ty<'a>(&self, id: PatId) -> Ty<'a> { self.type_of_pat.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } - pub fn expr_or_pat_ty<'db>(&self, id: ExprOrPatId) -> Ty<'db> { + pub fn expr_or_pat_ty<'a>(&self, id: ExprOrPatId) -> Ty<'a> { self.type_of_expr_or_pat(id).unwrap_or(self.error_ty.as_ref()) } - pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { + pub fn binding_ty<'a>(&self, id: BindingId) -> Ty<'a> { self.type_of_binding.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } /// This does not deduplicate, which means you'll get the types once per capture. - pub fn closure_captures_tys<'db>(&self, closure: ExprId) -> impl Iterator> { + pub fn closure_captures_tys<'a>(&self, closure: ExprId) -> impl Iterator> { self.closures_data[&closure] .min_captures .values() @@ -1242,11 +1267,11 @@ impl InferenceResult { } /// Like [`Self::closure_captures_tys()`], but using [`CapturedPlace::captured_ty()`]. - pub fn closure_captures_captured_tys<'db>( + pub fn closure_captures_captured_tys<'a>( &self, - db: &'db dyn HirDatabase, + db: &'a dyn HirDatabase, closure: ExprId, - ) -> impl Iterator> { + ) -> impl Iterator> { self.closures_data[&closure] .min_captures .values() @@ -1266,12 +1291,12 @@ enum DerefPatBorrowMode { /// The inference context contains all information needed during type inference. #[derive(Debug)] -pub(crate) struct InferenceContext<'body, 'db> { +pub(crate) struct InferenceContext<'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: InferBodyId, + pub(crate) owner: InferBodyId<'db>, pub(crate) store_owner: ExpressionStoreOwnerId, pub(crate) generic_def: GenericDefId, - pub(crate) store: &'body ExpressionStore, + pub(crate) store: &'db ExpressionStore, pub(crate) lowering_mode: LoweringMode, /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext /// and resolve the path via its methods. This will ensure proper error reporting. @@ -1286,7 +1311,7 @@ pub(crate) struct InferenceContext<'body, 'db> { pub(crate) features: &'db UnstableFeatures, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, - pub(crate) result: InferenceResult, + pub(crate) result: InferenceResult<'db>, tuple_field_accesses_rev: IndexSet, std::hash::BuildHasherDefault>, /// The return type of the function being inferred, the closure or async block if we're @@ -1316,7 +1341,7 @@ pub(crate) struct InferenceContext<'body, 'db> { diagnostics: Diagnostics, vars_emitted_type_must_be_known_for: FxHashSet>, - defined_anon_consts: RefCell>, + defined_anon_consts: RefCell>>, } #[derive(Clone, Debug)] @@ -1363,13 +1388,13 @@ fn find_continuable<'a, 'db>( } } -impl<'body, 'db> InferenceContext<'body, 'db> { +impl<'db> InferenceContext<'db> { fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store_owner: ExpressionStoreOwnerId, generic_def: GenericDefId, - store: &'body ExpressionStore, + store: &'db ExpressionStore, resolver: Resolver<'db>, allow_using_generic_params: bool, lowering_mode: LoweringMode, @@ -1411,7 +1436,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - fn merge(&mut self, other: &InferenceResult) { + fn merge(&mut self, other: &InferenceResult<'db>) { let InferenceResult { method_resolutions, field_resolutions, @@ -1566,7 +1591,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you // used this function for another workaround, mention it here. If you really need this function and believe that // there is no problem in it being `pub(crate)`, remove this comment. - fn resolve_all(self) -> InferenceResult { + fn resolve_all(self) -> InferenceResult<'db> { let InferenceContext { table, mut result, @@ -1699,7 +1724,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { result } - fn collect_const(&mut self, id: ConstId, data: &ConstSignature) { + fn collect_const(&mut self, id: ConstId, data: &'db ConstSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, @@ -1711,7 +1736,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.return_ty = return_ty; } - fn collect_static(&mut self, id: StaticId, data: &StaticSignature) { + fn collect_static(&mut self, id: StaticId, data: &'db StaticSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, @@ -1878,13 +1903,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.result.method_resolutions.insert(expr, (func, subst.store())); } - fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { + fn write_variant_resolution(&mut self, id: ExprOrPatIdPacked, variant: VariantId) { self.result.variant_resolutions.insert(id, variant); } fn write_assoc_resolution( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, item: CandidateId, subs: GenericArgs<'db>, ) { @@ -1920,7 +1945,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn with_ty_lowering( &mut self, - store: &ExpressionStore, + store: &'db ExpressionStore, types_source: InferenceTyDiagnosticSource, store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, @@ -1967,7 +1992,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn make_ty( &mut self, type_ref: TypeRefId, - store: &ExpressionStore, + store: &'db ExpressionStore, type_source: InferenceTyDiagnosticSource, store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, @@ -1994,7 +2019,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn identity_args(&self) -> GenericArgs<'db> { *self.identity_args.get_or_init(|| { - GenericArgs::identity_for_item(self.interner(), self.store_owner.into()) + GenericArgs::identity_for_item(self.interner(), self.generic_def.into()) }) } @@ -2140,14 +2165,18 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.table.resolve_vars_if_possible(t) } - pub(crate) fn structurally_resolve_type(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> Ty<'db> { + pub(crate) fn structurally_resolve_type( + &mut self, + node: ExprOrPatIdPacked, + ty: Ty<'db>, + ) -> Ty<'db> { let result = self.table.try_structurally_resolve_type(node.into(), ty); if result.is_ty_var() { self.type_must_be_known_at_this_point(node, ty) } else { result } } pub(crate) fn emit_type_mismatch( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, expected: Ty<'db>, found: Ty<'db>, ) { @@ -2162,7 +2191,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn demand_eqtype( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { @@ -2192,7 +2221,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn demand_suptype( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { @@ -2224,7 +2253,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { pub(crate) fn type_must_be_known_at_this_point( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ty: Ty<'db>, ) -> Ty<'db> { if self.vars_emitted_type_must_be_known_for.insert(ty.into()) { @@ -2260,7 +2289,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, path: &Path, value_ns: bool, ) -> (Ty<'db>, Option) { @@ -2555,7 +2584,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { }; fn forbid_unresolved_segments<'db>( - ctx: &InferenceContext<'_, 'db>, + ctx: &InferenceContext<'db>, result: (Ty<'db>, Option), unresolved: Option, ) -> (Ty<'db>, Option) { @@ -2570,7 +2599,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant_on_alias( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ty: Ty<'db>, unresolved: Option, path: &ModPath, @@ -2608,11 +2637,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - fn resolve_boxed_box(&self) -> Option { - let struct_ = self.lang_items.OwnedBox?; - Some(struct_.into()) - } - fn resolve_range_full(&self) -> Option { let struct_ = self.lang_items.RangeFull?; Some(struct_.into()) @@ -2725,7 +2749,7 @@ impl<'db> Expectation<'db> { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(ctx: &mut InferenceContext<'_, 'db>, ty: Ty<'db>) -> Self { + fn rvalue_hint(ctx: &mut InferenceContext<'db>, ty: Ty<'db>) -> Self { match ctx.struct_tail_without_normalization(ty).kind() { TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(..) => { Expectation::RValueLikeUnsized(ty) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs index e5304582ca412..7331f7a8a4d27 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs @@ -33,7 +33,7 @@ enum CallStep<'db> { Overloaded(MethodCallee<'db>), } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_call( &mut self, call_expr: ExprId, @@ -106,7 +106,7 @@ impl<'db> InferenceContext<'_, 'db> { call_expr: ExprId, callee_expr: ExprId, arg_exprs: &[ExprId], - autoderef: &mut InferenceContextAutoderef<'_, '_, 'db>, + autoderef: &mut InferenceContextAutoderef<'_, 'db>, error_reported: &mut bool, ) -> Option> { let final_ty = autoderef.final_ty(); @@ -540,8 +540,8 @@ pub(crate) struct DeferredCallResolution<'db> { fn_sig: FnSig<'db>, } -impl<'a, 'db> DeferredCallResolution<'db> { - pub(crate) fn resolve(self, ctx: &mut InferenceContext<'a, 'db>) { +impl<'db> DeferredCallResolution<'db> { + pub(crate) fn resolve(self, ctx: &mut InferenceContext<'db>) { debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index da996ccbea86a..dc08139081947 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -123,7 +123,7 @@ impl<'db> CastCheck<'db> { pub(super) fn check( &mut self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) -> Result<(), InferenceDiagnostic> { self.expr_ty = ctx.table.try_structurally_resolve_type(self.source_expr.into(), self.expr_ty); @@ -159,7 +159,7 @@ impl<'db> CastCheck<'db> { self.do_check(ctx).map_err(|e| e.into_diagnostic(self.expr, self.expr_ty, self.cast_ty)) } - fn do_check(&self, ctx: &mut InferenceContext<'_, 'db>) -> Result<(), CastError> { + fn do_check(&self, ctx: &mut InferenceContext<'db>) -> Result<(), CastError> { let (t_from, t_cast) = match (CastTy::from_ty(ctx.db, self.expr_ty), CastTy::from_ty(ctx.db, self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), @@ -258,7 +258,7 @@ impl<'db> CastCheck<'db> { fn check_ref_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, t_expr: Ty<'db>, m_expr: Mutability, t_cast: Ty<'db>, @@ -304,7 +304,7 @@ impl<'db> CastCheck<'db> { fn check_ptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, src: Ty<'db>, dst: Ty<'db>, ) -> Result<(), CastError> { @@ -456,7 +456,7 @@ impl<'db> CastCheck<'db> { fn check_ptr_addr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, expr_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, expr_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -470,7 +470,7 @@ impl<'db> CastCheck<'db> { fn check_addr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -486,7 +486,7 @@ impl<'db> CastCheck<'db> { fn check_fptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -520,7 +520,7 @@ enum PointerKind<'db> { fn pointer_kind<'db>( expr: ExprId, ty: Ty<'db>, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) -> Result>, ()> { let ty = ctx.table.try_structurally_resolve_type(expr.into(), ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 2a5567dfae544..e2948a81ac7d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -47,7 +47,7 @@ struct ClosureSignatures<'db> { liberated_sig: FnSig<'db>, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { fn poll_option_ty(&mut self, item_ty: Ty<'db>) -> Ty<'db> { let interner = self.interner(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs index 5ea43bc03ca86..38e634eb7db49 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -35,8 +35,8 @@ use std::{iter, mem}; use hir_def::{ expr_store::ExpressionStore, hir::{ - BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatId, Pat, - PatId, Statement, + BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatIdPacked, + Pat, PatId, Statement, }, resolver::ValueNs, }; @@ -194,7 +194,7 @@ enum PlaceAncestryRelation { /// analysis pass. type InferredCaptureInformation = Vec<(Place, CaptureInfo)>; -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn closure_analyze(&mut self) { let upvars = crate::upvars::upvars_mentioned(self.db, self.store_owner) .unwrap_or(const { &FxHashMap::with_hasher(FxBuildHasher) }); @@ -1202,7 +1202,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { let PlaceBase::Upvar { .. } = place_with_id.place.base else { return }; @@ -1222,7 +1222,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; }; @@ -1237,7 +1237,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; }; @@ -1256,7 +1256,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; @@ -1284,15 +1284,15 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { self.borrow(assignee_place, BorrowKind::Mutable, ctx); } } /// Rust doesn't permit moving fields out of a type that implements drop #[instrument(skip(fcx), ret, level = "debug")] -fn restrict_precision_for_drop_types<'a, 'db>( - fcx: &mut InferenceContext<'a, 'db>, +fn restrict_precision_for_drop_types<'db>( + fcx: &mut InferenceContext<'db>, mut place: Place, capture_info: &mut CaptureInfo, ) -> Place { @@ -1461,7 +1461,7 @@ fn determine_capture_info(capture_info_a: &mut CaptureInfo, capture_info_b: &mut fn determine_capture_sources( capture_info_a: &mut CaptureInfo, capture_info_b: &mut CaptureInfo, - dedup_sources_scratch: &mut FxHashMap, + dedup_sources_scratch: &mut FxHashMap, ) -> SmallVec<[CaptureSourceStack; 2]> { dedup_sources_scratch.clear(); dedup_sources_scratch.extend( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index d8a8cceee6583..4d300f5048a55 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -9,8 +9,8 @@ use hir_def::{ AdtId, HasModule, VariantId, attrs::AttrFlags, hir::{ - Array, AsmOperand, BindingId, Expr, ExprId, ExprOrPatId, MatchArm, Pat, PatId, - RecordLitField, RecordSpread, Statement, + Array, AsmOperand, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, MatchArm, Pat, + PatId, RecordLitField, RecordSpread, Statement, }, resolver::ValueNs, }; @@ -144,7 +144,7 @@ pub(crate) struct PlaceWithOrigin { impl PlaceWithOrigin { fn new_no_projections<'db>( - origin: impl Into, + origin: impl Into, base_ty: Ty<'db>, base: PlaceBase, ) -> PlaceWithOrigin { @@ -166,7 +166,7 @@ impl PlaceWithOrigin { PlaceWithOrigin { origins, place: Place { base_ty: base_ty.store(), base, projections } } } - fn push_projection(&mut self, projection: Projection, origin: ExprOrPatId) { + fn push_projection(&mut self, projection: Projection, origin: ExprOrPatIdPacked) { self.place.projections.push(projection); for origin_stack in &mut self.origins { origin_stack.push(origin); @@ -301,7 +301,7 @@ pub(crate) trait Delegate<'db> { /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic /// id will be the id of the expression `expr` but the place itself will have /// the id of the binding in the pattern `pat`. - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The value found at `place` is used, depending /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. @@ -316,7 +316,7 @@ pub(crate) trait Delegate<'db> { /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic /// id will be the id of the expression `expr` but the place itself will have /// the id of the binding in the pattern `pat`. - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The value found at `place` is being borrowed with kind `bk`. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). @@ -324,7 +324,7 @@ pub(crate) trait Delegate<'db> { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ); /// The value found at `place` is being copied. @@ -333,7 +333,7 @@ pub(crate) trait Delegate<'db> { /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared /// borrow is the "minimum access" that would be needed to perform a copy. - fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default // we treat a copy of `x` as a borrow of `x`. self.borrow(place_with_id, BorrowKind::Immutable, ctx) @@ -341,12 +341,12 @@ pub(crate) trait Delegate<'db> { /// The path at `assignee_place` is being assigned to. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The path at `binding_place` is a binding that is being initialized. /// /// This covers cases such as `let x = 42;` - fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { // Bindings can normally be treated as a regular assignment, so by default we // forward this to the mutate callback. self.mutate(binding_place, ctx) @@ -357,16 +357,16 @@ pub(crate) trait Delegate<'db> { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ); } impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).consume(place_with_id, ctx) } - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).use_cloned(place_with_id, ctx) } @@ -374,20 +374,20 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { (**self).borrow(place_with_id, bk, ctx) } - fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).copy(place_with_id, ctx) } - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).mutate(assignee_place, ctx) } - fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).bind(binding_place, ctx) } @@ -395,7 +395,7 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { (**self).fake_read(place_with_id, cause, ctx) } @@ -404,21 +404,21 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { /// A visitor that reports how each expression is being used. /// /// See [module-level docs][self] and [`Delegate`] for details. -pub(crate) struct ExprUseVisitor<'a, 'b, 'db, D: Delegate<'db>> { - cx: &'a mut InferenceContext<'b, 'db>, +pub(crate) struct ExprUseVisitor<'a, 'db, D: Delegate<'db>> { + cx: &'a mut InferenceContext<'db>, delegate: D, closure_expr: ExprId, upvars: UpvarsRef<'db>, } -impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { +impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D> { /// Creates the ExprUseVisitor, configuring it with the various options provided: /// /// - `delegate` -- who receives the callbacks /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) /// - `typeck_results` --- typeck results for the code being analyzed pub(crate) fn new( - cx: &'a mut InferenceContext<'b, 'db>, + cx: &'a mut InferenceContext<'db>, closure_expr: ExprId, upvars: UpvarsRef<'db>, delegate: D, @@ -648,7 +648,7 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { } } - Expr::Become { expr } | Expr::Await { expr } | Expr::Box { expr } => { + Expr::Become { expr } | Expr::Await { expr } => { self.consume_expr(expr)?; } @@ -1165,7 +1165,7 @@ impl_from!(PatId for CatPatternPat); /// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into /// two operations: a dereference to reach the array data and then an index to /// jump forward to the relevant item. -impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { +impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D> { fn expect_and_resolve_type(&mut self, ty: Option>) -> Result> { match ty { Some(ty) => { @@ -1392,7 +1392,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { fn cat_local( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expr_ty: Ty<'db>, var_id: BindingId, ) -> Result { @@ -1408,7 +1408,11 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. - fn cat_upvar(&mut self, hir_id: ExprOrPatId, var_id: BindingId) -> Result { + fn cat_upvar( + &mut self, + hir_id: ExprOrPatIdPacked, + var_id: BindingId, + ) -> Result { let var_ty = self.expect_and_resolve_type( self.cx.result.type_of_binding.get(var_id).map(|it| it.as_ref()), )?; @@ -1420,13 +1424,13 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { )) } - fn cat_rvalue(&self, hir_id: ExprOrPatId, expr_ty: Ty<'db>) -> PlaceWithOrigin { + fn cat_rvalue(&self, hir_id: ExprOrPatIdPacked, expr_ty: Ty<'db>) -> PlaceWithOrigin { PlaceWithOrigin::new_no_projections(hir_id, expr_ty, PlaceBase::Rvalue) } fn cat_projection( &self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, mut base_place: PlaceWithOrigin, ty: Ty<'db>, kind: ProjectionKind, @@ -1455,7 +1459,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { fn cat_deref( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, mut base_place: PlaceWithOrigin, ) -> Result { let base_curr_ty = base_place.place.ty(); @@ -1712,7 +1716,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// Represents the place matched on by a deref pattern's interior. fn pat_deref_place( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, base_place: PlaceWithOrigin, inner: PatId, target_ty: Ty<'db>, @@ -1746,7 +1750,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// FIXME(never_patterns): update this comment once the aforementioned MIR builder /// code is changed to be insensitive to inhhabitedness. #[instrument(skip(self), level = "debug")] - fn is_multivariant_adt(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> bool { + fn is_multivariant_adt(&mut self, node: ExprOrPatIdPacked, ty: Ty<'db>) -> bool { if let TyKind::Adt(def, _) = self.cx.structurally_resolve_type(node, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need // to assume that more cases will be added to the variant in the future. This mean diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 343919f5babbc..85d8142335dd3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -793,7 +793,7 @@ where fn coerce_closure_to_fn( &mut self, a: Ty<'db>, - closure_def_id_a: InternedClosureId, + closure_def_id_a: InternedClosureId<'db>, args_a: GenericArgs<'db>, b: Ty<'db>, ) -> CoerceResult<'db> { @@ -856,9 +856,9 @@ where } } -struct InferenceCoercionDelegate<'a, 'b, 'db>(&'a mut InferenceContext<'b, 'db>); +struct InferenceCoercionDelegate<'a, 'db>(&'a mut InferenceContext<'db>); -impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> { +impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, 'db> { #[inline] fn infcx(&self) -> &InferCtxt<'db> { &self.0.table.infer_ctxt @@ -884,7 +884,7 @@ impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> { } } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { /// Attempt to coerce an expression to a type, and return the /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. @@ -1242,7 +1242,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// if necessary. pub(crate) fn coerce( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, cause: &ObligationCause, expression: ExprId, expression_ty: Ty<'db>, @@ -1265,7 +1265,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// removing a `;`). pub(crate) fn coerce_forced_unit( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, expr: ExprId, cause: &ObligationCause, label_unit_as_expected: bool, @@ -1287,7 +1287,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// `Nil`. pub(crate) fn coerce_inner( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, cause: &ObligationCause, expression: ExprId, mut expression_ty: Ty<'db>, @@ -1403,7 +1403,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { self.pushed += 1; } - pub(crate) fn complete(self, icx: &mut InferenceContext<'_, 'db>) -> Ty<'db> { + pub(crate) fn complete(self, icx: &mut InferenceContext<'db>) -> Ty<'db> { if let Some(final_ty) = self.final_ty { final_ty } else { @@ -1597,7 +1597,7 @@ fn coerce<'db>( Ok((adjustments, ty)) } -fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool { +fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId<'_>) -> bool { let InternedClosure { owner, expr, .. } = closure.loc(db); upvars_mentioned(db, owner.expression_store_owner(db)) .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty())) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs index e871edd265c16..69753687afddd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs @@ -9,8 +9,11 @@ use either::Either; use hir_def::expr_store::path::Path; use hir_def::{ExpressionStoreOwnerId, GenericDefId}; use hir_def::{expr_store::ExpressionStore, type_ref::TypeRefId}; -use hir_def::{hir::ExprOrPatId, resolver::Resolver}; -use la_arena::{Idx, RawIdx}; +use hir_def::{ + hir::{ExprId, ExprOrPatIdPacked}, + resolver::Resolver, +}; +use la_arena::RawIdx; use rustc_hash::FxHashMap; use thin_vec::ThinVec; @@ -55,7 +58,7 @@ impl Diagnostics { } pub(crate) struct PathDiagnosticCallbackData<'a> { - node: ExprOrPatId, + node: ExprOrPatIdPacked, diagnostics: &'a Diagnostics, } @@ -90,7 +93,7 @@ pub(super) struct InferenceTyLoweringContext<'db, 'a> { ctx: TyLoweringContext<'db, 'a>, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, - defined_anon_consts: &'a RefCell>, + defined_anon_consts: &'a RefCell>>, } impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { @@ -98,7 +101,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { pub(super) fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, def: ExpressionStoreOwnerId, @@ -107,7 +110,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { lifetime_elision: LifetimeElisionKind<'db>, allow_using_generic_params: bool, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, - defined_anon_consts: &'a RefCell>, + defined_anon_consts: &'a RefCell>>, lifetime_lowering_mode: LifetimeLoweringMode, ) -> Self { let mut ctx = TyLoweringContext::new( @@ -131,7 +134,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { pub(super) fn at_path<'b>( &'b mut self, path: &'b Path, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ) -> PathLoweringContext<'b, 'a, 'db> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }), @@ -152,7 +155,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, - node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))), + node: ExprOrPatIdPacked::from(ExprId::from_raw(RawIdx::from_u32(0))), }), callback: |_data, _, _diag| {}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index df17cc38774a8..20cfc9008a9e1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -7,9 +7,9 @@ use hir_def::{ AdtId, FieldId, TupleFieldId, TupleId, VariantId, expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ - Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, - InlineAsmKind, LabelId, LoopSource, Pat, PatId, RecordLitField, RecordSpread, Statement, - UnaryOp, + Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, + ExprOrPatIdPacked, InlineAsmKind, LabelId, LoopSource, Pat, PatId, RecordLitField, + RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, signatures::VariantFields, @@ -20,7 +20,7 @@ use rustc_ast_ir::Mutability; use rustc_hash::FxHashMap; use rustc_type_ir::{ InferTy, Interner, - inherent::{GenericArgs as _, IntoKind, Ty as _}, + inherent::{IntoKind, Ty as _}, }; use stdx::never; use syntax::ast::RangeOp; @@ -53,7 +53,7 @@ pub(crate) enum ExprIsRead { No, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_expr( &mut self, tgt_expr: ExprId, @@ -143,29 +143,22 @@ impl<'db> InferenceContext<'_, 'db> { expr: ExprId, is_read: ExprIsRead, ) -> bool { - // rustc does the place expr check first, but since we are feeding - // readness of the `expr` as a given value, we just can short-circuit - // the place expr check if it's true(see codes and comments below) - if is_read == ExprIsRead::Yes { - return true; - } - - // We only care about place exprs. Anything else returns an immediate - // which would constitute a read. We don't care about distinguishing - // "syntactic" place exprs since if the base of a field projection is - // not a place then it would've been UB to read from it anyways since - // that constitutes a read. - if !self.is_syntactic_place_expr(expr) { - return true; - } - // rustc queries parent hir node of `expr` here and determine whether // the current `expr` is read of value per its parent. // But since we don't have hir node, we cannot follow such "bottom-up" // method. // So, we pass down such readness from the parent expression through the // recursive `infer_expr*` calls in a "top-down" manner. + // rustc does the place expr check first, but since we are feeding + // readness of the `expr` as a given value, we just can short-circuit + // the place expr check if it's true(see codes and comments below) is_read == ExprIsRead::Yes + // We only care about place exprs. Anything else returns an immediate + // which would constitute a read. We don't care about distinguishing + // "syntactic" place exprs since if the base of a field projection is + // not a place then it would've been UB to read from it anyways since + // that constitutes a read. + || !self.is_syntactic_place_expr(expr) } /// Whether this pattern constitutes a read of value of the scrutinee that @@ -266,7 +259,6 @@ impl<'db> InferenceContext<'_, 'db> { | Expr::Await { .. } | Expr::Ref { .. } | Expr::Range { .. } - | Expr::Box { .. } | Expr::RecordLit { .. } | Expr::Yeet { .. } | Expr::Missing @@ -628,7 +620,6 @@ impl<'db> InferenceContext<'_, 'db> { expected, tgt_expr, ), - &Expr::Box { expr } => self.infer_expr_box(expr, expected), Expr::UnaryOp { expr, op } => self.infer_unop_expr(*op, *expr, expected, tgt_expr), Expr::BinaryOp { lhs, rhs, op } => match op { Some(BinaryOp::Assignment { op: Some(op) }) => { @@ -904,7 +895,7 @@ impl<'db> InferenceContext<'_, 'db> { }; let ty = self.insert_type_vars_shallow(ty); self.write_expr_ty(tgt_expr, ty); - if self.shallow_resolve(ty).is_never() + if self.table.resolve_vars_with_obligations(ty).is_never() && self.expr_guaranteed_to_constitute_read_for_never(tgt_expr, is_read) { // Any expression that produces a value of type `!` must have diverged @@ -969,8 +960,10 @@ impl<'db> InferenceContext<'_, 'db> { return self.types.types.error; }; self.table.register_bound(awaitee_ty, into_future, ObligationCause::new(expr)); - // Do not eagerly normalize. - Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]) + self.table.try_structurally_resolve_type( + expr.into(), + Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]), + ) } fn infer_record_expr( @@ -1279,7 +1272,7 @@ impl<'db> InferenceContext<'_, 'db> { } } - fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> { + fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatIdPacked, scope_id: ExprId) -> Ty<'db> { let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, scope_id); let ty = match self.infer_path(path, id) { Some((_, ty)) => ty, @@ -1490,27 +1483,6 @@ impl<'db> InferenceContext<'_, 'db> { self.types.types.never } - fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation<'db>) -> Ty<'db> { - if let Some(box_id) = self.resolve_boxed_box() { - let table = &mut self.table; - let inner_exp = expected - .to_option(table) - .as_ref() - .and_then(|e| e.as_adt()) - .filter(|(e_adt, _)| e_adt == &box_id) - .map(|(_, subts)| { - let g = subts.type_at(0); - Expectation::rvalue_hint(self, g) - }) - .unwrap_or_else(Expectation::none); - - let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp, ExprIsRead::Yes); - Ty::new_box(self.interner(), inner_ty) - } else { - self.err_ty() - } - } - fn infer_block( &mut self, expr: ExprId, @@ -2102,7 +2074,7 @@ impl<'db> InferenceContext<'_, 'db> { // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types - let demand_compatible = |this: &mut InferenceContext<'_, 'db>, idx| { + let demand_compatible = |this: &mut InferenceContext<'db>, idx| { let formal_input_ty: Ty<'db> = formal_input_tys[idx]; let expected_input_ty: Ty<'db> = expected_input_tys[idx]; let provided_arg = provided_args[idx]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs index 3744a434d2199..0498ea8fd00a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs @@ -27,7 +27,7 @@ pub(crate) enum DivergingFallbackBehavior { ToNever, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn type_inference_fallback(&mut self) { debug!( "type-inference-fallback start obligations: {:#?}", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 4fa1b71ad4a94..7d285a3a21028 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -13,7 +13,7 @@ use crate::{ lower::lower_mutability, }; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_mut_body(&mut self, body_expr: ExprId) { self.infer_mut_expr(body_expr, Mutability::Not); } @@ -159,7 +159,6 @@ impl<'db> InferenceContext<'_, 'db> { | Expr::Range { lhs: Some(expr), rhs: None, range_type: _ } | Expr::Range { rhs: Some(expr), lhs: None, range_type: _ } | Expr::Await { expr } - | Expr::Box { expr } | Expr::Loop { body: expr, label: _, source: _ } | Expr::Cast { expr, type_ref: _ } => { self.infer_mut_expr(*expr, Mutability::Not); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs index 85801358d4441..5fd4e830fb172 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs @@ -20,7 +20,7 @@ use crate::{ }, }; -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Checks a `a = b` pub(crate) fn infer_assign_op_expr( &mut self, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs index 63149deb82b77..2d64f9567b375 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs @@ -12,7 +12,7 @@ use crate::{ }, }; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { /// This takes all the opaque type uses during HIR typeck. It first computes /// the concrete hidden type by iterating over all defining uses. /// @@ -63,7 +63,7 @@ impl<'db> UsageKind<'db> { } } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { fn compute_definition_site_hidden_types( &mut self, mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 1e539d24c18a8..f464de06cd30f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -10,8 +10,8 @@ use hir_def::{ AdtId, LocalFieldId, VariantId, expr_store::path::Path, hir::{ - BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId, - RecordFieldPat, + BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, Literal, Pat, + PatId, RecordFieldPat, }, resolver::ValueNs, signatures::VariantFields, @@ -237,7 +237,7 @@ impl<'db> ResolvedPat<'db> { } } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Experimental pattern feature: after matching against a shared reference, do we limit the /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`? /// This corresponds to Rule 3 of RFC 3627. @@ -853,7 +853,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // Subtyping doesn't matter here, as the value is some kind of scalar. let mut demand_eqtype = |x: &mut _| { if let Some((_, x_ty, x_expr)) = *x { - _ = self.demand_eqtype(ExprOrPatId::from(x_expr), expected, x_ty); + _ = self.demand_eqtype(ExprOrPatIdPacked::from(x_expr), expected, x_ty); } }; demand_eqtype(&mut lhs); @@ -868,7 +868,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // We require types to be resolved here so that we emit inference failure // rather than "_ is not a char or numeric". let ty = self.structurally_resolve_type( - lhs_expr.or(rhs_expr).map(ExprOrPatId::ExprId).unwrap_or(pat.into()), + lhs_expr.or(rhs_expr).map(ExprOrPatIdPacked::from).unwrap_or(pat.into()), expected, ); if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { @@ -1248,7 +1248,11 @@ impl<'a, 'db> InferenceContext<'a, 'db> { self.push_diagnostic(InferenceDiagnostic::UnionPatHasRest { pat }); } } else if !unmentioned_fields.is_empty() && !has_rest_pat { - // FIXME: Emit an error. + self.push_diagnostic(InferenceDiagnostic::RecordMissingFields { + record: ExprOrPatId::PatId(pat), + variant, + missed_fields: unmentioned_fields.into_iter().map(|f| f.0).collect(), + }) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index ecc81f9de0232..47a905fc142cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -3,6 +3,7 @@ use hir_def::{ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, + hir::ExprOrPatIdPacked, resolver::{ResolveValueResult, TypeNs, ValueNs}, signatures::{ConstSignature, FunctionSignature}, }; @@ -23,13 +24,13 @@ use crate::{ }, }; -use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; +use super::{InferenceContext, InferenceTyDiagnosticSource}; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn infer_path( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, Ty<'db>)> { let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?; @@ -60,7 +61,7 @@ impl<'db> InferenceContext<'_, 'db> { fn resolve_value_path( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, value: ValueNs, self_subst: Option>, ) -> Option> { @@ -145,7 +146,7 @@ impl<'db> InferenceContext<'_, 'db> { pub(super) fn resolve_value_path_inner( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, no_diagnostics: bool, ) -> Option<(ValueNs, Option>)> { // Don't use `self.make_ty()` here as we need `orig_ns`. @@ -185,7 +186,7 @@ impl<'db> InferenceContext<'_, 'db> { let ty = self.table.process_user_written_ty(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { - let hygiene = self.store.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id.unpack()); // FIXME: report error, unresolved first path segment let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?; @@ -273,7 +274,7 @@ impl<'db> InferenceContext<'_, 'db> { pub(super) fn add_required_obligations_for_value_path( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, def: GenericDefId, subst: GenericArgs<'db>, ) { @@ -293,7 +294,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, trait_ref: TraitRef<'db>, segment: PathSegment<'_>, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { let trait_ = trait_ref.def_id.0; let item = @@ -330,7 +331,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, ty: Ty<'db>, name: &Name, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { if ty.is_ty_error() { return None; @@ -399,7 +400,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, ty: Ty<'db>, name: &Name, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { let ty = self.table.try_structurally_resolve_type(id.into(), ty); let (enum_id, subst) = match ty.as_adt() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs index bbf047b8bacfb..b226e5ca85de0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs @@ -25,7 +25,7 @@ pub(super) enum PlaceOp { Index, } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn try_overloaded_deref( &self, expr: ExprId, @@ -107,7 +107,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { expr: ExprId, base_expr: ExprId, index_expr: ExprId, - autoderef: &mut InferenceContextAutoderef<'_, 'a, 'db>, + autoderef: &mut InferenceContextAutoderef<'_, 'db>, index_ty: Ty<'db>, ) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> { let ty = autoderef.final_ty(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 4c808714d9506..6157f51500d9e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -314,7 +314,11 @@ impl<'db> InferenceTable<'db> { } /// Create a `GenericArgs` full of infer vars for `def`. - pub(crate) fn fresh_args_for_item(&self, span: Span, def: SolverDefId) -> GenericArgs<'db> { + pub(crate) fn fresh_args_for_item( + &self, + span: Span, + def: SolverDefId<'db>, + ) -> GenericArgs<'db> { self.infer_ctxt.fresh_args_for_item(span, def) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index adba047042cb6..db1f7b874e95b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -176,7 +176,7 @@ pub fn layout_of_ty_query( let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); let ty = infer_ctxt - .at(&cause, trait_env.param_env()) + .at(&cause, trait_env.param_env(db)) .deeply_normalize(ty.as_ref()) .unwrap_or(ty.as_ref()); let result = match ty.kind() { @@ -190,7 +190,7 @@ pub fn layout_of_ty_query( s, repr.packed(), &args, - trait_env.as_ref(), + trait_env.as_ref(db), target, ); } @@ -355,11 +355,11 @@ pub fn layout_of_ty_query( PatternKind::Range { start, end } => { if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr { scalar.valid_range_mut().start = extract_const_value(start)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?; scalar.valid_range_mut().end = extract_const_value(end)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?; // FIXME(pattern_types): create implied bounds from pattern types in signatures @@ -419,10 +419,10 @@ pub fn layout_of_ty_query( .map(|pat| match pat.kind() { PatternKind::Range { start, end } => Ok::<_, LayoutError>(( extract_const_value(start)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?, extract_const_value(end)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?, )), PatternKind::NotNull | PatternKind::Or(_) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs index cf92c18f8ccd8..4ff5eb7690624 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs @@ -6,7 +6,7 @@ use rustc_abi::{AddressSpace, AlignFromBytesError, TargetDataLayoutError}; use crate::db::HirDatabase; -#[salsa_macros::tracked(returns(as_ref))] +#[salsa::tracked(returns(as_ref))] pub fn target_data_layout_query( db: &dyn HirDatabase, krate: Crate, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index a9975615be968..c631c87de5160 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -67,7 +67,7 @@ use hir_def::{ GenericDefId, HasModule, LifetimeParamId, ModuleId, StaticId, TypeAliasId, TypeOrConstParamId, TypeParamId, expr_store::{Body, ExpressionStore}, - hir::{BindingId, ExprId, ExprOrPatId, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, ExprOrPatIdPacked, PatId}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{Rawness, TypeRefId}, }; @@ -81,6 +81,7 @@ use rustc_type_ir::{ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, inherent::{IntoKind, Ty as _}, }; +use salsa::Update; use stdx::impl_from; use syntax::ast::{ConstArg, make}; use traits::FnTrait; @@ -165,7 +166,7 @@ impl ComplexMemoryMap<'_> { } impl<'db> MemoryMap<'db> { - pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError> { + pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError<'db>> { match self { MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), MemoryMap::Complex(cm) => cm.vtable.ty(id), @@ -181,8 +182,8 @@ impl<'db> MemoryMap<'db> { /// allocator function as `f` and it will return a mapping of old addresses to new addresses. fn transform_addresses( &self, - mut f: impl FnMut(&[u8], usize) -> Result, - ) -> Result, MirEvalError> { + mut f: impl FnMut(&[u8], usize) -> Result>, + ) -> Result, MirEvalError<'db>> { let mut transform = |(addr, val): (&usize, &[u8])| { let addr = *addr; let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; @@ -531,9 +532,9 @@ pub enum Span { } impl_from!(ExprId, PatId, BindingId, TypeRefId for Span); -impl From for Span { - fn from(value: ExprOrPatId) -> Self { - match value { +impl From for Span { + fn from(value: ExprOrPatIdPacked) -> Self { + match value.unpack() { ExprOrPatId::ExprId(idx) => idx.into(), ExprOrPatId::PatId(idx) => idx.into(), } @@ -553,19 +554,24 @@ impl Span { } /// A [`DefWithBodyId`], or an anon const. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Supertype)] -pub enum InferBodyId { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Supertype, Update)] +pub enum InferBodyId<'db> { DefWithBodyId(DefWithBodyId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), } -impl_from!(DefWithBodyId(FunctionId, ConstId, StaticId), AnonConstId for InferBodyId); -impl From for InferBodyId { +impl_from!( + impl<'db> + DefWithBodyId(FunctionId, ConstId, StaticId), + AnonConstId<'db> + for InferBodyId<'db> +); +impl<'db> From for InferBodyId<'db> { fn from(id: EnumVariantId) -> Self { InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(id)) } } -impl HasModule for InferBodyId { +impl HasModule for InferBodyId<'_> { fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { InferBodyId::DefWithBodyId(id) => id.module(db), @@ -574,7 +580,7 @@ impl HasModule for InferBodyId { } } -impl HasResolver for InferBodyId { +impl HasResolver for InferBodyId<'_> { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { InferBodyId::DefWithBodyId(id) => id.resolver(db), @@ -583,7 +589,7 @@ impl HasResolver for InferBodyId { } } -impl InferBodyId { +impl InferBodyId<'_> { pub fn expression_store_owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwnerId { match self { InferBodyId::DefWithBodyId(id) => id.into(), @@ -631,17 +637,11 @@ impl InferBodyId { pub fn setup_tracing() -> Option { use std::env; - use std::sync::LazyLock; use tracing_subscriber::{Registry, layer::SubscriberExt}; use tracing_tree::HierarchicalLayer; - static ENABLE: LazyLock = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok()); - if !*ENABLE { - return None; - } - let filter: tracing_subscriber::filter::Targets = - env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); + env::var("SOLVER_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); let layer = HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index e251fa84ed1a1..bdb882b70b259 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -10,6 +10,7 @@ pub(crate) mod path; use std::{cell::OnceCell, iter, mem, sync::OnceLock}; +use base_db::salsa::update_fallback_db; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, @@ -33,8 +34,8 @@ use hir_def::{ TraitFlags, TraitSignature, TypeAliasFlags, TypeAliasSignature, }, type_ref::{ - ConstRef, FnType, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, - TypeBound, TypeRef, TypeRefId, + ConstRef, FnType, LifetimeRef, LifetimeRefId, PathId, TraitBoundModifier, + TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; use hir_expand::name::Name; @@ -44,12 +45,13 @@ use rustc_abi::ExternAbi; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVarIndexKind, - BoundVariableKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, - ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, - TypeVisitableExt, Upcast, UpcastFrom, elaborate, + AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVariableKind, + DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, + Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, TypeVisitableExt, Upcast, + UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; +use salsa::Update; use smallvec::SmallVec; use stdx::{impl_from, never}; use thin_vec::ThinVec; @@ -210,7 +212,7 @@ pub struct TyLoweringContext<'db, 'a> { types: &'db crate::next_solver::DefaultAny<'db>, lang_items: &'db LangItems, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, generics: &'a OnceCell>, @@ -223,10 +225,10 @@ pub struct TyLoweringContext<'db, 'a> { lifetime_elision: LifetimeElisionKind<'db>, forbid_params_after: Option, forbid_params_after_reason: ForbidParamsAfterReason, - pub(crate) defined_anon_consts: ThinVec, + pub(crate) defined_anon_consts: ThinVec>, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, is_lowering_impl_trait_bounds: bool, - bound_vars: Vec>, // FIXME: HRTB and other for lifetime doesn't change it now + bound_vars: Vec<(Vec, BoundVarKinds<'db>)>, lifetime_lowering_mode: LifetimeLoweringMode, } @@ -234,7 +236,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { pub fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, generics: &'a OnceCell>, @@ -244,7 +246,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); let in_binders = DebruijnIndex::ZERO; let interner = DbInterner::new_with(db, resolver.krate()); - let bound_vars = vec![BoundVarKinds::empty(interner)]; + let bound_vars = + vec![(Vec::new(), TyLoweringContext::bound_vars(db, interner, generic_def, generics))]; Self { db, // Can provide no block since we don't use it for trait solving. @@ -299,10 +302,13 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { pub(crate) fn with_shifted_in( &mut self, - debruijn: DebruijnIndex, + binder: &[Name], f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, - ) -> T { - self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f) + ) -> (T, BoundVarKinds<'db>) { + self.push_bound_vars(binder); + let res = self.with_debruijn(self.in_binders.shifted_in(1), f); + let bound_vars = self.pop_bound_vars(); + (res, bound_vars) } pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { @@ -372,8 +378,22 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } + fn push_bound_vars(&mut self, binder: &[Name]) { + let bound_vars = BoundVarKinds::new_from_iter( + self.interner, + binder.iter().map(|_| { + BoundVariableKind::Region(BoundRegionKind::Named(self.generic_def.into())) + }), + ); + self.bound_vars.push((binder.to_vec(), bound_vars)); + } + + fn pop_bound_vars(&mut self) -> BoundVarKinds<'db> { + self.bound_vars.pop().unwrap().1 + } + fn peek_bound_vars(&self) -> BoundVarKinds<'db> { - *self.bound_vars.last().unwrap() + self.bound_vars.last().unwrap().1 } fn bound_vars( @@ -504,32 +524,50 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.types.regions.error } else { if is_late_bound { - if self.lifetime_lowering_mode == LifetimeLoweringMode::Bound { - Region::new_bound( - self.interner, - self.in_binders, - BoundRegion { - var: BoundVar::from_u32(index), - kind: BoundRegionKind::Named(id.parent.into()), - }, - ) - } else { - let solver_def_id = id.parent.into(); - Region::new_late_param( - self.interner, - solver_def_id, - BoundRegion { - var: BoundVar::from_u32(index), - kind: BoundRegionKind::Named(solver_def_id), - }, - ) - } + self.hrtb_region_param( + index, + DebruijnIndex::from_usize(self.in_binders.as_usize()), + id.parent, + ) } else { Region::new_early_param(self.interner, EarlyParamRegion { id, index }) } } } + fn hrtb_region_param( + &self, + index: u32, + debruijn: DebruijnIndex, + parent: GenericDefId, + ) -> Region<'db> { + if self.param_index_is_disallowed(index) { + // FIXME: Report an error. + self.types.regions.error + } else { + if self.lifetime_lowering_mode == LifetimeLoweringMode::Bound { + Region::new_bound( + self.interner, + debruijn, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(parent.into()), + }, + ) + } else { + let solver_def_id = parent.into(); + Region::new_late_param( + self.interner, + solver_def_id, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(solver_def_id), + }, + ) + } + } + } + #[tracing::instrument(skip(self), ret)] pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { let interner = self.interner; @@ -714,7 +752,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let (params, ret_ty) = fn_.split_params_and_ret(); let old_lifetime_elision = self.lifetime_elision; let mut args = Vec::with_capacity(fn_.params.len()); - self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx: &mut TyLoweringContext<'_, '_>| { + let binder = fn_.binder.as_ref().map(|b| b.as_ref()).unwrap_or_default(); + let (_, binder) = self.with_shifted_in(binder, |ctx: &mut TyLoweringContext<'_, '_>| { ctx.lifetime_elision = LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; args.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr))); @@ -723,8 +762,6 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }); self.lifetime_elision = old_lifetime_elision; - // FIXME: When we don't drop HRTB lifetimes, use those here. - let binder = BoundVarKinds::empty(interner); Ty::new_fn_ptr( interner, Binder::bind_with_vars( @@ -850,12 +887,21 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { where_predicate: &'b WherePredicate, ignore_bindings: bool, ) -> impl Iterator, GenericPredicateSource)> + use<'a, 'b, 'db> { + let lower_type_outlives = |ctx: &mut TyLoweringContext<'db, '_>, + target: &TypeRefId, + bound| { + let self_ty = ctx.lower_ty(*target); + let clause = ctx.lower_type_bound(bound, self_ty, ignore_bindings).collect::>(); + Either::Left(clause.into_iter()) + }; + match where_predicate { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - let self_ty = self.lower_ty(*target); - Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings)) - } + WherePredicate::TypeBound { lifetimes, target, bound } => match lifetimes { + Some(lifetimes) => { + self.with_shifted_in(lifetimes, |ctx| lower_type_outlives(ctx, target, bound)).0 + } + None => lower_type_outlives(self, target, bound), + }, &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(( Clause(Predicate::new( self.interner, @@ -881,42 +927,48 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let interner = self.interner; let meta_sized = self.lang_items.MetaSized; let pointee_sized = self.lang_items.PointeeSized; + let mut assoc_bounds = None; let mut clause = None; - match bound { - &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { - let binder = self.peek_bound_vars(); - // FIXME Don't silently drop the hrtb lifetimes here - if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { - // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented - // sized-hierarchy correctly. - if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { - // Ignore this bound - } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { - // Regard this as `?Sized` bound - ctx.ty_ctx().unsized_types.insert(self_ty); - } else { - if !ignore_bindings { - assoc_bounds = ctx.assoc_type_bindings_from_type_bound( - trait_ref, - path.type_ref().into(), - ); - } - clause = Some(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - ), - binder, - ), - ))); + + let mut lower_path_bound = |ctx: &mut TyLoweringContext<'db, '_>, path| { + let binder = ctx.peek_bound_vars(); + + if let Some((trait_ref, mut ctx)) = ctx.lower_trait_ref_from_path(path, self_ty) { + // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented + // sized-hierarchy correctly. + if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { + // Ignore this bound + } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { + // Regard this as `?Sized` bound + ctx.ty_ctx().unsized_types.insert(self_ty); + } else { + if !ignore_bindings { + assoc_bounds = ctx + .assoc_type_bindings_from_type_bound(trait_ref, path.type_ref().into()) + .map(|iter| iter.collect::>()); } + clause = Some(Clause(Predicate::new( + interner, + Binder::bind_with_vars( + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }, + )), + binder, + ), + ))); } } + }; + + match bound { + &TypeBound::ForLifetime(ref binder, path) => { + self.with_shifted_in(binder, |ctx| lower_path_bound(ctx, path)).0 + } + &TypeBound::Path(path, TraitBoundModifier::None) => lower_path_bound(self, path), &TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self.lang_items.Sized; // Don't lower associated type bindings as the only possible relaxed trait bound @@ -961,15 +1013,15 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // bounds in the input. // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. // These invariants are utilized by `TyExt::dyn_trait()` and chalk. - let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { + let bounds = 'bounds: { let mut principal = None; let mut auto_traits = SmallVec::<[_; 3]>::new(); let mut projections = Vec::new(); let mut had_error = false; for b in bounds { - let db = ctx.db; - ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| { + let db = self.db; + self.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| { match b.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); @@ -1006,12 +1058,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } if had_error { - return None; + break 'bounds None; } if principal.is_none() && auto_traits.is_empty() { // No traits is not allowed. - return None; + break 'bounds None; } // `Send + Sync` is the same as `Sync + Send`. @@ -1200,20 +1252,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { interner, principal.into_iter().chain(projections).chain(auto_traits), )) - }); + }; if let Some(bounds) = bounds { let region = match region { - Some(it) => match it.kind() { - rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => { - Region::new_bound( - self.interner, - db.shifted_out_to_binder(DebruijnIndex::from_u32(1)), - var, - ) - } - _ => it, - }, + Some(it) => it, None => Region::new_static(self.interner), }; Ty::new_dynamic(self.interner, bounds, region) @@ -1224,7 +1267,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } - fn lower_impl_trait(&mut self, def_id: InternedOpaqueTyId, bounds: &[TypeBound]) -> ImplTrait { + fn lower_impl_trait( + &mut self, + def_id: InternedOpaqueTyId<'db>, + bounds: &[TypeBound], + ) -> ImplTrait { let interner = self.interner; cov_mark::hit!(lower_rpit); let args = GenericArgs::identity_for_item(interner, def_id.into()); @@ -1234,44 +1281,41 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ); let prev_is_lowering_impl_trait_bounds = mem::replace(&mut self.is_lowering_impl_trait_bounds, true); - let (predicates, assoc_ty_bounds_start) = - self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { - let mut predicates = Vec::new(); - let mut assoc_ty_bounds = Vec::new(); - for b in bounds { - for (pred, source) in ctx.lower_type_bound(b, self_ty, false) { - match source { - GenericPredicateSource::SelfOnly => predicates.push(pred), - GenericPredicateSource::AssocTyBound => assoc_ty_bounds.push(pred), - } - } - } - if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = self.lang_items.Sized; - let sized_clause = sized_trait.map(|trait_id| { - let trait_ref = TraitRef::new_from_args( - interner, - trait_id.into(), - GenericArgs::new_from_slice(&[self_ty.into()]), - ); - Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )) - }); - predicates.extend(sized_clause); + let mut predicates = Vec::new(); + let mut assoc_ty_bounds = Vec::new(); + for b in bounds { + for (pred, source) in self.lower_type_bound(b, self_ty, false) { + match source { + GenericPredicateSource::SelfOnly => predicates.push(pred), + GenericPredicateSource::AssocTyBound => assoc_ty_bounds.push(pred), } + } + } - let assoc_ty_bounds_start = predicates.len() as u32; - predicates.extend(assoc_ty_bounds); - (predicates, assoc_ty_bounds_start) + if !self.unsized_types.contains(&self_ty) { + let sized_trait = self.lang_items.Sized; + let sized_clause = sized_trait.map(|trait_id| { + let trait_ref = TraitRef::new_from_args( + interner, + trait_id.into(), + GenericArgs::new_from_slice(&[self_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) }); + predicates.extend(sized_clause); + } + + let assoc_ty_bounds_start = predicates.len() as u32; + predicates.extend(assoc_ty_bounds); self.is_lowering_impl_trait_bounds = prev_is_lowering_impl_trait_bounds; ImplTrait { @@ -1281,6 +1325,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { + if let Some(region) = self.find_and_lower_hrtb_lifetime(lifetime) { + return region; + }; + match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { LifetimeNs::Static => Region::new_static(self.interner), @@ -1293,15 +1341,41 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { None => Region::error(self.interner), } } + + fn find_and_lower_hrtb_lifetime(&mut self, lifetime: LifetimeRefId) -> Option> { + if let LifetimeRef::Named(lt_name) = &self.store[lifetime] { + self.bound_vars.iter().rev().enumerate().find_map(|(debruijn, (binder, _))| { + binder.iter().enumerate().find_map(|(index, l)| { + (l == lt_name).then(|| { + self.hrtb_region_param( + index as u32, + DebruijnIndex::from_usize(debruijn), + self.generic_def, + ) + }) + }) + }) + } else { + None + } + } } -#[derive(Clone, PartialEq, Eq)] -pub struct TyLoweringResult { +#[derive(Clone, PartialEq, Eq, Update)] +pub struct TyLoweringResult<'db, T> { + #[update(fallback)] pub value: T, - info: Option, ThinVec)>>, + #[update(bounds(TyLoweringResultInfo<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + info: Option>>, } -impl std::fmt::Debug for TyLoweringResult { +#[derive(Clone, PartialEq, Eq, Update)] +struct TyLoweringResultInfo<'db> { + diagnostics: ThinVec, + anon_consts: ThinVec>, +} + +impl std::fmt::Debug for TyLoweringResult<'_, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut debug = f.debug_struct("TyLoweringResult"); debug.field("value", &self.value); @@ -1317,23 +1391,23 @@ impl std::fmt::Debug for TyLoweringResult { } } -impl TyLoweringResult { +impl<'db, T> TyLoweringResult<'db, T> { fn new( value: T, mut diagnostics: ThinVec, - mut defined_anon_consts: ThinVec, + mut defined_anon_consts: ThinVec>, ) -> Self { let info = if diagnostics.is_empty() && defined_anon_consts.is_empty() { None } else { diagnostics.shrink_to_fit(); defined_anon_consts.shrink_to_fit(); - Some(Box::new((diagnostics, defined_anon_consts))) + Some(Box::new(TyLoweringResultInfo { diagnostics, anon_consts: defined_anon_consts })) }; Self { value, info } } - fn from_ctx(value: T, ctx: TyLoweringContext<'_, '_>) -> Self { + fn from_ctx(value: T, ctx: TyLoweringContext<'db, '_>) -> Self { Self::new(value, ctx.diagnostics, ctx.defined_anon_consts) } @@ -1344,15 +1418,15 @@ impl TyLoweringResult { #[inline] pub fn diagnostics(&self) -> &[TyLoweringDiagnostic] { match &self.info { - Some(info) => &info.0, + Some(info) => &info.diagnostics, None => &[], } } #[inline] - pub fn defined_anon_consts(&self) -> &[AnonConstId] { + pub fn defined_anon_consts(&self) -> &[AnonConstId<'db>] { match &self.info { - Some(info) => &info.1, + Some(info) => &info.anon_consts, None => &[], } } @@ -1389,11 +1463,11 @@ pub(crate) fn impl_trait_query<'db>( .map(|it| it.value.get(DbInterner::new_no_crate(db))) } -#[salsa::tracked(returns(ref))] -pub(crate) fn impl_trait_with_diagnostics( - db: &dyn HirDatabase, +#[salsa::tracked(returns(ref), cycle_result = impl_trait_with_diagnostics_cycle_result)] +pub(crate) fn impl_trait_with_diagnostics<'db>( + db: &'db dyn HirDatabase, impl_id: ImplId, -) -> Option>> { +) -> Option>> { let impl_data = ImplSignature::of(db, impl_id); let resolver = impl_id.resolver(db); let generics = OnceCell::new(); @@ -1413,6 +1487,14 @@ pub(crate) fn impl_trait_with_diagnostics( Some(TyLoweringResult::from_ctx(StoredEarlyBinder::bind(StoredTraitRef::new(trait_ref)), ctx)) } +pub(crate) fn impl_trait_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, + _: salsa::Id, + _impl_id: ImplId, +) -> Option>> { + None +} + impl ImplTraitId { #[inline] pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { @@ -1456,7 +1538,7 @@ impl ImplTraitId { } } -impl InternedOpaqueTyId { +impl InternedOpaqueTyId<'_> { #[inline] pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { self.loc(db).predicates(db) @@ -1547,7 +1629,7 @@ pub enum TyDefId { } impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum ValueTyDefId { FunctionId(FunctionId), StructId(StructId), @@ -1607,11 +1689,11 @@ pub(crate) fn type_for_const<'db>( } /// Build the declared type of a const. -#[salsa_macros::tracked(returns(ref))] -pub(crate) fn type_for_const_with_diagnostics( - db: &dyn HirDatabase, +#[salsa::tracked(returns(ref))] +pub(crate) fn type_for_const_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: ConstId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = def.resolver(db); let data = ConstSignature::of(db, def); let parent = def.loc(db).container; @@ -1639,11 +1721,11 @@ pub(crate) fn type_for_static<'db>( } /// Build the declared type of a static. -#[salsa_macros::tracked(returns(ref))] -pub(crate) fn type_for_static_with_diagnostics( - db: &dyn HirDatabase, +#[salsa::tracked(returns(ref))] +pub(crate) fn type_for_static_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: StaticId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = def.resolver(db); let data = StaticSignature::of(db, def); let generics = OnceCell::new(); @@ -1673,9 +1755,10 @@ fn type_for_struct_constructor<'db>( FieldsShape::Unit => Some(type_for_adt(db, def.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); + let def = CallableDefId::StructId(def); Some(EarlyBinder::bind(Ty::new_fn_def( interner, - CallableDefId::StructId(def).into(), + def.into(), GenericArgs::identity_for_item(interner, def.into()), ))) } @@ -1693,10 +1776,11 @@ fn type_for_enum_variant_constructor<'db>( FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); + let def = CallableDefId::EnumVariantId(def); Some(EarlyBinder::bind(Ty::new_fn_def( interner, - CallableDefId::EnumVariantId(def).into(), - GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + def.into(), + GenericArgs::identity_for_item(interner, def.into()), ))) } } @@ -1717,10 +1801,10 @@ pub(crate) fn value_ty<'db>( } #[salsa::tracked(returns(ref), cycle_result = type_for_type_alias_with_diagnostics_cycle_result)] -pub(crate) fn type_for_type_alias_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_for_type_alias_with_diagnostics<'db>( + db: &'db dyn HirDatabase, t: TypeAliasId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let type_alias_data = TypeAliasSignature::of(db, t); let interner = DbInterner::new_no_crate(db); if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { @@ -1752,11 +1836,11 @@ pub(crate) fn type_for_type_alias_with_diagnostics( } } -pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( - db: &dyn HirDatabase, +pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _adt: TypeAliasId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { TyLoweringResult::empty(StoredEarlyBinder::bind( Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), )) @@ -1770,10 +1854,10 @@ pub(crate) fn impl_self_ty_query<'db>( } #[salsa::tracked(returns(ref), cycle_result = impl_self_ty_with_diagnostics_cycle_result)] -pub(crate) fn impl_self_ty_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn impl_self_ty_with_diagnostics<'db>( + db: &'db dyn HirDatabase, impl_id: ImplId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = impl_id.resolver(db); let generics = OnceCell::new(); let impl_data = ImplSignature::of(db, impl_id); @@ -1792,11 +1876,11 @@ pub(crate) fn impl_self_ty_with_diagnostics( TyLoweringResult::from_ctx(StoredEarlyBinder::bind(ty.store()), ctx) } -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _impl_id: ImplId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { TyLoweringResult::empty(StoredEarlyBinder::bind( Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), )) @@ -1818,10 +1902,10 @@ pub(crate) fn const_param_types( } #[salsa::tracked(returns(ref), cycle_result = const_param_types_with_diagnostics_cycle_result)] -pub(crate) fn const_param_types_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn const_param_types_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { let mut result = ArenaMap::new(); let (data, store) = GenericParams::with_store(db, def); let resolver = def.resolver(db); @@ -1846,11 +1930,11 @@ pub(crate) fn const_param_types_with_diagnostics( TyLoweringResult::from_ctx(result, ctx) } -fn const_param_types_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, +fn const_param_types_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { TyLoweringResult::empty(ArenaMap::default()) } @@ -1881,10 +1965,10 @@ impl FieldType { /// Build the type of all specific fields of a struct or enum variant. #[salsa::tracked(returns(ref))] -pub(crate) fn field_types_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn field_types_with_diagnostics<'db>( + db: &'db dyn HirDatabase, variant_id: VariantId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { let var_data = variant_id.fields(db); let fields = var_data.fields(); if fields.is_empty() { @@ -1952,9 +2036,7 @@ impl SupertraitsInfo { let resolver = trait_.resolver(db); let signature = TraitSignature::of(db, trait_); for pred in signature.generic_params.where_predicates() { - let (WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred - else { + let WherePredicate::TypeBound { lifetimes: _, target, bound } = pred else { continue; }; let (TypeBound::Path(bounded_trait, TraitBoundModifier::None) @@ -2070,9 +2152,7 @@ fn resolve_type_param_assoc_type_shorthand( for maybe_parent_generics in generics.iter_owners().rev() { ctx.set_owner(maybe_parent_generics); for pred in maybe_parent_generics.where_predicates() { - let (WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred - else { + let WherePredicate::TypeBound { lifetimes: _, target, bound } = pred else { continue; }; let (TypeBound::Path(bounded_trait_path, TraitBoundModifier::None) @@ -2213,10 +2293,10 @@ pub struct TypeAliasBounds { } #[salsa::tracked(returns(ref))] -pub(crate) fn type_alias_bounds_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_alias_bounds_with_diagnostics<'db>( + db: &'db dyn HirDatabase, type_alias: TypeAliasId, -) -> TyLoweringResult>> { +) -> TyLoweringResult<'db, TypeAliasBounds>> { let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = type_alias.resolver(db); let generics = OnceCell::new(); @@ -2300,17 +2380,17 @@ impl<'db> GenericPredicates { pub fn query_with_diagnostics( db: &'db dyn HirDatabase, def: GenericDefId, - ) -> TyLoweringResult { + ) -> TyLoweringResult<'db, GenericPredicates> { generic_predicates(db, def) } } /// A cycle can occur from malformed code. -fn generic_predicates_cycle_result( - db: &dyn HirDatabase, +fn generic_predicates_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericPredicates> { TyLoweringResult::empty(GenericPredicates::from_explicit_own_predicates( StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()), )) @@ -2450,10 +2530,10 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId /// Resolve the where clause(s) of an item with generics, /// with a given filter #[tracing::instrument(skip(db), ret)] -fn generic_predicates( - db: &dyn HirDatabase, +fn generic_predicates<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericPredicates> { let generics = generics(db, def); let store = generics.store(); let generics = &OnceCell::from(generics); @@ -2664,11 +2744,11 @@ pub(crate) fn generic_defaults(db: &dyn HirDatabase, def: GenericDefId) -> Gener /// Resolve the default type params from generics. /// /// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). -#[salsa_macros::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] -pub(crate) fn generic_defaults_with_diagnostics( - db: &dyn HirDatabase, +#[salsa::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] +pub(crate) fn generic_defaults_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericDefaults> { let generics = generics(db, def); if generics.has_no_params() { return TyLoweringResult::empty(GenericDefaults(ThinVec::new())); @@ -2729,11 +2809,11 @@ pub(crate) fn generic_defaults_with_diagnostics( } } -fn generic_defaults_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, +fn generic_defaults_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericDefaults> { TyLoweringResult::empty(GenericDefaults(ThinVec::new())) } @@ -2746,10 +2826,10 @@ pub(crate) fn callable_item_signature<'db>( } #[salsa::tracked(returns(ref))] -pub(crate) fn callable_item_signature_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn callable_item_signature_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: CallableDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { match def { CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), CallableDefId::StructId(s) => TyLoweringResult::empty(fn_sig_for_struct_constructor(db, s)), @@ -2759,10 +2839,10 @@ pub(crate) fn callable_item_signature_with_diagnostics( } } -fn fn_sig_for_fn( - db: &dyn HirDatabase, +fn fn_sig_for_fn<'db>( + db: &'db dyn HirDatabase, def: FunctionId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 27d52881c6471..77037c5b12d13 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -890,11 +890,11 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ) } - pub(super) fn assoc_type_bindings_from_type_bound<'c>( + pub(super) fn assoc_type_bindings_from_type_bound( mut self, trait_ref: TraitRef<'db>, span: Span, - ) -> Option, GenericPredicateSource)> + use<'a, 'b, 'c, 'db>> + ) -> Option, GenericPredicateSource)> + use<'a, 'b, 'db>> { let interner = self.ctx.interner; self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index c5868ab6b5271..e8702bf2c99de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -11,10 +11,11 @@ mod probe; use either::Either; use hir_expand::name::Name; +use salsa::Update; use span::Edition; use tracing::{debug, instrument}; -use base_db::Crate; +use base_db::{Crate, salsa::update_fallback_db}; use hir_def::{ AssocItemId, BlockIdLt, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId, ModuleId, TraitId, @@ -125,7 +126,7 @@ pub enum CandidateSource { Trait(TraitId), } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Performs method lookup. If lookup is successful, it will return the callee /// and store an appropriate adjustment for the self-expr. In some cases it may /// report an error (e.g., invoking the `drop` method). @@ -522,10 +523,10 @@ fn crates_containing_incoherent_inherent_impls(db: &dyn HirDatabase, krate: Crat krate.transitive_deps(db).into_iter().filter(|krate| krate.data(db).origin.is_lang()).collect() } -pub fn with_incoherent_inherent_impls( - db: &dyn HirDatabase, +pub fn with_incoherent_inherent_impls<'db>( + db: &'db dyn HirDatabase, krate: Crate, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, mut callback: impl FnMut(&[ImplId]), ) { let has_incoherent_impls = match self_ty.def() { @@ -547,7 +548,7 @@ pub fn with_incoherent_inherent_impls( } } -pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType) -> Option { +pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType<'_>) -> Option { match ty.def()? { SolverDefId::AdtId(id) => Some(id.module(db)), SolverDefId::TypeAliasId(id) => Some(id.module(db)), @@ -556,15 +557,16 @@ pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType) -> Opti } } -#[derive(Debug, PartialEq, Eq)] -pub struct InherentImpls { - map: FxHashMap>, +#[derive(Debug, PartialEq, Eq, Update)] +pub struct InherentImpls<'db> { + #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + map: FxHashMap, Box<[ImplId]>>, } #[salsa::tracked] -impl<'db> InherentImpls { +impl<'db> InherentImpls<'db> { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Self { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> InherentImpls<'db> { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -573,7 +575,10 @@ impl<'db> InherentImpls { } #[salsa::tracked(returns(ref))] - pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { + pub fn for_block( + db: &'db dyn HirDatabase, + block: BlockIdLt<'db>, + ) -> Option>> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -582,8 +587,8 @@ impl<'db> InherentImpls { } } -impl InherentImpls { - fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self { +impl<'db> InherentImpls<'db> { + fn collect_def_map(db: &'db dyn HirDatabase, def_map: &'db DefMap) -> Self { let mut map = FxHashMap::default(); collect(db, def_map, &mut map); let mut map = map @@ -593,10 +598,10 @@ impl InherentImpls { map.shrink_to_fit(); return Self { map }; - fn collect( - db: &dyn HirDatabase, + fn collect<'db>( + db: &'db dyn HirDatabase, def_map: &DefMap, - map: &mut FxHashMap>, + map: &mut FxHashMap, Vec>, ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.inherent_impls() { @@ -622,15 +627,15 @@ impl InherentImpls { } } - pub fn for_self_ty(&self, self_ty: &SimplifiedType) -> &[ImplId] { + pub fn for_self_ty(&self, self_ty: &SimplifiedType<'db>) -> &[ImplId] { self.map.get(self_ty).map(|it| &**it).unwrap_or_default() } - pub fn for_each_crate_and_block<'db>( + pub fn for_each_crate_and_block( db: &'db dyn HirDatabase, krate: Crate, block: Option>, - for_each: &mut dyn FnMut(&InherentImpls), + for_each: &mut dyn FnMut(&InherentImpls<'db>), ) { let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); @@ -638,20 +643,21 @@ impl InherentImpls { } } -#[derive(Debug, PartialEq)] -struct OneTraitImpls { - non_blanket_impls: FxHashMap, Box<[BuiltinDeriveImplId]>)>, +#[derive(Debug, PartialEq, Update)] +struct OneTraitImpls<'db> { + #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + non_blanket_impls: FxHashMap, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>, blanket_impls: Box<[ImplId]>, } #[derive(Default)] -struct OneTraitImplsBuilder { - non_blanket_impls: FxHashMap, Vec)>, +struct OneTraitImplsBuilder<'db> { + non_blanket_impls: FxHashMap, (Vec, Vec)>, blanket_impls: Vec, } -impl OneTraitImplsBuilder { - fn finish(self) -> OneTraitImpls { +impl<'db> OneTraitImplsBuilder<'db> { + fn finish(self) -> OneTraitImpls<'db> { let mut non_blanket_impls = self .non_blanket_impls .into_iter() @@ -665,15 +671,15 @@ impl OneTraitImplsBuilder { } } -#[derive(Debug, PartialEq)] -pub struct TraitImpls { - map: FxHashMap, +#[derive(Debug, PartialEq, Update)] +pub struct TraitImpls<'db> { + map: FxHashMap>, } #[salsa::tracked] -impl<'db> TraitImpls { +impl<'db> TraitImpls<'db> { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc> { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -682,7 +688,10 @@ impl<'db> TraitImpls { } #[salsa::tracked(returns(as_deref))] - pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { + pub fn for_block( + db: &'db dyn HirDatabase, + block: BlockIdLt<'db>, + ) -> Option>> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -696,8 +705,8 @@ impl<'db> TraitImpls { } } -impl TraitImpls { - fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self { +impl<'db> TraitImpls<'db> { + fn collect_def_map(db: &'db dyn HirDatabase, def_map: &DefMap) -> Self { let lang_items = hir_def::lang_item::lang_items(db, def_map.krate()); let mut map = FxHashMap::default(); collect(db, def_map, lang_items, &mut map); @@ -708,11 +717,11 @@ impl TraitImpls { map.shrink_to_fit(); return Self { map }; - fn collect( - db: &dyn HirDatabase, + fn collect<'db>( + db: &'db dyn HirDatabase, def_map: &DefMap, lang_items: &LangItems, - map: &mut FxHashMap, + map: &mut FxHashMap>, ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.trait_impls() { @@ -779,7 +788,7 @@ impl TraitImpls { pub fn has_impls_for_trait_and_self_ty( &self, trait_: TraitId, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, ) -> bool { self.map.get(&trait_).is_some_and(|trait_impls| { trait_impls.non_blanket_impls.contains_key(self_ty) @@ -788,10 +797,10 @@ impl TraitImpls { } pub fn for_trait_and_self_ty( - &self, + &'db self, trait_: TraitId, - self_ty: &SimplifiedType, - ) -> (&[ImplId], &[BuiltinDeriveImplId]) { + self_ty: &SimplifiedType<'db>, + ) -> (&'db [ImplId], &'db [BuiltinDeriveImplId]) { self.map .get(&trait_) .and_then(|map| map.non_blanket_impls.get(self_ty)) @@ -815,7 +824,7 @@ impl TraitImpls { pub fn for_self_ty( &self, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), ) { for for_trait in self.map.values() { @@ -826,11 +835,11 @@ impl TraitImpls { } } - pub fn for_each_crate_and_block<'db>( + pub fn for_each_crate_and_block( db: &'db dyn HirDatabase, krate: Crate, block: Option>, - for_each: &mut dyn FnMut(&TraitImpls), + for_each: &mut dyn FnMut(&TraitImpls<'db>), ) { let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block)).for_each(&mut *for_each); @@ -838,12 +847,12 @@ impl TraitImpls { } /// Like [`Self::for_each_crate_and_block()`], but takes in account two blocks, one for a trait and one for a self type. - pub fn for_each_crate_and_block_trait_and_type<'db>( + pub fn for_each_crate_and_block_trait_and_type( db: &'db dyn HirDatabase, krate: Crate, type_block: Option>, trait_block: Option>, - for_each: &mut dyn FnMut(&TraitImpls), + for_each: &mut dyn FnMut(&TraitImpls<'db>), ) { let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate); in_self_and_deps.iter().for_each(|impls| for_each(impls)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs index d960a6547d462..6d948464b1c03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs @@ -36,8 +36,8 @@ use crate::{ }, }; -struct ConfirmContext<'a, 'b, 'db> { - ctx: &'a mut InferenceContext<'b, 'db>, +struct ConfirmContext<'a, 'db> { + ctx: &'a mut InferenceContext<'db>, candidate: FunctionId, call_expr: ExprId, } @@ -49,7 +49,7 @@ pub(crate) struct ConfirmResult<'db> { pub(crate) adjustments: Box<[Adjustment]>, } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn confirm_method( &mut self, pick: &probe::Pick<'db>, @@ -70,12 +70,12 @@ impl<'a, 'db> InferenceContext<'a, 'db> { } } -impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { +impl<'a, 'db> ConfirmContext<'a, 'db> { fn new( - ctx: &'a mut InferenceContext<'b, 'db>, + ctx: &'a mut InferenceContext<'db>, candidate: FunctionId, call_expr: ExprId, - ) -> ConfirmContext<'a, 'b, 'db> { + ) -> ConfirmContext<'a, 'db> { ConfirmContext { ctx, candidate, call_expr } } @@ -312,7 +312,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { fn extract_existential_trait_ref(&self, self_ty: Ty<'db>, mut closure: F) -> R where - F: FnMut(&ConfirmContext<'a, 'b, 'db>, Ty<'db>, PolyExistentialTraitRef<'db>) -> R, + F: FnMut(&ConfirmContext<'a, 'db>, Ty<'db>, PolyExistentialTraitRef<'db>) -> R, { // If we specified that this is an object method, then the // self-type ought to be something that can be dereferenced to @@ -348,13 +348,13 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { generic_args: Option<&HirGenericArgs>, parent_args: GenericArgs<'db>, ) -> GenericArgs<'db> { - struct LowererCtx<'a, 'b, 'db> { - ctx: &'a mut InferenceContext<'b, 'db>, + struct LowererCtx<'a, 'db> { + ctx: &'a mut InferenceContext<'db>, expr: ExprId, parent_args: &'a [GenericArg<'db>], } - impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, 'db> { + impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, 'db> { fn report_len_mismatch( &mut self, def: GenericDefId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs index 3be9afdf45437..0a47e031b720f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs @@ -993,7 +993,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { fn assemble_inherent_impl_candidates_for_type( &mut self, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, receiver_steps: usize, ) { let Some(module) = simplified_type_module(self.db(), self_ty) else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 2fa3f5e797b5e..fe4b383fbe672 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -15,6 +15,7 @@ use rustc_type_ir::{ CollectAndApply, GenericTypeVisitable, inherent::{GenericArgs as _, IntoKind, Ty as _}, }; +use salsa::Update; use smallvec::{SmallVec, smallvec}; use stdx::impl_from; @@ -318,7 +319,12 @@ impl<'db> PlaceRef<'db> { pub fn store(&self) -> Place { Place { local: self.local, projection: self.projection.store() } } - pub fn ty(&self, body: &MirBody, infcx: &InferCtxt<'db>, env: ParamEnv<'db>) -> PlaceTy<'db> { + pub fn ty( + &self, + body: &MirBody<'db>, + infcx: &InferCtxt<'db>, + env: ParamEnv<'db>, + ) -> PlaceTy<'db> { PlaceTy::from_ty(body.locals[self.local].ty.as_ref()).multi_projection_ty( infcx, env, @@ -988,16 +994,6 @@ pub enum Rvalue { /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. Aggregate(AggregateKind, Box<[Operand]>), - /// Transmutes a `*mut u8` into shallow-initialized `Box`. - /// - /// This is different from a normal transmute because dataflow analysis will treat the box as - /// initialized but its content as uninitialized. Like other pointer casts, this in general - /// affects alias analysis. - ShallowInitBox(Operand, StoredTy), - - /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer. - ShallowInitBoxWithAlloc(StoredTy), - /// A CopyForDeref is equivalent to a read from a place at the /// codegen level, but is treated specially by drop elaboration. When such a read happens, it /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) @@ -1059,21 +1055,21 @@ pub struct BasicBlock { pub is_cleanup: bool, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MirBody { +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub struct MirBody<'db> { pub basic_blocks: Arena, pub locals: Arena, pub start_block: BasicBlockId, - pub owner: InferBodyId, + pub owner: InferBodyId<'db>, pub binding_locals: ArenaMap, pub upvar_locals: FxHashMap>, pub param_locals: Vec, /// This field stores the closures directly owned by this body. It is used /// in traversing every mir body. - pub closures: Vec, + pub closures: Vec>, } -impl MirBody { +impl MirBody<'_> { pub fn local_to_binding_map(&self) -> ArenaMap { self.binding_locals.iter().map(|(it, y)| (*y, it)).collect() } @@ -1095,9 +1091,7 @@ impl MirBody { StatementKind::Assign(p, r) => { f(p); match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, &mut f), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index a9271675a0745..e860ae8d3e01f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -9,6 +9,7 @@ use either::Either; use hir_def::HasModule; use la_arena::ArenaMap; use rustc_hash::FxHashMap; +use salsa::Update; use stdx::never; use crate::{ @@ -56,17 +57,17 @@ pub struct BorrowRegion { pub places: Vec, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BorrowckResult { - owner: Either, +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub struct BorrowckResult<'db> { + owner: Either, InternedClosureId<'db>>, pub mutability_of_locals: ArenaMap, pub moved_out_of_ref: Vec, pub partially_moved: Vec, pub borrow_regions: Vec, } -impl BorrowckResult { - pub fn mir_body<'db>(&self, db: &'db dyn HirDatabase) -> &'db MirBody { +impl<'db> BorrowckResult<'db> { + pub fn mir_body(&self, db: &'db dyn HirDatabase) -> &'db MirBody<'db> { match self.owner { Either::Left(it) => db.mir_body(it).unwrap(), Either::Right(it) => db.mir_body_for_closure(it).unwrap(), @@ -76,23 +77,29 @@ impl BorrowckResult { fn all_mir_bodies<'db>( db: &'db dyn HirDatabase, - def: InferBodyId, - mut cb: impl FnMut(&'db MirBody, Either) -> BorrowckResult, + def: InferBodyId<'db>, + mut cb: impl FnMut( + &'db MirBody<'db>, + Either, InternedClosureId<'db>>, + ) -> BorrowckResult<'db>, mut merge_from_closures: impl FnMut( - (&mut BorrowckResult, &'db MirBody), - (&BorrowckResult, &'db MirBody), + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), ), -) -> Result, MirLowerError> { +) -> Result]>, MirLowerError<'db>> { fn for_closure<'db>( db: &'db dyn HirDatabase, - c: InternedClosureId, - results: &mut Vec<(BorrowckResult, &'db MirBody)>, - cb: &mut impl FnMut(&'db MirBody, Either) -> BorrowckResult, + c: InternedClosureId<'db>, + results: &mut Vec<(BorrowckResult<'db>, &'db MirBody<'db>)>, + cb: &mut impl FnMut( + &'db MirBody<'db>, + Either, InternedClosureId<'db>>, + ) -> BorrowckResult<'db>, merge_from_closures: &mut impl FnMut( - (&mut BorrowckResult, &'db MirBody), - (&BorrowckResult, &'db MirBody), + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), ), - ) -> Result<(), MirLowerError> { + ) -> Result<(), MirLowerError<'db>> { match db.mir_body_for_closure(c) { Ok(body) => { let parent_index = results.len(); @@ -108,8 +115,11 @@ fn all_mir_bodies<'db>( } fn merge<'db>( - results: &mut [(BorrowckResult, &'db MirBody)], - merge: &mut impl FnMut((&mut BorrowckResult, &'db MirBody), (&BorrowckResult, &'db MirBody)), + results: &mut [(BorrowckResult<'db>, &'db MirBody<'db>)], + merge: &mut impl FnMut( + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), + ), parent_index: usize, ) { let (parent_and_before, children) = results.split_at_mut(parent_index + 1); @@ -133,15 +143,18 @@ fn all_mir_bodies<'db>( } } -impl InferBodyId { - pub fn borrowck(self, db: &dyn HirDatabase) -> Result<&[BorrowckResult], MirLowerError> { +impl<'db> InferBodyId<'db> { + pub fn borrowck( + self, + db: &'db dyn HirDatabase, + ) -> Result<&'db [BorrowckResult<'db>], MirLowerError<'db>> { return borrowck_query(db, self).map_err(|e| e.clone()); #[salsa::tracked(returns(as_deref), lru = 2024)] - fn borrowck_query( - db: &dyn HirDatabase, - def: InferBodyId, - ) -> Result, MirLowerError> { + fn borrowck_query<'db>( + db: &'db dyn HirDatabase, + def: InferBodyId<'db>, + ) -> Result]>, MirLowerError<'db>> { let _p = tracing::info_span!("InferBodyId::borrowck").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); @@ -198,7 +211,7 @@ impl InferBodyId { fn moved_out_of_ref<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> Vec { let db = infcx.interner.db; let mut result = vec![]; @@ -226,9 +239,7 @@ fn moved_out_of_ref<'db>( for statement in &block.statements { match &statement.kind { StatementKind::Assign(_, r) => match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, statement.span), @@ -293,7 +304,7 @@ fn moved_out_of_ref<'db>( fn partially_moved<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> Vec { let db = infcx.interner.db; let mut result = vec![]; @@ -311,9 +322,7 @@ fn partially_moved<'db>( for statement in &block.statements { match &statement.kind { StatementKind::Assign(_, r) => match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, statement.span), @@ -375,7 +384,7 @@ fn partially_moved<'db>( result } -fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec { +fn borrow_regions<'db>(db: &'db dyn HirDatabase, body: &MirBody<'db>) -> Vec { let mut borrows = FxHashMap::default(); for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -428,7 +437,7 @@ enum ProjectionCase { fn place_case<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, lvalue: &Place, ) -> ProjectionCase { let mut is_part_of = false; @@ -455,13 +464,13 @@ fn place_case<'db>( /// `Uninit` and `drop` and similar after initialization. fn ever_initialized_map( db: &dyn HirDatabase, - body: &MirBody, + body: &MirBody<'_>, ) -> ArenaMap> { let mut result: ArenaMap> = body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect(); fn dfs( db: &dyn HirDatabase, - body: &MirBody, + body: &MirBody<'_>, l: LocalId, stack: &mut Vec, result: &mut ArenaMap>, @@ -574,7 +583,7 @@ fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> ArenaMap { let db = infcx.interner.db; let mut result: ArenaMap = @@ -623,7 +632,6 @@ fn mutability_of_locals<'db>( record_usage_for_operand(arg, &mut result); } } - Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (), Rvalue::ThreadLocalRef(n) | Rvalue::AddressOf(n) | Rvalue::BinaryOp(n) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index b968f33e81d0d..e968da5111add 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; -use base_db::{Crate, target::TargetLoadError}; +use base_db::{Crate, salsa::update_fallback_db, target::TargetLoadError}; use either::Either; use hir_def::{ AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, @@ -31,6 +31,7 @@ use rustc_type_ir::{ AliasTyKind, inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _}, }; +use salsa::Update; use span::FileId; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; @@ -155,16 +156,16 @@ impl TlsData { } } -struct StackFrame<'a> { - locals: Locals<'a>, +struct StackFrame<'a, 'db> { + locals: Locals<'a, 'db>, destination: Option, prev_stack_ptr: usize, - span: (MirSpan, InferBodyId), + span: (MirSpan, InferBodyId<'db>), } #[derive(Clone)] -enum MirOrDynIndex<'a> { - Mir(&'a MirBody), +enum MirOrDynIndex<'db> { + Mir(&'db MirBody<'db>), Dyn(usize), } @@ -174,7 +175,7 @@ pub struct Evaluator<'a, 'db> { target_data_layout: &'db TargetDataLayout, stack: Vec, heap: Vec, - code_stack: Vec>, + code_stack: Vec>, /// Stores the global location of the statics. We const evaluate every static first time we need it /// and see it's missing, then we add it to this to reuse. static_locations: FxHashMap, @@ -189,11 +190,11 @@ pub struct Evaluator<'a, 'db> { layout_cache: RefCell, Arc>>, projected_ty_cache: RefCell, PlaceElem), PlaceTy<'db>>>, not_special_fn_cache: RefCell>, - mir_or_dyn_index_cache: RefCell), MirOrDynIndex<'a>>>, + mir_or_dyn_index_cache: RefCell), MirOrDynIndex<'db>>>, /// Constantly dropping and creating `Locals` is very costly. We store /// old locals that we normally want to drop here, to reuse their allocations /// later. - unused_locals_store: RefCell>>>, + unused_locals_store: RefCell, Vec>>>, cached_ptr_size: usize, cached_fn_trait_func: Option, cached_fn_mut_trait_func: Option, @@ -236,11 +237,11 @@ impl Interval { Self { addr, size } } - fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { + fn get<'b, 'a, 'db>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { memory.read_memory(self.addr, self.size) } - fn write_from_bytes<'a, 'db: 'a>( + fn write_from_bytes<'a, 'db>( &self, memory: &mut Evaluator<'a, 'db>, bytes: &[u8], @@ -248,7 +249,7 @@ impl Interval { memory.write_memory(self.addr, bytes) } - fn write_from_interval<'a, 'db: 'a>( + fn write_from_interval<'a, 'db>( &self, memory: &mut Evaluator<'a, 'db>, interval: Interval, @@ -262,10 +263,7 @@ impl Interval { } impl<'db> IntervalAndTy<'db> { - fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> - where - 'db: 'a, - { + fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { memory.read_memory(self.interval.addr, self.interval.size) } @@ -273,11 +271,8 @@ impl<'db> IntervalAndTy<'db> { addr: Address, ty: Ty<'db>, evaluator: &Evaluator<'a, 'db>, - locals: &Locals<'a>, - ) -> Result<'db, IntervalAndTy<'db>> - where - 'db: 'a, - { + locals: &Locals<'a, 'db>, + ) -> Result<'db, IntervalAndTy<'db>> { let size = evaluator.size_of_sized(ty, locals, "type of interval")?; Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) } @@ -295,7 +290,7 @@ impl From for IntervalOrOwned { } impl IntervalOrOwned { - fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { + fn get<'b, 'a, 'db>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { Ok(match self { IntervalOrOwned::Owned(o) => o, IntervalOrOwned::Borrowed(b) => b.get(memory)?, @@ -354,9 +349,9 @@ impl Address { } } -#[derive(Clone, PartialEq, Eq)] -pub enum MirEvalError { - ConstEvalError(String, Box), +#[derive(Clone, PartialEq, Eq, Update)] +pub enum MirEvalError<'db> { + ConstEvalError(String, Box>), LayoutError(LayoutError, StoredTy), TargetDataLayoutNotAvailable(TargetLoadError), /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected @@ -364,14 +359,15 @@ pub enum MirEvalError { UndefinedBehavior(String), Panic(String), // FIXME: This should be folded into ConstEvalError? - MirLowerError(FunctionId, MirLowerError), - MirLowerErrorForClosure(InternedClosureId, MirLowerError), + MirLowerError(FunctionId, MirLowerError<'db>), + MirLowerErrorForClosure(InternedClosureId<'db>, MirLowerError<'db>), TypeIsUnsized(StoredTy, &'static str), NotSupported(String), InvalidConst, InFunction( - Box, - Vec<(Either, MirSpan, InferBodyId)>, + Box>, + #[update(bounds(InternedClosureId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + Vec<(Either>, MirSpan, InferBodyId<'db>)>, ), ExecutionLimitExceeded, StackOverflow, @@ -383,7 +379,7 @@ pub enum MirEvalError { InternalError(Box), } -impl MirEvalError { +impl MirEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -420,18 +416,18 @@ impl MirEvalError { (store, None) } }; - let span: InFile = match span { - MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + let span: InFile = match *span { + MirSpan::ExprId(e) => match source_map.expr_syntax(e) { Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, - MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + MirSpan::PatId(p) => match source_map.pat_syntax(p) { Ok(s) => s.map(|it| it.syntax_node_ptr()), Err(_) => continue, }, MirSpan::BindingId(b) => { match source_map - .patterns_for_binding(*b) + .patterns_for_binding(b) .iter() .find_map(|p| source_map.pat_syntax(*p).ok()) { @@ -525,7 +521,7 @@ impl MirEvalError { } } -impl std::fmt::Debug for MirEvalError { +impl std::fmt::Debug for MirEvalError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ConstEvalError(arg0, arg1) => { @@ -564,7 +560,7 @@ impl std::fmt::Debug for MirEvalError { } } -type Result<'db, T> = std::result::Result; +type Result<'db, T> = std::result::Result>; #[derive(Debug, Default)] struct DropFlags<'db> { @@ -595,9 +591,9 @@ impl<'db> DropFlags<'db> { } #[derive(Debug)] -struct Locals<'a> { +struct Locals<'a, 'db> { ptr: ArenaMap, - body: &'a MirBody, + body: &'db MirBody<'db>, drop_flags: DropFlags<'a>, } @@ -615,9 +611,9 @@ impl MirOutput { } } -pub fn interpret_mir<'a, 'db: 'a>( +pub fn interpret_mir<'db>( db: &'db dyn HirDatabase, - body: &MirBody, + body: &'db MirBody<'db>, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has @@ -657,10 +653,10 @@ const EXECUTION_LIMIT: usize = 100_000; #[cfg(not(test))] const EXECUTION_LIMIT: usize = 10_000_000; -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { pub fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, assert_placeholder_ty_is_unused: bool, trait_env: Option>, ) -> Result<'db, Evaluator<'a, 'db>> { @@ -718,11 +714,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.infcx.interner.lang_items() } - fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> { + fn place_addr(&self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Address> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) } - fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> { + fn place_interval(&self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Interval> { let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; Ok(Interval { addr: place_addr_and_ty.0, @@ -738,7 +734,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.cached_ptr_size } - fn caller_location_fields(&self, owner: InferBodyId, span: MirSpan) -> (String, u32, u32) { + fn caller_location_fields(&self, owner: InferBodyId<'db>, span: MirSpan) -> (String, u32, u32) { let Some((file_id, text_range)) = self.resolve_mir_span(owner, span) else { return (String::new(), 0, 0); }; @@ -749,7 +745,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { (path.unwrap_or_default(), line + 1, col + 1) } - fn resolve_mir_span(&self, owner: InferBodyId, span: MirSpan) -> Option<(FileId, TextRange)> { + fn resolve_mir_span( + &self, + owner: InferBodyId<'db>, + span: MirSpan, + ) -> Option<(FileId, TextRange)> { let (source_map, self_param_syntax) = match owner { InferBodyId::DefWithBodyId(def) => { let body = &Body::with_source_map(self.db, def).1; @@ -788,7 +788,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn place_addr_and_ty_and_metadata<'b>( &'b self, p: &Place, - locals: &'b Locals<'a>, + locals: &'b Locals<'a, 'db>, ) -> Result<'db, (Address, Ty<'db>, Option)> { let mut addr = locals.ptr[p.local].addr; let mut ty = PlaceTy::from_ty(locals.body.locals[p.local].ty.as_ref()); @@ -909,11 +909,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.layout(Ty::new_adt(self.interner(), adt, subst)) } - fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> { + fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a, 'db>) -> Result<'db, Ty<'db>> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> { + fn operand_ty(&self, o: &Operand, locals: &Locals<'a, 'db>) -> Result<'db, Ty<'db>> { Ok(match &o.kind { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant { konst: _, ty } => ty.as_ref(), @@ -934,7 +934,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn operand_ty_and_eval( &mut self, o: &Operand, - locals: &mut Locals<'a>, + locals: &mut Locals<'a, 'db>, ) -> Result<'db, IntervalAndTy<'db>> { Ok(IntervalAndTy { interval: self.eval_operand(o, locals)?, @@ -944,7 +944,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn interpret_mir( &mut self, - body: &'a MirBody, + body: &'db MirBody<'db>, args: impl Iterator, ) -> Result<'db, Interval> { if let Some(it) = self.stack_depth_limit.checked_sub(1) { @@ -1106,8 +1106,8 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn fill_locals_for_body( &mut self, - body: &MirBody, - locals: &mut Locals<'a>, + body: &'db MirBody<'db>, + locals: &mut Locals<'a, 'db>, args: impl Iterator, ) -> Result<'db, ()> { let mut remain_args = body.param_locals.len(); @@ -1130,9 +1130,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn create_locals_for_body( &mut self, - body: &'a MirBody, + body: &'db MirBody<'db>, destination: Option, - ) -> Result<'db, (Locals<'a>, usize)> { + ) -> Result<'db, (Locals<'a, 'db>, usize)> { let mut locals = match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() { None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() }, @@ -1175,7 +1175,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok((locals, prev_stack_pointer)) } - fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> { + fn eval_rvalue( + &mut self, + r: &Rvalue, + locals: &mut Locals<'a, 'db>, + ) -> Result<'db, IntervalOrOwned> { use IntervalOrOwned::*; Ok(match r { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), @@ -1475,14 +1479,6 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let size = len * val.len(); Owned(val.iter().copied().cycle().take(size).collect()) } - Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"), - Rvalue::ShallowInitBoxWithAlloc(ty) => { - let Some((size, align)) = self.size_align_of(ty.as_ref(), locals)? else { - not_supported!("unsized box initialization"); - }; - let addr = self.heap_allocate(size, align)?; - Owned(addr.to_bytes().to_vec()) - } Rvalue::CopyForDeref(_) => not_supported!("copy for deref"), Rvalue::Aggregate(kind, values) => { let values = values @@ -1840,7 +1836,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &mut self, it: VariantId, subst: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, (usize, Arc, Option<(usize, usize, i128)>)> { let adt = it.adt_id(self.db); if let Some(f) = locals.body.owner.as_variant() @@ -1933,7 +1929,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok(result) } - fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> { + fn eval_operand( + &mut self, + it: &Operand, + locals: &mut Locals<'a, 'db>, + ) -> Result<'db, Interval> { Ok(match &it.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p.as_ref()); @@ -2096,7 +2096,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { #[allow(clippy::double_parens)] fn allocate_const_in_heap( &mut self, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, konst: Const<'db>, ) -> Result<'db, Interval> { match konst.kind() { @@ -2138,7 +2138,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn allocate_allocation_in_heap( &mut self, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, allocation: Allocation<'db>, ) -> Result<'db, Interval> { let AllocationData { ty, memory: ref v, ref memory_map } = *allocation; @@ -2177,7 +2177,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok(Interval::new(addr, size)) } - fn eval_place(&mut self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> { + fn eval_place(&mut self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Interval> { let addr = self.place_addr(p, locals)?; Ok(Interval::new( addr, @@ -2280,7 +2280,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_align_of( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, Option<(usize, usize)>> { if let Some(layout) = self.layout_cache.borrow().get(&ty) { return Ok(layout @@ -2310,7 +2310,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_of_sized( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, what: &'static str, ) -> Result<'db, usize> { match self.size_align_of(ty, locals)? { @@ -2324,7 +2324,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_align_of_sized( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, what: &'static str, ) -> Result<'db, (usize, usize)> { match self.size_align_of(ty, locals)? { @@ -2365,13 +2365,13 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &self, bytes: &[u8], ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, ComplexMemoryMap<'db>> { - fn rec<'a, 'db: 'a>( + fn rec<'a, 'db>( this: &Evaluator<'a, 'db>, bytes: &[u8], ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, mm: &mut ComplexMemoryMap<'db>, stack_depth_limit: usize, ) -> Result<'db, ()> { @@ -2546,7 +2546,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy, addr: Address, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, ()> { // FIXME: support indirect references let layout = self.layout(ty)?; @@ -2678,10 +2678,10 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { bytes: Interval, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let id = from_bytes!(usize, bytes.get(self)?); let next_ty = self.vtable_map.ty(id)?; use rustc_type_ir::TyKind; @@ -2704,14 +2704,14 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn exec_closure( &mut self, - closure: InternedClosureId, + closure: InternedClosureId<'db>, closure_data: Interval, generic_args: GenericArgs<'db>, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let mir_body = self .db .monomorphized_mir_body_for_closure( @@ -2747,10 +2747,10 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { generic_args: GenericArgs<'db>, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { match def { CallableDefId::FunctionId(def) => { if self.detect_fn_trait(def).is_some() { @@ -2805,9 +2805,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &self, def: FunctionId, generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, - ) -> Result<'db, MirOrDynIndex<'a>> { + ) -> Result<'db, MirOrDynIndex<'db>> { let pair = (def, generic_args); if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) { return Ok(r.clone()); @@ -2847,11 +2847,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { mut def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { if self.detect_and_exec_special_function( def, args, @@ -2913,20 +2913,20 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn exec_looked_up_function( &mut self, - mir_body: &'a MirBody, - locals: &Locals<'a>, + mir_body: &'db MirBody<'db>, + locals: &Locals<'a, 'db>, def: FunctionId, arg_bytes: impl Iterator, span: MirSpan, destination: Interval, target_bb: Option, - ) -> Result<'db, Option>> { - Ok(if let Some(target_bb) = target_bb { + ) -> Result<'db, Option>> { + if let Some(target_bb) = target_bb { let (mut locals, prev_stack_ptr) = self.create_locals_for_body(mir_body, Some(destination))?; self.fill_locals_for_body(mir_body, &mut locals, arg_bytes.into_iter())?; let span = (span, locals.body.owner); - Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span }) + Ok(Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span })) } else { let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| { MirEvalError::InFunction( @@ -2935,8 +2935,8 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ) })?; destination.write_from_interval(self, result)?; - None - }) + Ok(None) + } } fn exec_fn_trait( @@ -2944,11 +2944,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let func = args .first() .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?; @@ -3013,7 +3013,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { } } - fn eval_static(&mut self, st: StaticId, locals: &Locals<'a>) -> Result<'db, Address> { + fn eval_static(&mut self, st: StaticId, locals: &Locals<'a, 'db>) -> Result<'db, Address> { if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; @@ -3063,7 +3063,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn drop_place( &mut self, place: &Place, - locals: &mut Locals<'a>, + locals: &mut Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, ()> { let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; @@ -3080,7 +3080,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn run_drop_glue_deep( &mut self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, addr: Address, metadata: &[u8], span: MirSpan, @@ -3199,7 +3199,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { pub fn render_const_using_debug_impl<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, c: Allocation<'db>, ty: Ty<'db>, ) -> Result<'db, String> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index d2a74f20a5626..e569b32bd779f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -28,13 +28,13 @@ enum EvalLangItem { DropInPlace, } -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { pub(super) fn detect_and_exec_special_function( &mut self, def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, bool> { @@ -133,7 +133,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { def: FunctionId, args: &[IntervalAndTy<'db>], self_ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -191,7 +191,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { layout: Arc, addr: Address, def: FunctionId, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -297,7 +297,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { it: EvalLangItem, generic_args: GenericArgs<'db>, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, Vec> { use EvalLangItem::*; @@ -369,7 +369,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { id: i64, args: &[IntervalAndTy<'db>], destination: Interval, - _locals: &Locals<'a>, + _locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { match id { @@ -400,7 +400,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], _generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, ()> { match as_str { @@ -564,7 +564,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, needs_override: bool, ) -> Result<'db, bool> { @@ -733,9 +733,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } - // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89 - // (https://github.com/rust-lang/rust/pull/142410) - "min_align_of" | "align_of" => { + "align_of" => { let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of generic arg is not provided".into(), @@ -763,9 +761,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { destination.write_from_bytes(self, &size.to_le_bytes()) } } - // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89 - // (https://github.com/rust-lang/rust/pull/142410) - "min_align_of_val" | "align_of_val" => { + "align_of_val" => { let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of_val generic arg is not provided".into(), @@ -1415,6 +1411,15 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.write_memory(location_addr, &location)?; destination.write_from_bytes(self, &location_addr.to_bytes()[..ptr_size]) } + "box_new" => { + let ty = generic_args.type_at(0); + let Some((size, align)) = self.size_align_of(ty, locals)? else { + not_supported!("unsized box initialization"); + }; + let addr = self.heap_allocate(size, align)?; + self.copy_from_interval(addr, args[0].interval)?; + destination.write_from_bytes(self, &addr.to_bytes()[..self.ptr_size()]) + } _ if needs_override => not_supported!("intrinsic {name} is not implemented"), _ => return Ok(false), } @@ -1425,7 +1430,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &mut self, ty: Ty<'db>, metadata: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, (usize, usize)> { Ok(match ty.kind() { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), @@ -1485,7 +1490,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { // We are a single threaded runtime with no UB checking and no optimization, so diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index a9d0bee623254..ff16ea68704d6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -6,7 +6,7 @@ use crate::consteval::try_const_usize; use super::*; -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> { match ty.kind() { TyKind::Adt(adt_def, subst) => { @@ -54,7 +54,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], _generic_args: GenericArgs<'db>, destination: Interval, - _locals: &Locals<'a>, + _locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { match name { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 622519445c69b..68d19769d4811 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -15,7 +15,7 @@ use crate::{ use super::{MirEvalError, interpret_mir}; -fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError> { +fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); @@ -123,7 +123,7 @@ fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: fn check_error_with( #[rust_analyzer::rust_fixture] ra_fixture: &str, - expect_err: impl FnOnce(MirEvalError) -> bool, + expect_err: impl FnOnce(MirEvalError<'_>) -> bool, ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); crate::attach_db(&db, || { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 8cc59ecd0c1eb..1c7e5c2f51396 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -23,6 +23,7 @@ use la_arena::{ArenaMap, RawIdx}; use rustc_apfloat::Float; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; +use salsa::Update; use span::{Edition, FileId}; use syntax::TextRange; @@ -80,15 +81,15 @@ struct DropScope { } struct MirLowerCtx<'a, 'db> { - result: MirBody, - owner: InferBodyId, + result: MirBody<'db>, + owner: InferBodyId<'db>, store_owner: ExpressionStoreOwnerId, current_loop_blocks: Option, labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'db dyn HirDatabase, store: &'a ExpressionStore, - infer: &'a InferenceResult, + infer: &'a InferenceResult<'db>, types: &'db crate::next_solver::DefaultAny<'db>, resolver: Resolver<'db>, drop_scopes: Vec, @@ -97,9 +98,9 @@ struct MirLowerCtx<'a, 'db> { } // FIXME: Make this smaller, its stored in database queries -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum MirLowerError { - ConstEvalError(Box, Box), +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub enum MirLowerError<'db> { + ConstEvalError(Box, Box>), LayoutError(LayoutError), IncompleteExpr, IncompletePattern, @@ -110,7 +111,7 @@ pub enum MirLowerError { UnresolvedMethod(String), UnresolvedField, UnsizedTemporary(StoredTy), - MissingFunctionDefinition(InferBodyId, ExprId), + MissingFunctionDefinition(InferBodyId<'db>, ExprId), HasErrors, /// This should never happen. Type mismatch should catch everything. TypeError(&'static str), @@ -168,7 +169,7 @@ impl Drop for DropScopeToken { // } // } -impl MirLowerError { +impl MirLowerError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -265,13 +266,13 @@ macro_rules! implementation_error { }}; } -impl From for MirLowerError { +impl From for MirLowerError<'_> { fn from(value: LayoutError) -> Self { MirLowerError::LayoutError(value) } } -impl MirLowerError { +impl MirLowerError<'_> { fn unresolved_path( db: &dyn HirDatabase, p: &Path, @@ -285,14 +286,14 @@ impl MirLowerError { } } -type Result<'db, T> = std::result::Result; +type Result<'db, T> = std::result::Result>; impl<'a, 'db> MirLowerCtx<'a, 'db> { fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &'a ExpressionStore, - infer: &'a InferenceResult, + infer: &'a InferenceResult<'db>, ) -> Self { let mut basic_blocks = Arena::new(); let start_block = basic_blocks.alloc(BasicBlock { @@ -998,22 +999,6 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into()); Ok(Some(current)) } - Expr::Box { expr } => { - let ty = self.expr_ty_after_adjustments(*expr); - self.push_assignment( - current, - place, - Rvalue::ShallowInitBoxWithAlloc(ty.store()), - expr_id.into(), - ); - let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? - else { - return Ok(None); - }; - let p = place.project(ProjectionElem::Deref); - self.push_assignment(current, p, operand.into(), expr_id.into()); - Ok(Some(current)) - } Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { @@ -1253,7 +1238,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let span = |sources: &[CaptureSourceStack]| match sources .first() - .map(|it| it.final_source()) + .map(|it| it.final_source().unpack()) { Some(ExprOrPatId::ExprId(it)) => it.into(), Some(ExprOrPatId::PatId(it)) => it.into(), @@ -1525,7 +1510,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_const( &mut self, - const_id: GeneralConstId, + const_id: GeneralConstId<'db>, prev_block: BasicBlockId, place: PlaceRef<'db>, subst: GenericArgs<'db>, @@ -1539,7 +1524,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_const_to_operand( &mut self, subst: GenericArgs<'db>, - const_id: GeneralConstId, + const_id: GeneralConstId<'db>, ) -> Result<'db, Operand> { let konst = Const::new_unevaluated( self.interner(), @@ -2123,11 +2108,11 @@ fn cast_kind<'db>( }) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)] +#[salsa::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)] pub fn mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, - closure: InternedClosureId, -) -> Result<'db, MirBody> { + closure: InternedClosureId<'db>, +) -> Result<'db, MirBody<'db>> { let InternedClosure { owner: body_owner, expr, .. } = closure.loc(db); let store = ExpressionStore::of(db, body_owner.expression_store_owner(db)); let infer = InferenceResult::of(db, body_owner); @@ -2282,8 +2267,11 @@ pub fn mir_body_for_closure_query<'db>( Ok(ctx.result) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)] -pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result<'db, MirBody> { +#[salsa::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)] +pub fn mir_body_query<'db>( + db: &'db dyn HirDatabase, + def: InferBodyId<'db>, +) -> Result<'db, MirBody<'db>> { let krate = def.krate(db); let edition = krate.data(db).edition; let detail = match def { @@ -2326,16 +2314,16 @@ pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result fn mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _: salsa::Id, - _def: InferBodyId, -) -> Result<'db, MirBody> { + _def: InferBodyId<'db>, +) -> Result<'db, MirBody<'db>> { Err(MirLowerError::Loop) } fn mir_body_for_closure_cycle_result<'db>( _db: &'db dyn HirDatabase, _: salsa::Id, - _def: InternedClosureId, -) -> Result<'db, MirBody> { + _def: InternedClosureId<'db>, +) -> Result<'db, MirBody<'db>> { Err(MirLowerError::Loop) } @@ -2343,13 +2331,13 @@ fn mir_body_for_closure_cycle_result<'db>( /// then delegates to [`lower_to_mir_with_store`]. pub fn lower_body_to_mir<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'db>, root_expr: ExprId, self_param: Option, params: &[Param], -) -> Result<'db, MirBody> { +) -> Result<'db, MirBody<'db>> { // Extract params and self_param only when lowering the body's root expression for a function. if let Some(fid) = owner.as_function() { let callable_sig = { @@ -2383,13 +2371,13 @@ pub fn lower_body_to_mir<'db>( /// const (picks bindings owned by `root_expr`). pub fn lower_to_mir_with_store<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'db>, root_expr: ExprId, params: impl Iterator)> + Clone, self_param: Option<(BindingId, Ty<'db>)>, -) -> Result<'db, MirBody> { +) -> Result<'db, MirBody<'db>> { if infer.has_type_mismatches() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs index d42072afa4b7c..8eb0a02694ce7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs @@ -6,7 +6,7 @@ use crate::{InferBodyId, db::HirDatabase, setup_tracing, test_db::TestDB}; fn lower_mir(#[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, || { + crate::attach_db(db.as_dyn(), || { 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); @@ -54,7 +54,7 @@ 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, || { + crate::attach_db(db.as_dyn(), || { 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); @@ -78,7 +78,7 @@ fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) { } for body in bodies { - let _ = InferBodyId::from(body).borrowck(&db); + let _ = InferBodyId::from(body).borrowck(db.as_dyn()); } }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index bcc86ba4bfd79..976ef2c45f1cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -39,7 +39,7 @@ struct Filler<'db> { } impl<'db> FallibleTypeFolder> for Filler<'db> { - type Error = MirLowerError; + type Error = MirLowerError<'db>; fn cx(&self) -> DbInterner<'db> { self.infcx.interner @@ -106,7 +106,7 @@ impl<'db> Filler<'db> { Self { infcx, trait_env: env, subst } } - fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError> { + fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -116,7 +116,7 @@ impl<'db> Filler<'db> { } } - fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError> { + fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -126,7 +126,7 @@ impl<'db> Filler<'db> { } } - fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError> { + fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -136,7 +136,7 @@ impl<'db> Filler<'db> { } } - fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { + fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> { match &mut op.kind { OperandKind::Constant { konst, ty } => { self.fill_const(konst)?; @@ -159,7 +159,7 @@ impl<'db> Filler<'db> { Ok(()) } - fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> { + fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> { for (_, l) in body.locals.iter_mut() { self.fill_ty(&mut l.ty)?; } @@ -179,9 +179,6 @@ impl<'db> Filler<'db> { super::AggregateKind::Union(_, _) => (), } } - Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => { - self.fill_ty(ty)?; - } Rvalue::Use(op) => { self.fill_operand(op)?; } @@ -238,50 +235,50 @@ impl<'db> Filler<'db> { } } -#[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)] -pub fn monomorphized_mir_body_query( - db: &dyn HirDatabase, - owner: InferBodyId, +#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)] +pub fn monomorphized_mir_body_query<'db>( + db: &'db dyn HirDatabase, + owner: InferBodyId<'db>, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, -) -> Result { - let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); +) -> Result, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref()); let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(body) } -fn monomorphized_mir_body_cycle_result( - _db: &dyn HirDatabase, +fn monomorphized_mir_body_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, - _: InferBodyId, + _: InferBodyId<'db>, _: StoredGenericArgs, _: StoredParamEnvAndCrate, -) -> Result { +) -> Result, MirLowerError<'db>> { Err(MirLowerError::Loop) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)] -pub fn monomorphized_mir_body_for_closure_query( - db: &dyn HirDatabase, - closure: InternedClosureId, +#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)] +pub fn monomorphized_mir_body_for_closure_query<'db>( + db: &'db dyn HirDatabase, + closure: InternedClosureId<'db>, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, -) -> Result { - let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); +) -> Result, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref()); let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(body) } -fn monomorphized_mir_body_for_closure_cycle_result( - _db: &dyn HirDatabase, +fn monomorphized_mir_body_for_closure_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, - _: InternedClosureId, + _: InternedClosureId<'db>, _: StoredGenericArgs, _: StoredParamEnvAndCrate, -) -> Result { +) -> Result, MirLowerError<'db>> { Err(MirLowerError::Loop) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 3e414544241c4..4a51b5113a436 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -43,7 +43,7 @@ macro_rules! wln { }; } -impl MirBody { +impl MirBody<'_> { pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { let hir_body = ExpressionStore::of(db, self.owner.expression_store_owner(db)); let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); @@ -100,7 +100,7 @@ impl MirBody { } struct MirPrettyCtx<'a, 'db> { - body: &'a MirBody, + body: &'a MirBody<'db>, hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, result: String, @@ -153,7 +153,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } } - fn for_closure(&mut self, closure: InternedClosureId) { + fn for_closure(&mut self, closure: InternedClosureId<'db>) { let body = match self.db.mir_body_for_closure(closure) { Ok(it) => it, Err(e) => { @@ -187,7 +187,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } fn new( - body: &'a MirBody, + body: &'a MirBody<'db>, hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, display_target: DisplayTarget, @@ -490,12 +490,6 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { self.place(p); w!(self, ")"); } - Rvalue::ShallowInitBoxWithAlloc(_) => w!(self, "ShallowInitBoxWithAlloc"), - Rvalue::ShallowInitBox(op, _) => { - w!(self, "ShallowInitBox("); - self.operand(op); - w!(self, ")"); - } Rvalue::CopyForDeref(p) => { w!(self, "CopyForDeref("); self.place(p); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index f0d33ad2ddafc..42fd31f2594da 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -143,7 +143,7 @@ impl std::fmt::Debug for DefaultAny<'_> { } #[inline] -pub fn default_types<'a, 'db>(db: &'db dyn HirDatabase) -> &'a DefaultAny<'db> { +pub fn default_types<'db>(db: &'db dyn HirDatabase) -> &'db DefaultAny<'db> { static TYPES: OnceLock> = OnceLock::new(); let interner = DbInterner::new_no_crate(db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs index 95f437165d045..9585cced6b114 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs @@ -1,5 +1,6 @@ use hir_def::TraitId; use macros::{TypeFoldable, TypeVisitable}; +use salsa::Update; use crate::next_solver::{ Binder, Clauses, DbInterner, EarlyBinder, FnSig, FnSigKind, GenericArg, PolyFnSig, @@ -7,7 +8,7 @@ use crate::next_solver::{ TraitRef, Ty, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Update)] pub struct StoredEarlyBinder(T); impl StoredEarlyBinder { @@ -102,7 +103,7 @@ impl StoredPolyFnSig { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, Update)] pub struct StoredTraitRef { #[type_visitable(ignore)] def_id: TraitId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index 63337b297dc7a..b122a8cddc410 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -10,6 +10,7 @@ use hir_def::{ }, }; use rustc_type_ir::inherent; +use salsa::Update; use stdx::impl_from; use crate::{ @@ -28,26 +29,26 @@ pub enum Ctor { Enum(EnumVariantId), } -#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SolverDefId { +#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, Update)] +pub enum SolverDefId<'db> { AdtId(AdtId), ConstId(ConstId), FunctionId(FunctionId), ImplId(ImplId), BuiltinDeriveImplId(BuiltinDeriveImplId), StaticId(StaticId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), TraitId(TraitId), TypeAliasId(TypeAliasId), - InternedClosureId(InternedClosureId), - InternedCoroutineId(InternedCoroutineId), - InternedCoroutineClosureId(InternedCoroutineClosureId), - InternedOpaqueTyId(InternedOpaqueTyId), + InternedClosureId(InternedClosureId<'db>), + InternedCoroutineId(InternedCoroutineId<'db>), + InternedCoroutineClosureId(InternedCoroutineClosureId<'db>), + InternedOpaqueTyId(InternedOpaqueTyId<'db>), EnumVariantId(EnumVariantId), Ctor(Ctor), } -impl std::fmt::Debug for SolverDefId { +impl std::fmt::Debug for SolverDefId<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let interner = DbInterner::conjure(); let db = interner.db; @@ -122,50 +123,54 @@ impl std::fmt::Debug for SolverDefId { } impl_from!( + impl<'db> AdtId(StructId, EnumId, UnionId), ConstId, FunctionId, ImplId, BuiltinDeriveImplId, StaticId, - AnonConstId, + AnonConstId<'db>, TraitId, TypeAliasId, - InternedClosureId, - InternedCoroutineId, - InternedCoroutineClosureId, - InternedOpaqueTyId, + InternedClosureId<'db>, + InternedCoroutineId<'db>, + InternedCoroutineClosureId<'db>, + InternedOpaqueTyId<'db>, EnumVariantId, Ctor - for SolverDefId + for SolverDefId<'db> ); -impl From for SolverDefId { - fn from(value: GenericDefId) -> Self { +impl_from!( + impl<'db> + GenericDefId { AdtId, ConstId, FunctionId, ImplId, StaticId, TraitId, TypeAliasId } + for SolverDefId<'db> +); + +impl<'db> From> for SolverDefId<'db> { + #[inline] + fn from(value: GeneralConstId<'db>) -> Self { match value { - GenericDefId::AdtId(adt_id) => SolverDefId::AdtId(adt_id), - GenericDefId::ConstId(const_id) => SolverDefId::ConstId(const_id), - GenericDefId::FunctionId(function_id) => SolverDefId::FunctionId(function_id), - GenericDefId::ImplId(impl_id) => SolverDefId::ImplId(impl_id), - GenericDefId::StaticId(static_id) => SolverDefId::StaticId(static_id), - GenericDefId::TraitId(trait_id) => SolverDefId::TraitId(trait_id), - GenericDefId::TypeAliasId(type_alias_id) => SolverDefId::TypeAliasId(type_alias_id), + GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), + GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), + GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id), } } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] - fn from(value: GeneralConstId) -> Self { + fn from(value: CallableDefId) -> Self { match value { - GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), - GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), - GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id), + CallableDefId::FunctionId(id) => id.into(), + CallableDefId::StructId(id) => id.into(), + CallableDefId::EnumVariantId(id) => id.into(), } } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: DefWithBodyId) -> Self { match value { @@ -177,9 +182,9 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From> for SolverDefId<'db> { #[inline] - fn from(value: InferBodyId) -> Self { + fn from(value: InferBodyId<'db>) -> Self { match value { InferBodyId::DefWithBodyId(id) => id.into(), InferBodyId::AnonConstId(id) => id.into(), @@ -187,7 +192,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: VariantId) -> Self { match value { @@ -198,7 +203,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: ExpressionStoreOwnerId) -> Self { match value { @@ -209,10 +214,10 @@ impl From for SolverDefId { } } -impl TryFrom for AttrDefId { +impl TryFrom> for AttrDefId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::AdtId(it) => Ok(it.into()), SolverDefId::ConstId(it) => Ok(it.into()), @@ -234,11 +239,11 @@ impl TryFrom for AttrDefId { } } -impl TryFrom for DefWithBodyId { +impl TryFrom> for DefWithBodyId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { let id = match value { SolverDefId::ConstId(id) => id.into(), SolverDefId::FunctionId(id) => id.into(), @@ -260,11 +265,11 @@ impl TryFrom for DefWithBodyId { } } -impl TryFrom for InferBodyId { +impl<'db> TryFrom> for InferBodyId<'db> { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'db>) -> Result { let id = match value { SolverDefId::ConstId(id) => id.into(), SolverDefId::FunctionId(id) => id.into(), @@ -286,10 +291,10 @@ impl TryFrom for InferBodyId { } } -impl TryFrom for GenericDefId { +impl TryFrom> for GenericDefId { type Error = (); - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { Ok(match value { SolverDefId::AdtId(adt_id) => GenericDefId::AdtId(adt_id), SolverDefId::ConstId(const_id) => GenericDefId::ConstId(const_id), @@ -310,8 +315,8 @@ impl TryFrom for GenericDefId { } } -impl<'db> inherent::DefId> for SolverDefId { - fn as_local(self) -> Option { +impl<'db> inherent::DefId> for SolverDefId<'db> { + fn as_local(self) -> Option> { Some(self) } fn is_local(self) -> bool { @@ -321,17 +326,17 @@ impl<'db> inherent::DefId> for SolverDefId { macro_rules! declare_id_wrapper { ($name:ident, $wraps:ident) => { - declare_id_wrapper!($name, $wraps, SolverDefId); + declare_id_wrapper!($name, $wraps, SolverDefId<'db>); }; - ($name:ident, $wraps:ident, $local:ident) => { + ($name:ident, $wraps:ident, $local:ty) => { declare_id_wrapper!($name, $wraps, $local, no_try_from); - impl TryFrom for $name { + impl TryFrom> for $name { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::$wraps(it) => Ok(Self(it)), _ => Err(()), @@ -340,7 +345,7 @@ macro_rules! declare_id_wrapper { } }; - ($name:ident, $wraps:ident, $local:ident, no_try_from) => { + ($name:ident, $wraps:ident, $local:ty, no_try_from) => { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct $name(pub $wraps); @@ -364,9 +369,9 @@ macro_rules! declare_id_wrapper { } } - impl From<$name> for SolverDefId { + impl<'db> From<$name> for SolverDefId<'db> { #[inline] - fn from(value: $name) -> SolverDefId { + fn from(value: $name) -> SolverDefId<'db> { value.0.into() } } @@ -382,25 +387,89 @@ macro_rules! declare_id_wrapper { }; } +/// This is similar to [`declare_id_wrapper`], but handles ids which have the `'db` lifetime. +macro_rules! declare_id_wrapper_with_lt { + ($name:ident, $wraps:ident) => { + declare_id_wrapper_with_lt!($name, $wraps, SolverDefId<'db>); + }; + + ($name:ident, $wraps:ident, $local:ty) => { + declare_id_wrapper_with_lt!($name, $wraps, $local, no_try_from); + + impl<'db> TryFrom> for $name<'db> { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId<'db>) -> Result { + match value { + SolverDefId::$wraps(it) => Ok(Self(it)), + _ => Err(()), + } + } + } + }; + + ($name:ident, $wraps:ident, $local:ty, no_try_from) => { + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub struct $name<'db>(pub $wraps<'db>); + + impl std::fmt::Debug for $name<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) + } + } + + impl<'db> From<$name<'db>> for $wraps<'db> { + #[inline] + fn from(value: $name<'db>) -> $wraps<'db> { + value.0 + } + } + + impl<'db> From<$wraps<'db>> for $name<'db> { + #[inline] + fn from(value: $wraps<'db>) -> $name<'db> { + Self(value) + } + } + + impl<'db> From<$name<'db>> for SolverDefId<'db> { + #[inline] + fn from(value: $name<'db>) -> SolverDefId<'db> { + value.0.into() + } + } + + impl<'db> inherent::DefId, $local> for $name<'db> { + fn as_local(self) -> Option<$local> { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } + } + }; +} + declare_id_wrapper!(TraitIdWrapper, TraitId); declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId); -declare_id_wrapper!(ClosureIdWrapper, InternedClosureId); -declare_id_wrapper!(CoroutineIdWrapper, InternedCoroutineId); -declare_id_wrapper!(CoroutineClosureIdWrapper, InternedCoroutineClosureId); +declare_id_wrapper_with_lt!(ClosureIdWrapper, InternedClosureId); +declare_id_wrapper_with_lt!(CoroutineIdWrapper, InternedCoroutineId); +declare_id_wrapper_with_lt!(CoroutineClosureIdWrapper, InternedCoroutineClosureId); declare_id_wrapper!(AdtIdWrapper, AdtId); -declare_id_wrapper!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper); +declare_id_wrapper_with_lt!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper<'db>); macro_rules! declare_ty_const_pair { ( $ty_id_name:ident, $const_id_name:ident, $term_id_name:ident ) => { declare_id_wrapper!($ty_id_name, TypeAliasId); declare_id_wrapper!($const_id_name, ConstId); - declare_id_wrapper!($term_id_name, TermId, SolverDefId, no_try_from); + declare_id_wrapper!($term_id_name, TermId, SolverDefId<'db>, no_try_from); - impl TryFrom for $term_id_name { + impl TryFrom> for $term_id_name { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::TypeAliasId(it) => Ok(Self(TermId::TypeAliasId(it))), SolverDefId::ConstId(it) => Ok(Self(TermId::ConstId(it))), @@ -443,7 +512,7 @@ macro_rules! declare_ty_const_pair { } } - impl From<$const_id_name> for GeneralConstIdWrapper { + impl<'db> From<$const_id_name> for GeneralConstIdWrapper<'db> { fn from(value: $const_id_name) -> Self { GeneralConstIdWrapper(GeneralConstId::ConstId(value.0)) } @@ -463,7 +532,7 @@ pub enum TermId { } impl_from!(TypeAliasId, ConstId for TermId); -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { fn from(value: TermId) -> Self { match value { TermId::TypeAliasId(id) => id.into(), @@ -473,28 +542,28 @@ impl From for SolverDefId { } #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct GeneralConstIdWrapper(pub GeneralConstId); +pub struct GeneralConstIdWrapper<'db>(pub GeneralConstId<'db>); -impl std::fmt::Debug for GeneralConstIdWrapper { +impl std::fmt::Debug for GeneralConstIdWrapper<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Debug::fmt(&self.0, f) } } -impl From for GeneralConstId { +impl<'db> From> for GeneralConstId<'db> { #[inline] - fn from(value: GeneralConstIdWrapper) -> GeneralConstId { + fn from(value: GeneralConstIdWrapper<'db>) -> GeneralConstId<'db> { value.0 } } -impl From for GeneralConstIdWrapper { +impl<'db> From> for GeneralConstIdWrapper<'db> { #[inline] - fn from(value: GeneralConstId) -> GeneralConstIdWrapper { + fn from(value: GeneralConstId<'db>) -> GeneralConstIdWrapper<'db> { Self(value) } } -impl From for SolverDefId { +impl<'db> From> for SolverDefId<'db> { #[inline] - fn from(value: GeneralConstIdWrapper) -> SolverDefId { + fn from(value: GeneralConstIdWrapper<'db>) -> SolverDefId<'db> { match value.0 { GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), @@ -502,10 +571,10 @@ impl From for SolverDefId { } } } -impl TryFrom for GeneralConstIdWrapper { +impl<'db> TryFrom> for GeneralConstIdWrapper<'db> { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'db>) -> Result { match value { SolverDefId::ConstId(it) => Ok(Self(it.into())), SolverDefId::StaticId(it) => Ok(Self(it.into())), @@ -514,8 +583,8 @@ impl TryFrom for GeneralConstIdWrapper { } } } -impl<'db> inherent::DefId> for GeneralConstIdWrapper { - fn as_local(self) -> Option { +impl<'db> inherent::DefId> for GeneralConstIdWrapper<'db> { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { @@ -543,9 +612,9 @@ impl From for CallableIdWrapper { Self(value) } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] - fn from(value: CallableIdWrapper) -> SolverDefId { + fn from(value: CallableIdWrapper) -> SolverDefId<'db> { match value.0 { CallableDefId::FunctionId(it) => it.into(), CallableDefId::StructId(it) => Ctor::Struct(it).into(), @@ -553,10 +622,10 @@ impl From for SolverDefId { } } } -impl TryFrom for CallableIdWrapper { +impl TryFrom> for CallableIdWrapper { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::FunctionId(it) => Ok(Self(it.into())), SolverDefId::Ctor(Ctor::Struct(it)) => Ok(Self(it.into())), @@ -566,7 +635,7 @@ impl TryFrom for CallableIdWrapper { } } impl<'db> inherent::DefId> for CallableIdWrapper { - fn as_local(self) -> Option { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { @@ -582,19 +651,19 @@ pub enum AnyImplId { impl_from!(ImplId, BuiltinDeriveImplId for AnyImplId); -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] - fn from(value: AnyImplId) -> SolverDefId { + fn from(value: AnyImplId) -> SolverDefId<'db> { match value { AnyImplId::ImplId(it) => it.into(), AnyImplId::BuiltinDeriveImplId(it) => it.into(), } } } -impl TryFrom for AnyImplId { +impl TryFrom> for AnyImplId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::ImplId(it) => Ok(it.into()), SolverDefId::BuiltinDeriveImplId(it) => Ok(it.into()), @@ -603,7 +672,7 @@ impl TryFrom for AnyImplId { } } impl<'db> inherent::DefId> for AnyImplId { - fn as_local(self) -> Option { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs index 0a41874374c21..826f234bf6d9f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs @@ -225,7 +225,7 @@ impl<'db> DbInterner<'db> { /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( self, - all_outlive_scope: SolverDefId, + all_outlive_scope: SolverDefId<'db>, value: Binder<'db, T>, ) -> T where diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs index 33dd33cb1d806..e422f75a02073 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -287,7 +287,7 @@ impl<'db> FulfillmentCtxt<'db> { /// This function can be also return false positives, which will lead to poor diagnostics /// so we want to keep this visitor *precise* too. pub struct StalledOnCoroutines<'a, 'db> { - pub stalled_coroutines: &'a [SolverDefId], + pub stalled_coroutines: &'a [SolverDefId<'db>], pub span: Span, pub cache: FxHashSet>, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 4e5f3c8c49c13..22b34b379dd86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -553,7 +553,7 @@ impl<'db> GenericArgs<'db> { /// replace defaults of generic parameters. pub fn for_item( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, mk_kind: F, ) -> GenericArgs<'db> where @@ -579,7 +579,7 @@ impl<'db> GenericArgs<'db> { } /// Creates an all-error `GenericArgs`. - pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> { + pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId<'db>) -> GenericArgs<'db> { GenericArgs::for_item(interner, def_id, |_, id, _, _| { GenericArg::error_from_id(interner, id) }) @@ -606,7 +606,7 @@ impl<'db> GenericArgs<'db> { /// Like `for_item()`, but calls first uses the args from `first`. pub fn fill_rest( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, first: impl IntoIterator>, mut fallback: F, ) -> GenericArgs<'db> diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index 49dbbcb06bcc8..9558a8b2b3128 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -7,11 +7,9 @@ use hir_def::{ use crate::db::HirDatabase; -use super::SolverDefId; +use super::{Ctor, DbInterner, SolverDefId}; -use super::DbInterner; - -pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<'_> { +pub(crate) fn generics<'db>(interner: DbInterner<'db>, def: SolverDefId<'db>) -> Generics<'db> { let db = interner.db; let (def, consider_late_bound) = match (def.try_into(), def) { (Ok(def), _) => (def, false), @@ -24,6 +22,10 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<' (_, SolverDefId::BuiltinDeriveImplId(id)) => { return crate::builtin_derive::generics_of(interner, id); } + (_, SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id))) => { + (id.loc(db).parent.into(), false) + } + (_, SolverDefId::Ctor(Ctor::Struct(id))) => (id.into(), false), (_, SolverDefId::AnonConstId(id)) => { let loc = id.loc(db); let generic_def = loc.owner.generic_def(db); @@ -94,7 +96,7 @@ impl<'db> Generics<'db> { (id, None) } }) - .chain(self.additional_param.zip(None)) + .chain(self.additional_param.map(|param| (param, None))) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs index 1e2a3ff0c2b33..270bc73d5f53f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs @@ -158,7 +158,7 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { self.next_const_var(Span::Dummy) } - fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { + fn fresh_args_for_item(&self, def_id: SolverDefId<'db>) -> GenericArgs<'db> { self.fresh_args_for_item(Span::Dummy, def_id) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs index 7d3f111f668fa..c3e9caa1c6766 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs @@ -15,7 +15,7 @@ use crate::{ db::GeneralConstId, next_solver::{ AliasTerm, AnyImplId, Binder, ClauseKind, Const, ConstKind, DbInterner, - HostEffectPredicate, PolyTraitPredicate, PredicateKind, SolverContext, Term, + HostEffectPredicate, PolyTraitPredicate, Predicate, PredicateKind, SolverContext, Term, TraitPredicate, Ty, TyKind, TypeError, fulfill::NextSolverError, infer::{ @@ -32,21 +32,10 @@ use crate::{ pub struct FulfillmentError<'db> { pub obligation: PredicateObligation<'db>, pub code: FulfillmentErrorCode<'db>, - /// Diagnostics only: the 'root' obligation which resulted in - /// the failure to process `obligation`. This is the obligation - /// that was initially passed to `register_predicate_obligation` - pub root_obligation: PredicateObligation<'db>, + pub parent_trait_obligations: Vec>, } -impl<'db> FulfillmentError<'db> { - pub fn new( - obligation: PredicateObligation<'db>, - code: FulfillmentErrorCode<'db>, - root_obligation: PredicateObligation<'db>, - ) -> FulfillmentError<'db> { - FulfillmentError { obligation, code, root_obligation } - } - +impl FulfillmentError<'_> { pub fn is_true_error(&self) -> bool { match self.code { FulfillmentErrorCode::Select(_) @@ -130,7 +119,8 @@ fn fulfillment_error_for_no_solution<'db>( ) -> FulfillmentError<'db> { let interner = infcx.interner; let db = interner.db; - let obligation = find_best_leaf_obligation(infcx, &root_obligation, false); + let (obligation, parent_trait_obligations) = + find_best_leaf_obligation(infcx, &root_obligation, false); let code = match obligation.predicate.kind().skip_binder() { PredicateKind::Clause(ClauseKind::Projection(_)) => { @@ -189,7 +179,7 @@ fn fulfillment_error_for_no_solution<'db>( } }; - FulfillmentError { obligation, code, root_obligation } + FulfillmentError { obligation, code, parent_trait_obligations } } fn fulfillment_error_for_stalled<'db>( @@ -239,25 +229,25 @@ fn fulfillment_error_for_stalled<'db>( } }); - FulfillmentError { - obligation: if refine_obligation { - find_best_leaf_obligation(infcx, &root_obligation, true) - } else { - root_obligation.clone() - }, - code, - root_obligation, - } + let (obligation, parent_trait_obligations) = if refine_obligation { + find_best_leaf_obligation(infcx, &root_obligation, true) + } else { + (root_obligation, Vec::new()) + }; + + FulfillmentError { obligation, code, parent_trait_obligations } } fn fulfillment_error_for_overflow<'db>( infcx: &InferCtxt<'db>, root_obligation: PredicateObligation<'db>, ) -> FulfillmentError<'db> { + let (obligation, parent_trait_obligations) = + find_best_leaf_obligation(infcx, &root_obligation, true); FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + obligation, code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation, + parent_trait_obligations, } } @@ -266,34 +256,44 @@ fn find_best_leaf_obligation<'db>( infcx: &InferCtxt<'db>, obligation: &PredicateObligation<'db>, consider_ambiguities: bool, -) -> PredicateObligation<'db> { +) -> (PredicateObligation<'db>, Vec>) { let obligation = infcx.resolve_vars_if_possible(obligation.clone()); // FIXME: we use a probe here as the `BestObligation` visitor does not // check whether it uses candidates which get shadowed by where-bounds. // // We should probably fix the visitor to not do so instead, as this also // means the leaf obligation may be incorrect. - let obligation = infcx + let (obligation, parent_trait_obligations) = infcx .fudge_inference_if_ok(|| { + let mut visitor = BestObligation { + obligation: obligation.clone(), + consider_ambiguities, + parent_trait_obligations: Vec::new(), + }; infcx - .visit_proof_tree( - obligation.as_goal(), - &mut BestObligation { obligation: obligation.clone(), consider_ambiguities }, - ) + .visit_proof_tree(obligation.as_goal(), &mut visitor) .break_value() .ok_or(()) // walk around the fact that the cause in `Obligation` is ignored by folders so that // we can properly fudge the infer vars in cause code. - .map(|o| (o.cause, o)) + .map(|(obligation, parent_trait_obligations)| { + (obligation.cause, obligation, parent_trait_obligations) + }) }) - .map(|(cause, o)| PredicateObligation { cause, ..o }) - .unwrap_or(obligation); - deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) + .map(|(cause, obligation, parent_trait_obligations)| { + (PredicateObligation { cause, ..obligation }, parent_trait_obligations) + }) + .unwrap_or((obligation, Vec::new())); + let parent_trait_obligations = + deeply_normalize_for_diagnostics(infcx, obligation.param_env, parent_trait_obligations); + let obligation = deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation); + (obligation, parent_trait_obligations) } struct BestObligation<'db> { obligation: PredicateObligation<'db>, consider_ambiguities: bool, + parent_trait_obligations: Vec>, } impl<'db> BestObligation<'db> { @@ -302,10 +302,26 @@ impl<'db> BestObligation<'db> { derived_obligation: PredicateObligation<'db>, and_then: impl FnOnce(&mut Self) -> >::Result, ) -> >::Result { + let parent_predicate = self.obligation.predicate; + let should_push = parent_predicate.as_trait_clause().is_some() + && self.parent_trait_obligations.last() != Some(&parent_predicate); + if should_push { + self.parent_trait_obligations.push(parent_predicate); + } let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); - let res = and_then(self); + let result = and_then(self); self.obligation = old_obligation; - res + if should_push { + self.parent_trait_obligations.pop(); + } + result + } + + fn break_with_current_obligation(&mut self) -> >::Result { + ControlFlow::Break(( + self.obligation.clone(), + std::mem::take(&mut self.parent_trait_obligations), + )) } /// Filter out the candidates that aren't interesting to visit for the @@ -360,7 +376,7 @@ impl<'db> BestObligation<'db> { &mut self, candidate: &inspect::InspectCandidate<'_, 'db>, term: Term<'db>, - ) -> ControlFlow> { + ) -> >::Result { let _ = (candidate, term); // FIXME: rustc does this, but we don't process WF obligations yet: // let infcx = candidate.goal().infcx(); @@ -386,7 +402,7 @@ impl<'db> BestObligation<'db> { // self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; // } - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } /// If a normalization of an associated item or a trait goal fails without trying any @@ -396,7 +412,7 @@ impl<'db> BestObligation<'db> { &mut self, goal: &inspect::InspectGoal<'_, 'db>, self_ty: Ty<'db>, - ) -> ControlFlow> { + ) -> >::Result { assert!(!self.consider_ambiguities); let interner = goal.infcx().interner; if let TyKind::Alias(..) = self_ty.kind() { @@ -430,7 +446,7 @@ impl<'db> BestObligation<'db> { fn detect_trait_error_in_higher_ranked_projection( &mut self, goal: &inspect::InspectGoal<'_, 'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; if let Some(projection_clause) = goal.goal().predicate.as_projection_clause() && !projection_clause.bound_vars().is_empty() @@ -464,7 +480,7 @@ impl<'db> BestObligation<'db> { &mut self, goal: &inspect::InspectGoal<'_, 'db>, alias: AliasTerm<'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; let obligation = Obligation::new( interner, @@ -486,7 +502,7 @@ impl<'db> BestObligation<'db> { fn detect_error_from_empty_candidates( &mut self, goal: &inspect::InspectGoal<'_, 'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; let pred_kind = goal.goal().predicate.kind(); @@ -504,12 +520,12 @@ impl<'db> BestObligation<'db> { Some(_) | None => {} } - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } } impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { - type Result = ControlFlow>; + type Result = ControlFlow<(PredicateObligation<'db>, Vec>)>; fn span(&self) -> Span { self.obligation.cause.span() @@ -531,7 +547,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { let candidate = match candidates.as_slice() { [candidate] => candidate, [] => return self.detect_error_from_empty_candidates(goal), - _ => return ControlFlow::Break(self.obligation.clone()), + _ => return self.break_with_current_obligation(), }; // Don't walk into impls that have `do_not_recommend`. @@ -544,7 +560,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { .contains(AttrFlags::DIAGNOSTIC_DO_NOT_RECOMMEND) { trace!("#[diagnostic::do_not_recommend] -> exit"); - return ControlFlow::Break(self.obligation.clone()); + return self.break_with_current_obligation(); } // FIXME: Also, what about considering >1 layer up the stack? May be necessary @@ -587,7 +603,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { && Some(poly_trait_pred.def_id().0) == interner.lang_items().FnPtrTrait && let Err(NoSolution) = nested_goal.result() { - return ControlFlow::Break(self.obligation.clone()); + return self.break_with_current_obligation(); } } @@ -661,7 +677,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { self.detect_trait_error_in_higher_ranked_projection(goal)?; - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 3fdf0480ebc2d..7c419147d2143 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -296,7 +296,7 @@ pub struct TypeTrace<'db> { /// Times when we replace bound regions with existentials: #[derive(Clone, Copy, Debug)] -pub enum BoundRegionConversionTime { +pub enum BoundRegionConversionTime<'db> { /// when a fn is called FnCall, @@ -304,7 +304,7 @@ pub enum BoundRegionConversionTime { HigherRankedType, /// when projecting an associated type - AssocTypeProjection(SolverDefId), + AssocTypeProjection(SolverDefId<'db>), } /// See the `region_obligations` field for more information. @@ -839,7 +839,7 @@ impl<'db> InferCtxt<'db> { /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. - pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId) -> GenericArgs<'db> { + pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId<'db>) -> GenericArgs<'db> { GenericArgs::for_item(self.interner, def_id, |_index, kind, _, _| { self.var_for_def(kind, span) }) @@ -849,7 +849,7 @@ impl<'db> InferCtxt<'db> { pub fn fill_rest_fresh_args( &self, span: Span, - def_id: SolverDefId, + def_id: SolverDefId<'db>, first: impl IntoIterator>, ) -> GenericArgs<'db> { GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| { @@ -903,7 +903,7 @@ impl<'db> InferCtxt<'db> { } #[inline(always)] - pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { + pub fn can_define_opaque_ty(&self, id: impl Into>) -> bool { match self.typing_mode_raw().assert_not_erased() { TypingMode::Analysis { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators.contains(&id.into()) @@ -1102,7 +1102,7 @@ impl<'db> InferCtxt<'db> { pub fn instantiate_binder_with_fresh_vars( &self, span: Span, - _lbrct: BoundRegionConversionTime, + _lbrct: BoundRegionConversionTime<'db>, value: Binder<'db, T>, ) -> T where diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs index e55e43a4cdb32..3b957c9c72894 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs @@ -394,7 +394,7 @@ impl<'db> TypeRelation> for Generalizer<'_, 'db> { &mut self, a_ty: Ty<'db>, _: Ty<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, a_args: GenericArgs<'db>, b_args: GenericArgs<'db>, mk: impl FnOnce(GenericArgs<'db>) -> Ty<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs index f3af697febcb2..f34afead74ffe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs @@ -91,7 +91,7 @@ impl<'db> TypeRelation> for LatticeOp<'_, 'db> { &mut self, a_ty: Ty<'db>, b_ty: Ty<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, a_args: GenericArgs<'db>, b_args: GenericArgs<'db>, mk: impl FnOnce(GenericArgs<'db>) -> Ty<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs index d6f0379c111a2..1462f292058ee 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs @@ -40,7 +40,7 @@ pub enum SelectionError<'db> { /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). /// We can thus not know whether the hidden type implements an auto trait, so /// we should not presume anything about it. - OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId), + OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId<'db>), /// Error for a `ConstArgHasType` goal ConstArgHasWrongType { ct: Const<'db>, ct_ty: Ty<'db>, expected_ty: Ty<'db> }, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 3e8fab9313185..a7216a034cc56 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -201,6 +201,7 @@ macro_rules! impl_stored_interned_slice { Self { interned: it.interned.to_owned() } } + // FIXME: This transmute is not safe as is! #[inline] pub fn as_ref<'a, 'db>(&'a self) -> $name<'db> { let it = $name { interned: self.interned.as_ref() }; @@ -212,7 +213,7 @@ macro_rules! impl_stored_interned_slice { unsafe impl salsa::Update for $stored_name { unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { // SAFETY: Comparing by (pointer) equality is safe. - unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) } + unsafe { salsa::update_fallback(old_pointer, new_value) } } } @@ -285,7 +286,7 @@ macro_rules! impl_stored_interned { unsafe impl salsa::Update for $stored_name { unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { - unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) } + unsafe { salsa::update_fallback(old_pointer, new_value) } } } @@ -378,7 +379,7 @@ impl<'db> DbInterner<'db> { } #[inline] - pub fn default_types<'a>(&self) -> &'a crate::next_solver::DefaultAny<'db> { + pub fn default_types(&self) -> &'db crate::next_solver::DefaultAny<'db> { crate::next_solver::default_types(self.db) } @@ -878,23 +879,23 @@ macro_rules! is_lang_item { } impl<'db> Interner for DbInterner<'db> { - type DefId = SolverDefId; - type LocalDefId = SolverDefId; + type DefId = SolverDefId<'db>; + type LocalDefId = SolverDefId<'db>; type LocalDefIds = SolverDefIds<'db>; type TraitId = TraitIdWrapper; type ForeignId = TypeAliasIdWrapper; type FunctionId = CallableIdWrapper; - type ClosureId = ClosureIdWrapper; - type CoroutineClosureId = CoroutineClosureIdWrapper; - type CoroutineId = CoroutineIdWrapper; + type ClosureId = ClosureIdWrapper<'db>; + type CoroutineClosureId = CoroutineClosureIdWrapper<'db>; + type CoroutineId = CoroutineIdWrapper<'db>; type AdtId = AdtIdWrapper; type ImplId = AnyImplId; - type UnevaluatedConstId = GeneralConstIdWrapper; + type UnevaluatedConstId = GeneralConstIdWrapper<'db>; type TraitAssocTyId = TraitAssocTyId; type TraitAssocConstId = TraitAssocConstId; type TraitAssocTermId = TraitAssocTermId; - type OpaqueTyId = OpaqueTyIdWrapper; - type LocalOpaqueTyId = OpaqueTyIdWrapper; + type OpaqueTyId = OpaqueTyIdWrapper<'db>; + type LocalOpaqueTyId = OpaqueTyIdWrapper<'db>; type FreeTyAliasId = FreeTyAliasId; type FreeConstAliasId = FreeConstAliasId; type FreeTermAliasId = FreeTermAliasId; @@ -1105,7 +1106,7 @@ impl<'db> Interner for DbInterner<'db> { AdtDef::new(def_id.0, self) } - fn alias_term_kind_from_def_id(self, def_id: SolverDefId) -> AliasTermKind<'db> { + fn alias_term_kind_from_def_id(self, def_id: SolverDefId<'db>) -> AliasTermKind<'db> { match def_id { SolverDefId::InternedOpaqueTyId(def_id) => { AliasTermKind::OpaqueTy { def_id: def_id.into() } @@ -1608,7 +1609,7 @@ impl<'db> Interner for DbInterner<'db> { ) { let krate = self.krate.expect("trait solving requires setting `DbInterner::krate`"); let trait_block = trait_def_id.0.loc(self.db).container.block(self.db); - let mut consider_impls_for_simplified_type = |simp: SimplifiedType| { + let mut consider_impls_for_simplified_type = |simp: SimplifiedType<'_>| { let type_block = simp.def().and_then(|def_id| { let module = match def_id { SolverDefId::AdtId(AdtId::StructId(id)) => id.module(self.db), @@ -1973,14 +1974,14 @@ impl<'db> Interner for DbInterner<'db> { return SolverDefIds::new_from_slice(&result); - struct CoroutinesVisitor<'a> { - db: &'a dyn HirDatabase, - owner: InferBodyId, - store: &'a ExpressionStore, - coroutines: &'a mut Vec, + struct CoroutinesVisitor<'a, 'db> { + db: &'db dyn HirDatabase, + owner: InferBodyId<'db>, + store: &'db ExpressionStore, + coroutines: &'a mut Vec>, } - impl StoreVisitor for CoroutinesVisitor<'_> { + impl<'db> StoreVisitor for CoroutinesVisitor<'_, 'db> { fn on_expr(&mut self, expr: ExprId) { if let hir_def::hir::Expr::Closure { closure_kind: @@ -2266,7 +2267,10 @@ impl<'db> DbInterner<'db> { } } -fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates { +fn predicates_of<'db>( + db: &'db dyn HirDatabase, + def_id: SolverDefId<'db>, +) -> &'db GenericPredicates { match def_id { SolverDefId::BuiltinDeriveImplId(impl_) => crate::builtin_derive::predicates(db, impl_), SolverDefId::AnonConstId(anon_const) => { @@ -2321,13 +2325,13 @@ macro_rules! TrivialTypeTraversalImpls { } TrivialTypeTraversalImpls! { - SolverDefId, + SolverDefId<'_>, TraitIdWrapper, TypeAliasIdWrapper, CallableIdWrapper, - ClosureIdWrapper, - CoroutineIdWrapper, - CoroutineClosureIdWrapper, + ClosureIdWrapper<'_>, + CoroutineIdWrapper<'_>, + CoroutineClosureIdWrapper<'_>, AdtIdWrapper, TraitAssocTyId, TraitAssocConstId, @@ -2341,9 +2345,9 @@ TrivialTypeTraversalImpls! { InherentAssocTyId, InherentAssocConstId, InherentAssocTermId, - OpaqueTyIdWrapper, + OpaqueTyIdWrapper<'_>, AnyImplId, - GeneralConstIdWrapper, + GeneralConstIdWrapper<'_>, Safety, Span, ParamConst, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs index bdb3f3087103e..dd5f72979515f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs @@ -30,8 +30,8 @@ interned_slice!( SolverDefIds, StoredSolverDefIds, def_ids, - SolverDefId, - SolverDefId, + SolverDefId<'db>, + SolverDefId<'static>, ); impl_foldable_for_interned_slice!(SolverDefIds); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index dc753a1b47667..a6facff7623d8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -77,7 +77,7 @@ impl<'db> Region<'db> { pub fn new_late_param( interner: DbInterner<'db>, - scope: SolverDefId, + scope: SolverDefId<'db>, bound_region: BoundRegion<'db>, ) -> Region<'db> { let late_bound_region = LateParamRegion { scope, bound_region }; @@ -169,7 +169,7 @@ pub struct EarlyParamRegion { /// This denotes some region at least as big as `scope`. It is similar to a placeholder region /// created when entering a binder, except it always lives in the root universe. pub struct LateParamRegion<'db> { - pub scope: SolverDefId, + pub scope: SolverDefId<'db>, pub bound_region: BoundRegion<'db>, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index b1b3a0e0dc78a..5486a565815de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -130,7 +130,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn add_item_bounds_for_hidden_type( &self, - opaque_id: OpaqueTyIdWrapper, + opaque_id: OpaqueTyIdWrapper<'_>, args: GenericArgs<'db>, param_env: ParamEnv<'db>, hidden_ty: Ty<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index d57d824e325fe..05f559c0349e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -43,7 +43,7 @@ use super::{ util::{FloatExt, IntegerExt}, }; -pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType; +pub type SimplifiedType<'db> = rustc_type_ir::fast_reject::SimplifiedType>; pub type TyKind<'db> = rustc_type_ir::TyKind>; pub type FnHeader<'db> = rustc_type_ir::FnHeader>; pub type AliasTyKind<'db> = rustc_type_ir::AliasTyKind>; @@ -176,7 +176,7 @@ impl<'db> Ty<'db> { pub fn new_opaque( interner: DbInterner<'db>, - def_id: InternedOpaqueTyId, + def_id: InternedOpaqueTyId<'db>, args: GenericArgs<'db>, ) -> Self { Ty::new_alias( @@ -1186,7 +1186,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Coroutine(def_id, args)) @@ -1194,7 +1194,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_closure( interner: DbInterner<'db>, - def_id: CoroutineClosureIdWrapper, + def_id: CoroutineClosureIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineClosure(def_id, args)) @@ -1202,7 +1202,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_closure( interner: DbInterner<'db>, - def_id: ClosureIdWrapper, + def_id: ClosureIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Closure(def_id, args)) @@ -1210,7 +1210,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) @@ -1218,7 +1218,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness_for_coroutine( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, coroutine_args: as Interner>::GenericArgs, ) -> Self { // HACK: Coroutine witness types are lifetime erased, so they diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index fb3bd18bf48ac..7e40e3c17d517 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -456,7 +456,7 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable>>( pub fn explicit_item_bounds<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, ) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { let db = interner.db(); let clauses = match def_id { @@ -469,7 +469,7 @@ pub fn explicit_item_bounds<'db>( pub fn explicit_item_self_bounds<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, ) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { let db = interner.db(); let clauses = match def_id { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs index dfd1fd96c6564..9cb0022ca6bfc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs @@ -20,10 +20,10 @@ use crate::{ }, }; -pub(crate) fn opaque_types_defined_by( - db: &dyn HirDatabase, - def_id: InferBodyId, - result: &mut Vec, +pub(crate) fn opaque_types_defined_by<'db>( + db: &'db dyn HirDatabase, + def_id: InferBodyId<'_>, + result: &mut Vec>, ) { if let Some(func) = def_id.as_function() { // A function may define its own RPITs. @@ -79,11 +79,11 @@ pub(crate) fn opaque_types_defined_by( // FIXME: Collect opaques from `#[define_opaque]`. - fn extend_with_opaques( - db: &dyn HirDatabase, + fn extend_with_opaques<'db>( + db: &'db dyn HirDatabase, opaques: &Option>>, mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId, - result: &mut Vec, + result: &mut Vec>, ) { if let Some(opaques) = opaques { for (opaque_idx, _) in (**opaques).as_ref().skip_binder().impl_traits.iter() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs index e4e76fa67bacb..ab2dca0455aa8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs @@ -29,7 +29,7 @@ pub struct SolverDiagnostic { pub enum SolverDiagnosticKind { TraitUnimplemented { trait_predicate: StoredTraitPredicate, - root_trait_predicate: Option, + parent_trait_predicates: Vec, }, } @@ -78,13 +78,19 @@ fn handle_trait_unimplemented<'db>( polarity: trait_pred.polarity, }; - let root_trait_predicate = match error.root_obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::Trait(trait_pred)) => Some(StoredTraitPredicate { - trait_ref: StoredTraitRef::new(trait_pred.trait_ref), - polarity: trait_pred.polarity, - }), - _ => None, - }; + let mut parent_trait_predicates = error + .parent_trait_obligations + .iter() + .filter_map(|predicate| predicate.as_trait_clause()) + .map(|trait_predicate| { + let trait_predicate = trait_predicate.skip_binder(); + StoredTraitPredicate { + trait_ref: StoredTraitRef::new(trait_predicate.trait_ref), + polarity: trait_predicate.polarity, + } + }) + .collect::>(); + parent_trait_predicates.reverse(); - Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, root_trait_predicate }) + Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, parent_trait_predicates }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 7bf22b93f7753..59fda51781d21 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -16,7 +16,7 @@ use syntax::TextRange; use test_utils::extract_annotations; use triomphe::Arc; -#[salsa_macros::db] +#[salsa::db] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, @@ -75,7 +75,7 @@ impl fmt::Debug for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) @@ -138,7 +138,7 @@ impl SourceDatabase for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for TestDB {} impl panic::RefUnwindSafe for TestDB {} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index febd2a833a6a7..c19a1f27af96e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -204,7 +204,7 @@ fn check_impl( _ => None, }); for (expr_or_pat, expected, actual) in type_mismatches { - let Some(node) = (match expr_or_pat { + let Some(node) = (match expr_or_pat.unpack() { hir_def::hir::ExprOrPatId::ExprId(expr) => { expr_node(body_source_map, expr, &db) } @@ -324,7 +324,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { crate::attach_db(&db, || { let mut buf = String::new(); - let mut infer_def = |inference_result: &InferenceResult, + let mut infer_def = |inference_result: &InferenceResult<'_>, store: &ExpressionStore, source_map: &ExpressionStoreSourceMap, self_param: Option<( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 1fc556d04d019..c951a5481c460 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -125,7 +125,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec .info .sources .iter() - .flat_map(|span| match span.final_source() { + .flat_map(|span| match span.final_source().unpack() { ExprOrPatId::ExprId(expr) => { vec![text_range(db, source_map.expr_syntax(expr).unwrap())] } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index db06d55278b2b..6d4ad930702df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -87,6 +87,24 @@ fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { ); } +#[test] +fn coerce_pointee_derive() { + check_no_mismatches( + r#" +//- minicore: coerce_pointee +use core::marker::CoercePointee; + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Pointer(*const T); + +fn coerce(value: Pointer<[u8; 1]>) -> Pointer<[u8]> { + value +} +"#, + ); +} + #[test] fn unsized_from_keeps_type_info() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index 5a4a6562ad3e9..fe7327134903e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &(dyn Foo<'?> + 'static) + // ^^^ &(dyn Foo<'_> + 'static) "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 3432d47b2f54c..08efef10ee78a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -28,16 +28,16 @@ fn foo() -> i32 { } }); }, - &[("InferenceResult::for_body_", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -74,10 +74,10 @@ fn foo() -> i32 { } }); }, - &[("InferenceResult::for_body_", 0)], + &[("InferenceResult < 'db >::for_body_", 0)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -117,16 +117,16 @@ fn baz() -> i32 { } }); }, - &[("InferenceResult::for_body_", 3)], + &[("InferenceResult < 'db >::for_body_", 3)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -139,7 +139,7 @@ fn baz() -> i32 { "ImplTraits::return_type_impl_traits_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -150,7 +150,7 @@ fn baz() -> i32 { "ImplTraits::return_type_impl_traits_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -190,10 +190,10 @@ fn baz() -> i32 { } }); }, - &[("InferenceResult::for_body_", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -207,7 +207,7 @@ fn baz() -> i32 { "FunctionSignature::of_", "Body::with_source_map_", "Body::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", "AttrFlags::query_", @@ -241,16 +241,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -280,15 +280,15 @@ pub struct NewStruct { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -316,16 +316,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -356,15 +356,15 @@ pub enum SomeEnum { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -392,16 +392,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -429,15 +429,15 @@ fn bar() -> f32 { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -469,16 +469,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -514,15 +514,15 @@ impl SomeStruct { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -570,6 +570,7 @@ fn main() { let _inference_result = InferenceResult::of(&db, def); } }, + // FIXME: What does this test check for now? trait_solve_shim is no longer a query &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ @@ -577,14 +578,14 @@ fn main() { "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "TraitItems::query_with_diagnostics_", "Body::of_", "Body::with_source_map_", "AttrFlags::query_", "ImplItems::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "TraitSignature::of_", "TraitSignature::with_source_map_", "AttrFlags::query_", @@ -600,7 +601,7 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "trait_environment_query", @@ -611,10 +612,10 @@ fn main() { "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", - "InherentImpls::for_crate_", + "InherentImpls < 'db >::for_crate_", "callable_item_signature_with_diagnostics", - "TraitImpls::for_crate_and_deps_", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_and_deps_", + "TraitImpls < 'db >::for_crate_", "impl_trait_with_diagnostics", "ImplSignature::of_", "ImplSignature::with_source_map_", @@ -670,7 +671,7 @@ fn main() { &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -680,7 +681,7 @@ fn main() { "AttrFlags::query_", "Body::of_", "ImplItems::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "AttrFlags::query_", "TraitSignature::with_source_map_", "AttrFlags::query_", @@ -693,7 +694,7 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::with_source_map_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -701,9 +702,9 @@ fn main() { "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", - "InherentImpls::for_crate_", + "InherentImpls < 'db >::for_crate_", "callable_item_signature_with_diagnostics", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "ImplSignature::with_source_map_", "ImplSignature::of_", "impl_trait_with_diagnostics", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index fd21286d50835..9d98218107106 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -901,3 +901,19 @@ fn example() -> Struct { "#, ); } + +#[test] +fn never_await() { + check_no_mismatches( + r#" +//- minicore: future +async fn test() -> ! { + loop {} +} + +pub async fn test1() -> ! { + test().await; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index dc882311871fb..c580841244f1b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -6,6 +6,16 @@ use crate::tests::check; use super::{check_infer, check_no_mismatches, check_types}; +#[test] +fn closure_in_enum_discriminant_does_not_panic() { + check( + r#" + enum Enum { X = || {} } + // ^^^^^ expected isize, got impl Fn() + "#, + ); +} + #[test] fn bug_484() { check_infer( @@ -2993,3 +3003,16 @@ fn f() {[_; || ()]} "#, ); } + +#[test] +fn regression_22795() { + check_no_mismatches( + r#" +trait T { fn m(&self); } +impl T for Self::Self {} +struct S; +impl T for S { fn m(&self) {} } +fn f(s: S) { s.m(); } + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 121e3959ce23a..97f83ca0362e0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -10,6 +10,23 @@ use crate::{ tests::{check_infer, check_no_mismatches, check_types}, }; +#[test] +fn nested_argument_position_impl_trait_captures_lifetime() { + check_no_mismatches( + r#" +//- minicore: iterator +trait Trait<'a> {} + +fn f<'a>(_values: impl IntoIterator>) {} + +fn crash<'a>(expr: &'a (), values: impl IntoIterator>) -> &'a () { + f(values); + expr +} +"#, + ); +} + #[test] fn liberating_distinct_late_bound_lifetimes_preserves_identity() { let (db, file_id) = TestDB::with_single_file( @@ -275,63 +292,6 @@ fn debug(_: &dyn Foo) {} impl Foo for i32 {} -fn main() { - debug(&1); -}"#, - ); - - // toolchains <= 1.88.0, before sized-hierarchy. - check_no_mismatches( - r#" -#![feature(lang_items)] -#[lang = "sized"] -pub trait Sized {} - -#[lang = "unsize"] -pub trait Unsize {} - -#[lang = "coerce_unsized"] -pub trait CoerceUnsized {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} - -impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} - -impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} - -impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} - -impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} - -impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} - -#[lang = "dispatch_from_dyn"] -pub trait DispatchFromDyn {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} - -impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} - -impl, 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); }"#, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index d7b7e4783978e..e8f378db3228a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2879,6 +2879,10 @@ unsafe impl Allocator for Global {} #[fundamental] pub struct Box(T, A); +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} pub struct Vec(T, A); @@ -2895,8 +2899,8 @@ impl [T] { } fn test() { - let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32])); - let v: Vec> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)])); + let vec = <[_]>::into_vec(box_new([1i32])); + let v: Vec> = <[_]> :: into_vec(box_new([box_new(Astruct)])); } trait B{} @@ -2904,22 +2908,26 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 639..643 'self': Box<[T], A> - 672..704 '{ ... }': Vec - 718..888 '{ ...])); }': () - 728..731 'vec': Vec - 734..749 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 734..780 '<[_]>:...i32]))': Vec - 750..779 '#[rust...1i32])': Box<[i32; 1], Global> - 772..778 '[1i32]': [i32; 1] - 773..777 '1i32': i32 - 790..791 'v': Vec, Global> - 811..828 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 811..885 '<[_]> ...ct)]))': Vec, Global> - 829..884 '#[rust...uct)])': Box<[Box; 1], Global> - 851..883 '[#[rus...ruct)]': [Box; 1] - 852..882 '#[rust...truct)': Box - 874..881 'Astruct': Astruct + 428..430 '_x': T + 733..737 'self': Box<[T], A> + 766..798 '{ ... }': Vec + 812..940 '{ ...])); }': () + 822..825 'vec': Vec + 828..843 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec + 828..860 '<[_]>:...i32]))': Vec + 844..851 'box_new': fn box_new<[i32; 1]>([i32; 1]) -> Box<[i32; 1], Global> + 844..859 'box_new([1i32])': Box<[i32; 1], Global> + 852..858 '[1i32]': [i32; 1] + 853..857 '1i32': i32 + 870..871 'v': Vec, Global> + 891..908 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 891..937 '<[_]> ...ct)]))': Vec, Global> + 909..916 'box_new': fn box_new<[Box; 1]>([Box; 1]) -> Box<[Box; 1], Global> + 909..936 'box_ne...uct)])': Box<[Box; 1], Global> + 917..935 '[box_n...ruct)]': [Box; 1] + 918..925 'box_new': fn box_new(Astruct) -> Box + 918..934 'box_ne...truct)': Box + 926..933 'Astruct': Astruct "#]], ) } @@ -4359,3 +4367,82 @@ fn check() { "#]], ); } + +#[test] +fn hrtb_fn_ptr() { + check_infer( + r#" +//- minicore: fn + +fn foo<'b>(f: for <'a> fn(&'a u32, &'b u32)) {} +"#, + expect![[r#" + 12..13 'f': fn(&'_ u32, &'_ u32) + 46..48 '{}': () + "#]], + ); +} + +#[test] +fn hrtb_with_where_predicate() { + check_no_mismatches( + r#" +trait Echo<'a> { + fn echo(&self, s: &'a str) -> &'a str; +} + +struct Bot; + +// Implement Echo<'b> for &'a Bot — independent of both 'a and 'b +impl<'a, 'b> Echo<'b> for &'a Bot { + fn echo(&self, s: &'b str) -> &'b str { + s + } +} + +fn foo(val: T) +where + for<'a, 'b> &'a T: Echo<'b>, +{ + let owned = String::from(" hello "); + let v = (&val).echo(&owned)); +} +"#, + ); +} + +#[test] +fn nested() { + check_no_mismatches( + r#" +//- minicore: fn +#![feature(lang_items)] +#[lang = "owned_box"] +struct Box(T); + +fn execute_nested_closures(f: F) +where + for<'a> F: Fn(&'a str) -> Box Fn(&'b str) + 'a>, +{ +} +"#, + ); +} + +#[test] +fn diff_nested() { + check_no_mismatches( + r#" +//- minicore: fn +#![feature(lang_items)] +#[lang = "owned_box"] +struct Box(T); + +fn foo_fn(f: F) +where + F: for<'a> Fn(&'a str) -> Box Fn(&'a &'b str) + 'a>, +{ +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 6e61fcaa5d70b..8233a009816fc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -2241,13 +2241,13 @@ fn tuple_struct_constructor_as_fn_trait() { check_types( r#" //- minicore: fn -struct S(u32, u64); +struct S(T, U); -fn takes_fn S>(f: F) -> S { f(1, 2) } +fn takes_fn S>(f: F) -> S { f(1, 2) } fn test() { takes_fn(S); - //^^^^^^^^^^^ S + //^^^^^^^^^^^ S } "#, ); @@ -2258,13 +2258,13 @@ fn enum_variant_constructor_as_fn_trait() { check_types( r#" //- minicore: fn -enum E { A(u32) } +enum E { A(T) } -fn takes_fn E>(f: F) -> E { f(1) } +fn takes_fn E>(f: F) -> E { f(1) } fn test() { takes_fn(E::A); - //^^^^^^^^^^^^^^ E + //^^^^^^^^^^^^^^ E } "#, ); @@ -5339,3 +5339,41 @@ fn foo() { "#, ); } + +#[test] +fn hrtb_impl_trait() { + check_infer( + r#" +trait Trait<'a> {} + +struct Foo; + +impl<'a> Trait<'a> for Bot {} + +fn impl_fn(val: impl for<'a> Trait<'a>) {} +"#, + expect![[r#" + 75..78 'val': impl Trait<'?0.0> + ?Sized + 104..106 '{}': () + "#]], + ); +} + +#[test] +fn hrtb_dyn_trait() { + check_infer( + r#" +trait Trait<'a, 'b> {} + +struct Foo; + +impl<'a, 'b> Trait<'a, 'b> for Foo {} + +fn run_dyn<'b>(val: &dyn for<'a> Trait<'a, 'b>) {} +"#, + expect![[r#" + 91..94 'val': &'? (dyn Trait<'_, '_> + 'static) + 124..126 '{}': () + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 935f541841d26..108e3e07a666a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -61,13 +61,13 @@ pub struct StoredParamEnvAndCrate { impl StoredParamEnvAndCrate { #[inline] - pub fn param_env(&self) -> ParamEnv<'_> { + pub fn param_env<'db>(&self, _db: &'db dyn HirDatabase) -> ParamEnv<'db> { ParamEnv { clauses: self.param_env.as_ref() } } #[inline] - pub fn as_ref(&self) -> ParamEnvAndCrate<'_> { - ParamEnvAndCrate { param_env: self.param_env(), krate: self.krate } + pub fn as_ref<'db>(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: self.param_env(db), krate: self.krate } } } @@ -175,7 +175,7 @@ pub enum WherePredicateEvaluation { pub fn where_predicate_must_hold<'db>( db: &'db dyn HirDatabase, resolver: &Resolver<'db>, - store: &ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, env: ParamEnvAndCrate<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 764d02ccf1d88..53d7231562819 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -19,26 +19,6 @@ use crate::{ mir::pad16, }; -/// SAFETY: `old_pointer` must be valid for unique writes -pub(crate) unsafe fn unsafe_update_eq(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(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator + '_ { [lang_items.Fn, lang_items.FnMut, lang_items.FnOnce].into_iter().flatten() } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 89021441892c6..a9575a93dbeee 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -22,6 +22,7 @@ smallvec.workspace = true tracing = { workspace = true, features = ["attributes"] } triomphe.workspace = true la-arena.workspace = true +salsa.workspace = true ra-ap-rustc_type_ir.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index b921a5eef14a9..d0801d8efd03e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -137,7 +137,7 @@ diagnostics![AnyDiagnostic<'db> -> MovedOutOfRef<'db>, MutRefInImmRefPat, MutableRefBinding, - NeedMut, + NeedMut<'db>, NonExhaustiveLet, NonExhaustiveRecordExpr, NonExhaustiveRecordPat, @@ -168,8 +168,8 @@ diagnostics![AnyDiagnostic<'db> -> UnresolvedMethodCall<'db>, UnresolvedModule, UnresolvedIdent, - UnusedMut, - UnusedVariable, + UnusedMut<'db>, + UnusedVariable<'db>, GenericArgsProhibited, ParenthesizedGenericArgsWithoutFnTrait, BadRtn, @@ -474,19 +474,19 @@ pub struct TypeMismatch<'db> { } #[derive(Debug)] -pub struct NeedMut { - pub local: Local, +pub struct NeedMut<'db> { + pub local: Local<'db>, pub span: InFile, } #[derive(Debug)] -pub struct UnusedMut { - pub local: Local, +pub struct UnusedMut<'db> { + pub local: Local<'db>, } #[derive(Debug)] -pub struct UnusedVariable { - pub local: Local, +pub struct UnusedVariable<'db> { + pub local: Local<'db>, } #[derive(Debug)] @@ -677,7 +677,7 @@ pub struct PatternArgInExternFn { pub struct UnimplementedTrait<'db> { pub span: SpanSyntax, pub trait_predicate: crate::TraitPredicate<'db>, - pub root_trait_predicate: Option>, + pub parent_trait_predicates: Vec>, } #[derive(Debug)] @@ -835,7 +835,7 @@ impl<'db> AnyDiagnostic<'db> { d: &'db InferenceDiagnostic, source_map: &hir_def::expr_store::BodySourceMap, sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, - type_owner: TypeOwnerId, + type_owner: TypeOwnerId<'db>, ) -> Option> { let expr_syntax = |expr| Self::expr_syntax(expr, source_map); let pat_syntax = |pat| Self::pat_syntax(pat, source_map); @@ -847,7 +847,7 @@ impl<'db> AnyDiagnostic<'db> { let span_syntax = |span| Self::span_syntax(span, source_map); Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { - let expr_or_pat = match expr { + let expr_or_pat = match expr.unpack() { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) } @@ -877,7 +877,7 @@ impl<'db> AnyDiagnostic<'db> { InvalidRangePatType { pat }.into() } &InferenceDiagnostic::DuplicateField { field: expr, variant } => { - let expr_or_pat = match expr { + let expr_or_pat = match expr.unpack() { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) } @@ -894,7 +894,7 @@ impl<'db> AnyDiagnostic<'db> { PrivateField { expr, field }.into() } &InferenceDiagnostic::PrivateAssocItem { id, item } => { - let expr_or_pat = expr_or_pat_syntax(id)?; + let expr_or_pat = expr_or_pat_syntax(id.unpack())?; let item = item.into(); PrivateAssocItem { expr_or_pat, item }.into() } @@ -937,11 +937,11 @@ impl<'db> AnyDiagnostic<'db> { .into() } &InferenceDiagnostic::UnresolvedAssocItem { id } => { - let expr_or_pat = expr_or_pat_syntax(id)?; + let expr_or_pat = expr_or_pat_syntax(id.unpack())?; UnresolvedAssocItem { expr_or_pat }.into() } &InferenceDiagnostic::UnresolvedIdent { id } => { - let node = match id { + let node = match id.unpack() { ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) { Ok(syntax) => syntax.map(|it| (it, None)), Err(SyntheticSyntax) => source_map @@ -1019,7 +1019,7 @@ impl<'db> AnyDiagnostic<'db> { Self::ty_diagnostic(diag, source_map, db)? } InferenceDiagnostic::PathDiagnostic { node, diag } => { - let source = expr_or_pat_syntax(*node)?; + let source = expr_or_pat_syntax(node.unpack())?; let syntax = source.value.to_node(&source.file_id.parse_or_expand(db)); let path = match_ast! { match (syntax.syntax()) { @@ -1100,7 +1100,7 @@ impl<'db> AnyDiagnostic<'db> { UnionExprMustHaveExactlyOneField { expr }.into() } InferenceDiagnostic::TypeMismatch { node, expected, found } => { - let expr_or_pat = expr_or_pat_syntax(*node)?; + let expr_or_pat = expr_or_pat_syntax(node.unpack())?; TypeMismatch { expr_or_pat, expected: Type { owner: type_owner, ty: EarlyBinder::bind(expected.as_ref()) }, @@ -1120,7 +1120,7 @@ impl<'db> AnyDiagnostic<'db> { Either::Left(expr) } ExplicitDropMethodUseKind::Path(path_expr_id) => { - let syntax = expr_or_pat_syntax(*path_expr_id)?; + let syntax = expr_or_pat_syntax(path_expr_id.unpack())?; let file_id = syntax.file_id; let syntax = syntax.with_value(syntax.value.cast::()?).to_node(db); @@ -1141,6 +1141,52 @@ impl<'db> AnyDiagnostic<'db> { &InferenceDiagnostic::ReturnOutsideFunction { expr, kind } => { ReturnOutsideFunction { expr: expr_syntax(expr)?, kind }.into() } + &InferenceDiagnostic::RecordMissingFields { record, variant, ref missed_fields } => { + let record = expr_or_pat_syntax(record)?; + let file = record.file_id; + let root = record.file_syntax(db); + let variant_data = variant.fields(db); + let missed_fields = missed_fields + .iter() + .map(|&idx| { + ( + variant_data.fields()[idx].name.clone(), + Field { parent: variant.into(), id: idx }, + ) + }) + .collect(); + match record.value.to_node(&root) { + Either::Left(ast::Expr::RecordExpr(record_expr)) + if record_expr.record_expr_field_list().is_some() => + { + let field_list_parent_path = + record_expr.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Left(record_expr)), + field_list_parent_path, + missed_fields, + } + .into(), + ); + } + Either::Right(ast::Pat::RecordPat(record_pat)) + if record_pat.record_pat_field_list().is_some() => + { + let field_list_parent_path = + record_pat.path().map(|path| AstPtr::new(&path)); + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Right(record_pat)), + field_list_parent_path, + missed_fields, + } + .into() + } + _ => return None, + } + } }) } @@ -1148,23 +1194,26 @@ impl<'db> AnyDiagnostic<'db> { db: &'db dyn HirDatabase, d: &'db SolverDiagnosticKind, span: SpanSyntax, - type_owner: TypeOwnerId, + type_owner: TypeOwnerId<'db>, ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { - SolverDiagnosticKind::TraitUnimplemented { trait_predicate, root_trait_predicate } => { + SolverDiagnosticKind::TraitUnimplemented { + trait_predicate, + parent_trait_predicates, + } => { let trait_predicate = crate::TraitPredicate { inner: trait_predicate.get(interner), owner: type_owner, }; - let root_trait_predicate = - root_trait_predicate.as_ref().map(|root_trait_predicate| { - crate::TraitPredicate { - inner: root_trait_predicate.get(interner), - owner: type_owner, - } - }); - UnimplementedTrait { span, trait_predicate, root_trait_predicate }.into() + let parent_trait_predicates = parent_trait_predicates + .iter() + .map(|trait_predicate| crate::TraitPredicate { + inner: trait_predicate.get(interner), + owner: type_owner, + }) + .collect(); + UnimplementedTrait { span, trait_predicate, parent_trait_predicates }.into() } }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 06fa91804ddee..dc35a5c57bec4 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -532,7 +532,7 @@ impl<'db> HirDisplay<'db> for Field { } } -impl<'db> HirDisplay<'db> for TupleField { +impl<'db> HirDisplay<'db> for TupleField<'db> { 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) @@ -806,10 +806,6 @@ fn write_where_predicates<'db>( let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) { (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2, (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2, - ( - ForLifetime { lifetimes: l1, target: t1, .. }, - ForLifetime { lifetimes: l2, target: t2, .. }, - ) => l1 == l2 && t1 == t2, _ => false, }; @@ -821,7 +817,12 @@ fn write_where_predicates<'db>( f.write_str("\n ")?; match pred { - TypeBound { target, bound } => { + TypeBound { lifetimes, target, bound } => { + if let Some(lifetimes) = lifetimes { + let lifetimes = + lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", "); + write!(f, "for<{lifetimes}> ")?; + } target.hir_fmt(f, owner, store)?; f.write_str(": ")?; bound.hir_fmt(f, owner, store)?; @@ -831,21 +832,12 @@ fn write_where_predicates<'db>( write!(f, ": ")?; bound.hir_fmt(f, owner, store)?; } - ForLifetime { lifetimes, target, bound } => { - let lifetimes = lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", "); - write!(f, "for<{lifetimes}> ")?; - target.hir_fmt(f, owner, store)?; - f.write_str(": ")?; - bound.hir_fmt(f, owner, store)?; - } } while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { f.write_str(" + ")?; match nxt { - TypeBound { bound, .. } | ForLifetime { bound, .. } => { - bound.hir_fmt(f, owner, store)? - } + TypeBound { bound, .. } => bound.hir_fmt(f, owner, store)?, Lifetime { bound, .. } => bound.hir_fmt(f, owner, store)?, } } diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index 219eb9c3b9268..9b07aa494e448 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -7,8 +7,10 @@ use hir_def::{ AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, + item_scope::ItemInNs as ItemInNsId, }; use hir_ty::next_solver::AnyImplId; +use stdx::impl_from; use crate::{ Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, EnumVariant, ExpressionStoreOwner, @@ -51,54 +53,28 @@ from_id![ (hir_def::ExternBlockId, crate::ExternBlock), ]; -impl From for Adt { - fn from(id: AdtId) -> Self { - match id { - AdtId::StructId(it) => Adt::Struct(it.into()), - AdtId::UnionId(it) => Adt::Union(it.into()), - AdtId::EnumId(it) => Adt::Enum(it.into()), - } - } -} - -impl From for AdtId { - fn from(id: Adt) -> Self { - match id { - Adt::Struct(it) => AdtId::StructId(it.id), - Adt::Union(it) => AdtId::UnionId(it.id), - Adt::Enum(it) => AdtId::EnumId(it.id), - } - } -} - -impl From for Variant { - fn from(v: VariantId) -> Self { - match v { - VariantId::EnumVariantId(it) => Variant::EnumVariant(it.into()), - VariantId::StructId(it) => Variant::Struct(it.into()), - VariantId::UnionId(it) => Variant::Union(it.into()), - } +impl_from!(AdtId { StructId => Struct, UnionId => Union, EnumId => Enum } for Adt); +impl_from!(Adt { Struct => StructId, Union => UnionId, Enum => EnumId } for AdtId); +impl_from!( + VariantId { EnumVariantId => EnumVariant, StructId => Struct, UnionId => Union } + for Variant +); +impl_from!( + GenericParamId { + TypeParamId => TypeParam, + ConstParamId => ConstParam, + LifetimeParamId => LifetimeParam, } -} -impl From for GenericParam { - fn from(id: GenericParamId) -> Self { - match id { - GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), - GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), - GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), - } + for GenericParam +); +impl_from!( + GenericParam { + LifetimeParam => LifetimeParamId, + ConstParam => ConstParamId, + TypeParam => TypeParamId, } -} - -impl From for GenericParamId { - fn from(id: GenericParam) -> Self { - match id { - GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), - GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), - GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), - } - } -} + for GenericParamId +); impl From for EnumVariant { fn from(id: EnumVariantId) -> Self { @@ -112,22 +88,21 @@ impl From for EnumVariantId { } } -impl From for ModuleDef { - fn from(id: ModuleDefId) -> Self { - match id { - ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()), - ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()), - ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()), - ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()), - ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), - ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), - ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), - ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), - ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it.into()), - ModuleDefId::MacroId(it) => ModuleDef::Macro(it.into()), - } +impl_from!( + ModuleDefId { + ModuleId => Module, + FunctionId => Function, + AdtId => Adt, + EnumVariantId => EnumVariant, + ConstId => Const, + StaticId => Static, + TraitId => Trait, + TypeAliasId => TypeAlias, + BuiltinType => BuiltinType, + MacroId => Macro, } -} + for ModuleDef +); impl TryFrom for ModuleDefId { type Error = (); @@ -165,26 +140,19 @@ impl TryFrom for DefWithBodyId { } } -impl From for DefWithBody { - fn from(def: DefWithBodyId) -> Self { - match def { - DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()), - DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), - DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), - DefWithBodyId::VariantId(it) => DefWithBody::EnumVariant(it.into()), - } +impl_from!( + DefWithBodyId { + FunctionId => Function, + StaticId => Static, + ConstId => Const, + VariantId => EnumVariant, } -} - -impl From for AssocItem { - fn from(def: AssocItemId) -> Self { - match def { - AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), - AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), - AssocItemId::ConstId(it) => AssocItem::Const(it.into()), - } - } -} + for DefWithBody +); +impl_from!( + AssocItemId { FunctionId => Function, TypeAliasId => TypeAlias, ConstId => Const } + for AssocItem +); impl TryFrom for GenericDefId { type Error = (); @@ -194,19 +162,18 @@ impl TryFrom for GenericDefId { } } -impl From for GenericDef { - fn from(def: GenericDefId) -> Self { - match def { - GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), - GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), - GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), - GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), - GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), - GenericDefId::ConstId(it) => GenericDef::Const(it.into()), - GenericDefId::StaticId(it) => GenericDef::Static(it.into()), - } +impl_from!( + GenericDefId { + FunctionId => Function, + AdtId => Adt, + TraitId => Trait, + TypeAliasId => TypeAlias, + ImplId => Impl, + ConstId => Const, + StaticId => Static, } -} + for GenericDef +); impl From for GenericDefId { fn from(id: Adt) -> Self { @@ -218,15 +185,10 @@ impl From for GenericDefId { } } -impl From for VariantId { - fn from(def: Variant) -> Self { - match def { - Variant::Struct(it) => VariantId::StructId(it.id), - Variant::EnumVariant(it) => VariantId::EnumVariantId(it.into()), - Variant::Union(it) => VariantId::UnionId(it.id), - } - } -} +impl_from!( + Variant { Struct => StructId, EnumVariant => EnumVariantId, Union => UnionId } + for VariantId +); impl From for FieldId { fn from(def: Field) -> Self { @@ -254,7 +216,7 @@ impl TryFrom for GenericDefId { } } -impl From<(DefWithBodyId, BindingId)> for Local { +impl<'db> From<(DefWithBodyId, BindingId)> for Local<'db> { fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { Local { parent: parent.into(), parent_infer: parent.into(), binding_id } } @@ -266,15 +228,7 @@ impl From<(ExpressionStoreOwnerId, LabelId)> for Label { } } -impl From for ItemInNs { - fn from(it: hir_def::item_scope::ItemInNs) -> Self { - match it { - hir_def::item_scope::ItemInNs::Types(it) => ItemInNs::Types(it.into()), - hir_def::item_scope::ItemInNs::Values(it) => ItemInNs::Values(it.into()), - hir_def::item_scope::ItemInNs::Macros(it) => ItemInNs::Macros(it.into()), - } - } -} +impl_from!(ItemInNsId { Types => Types, Values => Values, Macros => Macros } for ItemInNs); impl TryFrom for hir_def::item_scope::ItemInNs { type Error = (); diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 9248aaec02097..3a6e19636a0b5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -265,7 +265,7 @@ impl HasSource for LifetimeParam { } } -impl HasSource for LocalSource { +impl HasSource for LocalSource<'_> { type Ast = Either; fn source(self, _: &dyn HirDatabase) -> Option> { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ba73c180c319..70e2d3faf1602 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -416,15 +416,10 @@ impl_from!( for ModuleDef ); -impl From for ModuleDef { - fn from(var: Variant) -> Self { - match var { - Variant::Struct(t) => Adt::from(t).into(), - Variant::Union(t) => Adt::from(t).into(), - Variant::EnumVariant(t) => t.into(), - } - } -} +impl_from!( + Variant { Struct => Adt, Union => Adt, EnumVariant => EnumVariant } + for ModuleDef +); impl ModuleDef { pub fn module(self, db: &dyn HirDatabase) -> Option { @@ -443,12 +438,9 @@ impl ModuleDef { } pub fn canonical_path(&self, db: &dyn HirDatabase, edition: Edition) -> Option { - let mut segments = vec![self.name(db)?]; - for m in self.module(db)?.path_to_root(db) { - segments.extend(m.name(db)) - } - segments.reverse(); - Some(segments.iter().map(|it| it.display(db, edition)).join("::")) + let name = self.name(db)?; + let segments = self.module(db)?.path_segments(db).chain(Some(name)); + Some(segments.map(|it| it.display(db, edition).to_string()).join("::")) } pub fn canonical_module_path( @@ -684,6 +676,20 @@ impl Module { res } + /// Names of the modules enclosing `self`, crate root first, `self` last. + /// + /// Nameless modules — the crate root, and block modules — drop out, so this is + /// generally shorter than [`Module::path_to_root`]. Segments stay `Name`s rather + /// than rendered text because callers disagree on the edition to display with, + /// and some need to take the path apart rather than print it. + /// + /// [`ModuleDef::canonical_module_path`] is the same walk yielding the `Module`s + /// themselves, for callers that need more than the name — each module's own + /// edition, say. + pub fn path_segments(self, db: &dyn HirDatabase) -> impl Iterator { + self.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)) + } + pub fn modules_in_scope(&self, db: &dyn HirDatabase, pub_only: bool) -> Vec<(Name, Module)> { let def_map = self.id.def_map(db); let scope = &def_map[self.id].scope; @@ -706,7 +712,7 @@ impl Module { self, db: &dyn HirDatabase, visible_from: Option, - ) -> Vec<(Name, ScopeDef)> { + ) -> Vec<(Name, ScopeDef<'_>)> { self.id.def_map(db)[self.id] .scope .entries() @@ -1070,15 +1076,9 @@ impl Module { db.impl_self_ty_with_diagnostics(impl_id).diagnostics(), source_map, ); - push_ty_diagnostics( - db, - acc, - db.impl_trait_with_diagnostics(impl_id) - .as_ref() - .map(|it| it.diagnostics()) - .unwrap_or_default(), - source_map, - ); + if let Some(it) = db.impl_trait_with_diagnostics(impl_id) { + push_ty_diagnostics(db, acc, it.diagnostics(), source_map); + } for &(_, item) in impl_id.impl_items(db).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); @@ -1367,18 +1367,18 @@ pub struct Field { } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub struct TupleField { - pub owner: InferBodyId, +pub struct TupleField<'db> { + pub owner: InferBodyId<'db>, pub tuple: TupleId, pub index: u32, } -impl TupleField { +impl<'db> TupleField<'db> { pub fn name(&self) -> Name { Name::new_tuple_field(self.index as usize) } - pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { + pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); let ty = InferenceResult::of(db, self.owner) .tuple_field_access_type(self.tuple) @@ -1703,7 +1703,7 @@ impl EnumVariant { self.source(db)?.value.const_arg()?.expr() } - pub fn eval(self, db: &dyn HirDatabase) -> Result { + pub fn eval(self, db: &dyn HirDatabase) -> Result> { db.const_eval_discriminant(self.into()) } @@ -1870,21 +1870,24 @@ impl Variant { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AnonConst { - id: AnonConstId, +pub struct AnonConst<'db> { + id: AnonConstId<'db>, } -impl AnonConst { +impl<'db> AnonConst<'db> { pub fn owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwner { self.id.loc(db).owner.into() } - pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let loc = self.id.loc(db); Type { owner: self.id.into(), ty: loc.ty.get() } } - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval( + self, + db: &'db dyn HirDatabase, + ) -> Result, ConstEvalError<'db>> { let interner = DbInterner::new_no_crate(db); let ty = self.id.loc(db).ty.get().instantiate_identity().skip_norm_wip(); db.anon_const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { @@ -1896,9 +1899,9 @@ impl AnonConst { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum InferBody { +pub enum InferBody<'db> { Body(DefWithBody), - AnonConst(AnonConst), + AnonConst(AnonConst<'db>), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -1920,19 +1923,14 @@ impl From for ExpressionStoreOwner { } } -impl From for ExpressionStoreOwner { - fn from(v: ExpressionStoreOwnerId) -> Self { - match v { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - Self::Signature(generic_def_id.into()) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => Self::Body(def_with_body_id.into()), - ExpressionStoreOwnerId::VariantFields(variant_id) => { - Self::VariantFields(variant_id.into()) - } - } +impl_from!( + ExpressionStoreOwnerId { + Signature => Signature, + Body => Body, + VariantFields => VariantFields, } -} + for ExpressionStoreOwner +); impl ExpressionStoreOwner { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1996,7 +1994,7 @@ impl DefWithBody { } #[deprecated = "you should really not use this, this is exported for analysis-stats only"] - pub fn run_mir_body(self, db: &dyn HirDatabase) -> Result<(), MirLowerError> { + pub fn run_mir_body(self, db: &dyn HirDatabase) -> Result<(), MirLowerError<'_>> { let Some(id) = self.id() else { return Ok(()) }; db.mir_body(id.into()).map(drop) } @@ -2375,7 +2373,7 @@ impl Function { } } - fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, PolyFnSig<'db>) { + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, PolyFnSig<'db>) { let fn_ptr = self.fn_ptr_type(db); let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.skip_binder().kind() else { unreachable!(); @@ -2383,7 +2381,7 @@ impl Function { (fn_ptr.owner, sig_tys.with(hdr)) } - fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, FnSig<'db>) { + fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, FnSig<'db>) { let (owner, sig) = self.fn_sig(db); let sig = DbInterner::new_no_crate(db).instantiate_bound_regions_with_erased(sig); (owner, sig) @@ -2646,7 +2644,7 @@ impl Function { self, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, - ) -> Result { + ) -> Result> { let AnyFunctionId::FunctionId(id) = self.id else { return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported( "evaluation of builtin derive impl methods is not supported".to_owned(), @@ -2739,7 +2737,7 @@ impl<'db> Param<'db> { Some(self.as_local(db)?.name(db)) } - pub fn as_local(&self, db: &dyn HirDatabase) -> Option { + pub fn as_local(&self, db: &'db dyn HirDatabase) -> Option> { match self.func { Callee::Def(CallableDefId::FunctionId(it)) => { let parent = DefWithBodyId::FunctionId(it); @@ -2926,7 +2924,7 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); db.const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { @@ -2944,7 +2942,7 @@ impl HasVisibility for Const { } pub struct EvaluatedConst<'db> { - def: InferBodyId, + def: InferBodyId<'db>, allocation: hir_ty::next_solver::Allocation<'db>, ty: Ty<'db>, } @@ -2954,7 +2952,7 @@ impl<'db> EvaluatedConst<'db> { format!("{}", self.allocation.display(db, display_target)) } - pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result { + pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result> { let ty = self.allocation.ty.kind(); if let TyKind::Int(_) | TyKind::Uint(_) = ty { let b = &self.allocation.memory; @@ -3007,7 +3005,7 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); db.const_eval_static(self.id).map(|it| EvaluatedConst { allocation: it, @@ -3475,17 +3473,21 @@ impl From for ItemInNs { } } -impl From for ItemInNs { - fn from(module_def: ModuleDef) -> Self { - match module_def { - ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { - ItemInNs::Values(module_def) - } - ModuleDef::Macro(it) => ItemInNs::Macros(it), - _ => ItemInNs::Types(module_def), - } - } -} +impl_from!( + ModuleDef { + Module => Types, + Function => Values, + Adt => Types, + EnumVariant => Types, + Const => Values, + Static => Values, + Trait => Types, + TypeAlias => Types, + BuiltinType => Types, + Macro => Macros, + } + for ItemInNs +); impl ItemInNs { pub fn into_module_def(self) -> ModuleDef { @@ -3828,15 +3830,7 @@ impl HasVisibility for AssocItem { } } -impl From for ModuleDef { - fn from(assoc: AssocItem) -> Self { - match assoc { - AssocItem::Function(it) => ModuleDef::Function(it), - AssocItem::Const(it) => ModuleDef::Const(it), - AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it), - } - } -} +impl_from!(AssocItem { Function, Const, TypeAlias } for ModuleDef); #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum GenericDef { @@ -4011,17 +4005,21 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] pub struct GenericSubstitution<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, def: GenericDefId, subst: GenericArgs<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId<'db>) -> Self { Self { owner, def, subst } } - fn new_from_fn(def: Function, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Option { + fn new_from_fn( + def: Function, + subst: GenericArgs<'db>, + owner: TypeOwnerId<'db>, + ) -> Option { match def.id { AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, owner)), AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, @@ -4082,18 +4080,18 @@ impl<'db> GenericSubstitution<'db> { /// A single local definition. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Local { +pub struct Local<'db> { pub(crate) parent: ExpressionStoreOwnerId, - pub(crate) parent_infer: InferBodyId, + pub(crate) parent_infer: InferBodyId<'db>, pub(crate) binding_id: BindingId, } -pub struct LocalSource { - pub local: Local, +pub struct LocalSource<'db> { + pub local: Local<'db>, pub source: InFile>, } -impl LocalSource { +impl<'db> LocalSource<'db> { pub fn as_ident_pat(&self) -> Option<&ast::IdentPat> { match &self.source.value { Either::Left(it) => Some(it), @@ -4129,7 +4127,7 @@ impl LocalSource { } } -impl Local { +impl<'db> Local<'db> { pub fn is_param(self, db: &dyn HirDatabase) -> bool { // FIXME: This parses! let src = self.primary_source(db); @@ -4184,7 +4182,7 @@ impl Local { self.binding_id.into_raw().into_u32() } - pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { + pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let def = self.parent; let infer = InferenceResult::of(db, self.parent_infer); let ty = infer.binding_ty(self.binding_id); @@ -4192,7 +4190,7 @@ impl Local { } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` - pub fn sources(self, db: &dyn HirDatabase) -> Vec { + pub fn sources(self, db: &dyn HirDatabase) -> Vec> { let b; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { @@ -4233,7 +4231,7 @@ impl Local { } /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` - pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource<'db> { let b; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { @@ -4274,13 +4272,13 @@ impl Local { } } -impl PartialOrd for Local { +impl PartialOrd for Local<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for Local { +impl Ord for Local<'_> { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.binding_id.cmp(&other.binding_id) } @@ -4743,7 +4741,7 @@ impl Impl { pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec { let module = trait_.module(db).id; let mut all = Vec::new(); - let mut handle_impls = |impls: &TraitImpls| { + let mut handle_impls = |impls: &TraitImpls<'_>| { impls.for_trait(trait_.id, |impls| match impls { Either::Left(impls) => all.extend(impls.iter().copied().map(Impl::from)), Either::Right(impls) => all.extend(impls.iter().copied().map(Impl::from)), @@ -4867,7 +4865,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4898,15 +4896,15 @@ impl<'db> TraitRef<'db> { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum AnyClosureId { - ClosureId(InternedClosureId), - CoroutineClosureId(InternedCoroutineClosureId), +enum AnyClosureId<'db> { + ClosureId(InternedClosureId<'db>), + CoroutineClosureId(InternedCoroutineClosureId<'db>), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { - owner: TypeOwnerId, - id: AnyClosureId, + owner: TypeOwnerId<'db>, + id: AnyClosureId<'db>, subst: GenericArgs<'db>, } @@ -4961,20 +4959,20 @@ impl<'db> Closure<'db> { /// A coroutine expression, including async, generator, and async-generator coroutines. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Coroutine { - id: InternedCoroutineId, +pub struct Coroutine<'db> { + id: InternedCoroutineId<'db>, } -impl Coroutine { +impl<'db> Coroutine<'db> { /// Returns the values captured by this coroutine. - pub fn captured_items<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { + pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec> { captured_items(db, self.id.loc(db)) } } fn captured_items<'db>( db: &'db dyn HirDatabase, - closure: InternedClosure, + closure: InternedClosure<'db>, ) -> Vec> { let InternedClosure { owner: infer_owner, expr: closure, .. } = closure; let infer = InferenceResult::of(db, infer_owner); @@ -5055,13 +5053,13 @@ impl FnTrait { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { owner: ExpressionStoreOwnerId, - infer_owner: InferBodyId, + infer_owner: InferBodyId<'db>, closure: ExprId, capture: &'db hir_ty::closure_analysis::CapturedPlace, } impl<'db> ClosureCapture<'db> { - pub fn local(&self) -> Local { + pub fn local(&self) -> Local<'db> { Local { parent: self.owner, parent_infer: self.infer_owner, @@ -5210,8 +5208,8 @@ impl CaptureUsages<'_> { let mut result = Vec::with_capacity(self.sources.len()); for source in self.sources { let source = source.final_source(); - let is_ref = Self::is_ref(store, source); - match source { + let is_ref = Self::is_ref(store, source.unpack()); + match source.unpack() { ExprOrPatId::ExprId(expr) => { if let Ok(expr) = source_map.expr_syntax(expr) { result.push(CaptureUsageSource { is_ref, source: expr }) @@ -5249,16 +5247,23 @@ impl CaptureUsageSource { } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -enum TypeOwnerId { +enum TypeOwnerId<'db> { GenericDefId(GenericDefId), BuiltinDeriveImplId(BuiltinDeriveImplId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), // FIXME: What do when we unify two different crates? Currently we just randomly keep one. NoParams(base_db::Crate), } -impl_from!(GenericDefId, BuiltinDeriveImplId, AnonConstId for TypeOwnerId); -impl TypeOwnerId { +impl_from!( + impl<'db> + GenericDefId, + BuiltinDeriveImplId, + AnonConstId<'db> + for TypeOwnerId<'db> +); + +impl TypeOwnerId<'_> { fn unify(self, other: Self) -> Option { match (self, other) { (TypeOwnerId::NoParams(_), owner) => Some(owner), @@ -5324,7 +5329,7 @@ impl TypeOwnerId { /// with types of different origins will cause errors or panics. Instead, use the `instantiate` methods. #[derive(Clone, Debug)] pub struct Type<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, ty: EarlyBinder<'db, Ty<'db>>, } @@ -5519,7 +5524,7 @@ impl<'db> Type<'db> { tys: impl IntoIterator>>, ) -> Self { let interner = DbInterner::new_no_crate(db); - let mut owner = None::; + let mut owner = None::>; let ty = EarlyBinder::bind(Ty::new_tup_from_iter( interner, tys.into_iter().map(|ty| { @@ -5976,7 +5981,7 @@ impl<'db> Type<'db> { } /// Returns this type as a coroutine. - pub fn as_coroutine(&self) -> Option { + pub fn as_coroutine(&self) -> Option> { match self.ty.skip_binder().kind() { TyKind::Coroutine(id, _) => Some(Coroutine { id: id.0 }), _ => None, @@ -6070,7 +6075,10 @@ impl<'db> Type<'db> { } // FIXME: We should probably remove this. - pub fn fingerprint_for_trait_impl(&self, db: &'db dyn HirDatabase) -> Option { + pub fn fingerprint_for_trait_impl( + &self, + db: &'db dyn HirDatabase, + ) -> Option> { fast_reject::simplify_type( DbInterner::new_no_crate(db), self.ty.skip_binder(), @@ -6573,7 +6581,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, - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, callback: F, visited: FxHashSet>, } @@ -6706,8 +6714,8 @@ pub struct Callable<'db> { #[derive(Clone, PartialEq, Eq, Hash, Debug)] enum Callee<'db> { Def(CallableDefId), - Closure(InternedClosureId, GenericArgs<'db>), - CoroutineClosure(InternedCoroutineClosureId, GenericArgs<'db>), + Closure(InternedClosureId<'db>, GenericArgs<'db>), + CoroutineClosure(InternedCoroutineClosureId<'db>, GenericArgs<'db>), FnPtr, FnImpl(traits::FnTrait), BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, @@ -6915,17 +6923,17 @@ pub enum BindingMode { /// For IDE only #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ScopeDef { +pub enum ScopeDef<'db> { ModuleDef(ModuleDef), GenericParam(GenericParam), ImplSelfType(Impl), AdtSelfType(Adt), - Local(Local), + Local(Local<'db>), Label(Label), Unknown, } -impl ScopeDef { +impl ScopeDef<'_> { pub fn all_items(def: PerNs) -> ArrayVec { let mut items = ArrayVec::new(); @@ -6982,15 +6990,11 @@ impl ScopeDef { } } -impl From for ScopeDef { - fn from(item: ItemInNs) -> Self { - match item { - ItemInNs::Types(id) => ScopeDef::ModuleDef(id), - ItemInNs::Values(id) => ScopeDef::ModuleDef(id), - ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)), - } - } -} +impl_from!( + impl<'db> + ItemInNs { Types => ModuleDef, Values => ModuleDef, Macros => ModuleDef } + for ScopeDef<'db> +); #[derive(Clone, Debug, PartialEq, Eq)] pub struct Adjustment<'db> { @@ -7040,7 +7044,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { inner: hir_ty::next_solver::TraitPredicate<'db>, - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, } impl<'db> TraitPredicate<'db> { @@ -7163,7 +7167,7 @@ impl HasCrate for Module { } } -impl HasCrate for AnonConst { +impl<'db> HasCrate for AnonConst<'db> { fn krate(&self, db: &dyn HirDatabase) -> Crate { hir_def::HasModule::krate(&self.id.loc(db).owner, db).into() } @@ -7285,7 +7289,6 @@ impl_has_name!( Macro, ExternAssocItem, AssocItem, - Local, DeriveHelper, ToolModule, Label, @@ -7309,7 +7312,19 @@ macro_rules! impl_has_name_no_db { }; } -impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr); +impl_has_name_no_db!(StaticLifetime, BuiltinType, BuiltinAttr); + +impl HasName for Local<'_> { + fn name(&self, db: &dyn HirDatabase) -> Option { + (*self).name(db).into() + } +} + +impl HasName for TupleField<'_> { + fn name(&self, _db: &dyn HirDatabase) -> Option { + (*self).name().into() + } +} impl HasName for Param<'_> { fn name(&self, db: &dyn HirDatabase) -> Option { @@ -7445,10 +7460,10 @@ fn as_name_opt(name: Option) -> Name { #[track_caller] fn generic_args_from_tys<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, args: impl IntoIterator>>, -) -> (GenericArgs<'db>, TypeOwnerId) { - let mut owner = None::; +) -> (GenericArgs<'db>, TypeOwnerId<'db>) { + let mut owner = None::>; let mut args = args.into_iter(); let args = GenericArgs::for_item(interner, def_id, |_, id, _, _| { if matches!(id, GenericParamId::TypeParamId(_)) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index e9e6ec3a01249..fee6ae3d49527 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -67,11 +67,11 @@ use crate::{ const CONTINUE_NO_BREAKS: ControlFlow = ControlFlow::Continue(()); #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum PathResolution { +pub enum PathResolution<'db> { /// An item Def(ModuleDef), /// A local binding (only value namespace) - Local(Local), + Local(Local<'db>), /// A type parameter TypeParam(TypeParam), /// A const parameter @@ -82,7 +82,7 @@ pub enum PathResolution { DeriveHelper(DeriveHelper), } -impl PathResolution { +impl<'db> PathResolution<'db> { pub(crate) fn in_type_ns(&self) -> Option { match self { PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())), @@ -116,21 +116,21 @@ impl PathResolution { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct PathResolutionPerNs { - pub type_ns: Option, - pub value_ns: Option, - pub macro_ns: Option, +pub struct PathResolutionPerNs<'db> { + pub type_ns: Option>, + pub value_ns: Option>, + pub macro_ns: Option>, } -impl PathResolutionPerNs { +impl<'db> PathResolutionPerNs<'db> { pub fn new( - type_ns: Option, - value_ns: Option, - macro_ns: Option, + type_ns: Option>, + value_ns: Option>, + macro_ns: Option>, ) -> Self { PathResolutionPerNs { type_ns, value_ns, macro_ns } } - pub fn any(&self) -> Option { + pub fn any(&self) -> Option> { self.type_ns.or(self.value_ns).or(self.macro_ns) } } @@ -165,8 +165,8 @@ pub struct Semantics<'db, DB: ?Sized> { } type DefWithoutBodyWithAnonConsts = Either; -type ExprToAnonConst = FxHashMap; -type DefAnonConstsMap = FxHashMap; +type ExprToAnonConst<'db> = FxHashMap>; +type DefAnonConstsMap<'db> = FxHashMap>; pub struct SemanticsImpl<'db> { pub db: &'db dyn HirDatabase, @@ -174,7 +174,7 @@ pub struct SemanticsImpl<'db> { /// MacroCall to its expansion's MacroCallId cache macro_call_cache: RefCell, MacroCallId>>, /// All anon consts defined by a *signature* (not a body). - signature_anon_consts_cache: RefCell, + signature_anon_consts_cache: RefCell>, } impl fmt::Debug for Semantics<'_, DB> { @@ -783,7 +783,11 @@ impl<'db> SemanticsImpl<'db> { /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. - pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec { + pub fn rename_conflicts<'a>( + &self, + to_be_renamed: &Local<'a>, + new_name: &Name, + ) -> Vec> { let (store, root_expr) = to_be_renamed.parent_infer.store_and_root_expr(self.db); let resolver = to_be_renamed.parent.resolver(self.db); let starting_expr = store.binding_owner(to_be_renamed.binding_id).unwrap_or(root_expr); @@ -813,7 +817,7 @@ impl<'db> SemanticsImpl<'db> { pub fn as_format_args_parts( &self, string: &ast::String, - ) -> Option>)>> { + ) -> Option, InlineAsmOperand>>)>> { let string_start = string.syntax().text_range().start(); let token = self.wrap_token_infile(string.syntax().clone()); self.descend_into_macros_breakable(token, |token, _| { @@ -870,7 +874,7 @@ impl<'db> SemanticsImpl<'db> { TextRange, HirFileRange, ast::String, - Option>, + Option, InlineAsmOperand>>, )> { let original_token = self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?; @@ -892,7 +896,7 @@ impl<'db> SemanticsImpl<'db> { TextRange, HirFileRange, ast::String, - Option>, + Option, InlineAsmOperand>>, )> { let relative_offset = offset.checked_sub(original_token.value.syntax().text_range().start())?; @@ -924,13 +928,13 @@ impl<'db> SemanticsImpl<'db> { &self, InFile { value: string, file_id }: InFile<&ast::String>, offset: TextSize, - ) -> Option<(TextRange, Option>)> { + ) -> Option<(TextRange, Option, InlineAsmOperand>>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; let parent = literal.parent()?; if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { let source_analyzer = - &self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; + self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; source_analyzer .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset) .map(|(range, res)| (range, res.map(Either::Left))) @@ -1899,14 +1903,14 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } - pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option> { + pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option>> { self.analyze(field.syntax())?.resolve_field(field) } pub fn resolve_field_fallback( &self, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option>)> + ) -> Option<(Either>, Function>, Option>)> { self.analyze(field.syntax())?.resolve_field_fallback(self.db, field) } @@ -1914,7 +1918,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_record_field( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>)> { + ) -> Option<(Field, Option>, Type<'db>)> { self.resolve_record_field_with_substitution(field) .map(|(field, local, ty, _)| (field, local, ty)) } @@ -1922,7 +1926,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_record_field_with_substitution( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { + ) -> Option<(Field, Option>, Type<'db>, GenericSubstitution<'db>)> { self.analyze(field.syntax())?.resolve_record_field(self.db, field) } @@ -2026,18 +2030,18 @@ impl<'db> SemanticsImpl<'db> { Some(Macro { id }) } - pub fn resolve_path(&self, path: &ast::Path) -> Option { + pub fn resolve_path(&self, path: &ast::Path) -> Option> { self.resolve_path_with_subst(path).map(|(it, _)| it) } - pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option { + pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option> { self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path) } pub fn resolve_path_with_subst( &self, path: &ast::Path, - ) -> Option<(PathResolution, Option>)> { + ) -> Option<(PathResolution<'db>, Option>)> { self.analyze(path.syntax())?.resolve_path(self.db, path) } @@ -2106,17 +2110,17 @@ impl<'db> SemanticsImpl<'db> { .unwrap_or_default() } - fn with_ctx) -> T, T>(&self, f: F) -> T { + fn with_ctx) -> T, T>(&self, f: F) -> T { let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() }; f(&mut ctx) } - pub fn to_def(&self, src: &T) -> Option { + pub fn to_def>(&self, src: &T) -> Option { let src = self.find_file(src.syntax()).with_value(src); T::to_def(self, src) } - pub fn to_def2(&self, src: InFile<&T>) -> Option { + pub fn to_def2>(&self, src: InFile<&T>) -> Option { T::to_def(self, src) } @@ -2179,9 +2183,9 @@ impl<'db> SemanticsImpl<'db> { fn populate_anon_const_cache_for<'a>( &self, - cache: &'a mut DefAnonConstsMap, + cache: &'a mut DefAnonConstsMap<'db>, def: DefWithoutBodyWithAnonConsts, - ) -> &'a ExprToAnonConst { + ) -> &'a ExprToAnonConst<'db> { cache.entry(def).or_insert_with(|| match def { Either::Left(def) => { let all_anon_consts = @@ -2204,7 +2208,7 @@ impl<'db> SemanticsImpl<'db> { &self, def: DefWithoutBodyWithAnonConsts, root_expr: ExprId, - ) -> Option { + ) -> Option> { let mut cache = self.signature_anon_consts_cache.borrow_mut(); let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def); anon_consts_map.get(&root_expr).copied() @@ -2215,7 +2219,7 @@ impl<'db> SemanticsImpl<'db> { def: ExpressionStoreOwnerId, store: &ExpressionStore, node: ExprOrPatId, - ) -> Option { + ) -> Option> { let handle_def_without_body = |def| { let root_expr = match node { ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr), @@ -2236,7 +2240,7 @@ impl<'db> SemanticsImpl<'db> { fn with_all_infers_for_store( &self, owner: ExpressionStoreOwnerId, - callback: &mut dyn FnMut(&'db InferenceResult), + callback: &mut dyn FnMut(&'db InferenceResult<'db>), ) { let mut handle_def_without_body = |def| { let mut cache = self.signature_anon_consts_cache.borrow_mut(); @@ -2457,7 +2461,7 @@ impl<'db> SemanticsImpl<'db> { &self, element: Either<&ast::Expr, &ast::StmtList>, text_range: TextRange, - ) -> Option> { + ) -> Option>> { let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; let infer_body = sa.infer_body?; let store = sa.store()?; @@ -2506,7 +2510,7 @@ impl<'db> SemanticsImpl<'db> { let mut exprs: Vec<_> = exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect(); - let mut locals: FxIndexSet = FxIndexSet::default(); + let mut locals: FxIndexSet> = FxIndexSet::default(); let mut add_to_locals_used = |id, parent_expr| { let path = match id { ExprOrPatId::ExprId(expr_id) => { @@ -2637,16 +2641,16 @@ fn macro_call_to_macro_id( } } -pub trait ToDef: AstNode + Clone { +pub trait ToDef<'db>: AstNode + Clone { type Def; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option; + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option; } macro_rules! to_def_impls { - ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( - impl ToDef for $ast { + ($(($def:ty, $ast:path, $meth:ident)),* ,) => {$( + impl<'db> ToDef<'db> for $ast { type Def = $def; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option { sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) } } @@ -2673,7 +2677,7 @@ to_def_impls![ (crate::ConstParam, ast::ConstParam, const_param_to_def), (crate::GenericParam, ast::GenericParam, generic_param_to_def), (crate::Macro, ast::Macro, macro_to_def), - (crate::Local, ast::SelfParam, self_param_to_def), + (crate::Local<'db>, ast::SelfParam, self_param_to_def), (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), @@ -2682,10 +2686,10 @@ to_def_impls![ (MacroCallId, ast::MacroCall, macro_call_to_macro_call), ]; -impl ToDef for ast::IdentPat { - type Def = crate::Local; +impl<'db> ToDef<'db> for ast::IdentPat { + type Def = crate::Local<'db>; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option { sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema)) } } @@ -2712,7 +2716,7 @@ impl ToDef for ast::IdentPat { #[derive(Debug)] pub struct SemanticsScope<'db> { pub db: &'db dyn HirDatabase, - infer_body: Option, + infer_body: Option>, file_id: HirFileId, resolver: Resolver<'db>, } @@ -2753,7 +2757,7 @@ impl<'db> SemanticsScope<'db> { } /// Calls the passed closure `f` on all names in scope. - pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) { let scope = self.resolver.names_in_scope(self.db); for (name, entries) in scope { for entry in entries { @@ -2790,7 +2794,7 @@ impl<'db> SemanticsScope<'db> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. - pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option { + pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option> { let mut kind = PathKind::Plain; let mut segments = vec![]; let mut first = true; @@ -2838,7 +2842,7 @@ impl<'db> SemanticsScope<'db> { /// `Ty::Assoc` syntax). pub fn assoc_type_shorthand_candidates( &self, - resolution: &PathResolution, + resolution: &PathResolution<'db>, mut cb: impl FnMut(TypeAlias), ) { let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns()) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index f7528d3db10b2..3b39a489141e1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -178,7 +178,7 @@ pub(super) struct SourceToDefCtx<'db, 'cache> { pub(super) cache: &'cache mut SourceToDefCache<'db>, } -impl SourceToDefCtx<'_, '_> { +impl<'db> SourceToDefCtx<'db, '_> { pub(super) fn file_to_def(&mut self, file: FileId) -> &SmallVec<[ModuleId; 1]> { let _p = tracing::info_span!("SourceToDefCtx::file_to_def").entered(); self.cache.file_to_def_cache.entry(file).or_insert_with(|| { @@ -347,15 +347,17 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, - semantics: &SemanticsImpl<'_>, - ) -> Option { + semantics: &SemanticsImpl<'db>, + ) -> Option> { let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let src = src.cloned().map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; // the pattern could resolve to a constant, verify that this is not the case - if let crate::Pat::Bind { id, .. } = store[pat_id.as_pat()?] { - let parent_infer = semantics.infer_body_for_expr_or_pat(container, store, pat_id)?; + let pat_id = pat_id.as_pat()?; + if let crate::Pat::Bind { id, .. } = store[pat_id] { + let parent_infer = + semantics.infer_body_for_expr_or_pat(container, store, pat_id.into())?; Some(crate::Local { parent: container, parent_infer, binding_id: id }) } else { None diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index db4e92098e81f..fb27f9dec45ac 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -77,8 +77,8 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option>, - pub(crate) type_owner: TypeOwnerId, - pub(crate) infer_body: Option, + pub(crate) type_owner: TypeOwnerId<'db>, + pub(crate) infer_body: Option>, } #[derive(Debug)] @@ -87,19 +87,19 @@ pub(crate) enum BodyOrSig<'db> { def: DefWithBodyId, body: &'db Body, source_map: &'db BodySourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, }, VariantFields { def: VariantId, store: &'db ExpressionStore, source_map: &'db ExpressionStoreSourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, }, Sig { def: GenericDefId, store: &'db ExpressionStore, source_map: &'db ExpressionStoreSourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, #[expect(dead_code)] generics: &'db GenericParams, }, @@ -129,7 +129,7 @@ impl<'db> SourceAnalyzer<'db> { def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, ) -> SourceAnalyzer<'db> { let (body, source_map) = Body::with_source_map(db, def); let scopes = ExprScopes::of(db, def); @@ -295,11 +295,11 @@ impl<'db> SourceAnalyzer<'db> { }) } - fn infer(&self) -> Option<&InferenceResult> { - self.body_or_sig.as_ref().and_then(|it| match it { + fn infer(&self) -> Option<&'db InferenceResult<'db>> { + self.body_or_sig.as_ref().and_then(|it| match *it { BodyOrSig::VariantFields { infer, .. } | BodyOrSig::Sig { infer, .. } - | BodyOrSig::Body { infer, .. } => infer.as_deref(), + | BodyOrSig::Body { infer, .. } => infer, }) } @@ -311,9 +311,9 @@ impl<'db> SourceAnalyzer<'db> { &self, ) -> Option<( ExpressionStoreOwnerId, - &ExpressionStore, - &ExpressionStoreSourceMap, - Option<&InferenceResult>, + &'db ExpressionStore, + &'db ExpressionStoreSourceMap, + Option<&'db InferenceResult<'db>>, )> { self.body_or_sig.as_ref().map(|it| match *it { BodyOrSig::VariantFields { def, store, source_map, infer, .. } => { @@ -328,18 +328,18 @@ impl<'db> SourceAnalyzer<'db> { }) } - pub(crate) fn store(&self) -> Option<&ExpressionStore> { - self.body_or_sig.as_ref().map(|it| match it { - BodyOrSig::Sig { store, .. } => &**store, - BodyOrSig::VariantFields { store, .. } => &**store, + pub(crate) fn store(&self) -> Option<&'db ExpressionStore> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::Sig { store, .. } => store, + BodyOrSig::VariantFields { store, .. } => store, BodyOrSig::Body { body, .. } => &body.store, }) } - pub(crate) fn store_sm(&self) -> Option<&ExpressionStoreSourceMap> { - self.body_or_sig.as_ref().map(|it| match it { - BodyOrSig::Sig { source_map, .. } => &**source_map, - BodyOrSig::VariantFields { source_map, .. } => &**source_map, + pub(crate) fn store_sm(&self) -> Option<&'db ExpressionStoreSourceMap> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::Sig { source_map, .. } => source_map, + BodyOrSig::VariantFields { source_map, .. } => source_map, BodyOrSig::Body { source_map, .. } => &source_map.store, }) } @@ -476,8 +476,8 @@ impl<'db> SourceAnalyzer<'db> { .lower_ty(type_ref); struct VarsCtx<'a, 'db> { - types: &'db DefaultAny<'db>, - infer: Option<&'a InferenceResult>, + types: &'a DefaultAny<'db>, + infer: Option<&'a InferenceResult<'db>>, } impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> { @@ -516,7 +516,7 @@ impl<'db> SourceAnalyzer<'db> { fn expr_id_is_diverging( &self, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'_>, expr_id: ExprOrPatId, ) -> bool { // FIXME: This is an approximation, perhaps we need to store a set of diverging exprs in inference? @@ -690,7 +690,7 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_field( &self, field: &ast::FieldExpr, - ) -> Option> { + ) -> Option>> { let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; self.infer()?.field_resolution(expr_id).map(|it| { @@ -701,7 +701,7 @@ impl<'db> SourceAnalyzer<'db> { fn field_subst( &self, field_expr: ExprId, - infer: &InferenceResult, + infer: &InferenceResult<'_>, _db: &'db dyn HirDatabase, ) -> Option> { let body = self.store()?; @@ -716,7 +716,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option>)> + ) -> Option<(Either>, Function>, Option>)> { let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; @@ -949,7 +949,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { + ) -> Option<(Field, Option>, Type<'db>, GenericSubstitution<'db>)> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let expr = ast::Expr::from(record_expr); let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?; @@ -1160,7 +1160,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, path: &ast::Path, - ) -> Option<(PathResolution, Option>)> { + ) -> Option<(PathResolution<'db>, Option>)> { let parent = path.syntax().parent(); let parent = || parent.clone(); @@ -1486,9 +1486,9 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_hir_path_per_ns( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, path: &ast::Path, - ) -> Option { + ) -> Option> { let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id, LoweringMode::Ide); let hir_path = @@ -1628,7 +1628,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { let (hygiene, implicits) = self.store_sm()?.implicit_format_args(format_args)?; implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| { ( @@ -1666,9 +1666,9 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn as_format_args_parts<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, - ) -> Option)> + 'a> { + ) -> Option>)> + 'a> { let (hygiene, names) = self.store_sm()?.implicit_format_args(format_args)?; Some(names.iter().map(move |(range, name)| { ( @@ -1846,14 +1846,14 @@ fn adjust( } #[inline] -pub(crate) fn resolve_hir_path( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - infer_body: Option, +pub(crate) fn resolve_hir_path<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + infer_body: Option>, path: &Path, hygiene: HygieneId, store: Option<&ExpressionStore>, -) -> Option { +) -> Option> { resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any() } @@ -1869,16 +1869,16 @@ pub(crate) fn resolve_hir_path_as_attr_macro( .map(Into::into) } -fn resolve_hir_path_( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - infer_body: Option, +fn resolve_hir_path_<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + infer_body: Option>, path: &Path, prefer_value_ns: bool, hygiene: HygieneId, store: Option<&ExpressionStore>, resolve_per_ns: bool, -) -> PathResolutionPerNs { +) -> PathResolutionPerNs<'db> { let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -1993,14 +1993,14 @@ fn resolve_hir_path_( } } -fn resolve_hir_value_path( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, +fn resolve_hir_value_path<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, store_owner: Option, - infer_body: Option, + infer_body: Option>, path: &Path, hygiene: HygieneId, -) -> Option { +) -> Option> { resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { @@ -2032,12 +2032,12 @@ fn resolve_hir_value_path( /// } /// ``` /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function. -fn resolve_hir_path_qualifier( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, +fn resolve_hir_path_qualifier<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, path: &Path, store: &ExpressionStore, -) -> Option { +) -> Option> { (|| { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -2127,7 +2127,7 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H fn record_literal_matched_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: ExprId, expr: &Expr, ) -> Option<(VariantId, Vec)> { @@ -2159,7 +2159,7 @@ fn record_literal_matched_fields( fn record_pattern_matched_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: PatId, pat: &Pat, ) -> Option<(VariantId, Vec)> { diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 021a20ae1b71e..79a075ef8bc72 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; -use base_db::FxIndexSet; +use base_db::{FxIndexSet, salsa::Update}; use either::Either; use hir_def::{ AdtId, AssocItemId, AstIdLoc, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, @@ -28,7 +28,7 @@ use crate::{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)] +#[derive(Clone, PartialEq, Eq, Hash, Update)] pub struct FileSymbol<'db> { pub name: Symbol, pub def: ModuleDef, @@ -39,7 +39,33 @@ pub struct FileSymbol<'db> { pub is_assoc: bool, pub is_import: bool, pub do_not_complete: Complete, - _marker: PhantomData<&'db ()>, + _marker: PhantomData &'db ()>, +} + +impl<'db> std::fmt::Debug for FileSymbol<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let FileSymbol { + name, + def, + loc, + container_name, + is_alias, + is_assoc, + is_import, + do_not_complete, + _marker: _, + } = self; + f.debug_struct("FileSymbol") + .field("name", name) + .field("def", def) + .field("loc", loc) + .field("container_name", container_name) + .field("is_alias", is_alias) + .field("is_assoc", is_assoc) + .field("is_import", is_import) + .field("do_not_complete", do_not_complete) + .finish() + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index a824c8bdca5d9..07994268696eb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -65,7 +65,7 @@ pub enum Expr<'db> { /// Static variable Static(Static), /// Local variable - Local(Local), + Local(Local<'db>), /// Constant generic parameter ConstParam(ConstParam), /// Well known type (such as `true` for bool) diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index 8e107afc9e3d2..c0cfe18e6efd6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -37,7 +37,7 @@ use super::{LookupTable, NewTypesKey, TermSearchCtx}; /// depend on the current state of `lookup`_ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -102,7 +102,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( /// depend on the current state of `lookup`_ pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -150,7 +150,7 @@ pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -303,7 +303,7 @@ pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -440,7 +440,7 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -561,7 +561,7 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -605,7 +605,7 @@ pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( /// * `lookup` - Lookup table for types pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -637,7 +637,7 @@ pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -745,7 +745,7 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 4c3168219fc63..865995def013e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -95,16 +95,16 @@ pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_, '_ ) } -struct BoolNodeData { +struct BoolNodeData<'db> { target_node: SyntaxNode, name: ast::Name, ty_annotation: Option, initializer: Option, - definition: Definition, + definition: Definition<'db>, } /// Attempts to find an appropriate node to apply the action to. -fn find_bool_node(ctx: &AssistContext<'_, '_>) -> Option { +fn find_bool_node<'db>(ctx: &AssistContext<'_, 'db>) -> Option> { let name = ctx.find_node_at_offset::()?; if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { @@ -213,7 +213,7 @@ fn replace_usages( edit: &mut SourceChangeBuilder, ctx: &AssistContext<'_, '_>, usages: UsageSearchResult, - target_definition: Definition, + target_definition: Definition<'_>, target_module: &hir::Module, delayed_mutations: &mut Vec<(FileId, ImportScope, ast::Path)>, make: &SyntaxFactory, @@ -427,7 +427,7 @@ fn find_negated_usage(name: &ast::NameLike) -> Option<(ast::PrefixExpr, ast::Exp fn find_record_expr_usage( name: &ast::NameLike, got_field: hir::Field, - target_definition: Definition, + target_definition: Definition<'_>, ) -> Option<(ast::RecordExprField, ast::Expr)> { let name_ref = name.as_name_ref()?; let record_field = ast::RecordExprField::for_field_name(name_ref)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index fb7dcdf37179a..eb74e9107581b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -169,7 +169,7 @@ fn process_struct_name_reference( r: FileReference, editor: &SyntaxEditor, source: &ast::SourceFile, - strukt_def: &Definition, + strukt_def: &Definition<'_>, names: &[ast::Name], ) -> Option<()> { let make = editor.make(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index f5d2a6cfc5198..a2b15fd4c252d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -238,24 +238,24 @@ fn find_parent_and_path( } } -fn def_is_referenced_in(def: Definition, ctx: &AssistContext<'_, '_>) -> bool { +fn def_is_referenced_in<'db>(def: Definition<'db>, ctx: &AssistContext<'_, 'db>) -> bool { let search_scope = SearchScope::single_file(ctx.file_id()); def.usages(&ctx.sema).in_scope(&search_scope).at_least_one() } #[derive(Debug, Clone)] -struct Ref { +struct Ref<'db> { // could be alias visible_name: Name, - def: Definition, + def: Definition<'db>, is_pub: bool, } -impl Ref { +impl<'db> Ref<'db> { fn from_scope_def( - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, name: Name, - scope_def: ScopeDef, + scope_def: ScopeDef<'db>, ) -> Option { match scope_def { ScopeDef::ModuleDef(def) => Some(Ref { @@ -269,10 +269,10 @@ impl Ref { } #[derive(Debug, Clone)] -struct Refs(Vec); +struct Refs<'db>(Vec>); -impl Refs { - fn used_refs(&self, ctx: &AssistContext<'_, '_>) -> Refs { +impl<'db> Refs<'db> { + fn used_refs(&self, ctx: &AssistContext<'_, 'db>) -> Refs<'db> { Refs( self.0 .clone() @@ -296,18 +296,18 @@ impl Refs { ) } - fn filter_out_by_defs(&self, defs: Vec) -> Refs { + fn filter_out_by_defs(&self, defs: Vec>) -> Refs<'db> { Refs(self.0.clone().into_iter().filter(|r| !defs.contains(&r.def)).collect()) } } -fn find_refs_in_mod( - ctx: &AssistContext<'_, '_>, +fn find_refs_in_mod<'db>( + ctx: &AssistContext<'_, 'db>, expandable: Expandable, current_module: Module, visible_from: Module, must_be_pub: bool, -) -> Refs { +) -> Refs<'db> { match expandable { Expandable::Module(module) => { let module_scope = module.scope(ctx.db(), Some(visible_from)); @@ -376,7 +376,7 @@ fn is_visible_from(ctx: &AssistContext<'_, '_>, expandable: &Expandable, from: M // use foo::*$0; // use baz::Baz; // ↑ --------------- -fn find_imported_defs(ctx: &AssistContext<'_, '_>, use_item: Use) -> Vec { +fn find_imported_defs<'db>(ctx: &AssistContext<'_, 'db>, use_item: Use) -> Vec> { [Direction::Prev, Direction::Next] .into_iter() .flat_map(|dir| { @@ -401,7 +401,10 @@ fn find_imported_defs(ctx: &AssistContext<'_, '_>, use_item: Use) -> Vec) -> Vec { +fn find_names_to_import<'db>( + refs_in_target: Refs<'db>, + imported_defs: Vec>, +) -> Vec { let final_refs = refs_in_target.filter_out_by_defs(imported_defs); final_refs.0.iter().map(|r| r.visible_name.clone()).collect() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index f8572dcd3a85f..c2eb49dde5695 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -324,7 +324,7 @@ struct Function<'db> { control_flow: ControlFlow<'db>, ret_ty: RetType<'db>, body: FunctionBody, - outliving_locals: Vec, + outliving_locals: Vec>, /// Whether at least one of the container's tail expr is contained in the range we're extracting. contains_tail_expr: bool, mods: ContainerInfo<'db>, @@ -332,7 +332,7 @@ struct Function<'db> { #[derive(Debug)] struct Param<'db> { - var: Local, + var: Local<'db>, ty: hir::Type<'db>, move_local: bool, requires_mut: bool, @@ -441,8 +441,8 @@ enum FunctionBody { } #[derive(Debug)] -struct OutlivedLocal { - local: Local, +struct OutlivedLocal<'db> { + local: Local<'db>, mut_usage_outside_body: bool, } @@ -452,7 +452,7 @@ struct OutlivedLocal { struct LocalUsages(ide_db::search::UsageSearchResult); impl LocalUsages { - fn find_local_usages(ctx: &AssistContext<'_, '_>, var: Local) -> Self { + fn find_local_usages<'db>(ctx: &AssistContext<'_, 'db>, var: Local<'db>) -> Self { Self( Definition::Local(var) .usages(&ctx.sema) @@ -807,10 +807,10 @@ impl FunctionBody { impl FunctionBody { /// Analyzes a function body, returning the used local variables that are referenced in it as well as /// whether it contains an await expression. - fn analyze( + fn analyze<'db>( &self, - sema: &Semantics<'_, RootDatabase>, - ) -> (FxIndexSet, Option) { + sema: &Semantics<'db, RootDatabase>, + ) -> (FxIndexSet>, Option) { let mut self_param = None; let mut res = FxIndexSet::default(); @@ -819,7 +819,7 @@ impl FunctionBody { FunctionBody::Span { parent, text_range, .. } => (*text_range, Either::Right(parent)), }; - let mut add_name_if_local = |local_ref: Local| { + let mut add_name_if_local = |local_ref: Local<'db>| { // locals defined inside macros are not relevant to us let InFile { file_id, value } = local_ref.primary_source(sema.db).source; if !file_id.is_macro() { @@ -965,10 +965,10 @@ impl FunctionBody { } /// Local variables defined inside `body` that are accessed outside of it - fn ret_values<'a>( + fn ret_values<'a, 'db>( &self, - ctx: &'a AssistContext<'_, '_>, - ) -> impl Iterator + 'a { + ctx: &'a AssistContext<'_, 'db>, + ) -> impl Iterator> + 'a { let range = self.text_range(); locals_defined_in_body(&ctx.sema, self) .into_iter() @@ -1070,7 +1070,7 @@ impl FunctionBody { &self, ctx: &AssistContext<'_, 'db>, container_info: &ContainerInfo<'db>, - locals: FxIndexSet, + locals: FxIndexSet>, ) -> Vec> { locals .into_iter() @@ -1254,10 +1254,10 @@ fn path_element_of(reference: &FileReference) -> Option { } /// list local variables defined inside `body` -fn locals_defined_in_body( - sema: &Semantics<'_, RootDatabase>, +fn locals_defined_in_body<'db>( + sema: &Semantics<'db, RootDatabase>, body: &FunctionBody, -) -> FxIndexSet { +) -> FxIndexSet> { // FIXME: this doesn't work well with macros // see https://github.com/rust-lang/rust-analyzer/pull/7535#discussion_r570048550 let mut res = FxIndexSet::default(); @@ -1272,11 +1272,11 @@ fn locals_defined_in_body( } /// Returns usage details if local variable is used after(outside of) body -fn local_outlives_body( - ctx: &AssistContext<'_, '_>, +fn local_outlives_body<'db>( + ctx: &AssistContext<'_, 'db>, body_range: TextRange, - local: Local, -) -> Option { + local: Local<'db>, +) -> Option> { let usages = LocalUsages::find_local_usages(ctx, local); let mut has_mut_usages = false; let mut any_outlives = false; @@ -1299,7 +1299,7 @@ fn local_outlives_body( fn is_defined_outside_of_body( ctx: &AssistContext<'_, '_>, body: &FunctionBody, - src: &LocalSource, + src: &LocalSource<'_>, ) -> bool { src.original_file(ctx.db()) == ctx.file_id() && !body.contains_node(src.syntax()) } @@ -1547,7 +1547,7 @@ impl<'db> FlowHandler<'db> { fn path_expr_from_local( make: &SyntaxFactory, ctx: &AssistContext<'_, '_>, - var: Local, + var: Local<'_>, edition: Edition, ) -> ast::Expr { let name = var.name(ctx.db()).display(ctx.db(), edition).to_string(); @@ -2012,10 +2012,10 @@ fn make_ty( make.ty(&ty_str) } -fn rewrite_body_segment( - ctx: &AssistContext<'_, '_>, +fn rewrite_body_segment<'db>( + ctx: &AssistContext<'_, 'db>, to_this_param: Option, - params: &[Param<'_>], + params: &[Param<'db>], handler: &FlowHandler<'_>, syntax: &SyntaxNode, ) -> SyntaxNode { @@ -2030,15 +2030,15 @@ fn rewrite_body_segment( } /// change all usages to account for added `&`/`&mut` for some params -fn fix_param_usages( +fn fix_param_usages<'db>( editor: &SyntaxEditor, source_syntax: &SyntaxNode, syntax: &SyntaxNode, - ctx: &AssistContext<'_, '_>, - to_this_param: Option, - params: &[Param<'_>], + ctx: &AssistContext<'_, 'db>, + to_this_param: Option>, + params: &[Param<'db>], ) { - let mut usages_for_param: Vec<(&Param<'_>, Vec)> = Vec::new(); + let mut usages_for_param: Vec<(&Param<'db>, Vec)> = Vec::new(); let mut usages_for_self_param: Vec = Vec::new(); let source_range = source_syntax.text_range(); let syntax_offset = source_range.start() - syntax.text_range().start(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index 40c54e98820a8..60a1c7ab44eb0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -362,11 +362,11 @@ impl Module { (refs, adt_fields, use_stmts_to_be_inserted) } - fn expand_and_group_usages_file_wise( + fn expand_and_group_usages_file_wise<'db>( &self, - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, replace_range: TextRange, - node_def: Definition, + node_def: Definition<'db>, refs_in_files: &mut FxHashMap>, use_stmts_to_be_inserted: &mut FxHashMap, ) { @@ -535,12 +535,12 @@ impl Module { imports_to_remove } - fn process_def_in_sel( + fn process_def_in_sel<'db>( &mut self, - def: Definition, + def: Definition<'db>, use_node: &SyntaxNode, curr_parent_module: &Option, - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, make: &SyntaxFactory, ) -> Option { //We only need to find in the current file @@ -738,7 +738,7 @@ fn check_intersection_and_push( } fn check_def_in_mod_and_out_sel( - def: Definition, + def: Definition<'_>, ctx: &AssistContext<'_, '_>, curr_parent_module: &Option, selection_range: TextRange, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index b75e7d4802d0a..c2c50b16de76f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -530,7 +530,7 @@ impl Anchor { } } -fn like_const_value(ctx: &AssistContext<'_, '_>, path_resolution: hir::PathResolution) -> bool { +fn like_const_value(ctx: &AssistContext<'_, '_>, path_resolution: hir::PathResolution<'_>) -> bool { let db = ctx.db(); let adt_like_const_value = |adt: Option| matches!(adt, Some(hir::Adt::Struct(s)) if s.kind(db) == hir::StructKind::Unit); match path_resolution { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 438966a1d67dd..fd67617be45dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -335,12 +335,12 @@ fn get_fn_params<'db>( Some(params) } -fn inline( - sema: &Semantics<'_, RootDatabase>, +fn inline<'db>( + sema: &Semantics<'db, RootDatabase>, function_def_file_id: EditionedFileId, function: hir::Function, fn_body: &ast::BlockExpr, - params: &[(ast::Pat, Option, hir::Param<'_>)], + params: &[(ast::Pat, Option, hir::Param<'db>)], CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo, file_editor: &SyntaxEditor, ) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs index 9dda4bbb966b6..f50ccc3e1136d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs @@ -114,6 +114,15 @@ mod tests { ) } + #[test] + fn invert_if_general_case_needs_paren() { + check_assist( + invert_if, + "fn f() { i$0f cond as bool { 3 * 2 } else { 1 } }", + "fn f() { if !(cond as bool) { 1 } else { 3 * 2 } }", + ) + } + #[test] fn invert_if_on_else_keyword() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 2d3b1b05400c3..a4edb556d4577 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -835,6 +835,17 @@ use top::{a::A, b::{B as D, B as C}}; r" use foo::bar; use foo::$0; +", + ); + } + + #[test] + fn test_merge_with_malformed_colon_path_segment() { + check_assist_not_applicable( + merge_imports, + r" +use foo::bar; +use foo::$0:; ", ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 2958acc4783ab..d6582a9559129 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -140,7 +140,7 @@ fn is_path_per_ns_unused_in_scope( ctx: &AssistContext<'_, '_>, u: &ast::UseTree, scope: &mut Vec, - path: &PathResolutionPerNs, + path: &PathResolutionPerNs<'_>, ) -> bool { if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns { if is_trait_unused_in_scope(ctx, u, scope, t) { @@ -159,7 +159,7 @@ fn is_path_unused_in_scope( ctx: &AssistContext<'_, '_>, u: &ast::UseTree, scope: &mut Vec, - path: &[Option], + path: &[Option>], ) -> bool { !path .iter() @@ -182,9 +182,9 @@ fn is_trait_unused_in_scope( .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope)) } -fn used_once_in_scope( - ctx: &AssistContext<'_, '_>, - def: Definition, +fn used_once_in_scope<'db>( + ctx: &AssistContext<'_, 'db>, + def: Definition<'db>, rename: Option, scopes: &Vec, ) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index 979f832978632..2be8dd1fbda8e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -155,10 +155,10 @@ fn find_path_type( } /// Returns all usage references for the given type parameter definition. -fn find_usages( - sema: &Semantics<'_, RootDatabase>, +fn find_usages<'db>( + sema: &Semantics<'db, RootDatabase>, fn_: &ast::Fn, - type_param_def: Definition, + type_param_def: Definition<'db>, file_id: EditionedFileId, ) -> UsageSearchResult { let file_range = FileRange { file_id, range: fn_.syntax().text_range() }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 0bd1ec12d06c2..d7f00bf669cce 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -40,6 +40,12 @@ pub(crate) fn replace_qualified_name_with_use( let original_path = target_path(ctx, original_path)?; + // There is no qualifier to replace, so there is nothing for this assist to do + if original_path.qualifier().is_none() { + cov_mark::hit!(not_applicable_for_unqualified_path); + return None; + } + // then search for an import for the first path segment of what we want to replace // that way it is less likely that we import the item from a different location due re-exports let module = match ctx.sema.resolve_path(&original_path.first_qualifier_or_self())? { @@ -250,6 +256,22 @@ fs::Path check_assist_not_applicable(replace_qualified_name_with_use, r"use std::fmt$0;"); } + #[test] + fn test_replace_not_applicable_for_unqualified_path() { + cov_mark::check!(not_applicable_for_unqualified_path); + check_assist_not_applicable( + replace_qualified_name_with_use, + r" +//- /main.rs crate:main deps:sub +fn main() { + su$0b(); +} +//- /sub.rs crate:sub +pub fn sub() {} +", + ); + } + #[test] fn replaces_all_affected_paths() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs index 5542180362e16..8bfc3439f4966 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs @@ -90,9 +90,9 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_, '_>) ) } -fn find_all_references( - ctx: &AssistContext<'_, '_>, - def: &Definition, +fn find_all_references<'db>( + ctx: &AssistContext<'_, 'db>, + def: &Definition<'db>, ) -> impl Iterator { def.usages(&ctx.sema).all().into_iter().flat_map(|(file_id, references)| { references.into_iter().map(move |reference| (file_id, reference)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 344beb32ae0e9..670a030255cfc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -303,7 +303,9 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { } pub(crate) fn invert_boolean_expression(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr { - invert_special_case(make, &expr).unwrap_or_else(|| make.expr_prefix(T![!], expr).into()) + invert_special_case(make, &expr).unwrap_or_else(|| { + make.expr_prefix(T![!], wrap_paren(expr, make, ExprPrecedence::Prefix)).into() + }) } fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 20048ea97b2c8..f1a34f15d0a5b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -222,12 +222,12 @@ impl Completions { }); } - pub(crate) fn add_path_resolution( + pub(crate) fn add_path_resolution<'db>( &mut self, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, doc_aliases: Vec, ) { let is_private_editable = match ctx.def_is_visible(&resolution) { @@ -244,12 +244,12 @@ impl Completions { .add_to(self, ctx.db); } - pub(crate) fn add_pattern_resolution( + pub(crate) fn add_pattern_resolution<'db>( &mut self, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, ) { let is_private_editable = match ctx.def_is_visible(&resolution) { Visible::Yes => false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 8d906064c0244..889beeac081ee 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -44,9 +44,9 @@ where } } -pub(crate) fn complete_expr_path( +pub(crate) fn complete_expr_path<'db>( acc: &mut Completions, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, expr_ctx: &PathExprCtx<'_>, ) { @@ -87,7 +87,7 @@ pub(crate) fn complete_expr_path( false }; - let scope_def_applicable = |def| match def { + let scope_def_applicable = |def: ScopeDef<'db>| match def { ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false, ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), _ => true, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index 0b2b6682aaabe..c07c02e28538f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -9,15 +9,15 @@ use crate::{ render::render_type_inference, }; -pub(crate) fn complete_type_path( +pub(crate) fn complete_type_path<'db>( acc: &mut Completions, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, location: &TypeLocation, ) { let _p = tracing::info_span!("complete_type_path").entered(); - let scope_def_applicable = |def| { + let scope_def_applicable = |def: ScopeDef<'db>| { use hir::{GenericParam::*, ModuleDef::*}; match def { ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 507ecaff0dca0..705305f557e9c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -273,7 +273,7 @@ pub(crate) enum Qualified<'db> { No, With { path: ast::Path, - resolution: Option, + resolution: Option>, /// How many `super` segments are present in the path /// /// This would be None, if path is not solely made of @@ -491,7 +491,7 @@ pub(crate) struct CompletionContext<'a, 'db> { pub(crate) qualifier_ctx: QualifierCtx, - pub(crate) locals: FxHashMap, + pub(crate) locals: FxHashMap>, /// The module depth of the current module of the cursor position. /// - crate-root @@ -545,7 +545,7 @@ impl<'db> CompletionContext<'_, 'db> { } /// Checks if an item is visible and not `doc(hidden)` at the completion site. - pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { + pub(crate) fn def_is_visible(&self, item: &ScopeDef<'db>) -> Visible { match item { ScopeDef::ModuleDef(def) => match def { hir::ModuleDef::Module(it) => self.is_visible(it), @@ -664,7 +664,7 @@ impl<'db> CompletionContext<'_, 'db> { /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and /// passes all doc-aliases along, to funnel it into `Completions::add_path_resolution`. - pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec)) { + pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>, Vec)) { let _p = tracing::info_span!("CompletionContext::process_all_names").entered(); self.scope.process_all_names(&mut |name, def| { if self.is_scope_def_hidden(def) { @@ -675,12 +675,12 @@ impl<'db> CompletionContext<'_, 'db> { }); } - pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) { let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered(); self.scope.process_all_names(f); } - fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool { + fn is_scope_def_hidden(&self, scope_def: ScopeDef<'db>) -> bool { if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) { return self.is_doc_hidden(&attrs, krate); } @@ -722,7 +722,7 @@ impl<'db> CompletionContext<'_, 'db> { self.krate != defining_crate && attrs.is_doc_hidden() } - pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { + pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef<'db>) -> Vec { if let Some(attrs) = scope_def.attrs(self.db) { attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect() } else { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index b2ee94d49cbfe..b06f52c113459 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -794,6 +794,10 @@ fn expected_type_and_name<'db>( }.map(TypeInfo::original); (ty, None) }, + ast::MatchGuard(it) => { + let ty = it.condition().and_then(|e| sema.type_of_expr(&e)).map(TypeInfo::original); + (ty, None) + }, ast::IdentPat(it) => { cov_mark::hit!(expected_type_if_let_with_leading_char); cov_mark::hit!(expected_type_match_arm_with_leading_char); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 1d1a55c6fe144..c5fba82de4802 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -409,6 +409,21 @@ fn foo() { ); } +#[test] +fn expected_type_guard_condition() { + check_expected_type_and_name( + r#" +enum E { V } +fn foo() { + match E::V { + _ if a$0 => {} + } +} +"#, + expect![[r#"ty: bool, name: ?"#]], + ); +} + #[test] fn expected_type_if_body() { check_expected_type_and_name( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 61281f8cfb8f1..2ff726c6d03e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -551,11 +551,11 @@ pub(crate) struct Builder { } impl Builder { - pub(crate) fn from_resolution( - ctx: &CompletionContext<'_, '_>, + pub(crate) fn from_resolution<'db>( + ctx: &CompletionContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, ) -> Self { let doc_aliases = ctx.doc_aliases_in_scope(resolution); render_path_resolution( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 7cb1eaa061f3c..9f8a2f71f18c8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -253,20 +253,20 @@ pub(crate) fn render_type_inference( builder.build(ctx.db) } -pub(crate) fn render_path_resolution( - ctx: RenderContext<'_, '_>, +pub(crate) fn render_path_resolution<'db>( + ctx: RenderContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { render_resolution_path(ctx, path_ctx, local_name, None, resolution) } -pub(crate) fn render_pattern_resolution( - ctx: RenderContext<'_, '_>, +pub(crate) fn render_pattern_resolution<'db>( + ctx: RenderContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution) } @@ -356,9 +356,9 @@ pub(crate) fn render_expr<'db>( Some(item) } -fn get_import_name( - resolution: ScopeDef, - ctx: &RenderContext<'_, '_>, +fn get_import_name<'db>( + resolution: ScopeDef<'db>, + ctx: &RenderContext<'_, 'db>, import_edit: &LocatedImport, ) -> Option { // FIXME: Temporary workaround for handling aliased import. @@ -374,9 +374,9 @@ fn get_import_name( } } -fn scope_def_to_name( - resolution: ScopeDef, - ctx: &RenderContext<'_, '_>, +fn scope_def_to_name<'db>( + resolution: ScopeDef<'db>, + ctx: &RenderContext<'_, 'db>, import_edit: &LocatedImport, ) -> Option { Some(match resolution { @@ -387,12 +387,12 @@ fn scope_def_to_name( }) } -fn render_resolution_pat( - ctx: RenderContext<'_, '_>, +fn render_resolution_pat<'db>( + ctx: RenderContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_pat").entered(); use hir::ModuleDef::*; @@ -410,7 +410,7 @@ fn render_resolution_path<'db>( path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_path").entered(); use hir::ModuleDef::*; @@ -528,11 +528,11 @@ fn render_resolution_path<'db>( item } -fn render_resolution_simple_( - ctx: RenderContext<'_, '_>, +fn render_resolution_simple_<'db>( + ctx: RenderContext<'_, 'db>, local_name: &hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_simple_").entered(); @@ -558,7 +558,7 @@ fn render_resolution_simple_( item } -fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { +fn res_to_kind(resolution: ScopeDef<'_>) -> CompletionItemKind { use hir::ModuleDef::*; match resolution { ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, @@ -589,7 +589,10 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { } } -fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option> { +fn scope_def_docs<'db>( + db: &'db RootDatabase, + resolution: ScopeDef<'db>, +) -> Option> { use hir::ModuleDef::*; match resolution { ScopeDef::ModuleDef(Module(it)) => it.docs(db), @@ -603,7 +606,7 @@ fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option, resolution: ScopeDef) -> bool { +fn scope_def_is_deprecated(ctx: &RenderContext<'_, '_>, resolution: ScopeDef<'_>) -> bool { let db = ctx.db(); match resolution { ScopeDef::ModuleDef(hir::ModuleDef::EnumVariant(it)) => ctx.is_variant_deprecated(it), diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index 2c0919a183709..501579277bbd5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -24,7 +24,6 @@ itertools.workspace = true arrayvec.workspace = true memchr = "2.7.5" salsa.workspace = true -salsa-macros.workspace = true triomphe.workspace = true nohash-hasher.workspace = true bitflags.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 82cff372963a9..c1fd002b3467b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -31,10 +31,10 @@ use syntax::{ // FIXME: a more precise name would probably be `Symbol`? #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum Definition { +pub enum Definition<'db> { Macro(Macro), Field(Field), - TupleField(TupleField), + TupleField(TupleField<'db>), Module(Module), Crate(Crate), Function(Function), @@ -46,7 +46,7 @@ pub enum Definition { TypeAlias(TypeAlias), SelfType(Impl), GenericParam(GenericParam), - Local(Local), + Local(Local<'db>), Label(Label), DeriveHelper(DeriveHelper), BuiltinType(BuiltinType), @@ -58,7 +58,7 @@ pub enum Definition { InlineAsmOperand(InlineAsmOperand), } -impl Definition { +impl<'db> Definition<'db> { pub fn canonical_module_path(&self, db: &RootDatabase) -> Option> { self.module(db).map(|it| it.path_to_root(db).into_iter().rev()) } @@ -104,8 +104,8 @@ impl Definition { Some(module) } - pub fn enclosing_definition(&self, db: &RootDatabase) -> Option { - fn container_to_definition(container: ItemContainer) -> Option { + pub fn enclosing_definition(&self, db: &RootDatabase) -> Option> { + fn container_to_definition<'db>(container: ItemContainer) -> Option> { match container { ItemContainer::Trait(it) => Some(it.into()), ItemContainer::Impl(it) => Some(it.into()), @@ -202,12 +202,12 @@ impl Definition { Some(name) } - pub fn docs<'db>( + pub fn docs<'a>( &self, - db: &'db RootDatabase, + db: &'a RootDatabase, famous_defs: Option<&FamousDefs<'_, '_>>, display_target: DisplayTarget, - ) -> Option> { + ) -> Option> { self.docs_with_rangemap(db, famous_defs, display_target).map(|docs| match docs { Either::Left(Cow::Borrowed(docs)) => Documentation::new_borrowed(docs.docs()), Either::Left(Cow::Owned(docs)) => Documentation::new_owned(docs.into_docs()), @@ -215,12 +215,12 @@ impl Definition { }) } - pub fn docs_with_rangemap<'db>( + pub fn docs_with_rangemap<'a>( &self, - db: &'db RootDatabase, + db: &'a RootDatabase, famous_defs: Option<&FamousDefs<'_, '_>>, display_target: DisplayTarget, - ) -> Option, Documentation<'db>>> { + ) -> Option, Documentation<'a>>> { let docs = match self { Definition::Macro(it) => it.docs_with_rangemap(db), Definition::Field(it) => it.docs_with_rangemap(db), @@ -432,7 +432,7 @@ impl<'db> IdentClass<'db> { .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass)) } - pub fn definitions(self) -> ArrayVec<(Definition, Option>), 2> { + pub fn definitions(self) -> ArrayVec<(Definition<'db>, Option>), 2> { let mut res = ArrayVec::new(); match self { IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { @@ -473,7 +473,7 @@ impl<'db> IdentClass<'db> { res } - pub fn definitions_no_ops(self) -> ArrayVec { + pub fn definitions_no_ops(self) -> ArrayVec, 2> { let mut res = ArrayVec::new(); match self { IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { @@ -517,14 +517,14 @@ impl<'db> IdentClass<'db> { /// A model special case is `None` constant in pattern. #[derive(Debug)] pub enum NameClass<'db> { - Definition(Definition), + Definition(Definition<'db>), /// `None` in `if let None = Some(82) {}`. /// Syntactically, it is a name, but semantically it is a reference. - ConstReference(Definition), + ConstReference(Definition<'db>), /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces /// a definition into a local scope, and refers to an existing definition. PatFieldShorthand { - local_def: Local, + local_def: Local<'db>, field_ref: Field, adt_subst: GenericSubstitution<'db>, }, @@ -532,7 +532,7 @@ pub enum NameClass<'db> { impl<'db> NameClass<'db> { /// `Definition` defined by this name. - pub fn defined(self) -> Option { + pub fn defined(self) -> Option> { let res = match self { NameClass::Definition(it) => it, NameClass::ConstReference(_) => return None, @@ -566,10 +566,10 @@ impl<'db> NameClass<'db> { }; return Some(NameClass::Definition(definition)); - fn classify_item( - sema: &Semantics<'_, RootDatabase>, + fn classify_item<'db>( + sema: &Semantics<'db, RootDatabase>, item: ast::Item, - ) -> Option { + ) -> Option> { let definition = match item { ast::Item::MacroRules(it) => { Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?) @@ -621,10 +621,10 @@ impl<'db> NameClass<'db> { Some(NameClass::Definition(Definition::Local(local))) } - fn classify_rename( - sema: &Semantics<'_, RootDatabase>, + fn classify_rename<'db>( + sema: &Semantics<'db, RootDatabase>, rename: ast::Rename, - ) -> Option { + ) -> Option> { if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) { let path = use_tree.path()?; sema.resolve_path(&path).map(Definition::from) @@ -722,9 +722,9 @@ impl OperatorClass { /// reference to point to two different defs. #[derive(Debug)] pub enum NameRefClass<'db> { - Definition(Definition, Option>), + Definition(Definition<'db>, Option>), FieldShorthand { - local_ref: Local, + local_ref: Local<'db>, field_ref: Field, adt_subst: GenericSubstitution<'db>, }, @@ -892,30 +892,40 @@ impl<'db> NameRefClass<'db> { } impl_from!( - Field, Module, Function, Adt, EnumVariant, Const, Static, Trait, TypeAlias, BuiltinType, Local, - GenericParam, Label, Macro, ExternCrateDecl - for Definition + impl<'db> + Field, + TupleField<'db>, + Module, + Function, + Adt, + EnumVariant, + Const, + Static, + Trait, + TypeAlias, + BuiltinType, + Local<'db>, + GenericParam, + Label, + Macro, + ExternCrateDecl, + InlineAsmOperand + for Definition<'db> ); -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(impl_: Impl) -> Self { Definition::SelfType(impl_) } } -impl From for Definition { - fn from(value: InlineAsmOperand) -> Self { - Definition::InlineAsmOperand(value) - } -} - -impl From> for Definition { - fn from(value: Either) -> Self { +impl<'db> From, InlineAsmOperand>> for Definition<'db> { + fn from(value: Either, InlineAsmOperand>) -> Self { value.either(Definition::from, Definition::from) } } -impl AsAssocItem for Definition { +impl AsAssocItem for Definition<'_> { fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { Definition::Function(it) => it.as_assoc_item(db), @@ -926,7 +936,7 @@ impl AsAssocItem for Definition { } } -impl AsExternAssocItem for Definition { +impl AsExternAssocItem for Definition<'_> { fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { Definition::Function(it) => it.as_extern_assoc_item(db), @@ -937,7 +947,7 @@ impl AsExternAssocItem for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(assoc_item: AssocItem) -> Self { match assoc_item { AssocItem::Function(it) => Definition::Function(it), @@ -947,8 +957,8 @@ impl From for Definition { } } -impl From for Definition { - fn from(path_resolution: PathResolution) -> Self { +impl<'db> From> for Definition<'db> { + fn from(path_resolution: PathResolution<'db>) -> Self { match path_resolution { PathResolution::Def(def) => def.into(), PathResolution::Local(local) => Definition::Local(local), @@ -962,7 +972,7 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: ModuleDef) -> Self { match def { ModuleDef::Module(it) => Definition::Module(it), @@ -979,7 +989,7 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: DocLinkDef) -> Self { match def { DocLinkDef::ModuleDef(it) => it.into(), @@ -989,13 +999,13 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: Variant) -> Self { ModuleDef::from(def).into() } } -impl TryFrom for Definition { +impl<'db> TryFrom for Definition<'db> { type Error = (); fn try_from(def: DefWithBody) -> Result { match def { @@ -1007,7 +1017,7 @@ impl TryFrom for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: GenericDef) -> Self { match def { GenericDef::Function(it) => it.into(), @@ -1021,7 +1031,7 @@ impl From for Definition { } } -impl TryFrom for Definition { +impl<'db> TryFrom for Definition<'db> { type Error = (); fn try_from(def: ExpressionStoreOwner) -> Result { match def { @@ -1032,9 +1042,9 @@ impl TryFrom for Definition { } } -impl TryFrom for GenericDef { +impl TryFrom> for GenericDef { type Error = (); - fn try_from(def: Definition) -> Result { + fn try_from(def: Definition<'_>) -> Result { match def { Definition::Function(it) => Ok(it.into()), Definition::Adt(it) => Ok(it.into()), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index f28ce53e91c03..b5f62c8fd7365 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -222,7 +222,7 @@ impl FamousDefs<'_, '_> { Some(res) } - fn find_def(&self, path: &str) -> Option { + fn find_def(&self, path: &str) -> Option> { let db = self.0.db; let mut path = path.split(':'); let trait_ = path.next_back()?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index 838aac2283f12..00e81b3ef4300 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -83,10 +83,10 @@ pub fn mod_path_to_ast_with_factory( } /// Iterates all `ModuleDef`s and `Impl` blocks of the given file. -pub fn visit_file_defs( - sema: &Semantics<'_, RootDatabase>, +pub fn visit_file_defs<'db>( + sema: &Semantics<'db, RootDatabase>, file_id: FileId, - cb: &mut dyn FnMut(Definition), + cb: &mut dyn FnMut(Definition<'db>), ) { let db = sema.db; let module = match sema.file_to_module_def(file_id) { @@ -139,10 +139,10 @@ pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool { } // FIXME: This is a weird function -pub fn get_definition( - sema: &Semantics<'_, RootDatabase>, +pub fn get_definition<'db>( + sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option { +) -> Option> { for token in sema.descend_into_macros_exact(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); if let Some(&[x]) = def.as_deref() { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 6edc550b331a1..f5dff47acf9ab 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -461,7 +461,7 @@ impl<'db> ImportAssets<'db> { .into_iter() } - fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { + fn scope_definitions<'a>(&self, sema: &Semantics<'a, RootDatabase>) -> FxHashSet> { let _p = tracing::info_span!("ImportAssets::scope_definitions").entered(); let mut scope_definitions = FxHashSet::default(); if let Some(scope) = sema.scope(&self.candidate_node) { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 17fae61da6131..59099056f5c5b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -828,7 +828,9 @@ fn split_prefix( } } else { let suffix_segments: Vec<_> = path.segments().skip(prefix.segments().count()).collect(); - if suffix_segments.is_empty() { + if suffix_segments.is_empty() + || suffix_segments.iter().any(|segment| segment.kind().is_none()) + { return None; } let suffix_path = make.path_from_segments(suffix_segments, false); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index c6b4d28169fe3..930cb993e1d3a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -78,7 +78,7 @@ pub use span::{self, FileId}; pub type FilePosition = FilePositionWrapper; pub type FileRange = FileRangeWrapper; -#[salsa_macros::db] +#[salsa::db] pub struct RootDatabase { // FIXME: Revisit this commit now that we migrated to the new salsa, given we store arcs in this // db directly now @@ -94,7 +94,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for RootDatabase {} impl Drop for RootDatabase { @@ -120,7 +120,7 @@ impl fmt::Debug for RootDatabase { } } -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for RootDatabase { fn file_text(&self, file_id: vfs::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index fb7edb1acd2f2..518387514c887 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -4,9 +4,8 @@ //! various caches, it's not really advanced at the moment. use std::panic::AssertUnwindSafe; -use base_db::all_crates; use hir::{Symbol, import_map::ImportMap, sym}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use salsa::{Cancelled, Database}; use crate::{FxIndexMap, RootDatabase, base_db::Crate, symbol_index::SymbolIndex}; @@ -23,12 +22,22 @@ pub struct ParallelPrimeCachesProgress { pub work_type: &'static str, } +/// Warm caches for `scope`. +/// +/// `scope` must be closed under transitive dependencies: the scheduler only +/// follows reverse-dep edges within `scope`. Out-of-scope crates can still be +/// primed by salsa on demand when a scope crate's queries reach into them. +/// Callers that want to prime everything pass `&all_crates(db)`. pub fn parallel_prime_caches( db: &RootDatabase, + scope: &[Crate], num_worker_threads: usize, cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync), ) { - let _p = tracing::info_span!("parallel_prime_caches").entered(); + if scope.is_empty() { + return; + } + let _p = tracing::info_span!("parallel_prime_caches", scope_size = scope.len()).entered(); enum ParallelPrimeCacheWorkerProgress { BeginCrateDefMap { crate_id: Crate, crate_name: Symbol }, @@ -52,17 +61,30 @@ pub fn parallel_prime_caches( // Such def map will just block on the dependency, which is just wasted time. So better // to compute the symbols/import map of an already computed def map in that time. + let scope_set: FxHashSet = scope.iter().copied().collect(); + let (reverse_deps, mut to_be_done_deps) = { - let all_crates = all_crates(db); - let to_be_done_deps = all_crates + // Only count in-scope deps — otherwise an out-of-scope dep would + // leave the scheduler waiting on a crate it never enqueued. + let to_be_done_deps = scope .iter() - .map(|&krate| (krate, krate.data(db).dependencies.len() as u32)) + .map(|&krate| { + let count = krate + .data(db) + .dependencies + .iter() + .filter(|dep| scope_set.contains(&dep.crate_id)) + .count() as u32; + (krate, count) + }) .collect::>(); let mut reverse_deps = - all_crates.iter().map(|&krate| (krate, Vec::new())).collect::>(); - for &krate in &*all_crates { + scope.iter().map(|&krate| (krate, Vec::new())).collect::>(); + for &krate in scope { for dep in &krate.data(db).dependencies { - reverse_deps.get_mut(&dep.crate_id).unwrap().push(krate); + if let Some(rev) = reverse_deps.get_mut(&dep.crate_id) { + rev.push(krate); + } } } (reverse_deps, to_be_done_deps) @@ -197,7 +219,7 @@ pub fn parallel_prime_caches( ) }; - let crate_def_maps_total = all_crates(db).len(); + let crate_def_maps_total = scope.len(); let mut crate_def_maps_done = 0; let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize); let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs index 2f4d319ec8218..c8607a8099b91 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs @@ -3,6 +3,7 @@ use std::hash::{BuildHasher, Hash}; use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics, Symbol}; +use itertools::Itertools; use smallvec::SmallVec; use span::{TextRange, TextSize}; use syntax::{ @@ -96,9 +97,13 @@ impl RaFixtureAnalysis { let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?; let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| { attrs.filter_map(|attr| attr.as_simple_path()).any(|path| { - path.segments() - .zip(["rust_analyzer", "rust_fixture"]) - .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name)) + let Some([Some(segment1), Some(segment2)]) = + path.segments().map(|seg| seg.name_ref()).collect_array() + else { + return false; + }; + segment1.text_non_mutable() == "rust_analyzer" + && segment2.text_non_mutable() == "rust_fixture" }) }); if !has_rust_fixture_attr { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index ff4d5a28866c4..b89c2fdf4ad87 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -82,10 +82,10 @@ pub enum RenameDefinition { No, } -impl Definition { +impl<'db> Definition<'db> { pub fn rename( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, new_name: &str, rename_definition: RenameDefinition, config: &RenameConfig, @@ -345,9 +345,9 @@ fn rename_mod( Ok(source_change) } -fn rename_reference( - sema: &Semantics<'_, RootDatabase>, - def: Definition, +fn rename_reference<'db>( + sema: &Semantics<'db, RootDatabase>, + def: Definition<'db>, new_name: &str, rename_definition: RenameDefinition, edition: Edition, @@ -523,7 +523,7 @@ fn rename_field_constructors( pub fn source_edit_from_references( db: &RootDatabase, references: &[FileReference], - def: Definition, + def: Definition<'_>, new_name: &Name, edition: Edition, ) -> TextEdit { @@ -579,7 +579,7 @@ fn source_edit_from_name_ref( edit: &mut TextEditBuilder, name_ref: &ast::NameRef, new_name: &dyn Display, - def: Definition, + def: Definition<'_>, ) -> bool { if name_ref.super_token().is_some() { return true; @@ -670,10 +670,10 @@ fn source_edit_from_name_ref( false } -fn source_edit_from_def( - sema: &Semantics<'_, RootDatabase>, +fn source_edit_from_def<'db>( + sema: &Semantics<'db, RootDatabase>, config: &RenameConfig, - def: Definition, + def: Definition<'db>, new_name: &Name, source_change: &mut SourceChange, ) -> Result<(FileId, TextEdit)> { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index d59df3601fbbb..b688cb188d58d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -286,7 +286,7 @@ impl IntoIterator for SearchScope { } } -impl Definition { +impl<'db> Definition<'db> { fn search_scope(&self, db: &RootDatabase) -> SearchScope { let _p = tracing::info_span!("search_scope").entered(); @@ -440,7 +440,7 @@ impl Definition { } } - pub fn usages<'a, 'db>(self, sema: &'a Semantics<'db, RootDatabase>) -> FindUsages<'a, 'db> { + pub fn usages<'a>(self, sema: &'a Semantics<'db, RootDatabase>) -> FindUsages<'a, 'db> { FindUsages { def: self, rename: None, @@ -457,7 +457,7 @@ impl Definition { #[derive(Clone)] pub struct FindUsages<'a, 'db> { - def: Definition, + def: Definition<'db>, rename: Option<&'a Rename>, sema: &'a Semantics<'db, RootDatabase>, scope: Option<&'a SearchScope>, @@ -678,7 +678,7 @@ impl<'a, 'db> FindUsages<'a, 'db> { db: &RootDatabase, to_process: &mut Vec<(SmolStr, SearchScope)>, alias_name: &str, - def: Definition, + def: Definition<'_>, ) { let alias = alias_name.trim_start_matches("r#").to_smolstr(); tracing::debug!("found alias: {alias}"); @@ -1211,7 +1211,7 @@ impl<'a, 'db> FindUsages<'a, 'db> { file_id: EditionedFileId, range: TextRange, token: ast::String, - res: Either, + res: Either, InlineAsmOperand>, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { let def = res.either(Definition::from, Definition::from); @@ -1393,7 +1393,10 @@ impl<'a, 'db> FindUsages<'a, 'db> { } } -fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Option> { +fn def_to_ty<'db>( + sema: &Semantics<'db, RootDatabase>, + def: &Definition<'db>, +) -> Option> { match def { Definition::Adt(adt) => Some(adt.ty(sema.db)), Definition::TypeAlias(it) => Some(it.ty(sema.db)), @@ -1406,7 +1409,7 @@ fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Opti impl ReferenceCategory { fn new( sema: &Semantics<'_, RootDatabase>, - def: &Definition, + def: &Definition<'_>, r: &ast::NameRef, ) -> ReferenceCategory { let mut result = ReferenceCategory::empty(); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 55acf5abf868d..edec86285ba68 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -29,7 +29,7 @@ use std::{ use base_db::{ CrateOrigin, InternedSourceRootId, LangCrateOrigin, LibraryRoots, LocalRoots, SourceRootId, - source_root_crates, + salsa::Update, source_root_crates, }; use fst::{Automaton, Streamer, raw::IndexedValue}; use hir::{ @@ -40,7 +40,6 @@ use hir::{ }; use itertools::Itertools; use rayon::prelude::*; -use salsa::Update; use crate::RootDatabase; @@ -366,6 +365,25 @@ pub struct SymbolIndex<'db> { map: fst::Map>, } +// SAFETY: +// - It is safe to compare a `SymbolIndex` from a previous revision to a new one. +// - FileSymbol<'db>: Update +unsafe impl<'db> Update for SymbolIndex<'db> +where + FileSymbol<'db>: Update, +{ + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + // SAFETY: Safe to dereference as per `salsa::Update` contract. + let this = unsafe { &mut *old_pointer }; + if *this != new_value { + *this = new_value; + true + } else { + false + } + } +} + impl<'db> SymbolIndex<'db> { /// The symbol index for a given source root within library_roots. pub fn library_symbols( @@ -475,18 +493,6 @@ impl Hash for SymbolIndex<'_> { } } -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 { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt index 12eb7e8e0a551..7a59abf36b588 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt @@ -41,7 +41,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -78,7 +77,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "mul1", @@ -115,7 +113,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "mul2", @@ -152,7 +149,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -189,7 +185,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -226,7 +221,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s2", @@ -263,7 +257,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 0ef19eb493f7c..d0619761c095d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -41,7 +41,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Alias", @@ -76,7 +75,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "B", @@ -113,7 +111,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "CONST", @@ -148,7 +145,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "CONST_WITH_INNER", @@ -183,7 +179,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Enum", @@ -220,7 +215,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "ItemLikeMacro", @@ -257,7 +251,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Macro", @@ -294,7 +287,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "STATIC", @@ -329,7 +321,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -366,7 +357,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructFromMacro", @@ -403,7 +393,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInFn", @@ -442,7 +431,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInNamedConst", @@ -481,7 +469,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInUnnamedConst", @@ -518,7 +505,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructT", @@ -555,7 +541,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", @@ -590,7 +575,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", @@ -627,7 +611,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Union", @@ -664,7 +647,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "a_mod", @@ -699,7 +681,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "b_mod", @@ -734,7 +715,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "define_struct", @@ -771,7 +751,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "generic_impl_fn", @@ -808,7 +787,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "impl_fn", @@ -845,7 +823,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "macro_rules_macro", @@ -882,7 +859,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "main", @@ -917,7 +893,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "really_define_struct", @@ -954,7 +929,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "trait_fn", @@ -991,7 +965,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), @@ -1037,7 +1010,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), @@ -1081,7 +1053,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "IsThisJustATrait", @@ -1118,7 +1089,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInModB", @@ -1155,7 +1125,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "SuperItemLikeMacro", @@ -1192,7 +1161,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "ThisStruct", @@ -1229,7 +1197,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt index b03d926efe66f..20b162b7cd8c7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt @@ -34,6 +34,5 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt index 84bb6670d7eca..1d475ab005ad7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt @@ -34,7 +34,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Foo", @@ -71,6 +70,5 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs index 994427ac76f89..4a560d30ba3ce 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs @@ -86,7 +86,10 @@ pub fn get_missing_assoc_items( } /// Converts associated trait impl items to their trait definition counterpart -pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> Definition { +pub(crate) fn convert_to_def_in_trait<'db>( + db: &'db dyn HirDatabase, + def: Definition<'db>, +) -> Definition<'db> { (|| { let assoc = def.as_assoc_item(db)?; let trait_ = assoc.implemented_trait(db)?; @@ -96,7 +99,10 @@ pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> } /// If this is an trait (impl) assoc item, returns the assoc item of the corresponding trait definition. -pub(crate) fn as_trait_assoc_def(db: &dyn HirDatabase, def: Definition) -> Option { +pub(crate) fn as_trait_assoc_def<'db>( + db: &dyn HirDatabase, + def: Definition<'db>, +) -> Option> { let assoc = def.as_assoc_item(db)?; let trait_ = match assoc.container(db) { hir::AssocItemContainer::Trait(_) => return Some(def), @@ -105,11 +111,11 @@ pub(crate) fn as_trait_assoc_def(db: &dyn HirDatabase, def: Definition) -> Optio assoc_item_of_trait(db, assoc, trait_) } -fn assoc_item_of_trait( +fn assoc_item_of_trait<'db>( db: &dyn HirDatabase, assoc: hir::AssocItem, trait_: hir::Trait, -) -> Option { +) -> Option> { use hir::AssocItem::*; let name = match assoc { Function(it) => it.name(db), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 2030be436887a..639be5e85a59c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -274,7 +274,7 @@ fn get_default_constructor( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix, check_no_fix}; + use crate::tests::{check_diagnostics, check_fix, check_has_fix, check_no_fix}; #[test] fn missing_record_pat_field_diagnostic() { @@ -829,7 +829,7 @@ fn f() { #[test] fn test_fill_struct_pat_fields_partial() { - check_fix( + check_has_fix( r#" struct S { a: &'static str, b: i32 } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 808b76e08211e..18859c0db1e60 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -674,17 +674,6 @@ fn main() { #[test] fn orphan_unsafe_format_args() { // Checks that we don't place orphan arguments for formatting under an unsafe block. - check_diagnostics( - r#" -//- minicore: fmt_before_1_89_0 -fn foo() { - let p = 0xDEADBEEF as *const i32; - format_args!("", *p); - // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block -} - "#, - ); - check_diagnostics( r#" //- minicore: fmt diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index e4ee0666534f5..fa9a69c996718 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -7,7 +7,10 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // Diagnostic: need-mut // // This diagnostic is triggered on mutating an immutable variable. -pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NeedMut) -> Option { +pub(crate) fn need_mut( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::NeedMut<'_>, +) -> Option { let root = d.span.file_id.parse_or_expand(ctx.sema.db); let node = d.span.value.to_node(&root); let mut span = d.span; @@ -64,7 +67,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NeedMut) -> Op // This diagnostic is triggered when a mutable variable isn't actually mutated. pub(crate) fn unused_mut( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnusedMut, + d: &hir::UnusedMut<'_>, ) -> Option { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); let fixes = (|| { @@ -1093,14 +1096,17 @@ fn x(t: &[u8]) { use core::ops::{Deref, DerefMut}; use core::{marker::Unsize, ops::CoerceUnsized}; +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + #[lang = "owned_box"] pub struct Box { inner: *mut T, } impl Box { fn new(t: T) -> Self { - #[rustc_box] - Box::new(t) + box_new(t) } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index f6fe83177fba9..cc900808b5bc5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,7 +1,9 @@ use either::Either; -use hir::{HasSource, HirDisplay, Semantics, VariantId}; +use hir::{HasSource, HirDisplay, InFile, Semantics, VariantId}; use ide_db::text_edit::TextEdit; -use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange}; +use ide_db::{ + EditionedFileId, RootDatabase, helpers::is_editable_crate, source_change::SourceChange, +}; use syntax::{ AstNode, ast::{self, edit::IndentLevel, make}, @@ -85,7 +87,10 @@ fn missing_record_expr_field_fixes( record_field_list(fields)? } }; - let def_file_id = def_file_id.original_file(sema.db); + + if !is_editable_crate(module.krate(sema.db), sema.db) { + return None; + } let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?.adjusted(); if new_field_type.is_unknown() { @@ -97,36 +102,35 @@ fn missing_record_expr_field_fixes( make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?), ); - let (indent, offset, postfix, needs_comma) = - if let Some(last_field) = record_fields.fields().last() { - let indent = IndentLevel::from_node(last_field.syntax()); - let offset = last_field.syntax().text_range().end(); - let needs_comma = !last_field.to_string().ends_with(','); - (indent, offset, String::new(), needs_comma) - } else { - let indent = IndentLevel::from_node(record_fields.syntax()); - let offset = record_fields.l_curly_token()?.text_range().end(); - let postfix = if record_fields.syntax().text().contains_char('\n') { - ",".into() - } else { - format!(",\n{indent}") - }; - (indent + 1, offset, postfix, false) - }; + let after = if let Some(last_field) = record_fields.fields().last() { + last_field.syntax().last_token()? + } else { + record_fields.l_curly_token()? + }; + let hir::FileRange { file_id, range } = + InFile::new(def_file_id, after.text_range()).original_node_file_range_opt(sema.db)?.0; + let origin = sema.parse(file_id).syntax().covering_element(range); + let indent = IndentLevel::from_element(&origin); + + let (comma, indent, postfix) = match after.kind() { + syntax::SyntaxKind::L_CURLY => { + let newline = !after.next_token().is_some_and(|it| it.text().contains('\n')); + ("", indent + 1, if newline { format!(",\n{indent}") } else { ",".into() }) + } + _ => (",", indent, String::new()), + }; - let mut new_field = new_field.to_string(); // FIXME: check submodule instead of FileId - let vis = if usage_file_id != def_file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { + let vis = if usage_file_id != file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { "pub(crate) " } else { "" }; - let comma = if needs_comma { "," } else { "" }; - new_field = format!("{comma}\n{indent}{vis}{new_field}{postfix}"); + let new_field = format!("{comma}\n{indent}{vis}{new_field}{postfix}"); let source_change = SourceChange::from_text_edit( - def_file_id.file_id(sema.db), - TextEdit::insert(offset, new_field), + file_id.file_id(sema.db), + TextEdit::insert(range.end(), new_field), ); return Some(vec![fix( @@ -449,6 +453,80 @@ fn main() { ) } + #[test] + fn test_add_field_macro_defined_struct() { + check_fix( + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +identity! { + struct S { + a: i32 + } +} +fn f() { let _ = S { a: 1, b$0: false }; } +"#, + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +identity! { + struct S { + a: i32, + b: bool + } +} +fn f() { let _ = S { a: 1, b: false }; } +"#, + ); + } + + #[test] + fn test_add_field_macro_defined_struct_large_offset() { + // Regression test: we should handle macro definitions whose offset is larger than + // the max position in main.rs. + check_fix( + r#" +//- /main.rs +#[macro_use] +mod m; +make_items!(); +fn f() { let _ = S { a: 1, bbb$0: 2 }; } +//- /m.rs +macro_rules! make_items { + () => { + pub struct Padding { + pub p0: i32, pub p1: i32, pub p2: i32, + pub p3: i32, pub p4: i32, pub p5: i32, + } + pub struct S { pub a: i32 } + }; +} +"#, + r#" +macro_rules! make_items { + () => { + pub struct Padding { + pub p0: i32, pub p1: i32, pub p2: i32, + pub p3: i32, pub p4: i32, pub p5: i32, + } + pub struct S { pub a: i32, + pub(crate) bbb: i32 } + }; +} +"#, + ) + } + + #[test] + fn no_such_field_no_fix_for_struct_in_library_crate() { + check_no_fix( + r#" +//- /lib.rs crate:lib new_source_root:library +pub struct S { pub a: i32 } +//- /main.rs crate:main deps:lib new_source_root:local +fn f() { let _ = lib::S { a: 1, b$0: false }; } +"#, + ) + } + #[test] fn test_struct_field_private() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs index 4a253bc8310c0..702f9fa7c9976 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs @@ -9,18 +9,19 @@ pub(crate) fn unimplemented_trait<'db>( ctx: &DiagnosticsContext<'_, 'db>, d: &hir::UnimplementedTrait<'db>, ) -> Diagnostic { - let message = match &d.root_trait_predicate { - Some(root_predicate) if *root_predicate != d.trait_predicate => format!( - "the trait bound `{}` is not satisfied\n\ - required by the bound `{}`\n", - d.trait_predicate.display(ctx.db(), ctx.display_target), - root_predicate.display(ctx.db(), ctx.display_target), - ), - _ => format!( - "the trait bound `{}` is not satisfied", - d.trait_predicate.display(ctx.db(), ctx.display_target), - ), - }; + let mut message = format!( + "the trait bound `{}` is not satisfied", + d.trait_predicate.display(ctx.db(), ctx.display_target), + ); + for parent_predicate in &d.parent_trait_predicates { + message.push_str(&format!( + "\nrequired by the bound `{}`", + parent_predicate.display(ctx.db(), ctx.display_target), + )); + } + if !d.parent_trait_predicates.is_empty() { + message.push('\n'); + } Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0277"), @@ -46,6 +47,10 @@ fn bar() { foo([1]); // ^^^ error: the trait bound `i32: Trait` is not satisfied // | required by the bound `[i32; 1]: Trait` + foo([[1]]); + // ^^^ error: the trait bound `i32: Trait` is not satisfied + // | required by the bound `[i32; 1]: Trait` + // | required by the bound `[[i32; 1]; 1]: Trait` } "#, ); @@ -77,7 +82,6 @@ fn foo() { //- minicore: iterator fn foo() { for _ in () {} - // ^^ error: the trait bound `(): Iterator` is not satisfied // ^^ error: the trait bound `(): Iterator` is not satisfied // | required by the bound `(): IntoIterator` } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index dede3b4aad5af..9e5150cf5247c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -15,7 +15,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // This diagnostic is triggered when a local variable is not used. pub(crate) fn unused_variables( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnusedVariable, + d: &hir::UnusedVariable<'_>, ) -> Option { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); if ast.file_id.macro_file().is_some() { diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index 461de4092e30a..3dbba0ff2dab4 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -25,13 +25,13 @@ pub(crate) struct ResolvedPattern<'db> { pub(crate) placeholders_by_stand_in: FxHashMap, pub(crate) node: SyntaxNode, // Paths in `node` that we've resolved. - pub(crate) resolved_paths: FxHashMap, + pub(crate) resolved_paths: FxHashMap>, pub(crate) ufcs_function_calls: FxHashMap>, pub(crate) contains_self: bool, } -pub(crate) struct ResolvedPath { - pub(crate) resolution: hir::PathResolution, +pub(crate) struct ResolvedPath<'db> { + pub(crate) resolution: hir::PathResolution<'db>, /// The depth of the ast::Path that was resolved within the pattern. pub(crate) depth: u32, } @@ -120,7 +120,7 @@ impl<'db> Resolver<'_, 'db> { &self, node: SyntaxNode, depth: u32, - resolved_paths: &mut FxHashMap, + resolved_paths: &mut FxHashMap>, ) -> Result<(), SsrError> { use syntax::ast::AstNode; if let Some(path) = ast::Path::cast(node.clone()) { @@ -165,7 +165,7 @@ impl<'db> Resolver<'_, 'db> { false } - fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool { + fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution<'db>) -> bool { match resolution { hir::PathResolution::Def(hir::ModuleDef::Function(function)) if function.as_assoc_item(self.resolution_scope.scope.db).is_some() => @@ -215,7 +215,7 @@ impl<'db> ResolutionScope<'db> { self.node.ancestors().find(|node| node.kind() == SyntaxKind::FN) } - fn resolve_path(&self, path: &ast::Path) -> Option { + fn resolve_path(&self, path: &ast::Path) -> Option> { // First try resolving the whole path. This will work for things like // `std::collections::HashMap`, but will fail for things like // `std::collections::HashMap::new`. diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index 51e4951cf662b..c6a1d69672119 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -17,8 +17,8 @@ use syntax::{AstNode, SyntaxKind, SyntaxNode, ast}; /// and as a pattern. In each, the usages of `foo::Bar` are the same and we'd like to avoid finding /// them more than once. #[derive(Default)] -pub(crate) struct UsageCache { - usages: Vec<(Definition, UsageSearchResult)>, +pub(crate) struct UsageCache<'db> { + usages: Vec<(Definition<'db>, UsageSearchResult)>, } impl<'db> MatchFinder<'db> { @@ -28,7 +28,7 @@ impl<'db> MatchFinder<'db> { pub(crate) fn find_matches_for_rule( &self, rule: &ResolvedRule<'db>, - usage_cache: &mut UsageCache, + usage_cache: &mut UsageCache<'db>, matches_out: &mut Vec, ) { if rule.pattern.contains_self { @@ -51,11 +51,11 @@ impl<'db> MatchFinder<'db> { &self, rule: &ResolvedRule<'db>, pattern: &ResolvedPattern<'db>, - usage_cache: &mut UsageCache, + usage_cache: &mut UsageCache<'db>, matches_out: &mut Vec, ) { if let Some(resolved_path) = pick_path_for_usages(pattern) { - let definition: Definition = resolved_path.resolution.into(); + let definition: Definition<'db> = resolved_path.resolution.into(); for file_range in self.find_usages(usage_cache, definition).file_ranges() { for node_to_match in self.find_nodes_to_match(resolved_path, file_range) { if !is_search_permitted_ancestors(&node_to_match) { @@ -70,7 +70,7 @@ impl<'db> MatchFinder<'db> { fn find_nodes_to_match( &self, - resolved_path: &ResolvedPath, + resolved_path: &ResolvedPath<'db>, file_range: FileRange, ) -> Vec { let file = self.sema.parse(file_range.file_id); @@ -112,8 +112,8 @@ impl<'db> MatchFinder<'db> { fn find_usages<'a>( &self, - usage_cache: &'a mut UsageCache, - definition: Definition, + usage_cache: &'a mut UsageCache<'db>, + definition: Definition<'db>, ) -> &'a UsageSearchResult { // Logically if a lookup succeeds we should just return it. Unfortunately returning it would // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a @@ -252,8 +252,8 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { node.kind() != SyntaxKind::USE } -impl UsageCache { - fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { +impl<'db> UsageCache<'db> { + fn find(&mut self, definition: &Definition<'db>) -> Option<&UsageSearchResult> { // We expect a very small number of cache entries (generally 1), so a linear scan should be // fast enough and avoids the need to implement Hash for Definition. for (d, refs) in &self.usages { @@ -268,7 +268,9 @@ impl UsageCache { /// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't /// something that we can find references to. We then somewhat arbitrarily pick the path that is the /// longest as this is hopefully more likely to be less common, making it faster to find. -fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> { +fn pick_path_for_usages<'a, 'db>( + pattern: &'a ResolvedPattern<'db>, +) -> Option<&'a ResolvedPath<'db>> { // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are // private to the current module, then we definitely would want to pick them over say a path // from std. Possibly we should go further than this and intersect the search scopes for all diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index fd462d003d7dd..70d05cd3b5dcc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -53,7 +53,7 @@ const MARKDOWN_OPTIONS: Options = pub(crate) fn rewrite_links( db: &RootDatabase, markdown: &str, - definition: Definition, + definition: Definition<'_>, range_map: Option<&hir::Docs>, ) -> String { let mut cb = broken_link_clone_cb; @@ -207,13 +207,13 @@ pub(crate) fn extract_definitions_from_docs( .collect() } -pub(crate) fn resolve_doc_path_for_def( +pub(crate) fn resolve_doc_path_for_def<'db>( db: &dyn HirDatabase, - def: Definition, + def: Definition<'db>, link: &str, ns: Option, is_inner_doc: hir::IsInnerDoc, -) -> Option { +) -> Option> { match def { Definition::Module(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), @@ -243,10 +243,10 @@ pub(crate) fn resolve_doc_path_for_def( .map(Definition::from) } -pub(crate) fn doc_attributes( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn doc_attributes<'db>( + sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, -) -> Option<(hir::AttrsWithOwner, Definition)> { +) -> Option<(hir::AttrsWithOwner, Definition<'db>)> { match_ast! { match node { ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))), @@ -293,12 +293,12 @@ pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option( + pub(crate) fn get_definition_with_descend_at<'db, T>( self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, offset: TextSize, // Definition, CommentOwner, range of intra doc link in original file - mut cb: impl FnMut(Definition, SyntaxNode, TextRange) -> Option, + mut cb: impl FnMut(Definition<'db>, SyntaxNode, TextRange) -> Option, ) -> Option { let DocCommentToken { prefix_len, doc_token } = self; // offset relative to the comments contents @@ -346,11 +346,11 @@ impl DocCommentToken { /// //! [`S$0`] /// } /// ``` - fn doc_attributes( - sema: &Semantics<'_, RootDatabase>, + fn doc_attributes<'db>( + sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, is_inner_doc: bool, - ) -> Option<(AttrsWithOwner, Definition)> { + ) -> Option<(AttrsWithOwner, Definition<'db>)> { if is_inner_doc && node.kind() != SOURCE_FILE { let parent = node.parent()?; doc_attributes(sema, &parent).or(doc_attributes(sema, &parent.parent()?)) @@ -373,7 +373,7 @@ fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>) // https://github.com/rust-lang/rfcs/pull/2988 fn get_doc_links( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target_dir: Option<&str>, sysroot: Option<&str>, ) -> DocumentationLinks { @@ -411,7 +411,7 @@ fn get_doc_links( fn rewrite_intra_doc_link( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target: &str, title: &str, is_inner_doc: hir::IsInnerDoc, @@ -455,7 +455,7 @@ fn rewrite_intra_doc_link( } /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). -fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option { +fn rewrite_url_link(db: &RootDatabase, def: Definition<'_>, target: &str) -> Option { if !(target.contains('#') || target.contains(".html")) { return None; } @@ -472,7 +472,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option< url.join(target).ok().map(Into::into) } -fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { +fn mod_path_of_def(db: &RootDatabase, def: Definition<'_>) -> Option { def.canonical_module_path(db).map(|it| { let mut path = String::new(); it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.as_str())); @@ -540,7 +540,7 @@ fn map_links<'e>( /// ``` fn get_doc_base_urls( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target_dir: Option<&str>, sysroot: Option<&str>, ) -> (Option, Option) { @@ -632,10 +632,10 @@ fn get_doc_base_urls( /// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next /// ^^^^^^^^^^^^^^^^^^^ /// ``` -fn filename_and_frag_for_def( +fn filename_and_frag_for_def<'db>( db: &dyn HirDatabase, - def: Definition, -) -> Option<(Definition, String, Option)> { + def: Definition<'db>, +) -> Option<(Definition<'db>, String, Option)> { if let Some(assoc_item) = def.as_assoc_item(db) { let def = match assoc_item.container(db) { AssocItemContainer::Trait(t) => t.into(), diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index 509c55a31e58d..720528d0b52f2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -86,7 +86,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { fn def_under_cursor<'db>( sema: &Semantics<'db, RootDatabase>, position: &FilePosition, -) -> (Definition, Cow<'db, hir::Docs>) { +) -> (Definition<'db>, Cow<'db, hir::Docs>) { let (docs, def) = sema .parse_guess_edition(position.file_id) .syntax() @@ -104,7 +104,7 @@ fn def_under_cursor<'db>( fn node_to_def<'db>( sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, -) -> Option>, Definition)>> { +) -> Option>, Definition<'db>)>> { Some(match_ast! { match node { ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))), diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index b6d1689437ff1..b778066f42728 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -399,7 +399,7 @@ fn try_lookup_macro_def_in_macro_use( /// ``` fn try_filter_trait_item_definition( sema: &Semantics<'_, RootDatabase>, - def: &Definition, + def: &Definition<'_>, ) -> Option> { let db = sema.db; let assoc = def.as_assoc_item(db)?; @@ -653,7 +653,7 @@ fn nav_for_break_points( Some(navs) } -fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec { +fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Vec { def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default() } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index ffd144a827e34..9de956be5ed19 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -29,7 +29,7 @@ pub(crate) fn goto_type_definition( })?; let mut res = Vec::new(); - let mut push = |def: Definition| { + let mut push = |def: Definition<'_>| { if let Some(navs) = def.try_to_nav(&sema) { for nav in navs { if !res.contains(&nav) { diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index db5464a1fe93a..dfe8dcaa7745a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -668,7 +668,10 @@ fn cover_range(r0: Option, r1: Option) -> Option, token: SyntaxToken) -> FxHashSet { +fn find_defs<'db>( + sema: &Semantics<'db, RootDatabase>, + token: SyntaxToken, +) -> FxHashSet> { sema.descend_into_macros_exact(token) .into_iter() .filter_map(|token| IdentClass::classify_token(sema, &token)) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 28e1dc72bf4cd..3d73b5b0f24d4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -450,7 +450,7 @@ fn hover_ranged( pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, file_id: FileId, - def: Definition, + def: Definition<'_>, subst: Option>, scope_node: &SyntaxNode, macro_arm: Option, @@ -568,7 +568,7 @@ fn notable_traits<'db>( fn show_implementations_action( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, ) -> Option { fn to_action(nav_target: NavigationTarget) -> HoverAction { HoverAction::Implementation(FilePosition { @@ -590,7 +590,7 @@ fn show_implementations_action( fn show_fn_references_action( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, ) -> Option { match def { Definition::Function(it) => { @@ -607,7 +607,7 @@ fn show_fn_references_action( fn runnable_action( sema: &hir::Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, file_id: FileId, ) -> Option { match def { @@ -628,7 +628,7 @@ fn runnable_action( fn goto_type_action_for_def( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], subst_types: Option)>>, edition: Edition, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 638ea6bdb9773..f26b99292929e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -338,7 +338,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option, markup: &Markup, markup_range_map: Option, config: &HoverConfig<'_>, @@ -352,7 +352,11 @@ pub(super) fn process_markup( Markup::from(markup) } -fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -> Option { +fn definition_owner_name( + db: &RootDatabase, + def: Definition<'_>, + edition: Edition, +) -> Option { match def { Definition::Field(f) => { let parent = f.parent_def(db); @@ -435,17 +439,13 @@ pub(super) fn path( edition: Edition, ) -> 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() - .rev() - .flat_map(|it| it.name(db).map(|name| name.display(db, edition).to_string())); + let module_path = module.path_segments(db).map(|it| it.display(db, edition).to_string()); crate_name.into_iter().chain(module_path).chain(item_name).join("::") } pub(super) fn definition( db: &RootDatabase, - def: Definition, + def: Definition<'_>, famous_defs: Option<&FamousDefs<'_, '_>>, notable_traits: &[(Trait, Vec<(Option>, Name)>)], macro_arm: Option, @@ -1077,7 +1077,7 @@ fn closure_ty( Some(res) } -fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option { +fn definition_path(db: &RootDatabase, &def: &Definition<'_>, edition: Edition) -> Option { if matches!( def, Definition::TupleField(_) diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs index 994d325cccde6..f8e8d874492c3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs @@ -60,7 +60,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura pub(crate) fn render_const_eval_error( db: &RootDatabase, - e: ConstEvalError, + e: ConstEvalError<'_>, display_target: DisplayTarget, ) -> String { let span_formatter = |file_id, text_range: TextRange| { diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index dded01520ffbc..c4a3ec1e8eae9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -333,11 +333,21 @@ impl Analysis { }) } - pub fn parallel_prime_caches(&self, num_worker_threads: usize, cb: F) -> Cancellable<()> + /// Warm caches for the given `scope`. `scope` must be closed under + /// transitive dependencies; callers that want to prime everything pass + /// `&base_db::all_crates(db)`. + pub fn parallel_prime_caches( + &self, + scope: &[Crate], + num_worker_threads: usize, + cb: F, + ) -> Cancellable<()> where F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe, { - self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb)) + self.with_db(move |db| { + prime_caches::parallel_prime_caches(db, scope, num_worker_threads, &cb) + }) } /// Gets the text of the source file. diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 335e1b5b13caa..c92f2bbace84a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -118,7 +118,7 @@ pub enum MonikerResult { } impl MonikerResult { - pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option { + pub fn from_def(db: &RootDatabase, def: Definition<'_>, from_crate: Crate) -> Option { def_to_moniker(db, def, from_crate) } } @@ -178,7 +178,7 @@ pub(crate) fn moniker( Some(RangeInfo::new(original_token.text_range(), navs)) } -pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformationKind { +pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition<'_>) -> SymbolInformationKind { use SymbolInformationKind::*; match def { @@ -250,7 +250,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati /// definitions. pub(crate) fn def_to_moniker( db: &RootDatabase, - definition: Definition, + definition: Definition<'_>, from_crate: Crate, ) -> Option { match definition { @@ -266,7 +266,7 @@ pub(crate) fn def_to_moniker( fn enclosing_def_to_moniker( db: &RootDatabase, - mut def: Definition, + mut def: Definition<'_>, from_crate: Crate, ) -> Option { loop { @@ -280,7 +280,7 @@ fn enclosing_def_to_moniker( fn def_to_non_local_moniker( db: &RootDatabase, - definition: Definition, + definition: Definition<'_>, from_crate: Crate, ) -> Option { let module = match definition { diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index fd6c8263f9d8c..125b2f495acca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -296,7 +296,7 @@ impl<'db> TryToNav for FileSymbol<'db> { } } -impl TryToNav for Definition { +impl TryToNav for Definition<'_> { fn try_to_nav( &self, sema: &Semantics<'_, RootDatabase>, @@ -640,7 +640,7 @@ impl TryToNav for hir::GenericParam { } } -impl ToNav for LocalSource { +impl ToNav for LocalSource<'_> { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { let InFile { file_id, value } = &self.source; let file_id = *file_id; @@ -675,7 +675,7 @@ impl ToNav for LocalSource { } } -impl ToNav for hir::Local { +impl ToNav for hir::Local<'_> { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { self.primary_source(db).to_nav(db) } diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 34286c4790b7d..bb79fc2aa0858 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -121,8 +121,8 @@ pub struct FindAllRefsConfig<'a> { /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages /// In these cases, other kinds of references (like type references) are filtered out. -pub(crate) fn find_all_refs( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn find_all_refs<'db>( + sema: &Semantics<'db, RootDatabase>, position: FilePosition, config: &FindAllRefsConfig<'_>, ) -> Option> { @@ -130,7 +130,7 @@ pub(crate) fn find_all_refs( let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); let exclude_library_refs = !is_library_file(sema.db, position.file_id); let make_searcher = |literal_search: bool| { - move |def: Definition| { + move |def: Definition<'db>| { let mut included_categories = ReferenceCategory::all(); if config.exclude_imports { included_categories.remove(ReferenceCategory::IMPORT); @@ -228,11 +228,11 @@ fn is_library_file(db: &RootDatabase, file_id: FileId) -> bool { db.source_root(source_root).source_root(db).is_library } -pub(crate) fn find_defs( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn find_defs<'db>( + sema: &Semantics<'db, RootDatabase>, syntax: &SyntaxNode, offset: TextSize, -) -> Option> { +) -> Option>> { if let Some(token) = syntax.token_at_offset(offset).left_biased() && let Some(doc_comment) = token_as_doc_comment(&token) { @@ -304,7 +304,7 @@ pub(crate) fn find_defs( /// Filter out all non-literal usages for adt-defs fn retain_adt_literal_usages( usages: &mut UsageSearchResult, - def: Definition, + def: Definition<'_>, sema: &Semantics<'_, RootDatabase>, ) { let refs = usages.references.values_mut(); @@ -600,7 +600,7 @@ fn main() { false, false, expect![[r#" - Some Variant FileId(1) 6737..6769 6762..6766 + Some Variant FileId(1) 6734..6766 6759..6763 FileId(0) 46..50 "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 185815fa73197..4a2cc5f551b6e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -274,13 +274,14 @@ fn alias_fallback( Some(builder.finish()) } -fn find_definitions( - sema: &Semantics<'_, RootDatabase>, +fn find_definitions<'db>( + sema: &Semantics<'db, RootDatabase>, syntax: &SyntaxNode, FilePosition { file_id, offset }: FilePosition, new_name: &Name, -) -> RenameResult> -{ +) -> RenameResult< + impl Iterator, Name, RenameDefinition)>, +> { let maybe_format_args = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); @@ -492,9 +493,9 @@ fn transform_assoc_fn_into_method_call( } } -fn rename_to_self( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, +fn rename_to_self<'db>( + sema: &Semantics<'db, RootDatabase>, + local: hir::Local<'db>, ) -> RenameResult { if never!(local.is_self(sema.db)) { bail!("rename_to_self invoked on self"); @@ -749,9 +750,9 @@ fn transform_method_call_into_assoc_fn( } } -fn rename_self_to_param( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, +fn rename_self_to_param<'db>( + sema: &Semantics<'db, RootDatabase>, + local: hir::Local<'db>, self_param: hir::SelfParam, new_name: &Name, identifier_kind: IdentifierKind, diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index ce4e5cf97fb24..77d1d5a23f5a5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -487,7 +487,7 @@ fn runnable_mod_outline_definition( }) } -fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Option { +fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Option { let db = sema.db; let attrs = match def { Definition::Module(it) => it.attrs(db), diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index db24c8dd0687c..9e8d772cb3d12 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -31,7 +31,7 @@ pub struct StaticIndex<'a> { pub tokens: TokenStore, analysis: &'a Analysis, db: &'a RootDatabase, - def_map: FxHashMap, + def_map: FxHashMap, TokenId>, } #[derive(Debug)] @@ -131,7 +131,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec { fn documentation_for_definition( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, scope_node: &SyntaxNode, ) -> Option> { let famous_defs = match &def { @@ -147,7 +147,7 @@ fn documentation_for_definition( fn get_definitions<'db>( sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option>), 2>> { +) -> Option, Option>), 2>> { for token in sema.descend_into_macros_exact(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); if let Some(defs) = def @@ -164,7 +164,7 @@ pub enum VendoredLibrariesConfig<'a> { Excluded, } -impl StaticIndex<'_> { +impl<'a> StaticIndex<'a> { fn add_file(&mut self, file_id: FileId) { let current_crate = crates_for(self.db, file_id).pop().map(Into::into); let folds = self.analysis.folding_ranges(file_id, true).unwrap(); @@ -195,7 +195,7 @@ impl StaticIndex<'_> { }; let mut result = StaticIndexedFile { file_id, folds, tokens: vec![] }; - let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| { + let mut add_token = |def: Definition<'a>, range: TextRange, scope_node: &SyntaxNode| { let id = if let Some(it) = self.def_map.get(&def) { *it } else { @@ -265,7 +265,7 @@ impl StaticIndex<'_> { self.files.push(result); } - pub fn compute<'a>( + pub fn compute( analysis: &'a Analysis, vendored_libs_config: VendoredLibrariesConfig<'_>, ) -> StaticIndex<'a> { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 6823736d12730..92daacd6d314f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -457,7 +457,7 @@ fn highlight_name( pub(super) fn highlight_def( sema: &Semantics<'_, RootDatabase>, krate: Option, - def: Definition, + def: Definition<'_>, edition: Edition, is_ref: bool, ) -> Highlight { @@ -864,7 +864,7 @@ fn highlight_name_ref_by_syntax( } } -fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local, db: &RootDatabase) -> bool { +fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local<'_>, db: &RootDatabase) -> bool { // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. parents_match(node.clone().into(), &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 9af6d67b59803..56020b401780a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -211,7 +211,7 @@ pub(super) fn doc_comment( } } -fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition) -> HlTag { +fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition<'_>) -> HlTag { let symbol = match def { Definition::Crate(_) | Definition::ExternCrateDecl(_) => SymbolKind::CrateRoot, Definition::Module(m) if m.is_crate_root(db) => SymbolKind::CrateRoot, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 22f3ba9ed8314..ad829d9e99c2c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html @@ -43,6 +43,8 @@
fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
 
+fn non_fixture(#[rust_analyzer] ra_fixture: &str) {}
+
 fn main() {
     fixture(r#"
 @@- minicore: sized
@@ -59,4 +61,6 @@
     }$0)
 }"
     );
+
+    non_fixture(r"@@- ");
 }
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index c0a923afbe6a3..f4b103902499c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -447,7 +447,7 @@ macro_rules! void_2024 { } "#, - expect_file![format!("./test_data/highlight_keywords_macros.html")], + expect_file!["./test_data/highlight_keywords_macros.html"], false, ); } @@ -1066,6 +1066,8 @@ fn test_injection() { r##" fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {} +fn non_fixture(#[rust_analyzer] ra_fixture: &str) {} + fn main() { fixture(r#" @@- minicore: sized @@ -1082,6 +1084,8 @@ fn foo() { }\$0) }" ); + + non_fixture(r"@@- "); } "##, expect_file!["./test_data/highlight_injection.html"], diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index f5c5cb432d559..bf2331a40f9b6 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -197,7 +197,8 @@ pub fn load_workspace_into_db( ); if load_config.prefill_caches { - prime_caches::parallel_prime_caches(db, load_config.num_worker_threads, &|_| ()); + let all = ide_db::base_db::all_crates(db); + prime_caches::parallel_prime_caches(db, &all, load_config.num_worker_threads, &|_| ()); } Ok((vfs, proc_macro_server.and_then(Result::ok))) diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index e135291d89dfe..440e75eb7e1b7 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -275,7 +275,7 @@ fn expand_subtree( } } - let res = count(binding, 0, depth.unwrap_or(0)); + let res = count(binding, 0, *depth); builder.push(tt::Leaf::Literal(tt::Literal { text_and_suffix: sym::Integer::get(res), diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 9fbd06cf88626..7c3d451d04650 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -92,39 +92,14 @@ impl MetaTemplate { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum Op { - Var { - name: Symbol, - kind: Option, - id: Span, - }, - Ignore { - name: Symbol, - id: Span, - }, - Index { - depth: usize, - }, - Len { - depth: usize, - }, - Count { - name: Symbol, - // FIXME: `usize` once we drop support for 1.76 - depth: Option, - }, - Concat { - elements: Box<[ConcatMetaVarExprElem]>, - span: Span, - }, - Repeat { - tokens: MetaTemplate, - kind: RepeatKind, - separator: Option>, - }, - Subtree { - tokens: MetaTemplate, - delimiter: tt::Delimiter, - }, + Var { name: Symbol, kind: Option, id: Span }, + Ignore { name: Symbol, id: Span }, + Index { depth: usize }, + Len { depth: usize }, + Count { name: Symbol, depth: usize }, + Concat { elements: Box<[ConcatMetaVarExprElem]>, span: Span }, + Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option> }, + Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter }, Literal(tt::Literal), Punct(Box>), Ident(tt::Ident), @@ -432,11 +407,8 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result { s if sym::count == *s => { args_iter.expect_dollar()?; let ident = args_iter.expect_ident()?; - let depth = if try_eat_comma(&mut args_iter) { - Some(parse_depth(&mut args_iter)?) - } else { - None - }; + let depth = + if try_eat_comma(&mut args_iter) { parse_depth(&mut args_iter)? } else { 0 }; Op::Count { name: ident.sym.clone(), depth } } s if sym::concat == *s => { diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index 9f84f632d5e44..926a9e327e8c4 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -473,10 +473,6 @@ impl WorkspaceBuildScripts { if let Some(lockfile_copy) = &lockfile_copy { requires_unstable_options = true; match lockfile_copy.usage { - LockfileUsage::WithFlag => { - cmd.arg("--lockfile-path"); - cmd.arg(lockfile_copy.path.as_str()); - } LockfileUsage::WithEnvVarUnstable => { cmd.arg("-Zlockfile-path"); cmd.env( diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index defd9f96ab5fb..a6bfea8200c53 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -143,8 +143,6 @@ pub(crate) struct LockfileCopy { } pub(crate) enum LockfileUsage { - /// Rust [1.82.0, 1.95.0). `cargo --lockfile-path ` - WithFlag, /// Rust [1.95.0, 1.97.0). `CARGO_RESOLVER_LOCKFILE_PATH= cargo -Zlockfile-path ` WithEnvVarUnstable, /// Rust >= 1.97.0. `CARGO_RESOLVER_LOCKFILE_PATH= cargo ` @@ -155,15 +153,6 @@ pub(crate) fn make_lockfile_copy( toolchain_version: &semver::Version, lockfile_path: &Utf8Path, ) -> Option { - const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG: semver::Version = - semver::Version { - major: 1, - minor: 82, - patch: 0, - pre: semver::Prerelease::EMPTY, - build: semver::BuildMetadata::EMPTY, - }; - const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE: semver::Version = semver::Version { major: 1, @@ -187,8 +176,6 @@ pub(crate) fn make_lockfile_copy( } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE { LockfileUsage::WithEnvVarUnstable - } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG { - LockfileUsage::WithFlag } else { return None; }; diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 97375fe9ddd1a..3db5a0fffce7f 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -767,10 +767,6 @@ impl FetchMetadata { let mut using_lockfile_copy = false; if let Some(lockfile_copy) = &lockfile_copy { match lockfile_copy.usage { - LockfileUsage::WithFlag => { - other_options.push("--lockfile-path".to_owned()); - other_options.push(lockfile_copy.path.to_string()); - } LockfileUsage::WithEnvVarUnstable => { other_options.push("-Zlockfile-path".to_owned()); command.env("CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str()); diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 4ea136afbb455..4e2c1e846ce30 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -267,7 +267,7 @@ pub struct Crate { // Extra crate-level attributes, without the surrounding `#![]`. pub(crate) crate_attrs: Vec, pub(crate) proc_macro_dylib_path: Option, - pub(crate) is_workspace_member: bool, + pub is_workspace_member: bool, pub(crate) include: Vec, pub(crate) exclude: Vec, pub(crate) is_proc_macro: bool, diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml deleted file mode 100644 index 5991120a30d83..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "query-group-macro" -version = "0.0.0" -repository.workspace = true -description = "A macro mimicking the `#[salsa::query_group]` macro for migrating to new Salsa" - -authors.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true - -[lib] -doctest = false -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] } - -[dev-dependencies] -expect-test = "1.5.1" -salsa.workspace = true -salsa-macros.workspace = true diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs deleted file mode 100644 index 9f7459066d908..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ /dev/null @@ -1,256 +0,0 @@ -//! A macro that mimics the old Salsa-style `#[query_group]` macro. - -use std::vec; - -use proc_macro::TokenStream; -use proc_macro2::Span; -use queries::{Queries, TrackedQuery, Transparent}; -use quote::{ToTokens, format_ident, quote}; -use syn::parse::ParseStream; -use syn::spanned::Spanned; -use syn::visit_mut::VisitMut; -use syn::{Attribute, FnArg, ItemTrait, Path, TraitItem, parse_quote, parse_quote_spanned}; - -mod queries; - -#[proc_macro_attribute] -pub fn query_group(args: TokenStream, input: TokenStream) -> TokenStream { - match query_group_impl(args, input.clone()) { - Ok(tokens) => tokens, - Err(e) => token_stream_with_error(input, e), - } -} - -struct SalsaAttr { - name: String, - tts: TokenStream, - span: Span, -} - -impl std::fmt::Debug for SalsaAttr { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "{:?}", self.name) - } -} - -impl TryFrom for SalsaAttr { - type Error = syn::Attribute; - - fn try_from(attr: syn::Attribute) -> Result { - if is_not_salsa_attr_path(attr.path()) { - return Err(attr); - } - - let span = attr.span(); - - let name = attr.path().segments[1].ident.to_string(); - let tts = match attr.meta { - syn::Meta::Path(path) => path.into_token_stream(), - syn::Meta::List(ref list) => { - let tts = list - .into_token_stream() - .into_iter() - .skip(attr.path().to_token_stream().into_iter().count()); - proc_macro2::TokenStream::from_iter(tts) - } - syn::Meta::NameValue(nv) => nv.into_token_stream(), - } - .into(); - - Ok(SalsaAttr { name, tts, span }) - } -} - -fn is_not_salsa_attr_path(path: &syn::Path) -> bool { - path.segments.first().map(|s| s.ident != "salsa").unwrap_or(true) || path.segments.len() != 2 -} - -fn filter_attrs(attrs: Vec) -> (Vec, Vec) { - let mut other = vec![]; - let mut salsa = vec![]; - // Leave non-salsa attributes untouched. These are - // attributes that don't start with `salsa::` or don't have - // exactly two segments in their path. - for attr in attrs { - match SalsaAttr::try_from(attr) { - Ok(it) => salsa.push(it), - Err(it) => other.push(it), - } - } - (other, salsa) -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum QueryKind { - TrackedWithSalsaStruct, - Transparent, -} - -pub(crate) fn query_group_impl( - _args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> Result { - let mut item_trait = syn::parse::(input)?; - - let supertraits = &item_trait.supertraits; - - let db_attr: Attribute = parse_quote! { - #[salsa_macros::db] - }; - item_trait.attrs.push(db_attr); - - let trait_name_ident = &item_trait.ident.clone(); - let input_struct_name = format_ident!("{}Data", trait_name_ident); - let create_data_ident = format_ident!("create_data_{}", trait_name_ident); - - let mut trait_methods = vec![]; - - for item in &mut item_trait.items { - if let syn::TraitItem::Fn(method) = item { - let signature = &method.sig; - - let (_attrs, salsa_attrs) = filter_attrs(method.attrs.clone()); - - let mut query_kind = QueryKind::TrackedWithSalsaStruct; - let mut invoke = None; - - let params: Vec = signature.inputs.clone().into_iter().collect(); - let pat_and_tys = params - .into_iter() - .filter(|fn_arg| matches!(fn_arg, FnArg::Typed(_))) - .map(|fn_arg| match fn_arg { - FnArg::Typed(pat_type) => pat_type, - FnArg::Receiver(_) => unreachable!("this should have been filtered out"), - }) - .collect::>(); - - for SalsaAttr { name, tts, span } in salsa_attrs { - match name.as_str() { - "invoke" => { - let path = syn::parse::>(tts)?; - invoke = Some(path.0.clone()); - if query_kind != QueryKind::Transparent { - query_kind = QueryKind::TrackedWithSalsaStruct; - } - } - "tracked" if method.default.is_some() => { - query_kind = QueryKind::TrackedWithSalsaStruct; - } - "transparent" => { - query_kind = QueryKind::Transparent; - } - _ => return Err(syn::Error::new(span, format!("unknown attribute `{name}`"))), - } - } - - let syn::ReturnType::Type(_, _) = signature.output.clone() else { - return Err(syn::Error::new(signature.span(), "Queries must have a return type")); - }; - - if let Some(block) = &mut method.default { - SelfToDbRewriter.visit_block_mut(block); - } - - match (query_kind, invoke) { - (QueryKind::TrackedWithSalsaStruct, invoke) => { - let method = TrackedQuery { - trait_name: trait_name_ident.clone(), - signature: signature.clone(), - pat_and_tys: pat_and_tys.clone(), - invoke, - default: method.default.take(), - }; - - trait_methods.push(Queries::TrackedQuery(method)) - } - (QueryKind::Transparent, invoke) => { - let method = Transparent { - signature: method.sig.clone(), - pat_and_tys: pat_and_tys.clone(), - invoke, - default: method.default.take(), - }; - trait_methods.push(Queries::Transparent(method)); - } - } - } - } - - let input_struct = quote! { - #[salsa_macros::input] - pub(crate) struct #input_struct_name {} - }; - - let create_data_method = quote! { - #[allow(non_snake_case)] - #[salsa_macros::tracked] - fn #create_data_ident(db: &dyn #trait_name_ident) -> #input_struct_name { - #input_struct_name::new(db) - } - }; - - let trait_impl = quote! { - #[salsa_macros::db] - impl #trait_name_ident for DB - where - DB: #supertraits, - { - #(#trait_methods)* - } - }; - RemoveAttrsFromTraitMethods.visit_item_trait_mut(&mut item_trait); - - let out = quote! { - #item_trait - - #trait_impl - - #input_struct - - #create_data_method - } - .into(); - - Ok(out) -} - -/// Parenthesis helper -pub(crate) struct Parenthesized(pub(crate) T); - -impl syn::parse::Parse for Parenthesized -where - T: syn::parse::Parse, -{ - fn parse(input: ParseStream<'_>) -> syn::Result { - let content; - syn::parenthesized!(content in input); - content.parse::().map(Parenthesized) - } -} - -struct RemoveAttrsFromTraitMethods; - -impl VisitMut for RemoveAttrsFromTraitMethods { - fn visit_item_trait_mut(&mut self, i: &mut syn::ItemTrait) { - for item in &mut i.items { - if let TraitItem::Fn(trait_item_fn) = item { - trait_item_fn.attrs = vec![]; - } - } - } -} - -pub(crate) fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { - tokens.extend(TokenStream::from(error.into_compile_error())); - tokens -} - -struct SelfToDbRewriter; - -impl VisitMut for SelfToDbRewriter { - fn visit_expr_path_mut(&mut self, i: &mut syn::ExprPath) { - if i.path.is_ident("self") { - i.path = parse_quote_spanned!(i.path.span() => db); - } - } -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs deleted file mode 100644 index 935d65bb24581..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! The IR of the `#[query_group]` macro. - -use quote::{ToTokens, format_ident, quote, quote_spanned}; -use syn::{Ident, PatType, Path, spanned::Spanned}; - -pub(crate) struct TrackedQuery { - pub(crate) trait_name: Ident, - pub(crate) signature: syn::Signature, - pub(crate) pat_and_tys: Vec, - pub(crate) invoke: Option, - pub(crate) default: Option, -} - -impl ToTokens for TrackedQuery { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let sig = &self.signature; - let trait_name = &self.trait_name; - - let ret = &sig.output; - - let invoke = match &self.invoke { - Some(path) => path.to_token_stream(), - None => sig.ident.to_token_stream(), - }; - - let fn_ident = &sig.ident; - let shim: Ident = format_ident!("{}_shim", fn_ident); - - let pat_and_tys = &self.pat_and_tys; - let params = self - .pat_and_tys - .iter() - .map(|pat_type| pat_type.pat.clone()) - .collect::>>(); - - let invoke_block = match &self.default { - Some(default) => quote! { #default }, - None => { - let invoke_params: proc_macro2::TokenStream = quote! {db, #(#params),*}; - quote_spanned! { invoke.span() => {#invoke(#invoke_params)}} - } - }; - - let method = quote! { - #sig { - #[salsa_macros::tracked] - fn #shim<'db>( - db: &'db dyn #trait_name, - #(#pat_and_tys),* - ) #ret - #invoke_block - - #shim(self, #(#params),*) - } - }; - - method.to_tokens(tokens); - } -} - -pub(crate) struct Transparent { - pub(crate) signature: syn::Signature, - pub(crate) pat_and_tys: Vec, - pub(crate) invoke: Option, - pub(crate) default: Option, -} - -impl ToTokens for Transparent { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let sig = &self.signature; - - let ty = self - .pat_and_tys - .iter() - .map(|pat_type| pat_type.pat.clone()) - .collect::>>(); - - let invoke = match &self.invoke { - Some(path) => path.to_token_stream(), - None => sig.ident.to_token_stream(), - }; - - let method = match &self.default { - Some(default) => quote! { - #sig { let db = self; #default } - }, - None => quote! { - #sig { - #invoke(self, #(#ty),*) - } - }, - }; - - method.to_tokens(tokens); - } -} - -#[allow(clippy::large_enum_variant)] -pub(crate) enum Queries { - TrackedQuery(TrackedQuery), - Transparent(Transparent), -} - -impl ToTokens for Queries { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - match self { - Queries::TrackedQuery(tracked_query) => tracked_query.to_tokens(tokens), - Queries::Transparent(transparent) => transparent.to_tokens(tokens), - } - } -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs deleted file mode 100644 index 9e99b6d7fd0df..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs +++ /dev/null @@ -1,54 +0,0 @@ -use expect_test::expect; -use query_group_macro::query_group; - -mod logger_db; -use logger_db::LoggerDb; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait HelloWorldDatabase: salsa::Database { - // unadorned query - fn length_query_with_no_params(&self) -> usize; - - // not a query. should not invoked - #[salsa::transparent] - fn transparent_length(&self, key: ()) -> usize; -} - -fn length_query_with_no_params(db: &dyn HelloWorldDatabase) -> usize { - InputString::get(db).inner(db).len() -} - -fn transparent_length(db: &dyn HelloWorldDatabase, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} - -#[test] -fn unadorned_query() { - let db = LoggerDb::default(); - - InputString::new(&db, String::from("Hello, world!")); - let len = db.length_query_with_no_params(); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: length_query_with_no_params_shim(Id(400)) })", - ]"#]]); -} - -#[test] -fn transparent() { - let db = LoggerDb::default(); - - InputString::new(&db, String::from("Hello, world!")); - let len = db.transparent_length(()); - - assert_eq!(len, 13); - db.assert_logs(expect!["[]"]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs deleted file mode 100644 index 71af63a0d3b8b..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::sync::{Arc, Mutex}; - -#[salsa_macros::db] -#[derive(Clone)] -pub(crate) struct LoggerDb { - storage: salsa::Storage, - logger: Logger, -} - -impl Default for LoggerDb { - fn default() -> Self { - let logger = Logger::default(); - Self { - storage: salsa::Storage::new(Some(Box::new({ - let logger = logger.clone(); - move |event| match event.kind { - salsa::EventKind::WillExecute { .. } - | salsa::EventKind::WillCheckCancellation - | salsa::EventKind::DidValidateMemoizedValue { .. } - | salsa::EventKind::WillDiscardStaleOutput { .. } - | salsa::EventKind::DidDiscard { .. } => { - logger.logs.lock().unwrap().push(format!("salsa_event({:?})", event.kind)); - } - _ => {} - } - }))), - logger, - } - } -} - -#[derive(Default, Clone)] -struct Logger { - logs: Arc>>, -} - -#[salsa_macros::db] -impl salsa::Database for LoggerDb {} - -impl LoggerDb { - /// Log an event from inside a tracked function. - pub(crate) fn push_log(&self, string: String) { - self.logger.logs.lock().unwrap().push(string); - } - - /// Asserts what the (formatted) logs should look like, - /// clearing the logged events. This takes `&mut self` because - /// it is meant to be run from outside any tracked functions. - pub(crate) fn assert_logs(&self, expected: expect_test::Expect) { - let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap()); - expected.assert_eq(&format!("{logs:#?}")); - } -} - -/// Test the logger database. -/// -/// This test isn't very interesting, but it *does* remove a dead code warning. -#[test] -fn test_logger_db() { - let db = LoggerDb::default(); - db.push_log("test".to_string()); - db.assert_logs(expect_test::expect![ - r#" - [ - "test", - ]"# - ]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs deleted file mode 100644 index 678a7ce5d74d0..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs +++ /dev/null @@ -1,27 +0,0 @@ -use query_group_macro::query_group; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait DatabaseOne: salsa::Database { - // unadorned query - #[salsa::transparent] - fn length(&self, key: ()) -> usize; -} - -#[query_group] -pub trait DatabaseTwo: DatabaseOne { - #[salsa::transparent] - fn second_length(&self, key: ()) -> usize; -} - -fn length(db: &dyn DatabaseOne, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} - -fn second_length(db: &dyn DatabaseTwo, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs deleted file mode 100644 index cc57ba78455fa..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs +++ /dev/null @@ -1,109 +0,0 @@ -use expect_test::expect; - -mod logger_db; -use logger_db::LoggerDb; -use query_group_macro::query_group; - -#[salsa_macros::input] -struct Input { - str: String, -} - -#[query_group] -trait PartialMigrationDatabase: salsa::Database { - fn length_query(&self, input: Input) -> usize; - - // renamed/invoke query - #[salsa::invoke(invoke_length_query_actual)] - fn invoke_length_query(&self, input: Input) -> usize; - - // invoke tracked function - #[salsa::invoke(invoke_length_tracked_actual)] - fn invoke_length_tracked(&self, input: Input) -> usize; -} - -fn length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -fn invoke_length_query_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -#[salsa_macros::tracked] -fn invoke_length_tracked_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -#[test] -fn unadorned_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.length_query(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: length_query_shim(Id(0)) })", - ]"#]]); -} - -#[test] -fn invoke_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.invoke_length_query(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_query_shim(Id(0)) })", - ]"#]]); -} - -// todo: does this even make sense? -#[test] -fn invoke_tracked_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.invoke_length_tracked(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_tracked_shim(Id(0)) })", - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_tracked_actual(Id(0)) })", - ]"#]]); -} - -#[test] -fn new_salsa_baseline() { - let db = LoggerDb::default(); - - #[salsa_macros::input] - struct Input { - str: String, - } - - #[salsa_macros::tracked] - fn new_salsa_length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() - } - - let input = Input::new(&db, String::from("Hello, world!")); - let len = new_salsa_length_query(&db, input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: new_salsa_length_query(Id(0)) })", - ]"#]]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs deleted file mode 100644 index 7e5e8d3a5b75f..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs +++ /dev/null @@ -1,41 +0,0 @@ -mod logger_db; -use expect_test::expect; -use logger_db::LoggerDb; - -use query_group_macro::query_group; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Error; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait ResultDatabase: salsa::Database { - #[salsa::transparent] - fn length(&self, key: ()) -> Result; - - #[salsa::transparent] - fn length2(&self, key: ()) -> Result; -} - -fn length(db: &dyn ResultDatabase, _key: ()) -> Result { - Ok(InputString::get(db).inner(db).len()) -} - -fn length2(db: &dyn ResultDatabase, _key: ()) -> Result { - Ok(InputString::get(db).inner(db).len()) -} - -#[test] -fn test_queries_with_results() { - let db = LoggerDb::default(); - let input = "hello"; - _ = InputString::new(&db, input.to_owned()); - assert_eq!(db.length(()), Ok(input.len())); - assert_eq!(db.length2(()), Ok(input.len())); - - db.assert_logs(expect!["[]"]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs deleted file mode 100644 index 63a5dbd16c5f7..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs +++ /dev/null @@ -1,20 +0,0 @@ -use query_group_macro::query_group; - -#[salsa_macros::db] -pub trait SourceDb: salsa::Database { - /// Text of the file. - fn file_text(&self, id: usize) -> String; -} - -#[query_group] -pub trait RootDb: SourceDb { - #[salsa::transparent] - fn parse(&self, id: usize) -> String; -} - -fn parse(db: &dyn RootDb, id: usize) -> String { - // this is the test: does the following compile? - db.file_text(id); - - String::new() -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs deleted file mode 100644 index ab9d1746f731b..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs +++ /dev/null @@ -1,32 +0,0 @@ -use query_group_macro::query_group; - -mod logger_db; -use expect_test::expect; -use logger_db::LoggerDb; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait HelloWorldDatabase: salsa::Database { - #[salsa::transparent] - fn length_query(&self, key: ()) -> (usize, usize); -} - -fn length_query(db: &dyn HelloWorldDatabase, _key: ()) -> (usize, usize) { - let len = InputString::get(db).inner(db).len(); - (len, len) -} - -#[test] -fn query() { - let db = LoggerDb::default(); - - _ = InputString::new(&db, String::from("Hello, world!")); - let len = db.length_query(()); - - assert_eq!(len, (13, 13)); - db.assert_logs(expect!["[]"]); -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index e05385528a052..6bd27c2621978 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -157,7 +157,7 @@ fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { // Deliberately enable all `warn` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. filter: env::var("RA_LOG").ok().unwrap_or_else(|| "warn".to_owned()), - chalk_filter: env::var("CHALK_DEBUG").ok(), + solver_filter: env::var("SOLVER_DEBUG").ok(), profile_filter: env::var("RA_PROFILE").ok(), json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index 6643037220ae4..cc0efe9ee9389 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -82,10 +82,7 @@ fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { fn full_name_of_item(db: &dyn HirDatabase, module: Module, name: Name) -> String { module - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) + .path_segments(db) .chain(Some(name)) .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::") diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index ae9a0cf094cae..79016921bfaaa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -753,10 +753,7 @@ impl flags::AnalysisStats { }; if verbosity.is_spammy() { let full_name = module - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) + .path_segments(db) .chain(Some(body.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::"); @@ -797,7 +794,9 @@ impl flags::AnalysisStats { bodies .par_iter() .map_with(db.clone(), |snap, &body| { - InferenceResult::of(snap, body); + hir::attach_db(snap, || { + InferenceResult::of(snap, body); + }); }) .count(); let _signatures = signatures @@ -1487,10 +1486,7 @@ fn full_name(db: &RootDatabase, name: impl Fn() -> Option, module: hir::Mo .into_iter() .chain( module - .path_to_root(db) - .into_iter() - .filter_map(|it| it.name(db)) - .rev() + .path_segments(db) .chain(Some(name().unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()), ) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs index beedcfae4ed85..782b0bda0a9ae 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs @@ -55,7 +55,8 @@ impl flags::PrimeCaches { ); let threads = self.num_threads.unwrap_or_else(num_cpus::get_physical); - ide_db::prime_caches::parallel_prime_caches(&db, threads, &|_| ()); + let all = ide_db::base_db::all_crates(&db); + ide_db::prime_caches::parallel_prime_caches(&db, &all, threads, &|_| ()); let elapsed = stop_watch.elapsed(); eprintln!( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 5388f68f02194..76a79ae08d897 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -14,7 +14,7 @@ use hir::ChangeWithProcMacros; use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; use ide_db::{ MiniCore, - base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision}, + base_db::{Crate, ProcMacroPaths, SourceDatabase, all_crates, salsa::Revision}, }; use itertools::Itertools; use load_cargo::SourceRootConfig; @@ -24,7 +24,9 @@ use parking_lot::{ RwLockWriteGuard, }; use proc_macro_api::ProcMacroClient; -use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts}; +use project_model::{ + ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, TargetKind, WorkspaceBuildScripts, +}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::thread; use tracing::{Level, span, trace}; @@ -42,7 +44,7 @@ use crate::{ main_loop::Task, mem_docs::MemDocs, op_queue::{Cause, OpQueue}, - reload, + priming_scope, reload, target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec}, task_pool::{DeferredTaskQueue, TaskPool}, test_runner::{CargoTestHandle, CargoTestMessage}, @@ -738,6 +740,75 @@ impl GlobalState { *fetch_receiver = crossbeam_channel::after(Duration::from_millis(100)); } } + + /// Set of crates to prime: the transitive-dependency closure of every + /// local Cargo workspace `lib`/`bin` target, `rust-project.json` workspace + /// member, and detached file. Computed once when the server becomes + /// quiescent. + /// + /// Test, example, and benchmark members are deliberately excluded — they're + /// leaves, so not priming them costs no parallelism on dependency work. + /// `bin` targets are kept because they're the crate the user is most likely + /// editing. + pub(crate) fn compute_priming_scope(&self) -> Arc<[Crate]> { + let db = self.analysis_host.raw_database(); + let all = all_crates(db); + + // Map each crate-root path to its crate(s) so target roots resolve to + // `Crate` ids. The vfs read lock is held only for this build. + let root_to_crate: FxHashMap> = { + let vfs = self.vfs.read(); + let mut root_to_crate: FxHashMap> = FxHashMap::default(); + for &krate in &*all { + let root_file = krate.data(db).root_file_id; + let path = vfs.0.file_path(root_file); + let Some(path) = path.as_path() else { + continue; + }; + root_to_crate.entry(path.to_path_buf()).or_default().push(krate); + } + root_to_crate + }; + + let mut seed: FxHashSet = FxHashSet::default(); + for workspace in self.workspaces.iter() { + match &workspace.kind { + ProjectWorkspaceKind::Cargo { cargo, .. } + | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, ..)), .. } => { + for pkg in cargo.packages() { + if !cargo[pkg].is_local { + continue; + } + for &target in &cargo[pkg].targets { + if !matches!( + cargo[target].kind, + TargetKind::Lib { .. } | TargetKind::Bin + ) { + continue; + } + if let Some(krates) = root_to_crate.get(&*cargo[target].root) { + seed.extend(krates.iter().copied()); + } + } + } + } + ProjectWorkspaceKind::Json(project_json) => seed.extend( + project_json + .crates() + .filter(|(_, krate)| krate.is_workspace_member) + .filter_map(|(_, krate)| root_to_crate.get(&krate.root_module)) + .flat_map(|it| it.iter().copied()), + ), + ProjectWorkspaceKind::DetachedFile { file, cargo: None } => { + if let Some(krates) = root_to_crate.get(&**file) { + seed.extend(krates.iter().copied()); + } + } + } + } + + priming_scope::compute(db, seed) + } } impl Drop for GlobalState { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index e953ea2136297..48db8e38e988c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -22,7 +22,7 @@ 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. pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version { major: 1, - minor: 78, + minor: 94, patch: 0, pre: semver::Prerelease::EMPTY, build: semver::BuildMetadata::EMPTY, @@ -38,6 +38,7 @@ mod line_index; mod main_loop; mod mem_docs; mod op_queue; +mod priming_scope; mod reload; mod target_spec; mod task_pool; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index c73be92a90906..56490061a74f6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -647,14 +647,15 @@ impl GlobalState { } fn prime_caches(&mut self, cause: String) { - tracing::debug!(%cause, "will prime caches"); + let scope = self.compute_priming_scope(); + tracing::debug!(%cause, scope_size = scope.len(), "will prime caches"); let num_worker_threads = self.config.prime_caches_num_threads(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let analysis = AssertUnwindSafe(self.snapshot().analysis); move |sender| { sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); - let res = analysis.parallel_prime_caches(num_worker_threads, |progress| { + let res = analysis.parallel_prime_caches(&scope, num_worker_threads, |progress| { let report = PrimeCachesProgress::Report(progress); sender.send(Task::PrimeCaches(report)).unwrap(); }); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs new file mode 100644 index 0000000000000..f3d9d89bd27c3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs @@ -0,0 +1,166 @@ +//! Scope computation for cache priming. + +use ide_db::{RootDatabase, base_db::Crate}; +use rustc_hash::FxHashSet; +use triomphe::Arc; + +/// Close `seeds` under transitive dependencies. +pub(crate) fn compute(db: &RootDatabase, seeds: impl IntoIterator) -> Arc<[Crate]> { + let mut closure: FxHashSet = FxHashSet::default(); + let mut worklist: Vec = seeds.into_iter().collect(); + while let Some(krate) = worklist.pop() { + if !closure.insert(krate) { + continue; + } + worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id)); + } + closure.into_iter().collect() +} + +#[cfg(test)] +mod tests { + use ide_db::{ + RootDatabase, + base_db::{ + CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, CratesIdMap, + DependencyBuilder, Env, LangCrateOrigin, + }, + span::{Edition, FileId}, + }; + use rustc_hash::FxHashMap; + use triomphe::Arc as TriompheArc; + use vfs::AbsPathBuf; + + use super::*; + + fn empty_ws_data() -> TriompheArc { + TriompheArc::new(CrateWorkspaceData { target: Err("".into()), toolchain: None }) + } + + /// Builds a synthetic crate graph in a fresh `RootDatabase` and returns + /// the resolved `Crate` IDs keyed by the symbolic names used in `crates`. + /// + /// `crates` is a list of `(name, origin, deps)`. The crate root file id + /// is derived from the crate's index. Dependencies must refer to crates + /// declared earlier in the list. + fn build(crates: &[(&str, CrateOrigin, &[&str])]) -> (RootDatabase, FxHashMap) { + let mut db = RootDatabase::default(); + let mut graph = CrateGraphBuilder::default(); + let proc_macro_cwd = + TriompheArc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())); + + let mut ids = Vec::with_capacity(crates.len()); + for (i, (name, origin, _)) in crates.iter().enumerate() { + let id = graph.add_crate_root( + FileId::from_raw((i + 1) as u32), + Edition::Edition2021, + None, + None, + Default::default(), + Default::default(), + Env::default(), + origin.clone(), + Vec::new(), + false, + proc_macro_cwd.clone(), + empty_ws_data(), + ); + ids.push((name.to_string(), id)); + } + + for (i, (_, _, deps)) in crates.iter().enumerate() { + for dep_name in *deps { + let from = ids[i].1; + let to = ids + .iter() + .find(|(n, _)| n == dep_name) + .unwrap_or_else(|| panic!("unknown dep `{dep_name}`")) + .1; + graph + .add_dep(from, DependencyBuilder::new(CrateName::new(dep_name).unwrap(), to)) + .unwrap(); + } + } + + let resolved: CratesIdMap = graph.set_in_db(&mut db); + let by_name = ids.into_iter().map(|(n, id)| (n, resolved[&id])).collect(); + (db, by_name) + } + + fn lang(name: &str) -> CrateOrigin { + CrateOrigin::Lang(LangCrateOrigin::from(name)) + } + + fn local() -> CrateOrigin { + CrateOrigin::Local { repo: None, name: None } + } + + fn library(name: &str) -> CrateOrigin { + CrateOrigin::Library { repo: None, name: CrateName::new(name).unwrap().symbol().clone() } + } + + fn primed(scope: &Arc<[Crate]>, by_name: &FxHashMap) -> Vec { + let lookup: FxHashMap = + by_name.iter().map(|(n, c)| (*c, n.as_str())).collect(); + let mut names: Vec = scope.iter().map(|c| lookup[c].to_owned()).collect(); + names.sort(); + names + } + + #[test] + fn closes_seeds_under_deps() { + // core ← lib_a ← lib_b ← bin_c + // ↖ test_d + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_a", local(), &["core"]), + ("lib_b", local(), &["lib_a"]), + ("bin_c", local(), &["lib_b"]), + ("test_d", local(), &["lib_b"]), + ]); + + let scope = compute(&db, [by["lib_a"], by["lib_b"]]); + assert_eq!(primed(&scope, &by), vec!["core", "lib_a", "lib_b"]); + } + + #[test] + fn active_seed_pulls_transitive_deps() { + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_a", local(), &["core"]), + ("lib_b", local(), &["lib_a"]), + ("bin_c", local(), &["lib_b"]), + ]); + + let scope = compute(&db, [by["bin_c"]]); + assert_eq!(primed(&scope, &by), vec!["bin_c", "core", "lib_a", "lib_b"]); + } + + #[test] + fn does_not_pull_reverse_deps() { + // Seeding only the leaf must not warm crates that depend on it. + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_leaf", local(), &["core"]), + ("dependent_a", local(), &["lib_leaf"]), + ("dependent_b", local(), &["lib_leaf"]), + ]); + + let scope = compute(&db, [by["lib_leaf"]]); + assert_eq!(primed(&scope, &by), vec!["core", "lib_leaf"]); + } + + #[test] + fn pulls_library_dep_via_seeded_crate() { + // A `Library` (non-workspace-member) origin behaves like any other — + // dep walk is origin-agnostic, only the seed selection cares. + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("ext", library("serde"), &["core"]), + ("lib_a", local(), &["ext"]), + ]); + + let scope = compute(&db, [by["lib_a"]]); + assert_eq!(primed(&scope, &by), vec!["core", "ext", "lib_a"]); + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index c72f6782052f0..3bf3cd5622550 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -659,7 +659,9 @@ impl GlobalState { Config::user_config_dir_path().as_deref(), ); - if !same_workspaces && self.config.expand_proc_macros() { + if (self.proc_macro_clients.is_empty() || !same_workspaces) + && self.config.expand_proc_macros() + { info!("Spawning proc-macro servers"); // Workspaces referring to the same proc-macro server executable (i.e. the same diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index 2bc9f3c34a5ba..9c6648916a259 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -20,16 +20,16 @@ use crate::tracing::json; pub struct Config { pub writer: T, pub filter: String, - /// The meaning of CHALK_DEBUG is to tell chalk crates - /// (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing + /// The meaning of SOLVER_DEBUG is to tell the solver crates + /// (i.e. rustc_type_ir, rustc_next_trait_solver) how to filter tracing /// logs. But now we can only have just one filter, which means we have to - /// merge chalk filter to our main filter (from RA_LOG env). + /// merge the solver filter to our main filter (from RA_LOG env). /// - /// The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. + /// The acceptable syntax of SOLVER_DEBUG is `target[span{field=value}]=level`. /// As the value should only affect chalk crates, we'd better manually - /// specify the target. And for simplicity, CHALK_DEBUG only accept the value + /// specify the target. And for simplicity, SOLVER_DEBUG only accept the value /// that specify level. - pub chalk_filter: Option, + pub solver_filter: Option, /// Filtering syntax, set in a shell: /// ```text /// env RA_PROFILE=* // dump everything @@ -75,22 +75,24 @@ where } .with_filter(targets_filter); - let chalk_layer = match self.chalk_filter { - Some(chalk_filter) => { + let solver_layer = match self.solver_filter { + Some(solver_filter) => { let level: LevelFilter = - chalk_filter.parse().with_context(|| "invalid chalk log filter")?; - - let chalk_filter = Targets::new() - .with_target("chalk_solve", level) - .with_target("chalk_ir", level) - .with_target("chalk_recursive", level); + solver_filter.parse().with_context(|| "invalid solver log filter")?; + + // Once with `ra_ap_` and once without; in-tree r-a uses without, out-of-tree uses with. + let solver_filter = Targets::new() + .with_target("ra_ap_rustc_type_ir", level) + .with_target("rustc_type_ir", level) + .with_target("ra_ap_rustc_next_trait_solver", level) + .with_target("rustc_next_trait_solver", level); // TODO: remove `.with_filter(LevelFilter::OFF)` on the `None` branch. HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) .with_indent_amount(2) .with_writer(io::stderr) - .with_filter(chalk_filter) + .with_filter(solver_filter) .boxed() } None => None::.with_filter(LevelFilter::OFF).boxed(), @@ -122,7 +124,7 @@ where .with(ra_fmt_layer) .with(json_profiler_layer) .with(profiler_layer) - .with(chalk_layer); + .with(solver_layer); tracing::subscriber::set_global_default(subscriber)?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index c3568ce950fd7..2a469a5bfb80f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -170,7 +170,7 @@ impl Project<'_> { // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()), - chalk_filter: std::env::var("CHALK_DEBUG").ok(), + solver_filter: std::env::var("SOLVER_DEBUG").ok(), profile_filter: std::env::var("RA_PROFILE").ok(), json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), } diff --git a/src/tools/rust-analyzer/crates/stdx/src/macros.rs b/src/tools/rust-analyzer/crates/stdx/src/macros.rs index 880e2da70fc39..907746888f63f 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/macros.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/macros.rs @@ -30,15 +30,93 @@ macro_rules! format_to_acc { }; } -/// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums +/// Generates `From` impls that wrap values in, or map variants between, enums. /// -/// # Example +/// Enum mappings with `Source => Target` rename the variant and convert its payload with `.into()`. +/// +/// # Examples /// /// ```ignore /// impl_from!(Struct, Union, Enum for Adt); +/// impl_from!(impl<'db> Item, InternedItem<'db> for ItemId<'db>); +/// impl_from!(AssocItem { Function, Const, TypeAlias } for Item); +/// impl_from!(AdtId { StructId => Struct, EnumId => Enum } for Adt); /// ``` #[macro_export] macro_rules! impl_from { + ( + impl<$lifetime:lifetime> + $source:ident $(<$source_lifetime:lifetime>)? + { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? } + for $target:ident<$target_lifetime:lifetime> + ) => { + impl<$lifetime> From<$source$(<$source_lifetime>)?> for $target<$target_lifetime> { + fn from(value: $source$(<$source_lifetime>)?) -> Self { + match value { + $( + $source::$source_variant(value) => $crate::impl_from!( + @map_enum_variant $target, value, $source_variant + $(=> $target_variant)? + ), + )* + } + } + } + }; + ( + $source:ident + { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? } + for $target:ident + ) => { + impl From<$source> for $target { + fn from(value: $source) -> Self { + match value { + $( + $source::$source_variant(value) => $crate::impl_from!( + @map_enum_variant $target, value, $source_variant + $(=> $target_variant)? + ), + )* + } + } + } + }; + (@map_enum_variant $target:ident, $value:ident, $variant:ident) => { + $target::$variant($value) + }; + ( + @map_enum_variant $target:ident, $value:ident, + $source_variant:ident => $target_variant:ident + ) => { + $target::$target_variant($value.into()) + }; + ( + impl<$lifetime:lifetime> + $( + $variant:ident $(<$variant_lifetime:lifetime>)? + $(($($sub_variant:ident $(<$sub_variant_lifetime:lifetime>)?),*))? + ),* + for $enum:ident<$enum_lifetime:lifetime> + ) => { + $( + impl<$lifetime> From<$variant$(<$variant_lifetime>)?> for $enum<$enum_lifetime> { + fn from(it: $variant$(<$variant_lifetime>)?) -> $enum<$enum_lifetime> { + $enum::$variant(it) + } + } + $($( + impl<$lifetime> From<$sub_variant$(<$sub_variant_lifetime>)?> + for $enum<$enum_lifetime> + { + fn from( + it: $sub_variant$(<$sub_variant_lifetime>)?, + ) -> $enum<$enum_lifetime> { + $enum::$variant($variant::$sub_variant(it)) + } + } + )*)? + )* + }; ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => { $( impl From<$variant> for $enum { diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 0dcf18a4ad97a..181f9a14e764d 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -903,7 +903,20 @@ impl TtTreeSink<'_> { } self.text_pos += TextSize::of(text); } - None => unreachable!(), + None => { + self.error("illegal float literal".to_owned()); + self.inner.start_node(SyntaxKind::ERROR); + self.inner.token(SyntaxKind::FLOAT_NUMBER, text); + self.token_map.push(self.text_pos + TextSize::of(text), span); + self.inner.finish_node(); + self.inner.finish_node(); + + if !has_pseudo_dot { + self.inner.finish_node(); + } + + self.text_pos += TextSize::of(text); + } } self.cursor.bump(); } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs index 16f2498bf357c..691084d8b0965 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs @@ -1,3 +1,4 @@ +use expect_test::expect; use rustc_hash::FxHashMap; use span::Span; use syntax::{AstNode, ast}; @@ -7,7 +8,7 @@ use tt::{Leaf, Punct, Spacing, buffer::Cursor}; use crate::{ DocCommentDesugarMode, dummy_test_span_utils::{DUMMY, DummyTestSpanMap}, - syntax_node_to_token_tree, + parse_to_token_tree_static_span, syntax_node_to_token_tree, token_tree_to_syntax_node, }; fn check_punct_spacing(fixture: &str) { @@ -97,3 +98,51 @@ fn main() { "#, ); } + +#[test] +fn scientific_notation_field_access_recovers() { + let tt = parse_to_token_tree_static_span( + span::Edition::CURRENT, + DUMMY, + r#" +fn main() { + s.00E+10; +} +"#, + ) + .unwrap(); + + let (parse, _) = token_tree_to_syntax_node(&tt, parser::TopEntryPoint::SourceFile, &mut |_| { + span::Edition::CURRENT + }); + let parse = parse.cast::().unwrap(); + + expect![[r#" + SOURCE_FILE@0..19 + FN@0..19 + FN_KW@0..2 "fn" + NAME@2..6 + IDENT@2..6 "main" + PARAM_LIST@6..8 + L_PAREN@6..7 "(" + R_PAREN@7..8 ")" + BLOCK_EXPR@8..19 + STMT_LIST@8..19 + L_CURLY@8..9 "{" + EXPR_STMT@9..18 + FIELD_EXPR@9..17 + FIELD_EXPR@9..17 + PATH_EXPR@9..10 + PATH@9..10 + PATH_SEGMENT@9..10 + NAME_REF@9..10 + IDENT@9..10 "s" + DOT@10..11 "." + ERROR@11..17 + FLOAT_NUMBER@11..17 "00E+10" + SEMICOLON@17..18 ";" + R_CURLY@18..19 "}" + error 11..11: illegal float literal + "#]] + .assert_eq(&parse.debug_dump()); +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index eaa36903bf26f..080f9a7c6b175 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -200,7 +200,7 @@ impl ast::IdentPat { if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) { - last.detach(); + editor.delete(last); } } } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs index 4eab7f4b18424..cf75017572580 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs @@ -261,9 +261,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { .iter() .find(|&&(off, _idx)| off == offset) .expect("annotation continuation not found"); - res[idx].1.push('\n'); + if !res[idx].1.ends_with('\n') { + res[idx].1.push('\n'); + } res[idx].1.push_str(&content); res[idx].1.push('\n'); + this_line_annotations.push((offset, idx)); } } } @@ -352,6 +355,7 @@ fn main() { zoo + 1 } //^^^ type: // | i32 + // | u32 // ^file "#, @@ -363,9 +367,9 @@ fn main() { assert_eq!( res[..3], - [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into())] + [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\nu32\n".into())] ); - assert_eq!(res[3].0.len(), 115); + assert_eq!(res[3].0.len(), 127); } #[test] diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index f3a460b9ac3da..ca2d824f2c2b4 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -37,8 +37,6 @@ //! error: fmt //! float_consts: //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fmt_before_1_93_0: fmt -//! fmt_before_1_89_0: fmt_before_1_93_0 //! fn: sized, tuple //! from: sized, result //! future: pin @@ -1428,111 +1426,8 @@ pub mod fmt { Center, Unknown, } - - // region:fmt_before_1_93_0 - #[lang = "format_count"] - pub enum Count { - Is(usize), - Param(usize), - Implied, - } - - #[lang = "format_placeholder"] - pub struct Placeholder { - pub position: usize, - pub fill: char, - pub align: Alignment, - pub flags: u32, - pub precision: Count, - pub width: Count, - } - - impl Placeholder { - pub const fn new( - position: usize, - fill: char, - align: Alignment, - flags: u32, - precision: Count, - width: Count, - ) -> Self { - Placeholder { position, fill, align, flags, precision, width } - } - } - // endregion:fmt_before_1_93_0 - - // region:fmt_before_1_89_0 - #[lang = "format_unsafe_arg"] - pub struct UnsafeArg { - _private: (), - } - - impl UnsafeArg { - pub unsafe fn new() -> Self { - UnsafeArg { _private: () } - } - } - // endregion:fmt_before_1_89_0 - } - - // region:fmt_before_1_93_0 - #[derive(Copy, Clone)] - #[lang = "format_arguments"] - pub struct Arguments<'a> { - pieces: &'a [&'static str], - fmt: Option<&'a [rt::Placeholder]>, - args: &'a [rt::Argument<'a>], - } - - impl<'a> Arguments<'a> { - pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { - Arguments { pieces, fmt: None, args } - } - - pub const fn new_const(pieces: &'a [&'static str]) -> Arguments<'a> { - Arguments { pieces, fmt: None, args: &[] } - } - - // region:fmt_before_1_89_0 - pub fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - // endregion:fmt_before_1_89_0 - - // region:!fmt_before_1_89_0 - pub unsafe fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - // 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(""), - ([s], []) => Some(s), - _ => None, - } - } } - // endregion:fmt_before_1_93_0 - // region:!fmt_before_1_93_0 #[lang = "format_arguments"] #[derive(Copy, Clone)] pub struct Arguments<'a> { @@ -1564,7 +1459,6 @@ pub mod fmt { } } } - // endregion:!fmt_before_1_93_0 // region:derive pub(crate) mod derive { diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index bb251a6823ac6..c15bc3af026e5 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -623,7 +623,6 @@ ui/const-generics/issues/issue-88119.rs ui/const-generics/issues/issue-88468.rs ui/const-generics/issues/issue-88997.rs ui/const-generics/issues/issue-89146.rs -ui/const-generics/issues/issue-89304.rs ui/const-generics/issues/issue-89320.rs ui/const-generics/issues/issue-89334.rs ui/const-generics/issues/issue-90318.rs diff --git a/tests/run-make/brepro-msvc-determinism/main.rs b/tests/run-make/brepro-msvc-determinism/main.rs new file mode 100644 index 0000000000000..31610b59e57d4 --- /dev/null +++ b/tests/run-make/brepro-msvc-determinism/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("brepro"); +} diff --git a/tests/run-make/brepro-msvc-determinism/rmake.rs b/tests/run-make/brepro-msvc-determinism/rmake.rs new file mode 100644 index 0000000000000..a6562fec541d6 --- /dev/null +++ b/tests/run-make/brepro-msvc-determinism/rmake.rs @@ -0,0 +1,73 @@ +use std::path::PathBuf; + +use object::pod::slice_from_all_bytes; +use object::read::pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64}; +use object::{FileKind, Object, pe}; +use run_make_support::{bin_name, is_windows_msvc, object, rfs, rustc}; + +// Returns the TimeDateStamp values from every IMAGE_DEBUG_DIRECTORY entry +// in a parsed PE image. +// Shared by both PE32 and PE32+ binaries. +fn timestamps(obj: &PeFile<'_, Pe>) -> Vec { + let data_dir = + obj.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG).expect("no debug directory found"); + + let debug_data = + data_dir.data(obj.data(), &obj.section_table()).expect("failed to read debug directory"); + + let debug_dirs = slice_from_all_bytes::(debug_data) + .expect("invalid IMAGE_DEBUG_DIRECTORY"); + + let mut stamps = Vec::new(); + + // COFF file header TimeDateStamp. + stamps.push(obj.nt_headers().file_header().time_date_stamp.get(object::LittleEndian)); + + // IMAGE_DEBUG_DIRECTORY TimeDateStamp values. + stamps.extend(debug_dirs.iter().map(|d| d.time_date_stamp.get(object::LittleEndian))); + + stamps +} + +fn main() { + if !is_windows_msvc() { + return; + } + + // Compile the test crate and collect the + // IMAGE_DEBUG_DIRECTORY timestamps from the resulting executable. + let build = || -> Vec { + rustc().input("main.rs").arg("-Clink-arg=/Brepro").output(bin_name("brepro-test")).run(); + + let bytes = rfs::read(bin_name("brepro-test")); + + // Parse the generated executable according to its PE format so the + // test works for both 32-bit and 64-bit MSVC targets. + match FileKind::parse(bytes.as_slice()).unwrap() { + FileKind::Pe32 => { + let obj = PeFile32::parse(bytes.as_slice()).unwrap(); + timestamps(&obj) + } + FileKind::Pe64 => { + let obj = PeFile64::parse(bytes.as_slice()).unwrap(); + timestamps(&obj) + } + kind => panic!("unexpected file kind: {kind:?}"), + } + }; + + // First build. + let stamps_a = build(); + + // Remove the generated PDB so the second build starts fresh. + rfs::remove_file(PathBuf::from(bin_name("brepro-test")).with_extension("pdb")); + + // Second build. + let stamps_b = build(); + + assert!(!stamps_a.is_empty(), "no IMAGE_DEBUG_DIRECTORY entries found"); + + // /Brepro should make the linker emit deterministic timestamps across + // identical builds. + assert_eq!(stamps_a, stamps_b, "TimeDateStamp differs between identical builds"); +} diff --git a/tests/ui/borrowck/borrowck-move-error-many-places.rs b/tests/ui/borrowck/borrowck-move-error-many-places.rs new file mode 100644 index 0000000000000..db504ea20c2d2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-many-places.rs @@ -0,0 +1,28 @@ +#![allow(unused)] +enum Foo { + Foo1(Box, Box), + Foo2(Box), + Foo3(Box), + Foo4(Box), + Foo5(Box), + Foo6(Box), + Foo7(Box), + Foo8(Box), +} + +fn blah() { + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match *f { //~ ERROR cannot move out of + Foo::Foo1(num1, + num2) => (), + Foo::Foo2(num) => (), + Foo::Foo3(num) => (), + Foo::Foo4(num) => (), + Foo::Foo5(num) => (), + Foo::Foo6(num) => (), + Foo::Foo7(num) => (), + Foo::Foo8(num) => (), + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-error-many-places.stderr b/tests/ui/borrowck/borrowck-move-error-many-places.stderr new file mode 100644 index 0000000000000..a35f5f7e410dc --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-many-places.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference + --> $DIR/borrowck-move-error-many-places.rs:15:11 + | +LL | match *f { + | ^^ +LL | Foo::Foo1(num1, + | ---- data moved here +LL | num2) => (), + | ---- ...and here +LL | Foo::Foo2(num) => (), + | --- ...and here +LL | Foo::Foo3(num) => (), + | --- ...and here +LL | Foo::Foo4(num) => (), + | --- ...and here + | + = note: ...and 4 other places + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the dereference here + | +LL - match *f { +LL + match f { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/comptime/comptime_impl.stderr b/tests/ui/comptime/comptime_impl.stderr index 4231df305cfc1..4c55736c0bb63 100644 --- a/tests/ui/comptime/comptime_impl.stderr +++ b/tests/ui/comptime/comptime_impl.stderr @@ -14,8 +14,8 @@ LL | Bar.foo(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for Bar { - | +++++ +LL | const impl Foo for Bar { + | +++++ error[E0277]: the trait bound `Bar: const Foo` is not satisfied --> $DIR/comptime_impl.rs:31:9 @@ -25,8 +25,8 @@ LL | Bar.bar(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for Bar { - | +++++ +LL | const impl Foo for Bar { + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/comptime/link-dead-code.rs b/tests/ui/comptime/link-dead-code.rs new file mode 100644 index 0000000000000..4f359420521f6 --- /dev/null +++ b/tests/ui/comptime/link-dead-code.rs @@ -0,0 +1,11 @@ +//@ build-pass +//@ compile-flags: -Clink-dead-code +//! Check that we don't try to generate assembly for comptime +//! fns, even when link-dead-code is active. + +#![feature(rustc_attrs)] + +#[rustc_comptime] +fn f() {} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs new file mode 100644 index 0000000000000..7f7766dbf035e --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs @@ -0,0 +1,33 @@ +// Cited from [#157937](https://github.com/rust-lang/rust/issues/157937) + +#![feature(generic_const_exprs)] +trait Trait { + const CONST: usize; +} +struct A { + _marker: T, +} +impl Trait for [i8; N] { + const CONST: usize = N; +} +impl From for A<[i8; N]> { + fn from(_: usize) -> Self { + todo!() + } +} +impl From> for A { +//~^ ERROR: conflicting implementations of trait `From>` for type `A<[i8; _]>` [E0119] + fn from(_: A<[i8; T::CONST]>) -> Self { + todo!() + } +} +fn f() -> A +where + [(); T::CONST]:, +{ + let a = A::from(0); + A::from(a) +} +fn main() { + f::<[i8; 1]>(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr new file mode 100644 index 0000000000000..8d72acec7da52 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `From>` for type `A<[i8; _]>` + --> $DIR/coherence-overlap-const-projection-157937.rs:18:1 + | +LL | impl From> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl From for T; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/issues/issue-89304.rs b/tests/ui/const-generics/issues/issue-89304.rs deleted file mode 100644 index d5cbfc9300b1c..0000000000000 --- a/tests/ui/const-generics/issues/issue-89304.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ check-pass - -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct GenericStruct { val: i64 } - -impl From> for GenericStruct<{T + 1}> { - fn from(other: GenericStruct) -> Self { - Self { val: other.val } - } -} - -impl From> for GenericStruct { - fn from(other: GenericStruct<{T + 1}>) -> Self { - Self { val: other.val } - } -} - -fn main() {} diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs index bdcf537859cc4..0de46b3a594ea 100644 --- a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] fn main() { // Test that calls to intrinsics are never promoted - let x: &'static usize = - &std::intrinsics::size_of::(); //~ ERROR temporary value dropped while borrowed + let x: &'static () = + &std::intrinsics::cold_path(); //~ ERROR temporary value dropped while borrowed } diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr index d533dcaa6f6b5..bb36caf64ddd5 100644 --- a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr @@ -1,10 +1,10 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/const-eval-intrinsic-promotion.rs:5:10 | -LL | let x: &'static usize = - | -------------- type annotation requires that borrow lasts for `'static` -LL | &std::intrinsics::size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +LL | let x: &'static () = + | ----------- type annotation requires that borrow lasts for `'static` +LL | &std::intrinsics::cold_path(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use LL | } | - temporary value is freed at the end of this statement diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs index a49fe6184890f..ba7cae44a0e46 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Znext-solver=globally +//@ ignore-parallel-frontend query cycle // ICE regression test for https://github.com/rust-lang/rust/issues/151327 #![feature(min_specialization)] diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr index 76d17e33c30ac..2a5e9bd4148fe 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr @@ -1,27 +1,27 @@ error[E0391]: cycle detected when coherence checking all impls of trait `Foo` - --> $DIR/next-solver-region-resolution.rs:6:1 + --> $DIR/next-solver-region-resolution.rs:7:1 | LL | trait Foo { | ^^^^^^^^^ | = note: ...which requires building specialization graph of trait `Foo`... note: ...which requires computing whether impls specialize one another... - --> $DIR/next-solver-region-resolution.rs:12:1 + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where LL | | Self::Item: 'a, | |___________________^ -note: ...which requires computing normalized predicates of ``... - --> $DIR/next-solver-region-resolution.rs:18:1 +note: ...which requires computing normalized predicates of ``... + --> $DIR/next-solver-region-resolution.rs:19:1 | LL | / impl<'a, T> Foo for &T LL | | where LL | | Self::Item: Baz, | |____________________^ = note: ...which again requires coherence checking all impls of trait `Foo`, completing the cycle -note: cycle used when checking that `` is well-formed - --> $DIR/next-solver-region-resolution.rs:12:1 +note: cycle used when checking that `` is well-formed + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr new file mode 100644 index 0000000000000..52862ec5151b3 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr @@ -0,0 +1,7 @@ +warning: target feature `fpregs` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs new file mode 100644 index 0000000000000..c07479eca0f7b --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs @@ -0,0 +1,23 @@ +//! Sometimes `-Ctarget-cpu` can *disable* target features that would by default be enabled on the +//! current target. Ensure that we catch the case where those target features are important for the +//! ABI. + +//@ compile-flags: --crate-type=lib +//@ revisions: x86 arm +//@[x86] compile-flags: --target=i686-unknown-linux-gnu -Ctarget-cpu=pentium +//@[x86] needs-llvm-components: x86 +//@[arm] compile-flags: --target=armv8r-none-eabihf -Ctarget-cpu=cortex-r4 +//@[arm] needs-llvm-components: arm + +// For now this is just a warning. +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore + +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +//~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.stderr b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.x86.stderr similarity index 100% rename from tests/ui/target-feature/target-cpu-lacks-required-target-feature.stderr rename to tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.x86.stderr diff --git a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs b/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs deleted file mode 100644 index 5e46ea8adf64a..0000000000000 --- a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: --target=i686-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-cpu=pentium -// For now this is just a warning. -//@ build-pass -//@ ignore-backends: gcc -//@ add-minicore - -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -//~? WARN target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/traits/const-traits/assoc-type.current.stderr b/tests/ui/traits/const-traits/assoc-type.current.stderr index b730fd8ad3662..f66e9e03b0754 100644 --- a/tests/ui/traits/const-traits/assoc-type.current.stderr +++ b/tests/ui/traits/const-traits/assoc-type.current.stderr @@ -11,8 +11,8 @@ LL | type Bar: [const] Add; | ^^^^^^^^^^^ required by this bound in `Foo::Bar` help: make the `impl` of trait `Add` `const` | -LL | impl const Add for NonConstAdd { - | +++++ +LL | const impl Add for NonConstAdd { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/assoc-type.next.stderr b/tests/ui/traits/const-traits/assoc-type.next.stderr index b730fd8ad3662..f66e9e03b0754 100644 --- a/tests/ui/traits/const-traits/assoc-type.next.stderr +++ b/tests/ui/traits/const-traits/assoc-type.next.stderr @@ -11,8 +11,8 @@ LL | type Bar: [const] Add; | ^^^^^^^^^^^ required by this bound in `Foo::Bar` help: make the `impl` of trait `Add` `const` | -LL | impl const Add for NonConstAdd { - | +++++ +LL | const impl Add for NonConstAdd { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-closure.next.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr index 9a851a97f186a..bdea41585c666 100644 --- a/tests/ui/traits/const-traits/call-const-closure.next.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -6,8 +6,8 @@ LL | (const || ().foo())(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr index 9a851a97f186a..bdea41585c666 100644 --- a/tests/ui/traits/const-traits/call-const-closure.old.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -6,8 +6,8 @@ LL | (const || ().foo())(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs index dd8e3dfde4a3d..4b2165b110481 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs +++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs @@ -5,6 +5,11 @@ pub const trait Plus { fn plus(self, rhs: Self) -> Self; } + +pub const unsafe trait Minus { + fn minus(self, rhs: Self) -> Self; +} + const impl Plus for i32 { fn plus(self, rhs: Self) -> Self { self + rhs @@ -17,6 +22,20 @@ impl Plus for u32 { } } + +const unsafe impl Minus for i32 { + fn minus(self, rhs: Self) -> Self { + self - rhs + } +} + +unsafe impl Minus for u32 { + fn minus(self, rhs: Self) -> Self { + self - rhs + } +} + + pub const fn add_i32(a: i32, b: i32) -> i32 { a.plus(b) // ok } @@ -26,4 +45,15 @@ pub const fn add_u32(a: u32, b: u32) -> u32 { //~^ ERROR the trait bound `u32: [const] Plus` } + +pub const unsafe fn sub_i32(a: i32, b: i32) -> i32 { + a.minus(b) // ok +} + +pub const unsafe fn sub_u32(a: u32, b: u32) -> u32 { + a.minus(b) + //~^ ERROR the trait bound `u32: [const] Minus` +} + + fn main() {} diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr index 6e235d9cb6f0c..7ee8a0e935555 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr @@ -1,14 +1,25 @@ error[E0277]: the trait bound `u32: [const] Plus` is not satisfied - --> $DIR/call-const-trait-method-fail.rs:25:5 + --> $DIR/call-const-trait-method-fail.rs:44:5 | LL | a.plus(b) | ^ | help: make the `impl` of trait `Plus` `const` | -LL | impl const Plus for u32 { - | +++++ +LL | const impl Plus for u32 { + | +++++ -error: aborting due to 1 previous error +error[E0277]: the trait bound `u32: [const] Minus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:54:5 + | +LL | a.minus(b) + | ^ + | +help: make the `impl` of trait `Minus` `const` + | +LL | const unsafe impl Minus for u32 { + | +++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr index 91d3918372601..d641e22a9a905 100644 --- a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr @@ -13,8 +13,8 @@ LL | const fn equals_self(t: &T) -> bool { | ^^^^^^^^^^^ required by this bound in `equals_self` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for S { - | +++++ +LL | const impl Foo for S { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index 93563dd12f952..30fbeb72fab9a 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -6,8 +6,8 @@ LL | const _: () = assert!(need_const_closure(Tr::a) == 42); | help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () { - | +++++ +LL | const impl Tr for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr index 55a12f95a6d19..c5a0c8743fa13 100644 --- a/tests/ui/traits/const-traits/const-default-method-bodies.stderr +++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr @@ -6,8 +6,8 @@ LL | NonConstImpl.a(); | help: make the `impl` of trait `ConstDefaultFn` `const` | -LL | impl const ConstDefaultFn for NonConstImpl { - | +++++ +LL | const impl ConstDefaultFn for NonConstImpl { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr index c6d71bde6a368..b43a67667967b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr @@ -18,8 +18,8 @@ LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` help: make the `impl` of trait `A` `const` | -LL | impl const A for NonTrivialDrop {} - | +++++ +LL | const impl A for NonTrivialDrop {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr index c6d71bde6a368..b43a67667967b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr @@ -18,8 +18,8 @@ LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` help: make the `impl` of trait `A` `const` | -LL | impl const A for NonTrivialDrop {} - | +++++ +LL | const impl A for NonTrivialDrop {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr index 9f17b0d4354d7..d2b83ac2f3636 100644 --- a/tests/ui/traits/const-traits/const-opaque.no.stderr +++ b/tests/ui/traits/const-traits/const-opaque.no.stderr @@ -13,8 +13,8 @@ LL | const fn bar(t: T) -> impl [const] Foo { | ^^^^^^^^^^^ required by this bound in `bar` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () { - | +++++ +LL | const impl Foo for () { + | +++++ error[E0277]: the trait bound `(): const Foo` is not satisfied --> $DIR/const-opaque.rs:32:12 @@ -24,8 +24,8 @@ LL | opaque.method(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () { - | +++++ +LL | const impl Foo for () { + | +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr index a436221d75412..7bd1118022647 100644 --- a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr +++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr @@ -11,8 +11,8 @@ LL | const fn foo() where T: [const] Tr {} | ^^^^^^^^^^ required by this bound in `foo` help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () {} - | +++++ +LL | const impl Tr for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr index f93e57d5fd6b2..d92297fa7b69f 100644 --- a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr +++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr @@ -6,8 +6,8 @@ LL | ().a() | help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () {} - | +++++ +LL | const impl Tr for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr index ffa9679e86ce6..375cb58580490 100644 --- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr @@ -11,8 +11,8 @@ LL | type Assoc: [const] Bar | ^^^^^^^^^^^ required by this bound in `Foo::Assoc` help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for N where T: Bar {} - | +++++ +LL | const impl Bar for N where T: Bar {} + | +++++ error[E0277]: the trait bound `T: [const] Bar` is not satisfied --> $DIR/item-bound-entailment-fails.rs:24:21 diff --git a/tests/ui/traits/const-traits/minicore-deref-fail.stderr b/tests/ui/traits/const-traits/minicore-deref-fail.stderr index e6c087cb9d822..c64dce93cc562 100644 --- a/tests/ui/traits/const-traits/minicore-deref-fail.stderr +++ b/tests/ui/traits/const-traits/minicore-deref-fail.stderr @@ -6,8 +6,8 @@ LL | *Ty; | help: make the `impl` of trait `Deref` `const` | -LL | impl const Deref for Ty { - | +++++ +LL | const impl Deref for Ty { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/minicore-fn-fail.stderr index 0c260f7f33a77..949a1270b60e1 100644 --- a/tests/ui/traits/const-traits/minicore-fn-fail.stderr +++ b/tests/ui/traits/const-traits/minicore-fn-fail.stderr @@ -13,8 +13,8 @@ LL | const fn call_indirect(t: &T) { t() } | ^^^^^^^^^^^^ required by this bound in `call_indirect` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () {} - | +++++ +LL | const impl Foo for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/no-explicit-const-params.stderr index efd90482f7742..72c64120a3d77 100644 --- a/tests/ui/traits/const-traits/no-explicit-const-params.stderr +++ b/tests/ui/traits/const-traits/no-explicit-const-params.stderr @@ -62,8 +62,8 @@ LL | <() as Bar>::bar(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 5 previous errors diff --git a/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr index bb1c9ac785314..aed032714b6df 100644 --- a/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr @@ -6,8 +6,8 @@ LL | ::a(); | help: make the `impl` of trait `A` `const` | -LL | impl const A for T { - | +++++ +LL | const impl A for T { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr index bb3bc51c44a2c..8b8b84c850f33 100644 --- a/tests/ui/traits/const-traits/super-traits-fail.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail.stderr @@ -6,8 +6,8 @@ LL | const impl Bar for S {} | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for S { - | +++++ +LL | const impl Foo for S { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs new file mode 100644 index 0000000000000..6a28115ad32f0 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Znext-solver=globally + +trait Foo {} + +struct BarType; + +impl Foo for BarType {} +//~^ ERROR missing generics for struct `BarType` + +fn a(x: &dyn Foo) { + let bar = BarType; + a(bar); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr new file mode 100644 index 0000000000000..d3658748846c6 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr @@ -0,0 +1,40 @@ +error[E0107]: missing generics for struct `BarType` + --> $DIR/lower-universe-resolved-const-issue-159703.rs:7:30 + | +LL | impl Foo for BarType {} + | ^^^^^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `N` + --> $DIR/lower-universe-resolved-const-issue-159703.rs:5:8 + | +LL | struct BarType; + | ^^^^^^^ -------------- +help: add missing generic argument + | +LL | impl Foo for BarType {} + | +++ + +error[E0308]: mismatched types + --> $DIR/lower-universe-resolved-const-issue-159703.rs:12:7 + | +LL | a(bar); + | - ^^^ expected `&dyn Foo`, found `BarType<_>` + | | + | arguments to this function are incorrect + | + = note: expected reference `&dyn Foo` + found struct `BarType<_>` +note: function defined here + --> $DIR/lower-universe-resolved-const-issue-159703.rs:10:4 + | +LL | fn a(x: &dyn Foo) { + | ^ ----------- +help: consider borrowing here + | +LL | a(&bar); + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs new file mode 100644 index 0000000000000..1885e177a6b60 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: -Znext-solver=globally + +pub struct IndexMap { + #[expect(dead_code)] + build_hasher: S, +} + +struct Guard<'a, S, const N: usize>( + #[expect(dead_code)] &'a mut IndexMap, +); + +impl IndexMap { + pub fn clear(&mut self) { + let _ = Guard(self); + } +} + +fn main() {}