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 814afdd16c..0013c2a256 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,833 +1,828 @@ //! Tests for `builtin_derive_macro.rs` from `hir_expand`. -// FIXME: This file is commented out because due to the fast path for builtin derives, -// the macros do not really get expanded, and we cannot check their expansion. -// It's not removed because we still need to find some way to do that nevertheless. -// Maybe going through the list of registered derive calls in the def map? - -// use expect_test::expect; - -// use crate::macro_expansion_tests::{check, check_errors}; - -// #[test] -// fn test_copy_expand_simple() { -// check( -// r#" -// //- minicore: derive, copy -// #[derive(Copy)] -// struct Foo; -// "#, -// expect![[r#" -// #[derive(Copy)] -// struct Foo; - -// impl <> $crate::marker::Copy for Foo< > where {}"#]], -// ); -// } - -// #[test] -// fn test_copy_expand_in_core() { -// check( -// r#" -// //- /lib.rs crate:core -// #[rustc_builtin_macro] -// macro derive {} -// #[rustc_builtin_macro] -// macro Copy {} -// #[derive(Copy)] -// struct Foo; -// "#, -// expect![[r#" -// #[rustc_builtin_macro] -// macro derive {} -// #[rustc_builtin_macro] -// macro Copy {} -// #[derive(Copy)] -// struct Foo; - -// impl <> $crate::marker::Copy for Foo< > where {}"#]], -// ); -// } - -// #[test] -// fn test_copy_expand_with_type_params() { -// check( -// r#" -// //- minicore: derive, copy -// #[derive(Copy)] -// struct Foo; -// "#, -// expect![[r#" -// #[derive(Copy)] -// struct Foo; - -// impl $crate::marker::Copy for Foo where {}"#]], -// ); -// } - -// #[test] -// fn test_copy_expand_with_lifetimes() { -// // We currently just ignore lifetimes -// check( -// r#" -// //- minicore: derive, copy -// #[derive(Copy)] -// struct Foo; -// "#, -// expect![[r#" -// #[derive(Copy)] -// struct Foo; - -// impl $crate::marker::Copy for Foo where {}"#]], -// ); -// } - -// #[test] -// fn test_clone_expand() { -// check( -// r#" -// //- minicore: derive, clone -// #[derive(Clone)] -// enum Command { -// Move { x: A, y: B }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// #[derive(Clone)] -// enum Command { -// Move { x: A, y: B }, -// Do(&'static str), -// Jump, -// } - -// impl $crate::clone::Clone for Command where { -// fn clone(&self ) -> Self { -// match self { -// Command::Move { -// x: x, y: y, -// } -// =>Command::Move { -// x: x.clone(), y: y.clone(), -// } -// , Command::Do(f0, )=>Command::Do(f0.clone(), ), Command::Jump=>Command::Jump, -// } -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_clone_expand_with_associated_types() { -// check( -// r#" -// //- minicore: derive, clone -// trait Trait { -// type InWc; -// type InFieldQualified; -// type InFieldShorthand; -// type InGenericArg; -// } -// trait Marker {} -// struct Vec(T); - -// #[derive(Clone)] -// struct Foo -// where -// ::InWc: Marker, -// { -// qualified: ::InFieldQualified, -// shorthand: T::InFieldShorthand, -// generic: Vec, -// } -// "#, -// expect![[r#" -// trait Trait { -// type InWc; -// type InFieldQualified; -// type InFieldShorthand; -// type InGenericArg; -// } -// trait Marker {} -// struct Vec(T); - -// #[derive(Clone)] -// struct Foo -// where -// ::InWc: Marker, -// { -// qualified: ::InFieldQualified, -// shorthand: T::InFieldShorthand, -// generic: Vec, -// } - -// impl $crate::clone::Clone for Foo where ::InWc: Marker, T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { -// fn clone(&self ) -> Self { -// match self { -// Foo { -// qualified: qualified, shorthand: shorthand, generic: generic, -// } -// =>Foo { -// qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), -// } -// , -// } -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_clone_expand_with_const_generics() { -// check( -// r#" -// //- minicore: derive, clone -// #[derive(Clone)] -// struct Foo(u32); -// "#, -// expect![[r#" -// #[derive(Clone)] -// struct Foo(u32); - -// impl $crate::clone::Clone for Foo where { -// fn clone(&self ) -> Self { -// match self { -// Foo(f0, )=>Foo(f0.clone(), ), -// } -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_default_expand() { -// check( -// r#" -// //- minicore: derive, default -// #[derive(Default)] -// struct Foo { -// field1: i32, -// field2: (), -// } -// #[derive(Default)] -// enum Bar { -// Foo(u8), -// #[default] -// Bar, -// } -// "#, -// expect![[r#" -// #[derive(Default)] -// struct Foo { -// field1: i32, -// field2: (), -// } -// #[derive(Default)] -// enum Bar { -// Foo(u8), -// #[default] -// Bar, -// } - -// impl <> $crate::default::Default for Foo< > where { -// fn default() -> Self { -// Foo { -// field1: $crate::default::Default::default(), field2: $crate::default::Default::default(), -// } -// } -// } -// impl <> $crate::default::Default for Bar< > where { -// fn default() -> Self { -// Bar::Bar -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_partial_eq_expand() { -// check( -// r#" -// //- minicore: derive, eq -// #[derive(PartialEq, Eq)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// #[derive(PartialEq, Eq)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } - -// impl <> $crate::cmp::PartialEq for Command< > where { -// fn eq(&self , other: &Self ) -> bool { -// match (self , other) { -// (Command::Move { -// x: x_self, y: y_self, -// } -// , Command::Move { -// x: x_other, y: y_other, -// } -// )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false -// } -// } -// } -// impl <> $crate::cmp::Eq for Command< > where {}"#]], -// ); -// } - -// #[test] -// fn test_partial_eq_expand_with_derive_const() { -// // FIXME: actually expand with const -// check( -// r#" -// //- minicore: derive, eq -// #[derive_const(PartialEq, Eq)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// #[derive_const(PartialEq, Eq)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } - -// impl <> $crate::cmp::PartialEq for Command< > where { -// fn eq(&self , other: &Self ) -> bool { -// match (self , other) { -// (Command::Move { -// x: x_self, y: y_self, -// } -// , Command::Move { -// x: x_other, y: y_other, -// } -// )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false -// } -// } -// } -// impl <> $crate::cmp::Eq for Command< > where {}"#]], -// ); -// } - -// #[test] -// fn test_partial_ord_expand() { -// check( -// r#" -// //- minicore: derive, ord -// #[derive(PartialOrd, Ord)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// #[derive(PartialOrd, Ord)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } - -// impl <> $crate::cmp::PartialOrd for Command< > where { -// fn partial_cmp(&self , other: &Self ) -> $crate::option::Option<$crate::cmp::Ordering> { -// match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { -// match (self , other) { -// (Command::Move { -// x: x_self, y: y_self, -// } -// , Command::Move { -// x: x_other, y: y_other, -// } -// )=>match x_self.partial_cmp(&x_other) { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { -// match y_self.partial_cmp(&y_other) { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal) -// } -// c=>return c, -// } -// } -// c=>return c, -// } -// , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { -// $crate::option::Option::Some($crate::cmp::Ordering::Equal) -// } -// c=>return c, -// } -// , (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal) -// } -// } -// c=>return c, -// } -// } -// } -// impl <> $crate::cmp::Ord for Command< > where { -// fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering { -// match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) { -// $crate::cmp::Ordering::Equal=> { -// match (self , other) { -// (Command::Move { -// x: x_self, y: y_self, -// } -// , Command::Move { -// x: x_other, y: y_other, -// } -// )=>match x_self.cmp(&x_other) { -// $crate::cmp::Ordering::Equal=> { -// match y_self.cmp(&y_other) { -// $crate::cmp::Ordering::Equal=> { -// $crate::cmp::Ordering::Equal -// } -// c=>return c, -// } -// } -// c=>return c, -// } -// , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { -// $crate::cmp::Ordering::Equal=> { -// $crate::cmp::Ordering::Equal -// } -// c=>return c, -// } -// , (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal -// } -// } -// c=>return c, -// } -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_hash_expand() { -// check( -// r#" -// //- minicore: derive, hash -// use core::hash::Hash; - -// #[derive(Hash)] -// struct Foo { -// x: i32, -// y: u64, -// z: (i32, u64), -// } -// "#, -// expect![[r#" -// use core::hash::Hash; - -// #[derive(Hash)] -// struct Foo { -// x: i32, -// y: u64, -// z: (i32, u64), -// } - -// impl <> $crate::hash::Hash for Foo< > where { -// fn hash(&self , ra_expand_state: &mut H) { -// match self { -// Foo { -// x: x, y: y, z: z, -// } -// => { -// x.hash(ra_expand_state); -// y.hash(ra_expand_state); -// z.hash(ra_expand_state); -// } -// , -// } -// } -// }"#]], -// ); -// check( -// r#" -// //- minicore: derive, hash -// use core::hash::Hash; - -// #[derive(Hash)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// use core::hash::Hash; - -// #[derive(Hash)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } - -// impl <> $crate::hash::Hash for Command< > where { -// fn hash(&self , ra_expand_state: &mut H) { -// $crate::mem::discriminant(self ).hash(ra_expand_state); -// match self { -// Command::Move { -// x: x, y: y, -// } -// => { -// x.hash(ra_expand_state); -// y.hash(ra_expand_state); -// } -// , Command::Do(f0, )=> { -// f0.hash(ra_expand_state); -// } -// , Command::Jump=> {} -// , -// } -// } -// }"#]], -// ); -// } - -// #[test] -// fn test_debug_expand() { -// check( -// r#" -// //- minicore: derive, fmt -// use core::fmt::Debug; - -// #[derive(Debug)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } -// "#, -// expect![[r#" -// use core::fmt::Debug; - -// #[derive(Debug)] -// enum Command { -// Move { x: i32, y: i32 }, -// Do(&'static str), -// Jump, -// } - -// impl <> $crate::fmt::Debug for Command< > where { -// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { -// match self { -// Command::Move { -// x: x, y: y, -// } -// =>f.debug_struct("Move").field("x", &x).field("y", &y).finish(), Command::Do(f0, )=>f.debug_tuple("Do").field(&f0).finish(), Command::Jump=>f.write_str("Jump"), -// } -// } -// }"#]], -// ); -// } -// #[test] -// fn test_debug_expand_with_cfg() { -// check( -// r#" -// //- minicore: derive, fmt -// use core::fmt::Debug; - -// #[derive(Debug)] -// struct HideAndShow { -// #[cfg(never)] -// always_hide: u32, -// #[cfg(not(never))] -// always_show: u32, -// } -// #[derive(Debug)] -// enum HideAndShowEnum { -// #[cfg(never)] -// AlwaysHide, -// #[cfg(not(never))] -// AlwaysShow{ -// #[cfg(never)] -// always_hide: u32, -// #[cfg(not(never))] -// always_show: u32, -// } -// } -// "#, -// expect![[r#" -// use core::fmt::Debug; - -// #[derive(Debug)] -// struct HideAndShow { -// #[cfg(never)] -// always_hide: u32, -// #[cfg(not(never))] -// always_show: u32, -// } -// #[derive(Debug)] -// enum HideAndShowEnum { -// #[cfg(never)] -// AlwaysHide, -// #[cfg(not(never))] -// AlwaysShow{ -// #[cfg(never)] -// always_hide: u32, -// #[cfg(not(never))] -// always_show: u32, -// } -// } - -// impl <> $crate::fmt::Debug for HideAndShow< > where { -// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { -// match self { -// HideAndShow { -// always_show: always_show, -// } -// =>f.debug_struct("HideAndShow").field("always_show", &always_show).finish() -// } -// } -// } -// impl <> $crate::fmt::Debug for HideAndShowEnum< > where { -// fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { -// match self { -// HideAndShowEnum::AlwaysShow { -// always_show: always_show, -// } -// =>f.debug_struct("AlwaysShow").field("always_show", &always_show).finish(), -// } -// } -// }"#]], -// ); -// } -// #[test] -// fn test_default_expand_with_cfg() { -// check( -// r#" -// //- minicore: derive, default -// #[derive(Default)] -// struct Foo { -// field1: i32, -// #[cfg(never)] -// field2: (), -// #[cfg(feature = "never")] -// field3: (), -// #[cfg(not(feature = "never"))] -// field4: (), -// } -// #[derive(Default)] -// enum Bar { -// Foo, -// #[cfg_attr(not(never), default)] -// Bar, -// } -// "#, -// expect![[r##" -// #[derive(Default)] -// struct Foo { -// field1: i32, -// #[cfg(never)] -// field2: (), -// #[cfg(feature = "never")] -// field3: (), -// #[cfg(not(feature = "never"))] -// field4: (), -// } -// #[derive(Default)] -// enum Bar { -// Foo, -// #[cfg_attr(not(never), default)] -// Bar, -// } - -// impl <> $crate::default::Default for Foo< > where { -// fn default() -> Self { -// Foo { -// field1: $crate::default::Default::default(), field4: $crate::default::Default::default(), -// } -// } -// } -// impl <> $crate::default::Default for Bar< > where { -// fn default() -> Self { -// Bar::Bar -// } -// }"##]], -// ); -// } - -// #[test] -// fn coerce_pointee_expansion() { -// check( -// r#" -// //- minicore: coerce_pointee - -// use core::marker::CoercePointee; - -// pub trait Trait {} - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) -// where -// U: Trait + ToString;"#, -// expect![[r#" - -// use core::marker::CoercePointee; - -// pub trait Trait {} - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) -// where -// U: Trait + ToString; -// impl $crate::ops::DispatchFromDyn> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {} -// impl $crate::ops::CoerceUnsized> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {}"#]], -// ); -// } - -// #[test] -// fn coerce_pointee_errors() { -// check_errors( -// r#" -// //- minicore: coerce_pointee - -// use core::marker::CoercePointee; - -// #[derive(CoercePointee)] -// enum Enum {} - -// #[derive(CoercePointee)] -// struct Struct1; - -// #[derive(CoercePointee)] -// struct Struct2(); - -// #[derive(CoercePointee)] -// struct Struct3 {} - -// #[derive(CoercePointee)] -// struct Struct4(T); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct5(i32); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct7(T, U); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct8<#[pointee] T, U: ?Sized>(T); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct9(T); - -// #[derive(CoercePointee)] -// #[repr(transparent)] -// struct Struct9<#[pointee] T, U>(T) where T: ?Sized; -// "#, -// expect![[r#" -// 35..72: `CoercePointee` can only be derived on `struct`s -// 74..114: `CoercePointee` can only be derived on `struct`s with at least one field -// 116..158: `CoercePointee` can only be derived on `struct`s with at least one field -// 160..202: `CoercePointee` can only be derived on `struct`s with at least one field -// 204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` -// 260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type -// 328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits -// 441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits -// 532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized` -// 623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]], -// ); -// } - -// #[test] -// fn union_derive() { -// check_errors( -// r#" -// //- minicore: clone, copy, default, fmt, hash, ord, eq, derive - -// #[derive(Copy)] -// union Foo1 { _v: () } -// #[derive(Clone)] -// union Foo2 { _v: () } -// #[derive(Default)] -// union Foo3 { _v: () } -// #[derive(Debug)] -// union Foo4 { _v: () } -// #[derive(Hash)] -// union Foo5 { _v: () } -// #[derive(Ord)] -// union Foo6 { _v: () } -// #[derive(PartialOrd)] -// union Foo7 { _v: () } -// #[derive(Eq)] -// union Foo8 { _v: () } -// #[derive(PartialEq)] -// union Foo9 { _v: () } -// "#, -// expect![[r#" -// 78..118: this trait cannot be derived for unions -// 119..157: this trait cannot be derived for unions -// 158..195: this trait cannot be derived for unions -// 196..232: this trait cannot be derived for unions -// 233..276: this trait cannot be derived for unions -// 313..355: this trait cannot be derived for unions"#]], -// ); -// } - -// #[test] -// fn default_enum_without_default_attr() { -// check_errors( -// r#" -// //- minicore: default, derive - -// #[derive(Default)] -// enum Foo { -// Bar, -// } -// "#, -// expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"], -// ); -// } - -// #[test] -// fn generic_enum_default() { -// check( -// r#" -// //- minicore: default, derive - -// #[derive(Default)] -// enum Foo { -// Bar(T), -// #[default] -// Baz, -// } -// "#, -// expect![[r#" - -// #[derive(Default)] -// enum Foo { -// Bar(T), -// #[default] -// Baz, -// } - -// impl $crate::default::Default for Foo where { -// fn default() -> Self { -// Foo::Baz -// } -// }"#]], -// ); -// } +use expect_test::expect; + +use crate::macro_expansion_tests::{check, check_errors}; + +#[test] +fn test_copy_expand_simple() { + check( + r#" +//- minicore: derive, copy +#[derive(Copy)] +struct Foo; +"#, + expect![[r#" +#[derive(Copy)] +struct Foo; + +impl <> $crate::marker::Copy for Foo< > where {}"#]], + ); +} + +#[test] +fn test_copy_expand_in_core() { + check( + r#" +//- /lib.rs crate:core +#[rustc_builtin_macro] +macro derive {} +#[rustc_builtin_macro] +macro Copy {} +#[derive(Copy)] +struct Foo; +"#, + expect![[r#" +#[rustc_builtin_macro] +macro derive {} +#[rustc_builtin_macro] +macro Copy {} +#[derive(Copy)] +struct Foo; + +impl <> $crate::marker::Copy for Foo< > where {}"#]], + ); +} + +#[test] +fn test_copy_expand_with_type_params() { + check( + r#" +//- minicore: derive, copy +#[derive(Copy)] +struct Foo; +"#, + expect![[r#" +#[derive(Copy)] +struct Foo; + +impl $crate::marker::Copy for Foo where {}"#]], + ); +} + +#[test] +fn test_copy_expand_with_lifetimes() { + // We currently just ignore lifetimes + check( + r#" +//- minicore: derive, copy +#[derive(Copy)] +struct Foo; +"#, + expect![[r#" +#[derive(Copy)] +struct Foo; + +impl $crate::marker::Copy for Foo where {}"#]], + ); +} + +#[test] +fn test_clone_expand() { + check( + r#" +//- minicore: derive, clone +#[derive(Clone)] +enum Command { + Move { x: A, y: B }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive(Clone)] +enum Command { + Move { x: A, y: B }, + Do(&'static str), + Jump, +} + +impl $crate::clone::Clone for Command where { + fn clone(&self ) -> Self { + match self { + Command::Move { + x: x, y: y, + } + =>Command::Move { + x: x.clone(), y: y.clone(), + } + , Command::Do(f0, )=>Command::Do(f0.clone(), ), Command::Jump=>Command::Jump, + } + } +}"#]], + ); +} + +#[test] +fn test_clone_expand_with_associated_types() { + check( + r#" +//- minicore: derive, clone +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec(T); + +#[derive(Clone)] +struct Foo +where + ::InWc: Marker, +{ + qualified: ::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec, +} +"#, + expect![[r#" +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec(T); + +#[derive(Clone)] +struct Foo +where + ::InWc: Marker, +{ + qualified: ::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec, +} + +impl $crate::clone::Clone for Foo where ::InWc: Marker, T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { + fn clone(&self ) -> Self { + match self { + Foo { + qualified: qualified, shorthand: shorthand, generic: generic, + } + =>Foo { + qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), + } + , + } + } +}"#]], + ); +} + +#[test] +fn test_clone_expand_with_const_generics() { + check( + r#" +//- minicore: derive, clone +#[derive(Clone)] +struct Foo(u32); +"#, + expect![[r#" +#[derive(Clone)] +struct Foo(u32); + +impl $crate::clone::Clone for Foo where { + fn clone(&self ) -> Self { + match self { + Foo(f0, )=>Foo(f0.clone(), ), + } + } +}"#]], + ); +} + +#[test] +fn test_default_expand() { + check( + r#" +//- minicore: derive, default +#[derive(Default)] +struct Foo { + field1: i32, + field2: (), +} +#[derive(Default)] +enum Bar { + Foo(u8), + #[default] + Bar, +} +"#, + expect![[r#" +#[derive(Default)] +struct Foo { + field1: i32, + field2: (), +} +#[derive(Default)] +enum Bar { + Foo(u8), + #[default] + Bar, +} + +impl <> $crate::default::Default for Foo< > where { + fn default() -> Self { + Foo { + field1: $crate::default::Default::default(), field2: $crate::default::Default::default(), + } + } +} +impl <> $crate::default::Default for Bar< > where { + fn default() -> Self { + Bar::Bar + } +}"#]], + ); +} + +#[test] +fn test_partial_eq_expand() { + check( + r#" +//- minicore: derive, eq +#[derive(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl <> $crate::cmp::PartialEq for Command< > where { + fn eq(&self , other: &Self ) -> bool { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false + } + } +} +impl <> $crate::cmp::Eq for Command< > where {}"#]], + ); +} + +#[test] +fn test_partial_eq_expand_with_derive_const() { + // FIXME: actually expand with const + check( + r#" +//- minicore: derive, eq +#[derive_const(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive_const(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl <> $crate::cmp::PartialEq for Command< > where { + fn eq(&self , other: &Self ) -> bool { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false + } + } +} +impl <> $crate::cmp::Eq for Command< > where {}"#]], + ); +} + +#[test] +fn test_partial_ord_expand() { + check( + r#" +//- minicore: derive, ord +#[derive(PartialOrd, Ord)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive(PartialOrd, Ord)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl <> $crate::cmp::PartialOrd for Command< > where { + fn partial_cmp(&self , other: &Self ) -> $crate::option::Option<$crate::cmp::Ordering> { + match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>match x_self.partial_cmp(&x_other) { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + match y_self.partial_cmp(&y_other) { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + $crate::option::Option::Some($crate::cmp::Ordering::Equal) + } + c=>return c, + } + } + c=>return c, + } + , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + $crate::option::Option::Some($crate::cmp::Ordering::Equal) + } + c=>return c, + } + , (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal) + } + } + c=>return c, + } + } +} +impl <> $crate::cmp::Ord for Command< > where { + fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering { + match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) { + $crate::cmp::Ordering::Equal=> { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>match x_self.cmp(&x_other) { + $crate::cmp::Ordering::Equal=> { + match y_self.cmp(&y_other) { + $crate::cmp::Ordering::Equal=> { + $crate::cmp::Ordering::Equal + } + c=>return c, + } + } + c=>return c, + } + , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { + $crate::cmp::Ordering::Equal=> { + $crate::cmp::Ordering::Equal + } + c=>return c, + } + , (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal + } + } + c=>return c, + } + } +}"#]], + ); +} + +#[test] +fn test_hash_expand() { + check( + r#" +//- minicore: derive, hash +use core::hash::Hash; + +#[derive(Hash)] +struct Foo { + x: i32, + y: u64, + z: (i32, u64), +} +"#, + expect![[r#" +use core::hash::Hash; + +#[derive(Hash)] +struct Foo { + x: i32, + y: u64, + z: (i32, u64), +} + +impl <> $crate::hash::Hash for Foo< > where { + fn hash(&self , ra_expand_state: &mut H) { + match self { + Foo { + x: x, y: y, z: z, + } + => { + x.hash(ra_expand_state); + y.hash(ra_expand_state); + z.hash(ra_expand_state); + } + , + } + } +}"#]], + ); + check( + r#" +//- minicore: derive, hash +use core::hash::Hash; + +#[derive(Hash)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +use core::hash::Hash; + +#[derive(Hash)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl <> $crate::hash::Hash for Command< > where { + fn hash(&self , ra_expand_state: &mut H) { + $crate::mem::discriminant(self ).hash(ra_expand_state); + match self { + Command::Move { + x: x, y: y, + } + => { + x.hash(ra_expand_state); + y.hash(ra_expand_state); + } + , Command::Do(f0, )=> { + f0.hash(ra_expand_state); + } + , Command::Jump=> {} + , + } + } +}"#]], + ); +} + +#[test] +fn test_debug_expand() { + check( + r#" +//- minicore: derive, fmt +use core::fmt::Debug; + +#[derive(Debug)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +use core::fmt::Debug; + +#[derive(Debug)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl <> $crate::fmt::Debug for Command< > where { + fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { + match self { + Command::Move { + x: x, y: y, + } + =>f.debug_struct("Move").field("x", &x).field("y", &y).finish(), Command::Do(f0, )=>f.debug_tuple("Do").field(&f0).finish(), Command::Jump=>f.write_str("Jump"), + } + } +}"#]], + ); +} +#[test] +fn test_debug_expand_with_cfg() { + check( + r#" + //- minicore: derive, fmt + use core::fmt::Debug; + + #[derive(Debug)] + struct HideAndShow { + #[cfg(never)] + always_hide: u32, + #[cfg(not(never))] + always_show: u32, + } + #[derive(Debug)] + enum HideAndShowEnum { + #[cfg(never)] + AlwaysHide, + #[cfg(not(never))] + AlwaysShow{ + #[cfg(never)] + always_hide: u32, + #[cfg(not(never))] + always_show: u32, + } + } + "#, + expect![[r#" +use core::fmt::Debug; + +#[derive(Debug)] +struct HideAndShow { + #[cfg(never)] + always_hide: u32, + #[cfg(not(never))] + always_show: u32, +} +#[derive(Debug)] +enum HideAndShowEnum { + #[cfg(never)] + AlwaysHide, + #[cfg(not(never))] + AlwaysShow{ + #[cfg(never)] + always_hide: u32, + #[cfg(not(never))] + always_show: u32, + } +} + +impl <> $crate::fmt::Debug for HideAndShow< > where { + fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { + match self { + HideAndShow { + always_show: always_show, + } + =>f.debug_struct("HideAndShow").field("always_show", &always_show).finish() + } + } +} +impl <> $crate::fmt::Debug for HideAndShowEnum< > where { + fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { + match self { + HideAndShowEnum::AlwaysShow { + always_show: always_show, + } + =>f.debug_struct("AlwaysShow").field("always_show", &always_show).finish(), + } + } +}"#]], + ); +} +#[test] +fn test_default_expand_with_cfg() { + check( + r#" +//- minicore: derive, default +#[derive(Default)] +struct Foo { + field1: i32, + #[cfg(never)] + field2: (), + #[cfg(feature = "never")] + field3: (), + #[cfg(not(feature = "never"))] + field4: (), +} +#[derive(Default)] +enum Bar { + Foo, + #[cfg_attr(not(never), default)] + Bar, +} +"#, + expect![[r##" +#[derive(Default)] +struct Foo { + field1: i32, + #[cfg(never)] + field2: (), + #[cfg(feature = "never")] + field3: (), + #[cfg(not(feature = "never"))] + field4: (), +} +#[derive(Default)] +enum Bar { + Foo, + #[cfg_attr(not(never), default)] + Bar, +} + +impl <> $crate::default::Default for Foo< > where { + fn default() -> Self { + Foo { + field1: $crate::default::Default::default(), field4: $crate::default::Default::default(), + } + } +} +impl <> $crate::default::Default for Bar< > where { + fn default() -> Self { + Bar::Bar + } +}"##]], + ); +} + +#[test] +fn coerce_pointee_expansion() { + check( + r#" +//- minicore: coerce_pointee + +use core::marker::CoercePointee; + +pub trait Trait {} + +#[derive(CoercePointee)] +#[repr(transparent)] +pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) +where + U: Trait + ToString;"#, + expect![[r#" + +use core::marker::CoercePointee; + +pub trait Trait {} + +#[derive(CoercePointee)] +#[repr(transparent)] +pub struct Foo<'a, T: ?Sized + Trait, #[pointee] U: ?Sized, const N: u32>(T) +where + U: Trait + ToString; +impl $crate::ops::DispatchFromDyn> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {} +impl $crate::ops::CoerceUnsized> for Foo where U: Trait +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait, U:?Sized, {}"#]], + ); +} + +#[test] +fn coerce_pointee_errors() { + check_errors( + r#" +//- minicore: coerce_pointee + +use core::marker::CoercePointee; + +#[derive(CoercePointee)] +enum Enum {} + +#[derive(CoercePointee)] +struct Struct1; + +#[derive(CoercePointee)] +struct Struct2(); + +#[derive(CoercePointee)] +struct Struct3 {} + +#[derive(CoercePointee)] +struct Struct4(T); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct5(i32); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct7(T, U); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct8<#[pointee] T, U: ?Sized>(T); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct9(T); + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Struct9<#[pointee] T, U>(T) where T: ?Sized; +"#, + expect![[r#" + 35..72: `CoercePointee` can only be derived on `struct`s + 74..114: `CoercePointee` can only be derived on `struct`s with at least one field + 116..158: `CoercePointee` can only be derived on `struct`s with at least one field + 160..202: `CoercePointee` can only be derived on `struct`s with at least one field + 204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + 260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type + 328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits + 441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits + 532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized` + 623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]], + ); +} + +#[test] +fn union_derive() { + check_errors( + r#" +//- minicore: clone, copy, default, fmt, hash, ord, eq, derive + +#[derive(Copy)] +union Foo1 { _v: () } +#[derive(Clone)] +union Foo2 { _v: () } +#[derive(Default)] +union Foo3 { _v: () } +#[derive(Debug)] +union Foo4 { _v: () } +#[derive(Hash)] +union Foo5 { _v: () } +#[derive(Ord)] +union Foo6 { _v: () } +#[derive(PartialOrd)] +union Foo7 { _v: () } +#[derive(Eq)] +union Foo8 { _v: () } +#[derive(PartialEq)] +union Foo9 { _v: () } + "#, + expect![[r#" + 78..118: this trait cannot be derived for unions + 119..157: this trait cannot be derived for unions + 158..195: this trait cannot be derived for unions + 196..232: this trait cannot be derived for unions + 233..276: this trait cannot be derived for unions + 313..355: this trait cannot be derived for unions"#]], + ); +} + +#[test] +fn default_enum_without_default_attr() { + check_errors( + r#" +//- minicore: default, derive + +#[derive(Default)] +enum Foo { + Bar, +} + "#, + expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"], + ); +} + +#[test] +fn generic_enum_default() { + check( + r#" +//- minicore: default, derive + +#[derive(Default)] +enum Foo { + Bar(T), + #[default] + Baz, +} +"#, + expect![[r#" + +#[derive(Default)] +enum Foo { + Bar(T), + #[default] + Baz, +} + +impl $crate::default::Default for Foo where { + fn default() -> Self { + Foo::Baz + } +}"#]], + ); +} diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index 59bd9474a9..fa4409e117 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -53,6 +53,8 @@ use crate::{ #[track_caller] fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false); + let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); let def_map = crate_def_map(&db, krate); @@ -80,10 +82,15 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) .sorted_unstable_by_key(|(range, _)| range.start()) .format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}"))) .to_string(); + + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true); + expect.assert_eq(&errors); } fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false); + let extra_proc_macros = vec![( r#" #[proc_macro_attribute] @@ -246,6 +253,8 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } } + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true); + expect.indent(false); expect.assert_eq(&expanded_text); } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 3f29619bcb..59ca38c7c0 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -87,6 +87,25 @@ use crate::{ pub use self::path_resolution::ResolvePathResultPrefixInfo; +#[cfg(test)] +thread_local! { + /// HACK: In order to test builtin derive expansion, we gate their fast path with this atomic when cfg(test). + pub(crate) static ENABLE_BUILTIN_DERIVE_FAST_PATH: std::cell::Cell = + const { std::cell::Cell::new(true) }; +} + +#[inline] +#[cfg(test)] +fn enable_builtin_derive_fast_path() -> bool { + ENABLE_BUILTIN_DERIVE_FAST_PATH.get() +} + +#[inline(always)] +#[cfg(not(test))] +fn enable_builtin_derive_fast_path() -> bool { + true +} + const PREDEFINED_TOOLS: &[SmolStr] = &[ SmolStr::new_static("clippy"), SmolStr::new_static("rustfmt"), diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 8694ebe4e4..a7f687a316 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1526,8 +1526,9 @@ impl<'db> DefCollector<'db> { } } - if let MacroDefKind::BuiltInDerive(_, builtin_derive) = - def_id.kind + if super::enable_builtin_derive_fast_path() + && let MacroDefKind::BuiltInDerive(_, builtin_derive) = + def_id.kind { self.deferred_builtin_derives .entry(ast_id.ast_id.upcast())