Skip to main content

hir_expand/builtin/
derive_macro.rs

1//! Builtin derives.
2
3use base_db::SourceDatabase;
4use either::Either;
5use intern::sym;
6use itertools::{Itertools, izip};
7use parser::SyntaxKind;
8use rustc_hash::{FxHashMap, FxHashSet};
9use span::{Edition, Span};
10use stdx::never;
11use syntax_bridge::DocCommentDesugarMode;
12use tracing::debug;
13
14use crate::{
15    ExpandError, ExpandResult, MacroCallId,
16    builtin::quote::dollar_crate,
17    hygiene::span_with_def_site_ctxt,
18    name::{self, AsName, Name},
19    span_map::ExpansionSpanMap,
20    tt,
21};
22use syntax::{
23    ast::{
24        self, AstNode, FieldList, HasAttrs, HasGenericArgs, HasGenericParams, HasModuleItem,
25        HasName, HasTypeBounds,
26    },
27    syntax_editor::{GetOrCreateWhereClause, SyntaxEditor},
28};
29
30macro_rules! register_builtin {
31    ( $($trait:ident => $expand:ident),* $(,)? ) => {
32        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33        pub enum BuiltinDeriveExpander {
34            $($trait),*
35        }
36
37        impl BuiltinDeriveExpander {
38            pub fn expander(&self) -> fn(&dyn SourceDatabase, Span, &tt::TopSubtree) -> ExpandResult<tt::TopSubtree>  {
39                match *self {
40                    $( BuiltinDeriveExpander::$trait => $expand, )*
41                }
42            }
43
44            fn find_by_name(name: &name::Name) -> Option<Self> {
45                match name {
46                    $( id if id == &sym::$trait => Some(BuiltinDeriveExpander::$trait), )*
47                     _ => None,
48                }
49            }
50        }
51    };
52}
53
54impl BuiltinDeriveExpander {
55    pub fn expand(
56        &self,
57        db: &dyn SourceDatabase,
58        id: MacroCallId,
59        tt: &tt::TopSubtree,
60        span: Span,
61    ) -> ExpandResult<tt::TopSubtree> {
62        let span = span_with_def_site_ctxt(db, span, id.into(), Edition::CURRENT);
63        self.expander()(db, span, tt)
64    }
65}
66
67register_builtin! {
68    Copy => copy_expand,
69    Clone => clone_expand,
70    Default => default_expand,
71    Debug => debug_expand,
72    Hash => hash_expand,
73    Ord => ord_expand,
74    PartialOrd => partial_ord_expand,
75    Eq => eq_expand,
76    PartialEq => partial_eq_expand,
77    CoercePointee => coerce_pointee_expand,
78    Reborrow => reborrow_expand,
79    CoerceShared => coerce_shared_expand,
80}
81
82pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander> {
83    BuiltinDeriveExpander::find_by_name(ident)
84}
85
86#[derive(Clone)]
87enum VariantShape {
88    Struct(Vec<tt::Ident>),
89    Tuple(usize),
90    Unit,
91}
92
93fn tuple_field_iterator(span: Span, n: usize) -> impl Iterator<Item = tt::Ident> {
94    (0..n).map(move |it| tt::Ident::new(&format!("f{it}"), span))
95}
96
97impl VariantShape {
98    fn as_pattern(&self, path: tt::TopSubtree, span: Span) -> tt::TopSubtree {
99        self.as_pattern_map(path, span, |it| quote!(span => #it))
100    }
101
102    fn field_names(&self, span: Span) -> Vec<tt::Ident> {
103        match self {
104            VariantShape::Struct(s) => s.clone(),
105            VariantShape::Tuple(n) => tuple_field_iterator(span, *n).collect(),
106            VariantShape::Unit => vec![],
107        }
108    }
109
110    fn as_pattern_map(
111        &self,
112        path: tt::TopSubtree,
113        span: Span,
114        field_map: impl Fn(&tt::Ident) -> tt::TopSubtree,
115    ) -> tt::TopSubtree {
116        match self {
117            VariantShape::Struct(fields) => {
118                let fields = fields.iter().map(|it| {
119                    let mapped = field_map(it);
120                    quote! {span => #it : #mapped , }
121                });
122                quote! {span =>
123                    #path { # #fields }
124                }
125            }
126            &VariantShape::Tuple(n) => {
127                let fields = tuple_field_iterator(span, n).map(|it| {
128                    let mapped = field_map(&it);
129                    quote! {span =>
130                        #mapped ,
131                    }
132                });
133                quote! {span =>
134                    #path ( # #fields )
135                }
136            }
137            VariantShape::Unit => path,
138        }
139    }
140
141    fn from(
142        call_site: Span,
143        tm: &ExpansionSpanMap,
144        value: Option<FieldList>,
145    ) -> Result<Self, ExpandError> {
146        let r = match value {
147            None => VariantShape::Unit,
148            Some(FieldList::RecordFieldList(it)) => VariantShape::Struct(
149                it.fields()
150                    .map(|it| it.name())
151                    .map(|it| name_to_token(call_site, tm, it))
152                    .collect::<Result<_, _>>()?,
153            ),
154            Some(FieldList::TupleFieldList(it)) => VariantShape::Tuple(it.fields().count()),
155        };
156        Ok(r)
157    }
158}
159
160#[derive(Clone)]
161enum AdtShape {
162    Struct(VariantShape),
163    Enum { variants: Vec<(tt::Ident, VariantShape)>, default_variant: Option<usize> },
164    Union,
165}
166
167impl AdtShape {
168    fn as_pattern(&self, span: Span, name: &tt::Ident) -> Vec<tt::TopSubtree> {
169        self.as_pattern_map(name, |it| quote!(span =>#it), span)
170    }
171
172    fn field_names(&self, span: Span) -> Vec<Vec<tt::Ident>> {
173        match self {
174            AdtShape::Struct(s) => {
175                vec![s.field_names(span)]
176            }
177            AdtShape::Enum { variants, .. } => {
178                variants.iter().map(|(_, fields)| fields.field_names(span)).collect()
179            }
180            AdtShape::Union => {
181                never!("using fields of union in derive is always wrong");
182                vec![]
183            }
184        }
185    }
186
187    fn as_pattern_map(
188        &self,
189        name: &tt::Ident,
190        field_map: impl Fn(&tt::Ident) -> tt::TopSubtree,
191        span: Span,
192    ) -> Vec<tt::TopSubtree> {
193        match self {
194            AdtShape::Struct(s) => {
195                vec![s.as_pattern_map(quote! {span => #name }, span, field_map)]
196            }
197            AdtShape::Enum { variants, .. } => variants
198                .iter()
199                .map(|(v, fields)| {
200                    fields.as_pattern_map(quote! {span => #name :: #v }, span, &field_map)
201                })
202                .collect(),
203            AdtShape::Union => {
204                never!("pattern matching on union is always wrong");
205                vec![quote! {span => un }]
206            }
207        }
208    }
209}
210
211#[derive(Clone)]
212struct BasicAdtInfo {
213    name: tt::Ident,
214    shape: AdtShape,
215    /// first field is the name, and
216    /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
217    /// third fields is where bounds, if any
218    param_types: Vec<AdtParam>,
219    where_clause: Vec<tt::TopSubtree>,
220    associated_types: Vec<tt::TopSubtree>,
221}
222
223#[derive(Clone)]
224struct AdtParam {
225    name: tt::TopSubtree,
226    /// `None` if this is a type parameter.
227    const_ty: Option<tt::TopSubtree>,
228    bounds: Option<tt::TopSubtree>,
229}
230
231// FIXME: This whole thing needs a refactor. Each derive requires its special values, and the result is a mess.
232fn parse_adt(
233    db: &dyn SourceDatabase,
234    tt: &tt::TopSubtree,
235    call_site: Span,
236) -> Result<BasicAdtInfo, ExpandError> {
237    let (adt, tm) = to_adt_syntax(db, tt, call_site)?;
238    parse_adt_from_syntax(&adt, &tm, call_site)
239}
240
241fn parse_adt_from_syntax(
242    adt: &ast::Adt,
243    tm: &span::SpanMap,
244    call_site: Span,
245) -> Result<BasicAdtInfo, ExpandError> {
246    let (name, generic_param_list, where_clause, shape) = match &adt {
247        ast::Adt::Struct(it) => (
248            it.name(),
249            it.generic_param_list(),
250            it.where_clause(),
251            AdtShape::Struct(VariantShape::from(call_site, tm, it.field_list())?),
252        ),
253        ast::Adt::Enum(it) => {
254            let default_variant = it
255                .variant_list()
256                .into_iter()
257                .flat_map(|it| it.variants())
258                .position(|it| it.attrs().any(|it| it.simple_name() == Some("default".into())));
259            (
260                it.name(),
261                it.generic_param_list(),
262                it.where_clause(),
263                AdtShape::Enum {
264                    default_variant,
265                    variants: it
266                        .variant_list()
267                        .into_iter()
268                        .flat_map(|it| it.variants())
269                        .map(|it| {
270                            Ok((
271                                name_to_token(call_site, tm, it.name())?,
272                                VariantShape::from(call_site, tm, it.field_list())?,
273                            ))
274                        })
275                        .collect::<Result<_, ExpandError>>()?,
276                },
277            )
278        }
279        ast::Adt::Union(it) => {
280            (it.name(), it.generic_param_list(), it.where_clause(), AdtShape::Union)
281        }
282    };
283
284    let mut param_type_set: FxHashSet<Name> = FxHashSet::default();
285    let param_types = generic_param_list
286        .into_iter()
287        .flat_map(|param_list| param_list.type_or_const_params())
288        .map(|param| {
289            let name = {
290                let this = param.name();
291                match this {
292                    Some(it) => {
293                        param_type_set.insert(it.as_name());
294                        syntax_bridge::syntax_node_to_token_tree(
295                            it.syntax(),
296                            tm,
297                            call_site,
298                            DocCommentDesugarMode::ProcMacro,
299                        )
300                    }
301                    None => {
302                        tt::TopSubtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
303                    }
304                }
305            };
306            let bounds = match &param {
307                ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| {
308                    syntax_bridge::syntax_node_to_token_tree(
309                        it.syntax(),
310                        tm,
311                        call_site,
312                        DocCommentDesugarMode::ProcMacro,
313                    )
314                }),
315                ast::TypeOrConstParam::Const(_) => None,
316            };
317            let const_ty = if let ast::TypeOrConstParam::Const(param) = param {
318                let ty = param
319                    .ty()
320                    .map(|ty| {
321                        syntax_bridge::syntax_node_to_token_tree(
322                            ty.syntax(),
323                            tm,
324                            call_site,
325                            DocCommentDesugarMode::ProcMacro,
326                        )
327                    })
328                    .unwrap_or_else(|| {
329                        tt::TopSubtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
330                    });
331                Some(ty)
332            } else {
333                None
334            };
335            AdtParam { name, const_ty, bounds }
336        })
337        .collect();
338
339    let where_clause = if let Some(w) = where_clause {
340        w.predicates()
341            .map(|it| {
342                syntax_bridge::syntax_node_to_token_tree(
343                    it.syntax(),
344                    tm,
345                    call_site,
346                    DocCommentDesugarMode::ProcMacro,
347                )
348            })
349            .collect()
350    } else {
351        vec![]
352    };
353
354    // For a generic parameter `T`, when shorthand associated type `T::Assoc` appears in field
355    // types (of any variant for enums), we generate trait bound for it. It sounds reasonable to
356    // also generate trait bound for qualified associated type `<T as Trait>::Assoc`, but rustc
357    // does not do that for some unknown reason.
358    //
359    // See the analogous function in rustc [find_type_parameters()] and rust-lang/rust#50730.
360    // [find_type_parameters()]: https://github.com/rust-lang/rust/blob/1.70.0/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs#L378
361
362    // It's cumbersome to deal with the distinct structures of ADTs, so let's just get untyped
363    // `SyntaxNode` that contains fields and look for descendant `ast::PathType`s. Of note is that
364    // we should not inspect `ast::PathType`s in parameter bounds and where clauses.
365    let field_list = match adt {
366        ast::Adt::Enum(it) => it.variant_list().map(|list| list.syntax().clone()),
367        ast::Adt::Struct(it) => it.field_list().map(|list| list.syntax().clone()),
368        ast::Adt::Union(it) => it.record_field_list().map(|list| list.syntax().clone()),
369    };
370    let associated_types = field_list
371        .into_iter()
372        .flat_map(|it| it.descendants())
373        .filter_map(ast::PathType::cast)
374        .filter_map(|p| {
375            let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name();
376            param_type_set.contains(&name).then_some(p)
377        })
378        .map(|it| {
379            syntax_bridge::syntax_node_to_token_tree(
380                it.syntax(),
381                tm,
382                call_site,
383                DocCommentDesugarMode::ProcMacro,
384            )
385        })
386        .collect();
387    let name_token = name_to_token(call_site, tm, name)?;
388    Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types })
389}
390
391fn to_adt_syntax(
392    db: &dyn SourceDatabase,
393    tt: &tt::TopSubtree,
394    call_site: Span,
395) -> Result<(ast::Adt, span::SpanMap), ExpandError> {
396    let (parsed, tm) = crate::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items);
397    let macro_items = ast::MacroItems::cast(parsed.syntax_node())
398        .ok_or_else(|| ExpandError::other(call_site, "invalid item definition"))?;
399    let item =
400        macro_items.items().next().ok_or_else(|| ExpandError::other(call_site, "no item found"))?;
401    let adt = ast::Adt::cast(item.syntax().clone())
402        .ok_or_else(|| ExpandError::other(call_site, "expected struct, enum or union"))?;
403    Ok((adt, tm))
404}
405
406fn name_to_token(
407    call_site: Span,
408    token_map: &ExpansionSpanMap,
409    name: Option<ast::Name>,
410) -> Result<tt::Ident, ExpandError> {
411    let name = name.ok_or_else(|| {
412        debug!("parsed item has no name");
413        ExpandError::other(call_site, "missing name")
414    })?;
415    let span = token_map.span_at(name.syntax().text_range().start());
416
417    let name_token = tt::Ident::new(name.text(), span);
418    Ok(name_token)
419}
420
421/// Given that we are deriving a trait `DerivedTrait` for a type like:
422///
423/// ```ignore (only-for-syntax-highlight)
424/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
425///     a: A,
426///     b: B::Item,
427///     b1: <B as DeclaredTrait>::Item,
428///     c1: <C as WhereTrait>::Item,
429///     c2: Option<<C as WhereTrait>::Item>,
430///     ...
431/// }
432/// ```
433///
434/// create an impl like:
435///
436/// ```ignore (only-for-syntax-highlight)
437/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
438///     C:                       WhereTrait,
439///     A: DerivedTrait + B1 + ... + BN,
440///     B: DerivedTrait + B1 + ... + BN,
441///     C: DerivedTrait + B1 + ... + BN,
442///     B::Item:                 DerivedTrait + B1 + ... + BN,
443///     <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
444///     ...
445/// {
446///     ...
447/// }
448/// ```
449///
450/// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and
451/// therefore does not get bound by the derived trait.
452fn expand_simple_derive(
453    db: &dyn SourceDatabase,
454    invoc_span: Span,
455    tt: &tt::TopSubtree,
456    trait_path: tt::TopSubtree,
457    allow_unions: bool,
458    make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree,
459) -> ExpandResult<tt::TopSubtree> {
460    let info = match parse_adt(db, tt, invoc_span) {
461        Ok(info) => info,
462        Err(e) => {
463            return ExpandResult::new(
464                tt::TopSubtree::empty(tt::DelimSpan { open: invoc_span, close: invoc_span }),
465                e,
466            );
467        }
468    };
469    if !allow_unions && matches!(info.shape, AdtShape::Union) {
470        return ExpandResult::new(
471            tt::TopSubtree::empty(tt::DelimSpan::from_single(invoc_span)),
472            ExpandError::other(invoc_span, "this trait cannot be derived for unions"),
473        );
474    }
475    ExpandResult::ok(expand_simple_derive_with_parsed(
476        invoc_span,
477        info,
478        trait_path,
479        make_trait_body,
480        true,
481        tt::TopSubtree::empty(tt::DelimSpan::from_single(invoc_span)),
482    ))
483}
484
485fn expand_simple_derive_with_parsed(
486    invoc_span: Span,
487    info: BasicAdtInfo,
488    trait_path: tt::TopSubtree,
489    make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree,
490    constrain_to_trait: bool,
491    extra_impl_params: tt::TopSubtree,
492) -> tt::TopSubtree {
493    let trait_body = make_trait_body(&info);
494    let mut where_block: Vec<_> =
495        info.where_clause.into_iter().map(|w| quote! {invoc_span => #w , }).collect();
496    let (params, args): (Vec<_>, Vec<_>) = info
497        .param_types
498        .into_iter()
499        .map(|param| {
500            let ident = param.name;
501            if let Some(b) = param.bounds {
502                let ident2 = ident.clone();
503                where_block.push(quote! {invoc_span => #ident2 : #b , });
504            }
505            if let Some(ty) = param.const_ty {
506                let ident2 = ident.clone();
507                (quote! {invoc_span => const #ident : #ty , }, quote! {invoc_span => #ident2 , })
508            } else {
509                let bound = trait_path.clone();
510                let ident2 = ident.clone();
511                let param = if constrain_to_trait {
512                    quote! {invoc_span => #ident : #bound , }
513                } else {
514                    quote! {invoc_span => #ident , }
515                };
516                (param, quote! {invoc_span => #ident2 , })
517            }
518        })
519        .unzip();
520
521    if constrain_to_trait {
522        where_block.extend(info.associated_types.iter().map(|it| {
523            let it = it.clone();
524            let bound = trait_path.clone();
525            quote! {invoc_span => #it : #bound , }
526        }));
527    }
528
529    let name = info.name;
530    quote! {invoc_span =>
531        impl < # #params #extra_impl_params > #trait_path for #name < # #args > where # #where_block { #trait_body }
532    }
533}
534
535fn copy_expand(
536    db: &dyn SourceDatabase,
537    span: Span,
538    tt: &tt::TopSubtree,
539) -> ExpandResult<tt::TopSubtree> {
540    let krate = dollar_crate(span);
541    expand_simple_derive(
542        db,
543        span,
544        tt,
545        quote! {span => #krate::marker::Copy },
546        true,
547        |_| quote! {span =>},
548    )
549}
550
551fn reborrow_expand(
552    db: &dyn SourceDatabase,
553    span: Span,
554    tt: &tt::TopSubtree,
555) -> ExpandResult<tt::TopSubtree> {
556    let krate = dollar_crate(span);
557    expand_reborrow_marker_derive(
558        db,
559        span,
560        tt,
561        quote! {span => #krate::marker::Reborrow },
562        "Reborrow",
563    )
564}
565
566fn coerce_shared_expand(
567    db: &dyn SourceDatabase,
568    span: Span,
569    tt: &tt::TopSubtree,
570) -> ExpandResult<tt::TopSubtree> {
571    let (adt, span_map) = match to_adt_syntax(db, tt, span) {
572        Ok(it) => it,
573        Err(err) => {
574            return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
575        }
576    };
577    let ast::Adt::Struct(strukt) = &adt else {
578        return ExpandResult::new(
579            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
580            ExpandError::other(span, "`CoerceShared` can only be derived on `struct`s"),
581        );
582    };
583    let Some(target) = coerce_shared_target(db, span, strukt) else {
584        return ExpandResult::new(
585            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
586            ExpandError::other(
587                span,
588                "`derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute",
589            ),
590        );
591    };
592    let info = match parse_adt_from_syntax(&adt, &span_map, span) {
593        Ok(it) => it,
594        Err(err) => {
595            return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
596        }
597    };
598
599    let krate = dollar_crate(span);
600    ExpandResult::ok(expand_simple_derive_with_parsed(
601        span,
602        info,
603        quote! {span => #krate::marker::CoerceShared<#target> },
604        |_| quote! {span => },
605        false,
606        tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
607    ))
608}
609
610fn expand_reborrow_marker_derive(
611    db: &dyn SourceDatabase,
612    span: Span,
613    tt: &tt::TopSubtree,
614    trait_path: tt::TopSubtree,
615    trait_name: &'static str,
616) -> ExpandResult<tt::TopSubtree> {
617    let info = match parse_adt(db, tt, span) {
618        Ok(info) => info,
619        Err(err) => {
620            return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
621        }
622    };
623    if !matches!(info.shape, AdtShape::Struct(_)) {
624        return ExpandResult::new(
625            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
626            ExpandError::other(span, format!("`{trait_name}` can only be derived on `struct`s")),
627        );
628    }
629
630    ExpandResult::ok(expand_simple_derive_with_parsed(
631        span,
632        info,
633        trait_path,
634        |_| quote! {span => },
635        false,
636        tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
637    ))
638}
639
640fn coerce_shared_target(
641    db: &dyn SourceDatabase,
642    span: Span,
643    strukt: &ast::Struct,
644) -> Option<tt::TopSubtree> {
645    let mut attrs = strukt
646        .attrs()
647        .filter(|attr| attr.as_simple_call().is_some_and(|(name, _)| name == "coerce_shared"));
648    let attr = attrs.next()?;
649    if attrs.next().is_some() {
650        return None;
651    }
652    let (_, target_tokens) = attr.as_simple_call()?;
653    let l_paren = target_tokens.l_paren_token()?;
654    let r_paren = target_tokens.r_paren_token()?;
655
656    let mut span_map = span::SpanMap::empty();
657    span_map.push(target_tokens.syntax().text_range().start(), span);
658    span_map.push(target_tokens.syntax().text_range().end(), span);
659
660    let remove = FxHashSet::from_iter([l_paren.into(), r_paren.into()]);
661    let target = syntax_bridge::syntax_node_to_token_tree_modified(
662        target_tokens.syntax(),
663        &span_map,
664        FxHashMap::default(),
665        remove,
666        span,
667        DocCommentDesugarMode::ProcMacro,
668        |_, _| (true, Vec::new()),
669    );
670
671    let (parse, _) = crate::token_tree_to_syntax_node(db, &target, crate::ExpandTo::Type);
672    if !parse.errors().is_empty() {
673        return None;
674    }
675    ast::Type::cast(parse.syntax_node())?;
676    Some(target)
677}
678
679fn clone_expand(
680    db: &dyn SourceDatabase,
681    span: Span,
682    tt: &tt::TopSubtree,
683) -> ExpandResult<tt::TopSubtree> {
684    let krate = dollar_crate(span);
685    expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, true, |adt| {
686        if matches!(adt.shape, AdtShape::Union) {
687            let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
688            return quote! {span =>
689                fn clone(&self) -> Self {
690                    #star self
691                }
692            };
693        }
694        if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
695            let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
696            return quote! {span =>
697                fn clone(&self) -> Self {
698                    match #star self {}
699                }
700            };
701        }
702        let name = &adt.name;
703        let patterns = adt.shape.as_pattern(span, name);
704        let exprs = adt.shape.as_pattern_map(name, |it| quote! {span => #it .clone() }, span);
705        let arms = patterns.into_iter().zip(exprs).map(|(pat, expr)| {
706            let fat_arrow = fat_arrow(span);
707            quote! {span =>
708                #pat #fat_arrow #expr,
709            }
710        });
711
712        quote! {span =>
713            fn clone(&self) -> Self {
714                match self {
715                    # #arms
716                }
717            }
718        }
719    })
720}
721
722/// This function exists since `quote! {span => => }` doesn't work.
723fn fat_arrow(span: Span) -> tt::TopSubtree {
724    let eq = tt::Punct { char: '=', spacing: ::tt::Spacing::Joint, span };
725    quote! {span => #eq> }
726}
727
728/// This function exists since `quote! {span => && }` doesn't work.
729fn and_and(span: Span) -> tt::TopSubtree {
730    let and = tt::Punct { char: '&', spacing: ::tt::Spacing::Joint, span };
731    quote! {span => #and& }
732}
733
734fn default_expand(
735    db: &dyn SourceDatabase,
736    span: Span,
737    tt: &tt::TopSubtree,
738) -> ExpandResult<tt::TopSubtree> {
739    let krate = &dollar_crate(span);
740    let adt = match parse_adt(db, tt, span) {
741        Ok(info) => info,
742        Err(e) => {
743            return ExpandResult::new(
744                tt::TopSubtree::empty(tt::DelimSpan { open: span, close: span }),
745                e,
746            );
747        }
748    };
749    let (body, constrain_to_trait) = match &adt.shape {
750        AdtShape::Struct(fields) => {
751            let name = &adt.name;
752            let body = fields.as_pattern_map(
753                quote!(span =>#name),
754                span,
755                |_| quote!(span =>#krate::default::Default::default()),
756            );
757            (body, true)
758        }
759        AdtShape::Enum { default_variant, variants } => {
760            if let Some(d) = default_variant {
761                let (name, fields) = &variants[*d];
762                let adt_name = &adt.name;
763                let body = fields.as_pattern_map(
764                    quote!(span =>#adt_name :: #name),
765                    span,
766                    |_| quote!(span =>#krate::default::Default::default()),
767                );
768                (body, false)
769            } else {
770                return ExpandResult::new(
771                    tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
772                    ExpandError::other(span, "`#[derive(Default)]` on enum with no `#[default]`"),
773                );
774            }
775        }
776        AdtShape::Union => {
777            return ExpandResult::new(
778                tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
779                ExpandError::other(span, "this trait cannot be derived for unions"),
780            );
781        }
782    };
783    ExpandResult::ok(expand_simple_derive_with_parsed(
784        span,
785        adt,
786        quote! {span => #krate::default::Default },
787        |_adt| {
788            quote! {span =>
789                fn default() -> Self {
790                    #body
791                }
792            }
793        },
794        constrain_to_trait,
795        tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
796    ))
797}
798
799fn debug_expand(
800    db: &dyn SourceDatabase,
801    span: Span,
802    tt: &tt::TopSubtree,
803) -> ExpandResult<tt::TopSubtree> {
804    let krate = &dollar_crate(span);
805    expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, false, |adt| {
806        let for_variant = |name: String, v: &VariantShape| match v {
807            VariantShape::Struct(fields) => {
808                let for_fields = fields.iter().map(|it| {
809                    let x_string = it.to_string();
810                    quote! {span =>
811                        .field(#x_string, & #it)
812                    }
813                });
814                quote! {span =>
815                    f.debug_struct(#name) # #for_fields .finish()
816                }
817            }
818            VariantShape::Tuple(n) => {
819                let for_fields = tuple_field_iterator(span, *n).map(|it| {
820                    quote! {span =>
821                        .field( & #it)
822                    }
823                });
824                quote! {span =>
825                    f.debug_tuple(#name) # #for_fields .finish()
826                }
827            }
828            VariantShape::Unit => quote! {span =>
829                f.write_str(#name)
830            },
831        };
832        if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
833            let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
834            return quote! {span =>
835                fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
836                    match #star self {}
837                }
838            };
839        }
840        let arms = match &adt.shape {
841            AdtShape::Struct(fields) => {
842                let fat_arrow = fat_arrow(span);
843                let name = &adt.name;
844                let pat = fields.as_pattern(quote!(span =>#name), span);
845                let expr = for_variant(name.to_string(), fields);
846                vec![quote! {span => #pat #fat_arrow #expr }]
847            }
848            AdtShape::Enum { variants, .. } => variants
849                .iter()
850                .map(|(name, v)| {
851                    let fat_arrow = fat_arrow(span);
852                    let adt_name = &adt.name;
853                    let pat = v.as_pattern(quote!(span =>#adt_name :: #name), span);
854                    let expr = for_variant(name.to_string(), v);
855                    quote! {span =>
856                        #pat #fat_arrow #expr ,
857                    }
858                })
859                .collect(),
860            AdtShape::Union => unreachable!(),
861        };
862        quote! {span =>
863            fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
864                match self {
865                    # #arms
866                }
867            }
868        }
869    })
870}
871
872fn hash_expand(
873    db: &dyn SourceDatabase,
874    span: Span,
875    tt: &tt::TopSubtree,
876) -> ExpandResult<tt::TopSubtree> {
877    let krate = &dollar_crate(span);
878    expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, false, |adt| {
879        if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
880            let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
881            return quote! {span =>
882                fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) {
883                    match #star self {}
884                }
885            };
886        }
887        let arms =
888            adt.shape.as_pattern(span, &adt.name).into_iter().zip(adt.shape.field_names(span)).map(
889                |(pat, names)| {
890                    let expr = {
891                        let it =
892                            names.iter().map(|it| quote! {span => #it . hash(ra_expand_state); });
893                        quote! {span => {
894                            # #it
895                        } }
896                    };
897                    let fat_arrow = fat_arrow(span);
898                    quote! {span =>
899                        #pat #fat_arrow #expr ,
900                    }
901                },
902            );
903        let check_discriminant = if matches!(&adt.shape, AdtShape::Enum { .. }) {
904            quote! {span => #krate::mem::discriminant(self).hash(ra_expand_state); }
905        } else {
906            quote! {span =>}
907        };
908        quote! {span =>
909            fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) {
910                #check_discriminant
911                match self {
912                    # #arms
913                }
914            }
915        }
916    })
917}
918
919fn eq_expand(
920    db: &dyn SourceDatabase,
921    span: Span,
922    tt: &tt::TopSubtree,
923) -> ExpandResult<tt::TopSubtree> {
924    let krate = dollar_crate(span);
925    expand_simple_derive(
926        db,
927        span,
928        tt,
929        quote! {span => #krate::cmp::Eq },
930        true,
931        |_| quote! {span =>},
932    )
933}
934
935fn partial_eq_expand(
936    db: &dyn SourceDatabase,
937    span: Span,
938    tt: &tt::TopSubtree,
939) -> ExpandResult<tt::TopSubtree> {
940    let krate = dollar_crate(span);
941    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, false, |adt| {
942        let name = &adt.name;
943
944        let (self_patterns, other_patterns) = self_and_other_patterns(adt, name, span);
945        let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
946            |(pat1, pat2, names)| {
947                let fat_arrow = fat_arrow(span);
948                let body = match &*names {
949                    [] => {
950                        quote!(span =>true)
951                    }
952                    [first, rest @ ..] => {
953                        let rest = rest.iter().map(|it| {
954                            let t1 = tt::Ident::new(&format!("{}_self", it.sym), it.span);
955                            let t2 = tt::Ident::new(&format!("{}_other", it.sym), it.span);
956                            let and_and = and_and(span);
957                            quote!(span =>#and_and #t1 .eq( #t2 ))
958                        });
959                        let first = {
960                            let t1 = tt::Ident::new(&format!("{}_self", first.sym), first.span);
961                            let t2 = tt::Ident::new(&format!("{}_other", first.sym), first.span);
962                            quote!(span =>#t1 .eq( #t2 ))
963                        };
964                        quote!(span =>#first # #rest)
965                    }
966                };
967                quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
968            },
969        );
970
971        let fat_arrow = fat_arrow(span);
972        quote! {span =>
973            fn eq(&self, other: &Self) -> bool {
974                match (self, other) {
975                    # #arms
976                    _unused #fat_arrow false
977                }
978            }
979        }
980    })
981}
982
983fn self_and_other_patterns(
984    adt: &BasicAdtInfo,
985    name: &tt::Ident,
986    span: Span,
987) -> (Vec<tt::TopSubtree>, Vec<tt::TopSubtree>) {
988    let self_patterns = adt.shape.as_pattern_map(
989        name,
990        |it| {
991            let t = tt::Ident::new(&format!("{}_self", it.sym), it.span);
992            quote!(span =>#t)
993        },
994        span,
995    );
996    let other_patterns = adt.shape.as_pattern_map(
997        name,
998        |it| {
999            let t = tt::Ident::new(&format!("{}_other", it.sym), it.span);
1000            quote!(span =>#t)
1001        },
1002        span,
1003    );
1004    (self_patterns, other_patterns)
1005}
1006
1007fn ord_expand(
1008    db: &dyn SourceDatabase,
1009    span: Span,
1010    tt: &tt::TopSubtree,
1011) -> ExpandResult<tt::TopSubtree> {
1012    let krate = &dollar_crate(span);
1013    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, false, |adt| {
1014        fn compare(
1015            krate: &tt::Ident,
1016            left: tt::TopSubtree,
1017            right: tt::TopSubtree,
1018            rest: tt::TopSubtree,
1019            span: Span,
1020        ) -> tt::TopSubtree {
1021            let fat_arrow1 = fat_arrow(span);
1022            let fat_arrow2 = fat_arrow(span);
1023            quote! {span =>
1024                match #left.cmp(&#right) {
1025                    #krate::cmp::Ordering::Equal #fat_arrow1 {
1026                        #rest
1027                    }
1028                    c #fat_arrow2 return c,
1029                }
1030            }
1031        }
1032        let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
1033        let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
1034            |(pat1, pat2, fields)| {
1035                let mut body = quote!(span =>#krate::cmp::Ordering::Equal);
1036                for f in fields.into_iter().rev() {
1037                    let t1 = tt::Ident::new(&format!("{}_self", f.sym), f.span);
1038                    let t2 = tt::Ident::new(&format!("{}_other", f.sym), f.span);
1039                    body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
1040                }
1041                let fat_arrow = fat_arrow(span);
1042                quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
1043            },
1044        );
1045        let fat_arrow = fat_arrow(span);
1046        let mut body = quote! {span =>
1047            match (self, other) {
1048                # #arms
1049                _unused #fat_arrow #krate::cmp::Ordering::Equal
1050            }
1051        };
1052        if matches!(&adt.shape, AdtShape::Enum { .. }) {
1053            let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
1054            let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
1055            body = compare(krate, left, right, body, span);
1056        }
1057        quote! {span =>
1058            fn cmp(&self, other: &Self) -> #krate::cmp::Ordering {
1059                #body
1060            }
1061        }
1062    })
1063}
1064
1065fn partial_ord_expand(
1066    db: &dyn SourceDatabase,
1067    span: Span,
1068    tt: &tt::TopSubtree,
1069) -> ExpandResult<tt::TopSubtree> {
1070    let krate = &dollar_crate(span);
1071    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, false, |adt| {
1072        fn compare(
1073            krate: &tt::Ident,
1074            left: tt::TopSubtree,
1075            right: tt::TopSubtree,
1076            rest: tt::TopSubtree,
1077            span: Span,
1078        ) -> tt::TopSubtree {
1079            let fat_arrow1 = fat_arrow(span);
1080            let fat_arrow2 = fat_arrow(span);
1081            quote! {span =>
1082                match #left.partial_cmp(&#right) {
1083                    #krate::option::Option::Some(#krate::cmp::Ordering::Equal) #fat_arrow1 {
1084                        #rest
1085                    }
1086                    c #fat_arrow2 return c,
1087                }
1088            }
1089        }
1090        let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
1091        let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
1092
1093        let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
1094        let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
1095            |(pat1, pat2, fields)| {
1096                let mut body =
1097                    quote!(span =>#krate::option::Option::Some(#krate::cmp::Ordering::Equal));
1098                for f in fields.into_iter().rev() {
1099                    let t1 = tt::Ident::new(&format!("{}_self", f.sym), f.span);
1100                    let t2 = tt::Ident::new(&format!("{}_other", f.sym), f.span);
1101                    body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
1102                }
1103                let fat_arrow = fat_arrow(span);
1104                quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
1105            },
1106        );
1107        let fat_arrow = fat_arrow(span);
1108        let body = compare(
1109            krate,
1110            left,
1111            right,
1112            quote! {span =>
1113                match (self, other) {
1114                    # #arms
1115                    _unused #fat_arrow #krate::option::Option::Some(#krate::cmp::Ordering::Equal)
1116                }
1117            },
1118            span,
1119        );
1120        quote! {span =>
1121            fn partial_cmp(&self, other: &Self) -> #krate::option::Option<#krate::cmp::Ordering> {
1122                #body
1123            }
1124        }
1125    })
1126}
1127
1128fn coerce_pointee_expand(
1129    db: &dyn SourceDatabase,
1130    span: Span,
1131    tt: &tt::TopSubtree,
1132) -> ExpandResult<tt::TopSubtree> {
1133    let (adt, _span_map) = match to_adt_syntax(db, tt, span) {
1134        Ok(it) => it,
1135        Err(err) => {
1136            return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
1137        }
1138    };
1139    let (editor, adt) = SyntaxEditor::with_ast_node(&adt);
1140    let make = editor.make();
1141    let ast::Adt::Struct(strukt) = &adt else {
1142        return ExpandResult::new(
1143            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1144            ExpandError::other(span, "`CoercePointee` can only be derived on `struct`s"),
1145        );
1146    };
1147    let has_at_least_one_field = strukt
1148        .field_list()
1149        .map(|it| match it {
1150            ast::FieldList::RecordFieldList(it) => it.fields().next().is_some(),
1151            ast::FieldList::TupleFieldList(it) => it.fields().next().is_some(),
1152        })
1153        .unwrap_or(false);
1154    if !has_at_least_one_field {
1155        return ExpandResult::new(
1156            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1157            ExpandError::other(
1158                span,
1159                "`CoercePointee` can only be derived on `struct`s with at least one field",
1160            ),
1161        );
1162    }
1163    let is_repr_transparent = strukt.attrs().any(|attr| {
1164        attr.as_simple_call().is_some_and(|(name, tt)| {
1165            name == "repr"
1166                && tt.syntax().children_with_tokens().any(|it| {
1167                    it.into_token().is_some_and(|it| {
1168                        it.kind() == SyntaxKind::IDENT && it.text() == "transparent"
1169                    })
1170                })
1171        })
1172    });
1173    if !is_repr_transparent {
1174        return ExpandResult::new(
1175            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1176            ExpandError::other(
1177                span,
1178                "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
1179            ),
1180        );
1181    }
1182    let type_params = strukt
1183        .generic_param_list()
1184        .into_iter()
1185        .flat_map(|generics| {
1186            generics.generic_params().filter_map(|param| match param {
1187                ast::GenericParam::TypeParam(param) => Some(param),
1188                _ => None,
1189            })
1190        })
1191        .collect_vec();
1192    if type_params.is_empty() {
1193        return ExpandResult::new(
1194            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1195            ExpandError::other(
1196                span,
1197                "`CoercePointee` can only be derived on `struct`s that are generic over at least one type",
1198            ),
1199        );
1200    }
1201    let (pointee_param, pointee_param_idx) = if type_params.len() == 1 {
1202        // Regardless of the only type param being designed as `#[pointee]` or not, we can just use it as such.
1203        (type_params[0].clone(), 0)
1204    } else {
1205        let mut pointees = type_params.iter().cloned().enumerate().filter(|(_, param)| {
1206            param.attrs().any(|attr| {
1207                let is_pointee = attr.as_simple_atom().is_some_and(|name| name == "pointee");
1208                if is_pointee {
1209                    // Remove the `#[pointee]` attribute so it won't be present in the generated
1210                    // impls (where we cannot resolve it).
1211                    editor.delete(attr.syntax());
1212                }
1213                is_pointee
1214            })
1215        });
1216        match (pointees.next(), pointees.next()) {
1217            (Some((pointee_idx, pointee)), None) => (pointee, pointee_idx),
1218            (None, _) => {
1219                return ExpandResult::new(
1220                    tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1221                    ExpandError::other(
1222                        span,
1223                        "exactly one generic type parameter must be marked \
1224                                as `#[pointee]` to derive `CoercePointee` traits",
1225                    ),
1226                );
1227            }
1228            (Some(_), Some(_)) => {
1229                return ExpandResult::new(
1230                    tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1231                    ExpandError::other(
1232                        span,
1233                        "only one type parameter can be marked as `#[pointee]` \
1234                                when deriving `CoercePointee` traits",
1235                    ),
1236                );
1237            }
1238        }
1239    };
1240    let (Some(struct_name), Some(pointee_param_name)) = (strukt.name(), pointee_param.name())
1241    else {
1242        return ExpandResult::new(
1243            tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1244            ExpandError::other(span, "invalid item"),
1245        );
1246    };
1247
1248    {
1249        let mut pointee_has_maybe_sized_bound = false;
1250        if let Some(bounds) = pointee_param.type_bound_list() {
1251            pointee_has_maybe_sized_bound |= bounds.bounds().any(is_maybe_sized_bound);
1252        }
1253        if let Some(where_clause) = strukt.where_clause() {
1254            pointee_has_maybe_sized_bound |= where_clause.predicates().any(|pred| {
1255                let Some(ast::Type::PathType(ty)) = pred.ty() else { return false };
1256                let is_not_pointee = ty.path().is_none_or(|path| {
1257                    let is_pointee = path
1258                        .as_single_name_ref()
1259                        .is_some_and(|name| name.text() == pointee_param_name.text());
1260                    !is_pointee
1261                });
1262                if is_not_pointee {
1263                    return false;
1264                }
1265                pred.type_bound_list()
1266                    .is_some_and(|bounds| bounds.bounds().any(is_maybe_sized_bound))
1267            })
1268        }
1269        if !pointee_has_maybe_sized_bound {
1270            return ExpandResult::new(
1271                tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
1272                ExpandError::other(
1273                    span,
1274                    format!(
1275                        "`derive(CoercePointee)` requires `{pointee_param_name}` to be marked `?Sized`"
1276                    ),
1277                ),
1278            );
1279        }
1280    }
1281
1282    const ADDED_PARAM: &str = "__S";
1283
1284    let mut new_predicates: Vec<ast::WherePred> = Vec::new();
1285
1286    {
1287        // # Rewrite generic parameter bounds
1288        // For each bound `U: ..` in `struct<U: ..>`, make a new bound with `__S` in place of `#[pointee]`
1289        // Example:
1290        // ```
1291        // struct<
1292        //     U: Trait<T>,
1293        //     #[pointee] T: Trait<T> + ?Sized,
1294        //     V: Trait<T>> ...
1295        // ```
1296        // ... generates this `impl` generic parameters
1297        // ```
1298        // impl<
1299        //     U: Trait<T>,
1300        //     T: Trait<T> + ?Sized,
1301        //     V: Trait<T>
1302        // >
1303        // where
1304        //     U: Trait<__S>,
1305        //     __S: Trait<__S> + ?Sized,
1306        //     V: Trait<__S> ...
1307        // ```
1308        for param in &type_params {
1309            let Some(param_name) = param.name() else { continue };
1310            if let Some(bounds) = param.type_bound_list() {
1311                // If the target type is the pointee, duplicate the bound as whole.
1312                // Otherwise, duplicate only bounds that mention the pointee.
1313                let is_pointee = param_name.text() == pointee_param_name.text();
1314                let new_bounds = bounds.bounds().filter_map(|bound| {
1315                    let new_bound = substitute_type_bound(
1316                        bound.clone(),
1317                        pointee_param_name.text(),
1318                        ADDED_PARAM,
1319                    );
1320
1321                    if is_pointee {
1322                        return new_bound.or(Some(bound));
1323                    }
1324                    new_bound
1325                });
1326
1327                let new_bounds_target = if is_pointee {
1328                    make.name_ref(ADDED_PARAM)
1329                } else {
1330                    make.name_ref(param_name.text())
1331                };
1332                new_predicates.push(make.where_pred(
1333                    Either::Right(
1334                        make.ty_path_from_segments([make.path_segment(new_bounds_target)], false),
1335                    ),
1336                    new_bounds,
1337                ));
1338            }
1339        }
1340
1341        // # Rewrite `where` clauses
1342        //
1343        // Move on to `where` clauses.
1344        // Example:
1345        // ```
1346        // struct MyPointer<#[pointee] T, ..>
1347        // where
1348        //   U: Trait<V> + Trait<T>,
1349        //   Companion<T>: Trait<T>,
1350        //   T: Trait<T> + ?Sized,
1351        // { .. }
1352        // ```
1353        // ... will have a impl prelude like so
1354        // ```
1355        // impl<..> ..
1356        // where
1357        //   U: Trait<V> + Trait<T>,
1358        //   U: Trait<__S>,
1359        //   Companion<T>: Trait<T>,
1360        //   Companion<__S>: Trait<__S>,
1361        //   T: Trait<T> + ?Sized,
1362        //   __S: Trait<__S> + ?Sized,
1363        // ```
1364        //
1365        // We should also write a few new `where` bounds from `#[pointee] T` to `__S`
1366        // as well as any bound that indirectly involves the `#[pointee] T` type.
1367        for predicate in strukt.where_clause().into_iter().flat_map(|wc| wc.predicates()) {
1368            let Some(pred_target) = predicate.ty() else { continue };
1369
1370            // If the target type references the pointee, duplicate the bound as whole.
1371            // Otherwise, duplicate only bounds that mention the pointee.
1372            if let Some(predicate_with_substituted_target) =
1373                substitute_where_pred(&predicate, pointee_param_name.text(), ADDED_PARAM)
1374            {
1375                new_predicates.push(predicate_with_substituted_target);
1376            } else if let Some(bounds) = predicate.type_bound_list() {
1377                let new_bounds = bounds.bounds().filter_map(|bound| {
1378                    substitute_type_bound(bound, pointee_param_name.text(), ADDED_PARAM)
1379                });
1380                new_predicates.push(make.where_pred(Either::Right(pred_target), new_bounds));
1381            }
1382        }
1383    }
1384
1385    {
1386        // # Add `Unsize<__S>` bound to `#[pointee]` at the generic parameter location
1387        //
1388        // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
1389        new_predicates.push(
1390            make.where_pred(
1391                Either::Right(make.ty_path_from_segments(
1392                    [make.path_segment(make.name_ref(pointee_param_name.text()))],
1393                    false,
1394                )),
1395                [make.type_bound(
1396                    make.ty_path_from_segments(
1397                        [
1398                            make.path_segment(make.name_ref("core")),
1399                            make.path_segment(make.name_ref("marker")),
1400                            make.generic_ty_path_segment(
1401                                make.name_ref("Unsize"),
1402                                [make
1403                                    .type_arg(make.ty_path_from_segments(
1404                                        [make.path_segment(make.name_ref(ADDED_PARAM))],
1405                                        false,
1406                                    ))
1407                                    .into()],
1408                            ),
1409                        ],
1410                        true,
1411                    ),
1412                )],
1413            ),
1414        );
1415    }
1416
1417    let self_for_traits = {
1418        // Replace the `#[pointee]` with `__S`.
1419        let mut type_param_idx = 0;
1420        let self_params_for_traits = strukt
1421            .generic_param_list()
1422            .into_iter()
1423            .flat_map(|params| params.generic_params())
1424            .filter_map(|param| {
1425                Some(match param {
1426                    ast::GenericParam::ConstParam(param) => {
1427                        ast::GenericArg::ConstArg(make.expr_const_value(param.name()?.text()))
1428                    }
1429                    ast::GenericParam::LifetimeParam(param) => {
1430                        make.lifetime_arg(param.lifetime()?).into()
1431                    }
1432                    ast::GenericParam::TypeParam(param) => {
1433                        let name = if pointee_param_idx == type_param_idx {
1434                            make.name_ref(ADDED_PARAM)
1435                        } else {
1436                            make.name_ref(param.name()?.text())
1437                        };
1438                        type_param_idx += 1;
1439                        make.type_arg(make.ty_path_from_segments([make.path_segment(name)], false))
1440                            .into()
1441                    }
1442                })
1443            });
1444
1445        make.path_from_segments(
1446            [make.generic_ty_path_segment(
1447                make.name_ref(struct_name.text()),
1448                self_params_for_traits,
1449            )],
1450            false,
1451        )
1452    };
1453
1454    strukt.get_or_create_where_clause(&editor, new_predicates.into_iter());
1455    let edit = editor.finish();
1456    let strukt = ast::Struct::cast(edit.new_root().clone()).unwrap();
1457    let adt = ast::Adt::Struct(strukt.clone());
1458
1459    let mut span_map = span::SpanMap::empty();
1460    // One span for them all.
1461    span_map.push(adt.syntax().text_range().end(), span);
1462
1463    let self_for_traits = syntax_bridge::syntax_node_to_token_tree(
1464        self_for_traits.syntax(),
1465        &span_map,
1466        span,
1467        DocCommentDesugarMode::ProcMacro,
1468    );
1469    let info = match parse_adt_from_syntax(&adt, &span_map, span) {
1470        Ok(it) => it,
1471        Err(err) => {
1472            return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
1473        }
1474    };
1475
1476    let self_for_traits2 = self_for_traits.clone();
1477    let krate = dollar_crate(span);
1478    let krate2 = krate.clone();
1479    let dispatch_from_dyn = expand_simple_derive_with_parsed(
1480        span,
1481        info.clone(),
1482        quote! {span => #krate2::ops::DispatchFromDyn<#self_for_traits2> },
1483        |_adt| quote! {span => },
1484        false,
1485        quote! {span => __S },
1486    );
1487    let coerce_unsized = expand_simple_derive_with_parsed(
1488        span,
1489        info,
1490        quote! {span => #krate::ops::CoerceUnsized<#self_for_traits> },
1491        |_adt| quote! {span => },
1492        false,
1493        quote! {span => __S },
1494    );
1495    return ExpandResult::ok(quote! {span => #dispatch_from_dyn #coerce_unsized });
1496
1497    fn is_maybe_sized_bound(bound: ast::TypeBound) -> bool {
1498        if bound.question_mark_token().is_none() {
1499            return false;
1500        }
1501        let Some(ast::Type::PathType(ty)) = bound.ty() else {
1502            return false;
1503        };
1504        let Some(path) = ty.path() else {
1505            return false;
1506        };
1507        return segments_eq(&path, &["Sized"])
1508            || segments_eq(&path, &["core", "marker", "Sized"])
1509            || segments_eq(&path, &["std", "marker", "Sized"]);
1510
1511        fn segments_eq(path: &ast::Path, expected: &[&str]) -> bool {
1512            path.segments().zip_longest(expected.iter().copied()).all(|value| {
1513                value.both().is_some_and(|(segment, expected)| {
1514                    segment.name_ref().is_some_and(|name| name.text() == expected)
1515                })
1516            })
1517        }
1518    }
1519
1520    /// Returns true if any substitution was performed.
1521    fn substitute_type_bound(
1522        bound: ast::TypeBound,
1523        param_name: &str,
1524        replacement: &str,
1525    ) -> Option<ast::TypeBound> {
1526        let (editor, bound) = SyntaxEditor::with_ast_node(&bound);
1527        let substituted = bound
1528            .ty()
1529            .is_some_and(|ty| substitute_type_in_bound(&editor, ty, param_name, replacement));
1530        if !substituted {
1531            return None;
1532        }
1533
1534        let edit = editor.finish();
1535        Some(ast::TypeBound::cast(edit.new_root().clone()).unwrap())
1536    }
1537
1538    fn substitute_where_pred(
1539        predicate: &ast::WherePred,
1540        param_name: &str,
1541        replacement: &str,
1542    ) -> Option<ast::WherePred> {
1543        let (editor, predicate) = SyntaxEditor::with_ast_node(predicate);
1544        let substituted = predicate
1545            .ty()
1546            .is_some_and(|ty| substitute_type_in_bound(&editor, ty, param_name, replacement));
1547        if substituted && let Some(bounds) = predicate.type_bound_list() {
1548            for bound in bounds.bounds() {
1549                if let Some(ty) = bound.ty() {
1550                    substitute_type_in_bound(&editor, ty, param_name, replacement);
1551                }
1552            }
1553        }
1554        if !substituted {
1555            return None;
1556        }
1557
1558        let edit = editor.finish();
1559        Some(ast::WherePred::cast(edit.new_root().clone()).unwrap())
1560    }
1561
1562    fn substitute_type_in_bound(
1563        editor: &SyntaxEditor,
1564        ty: ast::Type,
1565        param_name: &str,
1566        replacement: &str,
1567    ) -> bool {
1568        let make = editor.make();
1569        return match ty {
1570            ast::Type::ArrayType(ty) => ty
1571                .ty()
1572                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1573            ast::Type::DynTraitType(ty) => {
1574                go_bounds(editor, ty.type_bound_list(), param_name, replacement)
1575            }
1576            ast::Type::FnPtrType(ty) => any_long(
1577                ty.param_list()
1578                    .into_iter()
1579                    .flat_map(|params| params.params().filter_map(|param| param.ty()))
1580                    .chain(ty.ret_type().and_then(|it| it.ty())),
1581                |ty| substitute_type_in_bound(editor, ty, param_name, replacement),
1582            ),
1583            ast::Type::ForType(ty) => ty
1584                .ty()
1585                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1586            ast::Type::ImplTraitType(ty) => {
1587                go_bounds(editor, ty.type_bound_list(), param_name, replacement)
1588            }
1589            ast::Type::ParenType(ty) => ty
1590                .ty()
1591                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1592            ast::Type::PathType(ty) => ty.path().is_some_and(|path| {
1593                if path.as_single_name_ref().is_some_and(|name| name.text() == param_name) {
1594                    editor.replace(
1595                        path.syntax(),
1596                        make.path_from_segments(
1597                            [make.path_segment(make.name_ref(replacement))],
1598                            false,
1599                        )
1600                        .syntax(),
1601                    );
1602                    return true;
1603                }
1604
1605                any_long(
1606                    path.segments()
1607                        .filter_map(|segment| segment.generic_arg_list())
1608                        .flat_map(|it| it.generic_args())
1609                        .filter_map(|generic_arg| match generic_arg {
1610                            ast::GenericArg::TypeArg(ty) => ty.ty(),
1611                            _ => None,
1612                        }),
1613                    |ty| substitute_type_in_bound(editor, ty, param_name, replacement),
1614                )
1615            }),
1616            ast::Type::PtrType(ty) => ty
1617                .ty()
1618                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1619            ast::Type::RefType(ty) => ty
1620                .ty()
1621                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1622            ast::Type::SliceType(ty) => ty
1623                .ty()
1624                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1625            ast::Type::TupleType(ty) => any_long(ty.fields(), |ty| {
1626                substitute_type_in_bound(editor, ty, param_name, replacement)
1627            }),
1628            ast::Type::PatternType(ty) => ty
1629                .ty()
1630                .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)),
1631            ast::Type::InferType(_) | ast::Type::MacroType(_) | ast::Type::NeverType(_) => false,
1632        };
1633
1634        fn go_bounds(
1635            editor: &SyntaxEditor,
1636            bounds: Option<ast::TypeBoundList>,
1637            param_name: &str,
1638            replacement: &str,
1639        ) -> bool {
1640            bounds.is_some_and(|bounds| {
1641                any_long(bounds.bounds(), |bound| {
1642                    bound.ty().is_some_and(|ty| {
1643                        substitute_type_in_bound(editor, ty, param_name, replacement)
1644                    })
1645                })
1646            })
1647        }
1648
1649        /// Like [`Iterator::any()`], but not short-circuiting.
1650        fn any_long<I: Iterator, F: FnMut(I::Item) -> bool>(iter: I, mut f: F) -> bool {
1651            let mut result = false;
1652            iter.for_each(|item| result |= f(item));
1653            result
1654        }
1655    }
1656}