diff --git a/crates/hir-def/src/builtin_derive.rs b/crates/hir-def/src/builtin_derive.rs index e0e163783f..32385516ab 100644 --- a/crates/hir-def/src/builtin_derive.rs +++ b/crates/hir-def/src/builtin_derive.rs @@ -3,40 +3,102 @@ //! To save time and memory, builtin derives are not really expanded. Instead, we record them //! and create their impls based on lowered data, see crates/hir-ty/src/builtin_derive.rs. -use hir_expand::builtin::BuiltinDeriveExpander; +use hir_expand::{InFile, builtin::BuiltinDeriveExpander, name::Name}; +use intern::{Symbol, sym}; +use tt::TextRange; + +use crate::{ + AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, db::DefDatabase, +}; macro_rules! declare_enum { - ( $( $trait:ident ),* $(,)? ) => { + ( $( $trait:ident => [ $( $method:ident ),* ] ),* $(,)? ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinDeriveImplTrait { $( $trait, )* } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types)] + pub enum BuiltinDeriveImplMethod { + $( $( $method, )* )* + } + impl BuiltinDeriveImplTrait { + #[inline] + pub fn name(self) -> Symbol { + match self { + $( Self::$trait => sym::$trait, )* + } + } + #[inline] pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option { match self { $( Self::$trait => lang_items.$trait, )* } } + + #[inline] + pub fn get_method(self, method_name: &Symbol) -> Option { + match self { + $( + Self::$trait => { + match method_name { + $( _ if *method_name == sym::$method => Some(BuiltinDeriveImplMethod::$method), )* + _ => None, + } + } + )* + } + } + + #[inline] + pub fn all_methods(self) -> &'static [BuiltinDeriveImplMethod] { + match self { + $( Self::$trait => &[ $(BuiltinDeriveImplMethod::$method),* ], )* + } + } + } + + impl BuiltinDeriveImplMethod { + #[inline] + pub fn name(self) -> Symbol { + match self { + $( $( BuiltinDeriveImplMethod::$method => sym::$method, )* )* + } + } } }; } declare_enum!( - Copy, - Clone, - Default, - Debug, - Hash, - Ord, - PartialOrd, - Eq, - PartialEq, - CoerceUnsized, - DispatchFromDyn, + Copy => [], + Clone => [clone], + Default => [default], + Debug => [fmt], + Hash => [hash], + Ord => [cmp], + PartialOrd => [partial_cmp], + Eq => [], + PartialEq => [eq], + CoerceUnsized => [], + DispatchFromDyn => [], ); +impl BuiltinDeriveImplMethod { + pub fn trait_method( + self, + db: &dyn DefDatabase, + impl_: BuiltinDeriveImplId, + ) -> Option { + let loc = impl_.loc(db); + let lang_items = crate::lang_item::lang_items(db, loc.krate(db)); + let trait_ = impl_.loc(db).trait_.get_id(lang_items)?; + trait_.trait_items(db).method_by_name(&Name::new_symbol_root(self.name())) + } +} + pub(crate) fn with_derive_traits( derive: BuiltinDeriveExpander, mut f: impl FnMut(BuiltinDeriveImplTrait), @@ -59,3 +121,29 @@ pub(crate) fn with_derive_traits( }; f(trait_); } + +impl BuiltinDeriveImplLoc { + pub fn source(&self, db: &dyn DefDatabase) -> InFile { + let (adt_ast_id, module) = match self.adt { + AdtId::StructId(adt) => { + let adt_loc = adt.loc(db); + (adt_loc.id.upcast(), adt_loc.container) + } + AdtId::UnionId(adt) => { + let adt_loc = adt.loc(db); + (adt_loc.id.upcast(), adt_loc.container) + } + AdtId::EnumId(adt) => { + let adt_loc = adt.loc(db); + (adt_loc.id.upcast(), adt_loc.container) + } + }; + let derive_range = self.derive_attr_id.find_derive_range( + db, + module.krate(db), + adt_ast_id, + self.derive_index, + ); + adt_ast_id.with_value(derive_range) + } +} diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 4f3700e8e4..9e7868b273 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -9,7 +9,7 @@ use indexmap::map::Entry; use itertools::Itertools; use la_arena::Idx; use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::{SmallVec, smallvec}; +use smallvec::SmallVec; use span::Edition; use stdx::format_to; use syntax::ast; @@ -531,12 +531,13 @@ impl ItemScope { adt: AstId, attr_id: AttrId, attr_call_id: MacroCallId, - len: usize, + mut derive_call_ids: SmallVec<[Option; 4]>, ) { + derive_call_ids.shrink_to_fit(); self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation { attr_id, attr_call_id, - derive_call_ids: smallvec![None; len], + derive_call_ids, }); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index fde1e6ca17..8d6c418d75 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -64,6 +64,7 @@ use base_db::{Crate, impl_intern_key}; use hir_expand::{ AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallStyles, MacroDefId, MacroDefKind, + attrs::AttrId, builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, eager::expand_eager_macro_input, @@ -337,6 +338,8 @@ impl ImplId { pub struct BuiltinDeriveImplLoc { pub adt: AdtId, pub trait_: BuiltinDeriveImplTrait, + pub derive_attr_id: AttrId, + pub derive_index: u32, } #[salsa::interned(debug, no_lifetime)] @@ -675,6 +678,18 @@ impl_from!( for ModuleDefId ); +impl From for ModuleDefId { + #[inline] + fn from(value: DefWithBodyId) -> Self { + match value { + DefWithBodyId::FunctionId(id) => id.into(), + DefWithBodyId::StaticId(id) => id.into(), + DefWithBodyId::ConstId(id) => id.into(), + DefWithBodyId::VariantId(id) => id.into(), + } + } +} + /// 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)] diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index 0013c2a256..814afdd16c 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -1,828 +1,833 @@ //! Tests for `builtin_derive_macro.rs` from `hir_expand`. -use expect_test::expect; - -use crate::macro_expansion_tests::{check, check_errors}; - -#[test] -fn test_copy_expand_simple() { - check( - r#" -//- minicore: derive, copy -#[derive(Copy)] -struct Foo; -"#, - expect![[r#" -#[derive(Copy)] -struct Foo; - -impl <> $crate::marker::Copy for Foo< > where {}"#]], - ); -} - -#[test] -fn test_copy_expand_in_core() { - check( - r#" -//- /lib.rs crate:core -#[rustc_builtin_macro] -macro derive {} -#[rustc_builtin_macro] -macro Copy {} -#[derive(Copy)] -struct Foo; -"#, - expect![[r#" -#[rustc_builtin_macro] -macro derive {} -#[rustc_builtin_macro] -macro Copy {} -#[derive(Copy)] -struct Foo; - -impl <> $crate::marker::Copy for Foo< > where {}"#]], - ); -} - -#[test] -fn test_copy_expand_with_type_params() { - check( - r#" -//- minicore: derive, copy -#[derive(Copy)] -struct Foo; -"#, - expect![[r#" -#[derive(Copy)] -struct Foo; - -impl $crate::marker::Copy for Foo where {}"#]], - ); -} - -#[test] -fn test_copy_expand_with_lifetimes() { - // We currently just ignore lifetimes - check( - r#" -//- minicore: derive, copy -#[derive(Copy)] -struct Foo; -"#, - expect![[r#" -#[derive(Copy)] -struct Foo; - -impl $crate::marker::Copy for Foo where {}"#]], - ); -} - -#[test] -fn test_clone_expand() { - check( - r#" -//- minicore: derive, clone -#[derive(Clone)] -enum Command { - Move { x: A, y: B }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -#[derive(Clone)] -enum Command { - Move { x: A, y: B }, - Do(&'static str), - Jump, -} - -impl $crate::clone::Clone for Command where { - fn clone(&self ) -> Self { - match self { - Command::Move { - x: x, y: y, - } - =>Command::Move { - x: x.clone(), y: y.clone(), - } - , Command::Do(f0, )=>Command::Do(f0.clone(), ), Command::Jump=>Command::Jump, - } - } -}"#]], - ); -} - -#[test] -fn test_clone_expand_with_associated_types() { - check( - r#" -//- minicore: derive, clone -trait Trait { - type InWc; - type InFieldQualified; - type InFieldShorthand; - type InGenericArg; -} -trait Marker {} -struct Vec(T); - -#[derive(Clone)] -struct Foo -where - ::InWc: Marker, -{ - qualified: ::InFieldQualified, - shorthand: T::InFieldShorthand, - generic: Vec, -} -"#, - expect![[r#" -trait Trait { - type InWc; - type InFieldQualified; - type InFieldShorthand; - type InGenericArg; -} -trait Marker {} -struct Vec(T); - -#[derive(Clone)] -struct Foo -where - ::InWc: Marker, -{ - qualified: ::InFieldQualified, - shorthand: T::InFieldShorthand, - generic: Vec, -} - -impl $crate::clone::Clone for Foo where ::InWc: Marker, T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { - fn clone(&self ) -> Self { - match self { - Foo { - qualified: qualified, shorthand: shorthand, generic: generic, - } - =>Foo { - qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), - } - , - } - } -}"#]], - ); -} - -#[test] -fn test_clone_expand_with_const_generics() { - check( - r#" -//- minicore: derive, clone -#[derive(Clone)] -struct Foo(u32); -"#, - expect![[r#" -#[derive(Clone)] -struct Foo(u32); - -impl $crate::clone::Clone for Foo where { - fn clone(&self ) -> Self { - match self { - Foo(f0, )=>Foo(f0.clone(), ), - } - } -}"#]], - ); -} - -#[test] -fn test_default_expand() { - check( - r#" -//- minicore: derive, default -#[derive(Default)] -struct Foo { - field1: i32, - field2: (), -} -#[derive(Default)] -enum Bar { - Foo(u8), - #[default] - Bar, -} -"#, - expect![[r#" -#[derive(Default)] -struct Foo { - field1: i32, - field2: (), -} -#[derive(Default)] -enum Bar { - Foo(u8), - #[default] - Bar, -} - -impl <> $crate::default::Default for Foo< > where { - fn default() -> Self { - Foo { - field1: $crate::default::Default::default(), field2: $crate::default::Default::default(), - } - } -} -impl <> $crate::default::Default for Bar< > where { - fn default() -> Self { - Bar::Bar - } -}"#]], - ); -} - -#[test] -fn test_partial_eq_expand() { - check( - r#" -//- minicore: derive, eq -#[derive(PartialEq, Eq)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -#[derive(PartialEq, Eq)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} - -impl <> $crate::cmp::PartialEq for Command< > where { - fn eq(&self , other: &Self ) -> bool { - match (self , other) { - (Command::Move { - x: x_self, y: y_self, - } - , Command::Move { - x: x_other, y: y_other, - } - )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false - } - } -} -impl <> $crate::cmp::Eq for Command< > where {}"#]], - ); -} - -#[test] -fn test_partial_eq_expand_with_derive_const() { - // FIXME: actually expand with const - check( - r#" -//- minicore: derive, eq -#[derive_const(PartialEq, Eq)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -#[derive_const(PartialEq, Eq)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} - -impl <> $crate::cmp::PartialEq for Command< > where { - fn eq(&self , other: &Self ) -> bool { - match (self , other) { - (Command::Move { - x: x_self, y: y_self, - } - , Command::Move { - x: x_other, y: y_other, - } - )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false - } - } -} -impl <> $crate::cmp::Eq for Command< > where {}"#]], - ); -} - -#[test] -fn test_partial_ord_expand() { - check( - r#" -//- minicore: derive, ord -#[derive(PartialOrd, Ord)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -#[derive(PartialOrd, Ord)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} - -impl <> $crate::cmp::PartialOrd for Command< > where { - fn partial_cmp(&self , other: &Self ) -> $crate::option::Option<$crate::cmp::Ordering> { - match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) { - $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { - match (self , other) { - (Command::Move { - x: x_self, y: y_self, - } - , Command::Move { - x: x_other, y: y_other, - } - )=>match x_self.partial_cmp(&x_other) { - $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { - match y_self.partial_cmp(&y_other) { - $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { - $crate::option::Option::Some($crate::cmp::Ordering::Equal) - } - c=>return c, - } - } - c=>return c, - } - , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { - $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { - $crate::option::Option::Some($crate::cmp::Ordering::Equal) - } - c=>return c, - } - , (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal) - } - } - c=>return c, - } - } -} -impl <> $crate::cmp::Ord for Command< > where { - fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering { - match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) { - $crate::cmp::Ordering::Equal=> { - match (self , other) { - (Command::Move { - x: x_self, y: y_self, - } - , Command::Move { - x: x_other, y: y_other, - } - )=>match x_self.cmp(&x_other) { - $crate::cmp::Ordering::Equal=> { - match y_self.cmp(&y_other) { - $crate::cmp::Ordering::Equal=> { - $crate::cmp::Ordering::Equal - } - c=>return c, - } - } - c=>return c, - } - , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { - $crate::cmp::Ordering::Equal=> { - $crate::cmp::Ordering::Equal - } - c=>return c, - } - , (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal - } - } - c=>return c, - } - } -}"#]], - ); -} - -#[test] -fn test_hash_expand() { - check( - r#" -//- minicore: derive, hash -use core::hash::Hash; - -#[derive(Hash)] -struct Foo { - x: i32, - y: u64, - z: (i32, u64), -} -"#, - expect![[r#" -use core::hash::Hash; - -#[derive(Hash)] -struct Foo { - x: i32, - y: u64, - z: (i32, u64), -} - -impl <> $crate::hash::Hash for Foo< > where { - fn hash(&self , ra_expand_state: &mut H) { - match self { - Foo { - x: x, y: y, z: z, - } - => { - x.hash(ra_expand_state); - y.hash(ra_expand_state); - z.hash(ra_expand_state); - } - , - } - } -}"#]], - ); - check( - r#" -//- minicore: derive, hash -use core::hash::Hash; - -#[derive(Hash)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -use core::hash::Hash; - -#[derive(Hash)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} - -impl <> $crate::hash::Hash for Command< > where { - fn hash(&self , ra_expand_state: &mut H) { - $crate::mem::discriminant(self ).hash(ra_expand_state); - match self { - Command::Move { - x: x, y: y, - } - => { - x.hash(ra_expand_state); - y.hash(ra_expand_state); - } - , Command::Do(f0, )=> { - f0.hash(ra_expand_state); - } - , Command::Jump=> {} - , - } - } -}"#]], - ); -} - -#[test] -fn test_debug_expand() { - check( - r#" -//- minicore: derive, fmt -use core::fmt::Debug; - -#[derive(Debug)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} -"#, - expect![[r#" -use core::fmt::Debug; - -#[derive(Debug)] -enum Command { - Move { x: i32, y: i32 }, - Do(&'static str), - Jump, -} - -impl <> $crate::fmt::Debug for Command< > where { - fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { - match self { - Command::Move { - x: x, y: y, - } - =>f.debug_struct("Move").field("x", &x).field("y", &y).finish(), Command::Do(f0, )=>f.debug_tuple("Do").field(&f0).finish(), Command::Jump=>f.write_str("Jump"), - } - } -}"#]], - ); -} -#[test] -fn test_debug_expand_with_cfg() { - check( - r#" - //- minicore: derive, fmt - use core::fmt::Debug; - - #[derive(Debug)] - struct HideAndShow { - #[cfg(never)] - always_hide: u32, - #[cfg(not(never))] - always_show: u32, - } - #[derive(Debug)] - enum HideAndShowEnum { - #[cfg(never)] - AlwaysHide, - #[cfg(not(never))] - AlwaysShow{ - #[cfg(never)] - always_hide: u32, - #[cfg(not(never))] - always_show: u32, - } - } - "#, - expect![[r#" -use core::fmt::Debug; - -#[derive(Debug)] -struct HideAndShow { - #[cfg(never)] - always_hide: u32, - #[cfg(not(never))] - always_show: u32, -} -#[derive(Debug)] -enum HideAndShowEnum { - #[cfg(never)] - AlwaysHide, - #[cfg(not(never))] - AlwaysShow{ - #[cfg(never)] - always_hide: u32, - #[cfg(not(never))] - always_show: u32, - } -} - -impl <> $crate::fmt::Debug for HideAndShow< > where { - fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { - match self { - HideAndShow { - always_show: always_show, - } - =>f.debug_struct("HideAndShow").field("always_show", &always_show).finish() - } - } -} -impl <> $crate::fmt::Debug for HideAndShowEnum< > where { - fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { - match self { - HideAndShowEnum::AlwaysShow { - always_show: always_show, - } - =>f.debug_struct("AlwaysShow").field("always_show", &always_show).finish(), - } - } -}"#]], - ); -} -#[test] -fn test_default_expand_with_cfg() { - check( - r#" -//- minicore: derive, default -#[derive(Default)] -struct Foo { - field1: i32, - #[cfg(never)] - field2: (), - #[cfg(feature = "never")] - field3: (), - #[cfg(not(feature = "never"))] - field4: (), -} -#[derive(Default)] -enum Bar { - Foo, - #[cfg_attr(not(never), default)] - Bar, -} -"#, - expect![[r##" -#[derive(Default)] -struct Foo { - field1: i32, - #[cfg(never)] - field2: (), - #[cfg(feature = "never")] - field3: (), - #[cfg(not(feature = "never"))] - field4: (), -} -#[derive(Default)] -enum Bar { - Foo, - #[cfg_attr(not(never), default)] - Bar, -} - -impl <> $crate::default::Default for Foo< > where { - fn default() -> Self { - Foo { - field1: $crate::default::Default::default(), field4: $crate::default::Default::default(), - } - } -} -impl <> $crate::default::Default for Bar< > where { - fn default() -> Self { - Bar::Bar - } -}"##]], - ); -} - -#[test] -fn coerce_pointee_expansion() { - check( - r#" -//- minicore: coerce_pointee - -use core::marker::CoercePointee; - -pub trait Trait {} - -#[derive(CoercePointee)] -#[repr(transparent)] -pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) -where - U: Trait + ToString;"#, - expect![[r#" - -use core::marker::CoercePointee; - -pub trait Trait {} - -#[derive(CoercePointee)] -#[repr(transparent)] -pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) -where - U: Trait + ToString; -impl $crate::ops::DispatchFromDyn> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {} -impl $crate::ops::CoerceUnsized> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {}"#]], - ); -} - -#[test] -fn coerce_pointee_errors() { - check_errors( - r#" -//- minicore: coerce_pointee - -use core::marker::CoercePointee; - -#[derive(CoercePointee)] -enum Enum {} - -#[derive(CoercePointee)] -struct Struct1; - -#[derive(CoercePointee)] -struct Struct2(); - -#[derive(CoercePointee)] -struct Struct3 {} - -#[derive(CoercePointee)] -struct Struct4(T); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct5(i32); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct7(T, U); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct8<#[pointee] T, U: ?Sized>(T); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct9(T); - -#[derive(CoercePointee)] -#[repr(transparent)] -struct Struct9<#[pointee] T, U>(T) where T: ?Sized; -"#, - expect![[r#" - 35..72: `CoercePointee` can only be derived on `struct`s - 74..114: `CoercePointee` can only be derived on `struct`s with at least one field - 116..158: `CoercePointee` can only be derived on `struct`s with at least one field - 160..202: `CoercePointee` can only be derived on `struct`s with at least one field - 204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` - 260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type - 328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits - 441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits - 532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized` - 623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]], - ); -} - -#[test] -fn union_derive() { - check_errors( - r#" -//- minicore: clone, copy, default, fmt, hash, ord, eq, derive - -#[derive(Copy)] -union Foo1 { _v: () } -#[derive(Clone)] -union Foo2 { _v: () } -#[derive(Default)] -union Foo3 { _v: () } -#[derive(Debug)] -union Foo4 { _v: () } -#[derive(Hash)] -union Foo5 { _v: () } -#[derive(Ord)] -union Foo6 { _v: () } -#[derive(PartialOrd)] -union Foo7 { _v: () } -#[derive(Eq)] -union Foo8 { _v: () } -#[derive(PartialEq)] -union Foo9 { _v: () } - "#, - expect![[r#" - 78..118: this trait cannot be derived for unions - 119..157: this trait cannot be derived for unions - 158..195: this trait cannot be derived for unions - 196..232: this trait cannot be derived for unions - 233..276: this trait cannot be derived for unions - 313..355: this trait cannot be derived for unions"#]], - ); -} - -#[test] -fn default_enum_without_default_attr() { - check_errors( - r#" -//- minicore: default, derive - -#[derive(Default)] -enum Foo { - Bar, -} - "#, - expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"], - ); -} - -#[test] -fn generic_enum_default() { - check( - r#" -//- minicore: default, derive - -#[derive(Default)] -enum Foo { - Bar(T), - #[default] - Baz, -} -"#, - expect![[r#" - -#[derive(Default)] -enum Foo { - Bar(T), - #[default] - Baz, -} - -impl $crate::default::Default for Foo where { - fn default() -> Self { - Foo::Baz - } -}"#]], - ); -} +// FIXME: This file is commented out because due to the fast path for builtin derives, +// the macros do not really get expanded, and we cannot check their expansion. +// It's not removed because we still need to find some way to do that nevertheless. +// Maybe going through the list of registered derive calls in the def map? + +// use expect_test::expect; + +// use crate::macro_expansion_tests::{check, check_errors}; + +// #[test] +// fn test_copy_expand_simple() { +// check( +// r#" +// //- minicore: derive, copy +// #[derive(Copy)] +// struct Foo; +// "#, +// expect![[r#" +// #[derive(Copy)] +// struct Foo; + +// impl <> $crate::marker::Copy for Foo< > where {}"#]], +// ); +// } + +// #[test] +// fn test_copy_expand_in_core() { +// check( +// r#" +// //- /lib.rs crate:core +// #[rustc_builtin_macro] +// macro derive {} +// #[rustc_builtin_macro] +// macro Copy {} +// #[derive(Copy)] +// struct Foo; +// "#, +// expect![[r#" +// #[rustc_builtin_macro] +// macro derive {} +// #[rustc_builtin_macro] +// macro Copy {} +// #[derive(Copy)] +// struct Foo; + +// impl <> $crate::marker::Copy for Foo< > where {}"#]], +// ); +// } + +// #[test] +// fn test_copy_expand_with_type_params() { +// check( +// r#" +// //- minicore: derive, copy +// #[derive(Copy)] +// struct Foo; +// "#, +// expect![[r#" +// #[derive(Copy)] +// struct Foo; + +// impl $crate::marker::Copy for Foo where {}"#]], +// ); +// } + +// #[test] +// fn test_copy_expand_with_lifetimes() { +// // We currently just ignore lifetimes +// check( +// r#" +// //- minicore: derive, copy +// #[derive(Copy)] +// struct Foo; +// "#, +// expect![[r#" +// #[derive(Copy)] +// struct Foo; + +// impl $crate::marker::Copy for Foo where {}"#]], +// ); +// } + +// #[test] +// fn test_clone_expand() { +// check( +// r#" +// //- minicore: derive, clone +// #[derive(Clone)] +// enum Command { +// Move { x: A, y: B }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// #[derive(Clone)] +// enum Command { +// Move { x: A, y: B }, +// Do(&'static str), +// Jump, +// } + +// impl $crate::clone::Clone for Command where { +// fn clone(&self ) -> Self { +// match self { +// Command::Move { +// x: x, y: y, +// } +// =>Command::Move { +// x: x.clone(), y: y.clone(), +// } +// , Command::Do(f0, )=>Command::Do(f0.clone(), ), Command::Jump=>Command::Jump, +// } +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_clone_expand_with_associated_types() { +// check( +// r#" +// //- minicore: derive, clone +// trait Trait { +// type InWc; +// type InFieldQualified; +// type InFieldShorthand; +// type InGenericArg; +// } +// trait Marker {} +// struct Vec(T); + +// #[derive(Clone)] +// struct Foo +// where +// ::InWc: Marker, +// { +// qualified: ::InFieldQualified, +// shorthand: T::InFieldShorthand, +// generic: Vec, +// } +// "#, +// expect![[r#" +// trait Trait { +// type InWc; +// type InFieldQualified; +// type InFieldShorthand; +// type InGenericArg; +// } +// trait Marker {} +// struct Vec(T); + +// #[derive(Clone)] +// struct Foo +// where +// ::InWc: Marker, +// { +// qualified: ::InFieldQualified, +// shorthand: T::InFieldShorthand, +// generic: Vec, +// } + +// impl $crate::clone::Clone for Foo where ::InWc: Marker, T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { +// fn clone(&self ) -> Self { +// match self { +// Foo { +// qualified: qualified, shorthand: shorthand, generic: generic, +// } +// =>Foo { +// qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), +// } +// , +// } +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_clone_expand_with_const_generics() { +// check( +// r#" +// //- minicore: derive, clone +// #[derive(Clone)] +// struct Foo(u32); +// "#, +// expect![[r#" +// #[derive(Clone)] +// struct Foo(u32); + +// impl $crate::clone::Clone for Foo where { +// fn clone(&self ) -> Self { +// match self { +// Foo(f0, )=>Foo(f0.clone(), ), +// } +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_default_expand() { +// check( +// r#" +// //- minicore: derive, default +// #[derive(Default)] +// struct Foo { +// field1: i32, +// field2: (), +// } +// #[derive(Default)] +// enum Bar { +// Foo(u8), +// #[default] +// Bar, +// } +// "#, +// expect![[r#" +// #[derive(Default)] +// struct Foo { +// field1: i32, +// field2: (), +// } +// #[derive(Default)] +// enum Bar { +// Foo(u8), +// #[default] +// Bar, +// } + +// impl <> $crate::default::Default for Foo< > where { +// fn default() -> Self { +// Foo { +// field1: $crate::default::Default::default(), field2: $crate::default::Default::default(), +// } +// } +// } +// impl <> $crate::default::Default for Bar< > where { +// fn default() -> Self { +// Bar::Bar +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_partial_eq_expand() { +// check( +// r#" +// //- minicore: derive, eq +// #[derive(PartialEq, Eq)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// #[derive(PartialEq, Eq)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } + +// impl <> $crate::cmp::PartialEq for Command< > where { +// fn eq(&self , other: &Self ) -> bool { +// match (self , other) { +// (Command::Move { +// x: x_self, y: y_self, +// } +// , Command::Move { +// x: x_other, y: y_other, +// } +// )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false +// } +// } +// } +// impl <> $crate::cmp::Eq for Command< > where {}"#]], +// ); +// } + +// #[test] +// fn test_partial_eq_expand_with_derive_const() { +// // FIXME: actually expand with const +// check( +// r#" +// //- minicore: derive, eq +// #[derive_const(PartialEq, Eq)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// #[derive_const(PartialEq, Eq)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } + +// impl <> $crate::cmp::PartialEq for Command< > where { +// fn eq(&self , other: &Self ) -> bool { +// match (self , other) { +// (Command::Move { +// x: x_self, y: y_self, +// } +// , Command::Move { +// x: x_other, y: y_other, +// } +// )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false +// } +// } +// } +// impl <> $crate::cmp::Eq for Command< > where {}"#]], +// ); +// } + +// #[test] +// fn test_partial_ord_expand() { +// check( +// r#" +// //- minicore: derive, ord +// #[derive(PartialOrd, Ord)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// #[derive(PartialOrd, Ord)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } + +// impl <> $crate::cmp::PartialOrd for Command< > where { +// fn partial_cmp(&self , other: &Self ) -> $crate::option::Option<$crate::cmp::Ordering> { +// match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { +// match (self , other) { +// (Command::Move { +// x: x_self, y: y_self, +// } +// , Command::Move { +// x: x_other, y: y_other, +// } +// )=>match x_self.partial_cmp(&x_other) { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { +// match y_self.partial_cmp(&y_other) { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal) +// } +// c=>return c, +// } +// } +// c=>return c, +// } +// , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { +// $crate::option::Option::Some($crate::cmp::Ordering::Equal) +// } +// c=>return c, +// } +// , (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal) +// } +// } +// c=>return c, +// } +// } +// } +// impl <> $crate::cmp::Ord for Command< > where { +// fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering { +// match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) { +// $crate::cmp::Ordering::Equal=> { +// match (self , other) { +// (Command::Move { +// x: x_self, y: y_self, +// } +// , Command::Move { +// x: x_other, y: y_other, +// } +// )=>match x_self.cmp(&x_other) { +// $crate::cmp::Ordering::Equal=> { +// match y_self.cmp(&y_other) { +// $crate::cmp::Ordering::Equal=> { +// $crate::cmp::Ordering::Equal +// } +// c=>return c, +// } +// } +// c=>return c, +// } +// , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { +// $crate::cmp::Ordering::Equal=> { +// $crate::cmp::Ordering::Equal +// } +// c=>return c, +// } +// , (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal +// } +// } +// c=>return c, +// } +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_hash_expand() { +// check( +// r#" +// //- minicore: derive, hash +// use core::hash::Hash; + +// #[derive(Hash)] +// struct Foo { +// x: i32, +// y: u64, +// z: (i32, u64), +// } +// "#, +// expect![[r#" +// use core::hash::Hash; + +// #[derive(Hash)] +// struct Foo { +// x: i32, +// y: u64, +// z: (i32, u64), +// } + +// impl <> $crate::hash::Hash for Foo< > where { +// fn hash(&self , ra_expand_state: &mut H) { +// match self { +// Foo { +// x: x, y: y, z: z, +// } +// => { +// x.hash(ra_expand_state); +// y.hash(ra_expand_state); +// z.hash(ra_expand_state); +// } +// , +// } +// } +// }"#]], +// ); +// check( +// r#" +// //- minicore: derive, hash +// use core::hash::Hash; + +// #[derive(Hash)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// use core::hash::Hash; + +// #[derive(Hash)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } + +// impl <> $crate::hash::Hash for Command< > where { +// fn hash(&self , ra_expand_state: &mut H) { +// $crate::mem::discriminant(self ).hash(ra_expand_state); +// match self { +// Command::Move { +// x: x, y: y, +// } +// => { +// x.hash(ra_expand_state); +// y.hash(ra_expand_state); +// } +// , Command::Do(f0, )=> { +// f0.hash(ra_expand_state); +// } +// , Command::Jump=> {} +// , +// } +// } +// }"#]], +// ); +// } + +// #[test] +// fn test_debug_expand() { +// check( +// r#" +// //- minicore: derive, fmt +// use core::fmt::Debug; + +// #[derive(Debug)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } +// "#, +// expect![[r#" +// use core::fmt::Debug; + +// #[derive(Debug)] +// enum Command { +// Move { x: i32, y: i32 }, +// Do(&'static str), +// Jump, +// } + +// impl <> $crate::fmt::Debug for Command< > where { +// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { +// match self { +// Command::Move { +// x: x, y: y, +// } +// =>f.debug_struct("Move").field("x", &x).field("y", &y).finish(), Command::Do(f0, )=>f.debug_tuple("Do").field(&f0).finish(), Command::Jump=>f.write_str("Jump"), +// } +// } +// }"#]], +// ); +// } +// #[test] +// fn test_debug_expand_with_cfg() { +// check( +// r#" +// //- minicore: derive, fmt +// use core::fmt::Debug; + +// #[derive(Debug)] +// struct HideAndShow { +// #[cfg(never)] +// always_hide: u32, +// #[cfg(not(never))] +// always_show: u32, +// } +// #[derive(Debug)] +// enum HideAndShowEnum { +// #[cfg(never)] +// AlwaysHide, +// #[cfg(not(never))] +// AlwaysShow{ +// #[cfg(never)] +// always_hide: u32, +// #[cfg(not(never))] +// always_show: u32, +// } +// } +// "#, +// expect![[r#" +// use core::fmt::Debug; + +// #[derive(Debug)] +// struct HideAndShow { +// #[cfg(never)] +// always_hide: u32, +// #[cfg(not(never))] +// always_show: u32, +// } +// #[derive(Debug)] +// enum HideAndShowEnum { +// #[cfg(never)] +// AlwaysHide, +// #[cfg(not(never))] +// AlwaysShow{ +// #[cfg(never)] +// always_hide: u32, +// #[cfg(not(never))] +// always_show: u32, +// } +// } + +// impl <> $crate::fmt::Debug for HideAndShow< > where { +// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { +// match self { +// HideAndShow { +// always_show: always_show, +// } +// =>f.debug_struct("HideAndShow").field("always_show", &always_show).finish() +// } +// } +// } +// impl <> $crate::fmt::Debug for HideAndShowEnum< > where { +// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { +// match self { +// HideAndShowEnum::AlwaysShow { +// always_show: always_show, +// } +// =>f.debug_struct("AlwaysShow").field("always_show", &always_show).finish(), +// } +// } +// }"#]], +// ); +// } +// #[test] +// fn test_default_expand_with_cfg() { +// check( +// r#" +// //- minicore: derive, default +// #[derive(Default)] +// struct Foo { +// field1: i32, +// #[cfg(never)] +// field2: (), +// #[cfg(feature = "never")] +// field3: (), +// #[cfg(not(feature = "never"))] +// field4: (), +// } +// #[derive(Default)] +// enum Bar { +// Foo, +// #[cfg_attr(not(never), default)] +// Bar, +// } +// "#, +// expect![[r##" +// #[derive(Default)] +// struct Foo { +// field1: i32, +// #[cfg(never)] +// field2: (), +// #[cfg(feature = "never")] +// field3: (), +// #[cfg(not(feature = "never"))] +// field4: (), +// } +// #[derive(Default)] +// enum Bar { +// Foo, +// #[cfg_attr(not(never), default)] +// Bar, +// } + +// impl <> $crate::default::Default for Foo< > where { +// fn default() -> Self { +// Foo { +// field1: $crate::default::Default::default(), field4: $crate::default::Default::default(), +// } +// } +// } +// impl <> $crate::default::Default for Bar< > where { +// fn default() -> Self { +// Bar::Bar +// } +// }"##]], +// ); +// } + +// #[test] +// fn coerce_pointee_expansion() { +// check( +// r#" +// //- minicore: coerce_pointee + +// use core::marker::CoercePointee; + +// pub trait Trait {} + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) +// where +// U: Trait + ToString;"#, +// expect![[r#" + +// use core::marker::CoercePointee; + +// pub trait Trait {} + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) +// where +// U: Trait + ToString; +// impl $crate::ops::DispatchFromDyn> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {} +// impl $crate::ops::CoerceUnsized> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {}"#]], +// ); +// } + +// #[test] +// fn coerce_pointee_errors() { +// check_errors( +// r#" +// //- minicore: coerce_pointee + +// use core::marker::CoercePointee; + +// #[derive(CoercePointee)] +// enum Enum {} + +// #[derive(CoercePointee)] +// struct Struct1; + +// #[derive(CoercePointee)] +// struct Struct2(); + +// #[derive(CoercePointee)] +// struct Struct3 {} + +// #[derive(CoercePointee)] +// struct Struct4(T); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct5(i32); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct7(T, U); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct8<#[pointee] T, U: ?Sized>(T); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct9(T); + +// #[derive(CoercePointee)] +// #[repr(transparent)] +// struct Struct9<#[pointee] T, U>(T) where T: ?Sized; +// "#, +// expect![[r#" +// 35..72: `CoercePointee` can only be derived on `struct`s +// 74..114: `CoercePointee` can only be derived on `struct`s with at least one field +// 116..158: `CoercePointee` can only be derived on `struct`s with at least one field +// 160..202: `CoercePointee` can only be derived on `struct`s with at least one field +// 204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` +// 260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type +// 328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits +// 441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits +// 532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized` +// 623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]], +// ); +// } + +// #[test] +// fn union_derive() { +// check_errors( +// r#" +// //- minicore: clone, copy, default, fmt, hash, ord, eq, derive + +// #[derive(Copy)] +// union Foo1 { _v: () } +// #[derive(Clone)] +// union Foo2 { _v: () } +// #[derive(Default)] +// union Foo3 { _v: () } +// #[derive(Debug)] +// union Foo4 { _v: () } +// #[derive(Hash)] +// union Foo5 { _v: () } +// #[derive(Ord)] +// union Foo6 { _v: () } +// #[derive(PartialOrd)] +// union Foo7 { _v: () } +// #[derive(Eq)] +// union Foo8 { _v: () } +// #[derive(PartialEq)] +// union Foo9 { _v: () } +// "#, +// expect![[r#" +// 78..118: this trait cannot be derived for unions +// 119..157: this trait cannot be derived for unions +// 158..195: this trait cannot be derived for unions +// 196..232: this trait cannot be derived for unions +// 233..276: this trait cannot be derived for unions +// 313..355: this trait cannot be derived for unions"#]], +// ); +// } + +// #[test] +// fn default_enum_without_default_attr() { +// check_errors( +// r#" +// //- minicore: default, derive + +// #[derive(Default)] +// enum Foo { +// Bar, +// } +// "#, +// expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"], +// ); +// } + +// #[test] +// fn generic_enum_default() { +// check( +// r#" +// //- minicore: default, derive + +// #[derive(Default)] +// enum Foo { +// Bar(T), +// #[default] +// Baz, +// } +// "#, +// expect![[r#" + +// #[derive(Default)] +// enum Foo { +// Bar(T), +// #[default] +// Baz, +// } + +// impl $crate::default::Default for Foo where { +// fn default() -> Self { +// Foo::Baz +// } +// }"#]], +// ); +// } diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 6f30ca04af..bf04a500a5 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -122,16 +122,16 @@ struct Foo { v4: bool // No comma here } +#[attr1] +#[derive(Bar)] +#[attr2] struct S; #[attr1] #[my_cool_derive()] struct Foo { v1: i32, #[attr3]v2: fn(#[attr4]param2: u32), v3: Foo< { 456 } >, -} -#[attr1] -#[derive(Bar)] -#[attr2] struct S;"#]], +}"#]], ); } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 2fac0837de..8694ebe4e4 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -224,6 +224,8 @@ struct DeferredBuiltinDerive { module_id: ModuleId, depth: usize, container: ItemContainerId, + derive_attr_id: AttrId, + derive_index: u32, } /// Walks the tree of module recursively @@ -1479,10 +1481,10 @@ impl<'db> DefCollector<'db> { let ast_id = ast_id.with_value(ast_adt_id); + let mut derive_call_ids = SmallVec::new(); match attr.parse_path_comma_token_tree(self.db) { Some(derive_macros) => { let call_id = call_id(); - let mut len = 0; for (idx, (path, call_site, _)) in derive_macros.enumerate() { let ast_id = AstIdWithPath::new( file_id, @@ -1505,14 +1507,7 @@ impl<'db> DefCollector<'db> { ); if let Ok((macro_id, def_id, call_id)) = id { - self.def_map.modules[directive.module_id] - .scope - .set_derive_macro_invoc( - ast_id.ast_id, - call_id, - *attr_id, - idx, - ); + derive_call_ids.push(Some(call_id)); // Record its helper attributes. if def_id.krate != self.def_map.krate { let def_map = crate_def_map(self.db, def_id.krate); @@ -1543,11 +1538,14 @@ impl<'db> DefCollector<'db> { module_id: directive.module_id, container: directive.container, depth: directive.depth, + derive_attr_id: *attr_id, + derive_index: idx as u32, }); } else { push_resolved(&mut resolved, directive, call_id); } } else { + derive_call_ids.push(None); self.unresolved_macros.push(MacroDirective { module_id: directive.module_id, depth: directive.depth + 1, @@ -1561,7 +1559,6 @@ impl<'db> DefCollector<'db> { container: directive.container, }); } - len = idx; } // We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection. @@ -1570,7 +1567,12 @@ impl<'db> DefCollector<'db> { // Check the comment in [`builtin_attr_macro`]. self.def_map.modules[directive.module_id] .scope - .init_derive_attribute(ast_id, *attr_id, call_id, len + 1); + .init_derive_attribute( + ast_id, + *attr_id, + call_id, + derive_call_ids, + ); } None => { let diag = DefDiagnostic::malformed_derive( @@ -1863,8 +1865,15 @@ impl ModCollector<'_, '_> { let module = &mut def_map.modules[module_id]; for deferred_derive in deferred_derives { crate::builtin_derive::with_derive_traits(deferred_derive.derive, |trait_| { - let impl_id = - BuiltinDeriveImplId::new(db, BuiltinDeriveImplLoc { adt: id, trait_ }); + let impl_id = BuiltinDeriveImplId::new( + db, + BuiltinDeriveImplLoc { + adt: id, + trait_, + derive_attr_id: deferred_derive.derive_attr_id, + derive_index: deferred_derive.derive_index, + }, + ); module.scope.define_builtin_derive_impl(impl_id); }); } diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs index 15d9634cfa..f3e67d01e5 100644 --- a/crates/hir-ty/src/builtin_derive.rs +++ b/crates/hir-ty/src/builtin_derive.rs @@ -20,16 +20,18 @@ use crate::{ GenericPredicates, db::HirDatabase, next_solver::{ - Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, StoredEarlyBinder, StoredTy, - TraitRef, Ty, TyKind, fold::fold_tys, generics::Generics, + Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, ParamEnv, StoredEarlyBinder, + StoredTy, TraitRef, Ty, TyKind, fold::fold_tys, generics::Generics, }, }; -fn fake_type_param(adt: AdtId) -> TypeParamId { +fn coerce_pointee_new_type_param(trait_id: TraitId) -> TypeParamId { // HACK: Fake the param. + // We cannot use a dummy param here, because it can leak into the IDE layer and that'll cause panics + // when e.g. trying to display it. So we use an existing param. TypeParamId::from_unchecked(TypeOrConstParamId { - parent: adt.into(), - local_id: la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(u32::MAX)), + parent: trait_id.into(), + local_id: la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(1)), }) } @@ -48,13 +50,35 @@ pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplI | BuiltinDeriveImplTrait::PartialEq => interner.generics_of(loc.adt.into()), BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let mut generics = interner.generics_of(loc.adt.into()); - generics.push_param(fake_type_param(loc.adt).into()); + let trait_id = loc + .trait_ + .get_id(interner.lang_items()) + .expect("we don't pass the impl to the solver if we can't resolve the trait"); + generics.push_param(coerce_pointee_new_type_param(trait_id).into()); generics } } } -pub(crate) fn impl_trait<'db>( +pub fn generic_params_count(db: &dyn HirDatabase, id: BuiltinDeriveImplId) -> usize { + let loc = id.loc(db); + let adt_params = GenericParams::new(db, loc.adt.into()); + let extra_params_count = match loc.trait_ { + BuiltinDeriveImplTrait::Copy + | BuiltinDeriveImplTrait::Clone + | BuiltinDeriveImplTrait::Default + | BuiltinDeriveImplTrait::Debug + | BuiltinDeriveImplTrait::Hash + | BuiltinDeriveImplTrait::Ord + | BuiltinDeriveImplTrait::PartialOrd + | BuiltinDeriveImplTrait::Eq + | BuiltinDeriveImplTrait::PartialEq => 0, + BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => 1, + }; + adt_params.len() + extra_params_count +} + +pub fn impl_trait<'db>( interner: DbInterner<'db>, id: BuiltinDeriveImplId, ) -> EarlyBinder<'db, TraitRef<'db>> { @@ -93,7 +117,7 @@ pub(crate) fn impl_trait<'db>( let args = GenericArgs::identity_for_item(interner, loc.adt.into()); let self_ty = Ty::new_adt(interner, loc.adt, args); let Some((pointee_param_idx, _, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params) + coerce_pointee_params(interner, loc, &generic_params, trait_id) else { // Malformed derive. return EarlyBinder::bind(TraitRef::new( @@ -110,14 +134,15 @@ pub(crate) fn impl_trait<'db>( } #[salsa::tracked(returns(ref), unsafe(non_update_types))] -pub(crate) fn builtin_derive_predicates<'db>( - db: &'db dyn HirDatabase, - impl_: BuiltinDeriveImplId, -) -> GenericPredicates { +pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates { let loc = impl_.loc(db); let generic_params = GenericParams::new(db, loc.adt.into()); let interner = DbInterner::new_with(db, loc.module(db).krate(db)); let adt_predicates = GenericPredicates::query(db, loc.adt.into()); + let trait_id = loc + .trait_ + .get_id(interner.lang_items()) + .expect("we don't pass the impl to the solver if we can't resolve the trait"); match loc.trait_ { BuiltinDeriveImplTrait::Copy | BuiltinDeriveImplTrait::Clone @@ -127,7 +152,7 @@ pub(crate) fn builtin_derive_predicates<'db>( | BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::Eq | BuiltinDeriveImplTrait::PartialEq => { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates) + simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) } BuiltinDeriveImplTrait::Default => { if matches!(loc.adt, AdtId::EnumId(_)) { @@ -137,12 +162,12 @@ pub(crate) fn builtin_derive_predicates<'db>( .store(), )) } else { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates) + simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) } } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let Some((pointee_param_idx, pointee_param_id, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params) + coerce_pointee_params(interner, loc, &generic_params, trait_id) else { // Malformed derive. return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( @@ -181,6 +206,12 @@ pub(crate) fn builtin_derive_predicates<'db>( } } +/// Not cached in a query, currently used in `hir` only. If you need this in `hir-ty` consider introducing a query. +pub fn param_env<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> ParamEnv<'db> { + let predicates = predicates(interner.db, id); + crate::lower::param_env_from_predicates(interner, predicates) +} + struct MentionsPointee { pointee_param_idx: u32, } @@ -216,11 +247,8 @@ fn simple_trait_predicates<'db>( loc: &BuiltinDeriveImplLoc, generic_params: &GenericParams, adt_predicates: &GenericPredicates, + trait_id: TraitId, ) -> GenericPredicates { - let trait_id = loc - .trait_ - .get_id(interner.lang_items()) - .expect("we don't pass the impl to the solver if we can't resolve the trait"); let extra_predicates = generic_params .iter_type_or_consts() .filter(|(_, data)| matches!(data, TypeOrConstParamData::TypeParamData(_))) @@ -309,6 +337,7 @@ fn coerce_pointee_params<'db>( interner: DbInterner<'db>, loc: &BuiltinDeriveImplLoc, generic_params: &GenericParams, + trait_id: TraitId, ) -> Option<(u32, TypeParamId, Ty<'db>)> { let pointee_param = { if let Ok((pointee_param, _)) = generic_params @@ -339,7 +368,7 @@ fn coerce_pointee_params<'db>( let pointee_param_idx = pointee_param.into_raw().into_u32() + (generic_params.len_lifetimes() as u32); let new_param_idx = generic_params.len() as u32; - let new_param_id = fake_type_param(loc.adt); + let new_param_id = coerce_pointee_new_type_param(trait_id); let new_param_ty = Ty::new_param(interner, new_param_id, new_param_idx); Some((pointee_param_idx, pointee_param_id, new_param_ty)) } @@ -352,11 +381,7 @@ mod tests { use stdx::format_to; use test_fixture::WithFixture; - use crate::{ - builtin_derive::{builtin_derive_predicates, impl_trait}, - next_solver::DbInterner, - test_db::TestDB, - }; + use crate::{builtin_derive::impl_trait, next_solver::DbInterner, test_db::TestDB}; fn check_trait_refs(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { let db = TestDB::with_files(ra_fixture); @@ -384,8 +409,7 @@ mod tests { let mut predicates = String::new(); for (_, module) in def_map.modules() { for derive in module.scope.builtin_derive_impls() { - let preds = - builtin_derive_predicates(&db, derive).all_predicates().skip_binder(); + let preds = super::predicates(&db, derive).all_predicates().skip_binder(); format_to!( predicates, "{}\n\n", diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 8816e13ba7..08f201fea9 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1568,6 +1568,7 @@ const GOAL: u8 = { } #[test] +#[ignore = "builtin derive macros are currently not working with MIR eval"] fn builtin_derive_macro() { check_number( r#" diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index f0f65eedbc..70474fc469 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -2,10 +2,12 @@ //! type inference-related queries. use base_db::{Crate, target::TargetLoadError}; +use either::Either; use hir_def::{ - AdtId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, - GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, VariantId, - db::DefDatabase, hir::ExprId, layout::TargetDataLayout, + AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, + FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, + TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId, + layout::TargetDataLayout, }; use la_arena::ArenaMap; use salsa::plumbing::AsId; @@ -83,7 +85,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, - ) -> (FunctionId, GenericArgs<'db>); + ) -> (Either, GenericArgs<'db>); // endregion:mir diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index b9e23464e9..efce9ab1f1 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -7,7 +7,7 @@ use std::{ mem, }; -use base_db::Crate; +use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, @@ -143,11 +143,11 @@ impl<'db> BoundsFormattingCtx<'db> { } impl<'db> HirFormatter<'_, 'db> { - fn start_location_link(&mut self, location: ModuleDefId) { + pub fn start_location_link(&mut self, location: ModuleDefId) { self.fmt.start_location_link(location); } - fn end_location_link(&mut self) { + pub fn end_location_link(&mut self) { self.fmt.end_location_link(); } @@ -1978,6 +1978,49 @@ fn write_bounds_like_dyn_trait<'db>( Ok(()) } +pub fn write_params_bounds<'db>( + f: &mut HirFormatter<'_, 'db>, + predicates: &[Clause<'db>], +) -> Result { + // Use an FxIndexMap to keep user's order, as far as possible. + let mut per_type = FxIndexMap::<_, Vec<_>>::default(); + for &predicate in predicates { + let base_ty = match predicate.kind().skip_binder() { + ClauseKind::Trait(clause) => Either::Left(clause.self_ty()), + ClauseKind::RegionOutlives(clause) => Either::Right(clause.0), + ClauseKind::TypeOutlives(clause) => Either::Left(clause.0), + ClauseKind::Projection(clause) => Either::Left(clause.self_ty()), + ClauseKind::ConstArgHasType(..) + | ClauseKind::WellFormed(_) + | ClauseKind::ConstEvaluatable(_) + | ClauseKind::HostEffect(..) + | ClauseKind::UnstableFeature(_) => continue, + }; + per_type.entry(base_ty).or_default().push(predicate); + } + + for (base_ty, clauses) in per_type { + f.write_str(" ")?; + match base_ty { + Either::Left(it) => it.hir_fmt(f)?, + Either::Right(it) => it.hir_fmt(f)?, + } + f.write_str(": ")?; + // Rudimentary approximation: type params are `Sized` by default, everything else not. + // FIXME: This is not correct, really. But I'm not sure how we can from the ty representation + // to extract the default sizedness, and if it's possible at all. + let default_sized = match base_ty { + Either::Left(ty) if matches!(ty.kind(), TyKind::Param(_)) => { + SizedByDefault::Sized { anchor: f.krate() } + } + _ => SizedByDefault::NotSized, + }; + write_bounds_like_dyn_trait(f, base_ty, &clauses, default_sized)?; + f.write_str(",\n")?; + } + Ok(()) +} + impl<'db> HirDisplay<'db> for TraitRef<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let trait_ = self.def_id.0; diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 7b414cd551..373862229b 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -25,7 +25,7 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; extern crate self as hir_ty; -mod builtin_derive; +pub mod builtin_derive; mod infer; mod inhabitedness; mod lower; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index ebbf29e6ff..9307868f39 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1855,6 +1855,20 @@ pub(crate) fn trait_environment_for_body_query( db.trait_environment(def) } +pub(crate) fn param_env_from_predicates<'db>( + interner: DbInterner<'db>, + predicates: &'db GenericPredicates, +) -> ParamEnv<'db> { + let clauses = rustc_type_ir::elaborate::elaborate( + interner, + predicates.all_predicates().iter_identity_copied(), + ); + let clauses = Clauses::new_from_iter(interner, clauses); + + // FIXME: We should normalize projections here, like rustc does. + ParamEnv { clauses } +} + pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> { return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; @@ -1865,13 +1879,8 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId ) -> StoredClauses { let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); - let predicates = GenericPredicates::query_all(db, def); - let clauses = - rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied()); - let clauses = Clauses::new_from_iter(interner, clauses); - - // FIXME: We should normalize projections here, like rustc does. - clauses.store() + let predicates = GenericPredicates::query(db, def); + param_env_from_predicates(interner, predicates).clauses.store() } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 88f48fdbc6..50dbd87d69 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -16,6 +16,7 @@ use hir_def::{ AssocItemId, BlockId, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId, ModuleId, TraitId, attrs::AttrFlags, + builtin_derive::BuiltinDeriveImplMethod, expr_store::path::GenericArgs as HirGenericArgs, hir::ExprId, lang_item::LangItems, @@ -372,9 +373,13 @@ pub fn lookup_impl_const<'db>( }; lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name) - .and_then( - |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None }, - ) + .and_then(|assoc| { + if let (Either::Left(AssocItemId::ConstId(id)), s) = assoc { + Some((id, s)) + } else { + None + } + }) .unwrap_or((const_id, subs)) } @@ -420,12 +425,12 @@ pub(crate) fn lookup_impl_method_query<'db>( env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, -) -> (FunctionId, GenericArgs<'db>) { +) -> (Either, GenericArgs<'db>) { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { - return (func, fn_subst); + return (Either::Left(func), fn_subst); }; let trait_params = db.generic_params(trait_id.into()).len(); let trait_ref = TraitRef::new_from_args( @@ -435,16 +440,19 @@ pub(crate) fn lookup_impl_method_query<'db>( ); let name = &db.function_signature(func).name; - let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref( - &infcx, - trait_ref, - env.param_env, - name, - ) - .and_then(|assoc| { - if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None } - }) else { - return (func, fn_subst); + let Some((impl_fn, impl_subst)) = + lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then( + |(assoc, impl_args)| { + let assoc = match assoc { + Either::Left(AssocItemId::FunctionId(id)) => Either::Left(id), + Either::Right(it) => Either::Right(it), + _ => return None, + }; + Some((assoc, impl_args)) + }, + ) + else { + return (Either::Left(func), fn_subst); }; ( @@ -461,11 +469,18 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>( trait_ref: TraitRef<'db>, env: ParamEnv<'db>, name: &Name, -) -> Option<(AssocItemId, GenericArgs<'db>)> { +) -> Option<(Either, GenericArgs<'db>)> +{ let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?; - let AnyImplId::ImplId(impl_id) = impl_id else { - // FIXME: Handle resolution to builtin derive. - return None; + let impl_id = match impl_id { + AnyImplId::ImplId(it) => it, + AnyImplId::BuiltinDeriveImplId(impl_) => { + return impl_ + .loc(infcx.interner.db) + .trait_ + .get_method(name.symbol()) + .map(|method| (Either::Right((impl_, method)), impl_subst)); + } }; let item = impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it { @@ -473,7 +488,7 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>( AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)), AssocItemId::TypeAliasId(_) => None, })?; - Some((item, impl_subst)) + Some((Either::Left(item), impl_subst)) } pub(crate) fn find_matching_impl<'db>( @@ -793,19 +808,29 @@ impl TraitImpls { .unwrap_or_default() } - pub fn for_trait(&self, trait_: TraitId, mut callback: impl FnMut(&[ImplId])) { + pub fn for_trait( + &self, + trait_: TraitId, + mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), + ) { if let Some(impls) = self.map.get(&trait_) { - callback(&impls.blanket_impls); + callback(Either::Left(&impls.blanket_impls)); for impls in impls.non_blanket_impls.values() { - callback(&impls.0); + callback(Either::Left(&impls.0)); + callback(Either::Right(&impls.1)); } } } - pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) { + pub fn for_self_ty( + &self, + self_ty: &SimplifiedType, + mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), + ) { for for_trait in self.map.values() { if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) { - callback(&for_ty.0); + callback(Either::Left(&for_ty.0)); + callback(Either::Right(&for_ty.1)); } } } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index c7156bb11e..cd860700c1 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -77,12 +77,14 @@ macro_rules! from_bytes { }).into()) }; } +use from_bytes; macro_rules! not_supported { ($it: expr) => { - return Err(MirEvalError::NotSupported(format!($it))) + return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it))) }; } +use not_supported; #[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)] pub struct VTableMap<'db> { @@ -2622,6 +2624,9 @@ impl<'db> Evaluator<'db> { def, generic_args, ); + let Either::Left(imp) = imp else { + not_supported!("evaluating builtin derive impls is not supported") + }; let mir_body = self .db diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index a47a8c4400..76c8701ea2 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -16,29 +16,14 @@ use crate::{ mir::eval::{ Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay, InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, Layout, Locals, - Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16, + Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported, + pad16, }, next_solver::Region, }; mod simd; -macro_rules! from_bytes { - ($ty:tt, $value:expr) => { - ($ty::from_le_bytes(match ($value).try_into() { - Ok(it) => it, - #[allow(unreachable_patterns)] - Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())), - })) - }; -} - -macro_rules! not_supported { - ($it: expr) => { - return Err(MirEvalError::NotSupported(format!($it))) - }; -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum EvalLangItem { BeginPanic, diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs index 3896917cab..e0b3e571b8 100644 --- a/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -6,21 +6,6 @@ use crate::consteval::try_const_usize; use super::*; -macro_rules! from_bytes { - ($ty:tt, $value:expr) => { - ($ty::from_le_bytes(match ($value).try_into() { - Ok(it) => it, - Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())), - })) - }; -} - -macro_rules! not_supported { - ($it: expr) => { - return Err(MirEvalError::NotSupported(format!($it))) - }; -} - impl<'db> Evaluator<'db> { fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> { match ty.kind() { diff --git a/crates/hir-ty/src/next_solver/format_proof_tree.rs b/crates/hir-ty/src/next_solver/format_proof_tree.rs index 59fb0d65c5..66da6d5400 100644 --- a/crates/hir-ty/src/next_solver/format_proof_tree.rs +++ b/crates/hir-ty/src/next_solver/format_proof_tree.rs @@ -1,8 +1,8 @@ use rustc_type_ir::{solve::GoalSource, solve::inspect::GoalEvaluation}; use serde_derive::{Deserialize, Serialize}; -use crate::next_solver::infer::InferCtxt; use crate::next_solver::inspect::{InspectCandidate, InspectGoal}; +use crate::next_solver::{AnyImplId, infer::InferCtxt}; use crate::next_solver::{DbInterner, Span}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -76,14 +76,31 @@ impl<'a, 'db> ProofTreeSerializer<'a, 'db> { use rustc_type_ir::solve::inspect::ProbeKind; match candidate.kind() { ProbeKind::TraitCandidate { source, .. } => { + use hir_def::{Lookup, src::HasSource}; use rustc_type_ir::solve::CandidateSource; + let db = self.infcx.interner.db; match source { - CandidateSource::Impl(impl_def_id) => { - use hir_def::{Lookup, src::HasSource}; - let db = self.infcx.interner.db; - let impl_src = impl_def_id.0.lookup(db).source(db); - Some(impl_src.value.to_string()) - } + CandidateSource::Impl(impl_def_id) => match impl_def_id { + AnyImplId::ImplId(impl_def_id) => { + let impl_src = impl_def_id.lookup(db).source(db); + Some(impl_src.value.to_string()) + } + AnyImplId::BuiltinDeriveImplId(impl_id) => { + let impl_loc = impl_id.loc(db); + let adt_src = match impl_loc.adt { + hir_def::AdtId::StructId(adt) => { + adt.loc(db).source(db).value.to_string() + } + hir_def::AdtId::UnionId(adt) => { + adt.loc(db).source(db).value.to_string() + } + hir_def::AdtId::EnumId(adt) => { + adt.loc(db).source(db).value.to_string() + } + }; + Some(format!("#[derive(${})]\n{}", impl_loc.trait_.name(), adt_src)) + } + }, _ => None, } } diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 269474e015..2a3df1d32a 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -2370,7 +2370,7 @@ impl<'db> DbInterner<'db> { fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates { if let SolverDefId::BuiltinDeriveImplId(impl_) = def_id { - crate::builtin_derive::builtin_derive_predicates(db, impl_) + crate::builtin_derive::predicates(db, impl_) } else { GenericPredicates::query(db, def_id.try_into().unwrap()) } diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index ea33c9bcd4..1457bb2e10 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -539,7 +539,7 @@ impl SomeStruct { "AttrFlags::query_", "AttrFlags::query_", "AttrFlags::query_", - "impl_trait_with_diagnostics_shim", + "impl_trait_with_diagnostics_query", "impl_signature_shim", "impl_signature_with_source_map_shim", "impl_self_ty_with_diagnostics_query", diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index d1056f31e1..cba1b39e52 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -35,6 +35,8 @@ pub enum AttrsOwner { Field(FieldId), LifetimeParam(LifetimeParamId), TypeOrConstParam(TypeOrConstParamId), + /// Things that do not have attributes. Used for builtin derives. + Dummy, } impl AttrsOwner { @@ -123,7 +125,9 @@ impl AttrsWithOwner { let owner = match self.owner { AttrsOwner::AttrDef(it) => Either::Left(it), AttrsOwner::Field(it) => Either::Right(it), - AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return &[], + AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => { + return &[]; + } }; self.attrs.doc_aliases(db, owner) } @@ -133,7 +137,9 @@ impl AttrsWithOwner { let owner = match self.owner { AttrsOwner::AttrDef(it) => Either::Left(it), AttrsOwner::Field(it) => Either::Right(it), - AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None, + AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => { + return None; + } }; self.attrs.cfgs(db, owner) } @@ -143,7 +149,9 @@ impl AttrsWithOwner { match self.owner { AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(), AttrsOwner::Field(it) => AttrFlags::field_docs(db, it), - AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None, + AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => { + None + } } } } @@ -156,6 +164,9 @@ pub trait HasAttrs: Sized { AttrsOwner::Field(it) => AttrsWithOwner::new_field(db, it), AttrsOwner::LifetimeParam(it) => AttrsWithOwner::new_lifetime_param(db, it), AttrsOwner::TypeOrConstParam(it) => AttrsWithOwner::new_type_or_const_param(db, it), + AttrsOwner::Dummy => { + AttrsWithOwner { attrs: AttrFlags::empty(), owner: AttrsOwner::Dummy } + } } } @@ -167,7 +178,9 @@ pub trait HasAttrs: Sized { match self.attr_id(db) { AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(), AttrsOwner::Field(it) => AttrFlags::field_docs(db, it), - AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None, + AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => { + None + } } } } @@ -190,12 +203,28 @@ impl_has_attrs![ (Trait, TraitId), (TypeAlias, TypeAliasId), (Macro, MacroId), - (Function, FunctionId), (Adt, AdtId), - (Impl, ImplId), (ExternCrateDecl, ExternCrateId), ]; +impl HasAttrs for Function { + fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner { + match self.id { + crate::AnyFunctionId::FunctionId(id) => AttrsOwner::AttrDef(id.into()), + crate::AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrsOwner::Dummy, + } + } +} + +impl HasAttrs for Impl { + fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner { + match self.id { + hir_ty::next_solver::AnyImplId::ImplId(id) => AttrsOwner::AttrDef(id.into()), + hir_ty::next_solver::AnyImplId::BuiltinDeriveImplId(..) => AttrsOwner::Dummy, + } + } +} + macro_rules! impl_has_attrs_enum { ($($variant:ident),* for $enum:ident) => {$( impl HasAttrs for $variant { @@ -294,7 +323,9 @@ fn resolve_doc_path_on_( AttrsOwner::AttrDef(AttrDefId::MacroId(it)) => it.resolver(db), AttrsOwner::AttrDef(AttrDefId::ExternCrateId(it)) => it.resolver(db), AttrsOwner::Field(it) => it.parent.resolver(db), - AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None, + AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => { + return None; + } }; let mut modpath = doc_modpath_from_str(link)?; diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index d0d8c4877d..1f9af564c3 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -2,19 +2,22 @@ use either::Either; use hir_def::{ - AdtId, GenericDefId, + AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId, + builtin_derive::BuiltinDeriveImplMethod, expr_store::ExpressionStore, hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_tree::FieldsShape, signatures::{StaticFlags, TraitFlags}, type_ref::{TypeBound, TypeRef, TypeRefId}, }; +use hir_expand::name::Name; use hir_ty::{ GenericPredicates, db::HirDatabase, display::{ HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault, - hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility, + hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_params_bounds, + write_visibility, }, next_solver::ClauseKind, }; @@ -22,25 +25,78 @@ use itertools::Itertools; use rustc_type_ir::inherent::IntoKind; use crate::{ - Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, + Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, }; +fn write_builtin_derive_impl_method<'db>( + f: &mut HirFormatter<'_, 'db>, + impl_: BuiltinDeriveImplId, + method: BuiltinDeriveImplMethod, +) -> Result { + let db = f.db; + let loc = impl_.loc(db); + let (adt_params, _adt_params_store) = db.generic_params_and_store(loc.adt.into()); + + if f.show_container_bounds() && !adt_params.is_empty() { + f.write_str("impl")?; + write_generic_params(loc.adt.into(), f)?; + f.write_char(' ')?; + let trait_id = loc.trait_.get_id(f.lang_items()); + if let Some(trait_id) = trait_id { + f.start_location_link(trait_id.into()); + } + write!(f, "{}", Name::new_symbol_root(loc.trait_.name()).display(db, f.edition()))?; + if trait_id.is_some() { + f.end_location_link(); + } + f.write_str(" for ")?; + f.start_location_link(loc.adt.into()); + write!(f, "{}", Adt::from(loc.adt).name(db).display(db, f.edition()))?; + f.end_location_link(); + write_generic_args(loc.adt.into(), f)?; + f.write_char('\n')?; + } + + let Some(trait_method) = method.trait_method(db, impl_) else { + return write!(f, "fn {}(…)", method.name()); + }; + let has_written_where = write_function(f, trait_method)?; + + if f.show_container_bounds() && !adt_params.is_empty() { + if !has_written_where { + f.write_str("\nwhere")? + } + write!(f, "\n // Bounds from impl:")?; + + let predicates = + hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder(); + write_params_bounds(f, predicates)?; + } + + Ok(()) +} + impl<'db> HirDisplay<'db> for Function { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { + let id = match self.id { + AnyFunctionId::FunctionId(id) => id, + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + return write_builtin_derive_impl_method(f, impl_, method); + } + }; + let db = f.db; - let data = db.function_signature(self.id); - let container = self.as_assoc_item(db).map(|it| it.container(db)); - let mut module = self.module(db); + let container = id.loc(db).container; // Write container (trait or impl) let container_params = match container { - Some(AssocItemContainer::Trait(trait_)) => { - let (params, params_store) = f.db.generic_params_and_store(trait_.id.into()); + ItemContainerId::TraitId(trait_) => { + let (params, params_store) = f.db.generic_params_and_store(trait_.into()); if f.show_container_bounds() && !params.is_empty() { - write_trait_header(&trait_, f)?; + write_trait_header(trait_.into(), f)?; f.write_char('\n')?; has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) .then_some((params, params_store)) @@ -48,10 +104,10 @@ impl<'db> HirDisplay<'db> for Function { None } } - Some(AssocItemContainer::Impl(impl_)) => { - let (params, params_store) = f.db.generic_params_and_store(impl_.id.into()); + ItemContainerId::ImplId(impl_) => { + let (params, params_store) = f.db.generic_params_and_store(impl_.into()); if f.show_container_bounds() && !params.is_empty() { - write_impl_header(&impl_, f)?; + write_impl_header(impl_, f)?; f.write_char('\n')?; has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) .then_some((params, params_store)) @@ -59,124 +115,20 @@ impl<'db> HirDisplay<'db> for Function { None } } - None => None, + _ => None, }; // Write signature of the function - // Block-local impls are "hoisted" to the nearest (non-block) module. - if let Some(AssocItemContainer::Impl(_)) = container { - module = module.nearest_non_block_module(db); - } - let module_id = module.id; - - write_visibility(module_id, self.visibility(db), f)?; - - if data.is_default() { - f.write_str("default ")?; - } - if data.is_const() { - f.write_str("const ")?; - } - if data.is_async() { - f.write_str("async ")?; - } - // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe - // (they are conditionally unsafe to call). We probably should show something else. - if self.is_unsafe_to_call(db, None, f.edition()) { - f.write_str("unsafe ")?; - } - if let Some(abi) = &data.abi { - write!(f, "extern \"{}\" ", abi.as_str())?; - } - write!(f, "fn {}", data.name.display(f.db, f.edition()))?; - - write_generic_params(GenericDefId::FunctionId(self.id), f)?; - - f.write_char('(')?; - - let mut first = true; - let mut skip_self = 0; - if let Some(self_param) = self.self_param(db) { - self_param.hir_fmt(f)?; - first = false; - skip_self = 1; - } - - // FIXME: Use resolved `param.ty` once we no longer discard lifetimes - let body = db.body(self.id.into()); - for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) { - if !first { - f.write_str(", ")?; - } else { - first = false; - } - - let pat_id = body.params[param.idx - body.self_param.is_some() as usize]; - let pat_str = body.pretty_print_pat(db, self.id.into(), pat_id, true, f.edition()); - f.write_str(&pat_str)?; - - f.write_str(": ")?; - type_ref.hir_fmt(f, &data.store)?; - } - - if data.is_varargs() { - if !first { - f.write_str(", ")?; - } - f.write_str("...")?; - } - - f.write_char(')')?; - - // `FunctionData::ret_type` will be `::core::future::Future` for async fns. - // Use ugly pattern match to strip the Future trait. - // Better way? - let ret_type = if !data.is_async() { - data.ret_type - } else if let Some(ret_type) = data.ret_type { - match &data.store[ret_type] { - TypeRef::ImplTrait(bounds) => match &bounds[0] { - &TypeBound::Path(path, _) => Some( - *data.store[path] - .segments() - .iter() - .last() - .unwrap() - .args_and_bindings - .unwrap() - .bindings[0] - .type_ref - .as_ref() - .unwrap(), - ), - _ => None, - }, - _ => None, - } - } else { - None - }; - - if let Some(ret_type) = ret_type { - match &data.store[ret_type] { - TypeRef::Tuple(tup) if tup.is_empty() => {} - _ => { - f.write_str(" -> ")?; - ret_type.hir_fmt(f, &data.store)?; - } - } - } - - // Write where clauses - let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?; + let has_written_where = write_function(f, id)?; if let Some((container_params, container_params_store)) = container_params { if !has_written_where { f.write_str("\nwhere")?; } - let container_name = match container.unwrap() { - AssocItemContainer::Trait(_) => "trait", - AssocItemContainer::Impl(_) => "impl", + let container_name = match container { + ItemContainerId::TraitId(_) => "trait", + ItemContainerId::ImplId(_) => "impl", + _ => unreachable!(), }; write!(f, "\n // Bounds from {container_name}:",)?; write_where_predicates(&container_params, &container_params_store, f)?; @@ -185,14 +137,129 @@ impl<'db> HirDisplay<'db> for Function { } } -fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result { +fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result { + let db = f.db; + let func = Function::from(func_id); + let data = db.function_signature(func_id); + + let mut module = func.module(db); + // Block-local impls are "hoisted" to the nearest (non-block) module. + if let ItemContainerId::ImplId(_) = func_id.loc(db).container { + module = module.nearest_non_block_module(db); + } + let module_id = module.id; + + write_visibility(module_id, func.visibility(db), f)?; + + if data.is_default() { + f.write_str("default ")?; + } + if data.is_const() { + f.write_str("const ")?; + } + if data.is_async() { + f.write_str("async ")?; + } + // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe + // (they are conditionally unsafe to call). We probably should show something else. + if func.is_unsafe_to_call(db, None, f.edition()) { + f.write_str("unsafe ")?; + } + if let Some(abi) = &data.abi { + write!(f, "extern \"{}\" ", abi.as_str())?; + } + write!(f, "fn {}", data.name.display(f.db, f.edition()))?; + + write_generic_params(GenericDefId::FunctionId(func_id), f)?; + + f.write_char('(')?; + + let mut first = true; + let mut skip_self = 0; + if let Some(self_param) = func.self_param(db) { + self_param.hir_fmt(f)?; + first = false; + skip_self = 1; + } + + // FIXME: Use resolved `param.ty` once we no longer discard lifetimes + let body = db.body(func_id.into()); + for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) { + if !first { + f.write_str(", ")?; + } else { + first = false; + } + + let pat_id = body.params[param.idx - body.self_param.is_some() as usize]; + let pat_str = body.pretty_print_pat(db, func_id.into(), pat_id, true, f.edition()); + f.write_str(&pat_str)?; + + f.write_str(": ")?; + type_ref.hir_fmt(f, &data.store)?; + } + + if data.is_varargs() { + if !first { + f.write_str(", ")?; + } + f.write_str("...")?; + } + + f.write_char(')')?; + + // `FunctionData::ret_type` will be `::core::future::Future` for async fns. + // Use ugly pattern match to strip the Future trait. + // Better way? + let ret_type = if !data.is_async() { + data.ret_type + } else if let Some(ret_type) = data.ret_type { + match &data.store[ret_type] { + TypeRef::ImplTrait(bounds) => match &bounds[0] { + &TypeBound::Path(path, _) => Some( + *data.store[path] + .segments() + .iter() + .last() + .unwrap() + .args_and_bindings + .unwrap() + .bindings[0] + .type_ref + .as_ref() + .unwrap(), + ), + _ => None, + }, + _ => None, + } + } else { + None + }; + + if let Some(ret_type) = ret_type { + match &data.store[ret_type] { + TypeRef::Tuple(tup) if tup.is_empty() => {} + _ => { + f.write_str(" -> ")?; + ret_type.hir_fmt(f, &data.store)?; + } + } + } + + // Write where clauses + let has_written_where = write_where_clause(GenericDefId::FunctionId(func_id), f)?; + Ok(has_written_where) +} + +fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Result { let db = f.db; f.write_str("impl")?; - let def_id = GenericDefId::ImplId(impl_.id); + let def_id = GenericDefId::ImplId(impl_); write_generic_params(def_id, f)?; - let impl_data = db.impl_signature(impl_.id); + let impl_data = db.impl_signature(impl_); if let Some(target_trait) = &impl_data.target_trait { f.write_char(' ')?; hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?; @@ -200,14 +267,28 @@ fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result } f.write_char(' ')?; - impl_.self_ty(db).hir_fmt(f)?; + Impl::from(impl_).self_ty(db).hir_fmt(f)?; Ok(()) } impl<'db> HirDisplay<'db> for SelfParam { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - let data = f.db.function_signature(self.func); + let func = match self.func.id { + AnyFunctionId::FunctionId(id) => id, + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { + BuiltinDeriveImplMethod::clone + | BuiltinDeriveImplMethod::fmt + | BuiltinDeriveImplMethod::hash + | BuiltinDeriveImplMethod::cmp + | BuiltinDeriveImplMethod::partial_cmp + | BuiltinDeriveImplMethod::eq => return f.write_str("&self"), + BuiltinDeriveImplMethod::default => { + unreachable!("this trait method does not have a self param") + } + }, + }; + let data = f.db.function_signature(func); let param = *data.params.first().unwrap(); match &data.store[param] { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), @@ -553,6 +634,18 @@ impl<'db> HirDisplay<'db> for ConstParam { } fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { + write_generic_params_or_args(def, f, true) +} + +fn write_generic_args<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { + write_generic_params_or_args(def, f, false) +} + +fn write_generic_params_or_args<'db>( + def: GenericDefId, + f: &mut HirFormatter<'_, 'db>, + include_defaults: bool, +) -> Result { let (params, store) = f.db.generic_params_and_store(def); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) @@ -587,7 +680,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) - } delim(f)?; write!(f, "{}", name.display(f.db, f.edition()))?; - if let Some(default) = &ty.default { + if include_defaults && let Some(default) = &ty.default { f.write_str(" = ")?; default.hir_fmt(f, &store)?; } @@ -597,7 +690,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) - write!(f, "const {}: ", name.display(f.db, f.edition()))?; c.ty.hir_fmt(f, &store)?; - if let Some(default) = &c.default { + if include_defaults && let Some(default) = &c.default { f.write_str(" = ")?; default.hir_fmt(f, &store)?; } @@ -746,7 +839,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> { impl<'db> HirDisplay<'db> for Trait { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { // FIXME(trait-alias) needs special handling to print the equal sign - write_trait_header(self, f)?; + write_trait_header(*self, f)?; let def_id = GenericDefId::TraitId(self.id); let has_where_clause = write_where_clause(def_id, f)?; @@ -783,7 +876,7 @@ impl<'db> HirDisplay<'db> for Trait { } } -fn write_trait_header<'db>(trait_: &Trait, f: &mut HirFormatter<'_, 'db>) -> Result { +fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; let data = f.db.trait_signature(trait_.id); if data.flags.contains(TraitFlags::UNSAFE) { diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index bc025c5ef5..fc20f4b46b 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -4,14 +4,15 @@ //! are splitting the hir. use hir_def::{ - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, - ModuleDefId, VariantId, + AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, + GenericParamId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, }; +use hir_ty::next_solver::AnyImplId; use crate::{ - Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, ItemInNs, Label, - Local, ModuleDef, Variant, VariantDef, + Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, + ItemInNs, Label, Local, ModuleDef, Variant, VariantDef, }; macro_rules! from_id { @@ -39,8 +40,8 @@ from_id![ (hir_def::TraitId, crate::Trait), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), - (hir_def::FunctionId, crate::Function), - (hir_def::ImplId, crate::Impl), + (crate::AnyFunctionId, crate::Function), + (hir_ty::next_solver::AnyImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), (hir_def::TypeParamId, crate::TypeParam), (hir_def::ConstParamId, crate::ConstParam), @@ -119,11 +120,15 @@ impl From for ModuleDef { } } -impl From for ModuleDefId { - fn from(id: ModuleDef) -> Self { - match id { +impl TryFrom for ModuleDefId { + type Error = (); + fn try_from(id: ModuleDef) -> Result { + Ok(match id { ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()), - ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()), + ModuleDef::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()), + }, ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()), ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()), ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), @@ -132,18 +137,22 @@ impl From for ModuleDefId { ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()), ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()), ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()), - } + }) } } -impl From for DefWithBodyId { - fn from(def: DefWithBody) -> Self { - match def { - DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id), +impl TryFrom for DefWithBodyId { + type Error = (); + fn try_from(def: DefWithBody) -> Result { + Ok(match def { + DefWithBody::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()), + }, DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), - } + }) } } @@ -168,17 +177,11 @@ impl From for AssocItem { } } -impl From for GenericDefId { - fn from(def: GenericDef) -> Self { - match def { - GenericDef::Function(it) => GenericDefId::FunctionId(it.id), - GenericDef::Adt(it) => GenericDefId::AdtId(it.into()), - GenericDef::Trait(it) => GenericDefId::TraitId(it.id), - GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), - GenericDef::Impl(it) => GenericDefId::ImplId(it.id), - GenericDef::Const(it) => GenericDefId::ConstId(it.id), - GenericDef::Static(it) => GenericDefId::StaticId(it.id), - } +impl TryFrom for GenericDefId { + type Error = (); + + fn try_from(def: GenericDef) -> Result { + def.id().ok_or(()) } } @@ -238,13 +241,17 @@ impl From for Field { } } -impl From for GenericDefId { - fn from(item: AssocItem) -> Self { - match item { - AssocItem::Function(f) => f.id.into(), +impl TryFrom for GenericDefId { + type Error = (); + fn try_from(item: AssocItem) -> Result { + Ok(match item { + AssocItem::Function(f) => match f.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()), + }, AssocItem::Const(c) => c.id.into(), AssocItem::TypeAlias(t) => t.id.into(), - } + }) } } @@ -270,13 +277,14 @@ impl From for ItemInNs { } } -impl From for hir_def::item_scope::ItemInNs { - fn from(it: ItemInNs) -> Self { - match it { - ItemInNs::Types(it) => Self::Types(it.into()), - ItemInNs::Values(it) => Self::Values(it.into()), +impl TryFrom for hir_def::item_scope::ItemInNs { + type Error = (); + fn try_from(it: ItemInNs) -> Result { + Ok(match it { + ItemInNs::Types(it) => Self::Types(it.try_into()?), + ItemInNs::Values(it) => Self::Values(it.try_into()?), ItemInNs::Macros(it) => Self::Macros(it.into()), - } + }) } } @@ -291,3 +299,21 @@ impl From for hir_def::builtin_type::BuiltinType { it.inner } } + +impl From for crate::Impl { + fn from(value: hir_def::ImplId) -> Self { + crate::Impl { id: AnyImplId::ImplId(value) } + } +} + +impl From for crate::Impl { + fn from(value: BuiltinDeriveImplId) -> Self { + crate::Impl { id: AnyImplId::BuiltinDeriveImplId(value) } + } +} + +impl From for crate::Function { + fn from(value: hir_def::FunctionId) -> Self { + crate::Function { id: AnyFunctionId::FunctionId(value) } + } +} diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 1aa7994001..09c5b1cca7 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -7,18 +7,18 @@ use hir_def::{ src::{HasChildSource, HasSource as _}, }; use hir_expand::{EditionedFileId, HirFileId, InFile}; -use hir_ty::db::InternedClosure; -use syntax::ast; +use hir_ty::{db::InternedClosure, next_solver::AnyImplId}; +use syntax::{AstNode, ast}; use tt::TextRange; use crate::{ - Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, + Adt, AnyFunctionId, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase, }; -pub trait HasSource { - type Ast; +pub trait HasSource: Sized { + type Ast: AstNode; /// Fetches the definition's source node. /// Using [`crate::SemanticsImpl::source`] is preferred when working with [`crate::Semantics`], /// as that caches the parsed file in the semantics' cache. @@ -27,6 +27,20 @@ pub trait HasSource { /// But we made this method `Option` to support rlib in the future /// by fn source(self, db: &dyn HirDatabase) -> Option>; + + /// Fetches the source node, along with its full range. + /// + /// The reason for the separate existence of this method is that some things, notably builtin derive impls, + /// do not really have a source node, at least not of the correct type. But we still can trace them + /// to source code (the derive producing them). So this method will return the range if it is supported, + /// and if the node is supported too it will return it as well. + fn source_with_range( + self, + db: &dyn HirDatabase, + ) -> Option)>> { + let source = self.source(db)?; + Some(source.map(|node| (node.syntax().text_range(), Some(node)))) + } } /// NB: Module is !HasSource, because it has two source nodes at the same time: @@ -146,7 +160,30 @@ impl HasSource for Variant { impl HasSource for Function { type Ast = ast::Fn; fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db).source(db)) + match self.id { + AnyFunctionId::FunctionId(id) => Some(id.loc(db).source(db)), + // When calling `source()`, we use the trait method source, but when calling `source_with_range()`, + // we return `None` as the syntax node source. This is relying on the assumption that if you are calling + // `source_with_range()` (e.g. in navigation) you're prepared to deal with no source node, while if + // you call `source()` maybe you don't - therefore we fall back to the trait method, to not lose features. + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => method + .trait_method(db, impl_) + .and_then(|trait_method| Function::from(trait_method).source(db)), + } + } + + fn source_with_range( + self, + db: &dyn HirDatabase, + ) -> Option)>> { + match self.id { + AnyFunctionId::FunctionId(id) => Some( + id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))), + ), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + Some(impl_.loc(db).source(db).map(|range| (range, None))) + } + } } } impl HasSource for Const { @@ -190,7 +227,24 @@ impl HasSource for Macro { impl HasSource for Impl { type Ast = ast::Impl; fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db).source(db)) + match self.id { + AnyImplId::ImplId(id) => Some(id.loc(db).source(db)), + AnyImplId::BuiltinDeriveImplId(_) => None, + } + } + + fn source_with_range( + self, + db: &dyn HirDatabase, + ) -> Option)>> { + match self.id { + AnyImplId::ImplId(id) => Some( + id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))), + ), + AnyImplId::BuiltinDeriveImplId(impl_) => { + Some(impl_.loc(db).source(db).map(|range| (range, None))) + } + } } } @@ -224,7 +278,7 @@ impl HasSource for Param<'_> { fn source(self, db: &dyn HirDatabase) -> Option> { match self.func { Callee::Def(CallableDefId::FunctionId(func)) => { - let InFile { file_id, value } = Function { id: func }.source(db)?; + let InFile { file_id, value } = Function::from(func).source(db)?; let params = value.param_list()?; if let Some(self_param) = params.self_param() { if let Some(idx) = self.idx.checked_sub(1) { @@ -261,7 +315,7 @@ impl HasSource for SelfParam { type Ast = ast::SelfParam; fn source(self, db: &dyn HirDatabase) -> Option> { - let InFile { file_id, value } = Function::from(self.func).source(db)?; + let InFile { file_id, value } = self.func.source(db)?; value .param_list() .and_then(|params| params.self_param()) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9fc29de4a1..6a19603923 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -48,12 +48,13 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, - HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, - MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UnionId, + AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, + DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, + MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, attrs::AttrFlags, + builtin_derive::BuiltinDeriveImplMethod, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, @@ -73,7 +74,8 @@ use hir_def::{ visibility::visibility_from_ast, }; use hir_expand::{ - AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind, + AstId, MacroCallKind, RenderedExpandError, ValueResult, builtin::BuiltinDeriveExpander, + proc_macro::ProcMacroKind, }; use hir_ty::{ GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic, @@ -88,8 +90,9 @@ use hir_ty::{ }, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, + AliasTy, AnyImplId, ClauseKind, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion, + ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Region, + RegionKind, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, traits::{self, is_inherent_impl_coherent, structurally_normalize_ty}, @@ -97,7 +100,8 @@ use hir_ty::{ use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, fast_reject, + AliasTyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitor, fast_reject, inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _}, }; use smallvec::SmallVec; @@ -105,7 +109,7 @@ use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, - ast::{self, HasName, HasVisibility as _}, + ast::{self, HasName as _, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -440,7 +444,10 @@ impl ModuleDef { Adt::Union(it) => it.id.into(), }, ModuleDef::Trait(it) => it.id.into(), - ModuleDef::Function(it) => it.id.into(), + ModuleDef::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Vec::new(), + }, ModuleDef::TypeAlias(it) => it.id.into(), ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), @@ -504,7 +511,7 @@ impl ModuleDef { pub fn attrs(&self, db: &dyn HirDatabase) -> Option { Some(match self { ModuleDef::Module(it) => it.attrs(db), - ModuleDef::Function(it) => it.attrs(db), + ModuleDef::Function(it) => HasAttrs::attrs(*it, db), ModuleDef::Adt(it) => it.attrs(db), ModuleDef::Variant(it) => it.attrs(db), ModuleDef::Const(it) => it.attrs(db), @@ -772,8 +779,11 @@ impl Module { for impl_def in self.impl_defs(db) { GenericDef::Impl(impl_def).diagnostics(db, acc); - let loc = impl_def.id.lookup(db); - let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id); + let AnyImplId::ImplId(impl_id) = impl_def.id else { + continue; + }; + let loc = impl_id.lookup(db); + let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id); expr_store_diagnostics(db, acc, &source_map); let file_id = loc.id.file_id; @@ -789,12 +799,12 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); - for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { + for diag in impl_id.impl_items_with_diagnostics(db).1.iter() { emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); } if impl_signature.target_trait.is_none() - && !is_inherent_impl_coherent(db, def_map, impl_def.id) + && !is_inherent_impl_coherent(db, def_map, impl_id) { acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } @@ -822,7 +832,7 @@ impl Module { if drop_trait != trait_.into() { return None; } - let parent = impl_def.id.into(); + let parent = impl_id.into(); let (lifetimes_attrs, type_and_consts_attrs) = AttrFlags::query_generic_params(db, parent); let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE)) @@ -851,7 +861,7 @@ impl Module { AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), }); - impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned()); + impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned()); let redundant = impl_assoc_items_scratch .iter() @@ -883,11 +893,11 @@ impl Module { .collect(); if !missing.is_empty() { - let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity(); + let self_ty = db.impl_self_ty(impl_id).instantiate_identity(); let self_ty = structurally_normalize_ty( &infcx, self_ty, - db.trait_environment(impl_def.id.into()), + db.trait_environment(impl_id.into()), ); let self_ty_is_guaranteed_unsized = matches!( self_ty.kind(), @@ -896,7 +906,13 @@ impl Module { if self_ty_is_guaranteed_unsized { missing.retain(|(_, assoc_item)| { let assoc_item = match *assoc_item { - AssocItem::Function(it) => it.id.into(), + AssocItem::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + never!("should not have an `AnyFunctionId::BuiltinDeriveImplMethod` here"); + return false; + }, + }, AssocItem::Const(it) => it.id.into(), AssocItem::TypeAlias(it) => it.id.into(), }; @@ -918,20 +934,15 @@ impl Module { impl_assoc_items_scratch.clear(); } + push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map); push_ty_diagnostics( db, acc, - db.impl_self_ty_with_diagnostics(impl_def.id).1, - &source_map, - ); - push_ty_diagnostics( - db, - acc, - db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1), &source_map, ); - for &(_, item) in impl_def.id.impl_items(db).items.iter() { + for &(_, item) in impl_id.impl_items(db).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } } @@ -955,7 +966,8 @@ impl Module { pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec { let def_map = self.id.def_map(db); - def_map[self.id].scope.impls().map(Impl::from).collect() + let scope = &def_map[self.id].scope; + scope.impls().map(Impl::from).chain(scope.builtin_derive_impls().map(Impl::from)).collect() } /// Finds a path that can be used to refer to the given item from within @@ -968,7 +980,7 @@ impl Module { ) -> Option { hir_def::find_path::find_path( db, - item.into().into(), + item.into().try_into().ok()?, self.into(), PrefixKind::Plain, false, @@ -985,7 +997,14 @@ impl Module { prefix_kind: PrefixKind, cfg: FindPathConfig, ) -> Option { - hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg) + hir_def::find_path::find_path( + db, + item.into().try_into().ok()?, + self.into(), + prefix_kind, + true, + cfg, + ) } #[inline] @@ -1863,9 +1882,9 @@ impl VariantDef { pub fn name(&self, db: &dyn HirDatabase) -> Name { match self { - VariantDef::Struct(s) => s.name(db), - VariantDef::Union(u) => u.name(db), - VariantDef::Variant(e) => e.name(db), + VariantDef::Struct(s) => (*s).name(db), + VariantDef::Union(u) => (*u).name(db), + VariantDef::Variant(e) => (*e).name(db), } } } @@ -1909,24 +1928,33 @@ impl DefWithBody { } } - fn id(&self) -> DefWithBodyId { - match self { - DefWithBody::Function(it) => it.id.into(), + fn id(&self) -> Option { + Some(match self { + DefWithBody::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None, + }, DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), - } + }) } /// A textual representation of the HIR of this def's body for debugging purposes. pub fn debug_hir(self, db: &dyn HirDatabase) -> String { - let body = db.body(self.id()); - body.pretty_print(db, self.id(), Edition::CURRENT) + let Some(id) = self.id() else { + return String::new(); + }; + let body = db.body(id); + body.pretty_print(db, id, Edition::CURRENT) } /// A textual representation of the MIR of this def's body for debugging purposes. pub fn debug_mir(self, db: &dyn HirDatabase) -> String { - let body = db.mir_body(self.id()); + let Some(id) = self.id() else { + return String::new(); + }; + let body = db.mir_body(id); match body { Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)), Err(e) => format!("error:\n{e:?}"), @@ -1939,11 +1967,17 @@ impl DefWithBody { acc: &mut Vec>, style_lints: bool, ) { + let Ok(id) = self.try_into() else { + return; + }; let krate = self.module(db).id.krate(db); - let (body, source_map) = db.body_with_source_map(self.into()); + let (body, source_map) = db.body_with_source_map(id); let sig_source_map = match self { - DefWithBody::Function(id) => db.function_signature_with_source_map(id.into()).1, + DefWithBody::Function(id) => match id.id { + AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1, + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return, + }, DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1, DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1, DefWithBody::Variant(variant) => { @@ -1958,11 +1992,11 @@ impl DefWithBody { expr_store_diagnostics(db, acc, &source_map); - let infer = InferenceResult::for_body(db, self.into()); + let infer = InferenceResult::for_body(db, id); for d in infer.diagnostics() { acc.extend(AnyDiagnostic::inference_diagnostic( db, - self.into(), + id, d, &source_map, &sig_source_map, @@ -1989,14 +2023,14 @@ impl DefWithBody { acc.push( TypeMismatch { expr_or_pat, - expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.as_ref()), - actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.as_ref()), + expected: Type::new(db, id, mismatch.expected.as_ref()), + actual: Type::new(db, id, mismatch.actual.as_ref()), } .into(), ); } - let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, self.into()); + let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, id); for (node, reason) in missing_unsafe.unsafe_exprs { match source_map.expr_or_pat_syntax(node) { Ok(node) => acc.push( @@ -2031,7 +2065,7 @@ impl DefWithBody { } } - if let Ok(borrowck_results) = db.borrowck(self.into()) { + if let Ok(borrowck_results) = db.borrowck(id) { for borrowck_result in borrowck_results.iter() { let mir_body = &borrowck_result.mir_body; for moof in &borrowck_result.moved_out_of_ref { @@ -2088,7 +2122,7 @@ impl DefWithBody { { need_mut = &mir::MutabilityReason::Not; } - let local = Local { parent: self.into(), binding_id }; + let local = Local { parent: id, binding_id }; let is_mut = body[binding_id].mode == BindingAnnotation::Mutable; match (need_mut, is_mut) { @@ -2144,17 +2178,11 @@ impl DefWithBody { } } - for diagnostic in BodyValidationDiagnostic::collect(db, self.into(), style_lints) { + for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) { acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); } - let def: ModuleDef = match self { - DefWithBody::Function(it) => it.into(), - DefWithBody::Static(it) => it.into(), - DefWithBody::Const(it) => it.into(), - DefWithBody::Variant(it) => it.into(), - }; - for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) { + for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) { acc.push(diag.into()) } } @@ -2192,45 +2220,181 @@ fn expr_store_diagnostics<'db>( .macro_calls() .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc)); } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum AnyFunctionId { + FunctionId(FunctionId), + BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Function { - pub(crate) id: FunctionId, + pub(crate) id: AnyFunctionId, +} + +impl fmt::Debug for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.id, f) + } } impl Function { pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.module(db).into() + match self.id { + AnyFunctionId::FunctionId(id) => id.module(db).into(), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => impl_.module(db).into(), + } } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.function_signature(self.id).name.clone() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(), + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => { + Name::new_symbol_root(method.name()) + } + } } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_value_def(db, self.id) + match self.id { + AnyFunctionId::FunctionId(id) => Type::from_value_def(db, id), + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + // Get the type for the trait function, as we can't get the type for the impl function + // because it has not `CallableDefId`. + let krate = impl_.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let param_env = hir_ty::builtin_derive::param_env(interner, impl_); + let env = ParamEnvAndCrate { param_env, krate }; + let Some(trait_method) = method.trait_method(db, impl_) else { + return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + }; + Function::from(trait_method).ty(db) + } + } } pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - let interner = DbInterner::new_no_crate(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity(); - let ty = Ty::new_fn_ptr(interner, callable_sig); - Type::new_with_resolver_inner(db, &resolver, ty) + match self.id { + AnyFunctionId::FunctionId(id) => { + let resolver = id.resolver(db); + let interner = DbInterner::new_no_crate(db); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = db.callable_item_signature(id.into()).instantiate_identity(); + let ty = Ty::new_fn_ptr(interner, callable_sig); + Type::new_with_resolver_inner(db, &resolver, ty) + } + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + struct ParamsShifter<'db> { + interner: DbInterner<'db>, + shift_by: i32, + } + + impl<'db> TypeFolder> for ParamsShifter<'db> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + if let TyKind::Param(param) = ty.kind() { + Ty::new_param( + self.interner, + param.id, + param.index.checked_add_signed(self.shift_by).unwrap(), + ) + } else { + ty.super_fold_with(self) + } + } + + fn fold_const( + &mut self, + ct: hir_ty::next_solver::Const<'db>, + ) -> hir_ty::next_solver::Const<'db> { + if let ConstKind::Param(param) = ct.kind() { + hir_ty::next_solver::Const::new_param( + self.interner, + ParamConst { + id: param.id, + index: param.index.checked_add_signed(self.shift_by).unwrap(), + }, + ) + } else { + ct.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if let RegionKind::ReEarlyParam(param) = r.kind() { + Region::new_early_param( + self.interner, + EarlyParamRegion { + id: param.id, + index: param.index.checked_add_signed(self.shift_by).unwrap(), + }, + ) + } else { + r + } + } + } + + // Get the type for the trait function, as we can't get the type for the impl function + // because it has not `CallableDefId`. + let krate = impl_.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let param_env = hir_ty::builtin_derive::param_env(interner, impl_); + let env = ParamEnvAndCrate { param_env, krate }; + let Some(trait_method) = method.trait_method(db, impl_) else { + return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + }; + // The procedure works as follows: the method may have additional generic parameters (e.g. `Hash::hash()`), + // and we want them to be params of the impl method as well. So we start with the trait method identity + // args and extract from them the trait method own args. In parallel, we retrieve the impl trait ref. + // Now we can put our args as [...impl_trait_ref.args, ...trait_method_own_args], but we have one problem: + // the args in `trait_method_own_args` use indices appropriate for the trait method, which are not necessarily + // good for the impl method. So we shift them by `impl_generics_len - trait_generics_len`, which is essentially + // `impl_generics_len - impl_trait_ref.args.len()`. + let trait_method_fn_ptr = Ty::new_fn_ptr( + interner, + db.callable_item_signature(trait_method.into()).instantiate_identity(), + ); + let impl_trait_ref = + hir_ty::builtin_derive::impl_trait(interner, impl_).instantiate_identity(); + let trait_method_args = + GenericArgs::identity_for_item(interner, trait_method.into()); + let trait_method_own_args = GenericArgs::new_from_iter( + interner, + trait_method_args.iter().skip(impl_trait_ref.args.len()), + ); + let impl_params_count = hir_ty::builtin_derive::generic_params_count(db, impl_); + let shift_args_by = impl_params_count as i32 - impl_trait_ref.args.len() as i32; + let shifted_trait_method_own_args = trait_method_own_args + .fold_with(&mut ParamsShifter { interner, shift_by: shift_args_by }); + let impl_method_args = GenericArgs::new_from_iter( + interner, + impl_trait_ref.args.iter().chain(shifted_trait_method_own_args), + ); + let impl_method_fn_ptr = + EarlyBinder::bind(trait_method_fn_ptr).instantiate(interner, impl_method_args); + Type { env, ty: impl_method_fn_ptr } + } + } + } + + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (ParamEnvAndCrate<'db>, PolyFnSig<'db>) { + let fn_ptr = self.fn_ptr_type(db); + let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.kind() else { + unreachable!(); + }; + (fn_ptr.env, sig_tys.with(hdr)) } // FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`? /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ty = db - .callable_item_signature(self.id.into()) - .instantiate_identity() - .skip_binder() - .output(); - Type::new_with_resolver_inner(db, &resolver, ty) + let (env, sig) = self.fn_sig(db); + Type { env, ty: sig.skip_binder().output() } } // FIXME: Find better API to also handle const generics @@ -2239,30 +2403,41 @@ impl Function { db: &'db dyn HirDatabase, generics: impl Iterator>, ) -> Type<'db> { - let resolver = self.id.resolver(db); + let ret_type = self.ret_type(db); let interner = DbInterner::new_no_crate(db); - let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); + let args = self.adapt_generic_args(interner, generics); + ret_type.derived(EarlyBinder::bind(ret_type.ty).instantiate(interner, args)) + } - let interner = DbInterner::new_no_crate(db); - let ty = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .output(); - Type::new_with_resolver_inner(db, &resolver, ty) + fn adapt_generic_args<'db>( + self, + interner: DbInterner<'db>, + generics: impl Iterator>, + ) -> GenericArgs<'db> { + let generics = generics.map(|ty| ty.ty); + match self.id { + AnyFunctionId::FunctionId(id) => generic_args_from_tys(interner, id.into(), generics), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + let impl_args = GenericArgs::identity_for_item(interner, impl_.into()); + GenericArgs::new_from_iter( + interner, + impl_args.iter().chain(generics.map(Into::into)), + ) + } + } } pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option> { + let AnyFunctionId::FunctionId(id) = self.id else { + return None; + }; if !self.is_async(db) { return None; } - let resolver = self.id.resolver(db); + let resolver = id.resolver(db); // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ret_ty = db - .callable_item_signature(self.id.into()) - .instantiate_identity() - .skip_binder() - .output(); + let ret_ty = + db.callable_item_signature(id.into()).instantiate_identity().skip_binder().output(); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { if let ClauseKind::Projection(projection) = pred.kind().skip_binder() && let Some(output_ty) = projection.term.as_type() @@ -2274,31 +2449,47 @@ impl Function { } pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).has_self_param() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(), + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { + BuiltinDeriveImplMethod::clone + | BuiltinDeriveImplMethod::fmt + | BuiltinDeriveImplMethod::hash + | BuiltinDeriveImplMethod::cmp + | BuiltinDeriveImplMethod::partial_cmp + | BuiltinDeriveImplMethod::eq => true, + BuiltinDeriveImplMethod::default => false, + }, + } } pub fn self_param(self, db: &dyn HirDatabase) -> Option { - self.has_self_param(db).then_some(SelfParam { func: self.id }) + self.has_self_param(db).then_some(SelfParam { func: self }) } pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { - let environment = param_env_from_has_crate(db, self.id); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); - callable_sig + let (env, sig) = self.fn_sig(db); + let func = match self.id { + AnyFunctionId::FunctionId(id) => Callee::Def(CallableDefId::FunctionId(id)), + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + Callee::BuiltinDeriveImplMethod { method, impl_ } + } + }; + sig.skip_binder() .inputs() .iter() .enumerate() - .map(|(idx, &ty)| { - let ty = Type { env: environment, ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } - }) + .map(|(idx, &ty)| Param { func: func.clone(), ty: Type { env, ty }, idx }) .collect() } pub fn num_params(self, db: &dyn HirDatabase) -> usize { - db.function_signature(self.id).params.len() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + self.fn_sig(db).1.skip_binder().inputs().len() + } + } } pub fn method_params(self, db: &dyn HirDatabase) -> Option>> { @@ -2307,21 +2498,11 @@ impl Function { } pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec> { - let environment = param_env_from_has_crate(db, self.id); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); - let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; - callable_sig - .inputs() - .iter() - .enumerate() - .skip(skip) - .map(|(idx, &ty)| { - let ty = Type { env: environment, ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } - }) - .collect() + let mut params = self.assoc_fn_params(db); + if self.has_self_param(db) { + params.remove(0); + } + params } // FIXME: Find better API to also handle const generics @@ -2330,40 +2511,50 @@ impl Function { db: &'db dyn HirDatabase, generics: impl Iterator>, ) -> Vec> { - let environment = param_env_from_has_crate(db, self.id); let interner = DbInterner::new_no_crate(db); - let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate(interner, args).skip_binder(); - let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; - callable_sig - .inputs() - .iter() - .enumerate() - .skip(skip) - .map(|(idx, &ty)| { - let ty = Type { env: environment, ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } + let args = self.adapt_generic_args(interner, generics); + let params = self.params_without_self(db); + params + .into_iter() + .map(|param| Param { + func: param.func, + idx: param.idx, + ty: Type { + env: param.ty.env, + ty: EarlyBinder::bind(param.ty.ty).instantiate(interner, args), + }, }) .collect() } pub fn is_const(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_const() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn is_async(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_async() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn is_varargs(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_varargs() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn extern_block(self, db: &dyn HirDatabase) -> Option { - match self.id.lookup(db).container { - ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }), - _ => None, + match self.id { + AnyFunctionId::FunctionId(id) => match id.lookup(db).container { + ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }), + _ => None, + }, + AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, } } @@ -2396,33 +2587,46 @@ impl Function { /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { - self.attrs(db).is_test() + self.attrs(db).contains(AttrFlags::IS_TEST) } /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { - self.exported_main(db) - || self.module(db).is_crate_root(db) && db.function_signature(self.id).name == sym::main + match self.id { + AnyFunctionId::FunctionId(id) => { + self.exported_main(db) + || self.module(db).is_crate_root(db) + && db.function_signature(id).name == sym::main + } + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } + } + + fn attrs(self, db: &dyn HirDatabase) -> AttrFlags { + match self.id { + AnyFunctionId::FunctionId(id) => AttrFlags::query(db, id.into()), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrFlags::empty(), + } } /// Is this a function with an `export_name` of `main`? pub fn exported_main(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_EXPORT_NAME_MAIN) + self.attrs(db).contains(AttrFlags::IS_EXPORT_NAME_MAIN) } /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_IGNORE) + self.attrs(db).contains(AttrFlags::IS_IGNORE) } /// Does this function have `#[bench]` attribute? pub fn is_bench(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_BENCH) + self.attrs(db).contains(AttrFlags::IS_BENCH) } /// Is this function marked as unstable with `#[feature]` attribute? pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + self.attrs(db).contains(AttrFlags::IS_UNSTABLE) } pub fn is_unsafe_to_call( @@ -2431,9 +2635,17 @@ impl Function { caller: Option, call_edition: Edition, ) -> bool { + let AnyFunctionId::FunctionId(id) = self.id else { + return false; + }; let (target_features, target_feature_is_safe_in_target) = caller .map(|caller| { - let target_features = hir_ty::TargetFeatures::from_fn(db, caller.id); + let target_features = match caller.id { + AnyFunctionId::FunctionId(id) => hir_ty::TargetFeatures::from_fn(db, id), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + hir_ty::TargetFeatures::default() + } + }; let target_feature_is_safe_in_target = match &caller.krate(db).id.workspace_data(db).target { Ok(target) => hir_ty::target_feature_is_safe_in_target(target), @@ -2447,7 +2659,7 @@ impl Function { matches!( hir_ty::is_fn_unsafe_to_call( db, - self.id, + id, &target_features, call_edition, target_feature_is_safe_in_target @@ -2460,12 +2672,18 @@ impl Function { /// /// This is false in the case of required (not provided) trait methods. pub fn has_body(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).has_body() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => true, + } } pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option { - let def_map = crate_def_map(db, HasModule::krate(&self.id, db)); - def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) + let AnyFunctionId::FunctionId(id) = self.id else { + return None; + }; + let def_map = crate_def_map(db, HasModule::krate(&id, db)); + def_map.fn_as_proc_macro(id).map(|id| Macro { id: id.into() }) } pub fn eval( @@ -2473,13 +2691,18 @@ impl Function { db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, ) -> 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(), + ))); + }; let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( - self.id.into(), + id.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment(self.id.into()), - krate: self.id.module(db).krate(db), + param_env: db.trait_environment(id.into()), + krate: id.module(db).krate(db), } .store(), )?; @@ -2596,36 +2819,47 @@ impl<'db> Param<'db> { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SelfParam { - func: FunctionId, + func: Function, } impl SelfParam { pub fn access(self, db: &dyn HirDatabase) -> Access { - let func_data = db.function_signature(self.func); - func_data - .params - .first() - .map(|¶m| match &func_data.store[param] { - TypeRef::Reference(ref_) => match ref_.mutability { - hir_def::type_ref::Mutability::Shared => Access::Shared, - hir_def::type_ref::Mutability::Mut => Access::Exclusive, - }, - _ => Access::Owned, - }) - .unwrap_or(Access::Owned) + match self.func.id { + AnyFunctionId::FunctionId(id) => { + let func_data = db.function_signature(id); + func_data + .params + .first() + .map(|¶m| match &func_data.store[param] { + TypeRef::Reference(ref_) => match ref_.mutability { + hir_def::type_ref::Mutability::Shared => Access::Shared, + hir_def::type_ref::Mutability::Mut => Access::Exclusive, + }, + _ => Access::Owned, + }) + .unwrap_or(Access::Owned) + } + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { + BuiltinDeriveImplMethod::clone + | BuiltinDeriveImplMethod::fmt + | BuiltinDeriveImplMethod::hash + | BuiltinDeriveImplMethod::cmp + | BuiltinDeriveImplMethod::partial_cmp + | BuiltinDeriveImplMethod::eq => Access::Shared, + BuiltinDeriveImplMethod::default => { + unreachable!("this function does not have a self param") + } + }, + } } pub fn parent_fn(&self) -> Function { - Function::from(self.func) + self.func } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); - let environment = param_env_from_has_crate(db, self.func); - let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0]; - Type { env: environment, ty } + let (env, sig) = self.func.fn_sig(db); + Type { env, ty: sig.skip_binder().inputs()[0] } } // FIXME: Find better API to also handle const generics @@ -2635,18 +2869,18 @@ impl SelfParam { generics: impl Iterator>, ) -> Type<'db> { let interner = DbInterner::new_no_crate(db); - let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty)); - let callable_sig = - db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); - let environment = param_env_from_has_crate(db, self.func); - let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0]; - Type { env: environment, ty } + let args = self.func.adapt_generic_args(interner, generics); + let Type { env, ty } = self.ty(db); + Type { env, ty: EarlyBinder::bind(ty).instantiate(interner, args) } } } impl HasVisibility for Function { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.assoc_visibility(self.id.into()) + match self.id { + AnyFunctionId::FunctionId(id) => db.assoc_visibility(id.into()), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => Visibility::Public, + } } } @@ -2870,7 +3104,7 @@ impl Trait { pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq) -> Option { self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it { - AssocItemId::FunctionId(id) => Some(Function { id }), + AssocItemId::FunctionId(id) => Some(id.into()), _ => None, }) } @@ -3151,15 +3385,15 @@ impl Macro { ) } - pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool { - match self.id { - MacroId::Macro2Id(it) => { - matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::MacroRulesId(it) => { - matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::ProcMacroId(_) => false, + pub fn builtin_derive_kind(&self, db: &dyn HirDatabase) -> Option { + let expander = match self.id { + MacroId::Macro2Id(it) => it.lookup(db).expander, + MacroId::MacroRulesId(it) => it.lookup(db).expander, + MacroId::ProcMacroId(_) => return None, + }; + match expander { + MacroExpander::BuiltInDerive(kind) => Some(BuiltinDeriveMacroKind(kind)), + _ => None, } } @@ -3197,6 +3431,9 @@ impl Macro { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct BuiltinDeriveMacroKind(BuiltinDeriveExpander); + impl HasVisibility for Macro { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { match self.id { @@ -3275,7 +3512,10 @@ pub trait AsExternAssocItem { impl AsExternAssocItem for Function { fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option { - as_extern_assoc_item(db, ExternAssocItem::Function, self.id) + let AnyFunctionId::FunctionId(id) = self.id else { + return None; + }; + as_extern_assoc_item(db, ExternAssocItem::Function, id) } } @@ -3303,7 +3543,7 @@ pub enum AssocItem { impl From for AssocItem { fn from(value: method_resolution::CandidateId) -> Self { match value { - method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(Function { id }), + method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(id.into()), method_resolution::CandidateId::ConstId(id) => AssocItem::Const(Const { id }), } } @@ -3321,7 +3561,10 @@ pub trait AsAssocItem { impl AsAssocItem for Function { fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { - as_assoc_item(db, AssocItem::Function, self.id) + match self.id { + AnyFunctionId::FunctionId(id) => as_assoc_item(db, AssocItem::Function, id), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => Some(AssocItem::Function(self)), + } } } @@ -3450,7 +3693,14 @@ impl AssocItem { pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { let container = match self { - AssocItem::Function(it) => it.id.lookup(db).container, + AssocItem::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.lookup(db).container, + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + return AssocItemContainer::Impl(Impl { + id: AnyImplId::BuiltinDeriveImplId(impl_), + }); + } + }, AssocItem::Const(it) => it.id.lookup(db).container, AssocItem::TypeAlias(it) => it.id.lookup(db).container, }; @@ -3587,9 +3837,13 @@ impl_from!( impl GenericDef { pub fn params(self, db: &dyn HirDatabase) -> Vec { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| { - let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } }; + let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } }; match toc.split(db) { Either::Left(it) => GenericParam::ConstParam(it), Either::Right(it) => GenericParam::TypeParam(it), @@ -3603,39 +3857,51 @@ impl GenericDef { } pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); generics .iter_lt() - .map(|(local_id, _)| LifetimeParam { - id: LifetimeParamId { parent: self.into(), local_id }, - }) + .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } }) .collect() } pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); generics .iter_type_or_consts() .map(|(local_id, _)| TypeOrConstParam { - id: TypeOrConstParamId { parent: self.into(), local_id }, + id: TypeOrConstParamId { parent: id, local_id }, }) .collect() } - fn id(self) -> GenericDefId { - match self { - GenericDef::Function(it) => it.id.into(), + fn id(self) -> Option { + Some(match self { + GenericDef::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None, + }, GenericDef::Adt(it) => it.into(), GenericDef::Trait(it) => it.id.into(), GenericDef::TypeAlias(it) => it.id.into(), - GenericDef::Impl(it) => it.id.into(), + GenericDef::Impl(it) => match it.id { + AnyImplId::ImplId(it) => it.into(), + AnyImplId::BuiltinDeriveImplId(_) => return None, + }, GenericDef::Const(it) => it.id.into(), GenericDef::Static(it) => it.id.into(), - } + }) } pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec>) { - let def = self.id(); + let Some(def) = self.id() else { return }; let generics = db.generic_params(def); @@ -3708,6 +3974,17 @@ impl<'db> GenericSubstitution<'db> { Self { def, subst, env } } + fn new_from_fn( + def: Function, + subst: GenericArgs<'db>, + env: ParamEnvAndCrate<'db>, + ) -> Option { + match def.id { + AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, env)), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, + } + } + pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { let container = match self.def { GenericDefId::ConstId(id) => Some(id.lookup(db).container), @@ -3820,7 +4097,9 @@ impl Local { pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { match self.parent { - DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }), + DefWithBodyId::FunctionId(func) if self.is_self(db) => { + Some(SelfParam { func: func.into() }) + } _ => None, } } @@ -4308,7 +4587,7 @@ impl TypeOrConstParam { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Impl { - pub(crate) id: ImplId, + pub(crate) id: AnyImplId, } impl Impl { @@ -4320,6 +4599,7 @@ impl Impl { fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec) { for (_, module) in def_map.modules() { result.extend(module.scope.impls().map(Impl::from)); + result.extend(module.scope.builtin_derive_impls().map(Impl::from)); for unnamed_const in module.scope.unnamed_consts() { for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) { @@ -4331,7 +4611,7 @@ impl Impl { } pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec { - module.id.def_map(db)[module.id].scope.impls().map(Into::into).collect() + module.impl_defs(db) } /// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type", @@ -4347,20 +4627,19 @@ impl Impl { else { return Vec::new(); }; - let mut extend_with_impls = - |impls: &[ImplId]| result.extend(impls.iter().copied().map(Impl::from)); - method_resolution::with_incoherent_inherent_impls( - db, - env.krate, - &simplified_ty, - &mut extend_with_impls, - ); + let mut extend_with_impls = |impls: Either<&[ImplId], &[BuiltinDeriveImplId]>| match impls { + Either::Left(impls) => result.extend(impls.iter().copied().map(Impl::from)), + Either::Right(impls) => result.extend(impls.iter().copied().map(Impl::from)), + }; + method_resolution::with_incoherent_inherent_impls(db, env.krate, &simplified_ty, |impls| { + extend_with_impls(Either::Left(impls)) + }); if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) { InherentImpls::for_each_crate_and_block( db, module.krate(db), module.block(db), - &mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)), + &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))), ); std::iter::successors(module.block(db), |block| block.loc(db).module.block(db)) .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) @@ -4382,7 +4661,10 @@ impl Impl { let module = trait_.module(db).id; let mut all = Vec::new(); let mut handle_impls = |impls: &TraitImpls| { - impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from))); + 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)), + }); }; for krate in module.krate(db).transitive_rev_deps(db) { handle_impls(TraitImpls::for_crate(db, krate)); @@ -4396,75 +4678,118 @@ impl Impl { } pub fn trait_(self, db: &dyn HirDatabase) -> Option { - let trait_ref = db.impl_trait(self.id)?; - let id = trait_ref.skip_binder().def_id; - Some(Trait { id: id.0 }) + match self.id { + AnyImplId::ImplId(id) => { + let trait_ref = db.impl_trait(id)?; + let id = trait_ref.skip_binder().def_id; + Some(Trait { id: id.0 }) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let lang_items = hir_def::lang_item::lang_items(db, loc.adt.module(db).krate(db)); + loc.trait_.get_id(lang_items).map(Trait::from) + } + } } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { - let trait_ref = db.impl_trait(self.id)?.instantiate_identity(); - let resolver = self.id.resolver(db); - Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) + match self.id { + AnyImplId::ImplId(id) => { + let trait_ref = db.impl_trait(id)?.instantiate_identity(); + let resolver = id.resolver(db); + Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let krate = loc.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let env = ParamEnvAndCrate { + param_env: hir_ty::builtin_derive::param_env(interner, id), + krate, + }; + let trait_ref = + hir_ty::builtin_derive::impl_trait(interner, id).instantiate_identity(); + Some(TraitRef { env, trait_ref }) + } + } } pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ty = db.impl_self_ty(self.id).instantiate_identity(); - Type::new_with_resolver_inner(db, &resolver, ty) + match self.id { + AnyImplId::ImplId(id) => { + let resolver = id.resolver(db); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let ty = db.impl_self_ty(id).instantiate_identity(); + Type::new_with_resolver_inner(db, &resolver, ty) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let krate = loc.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let env = ParamEnvAndCrate { + param_env: hir_ty::builtin_derive::param_env(interner, id), + krate, + }; + let ty = hir_ty::builtin_derive::impl_trait(interner, id) + .instantiate_identity() + .self_ty(); + Type { env, ty } + } + } } pub fn items(self, db: &dyn HirDatabase) -> Vec { - self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() + match self.id { + AnyImplId::ImplId(id) => { + id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() + } + AnyImplId::BuiltinDeriveImplId(impl_) => impl_ + .loc(db) + .trait_ + .all_methods() + .iter() + .map(|&method| { + AssocItem::Function(Function { + id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ }, + }) + }) + .collect(), + } } pub fn is_negative(self, db: &dyn HirDatabase) -> bool { - db.impl_signature(self.id).flags.contains(ImplFlags::NEGATIVE) + match self.id { + AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE), + AnyImplId::BuiltinDeriveImplId(_) => false, + } } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { - db.impl_signature(self.id).flags.contains(ImplFlags::UNSAFE) + match self.id { + AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE), + AnyImplId::BuiltinDeriveImplId(_) => false, + } } pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.lookup(db).container.into() - } - - pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option> { - let src = self.source(db)?; - - let macro_file = src.file_id.macro_file()?; - let loc = macro_file.lookup(db); - let (derive_attr, derive_index) = match loc.kind { - MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { - let module_id = self.id.lookup(db).container; - ( - module_id.def_map(db)[module_id] - .scope - .derive_macro_invoc(ast_id, derive_attr_index)?, - derive_index, - ) - } - _ => return None, - }; - let path = db - .parse_macro_expansion(derive_attr) - .value - .0 - .syntax_node() - .children() - .nth(derive_index as usize) - .and_then(::cast) - .and_then(|it| it.path())?; - Some(InMacroFile { file_id: derive_attr, value: path }) + match self.id { + AnyImplId::ImplId(id) => id.module(db).into(), + AnyImplId::BuiltinDeriveImplId(id) => id.module(db).into(), + } } pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool { - check_orphan_rules(db, self.id) + match self.id { + AnyImplId::ImplId(id) => check_orphan_rules(db, id), + AnyImplId::BuiltinDeriveImplId(_) => true, + } } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice() + match self.id { + AnyImplId::ImplId(id) => id.impl_items(db).macro_calls.to_vec().into_boxed_slice(), + AnyImplId::BuiltinDeriveImplId(_) => Box::default(), + } } } @@ -5540,7 +5865,7 @@ impl<'db> Type<'db> { else { unreachable!("`Mode::MethodCall` can only return functions"); }; - let id = Function { id }; + let id = Function { id: AnyFunctionId::FunctionId(id) }; match candidate.kind { method_resolution::PickKind::InherentImplPick(_) | method_resolution::PickKind::ObjectPick(..) @@ -5564,7 +5889,7 @@ impl<'db> Type<'db> { else { unreachable!("`Mode::MethodCall` can only return functions"); }; - let id = Function { id }; + let id = Function { id: AnyFunctionId::FunctionId(id) }; match candidate.candidate.kind { method_resolution::CandidateKind::InherentImplCandidate { .. @@ -5919,6 +6244,7 @@ enum Callee<'db> { CoroutineClosure(InternedCoroutineId, GenericArgs<'db>), FnPtr, FnImpl(traits::FnTrait), + BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, } pub enum CallableKind<'db> { @@ -5934,6 +6260,9 @@ impl<'db> Callable<'db> { pub fn kind(&self) -> CallableKind<'db> { match self.callee { Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), + Callee::BuiltinDeriveImplMethod { method, impl_ } => CallableKind::Function(Function { + id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ }, + }), Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) @@ -5948,12 +6277,22 @@ impl<'db> Callable<'db> { Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_.into()), } } + + fn as_function(&self) -> Option { + match self.callee { + Callee::Def(CallableDefId::FunctionId(it)) => Some(it.into()), + Callee::BuiltinDeriveImplMethod { method, impl_ } => { + Some(Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }) + } + _ => None, + } + } + pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> { - let func = match self.callee { - Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it, - _ => return None, - }; - let func = Function { id: func }; + if !self.is_bound_method { + return None; + } + let func = self.as_function()?; Some(( func.self_param(db)?, self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]), @@ -6350,7 +6689,12 @@ impl HasContainer for Module { impl HasContainer for Function { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { - container_id_to_hir(self.id.lookup(db).container) + match self.id { + AnyFunctionId::FunctionId(id) => container_id_to_hir(id.lookup(db).container), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + ItemContainer::Impl(Impl { id: AnyImplId::BuiltinDeriveImplId(impl_) }) + } + } } } @@ -6402,11 +6746,79 @@ impl HasContainer for ExternBlock { } } +pub trait HasName { + fn name(&self, db: &dyn HirDatabase) -> Option; +} + +macro_rules! impl_has_name { + ( $( $ty:ident ),* $(,)? ) => { + $( + impl HasName for $ty { + fn name(&self, db: &dyn HirDatabase) -> Option { + (*self).name(db).into() + } + } + )* + }; +} + +impl_has_name!( + ModuleDef, + Module, + Field, + Struct, + Union, + Enum, + Variant, + Adt, + VariantDef, + DefWithBody, + Function, + ExternCrateDecl, + Const, + Static, + Trait, + TypeAlias, + Macro, + ExternAssocItem, + AssocItem, + Local, + DeriveHelper, + ToolModule, + Label, + GenericParam, + TypeParam, + LifetimeParam, + ConstParam, + TypeOrConstParam, + InlineAsmOperand, +); + +macro_rules! impl_has_name_no_db { + ( $( $ty:ident ),* $(,)? ) => { + $( + impl HasName for $ty { + fn name(&self, _db: &dyn HirDatabase) -> Option { + (*self).name().into() + } + } + )* + }; +} + +impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr); + +impl HasName for Param<'_> { + fn name(&self, db: &dyn HirDatabase) -> Option { + self.name(db) + } +} + fn container_id_to_hir(c: ItemContainerId) -> ItemContainer { match c { ItemContainerId::ExternBlockId(id) => ItemContainer::ExternBlock(ExternBlock { id }), ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }), - ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }), + ItemContainerId::ImplId(id) => ItemContainer::Impl(id.into()), ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }), } } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index fcb97ab34e..485011c38d 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -13,7 +13,7 @@ use std::{ use base_db::FxIndexSet; use either::Either; use hir_def::{ - DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId, + DefWithBodyId, MacroId, StructId, TraitId, VariantId, attrs::parse_extra_crate_attrs, expr_store::{Body, ExprOrPatSource, HygieneId, path::Path}, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, @@ -34,7 +34,7 @@ use hir_ty::{ diagnostics::{unsafe_operations, unsafe_operations_for_body}, infer_query_with_inspect, next_solver::{ - DbInterner, Span, + AnyImplId, DbInterner, Span, format_proof_tree::{ProofTreeData, dump_proof_tree_structured}, }, }; @@ -53,11 +53,11 @@ use syntax::{ }; use crate::{ - Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, - Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource, Impl, - InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, - Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TupleField, Type, - TypeAlias, TypeParam, Union, Variant, VariantDef, + Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, + ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, + HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, + Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, + TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{SourceAnalyzer, resolve_hir_path}, @@ -106,7 +106,10 @@ impl PathResolution { | PathResolution::DeriveHelper(_) | PathResolution::ConstParam(_) => None, PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), - PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), + PathResolution::SelfType(impl_def) => match impl_def.id { + AnyImplId::ImplId(id) => Some(TypeNs::SelfType(id)), + AnyImplId::BuiltinDeriveImplId(_) => None, + }, } } } @@ -345,23 +348,23 @@ impl Semantics<'_, DB> { } pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { - self.imp.resolve_await_to_poll(await_expr).map(Function::from) + self.imp.resolve_await_to_poll(await_expr) } pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { - self.imp.resolve_prefix_expr(prefix_expr).map(Function::from) + self.imp.resolve_prefix_expr(prefix_expr) } pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { - self.imp.resolve_index_expr(index_expr).map(Function::from) + self.imp.resolve_index_expr(index_expr) } pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { - self.imp.resolve_bin_expr(bin_expr).map(Function::from) + self.imp.resolve_bin_expr(bin_expr) } pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { - self.imp.resolve_try_expr(try_expr).map(Function::from) + self.imp.resolve_try_expr(try_expr) } pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { @@ -1749,6 +1752,7 @@ impl<'db> SemanticsImpl<'db> { func: Function, subst: impl IntoIterator>, ) -> Option { + let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) }; let interner = DbInterner::new_no_crate(self.db); let mut subst = subst.into_iter(); let substs = @@ -1757,7 +1761,12 @@ impl<'db> SemanticsImpl<'db> { subst.next().expect("too few subst").ty.into() }); assert!(subst.next().is_none(), "too many subst"); - Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into()) + Some(match self.db.lookup_impl_method(env.env, func, substs).0 { + Either::Left(it) => it.into(), + Either::Right((impl_, method)) => { + Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } } + } + }) } fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option { @@ -1768,23 +1777,23 @@ impl<'db> SemanticsImpl<'db> { self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr) } - fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) } - fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) } - fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) } - fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) } - fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) } @@ -1861,7 +1870,9 @@ impl<'db> SemanticsImpl<'db> { } pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { - let def = DefWithBodyId::from(def); + let Ok(def) = DefWithBodyId::try_from(def) else { + return FxHashSet::default(); + }; let (body, source_map) = self.db.body_with_source_map(def); let infer = InferenceResult::for_body(self.db, def); let mut res = FxHashSet::default(); @@ -1877,7 +1888,9 @@ impl<'db> SemanticsImpl<'db> { always!(block.unsafe_token().is_some()); let block = self.wrap_node_infile(ast::Expr::from(block)); let Some(def) = self.body_for(block.syntax()) else { return Vec::new() }; - let def = def.into(); + let Ok(def) = def.try_into() else { + return Vec::new(); + }; let (body, source_map) = self.db.body_with_source_map(def); let infer = InferenceResult::for_body(self.db, def); let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else { @@ -2023,16 +2036,22 @@ impl<'db> SemanticsImpl<'db> { } /// Search for a definition's source and cache its syntax tree - pub fn source(&self, def: Def) -> Option> - where - Def::Ast: AstNode, - { + pub fn source(&self, def: Def) -> Option> { // FIXME: source call should go through the parse cache let res = def.source(self.db)?; self.cache(find_root(res.value.syntax()), res.file_id); Some(res) } + pub fn source_with_range( + &self, + def: Def, + ) -> Option)>> { + let res = def.source_with_range(self.db)?; + self.parse_or_expand(res.file_id); + Some(res) + } + pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option { let container = self.with_ctx(|ctx| ctx.find_container(node))?; @@ -2162,9 +2181,10 @@ impl<'db> SemanticsImpl<'db> { let def = match &enclosing_item { Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true, - Either::Left(ast::Item::Fn(it)) => { - self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId) - } + Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id { + AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, + })(), Either::Left(ast::Item::Const(it)) => { self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId) } @@ -2201,7 +2221,11 @@ impl<'db> SemanticsImpl<'db> { } pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option { - let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db); + let id = match impl_.id { + AnyImplId::ImplId(id) => id, + AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()), + }; + let source = hir_def::src::HasSource::ast_ptr(&id.loc(self.db), self.db); let mut file_id = source.file_id; let adt_ast_id = loop { let macro_call = file_id.macro_file()?; diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 848ad33801..bf123e13f9 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -57,9 +57,9 @@ use syntax::{ use triomphe::Arc; use crate::{ - Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, - Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, - TupleField, Type, TypeAlias, Variant, + Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, + DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, + ToolModule, Trait, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -431,7 +431,7 @@ impl<'db> SourceAnalyzer<'db> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let (f_in_trait, substs) = self.infer()?.method_resolution(expr_id)?; - Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into()) + Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)) } pub(crate) fn resolve_method_call_fallback( @@ -446,8 +446,8 @@ impl<'db> SourceAnalyzer<'db> { let (fn_, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs); Some(( - Either::Left(fn_.into()), - Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))), + Either::Left(fn_), + GenericSubstitution::new_from_fn(fn_, subst, self.trait_environment(db)), )) } None => { @@ -519,8 +519,8 @@ impl<'db> SourceAnalyzer<'db> { None => inference_result.method_resolution(expr_id).map(|(f, substs)| { let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs); ( - Either::Right(f.into()), - Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))), + Either::Right(f), + GenericSubstitution::new_from_fn(f, subst, self.trait_environment(db)), ) }), } @@ -569,7 +569,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, await_expr: &ast::AwaitExpr, - ) -> Option { + ) -> Option { let mut ty = self.ty_of_expr(await_expr.expr()?)?; let into_future_trait = self @@ -605,7 +605,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, prefix_expr: &ast::PrefixExpr, - ) -> Option { + ) -> Option { let (_op_trait, op_fn) = match prefix_expr.op_kind()? { ast::UnaryOp::Deref => { // This can be either `Deref::deref` or `DerefMut::deref_mut`. @@ -650,7 +650,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, index_expr: &ast::IndexExpr, - ) -> Option { + ) -> Option { let base_ty = self.ty_of_expr(index_expr.base()?)?; let index_ty = self.ty_of_expr(index_expr.index()?)?; @@ -679,7 +679,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, binop_expr: &ast::BinExpr, - ) -> Option { + ) -> Option { let op = binop_expr.op_kind()?; let lhs = self.ty_of_expr(binop_expr.lhs()?)?; let rhs = self.ty_of_expr(binop_expr.rhs()?)?; @@ -699,7 +699,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, try_expr: &ast::TryExpr, - ) -> Option { + ) -> Option { let ty = self.ty_of_expr(try_expr.expr()?)?; let op_fn = self.lang_items(db).TryTraitBranch?; @@ -905,7 +905,7 @@ impl<'db> SourceAnalyzer<'db> { subs, self.trait_environment(db), ); - (AssocItemId::from(f_in_trait), subst) + (AssocItem::Function(f_in_trait.into()), Some(subst)) } Some(func_ty) => { if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() { @@ -913,19 +913,19 @@ impl<'db> SourceAnalyzer<'db> { .resolve_impl_method_or_trait_def_with_subst( db, f_in_trait, subs, ); - let subst = GenericSubstitution::new( - fn_.into(), + let subst = GenericSubstitution::new_from_fn( + fn_, subst, self.trait_environment(db), ); - (fn_.into(), subst) + (AssocItem::Function(fn_), subst) } else { let subst = GenericSubstitution::new( f_in_trait.into(), subs, self.trait_environment(db), ); - (f_in_trait.into(), subst) + (AssocItem::Function(f_in_trait.into()), Some(subst)) } } } @@ -938,11 +938,11 @@ impl<'db> SourceAnalyzer<'db> { subst, self.trait_environment(db), ); - (konst.into(), subst) + (AssocItem::Const(konst.into()), Some(subst)) } }; - return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst))); + return Some((PathResolution::Def(assoc.into()), subst)); } if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_id) @@ -1401,7 +1401,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, func: FunctionId, substs: GenericArgs<'db>, - ) -> FunctionId { + ) -> Function { self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0 } @@ -1410,13 +1410,19 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, func: FunctionId, substs: GenericArgs<'db>, - ) -> (FunctionId, GenericArgs<'db>) { + ) -> (Function, GenericArgs<'db>) { let owner = match self.resolver.body_owner() { Some(it) => it, - None => return (func, substs), + None => return (func.into(), substs), }; let env = self.param_and(db.trait_environment_for_body(owner)); - db.lookup_impl_method(env, func, substs) + let (func, args) = db.lookup_impl_method(env, func, substs); + match func { + Either::Left(func) => (func.into(), args), + Either::Right((impl_, method)) => { + (Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }, args) + } + } } fn resolve_impl_const_or_trait_def_with_subst( diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 953bc73da9..7692a7d61a 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -734,11 +734,11 @@ FileSymbol { name: "generic_impl_fn", def: Function( - Function { - id: FunctionId( + FunctionId( + FunctionId( 6402, ), - }, + ), ), loc: DeclarationLocation { hir_file_id: FileId( @@ -769,11 +769,11 @@ FileSymbol { name: "impl_fn", def: Function( - Function { - id: FunctionId( + FunctionId( + FunctionId( 6401, ), - }, + ), ), loc: DeclarationLocation { hir_file_id: FileId( @@ -839,11 +839,11 @@ FileSymbol { name: "main", def: Function( - Function { - id: FunctionId( + FunctionId( + FunctionId( 6400, ), - }, + ), ), loc: DeclarationLocation { hir_file_id: FileId( @@ -907,11 +907,11 @@ FileSymbol { name: "trait_fn", def: Function( - Function { - id: FunctionId( + FunctionId( + FunctionId( 6403, ), - }, + ), ), loc: DeclarationLocation { hir_file_id: FileId( diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index f57f2883b1..06ae0b1d73 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -767,14 +767,30 @@ fn label_of_ty( ) }); + let module_def_location = |label_builder: &mut InlayHintLabelBuilder<'_>, + def: ModuleDef, + name| { + let def = def.try_into(); + if let Ok(def) = def { + label_builder.start_location_link(def); + } + #[expect( + clippy::question_mark, + reason = "false positive; replacing with `?` leads to 'type annotations needed' error" + )] + if let Err(err) = label_builder.write_str(name) { + return Err(err); + } + if def.is_ok() { + label_builder.end_location_link(); + } + Ok(()) + }; + label_builder.write_str(LABEL_START)?; - label_builder.start_location_link(ModuleDef::from(iter_trait).into()); - label_builder.write_str(LABEL_ITERATOR)?; - label_builder.end_location_link(); + module_def_location(label_builder, ModuleDef::from(iter_trait), LABEL_ITERATOR)?; label_builder.write_str(LABEL_MIDDLE)?; - label_builder.start_location_link(ModuleDef::from(item).into()); - label_builder.write_str(LABEL_ITEM)?; - label_builder.end_location_link(); + module_def_location(label_builder, ModuleDef::from(item), LABEL_ITEM)?; label_builder.write_str(LABEL_MIDDLE2)?; rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?; label_builder.write_str(LABEL_END)?; diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs index 1317684a08..e5e4c899ec 100644 --- a/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/crates/ide/src/inlay_hints/implicit_drop.rs @@ -34,9 +34,10 @@ pub(super) fn hints( let def = sema.to_def(node)?; let def: DefWithBody = def.into(); - let (hir, source_map) = sema.db.body_with_source_map(def.into()); + let def = def.try_into().ok()?; + let (hir, source_map) = sema.db.body_with_source_map(def); - let mir = sema.db.mir_body(def.into()).ok()?; + let mir = sema.db.mir_body(def).ok()?; let local_to_binding = mir.local_to_binding_map(); diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 020f235d3a..a271cac6fc 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -6,7 +6,7 @@ use arrayvec::ArrayVec; use either::Either; use hir::{ AssocItem, Crate, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId, - InFile, LocalSource, ModuleSource, Semantics, Symbol, db::ExpandDatabase, sym, + InFile, LocalSource, ModuleSource, Name, Semantics, Symbol, db::ExpandDatabase, sym, symbols::FileSymbol, }; use ide_db::{ @@ -204,6 +204,22 @@ impl NavigationTarget { ) } + pub(crate) fn from_named_with_range( + db: &RootDatabase, + ranges: InFile<(TextRange, Option)>, + name: Option, + kind: SymbolKind, + ) -> UpmappingResult { + let InFile { file_id, value: (full_range, focus_range) } = ranges; + let name = name.map(|name| name.symbol().clone()).unwrap_or_else(|| sym::underscore); + + orig_range_with_focus_r(db, file_id, full_range, focus_range).map( + |(FileRange { file_id, range: full_range }, focus_range)| { + NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind) + }, + ) + } + pub(crate) fn from_syntax( file_id: FileId, name: Symbol, @@ -414,7 +430,13 @@ impl ToNavFromAst for hir::Trait { impl TryToNav for D where - D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate, + D: HasSource + + ToNavFromAst + + Copy + + HasDocs + + for<'db> HirDisplay<'db> + + HasCrate + + hir::HasName, D::Ast: ast::HasName, { fn try_to_nav( @@ -422,11 +444,19 @@ where sema: &Semantics<'_, RootDatabase>, ) -> Option> { let db = sema.db; - let src = self.source(db)?; + let src = self.source_with_range(db)?; Some( - NavigationTarget::from_named( + NavigationTarget::from_named_with_range( db, - src.as_ref().map(|it| it as &dyn ast::HasName), + src.map(|(full_range, node)| { + ( + full_range, + node.and_then(|node| { + Some(ast::HasName::name(&node)?.syntax().text_range()) + }), + ) + }), + self.name(db), D::KIND, ) .map(|mut res| { @@ -477,16 +507,16 @@ impl TryToNav for hir::Impl { sema: &Semantics<'_, RootDatabase>, ) -> Option> { let db = sema.db; - let InFile { file_id, value } = self.source(db)?; - let derive_path = self.as_builtin_derive_path(db); + let InFile { file_id, value: (full_range, source) } = self.source_with_range(db)?; - let (file_id, focus, syntax) = match &derive_path { - Some(attr) => (attr.file_id.into(), None, attr.value.syntax()), - None => (file_id, value.self_ty(), value.syntax()), - }; - - Some(orig_range_with_focus(db, file_id, syntax, focus).map( - |(FileRange { file_id, range: full_range }, focus_range)| { + Some( + orig_range_with_focus_r( + db, + file_id, + full_range, + source.and_then(|source| Some(source.self_ty()?.syntax().text_range())), + ) + .map(|(FileRange { file_id, range: full_range }, focus_range)| { NavigationTarget::from_syntax( file_id, sym::kw_impl, @@ -494,8 +524,8 @@ impl TryToNav for hir::Impl { full_range, SymbolKind::Impl, ) - }, - )) + }), + ) } } diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 0738b7fadc..ffae7bf6c7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -2503,7 +2503,7 @@ fn r#fn$0() {} fn main() { r#fn(); } "#, expect![[r#" - r#fn Function FileId(0) 0..12 3..7 + fn Function FileId(0) 0..12 3..7 FileId(0) 25..29 "#]], diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index c562a9b30b..6cec912503 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -1679,11 +1679,11 @@ mod r#mod { [ "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..461, focus_range: 5..10, name: \"mod\", kind: Module, description: \"mod r#mod\" })", "(Test, NavigationTarget { file_id: FileId(0), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"r#for\", container_name: \"mod\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"r#struct\", container_name: \"mod\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"for\", container_name: \"mod\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"struct\", container_name: \"mod\" })", "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"r#fn\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"r#fn\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"fn\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"fn\" })", "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })", ] "#]], diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index aa7e40c658..3e325b2f99 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -526,6 +526,9 @@ define_symbols! { arbitrary_self_types_pointers, supertrait_item_shadowing, hash, + partial_cmp, cmp, + CoerceUnsized, + DispatchFromDyn, define_opaque, } diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 76256b0a22..9374d97d83 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -693,21 +693,24 @@ impl flags::AnalysisStats { let mut sw = self.stop_watch(); let mut all = 0; let mut fail = 0; - for &body_id in bodies { + for &body in bodies { bar.set_message(move || { - format!("mir lowering: {}", full_name(db, body_id, body_id.module(db))) + format!("mir lowering: {}", full_name(db, body, body.module(db))) }); bar.inc(1); - if matches!(body_id, DefWithBody::Variant(_)) { + if matches!(body, DefWithBody::Variant(_)) { continue; } - let module = body_id.module(db); - if !self.should_process(db, body_id, module) { + let module = body.module(db); + if !self.should_process(db, body, module) { continue; } all += 1; - let Err(e) = db.mir_body(body_id.into()) else { + let Ok(body_id) = body.try_into() else { + continue; + }; + let Err(e) = db.mir_body(body_id) else { continue; }; if verbosity.is_spammy() { @@ -716,7 +719,7 @@ impl flags::AnalysisStats { .into_iter() .rev() .filter_map(|it| it.name(db)) - .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) + .chain(Some(body.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::"); bar.println(format!("Mir body for {full_name} failed due {e:?}")); @@ -747,11 +750,12 @@ impl flags::AnalysisStats { if self.parallel { let mut inference_sw = self.stop_watch(); + let bodies = bodies.iter().filter_map(|&body| body.try_into().ok()).collect::>(); bodies .par_iter() .map_with(db.clone(), |snap, &body| { - snap.body(body.into()); - InferenceResult::for_body(snap, body.into()); + snap.body(body); + InferenceResult::for_body(snap, body); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -769,6 +773,7 @@ impl flags::AnalysisStats { let mut num_pat_type_mismatches = 0; let mut panics = 0; for &body_id in bodies { + let Ok(body_def_id) = body_id.try_into() else { continue }; let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); let display_target = module.krate(db).to_display_target(db); @@ -807,9 +812,9 @@ impl flags::AnalysisStats { bar.println(msg()); } bar.set_message(msg); - let body = db.body(body_id.into()); + let body = db.body(body_def_id); let inference_result = - catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_id.into()))); + catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_def_id))); let inference_result = match inference_result { Ok(inference_result) => inference_result, Err(p) => { @@ -826,7 +831,7 @@ impl flags::AnalysisStats { } }; // This query is LRU'd, so actually calling it will skew the timing results. - let sm = || db.body_with_source_map(body_id.into()).1; + let sm = || db.body_with_source_map(body_def_id).1; // region:expressions let (previous_exprs, previous_unknown, previous_partially_unknown) = @@ -1081,6 +1086,7 @@ impl flags::AnalysisStats { let mut sw = self.stop_watch(); bar.tick(); for &body_id in bodies { + let Ok(body_def_id) = body_id.try_into() else { continue }; let module = body_id.module(db); if !self.should_process(db, body_id, module) { continue; @@ -1114,7 +1120,7 @@ impl flags::AnalysisStats { bar.println(msg()); } bar.set_message(msg); - db.body(body_id.into()); + db.body(body_def_id); bar.inc(1); }