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 553c0b79533..86b4466153a 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 @@ -157,7 +157,7 @@ where generic: Vec, } -impl $crate::clone::Clone for Foo where T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { +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 { diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 024fb8c1f61..27954875143 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -194,6 +194,7 @@ struct BasicAdtInfo { /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param. /// third fields is where bounds, if any param_types: Vec<(tt::Subtree, Option, Option)>, + where_clause: Vec, associated_types: Vec, } @@ -202,10 +203,11 @@ fn parse_adt( adt: &ast::Adt, call_site: Span, ) -> Result { - let (name, generic_param_list, shape) = match adt { + let (name, generic_param_list, where_clause, shape) = match adt { ast::Adt::Struct(it) => ( it.name(), it.generic_param_list(), + it.where_clause(), AdtShape::Struct(VariantShape::from(tm, it.field_list())?), ), ast::Adt::Enum(it) => { @@ -217,6 +219,7 @@ fn parse_adt( ( it.name(), it.generic_param_list(), + it.where_clause(), AdtShape::Enum { default_variant, variants: it @@ -233,7 +236,9 @@ fn parse_adt( }, ) } - ast::Adt::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), + ast::Adt::Union(it) => { + (it.name(), it.generic_param_list(), it.where_clause(), AdtShape::Union) + } }; let mut param_type_set: FxHashSet = FxHashSet::default(); @@ -274,6 +279,14 @@ fn parse_adt( }) .collect(); + let where_clause = if let Some(w) = where_clause { + w.predicates() + .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)) + .collect() + } else { + vec![] + }; + // For a generic parameter `T`, when shorthand associated type `T::Assoc` appears in field // types (of any variant for enums), we generate trait bound for it. It sounds reasonable to // also generate trait bound for qualified associated type `::Assoc`, but rustc @@ -301,7 +314,7 @@ fn parse_adt( .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)) .collect(); let name_token = name_to_token(tm, name)?; - Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) + Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types }) } fn name_to_token( @@ -366,7 +379,8 @@ fn expand_simple_derive( } }; let trait_body = make_trait_body(&info); - let mut where_block = vec![]; + let mut where_block: Vec<_> = + info.where_clause.into_iter().map(|w| quote! {invoc_span => #w , }).collect(); let (params, args): (Vec<_>, Vec<_>) = info .param_types .into_iter() diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index b0a9361f1c5..2f75338f994 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -1373,3 +1373,34 @@ pub fn attr_macro() {} "#, ); } + +#[test] +fn clone_with_type_bound() { + check_types( + r#" +//- minicore: derive, clone, builtin_impls +#[derive(Clone)] +struct Float; + +trait TensorKind: Clone { + /// The primitive type of the tensor. + type Primitive: Clone; +} + +impl TensorKind for Float { + type Primitive = f64; +} + +#[derive(Clone)] +struct Tensor where K: TensorKind +{ + primitive: K::Primitive, +} + +fn foo(t: Tensor) { + let x = t.clone(); + //^ Tensor +} +"#, + ); +}