1use std::collections::{BTreeMap, BTreeSet};
4
5use proc_macro2::{Span, TokenStream};
6use quote::{format_ident, quote, quote_spanned, ToTokens};
7use syn::{
8 parse::{End, Nothing, Parse, ParseStream},
9 parse_quote, parse_quote_spanned,
10 punctuated::Punctuated,
11 spanned::Spanned,
12 visit::Visit,
13 visit_mut::VisitMut,
14 Attribute, Field, Fields, GenericArgument, GenericParam, Generics, Ident, Index, Item,
15 ItemStruct, Lifetime, LifetimeParam, Member, Meta, PathArguments, PathSegment, Token, Type,
16 TypeParamBound, TypePath, WhereClause, WherePredicate,
17};
18
19use crate::{
20 diagnostics::{DiagCtxt, ErrorGuaranteed},
21 util::*,
22};
23
24pub(crate) mod kw {
25 syn::custom_keyword!(covariant);
26 syn::custom_keyword!(invariant);
27 syn::custom_keyword!(contravariant);
28 syn::custom_keyword!(PinnedDrop);
29}
30
31pub(crate) enum Args {
32 Nothing(Nothing),
33 #[allow(dead_code)]
34 PinnedDrop(kw::PinnedDrop),
35}
36
37impl Parse for Args {
38 fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
39 let lh = input.lookahead1();
40 if lh.peek(End) {
41 input.parse().map(Self::Nothing)
42 } else if lh.peek(kw::PinnedDrop) {
43 input.parse().map(Self::PinnedDrop)
44 } else {
45 Err(lh.error())
46 }
47 }
48}
49
50impl ToTokens for Args {
51 fn to_tokens(&self, tokens: &mut TokenStream) {
52 match self {
53 Self::Nothing(_) => (),
54 Self::PinnedDrop(kw) => kw.to_tokens(tokens),
55 }
56 }
57}
58
59#[derive(Clone, Copy, Default, PartialEq, Eq)]
61enum BorrowedKind {
62 #[default]
64 Shared,
65 Mutable,
67}
68
69impl BorrowedKind {
70 fn parse(dcx: &mut DiagCtxt, attrs: &mut Vec<Attribute>) -> Option<Self> {
71 let attr = attrs.extract_single_attr(dcx, "borrowed")?;
72
73 Some(if let Meta::Path(_) = attr.meta {
74 BorrowedKind::Shared
75 } else {
76 match attr.parse_args_with(|input: ParseStream<'_>| {
77 let _: Token![mut] = input.parse()?;
78 Ok(BorrowedKind::Mutable)
79 }) {
80 Ok(v) => v,
81 Err(err) => {
82 dcx.error(attr.path(), err);
84 BorrowedKind::Shared
85 }
86 }
87 })
88 }
89}
90
91struct BorrowedInfo {
93 kind: BorrowedKind,
94 lifetime: Lifetime,
96 lt_variance: Variance,
98}
99
100#[derive(Clone, Copy, Default, PartialEq, Eq)]
101enum Variance {
102 #[default]
104 Covariant,
105 Invariant,
107}
108
109impl Parse for Variance {
110 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
111 let lh = input.lookahead1();
112 Ok(if lh.peek(kw::covariant) {
113 let _: kw::covariant = input.parse()?;
114 Variance::Covariant
115 } else if lh.peek(kw::invariant) {
116 let _: kw::invariant = input.parse()?;
117 Variance::Invariant
118 } else if lh.peek(kw::contravariant) {
119 let token: kw::contravariant = input.parse()?;
122 DiagCtxt::current(|dcx| {
123 dcx.error(
124 token,
125 "field lifetimes cannot be `contravariant`; use `invariant` instead",
126 )
127 });
128 Variance::Invariant
129 } else {
130 Err(lh.error())?
131 })
132 }
133}
134
135struct Capture {
137 variance: Variance,
138 lifetime: Lifetime,
140}
141
142impl std::borrow::Borrow<Lifetime> for Capture {
143 fn borrow(&self) -> &Lifetime {
144 &self.lifetime
145 }
146}
147
148impl PartialEq for Capture {
149 fn eq(&self, other: &Self) -> bool {
150 self.lifetime == other.lifetime
151 }
152}
153
154impl Eq for Capture {}
155
156impl PartialOrd for Capture {
157 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
158 Some(self.cmp(other))
159 }
160}
161
162impl Ord for Capture {
163 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
164 self.lifetime.cmp(&other.lifetime)
165 }
166}
167
168impl Parse for Capture {
169 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
170 let lifetime = input.parse()?;
171 let variance = if input.peek(Token![:]) {
172 let _: Token![:] = input.parse()?;
173 input.parse()?
174 } else {
175 Variance::Covariant
177 };
178 Ok(Capture { variance, lifetime })
179 }
180}
181
182impl Capture {
183 fn parse_list(
184 dcx: &mut DiagCtxt,
185 attrs: &mut Vec<Attribute>,
186 bound_lifetimes: &BTreeSet<&Lifetime>,
187 exist_lifetimes: &BTreeSet<ExistLt>,
188 field_idx_map: &BTreeMap<Ident, usize>,
189 ) -> Option<(BTreeSet<Capture>, Variance)> {
190 let attr = attrs.extract_single_attr(dcx, "uses")?;
191 let punctuated: Punctuated<Capture, Token![,]> = attr
192 .parse_args_with(Punctuated::parse_terminated)
193 .map_err(ErrorGuaranteed::from)
194 .ok()?;
195
196 let mut set = BTreeSet::new();
198 for borrow in punctuated {
199 let lt = &borrow.lifetime;
200 if set.contains(&borrow) {
201 dcx.error(lt, format!("lifetime `{lt}` is mentioned more than once"));
202 continue;
203 }
204
205 if bound_lifetimes.contains(lt) {
206 dcx.error(
207 lt,
208 format!("`{lt}` is a struct generics and cannot be used in `#[uses]`"),
209 );
210 continue;
211 }
212
213 if lt.ident != "_"
214 && !exist_lifetimes.contains(lt)
215 && !field_idx_map.contains_key(<.ident)
216 {
217 dcx.error(lt, format!("`{lt}` is not a field name"));
218 continue;
219 }
220
221 set.insert(borrow);
222 }
223
224 let wildcard = Lifetime::new("'_", Span::mixed_site());
225 let wildcard_variance = set.take(&wildcard).map(|b| b.variance).unwrap_or_default();
226 Some((set, wildcard_variance))
227 }
228}
229
230#[allow(unused)]
231struct FieldInfo {
232 field: Field,
233 member: Member,
234 pinned: bool,
235 borrowed: Option<BorrowedInfo>,
236 captures: BTreeSet<Capture>,
237 generic_lt_captures: BTreeSet<Lifetime>,
238 generic_ty_captures: BTreeSet<Ident>,
239}
240
241struct StructInfo {
242 args: Args,
243 struct_: ItemStruct,
244 fields: Vec<FieldInfo>,
245 field_idx_map: BTreeMap<Ident, usize>,
246 is_tuple_struct: bool,
247 self_referential: bool,
248 exist_lts: BTreeSet<ExistLt>,
250 field_lts_outlive_chain: Generics,
252 field_lts_split_variance_outlive_chain: Generics,
255 exist_lts_generics: Generics,
257}
258
259pub(crate) fn expand_with_cfg(
260 args: Args,
261 input: Item,
262 dcx: &mut DiagCtxt,
263) -> Result<TokenStream, ErrorGuaranteed> {
264 let mut struct_ = match input {
265 Item::Struct(struct_) => struct_,
266 Item::Enum(enum_) => {
267 return Err(dcx.error(
268 enum_.enum_token,
269 "`#[pin_data]` only supports structs for now",
270 ));
271 }
272 Item::Union(union) => {
273 return Err(dcx.error(
274 union.union_token,
275 "`#[pin_data]` only supports structs for now",
276 ));
277 }
278 rest => {
279 return Err(dcx.error(
280 rest,
281 "`#[pin_data]` can only be applied to struct, enum and union definitions",
282 ));
283 }
284 };
285
286 for (field_idx, field) in struct_.fields.iter_mut().enumerate() {
291 let cfg = field.attrs.extract_cfg_attrs();
292 if cfg.is_empty() {
293 continue;
294 }
295
296 let cfg_true_struct = quote!(#struct_);
297
298 let punctuated = match &mut struct_.fields {
299 Fields::Named(fields) => &mut fields.named,
300 Fields::Unnamed(fields) => &mut fields.unnamed,
301 Fields::Unit => unreachable!(),
302 };
303 *punctuated = std::mem::take(punctuated)
304 .into_pairs()
305 .enumerate()
306 .filter(|&(i, _)| i != field_idx)
307 .map(|(_, p)| p)
308 .collect();
309 let cfg_false_struct = quote!(#struct_);
310
311 return Ok(quote!(
315 #[cfg(all(#(#cfg,)*))]
316 #[::pin_init::pin_data(#args)]
317 #cfg_true_struct
318
319 #[cfg(not(all(#(#cfg,)*)))]
320 #[::pin_init::pin_data(#args)]
321 #cfg_false_struct
322 ));
323 }
324
325 expand(args, struct_, dcx)
326}
327
328fn expand(
329 args: Args,
330 mut struct_: ItemStruct,
331 dcx: &mut DiagCtxt,
332) -> Result<TokenStream, ErrorGuaranteed> {
333 let mut replacer = {
337 let name = &struct_.ident;
338 let (_, ty_generics, _) = struct_.generics.split_for_impl();
339 SelfReplacer(parse_quote!(#name #ty_generics))
340 };
341 replacer.visit_generics_mut(&mut struct_.generics);
342 replacer.visit_fields_mut(&mut struct_.fields);
343
344 let is_tuple_struct = matches!(struct_.fields, Fields::Unnamed(_));
345
346 let exist_lts = if let Some(whr) = &mut struct_.generics.where_clause {
347 ExistLt::parse(dcx, whr)
348 } else {
349 BTreeSet::new()
350 };
351
352 let bound_lifetimes: BTreeSet<&Lifetime> =
354 struct_.generics.lifetimes().map(|x| &x.lifetime).collect();
355 let type_params: BTreeSet<&Ident> = struct_.generics.type_params().map(|x| &x.ident).collect();
357 let field_idx_map: BTreeMap<Ident, usize> = struct_
359 .fields
360 .iter()
361 .enumerate()
362 .filter_map(|(index, field)| Some((field.ident.clone()?, index)))
363 .collect();
364
365 for l in &exist_lts {
366 let lt = &l.lifetime;
367 if bound_lifetimes.contains(<) {
368 dcx.error(
369 lt,
370 format!("existential `{lt}` conflicts with struct generics"),
371 );
372 }
373 }
374
375 let mut implicitly_borrowed = BTreeSet::new();
377
378 let mut fields: Vec<FieldInfo> = struct_
379 .fields
380 .into_iter()
381 .enumerate()
382 .map(|(index, mut field)| {
383 let pinned = field.attrs.extract_single_attr(dcx, "pin").is_some();
384
385 assert!(
386 !field.attrs.iter().any(|a| a.path().is_ident("cfg")),
387 "cfgs should be all resolved at this point"
388 );
389 let member = match &field.ident {
390 Some(ident) => Member::Named(ident.clone()),
391 None => Member::Unnamed(Index {
392 index: index as u32,
393 span: field.span(),
394 }),
395 };
396
397 let (mut captures, wildcard_variance) = Capture::parse_list(
399 dcx,
400 &mut field.attrs,
401 &bound_lifetimes,
402 &exist_lts,
403 &field_idx_map,
404 )
405 .unwrap_or_default();
406
407 let mut generic_lt_captures = BTreeSet::new();
408 let mut generic_ty_captures = BTreeSet::new();
409
410 Lifetime::visitor(|lt| {
423 if bound_lifetimes.contains(lt) {
424 generic_lt_captures.insert(lt.clone());
425 return;
426 }
427
428 if captures.contains(lt) {
429 return;
430 }
431
432 if !exist_lts.contains(lt) && !field_idx_map.contains_key(<.ident) {
433 dcx.error(
434 lt,
435 format!("`{lt}` is neither a lifetime in generics nor a field name"),
436 );
437 return;
438 }
439
440 captures.insert(Capture {
441 variance: wildcard_variance,
442 lifetime: lt.clone(),
443 });
444 })
445 .visit_type(&field.ty);
446
447 for capture in captures.iter(){
448 if !exist_lts.contains(&capture.lifetime){
449 implicitly_borrowed.insert(capture.lifetime.ident.clone());
450 }
451 }
452
453 GenericParam::maybe_type_params_visitor(|ident| {
454 if type_params.contains(ident) {
455 generic_ty_captures.insert(ident.clone());
456 }
457 })
458 .visit_type(&field.ty);
459
460 let borrowed = BorrowedKind::parse(dcx, &mut field.attrs).and_then(|kind| {
461 let lifetime = Lifetime::from_ident(&member.as_ident());
462
463 if bound_lifetimes.contains(&lifetime) {
464 dcx.error(
465 &lifetime,
466 format!("`{lifetime}` appear in generics and would conflict with field lifetime"),
467 );
468 return None;
469 }
470
471 Some(BorrowedInfo { kind, lifetime, lt_variance: Variance::default() })
472 });
473
474 FieldInfo {
475 field,
476 member,
477 pinned,
478 borrowed,
479 captures,
480 generic_lt_captures,
481 generic_ty_captures,
482 }
483 })
484 .collect();
485
486 for field_name in implicitly_borrowed.into_iter() {
487 let field = &mut fields[field_idx_map[&field_name]];
488
489 if field.borrowed.is_none() {
491 field.borrowed = Some(BorrowedInfo {
492 kind: BorrowedKind::Shared,
493 lifetime: Lifetime::from_ident(&field.member.as_ident()),
495 lt_variance: Variance::Covariant,
496 });
497 }
498 }
499
500 Lifetime::visitor(|lt| {
502 if bound_lifetimes.contains(<) {
503 return;
504 }
505
506 if field_idx_map.contains_key(<.ident) {
507 dcx.error(lt, "field lifetimes cannot be used in bounds");
509 }
510
511 })
513 .visit_generics(&struct_.generics);
514
515 let mut invariant_field_idx = BTreeSet::new();
527 let mut worklist = Vec::new();
528 for field in fields.iter() {
529 for borrow in field.captures.iter() {
530 if exist_lts.contains(&borrow.lifetime) {
531 continue;
532 }
533 if let Variance::Invariant = borrow.variance {
534 let Some(borrow_idx) = fields
535 .iter()
536 .position(|f| f.member.as_ident() == borrow.lifetime.ident)
537 else {
538 continue;
539 };
540 if invariant_field_idx.insert(borrow_idx) {
541 worklist.push(&fields[borrow_idx]);
542 }
543 }
544 }
545 }
546 while let Some(field) = worklist.pop() {
547 for borrow in field.captures.iter() {
548 if exist_lts.contains(&borrow.lifetime) {
549 continue;
550 }
551 let Some(borrow_idx) = fields
552 .iter()
553 .position(|f| f.member.as_ident() == borrow.lifetime.ident)
554 else {
555 continue;
556 };
557 let borrow = &fields[borrow_idx];
558 if invariant_field_idx.insert(borrow_idx) {
559 worklist.push(borrow);
560 }
561 }
562 }
563 for idx in invariant_field_idx {
564 fields[idx].borrowed.as_mut().unwrap().lt_variance = Variance::Invariant;
565 }
566
567 let borrowed_fields: Vec<_> = fields.iter().filter_map(|f| f.borrowed.as_ref()).collect();
569 let borrowed_covariant_fields: Vec<_> = borrowed_fields
570 .iter()
571 .filter(|f| f.lt_variance == Variance::Covariant)
572 .collect();
573 let borrowed_invariant_fields: Vec<_> = borrowed_fields
574 .iter()
575 .filter(|f| f.lt_variance == Variance::Invariant)
576 .collect();
577
578 let mut field_lts_outlive_chain = Generics {
579 lt_token: None,
580 params: borrowed_fields
581 .iter()
582 .zip(std::iter::once(None).chain(borrowed_fields.iter().map(Some)))
583 .map(|(borrowed, prev)| {
584 GenericParam::Lifetime(LifetimeParam {
585 attrs: Vec::new(),
586 lifetime: borrowed.lifetime.clone(),
587 colon_token: None,
588 bounds: prev
589 .iter()
590 .map(|borrowed| borrowed.lifetime.clone())
591 .collect(),
592 })
593 })
594 .collect(),
595 gt_token: None,
596 where_clause: None,
597 };
598
599 if let Some(last_borrowed_field) = borrowed_fields.last() {
600 let field_lt = &last_borrowed_field.lifetime;
601 for param in struct_.generics.params.iter() {
602 match param {
603 GenericParam::Lifetime(param) => {
604 let lt = ¶m.lifetime;
605 field_lts_outlive_chain
606 .make_where_clause()
607 .predicates
608 .push(parse_quote!(#lt: #field_lt));
609 }
610 GenericParam::Type(param) => {
611 let ty = ¶m.ident;
612 field_lts_outlive_chain
613 .make_where_clause()
614 .predicates
615 .push(parse_quote!(#ty: #field_lt));
616 }
617 GenericParam::Const(_) => (),
618 }
619 }
620 }
621
622 let exist_lt_generics = Generics {
623 lt_token: Some(Default::default()),
624 params: exist_lts
625 .iter()
626 .map(|l| {
627 GenericParam::Lifetime(LifetimeParam {
628 attrs: Vec::new(),
629 lifetime: l.lifetime.clone(),
630 colon_token: Default::default(),
631 bounds: l.bounds.iter().cloned().collect(),
632 })
633 })
634 .collect(),
635 gt_token: Some(Default::default()),
636 where_clause: None,
637 };
638
639 let mut field_lts_split_variance_outlive_chain = Generics {
640 lt_token: Some(Default::default()),
641 params: borrowed_covariant_fields
642 .iter()
643 .zip(std::iter::once(None).chain(borrowed_covariant_fields.iter().map(Some)))
644 .map(|(borrowed, prev)| {
645 GenericParam::Lifetime(LifetimeParam {
646 attrs: Vec::new(),
647 lifetime: borrowed.lifetime.clone(),
648 colon_token: None,
649 bounds: prev
650 .iter()
651 .map(|borrowed| borrowed.lifetime.clone())
652 .collect(),
653 })
654 })
655 .chain(
656 borrowed_invariant_fields
657 .iter()
658 .zip(std::iter::once(None).chain(borrowed_invariant_fields.iter().map(Some)))
659 .map(|(borrowed, prev)| {
660 GenericParam::Lifetime(LifetimeParam {
661 attrs: Vec::new(),
662 lifetime: borrowed.lifetime.clone(),
663 colon_token: None,
664 bounds: prev
665 .iter()
666 .map(|borrowed| borrowed.lifetime.clone())
667 .collect(),
668 })
669 }),
670 )
671 .collect(),
672 gt_token: Some(Default::default()),
673 where_clause: None,
674 };
675
676 for field in fields.iter() {
679 let Some(borrowed) = &field.borrowed else {
680 continue;
681 };
682 let field_lt = &borrowed.lifetime;
683
684 for lt in field.generic_lt_captures.iter() {
687 field_lts_split_variance_outlive_chain
688 .make_where_clause()
689 .predicates
690 .push(parse_quote!(#lt: #field_lt));
691 }
692
693 for ty in field.generic_ty_captures.iter() {
694 field_lts_split_variance_outlive_chain
695 .make_where_clause()
696 .predicates
697 .push(parse_quote!(#ty: #field_lt));
698 }
699
700 for borrow in field.captures.iter().rev() {
701 let lt = &borrow.lifetime;
702 if exist_lts.contains(lt) {
703 field_lts_split_variance_outlive_chain
704 .make_where_clause()
705 .predicates
706 .push(parse_quote!(#lt: #field_lt));
707 }
708 }
709
710 if borrowed.lt_variance != Variance::Covariant {
713 continue;
714 }
715
716 for capture in field.captures.iter() {
717 let Some(&idx) = field_idx_map.get(&capture.lifetime.ident) else {
718 continue;
719 };
720
721 let prev_borrowed = fields[idx].borrowed.as_ref().unwrap();
722
723 if prev_borrowed.lt_variance == Variance::Invariant {
726 let param = field_lts_split_variance_outlive_chain
731 .lifetimes_mut()
732 .find(|l| l.lifetime == prev_borrowed.lifetime)
733 .unwrap();
734 param.bounds.push(borrowed.lifetime.clone());
735 }
736 }
737 }
738
739 struct_.fields = Fields::Unit;
740 let info = StructInfo {
741 self_referential: fields
742 .iter()
743 .any(|f| !f.captures.is_empty() || f.borrowed.is_some()),
744 args,
745 struct_,
746 fields,
747 field_idx_map,
748 is_tuple_struct,
749 exist_lts,
750 field_lts_outlive_chain,
751 field_lts_split_variance_outlive_chain,
752 exist_lts_generics: exist_lt_generics,
753 };
754
755 for field in &info.fields {
756 if !field.pinned && is_phantom_pinned(&field.field.ty) {
757 dcx.warn(
758 &field.field,
759 format!(
760 "The field {} of type `PhantomPinned` only has an effect \
761 if it has the `#[pin]` attribute",
762 field.member.display_name(),
763 ),
764 );
765 }
766 }
767
768 let struct_def = generate_struct_def(&info);
769 let unpin_impl = generate_unpin_impl(&info);
770 let drop_impl = generate_drop_impl(&info);
771 let drop_order_check = generate_drop_order_check(dcx, &info);
772 let variance_check = generate_variance_check(&info);
773 let projections = generate_projections(&info);
774 let the_pin_data = generate_the_pin_data(&info);
775
776 Ok(quote! {
777 #struct_def
778 const _: () = {
781 #drop_order_check
782 #variance_check
783 #projections
784 #the_pin_data
785 #unpin_impl
786 #drop_impl
787 };
788 })
789}
790
791fn is_phantom_pinned(ty: &Type) -> bool {
792 match ty {
793 Type::Path(TypePath { qself: None, path }) => {
794 if path.segments.len() > 3 {
796 return false;
797 }
798 if path.leading_colon.is_some() && path.segments.len() != 3 {
801 return false;
802 }
803 let expected: Vec<&[&str]> = vec![&["PhantomPinned"], &["marker"], &["core", "std"]];
804 for (actual, expected) in path.segments.iter().rev().zip(expected) {
805 if !actual.arguments.is_empty() || expected.iter().all(|e| actual.ident != e) {
806 return false;
807 }
808 }
809 true
810 }
811 _ => false,
812 }
813}
814
815struct ExistLt {
816 lifetime: Lifetime,
817 bounds: Vec<Lifetime>,
818}
819
820impl std::borrow::Borrow<Lifetime> for ExistLt {
821 fn borrow(&self) -> &Lifetime {
822 &self.lifetime
823 }
824}
825
826impl PartialEq for ExistLt {
827 fn eq(&self, other: &Self) -> bool {
828 self.lifetime == other.lifetime
829 }
830}
831
832impl Eq for ExistLt {}
833
834impl PartialOrd for ExistLt {
835 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
836 Some(self.cmp(other))
837 }
838}
839
840impl Ord for ExistLt {
841 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
842 self.lifetime.cmp(&other.lifetime)
843 }
844}
845
846impl ExistLt {
847 fn parse(dcx: &mut DiagCtxt, whr: &mut WhereClause) -> BTreeSet<ExistLt> {
848 fn parse_one(
849 dcx: &mut DiagCtxt,
850 pred: &WherePredicate,
851 result: &mut BTreeSet<ExistLt>,
852 ) -> bool {
853 let WherePredicate::Type(pred) = &pred else {
854 return false;
855 };
856 let Type::Path(path) = &pred.bounded_ty else {
857 return false;
858 };
859
860 if path.qself.is_some()
861 || path.path.leading_colon.is_some()
862 || path.path.segments.len() != 1
863 {
864 return false;
865 }
866 let path_seg = &path.path.segments[0];
867
868 if path_seg.ident != "exists" {
869 return false;
870 };
871
872 let PathArguments::AngleBracketed(p) = &path_seg.arguments else {
873 dcx.error(
874 path_seg,
875 "existential clauses require a single lifetime, e.g. `exists<'a>`",
876 );
877 return true;
878 };
879
880 if p.args.len() != 1 {
881 dcx.error(
882 path_seg,
883 "existential clauses require a single lifetime, e.g. `exists<'a>`",
884 );
885 return true;
886 }
887
888 let GenericArgument::Lifetime(lt) = &p.args[0] else {
889 dcx.error(
890 path_seg,
891 "existential clauses require a single lifetime, e.g. `exists<'a>`",
892 );
893 return true;
894 };
895
896 if result.contains(lt) {
897 dcx.error(
898 lt,
899 format!("an existential clause for `{lt}` already exists"),
900 );
901 return true;
902 }
903
904 let mut bounds = Vec::new();
905 for bound in pred.bounds.iter() {
906 let TypeParamBound::Lifetime(lt) = bound else {
907 dcx.error(bound, "only lifetime can appear in existential clauses");
908 return true;
909 };
910 bounds.push(lt.clone());
911 }
912 if bounds.is_empty() {
913 dcx.error(
914 pred.colon_token,
915 "existential clauses require at least one outlive bounds",
916 );
917 return true;
918 }
919
920 result.insert(ExistLt {
921 lifetime: lt.clone(),
922 bounds: bounds.clone(),
923 });
924
925 true
926 }
927
928 let mut result = BTreeSet::new();
929 whr.predicates = std::mem::take(&mut whr.predicates)
930 .into_pairs()
931 .filter(|p| !parse_one(dcx, p.value(), &mut result))
932 .collect();
933
934 result
935 }
936}
937
938fn generate_struct_def(info: &StructInfo) -> TokenStream {
939 let ItemStruct {
940 attrs,
941 vis,
942 struct_token,
943 ident,
944 generics,
945 fields: _,
946 semi_token,
947 } = &info.struct_;
948
949 let generated_fields = info.fields.iter().map(|field| {
950 let Field {
951 attrs,
952 vis,
953 mutability: _,
954 ident,
955 colon_token,
956 ty,
957 } = &field.field;
958
959 let mut ty = ty.to_token_stream();
960
961 if !field.captures.is_empty()
964 || matches!(
965 field.borrowed,
966 Some(BorrowedInfo {
967 kind: BorrowedKind::Mutable,
968 ..
969 })
970 )
971 {
972 ty = quote!((#ty,));
975
976 let mut exist_lt_phantoms = Vec::new();
977 for borrow in field.captures.iter().rev() {
978 let lt = &borrow.lifetime;
979 ty = quote!(for<#lt> fn(&#lt()) -> #ty);
980
981 if let Some(exist_lt) = info.exist_lts.get(lt) {
982 for bound in &exist_lt.bounds {
983 exist_lt_phantoms.push(quote!(::pin_init::__internal::ExistLt<#bound>));
984 }
985 }
986 }
987
988 ty = quote!(::pin_init::__internal::Erase<#ty>);
989
990 if !exist_lt_phantoms.is_empty() {
991 ty = quote!(::pin_init::__internal::WithPhantom<#ty, (#(#exist_lt_phantoms,)*)>);
992 }
993 };
994
995 if let Some(borrowed) = &field.borrowed {
996 let mut invariance_capture = Vec::new();
997 if borrowed.lt_variance == Variance::Invariant {
998 for lt in &field.generic_lt_captures {
999 invariance_capture.push(quote!(&#lt ()));
1000 }
1001
1002 for ty in &field.generic_ty_captures {
1003 invariance_capture.push(quote!(::core::marker::PhantomData<#ty>));
1004 }
1005 }
1006 ty = quote!(::pin_init::__internal::Borrowed<#ty, (#(#invariance_capture,)*)>);
1007 }
1008
1009 quote! {
1010 #(#attrs)* #vis #ident #colon_token #ty
1011 }
1012 });
1013
1014 let whr = &generics.where_clause;
1015
1016 if info.is_tuple_struct {
1017 quote!(
1018 #(#attrs)*
1019 #vis
1020 #struct_token #ident #generics (#(#generated_fields,)*) #whr
1021 #semi_token
1022 )
1023 } else {
1024 quote!(
1025 #(#attrs)*
1026 #vis
1027 #struct_token #ident #generics #whr {
1028 #(#generated_fields,)*
1029 }
1030 #semi_token
1031 )
1032 }
1033}
1034
1035fn generate_unpin_impl(info: &StructInfo) -> TokenStream {
1036 let ItemStruct {
1037 generics, ident, ..
1038 } = &info.struct_;
1039 let (impl_generics, ty_generics, whr) = generics.split_for_impl();
1040 let predicates = whr
1041 .map(|x| &x.predicates)
1042 .unwrap_or(const { &Punctuated::new() });
1043
1044 if info.self_referential {
1045 return quote! {
1047 #[doc(hidden)]
1048 impl #impl_generics ::core::marker::Unpin for #ident #ty_generics
1049 where
1050 for<'__dummy> ::core::marker::PhantomPinned: ::core::marker::Unpin,
1053 #predicates
1054 {}
1055 };
1056 }
1057
1058 let pinned_fields = info.fields.iter().filter(|f| f.pinned).map(|f| {
1059 let ident = f.member.as_ident();
1060 let ty = &f.field.ty;
1061 quote!(
1062 #ident: #ty
1063 )
1064 });
1065
1066 quote! {
1067 #[allow(
1070 dead_code, non_snake_case )]
1073 struct __Unpin #generics #whr
1074 {
1075 __phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>,
1076 #(#pinned_fields),*
1077 }
1078
1079 #[doc(hidden)]
1080 impl #impl_generics ::core::marker::Unpin for #ident #ty_generics
1081 where
1082 for<'__dummy> __Unpin #ty_generics: ::core::marker::Unpin,
1085 #predicates
1086 {}
1087 }
1088}
1089
1090fn generate_drop_impl(info: &StructInfo) -> TokenStream {
1091 let ItemStruct {
1092 generics, ident, ..
1093 } = &info.struct_;
1094 let (impl_generics, ty_generics, whr) = generics.split_for_impl();
1095 let has_pinned_drop = matches!(info.args, Args::PinnedDrop(_));
1096 if has_pinned_drop {
1099 quote! {
1101 impl #impl_generics ::core::ops::Drop for #ident #ty_generics
1102 #whr
1103 {
1104 fn drop(&mut self) {
1105 let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) };
1108 let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() };
1111 ::pin_init::PinnedDrop::drop(pinned, token);
1112 }
1113 }
1114 }
1115 } else {
1116 quote! {
1118 trait MustNotImplDrop {}
1122 impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {}
1123 impl #impl_generics MustNotImplDrop for #ident #ty_generics
1124 #whr
1125 {}
1126 trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
1130 impl<T: ::pin_init::PinnedDrop + ?::core::marker::Sized>
1131 UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
1132 impl #impl_generics
1133 UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for #ident #ty_generics
1134 #whr
1135 {}
1136 }
1137 }
1138}
1139
1140fn generate_drop_order_check(dcx: &mut DiagCtxt, info: &StructInfo) -> TokenStream {
1141 let ItemStruct {
1142 ident: struct_name,
1143 generics,
1144 ..
1145 } = &info.struct_;
1146
1147 if !info.self_referential {
1149 return quote!();
1150 }
1151
1152 for (i, field) in info.fields.iter().enumerate() {
1154 let ident = field.member.as_ident();
1155 for capture in &field.captures {
1156 let borrowed_field = &capture.lifetime.ident;
1157
1158 if let Some(&borrowed_idx) = info.field_idx_map.get(borrowed_field) {
1159 if i == borrowed_idx {
1160 dcx.error(
1163 borrowed_field,
1164 format!("field `{ident}` cannot borrow from itself"),
1165 );
1166 } else if i > borrowed_idx {
1167 dcx.error(
1168 borrowed_field,
1169 format!("field `{ident}` borrows `{borrowed_field}`, but drops later"),
1170 );
1171 }
1172 }
1173 }
1174 }
1175
1176 let generics_with_field_lt = CombinedGenerics(vec![
1203 &info.exist_lts_generics,
1204 &info.field_lts_split_variance_outlive_chain,
1205 generics,
1206 ]);
1207
1208 let (_, ty_generics, _) = generics.split_for_impl();
1209 let (impl_generics_with_field_lt, _, whr_with_field_lt) =
1210 generics_with_field_lt.split_for_impl();
1211
1212 let wf_proofs = info.fields.iter().rev().map(|f| {
1238 let ty = &f.field.ty;
1239 let span = ty.span().resolved_at(Span::mixed_site());
1240 let ident = f.member.as_ident();
1241 let lt = f.borrowed.as_ref().map(|b| &b.lifetime);
1242 quote_spanned!(span =>
1243 let #ident: &#lt mut #ty = loop {};
1244 )
1245 });
1246
1247 let struct_span = struct_name.span().resolved_at(Span::mixed_site());
1248 quote_spanned! {struct_span =>
1249 #[allow(non_snake_case, unused)]
1250 fn __drop_order_check #impl_generics_with_field_lt (
1251 _: &#struct_name #ty_generics,
1255 ) #whr_with_field_lt {
1256 #(#wf_proofs)*
1257 }
1258 }
1259}
1260
1261fn generate_variance_check(info: &StructInfo) -> TokenStream {
1264 if !info.self_referential {
1265 return quote!();
1266 }
1267
1268 let mut checks = Vec::new();
1269
1270 for f in info.fields.iter() {
1271 let covariant_captures: Vec<_> = f
1272 .captures
1273 .iter()
1274 .filter(|b| b.variance == Variance::Covariant)
1275 .map(|b| &b.lifetime)
1276 .collect();
1277 if covariant_captures.is_empty() {
1278 continue;
1279 }
1280
1281 let ident = f.member.as_ident();
1282 let span = f.field.ty.span().resolved_at(Span::mixed_site());
1284
1285 let other_field_lifetimes = Generics {
1286 lt_token: None,
1287 params: f
1288 .captures
1289 .iter()
1290 .filter(|b| b.variance != Variance::Covariant)
1291 .map(|b| GenericParam::Lifetime(LifetimeParam::new(b.lifetime.clone())))
1292 .collect(),
1293 gt_token: None,
1294 where_clause: None,
1295 };
1296
1297 let long = Lifetime::new("'__long", span);
1298 let long_ty = f
1299 .field
1300 .ty
1301 .replace_lifetimes(&covariant_captures, &vec![&long; covariant_captures.len()]);
1302
1303 let short = Lifetime::new("'__short", span);
1304 let short_ty = f
1305 .field
1306 .ty
1307 .replace_lifetimes(&covariant_captures, &vec![&short; covariant_captures.len()]);
1308
1309 let check_name = format_ident!("__{ident}_covariance", span = span);
1310
1311 let covariance_check_generics = parse_quote!(<#long: #short, #short>);
1313 let combined_generics = CombinedGenerics(vec![
1314 &covariance_check_generics,
1315 &other_field_lifetimes,
1316 &info.struct_.generics,
1317 ]);
1318 let (combined_impl_generics, _, whr) = combined_generics.split_for_impl();
1319
1320 checks.push(quote_spanned!(span =>
1321 fn #check_name #combined_impl_generics (long: #long_ty) -> #short_ty #whr {
1323 long
1324 }
1325 ));
1326 }
1327
1328 quote!(
1329 #(#checks)*
1330 )
1331}
1332
1333fn generate_projections(info: &StructInfo) -> TokenStream {
1334 let ItemStruct {
1335 vis,
1336 ident,
1337 generics,
1338 ..
1339 } = &info.struct_;
1340 let this_lt = Lifetime::new("'__this", Span::mixed_site());
1341 let this_lt_generics: Generics = parse_quote!(<#this_lt>);
1342
1343 let field_lts = CombinedGenerics(vec![
1346 &info.field_lts_outlive_chain,
1347 &info.exist_lts_generics,
1348 ]);
1349 let generics_with_this_lt = CombinedGenerics(vec![&this_lt_generics, generics]);
1350 let generics_with_this_field_lt = CombinedGenerics(vec![
1351 &this_lt_generics,
1352 &info.exist_lts_generics,
1353 &info.field_lts_outlive_chain,
1354 generics,
1355 ]);
1356 let generics_with_this_field_ref_lt = CombinedGenerics(vec![
1357 &this_lt_generics,
1358 &info.exist_lts_generics,
1359 &info.field_lts_split_variance_outlive_chain,
1360 generics,
1361 ]);
1362 let (_, field_lt_ty_generics, _) = field_lts.split_for_impl();
1363 let (impl_generics, ty_generics, whr) = generics.split_for_impl();
1364 let (_, ty_generics_with_this_lt, _) = generics_with_this_lt.split_for_impl();
1365 let (_, ty_generics_with_this_field_lt, _) = generics_with_this_field_lt.split_for_impl();
1366 let (_, ty_generics_with_this_field_ref_lt, _) =
1367 generics_with_this_field_ref_lt.split_for_impl();
1368
1369 let this = format_ident!("this");
1370
1371 let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = info
1372 .fields
1373 .iter()
1374 .map(|f| {
1375 let vis = &f.field.vis;
1376 let ident = f.member.as_ident();
1377 let member = &f.member;
1378 let name = (!info.is_tuple_struct).then(|| quote!(#ident:));
1381
1382 let all_lifetimes: Vec<_> = f.captures.iter().map(|b| &b.lifetime).collect();
1385 let ty = f
1386 .field
1387 .ty
1388 .replace_lifetimes(&all_lifetimes, &vec![&this_lt; all_lifetimes.len()]);
1389
1390 let mut_token: Option<Token![mut]> = if f.borrowed.is_none() && f.captures.is_empty() {
1394 Some(Default::default())
1395 } else {
1396 None
1397 };
1398
1399 let mut accessor = quote!(&#mut_token #this.#member);
1400 if !f.captures.is_empty() || f.borrowed.is_some() {
1401 accessor = quote!(
1402 unsafe { ::core::mem::transmute::<_, &#mut_token #ty>(#accessor) }
1405 )
1406 }
1407
1408 if !f.captures.iter().all(|b| b.variance == Variance::Covariant)
1409 || matches!(
1410 f.borrowed,
1411 Some(BorrowedInfo {
1412 kind: BorrowedKind::Mutable,
1413 ..
1414 })
1415 )
1416 {
1417 (
1421 quote!(
1422 #vis #name ::pin_init::__internal::NotVisible<&'__this #mut_token #ty>,
1423 ),
1424 quote!(
1425 #name ::pin_init::__internal::NotVisible::new(),
1426 ),
1427 )
1428 } else if f.pinned {
1429 (
1430 quote!(
1431 #vis #name ::core::pin::Pin<&'__this #mut_token #ty>,
1432 ),
1433 quote!(
1434 #name unsafe { ::core::pin::Pin::new_unchecked(#accessor) },
1436 ),
1437 )
1438 } else {
1439 (
1440 quote!(
1441 #vis #name &'__this #mut_token #ty,
1442 ),
1443 quote!(
1444 #name #accessor,
1445 ),
1446 )
1447 }
1448 })
1449 .collect();
1450
1451 let (fields_decl_lt, fields_proj_lt): (Vec<_>, Vec<_>) = info
1452 .fields
1453 .iter()
1454 .map(|f| {
1455 let vis = &f.field.vis;
1456 let ident = f.member.as_ident();
1457 let member = &f.member;
1458 let name = (!info.is_tuple_struct).then(|| quote!(#ident:));
1459
1460 let ty = &f.field.ty;
1461
1462 let mut_token: Option<Token![mut]> = if f.borrowed.is_none() {
1464 Some(Default::default())
1465 } else {
1466 None
1467 };
1468
1469 let mut accessor = quote!(&#mut_token #this.#member);
1470 if !f.captures.is_empty() || f.borrowed.is_some() {
1471 accessor = quote!(
1472 unsafe { ::core::mem::transmute(#accessor) }
1476 )
1477 }
1478
1479 let lt = if f.borrowed.is_some() {
1482 Lifetime::from_ident(&ident)
1483 } else {
1484 this_lt.clone()
1485 };
1486
1487 if matches!(
1488 f.borrowed,
1489 Some(BorrowedInfo {
1490 kind: BorrowedKind::Mutable,
1491 ..
1492 })
1493 ) {
1494 (
1498 quote!(
1499 #vis #name ::pin_init::__internal::NotVisible<&#lt #mut_token #ty>,
1500 ),
1501 quote!(
1502 #name ::pin_init::__internal::NotVisible::new(),
1503 ),
1504 )
1505 } else if f.pinned {
1506 (
1507 quote!(
1508 #vis #name ::core::pin::Pin<&#lt #mut_token #ty>,
1509 ),
1510 quote!(
1511 #name unsafe { ::core::pin::Pin::new_unchecked(#accessor) },
1513 ),
1514 )
1515 } else {
1516 (
1517 quote!(
1518 #vis #name &#lt #mut_token #ty,
1519 ),
1520 quote!(
1521 #name #accessor,
1522 ),
1523 )
1524 }
1525 })
1526 .collect();
1527
1528 let structurally_pinned_fields_docs: Vec<_> = info
1529 .fields
1530 .iter()
1531 .filter(|f| f.pinned)
1532 .map(|f| format!(" - {}", f.member.display_name()))
1533 .collect();
1534 let not_structurally_pinned_fields_docs: Vec<_> = info
1535 .fields
1536 .iter()
1537 .filter(|f| !f.pinned)
1538 .map(|f| format!(" - {}", f.member.display_name()))
1539 .collect();
1540 let docs = format!(" Pin-projections of [`{ident}`]");
1541 let (projection_def, projection_init) = if info.is_tuple_struct {
1542 (
1543 quote! {
1544 #vis struct __Projection #generics_with_this_lt (
1545 #(#fields_decl)*
1546 ::core::marker::PhantomData<&'__this mut #ident #ty_generics>,
1547 ) #whr;
1548 },
1549 quote! {
1550 __Projection(
1551 #(#fields_proj)*
1552 ::core::marker::PhantomData,
1553 )
1554 },
1555 )
1556 } else {
1557 (
1558 quote! {
1559 #vis struct __Projection #generics_with_this_lt
1560 #whr
1561 {
1562 #(#fields_decl)*
1563 __this: ::core::marker::PhantomData<&'__this mut #ident #ty_generics>,
1564 }
1565 },
1566 quote! {
1567 __Projection {
1568 #(#fields_proj)*
1569 __this: ::core::marker::PhantomData,
1570 }
1571 },
1572 )
1573 };
1574
1575 let projection_lt = format_ident!("__ProjectionLt");
1576 let (projection_lt_def, projection_lt_init) = if info.is_tuple_struct {
1577 (
1578 quote! {
1579 #vis struct #projection_lt #generics_with_this_field_lt (
1580 #(#fields_decl_lt)*
1581 ::core::marker::PhantomData<&'__this mut #ident #ty_generics>,
1582 ) #whr;
1583 },
1584 quote! {
1585 #projection_lt(
1586 #(#fields_proj_lt)*
1587 ::core::marker::PhantomData,
1588 )
1589 },
1590 )
1591 } else {
1592 (
1593 quote! {
1594 #vis struct #projection_lt #generics_with_this_field_lt
1595 #whr
1596 {
1597 #(#fields_decl_lt)*
1598 ___pin_phantom_data:
1599 ::core::marker::PhantomData<&'__this mut #ident #ty_generics>,
1600 }
1601 },
1602 quote! {
1603 #projection_lt {
1604 #(#fields_proj_lt)*
1605 ___pin_phantom_data: ::core::marker::PhantomData,
1606 }
1607 },
1608 )
1609 };
1610
1611 let mut accessors = Vec::new();
1616 for f in info.fields.iter() {
1617 let ident = f.member.as_ident();
1618 let member = &f.member;
1619
1620 if f.captures.is_empty() {
1621 continue;
1623 }
1624
1625 if matches!(
1626 f.borrowed,
1627 Some(BorrowedInfo {
1628 kind: BorrowedKind::Mutable,
1629 ..
1630 })
1631 ) {
1632 continue;
1634 }
1635
1636 if f.captures.iter().all(|b| b.variance == Variance::Covariant) {
1637 let f_doc = format!("Access the `{ident}` field on a shared reference of `Self`.");
1638 let vis = &f.field.vis;
1639
1640 let span = f.field.ty.span().resolved_at(Span::mixed_site());
1642
1643 let all_lifetimes: Vec<_> = f.captures.iter().map(|b| &b.lifetime).collect();
1644 let ty = f
1645 .field
1646 .ty
1647 .replace_lifetimes(&all_lifetimes, &vec![&this_lt; all_lifetimes.len()]);
1648
1649 accessors.push(quote_spanned!(span =>
1650 #[doc = #f_doc]
1651 #[inline]
1652 #[allow(clippy::mut_from_ref)] #vis fn #ident<#this_lt>(&#this_lt self) -> &#this_lt #ty {
1654 unsafe { ::core::mem::transmute(&self.#member) }
1657 }
1658 ))
1659 } else {
1660 let f_doc = format!("Access the `{ident}` field on a shared reference of `Self`.");
1661 let vis = &f.field.vis;
1662 let with_ident = format_ident!("with_{ident}");
1663
1664 let all_lifetimes: Vec<_> = f.captures.iter().map(|b| &b.lifetime).collect();
1665 let ty = &f.field.ty;
1666
1667 accessors.push(quote!(
1668 #[doc = #f_doc]
1669 #[inline]
1670 #vis fn #with_ident<'__this, R>(
1671 &'__this self,
1672 f: impl for<#(#all_lifetimes,)*> ::core::ops::FnOnce(&'__this #ty) -> R,
1673 ) -> R {
1674 f(unsafe { ::core::mem::transmute(&self.#member) })
1676 }
1677 ))
1678 }
1679 }
1680
1681 let (fields_ref_decl_lt, fields_ref_proj_lt): (Vec<_>, Vec<_>) = info
1682 .fields
1683 .iter()
1684 .map(|f| {
1685 let vis = &f.field.vis;
1686 let ident = f.member.as_ident();
1687 let member = &f.member;
1688 let name = (!info.is_tuple_struct).then(|| quote!(#ident:));
1689
1690 let ty = &f.field.ty;
1691
1692 let mut accessor = quote!(&#this.#member);
1693 if !f.captures.is_empty() || f.borrowed.is_some() {
1694 accessor = quote!(
1695 unsafe { ::core::mem::transmute(#accessor) }
1699 )
1700 }
1701
1702 let lt = if f.borrowed.is_some() {
1705 Lifetime::from_ident(&ident)
1706 } else {
1707 this_lt.clone()
1708 };
1709
1710 if matches!(
1711 f.borrowed,
1712 Some(BorrowedInfo {
1713 kind: BorrowedKind::Mutable,
1714 ..
1715 })
1716 ) {
1717 (
1719 quote!(
1720 #vis #name ::pin_init::__internal::NotVisible<&#lt #ty>,
1721 ),
1722 quote!(
1723 #name ::pin_init::__internal::NotVisible::new(),
1724 ),
1725 )
1726 } else if f.pinned {
1727 (
1728 quote!(
1729 #vis #name ::core::pin::Pin<&#lt #ty>,
1730 ),
1731 quote!(
1732 #name unsafe { ::core::pin::Pin::new_unchecked(#accessor) },
1734 ),
1735 )
1736 } else {
1737 (
1738 quote!(
1739 #vis #name &#lt #ty,
1740 ),
1741 quote!(
1742 #name #accessor,
1743 ),
1744 )
1745 }
1746 })
1747 .collect();
1748
1749 let projection_ref_lt = format_ident!("__ProjectionRef");
1750 let (projection_ref_lt_def, projection_ref_lt_init) = if info.is_tuple_struct {
1751 (
1752 quote!(
1753 #vis struct #projection_ref_lt #generics_with_this_field_ref_lt(
1754 #(#fields_ref_decl_lt)*
1755 ::core::marker::PhantomData<&'__this #ident #ty_generics>,
1756 ) #whr;
1757 ),
1758 quote!(
1759 #projection_ref_lt(
1760 #(#fields_ref_proj_lt)*
1761 ::core::marker::PhantomData,
1762 )
1763 ),
1764 )
1765 } else {
1766 (
1767 quote! {
1768 #vis struct #projection_ref_lt #generics_with_this_field_ref_lt
1769 #whr
1770 {
1771 #(#fields_ref_decl_lt)*
1772 ___pin_phantom_data: ::core::marker::PhantomData<&'__this #ident #ty_generics>,
1773 }
1774 },
1775 quote! {
1776 #projection_ref_lt {
1777 #(#fields_ref_proj_lt)*
1778 ___pin_phantom_data: ::core::marker::PhantomData,
1779 }
1780 },
1781 )
1782 };
1783
1784 quote! {
1785 #[doc = #docs]
1786 #[allow(dead_code, non_snake_case)]
1789 #[doc(hidden)]
1790 #projection_def
1791
1792 #[doc = #docs]
1793 #[allow(dead_code, non_snake_case, explicit_outlives_requirements)]
1796 #[doc(hidden)]
1797 #projection_lt_def
1798
1799 #[allow(dead_code, non_snake_case, explicit_outlives_requirements)]
1802 #[doc(hidden)]
1803 #projection_ref_lt_def
1804
1805 impl #impl_generics #ident #ty_generics
1806 #whr
1807 {
1808 #(#[doc = #structurally_pinned_fields_docs])*
1812 #(#[doc = #not_structurally_pinned_fields_docs])*
1815 #[inline]
1816 #vis fn project<'__this>(
1817 self: ::core::pin::Pin<&'__this mut Self>,
1818 ) -> __Projection #ty_generics_with_this_lt {
1819 let #this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) };
1821 #projection_init
1822 }
1823
1824 #(#[doc = #structurally_pinned_fields_docs])*
1828 #(#[doc = #not_structurally_pinned_fields_docs])*
1831 #[inline]
1832 #vis fn with_project<'__this, R>(
1833 self: ::core::pin::Pin<&'__this mut Self>,
1834 f: impl for #field_lt_ty_generics ::core::ops::FnOnce(
1835 #projection_lt #ty_generics_with_this_field_lt
1836 ) -> R,
1837 ) -> R {
1838 let #this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) };
1840 f(#projection_lt_init)
1841 }
1842
1843 #(#[doc = #structurally_pinned_fields_docs])*
1847 #(#[doc = #not_structurally_pinned_fields_docs])*
1850 #[inline]
1851 #vis fn with_project_ref<'__this, R>(
1852 self: ::core::pin::Pin<&'__this Self>,
1853 f: impl for #field_lt_ty_generics ::core::ops::FnOnce(
1854 #projection_ref_lt #ty_generics_with_this_field_ref_lt
1855 ) -> R,
1856 ) -> R {
1857 let #this = ::core::pin::Pin::get_ref(self);
1858 f(#projection_ref_lt_init)
1859 }
1860
1861 #(#accessors)*
1862 }
1863 }
1864}
1865
1866fn generate_the_pin_data(info: &StructInfo) -> TokenStream {
1867 let ItemStruct {
1868 vis,
1869 ident: struct_name,
1870 generics,
1871 ..
1872 } = &info.struct_;
1873
1874 let field_lts = CombinedGenerics(vec![&info.field_lts_outlive_chain]);
1877 let field_exist_lts = CombinedGenerics(vec![
1878 &info.field_lts_outlive_chain,
1879 &info.exist_lts_generics,
1880 ]);
1881 let generics_with_field_lt = CombinedGenerics(vec![
1882 &info.field_lts_outlive_chain,
1883 &info.exist_lts_generics,
1884 generics,
1885 ]);
1886
1887 let (impl_generics, ty_generics, whr) = generics.split_for_impl();
1888 let (_, field_lt_ty_generics, _) = field_lts.split_for_impl();
1889 let (_, field_exist_lt_ty_generics, _) = field_exist_lts.split_for_impl();
1890 let (impl_generics_with_lt, ty_generics_with_field_lt, whr_with_field_lt) =
1891 generics_with_field_lt.split_for_impl();
1892
1893 let phantom_fields = info.fields.iter().map(|f| {
1897 let ty = &f.field.ty;
1898 let ident = f.member.as_ident();
1899
1900 if let Some(borrowed) = &f.borrowed {
1901 let lt = &borrowed.lifetime;
1902 quote!(
1903 #ident: ::pin_init::__internal::PhantomInvariant<&#lt mut #ty>,
1904 )
1905 } else {
1906 quote!(
1907 #ident: ::pin_init::__internal::PhantomInvariant<#ty>,
1908 )
1909 }
1910 });
1911
1912 let field_accessors = info
1913 .fields
1914 .iter()
1915 .map(|f| {
1916 let Field { vis, ty, .. } = &f.field;
1917 let field_name = f.member.as_ident();
1918 let member = &f.member;
1919 let pin_marker = if f.pinned {
1920 quote!(Pinned)
1921 } else {
1922 quote!(Unpinned)
1923 };
1924
1925 let (slot_ty, slot_arg) = match &f.borrowed {
1926 None => (quote!(Slot), quote!()),
1927 Some(BorrowedInfo {
1928 kind: BorrowedKind::Shared,
1929 lifetime,
1930 ..
1931 }) => (
1932 quote!(SelfRefSlot),
1945 quote!(#lifetime, ::pin_init::__internal::Shared, ),
1946 ),
1947 Some(BorrowedInfo {
1948 kind: BorrowedKind::Mutable,
1949 lifetime,
1950 ..
1951 }) => (
1952 quote!(SelfRefSlot),
1965 quote!(#lifetime, ::pin_init::__internal::Mutable, ),
1966 ),
1967 };
1968
1969 quote! {
1970 #[allow(non_snake_case)]
1979 #[inline(always)]
1980 #vis unsafe fn #field_name(
1981 self,
1982 slot: *mut #struct_name #ty_generics,
1983 ) -> ::pin_init::__internal::#slot_ty<
1984 #slot_arg ::pin_init::__internal::#pin_marker, #ty
1985 > {
1986 unsafe { ::pin_init::__internal::#slot_ty::new(&raw mut (*slot).#member as _) }
1994 }
1995 }
1996 })
1997 .collect::<TokenStream>();
1998
1999 let exist_lt_generics_params = info.exist_lts_generics.params.iter();
2000 quote! {
2001 #[doc(hidden)]
2003 #[allow(non_snake_case, explicit_outlives_requirements)]
2004 #vis struct __PinDataLt #generics_with_field_lt
2005 #whr_with_field_lt
2006 {
2007 #(#phantom_fields)*
2008 __pin_phantom: ::core::marker::PhantomData<#struct_name #ty_generics>,
2009 }
2010
2011 impl #impl_generics_with_lt ::core::clone::Clone for __PinDataLt #ty_generics_with_field_lt
2012 #whr_with_field_lt
2013 {
2014 fn clone(&self) -> Self { *self }
2015 }
2016
2017 impl #impl_generics_with_lt ::core::marker::Copy for __PinDataLt #ty_generics_with_field_lt
2018 #whr_with_field_lt
2019 {}
2020
2021 #[allow(dead_code)] #[expect(clippy::missing_safety_doc)]
2023 impl #impl_generics_with_lt __PinDataLt #ty_generics_with_field_lt
2024 #whr_with_field_lt
2025 {
2026 #field_accessors
2027 }
2028
2029 #[doc(hidden)]
2033 #vis struct __ThePinData #generics
2034 #whr
2035 {
2036 __phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>,
2037 }
2038
2039 impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics
2040 #whr
2041 {
2042 #[inline]
2043 fn clone(&self) -> Self { *self }
2044 }
2045
2046 impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics
2047 #whr
2048 {}
2049
2050 impl #impl_generics __ThePinData #ty_generics
2051 #whr
2052 {
2053 #[inline(always)]
2055 #vis fn __make_closure<#(#exist_lt_generics_params,)* __F, __E>(self, f: __F) -> __F
2056 where
2057 __F: for #field_lt_ty_generics ::core::ops::FnOnce(
2058 *mut #struct_name #ty_generics,
2059 __PinDataLt #ty_generics_with_field_lt
2060 ) -> ::core::result::Result<::pin_init::__internal::InitOk, __E>,
2061 {
2062 f
2063 }
2064
2065 #[inline(always)]
2066 #vis fn __with_lt #field_exist_lt_ty_generics(self)
2067 -> __PinDataLt #ty_generics_with_field_lt
2068 {
2069 unsafe { ::core::mem::zeroed() }
2072 }
2073 }
2074
2075 unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics
2078 #whr
2079 {
2080 type PinData = __ThePinData #ty_generics;
2081
2082 #[inline]
2083 fn __pin_data(_: ::pin_init::__internal::InitData<Self>) -> Self::PinData {
2084 __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() }
2085 }
2086 }
2087 }
2088}
2089
2090struct SelfReplacer(PathSegment);
2091
2092impl VisitMut for SelfReplacer {
2093 fn visit_path_mut(&mut self, i: &mut syn::Path) {
2094 if i.is_ident("Self") {
2095 let span = i.span();
2096 let seg = &self.0;
2097 *i = parse_quote_spanned!(span=> #seg);
2098 } else {
2099 syn::visit_mut::visit_path_mut(self, i);
2100 }
2101 }
2102
2103 fn visit_path_segment_mut(&mut self, seg: &mut PathSegment) {
2104 if seg.ident == "Self" {
2105 let span = seg.span();
2106 let this = &self.0;
2107 *seg = parse_quote_spanned!(span=> #this);
2108 } else {
2109 syn::visit_mut::visit_path_segment_mut(self, seg);
2110 }
2111 }
2112
2113 fn visit_item_mut(&mut self, _: &mut Item) {
2114 }
2116}