1use 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 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 const_ty: Option<tt::TopSubtree>,
228 bounds: Option<tt::TopSubtree>,
229}
230
231fn 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 ¶m {
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 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
421fn 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
722fn fat_arrow(span: Span) -> tt::TopSubtree {
724 let eq = tt::Punct { char: '=', spacing: ::tt::Spacing::Joint, span };
725 quote! {span => #eq> }
726}
727
728fn 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 (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 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 for param in &type_params {
1309 let Some(param_name) = param.name() else { continue };
1310 if let Some(bounds) = param.type_bound_list() {
1311 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 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 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 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 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 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 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 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}