Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/builtin_derive.rs114
-rw-r--r--crates/hir-def/src/item_scope.rs7
-rw-r--r--crates/hir-def/src/lib.rs15
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs1657
-rw-r--r--crates/hir-def/src/macro_expansion_tests/proc_macros.rs8
-rw-r--r--crates/hir-def/src/nameres/collector.rs35
-rw-r--r--crates/hir-ty/src/builtin_derive.rs78
-rw-r--r--crates/hir-ty/src/consteval/tests.rs1
-rw-r--r--crates/hir-ty/src/db.rs10
-rw-r--r--crates/hir-ty/src/display.rs49
-rw-r--r--crates/hir-ty/src/lib.rs2
-rw-r--r--crates/hir-ty/src/lower.rs23
-rw-r--r--crates/hir-ty/src/method_resolution.rs75
-rw-r--r--crates/hir-ty/src/mir/eval.rs7
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs19
-rw-r--r--crates/hir-ty/src/mir/eval/shim/simd.rs15
-rw-r--r--crates/hir-ty/src/next_solver/format_proof_tree.rs31
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs2
-rw-r--r--crates/hir-ty/src/tests/incremental.rs2
-rw-r--r--crates/hir/src/attrs.rs45
-rw-r--r--crates/hir/src/display.rs343
-rw-r--r--crates/hir/src/from_id.rs102
-rw-r--r--crates/hir/src/has_source.rs72
-rw-r--r--crates/hir/src/lib.rs962
-rw-r--r--crates/hir/src/semantics.rs82
-rw-r--r--crates/hir/src/source_analyzer.rs54
-rw-r--r--crates/ide-db/src/test_data/test_symbol_index_collection.txt24
-rw-r--r--crates/ide/src/inlay_hints.rs28
-rw-r--r--crates/ide/src/inlay_hints/implicit_drop.rs5
-rw-r--r--crates/ide/src/navigation_target.rs62
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/runnables.rs8
-rw-r--r--crates/intern/src/symbol/symbols.rs3
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs32
34 files changed, 2445 insertions, 1529 deletions
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<crate::TraitId> {
match self {
$( Self::$trait => lang_items.$trait, )*
}
}
+
+ #[inline]
+ pub fn get_method(self, method_name: &Symbol) -> Option<BuiltinDeriveImplMethod> {
+ 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<FunctionId> {
+ 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<TextRange> {
+ 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<ast::Adt>,
attr_id: AttrId,
attr_call_id: MacroCallId,
- len: usize,
+ mut derive_call_ids: SmallVec<[Option<MacroCallId>; 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<DefWithBodyId> 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<A, B>;
-"#,
- expect![[r#"
-#[derive(Copy)]
-struct Foo<A, B>;
-
-impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
- );
-}
-
-#[test]
-fn test_copy_expand_with_lifetimes() {
- // We currently just ignore lifetimes
- check(
- r#"
-//- minicore: derive, copy
-#[derive(Copy)]
-struct Foo<A, B, 'a, 'b>;
-"#,
- expect![[r#"
-#[derive(Copy)]
-struct Foo<A, B, 'a, 'b>;
-
-impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
- );
-}
-
-#[test]
-fn test_clone_expand() {
- check(
- r#"
-//- minicore: derive, clone
-#[derive(Clone)]
-enum Command<A, B> {
- Move { x: A, y: B },
- Do(&'static str),
- Jump,
-}
-"#,
- expect![[r#"
-#[derive(Clone)]
-enum Command<A, B> {
- Move { x: A, y: B },
- Do(&'static str),
- Jump,
-}
-
-impl <A: $crate::clone::Clone, B: $crate::clone::Clone, > $crate::clone::Clone for Command<A, B, > 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>(T);
-
-#[derive(Clone)]
-struct Foo<T: Trait>
-where
- <T as Trait>::InWc: Marker,
-{
- qualified: <T as Trait>::InFieldQualified,
- shorthand: T::InFieldShorthand,
- generic: Vec<T::InGenericArg>,
-}
-"#,
- expect![[r#"
-trait Trait {
- type InWc;
- type InFieldQualified;
- type InFieldShorthand;
- type InGenericArg;
-}
-trait Marker {}
-struct Vec<T>(T);
-
-#[derive(Clone)]
-struct Foo<T: Trait>
-where
- <T as Trait>::InWc: Marker,
-{
- qualified: <T as Trait>::InFieldQualified,
- shorthand: T::InFieldShorthand,
- generic: Vec<T::InGenericArg>,
-}
-
-impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where <T as Trait>::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<const X: usize, T>(u32);
-"#,
- expect![[r#"
-#[derive(Clone)]
-struct Foo<const X: usize, T>(u32);
-
-impl <const X: usize, T: $crate::clone::Clone, > $crate::clone::Clone for Foo<X, T, > 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<H: $crate::hash::Hasher>(&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<H: $crate::hash::Hasher>(&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<T: ?Sized> {}
-
-#[derive(CoercePointee)]
-#[repr(transparent)]
-pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
-where
- U: Trait<U> + ToString;"#,
- expect![[r#"
-
-use core::marker::CoercePointee;
-
-pub trait Trait<T: ?Sized> {}
-
-#[derive(CoercePointee)]
-#[repr(transparent)]
-pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
-where
- U: Trait<U> + ToString;
-impl <T, U, const N: u32, __S> $crate::ops::DispatchFromDyn<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, U:?Sized, {}
-impl <T, U, const N: u32, __S> $crate::ops::CoerceUnsized<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, 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: ?Sized>(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: ?Sized, U: ?Sized>(T, U);
-
-#[derive(CoercePointee)]
-#[repr(transparent)]
-struct Struct8<#[pointee] T, U: ?Sized>(T);
-
-#[derive(CoercePointee)]
-#[repr(transparent)]
-struct Struct9<T>(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<T> {
- Bar(T),
- #[default]
- Baz,
-}
-"#,
- expect![[r#"
-
-#[derive(Default)]
-enum Foo<T> {
- Bar(T),
- #[default]
- Baz,
-}
-
-impl <T, > $crate::default::Default for Foo<T, > 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<A, B>;
+// "#,
+// expect![[r#"
+// #[derive(Copy)]
+// struct Foo<A, B>;
+
+// impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
+// );
+// }
+
+// #[test]
+// fn test_copy_expand_with_lifetimes() {
+// // We currently just ignore lifetimes
+// check(
+// r#"
+// //- minicore: derive, copy
+// #[derive(Copy)]
+// struct Foo<A, B, 'a, 'b>;
+// "#,
+// expect![[r#"
+// #[derive(Copy)]
+// struct Foo<A, B, 'a, 'b>;
+
+// impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
+// );
+// }
+
+// #[test]
+// fn test_clone_expand() {
+// check(
+// r#"
+// //- minicore: derive, clone
+// #[derive(Clone)]
+// enum Command<A, B> {
+// Move { x: A, y: B },
+// Do(&'static str),
+// Jump,
+// }
+// "#,
+// expect![[r#"
+// #[derive(Clone)]
+// enum Command<A, B> {
+// Move { x: A, y: B },
+// Do(&'static str),
+// Jump,
+// }
+
+// impl <A: $crate::clone::Clone, B: $crate::clone::Clone, > $crate::clone::Clone for Command<A, B, > 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>(T);
+
+// #[derive(Clone)]
+// struct Foo<T: Trait>
+// where
+// <T as Trait>::InWc: Marker,
+// {
+// qualified: <T as Trait>::InFieldQualified,
+// shorthand: T::InFieldShorthand,
+// generic: Vec<T::InGenericArg>,
+// }
+// "#,
+// expect![[r#"
+// trait Trait {
+// type InWc;
+// type InFieldQualified;
+// type InFieldShorthand;
+// type InGenericArg;
+// }
+// trait Marker {}
+// struct Vec<T>(T);
+
+// #[derive(Clone)]
+// struct Foo<T: Trait>
+// where
+// <T as Trait>::InWc: Marker,
+// {
+// qualified: <T as Trait>::InFieldQualified,
+// shorthand: T::InFieldShorthand,
+// generic: Vec<T::InGenericArg>,
+// }
+
+// impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where <T as Trait>::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<const X: usize, T>(u32);
+// "#,
+// expect![[r#"
+// #[derive(Clone)]
+// struct Foo<const X: usize, T>(u32);
+
+// impl <const X: usize, T: $crate::clone::Clone, > $crate::clone::Clone for Foo<X, T, > 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<H: $crate::hash::Hasher>(&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<H: $crate::hash::Hasher>(&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<T: ?Sized> {}
+
+// #[derive(CoercePointee)]
+// #[repr(transparent)]
+// pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
+// where
+// U: Trait<U> + ToString;"#,
+// expect![[r#"
+
+// use core::marker::CoercePointee;
+
+// pub trait Trait<T: ?Sized> {}
+
+// #[derive(CoercePointee)]
+// #[repr(transparent)]
+// pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
+// where
+// U: Trait<U> + ToString;
+// impl <T, U, const N: u32, __S> $crate::ops::DispatchFromDyn<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, U:?Sized, {}
+// impl <T, U, const N: u32, __S> $crate::ops::CoerceUnsized<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, 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: ?Sized>(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: ?Sized, U: ?Sized>(T, U);
+
+// #[derive(CoercePointee)]
+// #[repr(transparent)]
+// struct Struct8<#[pointee] T, U: ?Sized>(T);
+
+// #[derive(CoercePointee)]
+// #[repr(transparent)]
+// struct Struct9<T>(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<T> {
+// Bar(T),
+// #[default]
+// Baz,
+// }
+// "#,
+// expect![[r#"
+
+// #[derive(Default)]
+// enum Foo<T> {
+// Bar(T),
+// #[default]
+// Baz,
+// }
+
+// impl <T, > $crate::default::Default for Foo<T, > 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
@@ -123,15 +123,15 @@ struct Foo {
}
#[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<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, 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<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, 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<AssocItemId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, 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, &params, &params_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, &params, &params_store)
.then_some((params, params_store))
@@ -59,140 +115,151 @@ 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 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 {
+ ItemContainerId::TraitId(_) => "trait",
+ ItemContainerId::ImplId(_) => "impl",
+ _ => unreachable!(),
+ };
+ write!(f, "\n // Bounds from {container_name}:",)?;
+ write_where_predicates(&container_params, &container_params_store, f)?;
}
- let module_id = module.id;
-
- write_visibility(module_id, self.visibility(db), f)?;
+ Ok(())
+ }
+}
- 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()))?;
+fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result<bool> {
+ let db = f.db;
+ let func = Function::from(func_id);
+ let data = db.function_signature(func_id);
- write_generic_params(GenericDefId::FunctionId(self.id), f)?;
+ 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;
- f.write_char('(')?;
+ write_visibility(module_id, func.visibility(db), f)?;
- 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;
- }
+ 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()))?;
- // 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;
- }
+ write_generic_params(GenericDefId::FunctionId(func_id), f)?;
- 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_char('(')?;
- f.write_str(": ")?;
- type_ref.hir_fmt(f, &data.store)?;
+ 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;
}
- if data.is_varargs() {
- if !first {
- f.write_str(", ")?;
- }
- f.write_str("...")?;
- }
-
- f.write_char(')')?;
-
- // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` 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,
- },
+ 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<Output = ...>` 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,
- }
- } 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)?;
- }
- }
+ },
+ _ => None,
}
+ } else {
+ None
+ };
- // Write where clauses
- let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?;
- if let Some((container_params, container_params_store)) = container_params {
- if !has_written_where {
- f.write_str("\nwhere")?;
+ 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)?;
}
- let container_name = match container.unwrap() {
- AssocItemContainer::Trait(_) => "trait",
- AssocItemContainer::Impl(_) => "impl",
- };
- write!(f, "\n // Bounds from {container_name}:",)?;
- write_where_predicates(&container_params, &container_params_store, f)?;
}
- Ok(())
}
+
+ // 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_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result {
+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<ModuleDefId> for ModuleDef {
}
}
-impl From<ModuleDef> for ModuleDefId {
- fn from(id: ModuleDef) -> Self {
- match id {
+impl TryFrom<ModuleDef> for ModuleDefId {
+ type Error = ();
+ fn try_from(id: ModuleDef) -> Result<Self, Self::Error> {
+ 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<ModuleDef> 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<DefWithBody> for DefWithBodyId {
- fn from(def: DefWithBody) -> Self {
- match def {
- DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
+impl TryFrom<DefWithBody> for DefWithBodyId {
+ type Error = ();
+ fn try_from(def: DefWithBody) -> Result<Self, ()> {
+ 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<AssocItemId> for AssocItem {
}
}
-impl From<GenericDef> 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<GenericDef> for GenericDefId {
+ type Error = ();
+
+ fn try_from(def: GenericDef) -> Result<Self, Self::Error> {
+ def.id().ok_or(())
}
}
@@ -238,13 +241,17 @@ impl From<FieldId> for Field {
}
}
-impl From<AssocItem> for GenericDefId {
- fn from(item: AssocItem) -> Self {
- match item {
- AssocItem::Function(f) => f.id.into(),
+impl TryFrom<AssocItem> for GenericDefId {
+ type Error = ();
+ fn try_from(item: AssocItem) -> Result<Self, Self::Error> {
+ 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<hir_def::item_scope::ItemInNs> for ItemInNs {
}
}
-impl From<ItemInNs> 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<ItemInNs> for hir_def::item_scope::ItemInNs {
+ type Error = ();
+ fn try_from(it: ItemInNs) -> Result<Self, Self::Error> {
+ 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<BuiltinType> for hir_def::builtin_type::BuiltinType {
it.inner
}
}
+
+impl From<hir_def::ImplId> for crate::Impl {
+ fn from(value: hir_def::ImplId) -> Self {
+ crate::Impl { id: AnyImplId::ImplId(value) }
+ }
+}
+
+impl From<BuiltinDeriveImplId> for crate::Impl {
+ fn from(value: BuiltinDeriveImplId) -> Self {
+ crate::Impl { id: AnyImplId::BuiltinDeriveImplId(value) }
+ }
+}
+
+impl From<hir_def::FunctionId> 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 <https://github.com/rust-lang/rust-analyzer/issues/6913>
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
+
+ /// 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<InFile<(TextRange, Option<Self::Ast>)>> {
+ 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<InFile<Self::Ast>> {
- 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<InFile<(TextRange, Option<Self::Ast>)>> {
+ 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<InFile<Self::Ast>> {
- 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<InFile<(TextRange, Option<Self::Ast>)>> {
+ 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<InFile<Self::Ast>> {
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<InFile<Self::Ast>> {
- 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<AttrsWithOwner> {
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<Impl> {
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<ModPath> {
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<ModPath> {
- 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<DefWithBodyId> {
+ 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<AnyDiagnostic<'db>>,
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<DbInterner<'db>> 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<Item = Type<'db>>,
) -> 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<Item = Type<'db>>,
+ ) -> 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<Type<'db>> {
+ 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<SelfParam> {
- 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<Param<'_>> {
- 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<Vec<Param<'_>>> {
@@ -2307,21 +2498,11 @@ impl Function {
}
pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
- 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<Item = Type<'db>>,
) -> Vec<Param<'db>> {
- 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<ExternBlock> {
- 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<Function>,
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<Macro> {
- 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<String, ConstEvalError> {
+ 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(|&param| 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(|&param| 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<Item = Type<'db>>,
) -> 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<Name>) -> Option<Function> {
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<BuiltinDeriveMacroKind> {
+ 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<ExternAssocItem> {
- 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<method_resolution::CandidateId> 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<AssocItem> {
- 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<GenericParam> {
- 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<LifetimeParam> {
- 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<TypeOrConstParam> {
- 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<GenericDefId> {
+ 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<AnyDiagnostic<'db>>) {
- 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<Self> {
+ 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<SelfParam> {
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<Impl>) {
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<Impl> {
- 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<Trait> {
- 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<TraitRef<'_>> {
- 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<AssocItem> {
- 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<InMacroFile<ast::Path>> {
- 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(<ast::Attr as AstNode>::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<ast::Item>, 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<Function> {
+ 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<Name>;
+}
+
+macro_rules! impl_has_name {
+ ( $( $ty:ident ),* $(,)? ) => {
+ $(
+ impl HasName for $ty {
+ fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
+ (*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<Name> {
+ (*self).name().into()
+ }
+ }
+ )*
+ };
+}
+
+impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr);
+
+impl HasName for Param<'_> {
+ fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
+ 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<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
}
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
- 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<Function> {
- 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<Function> {
- 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<Function> {
- 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<Function> {
- 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<VariantDef> {
@@ -1749,6 +1752,7 @@ impl<'db> SemanticsImpl<'db> {
func: Function,
subst: impl IntoIterator<Item = Type<'db>>,
) -> Option<Function> {
+ 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<StructId> {
@@ -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<FunctionId> {
+ fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
}
- fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
+ fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
}
- fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
+ fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
}
- fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
+ fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
}
- fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
+ fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
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<ExprOrPatSource> {
- 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<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
- where
- Def::Ast: AstNode,
- {
+ pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> {
// 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<Def: HasSource>(
+ &self,
+ def: Def,
+ ) -> Option<InFile<(TextRange, Option<Def::Ast>)>> {
+ 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<DefWithBody> {
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<Adt> {
- 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<FunctionId> {
+ ) -> Option<Function> {
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<FunctionId> {
+ ) -> Option<Function> {
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<FunctionId> {
+ ) -> Option<Function> {
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<FunctionId> {
+ ) -> Option<Function> {
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<FunctionId> {
+ ) -> Option<Function> {
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<TextRange>)>,
+ name: Option<Name>,
+ kind: SymbolKind,
+ ) -> UpmappingResult<NavigationTarget> {
+ 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<D> 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<UpmappingResult<NavigationTarget>> {
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<UpmappingResult<NavigationTarget>> {
let db = sema.db;
- let InFile { file_id, value } = self.source(db)?;
- let derive_path = self.as_builtin_derive_path(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()),
- };
+ let InFile { file_id, value: (full_range, source) } = self.source_with_range(db)?;
- 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::<Vec<_>>();
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);
}