• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 #![allow(
4     dead_code,
5     unreachable_pub,
6     clippy::items_after_statements,
7     clippy::no_effect_underscore_binding,
8     clippy::undocumented_unsafe_blocks
9 )]
10 
11 #[macro_use]
12 mod auxiliary;
13 
14 use std::{
15     marker::{PhantomData, PhantomPinned},
16     panic,
17     pin::Pin,
18 };
19 
20 use pin_project::{pin_project, pinned_drop, UnsafeUnpin};
21 
22 #[test]
projection()23 fn projection() {
24     #[pin_project(
25         project = StructProj,
26         project_ref = StructProjRef,
27         project_replace = StructProjOwn,
28     )]
29     struct Struct<T, U> {
30         #[pin]
31         f1: T,
32         f2: U,
33     }
34 
35     let mut s = Struct { f1: 1, f2: 2 };
36     let mut s_orig = Pin::new(&mut s);
37     let s = s_orig.as_mut().project();
38 
39     let _: Pin<&mut i32> = s.f1;
40     assert_eq!(*s.f1, 1);
41     let _: &mut i32 = s.f2;
42     assert_eq!(*s.f2, 2);
43 
44     assert_eq!(s_orig.as_ref().f1, 1);
45     assert_eq!(s_orig.as_ref().f2, 2);
46 
47     let mut s = Struct { f1: 1, f2: 2 };
48     let mut s = Pin::new(&mut s);
49     {
50         let StructProj { f1, f2 } = s.as_mut().project();
51         let _: Pin<&mut i32> = f1;
52         let _: &mut i32 = f2;
53     }
54     {
55         let StructProjRef { f1, f2 } = s.as_ref().project_ref();
56         let _: Pin<&i32> = f1;
57         let _: &i32 = f2;
58     }
59     {
60         let StructProjOwn { f1, f2 } = s.as_mut().project_replace(Struct { f1: 3, f2: 4 });
61         let _: PhantomData<i32> = f1;
62         let _: i32 = f2;
63         assert_eq!(f2, 2);
64         assert_eq!(s.f1, 3);
65         assert_eq!(s.f2, 4);
66     }
67 
68     #[pin_project(project_replace)]
69     struct TupleStruct<T, U>(#[pin] T, U);
70 
71     let mut s = TupleStruct(1, 2);
72     let s = Pin::new(&mut s).project();
73 
74     let _: Pin<&mut i32> = s.0;
75     assert_eq!(*s.0, 1);
76     let _: &mut i32 = s.1;
77     assert_eq!(*s.1, 2);
78 
79     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
80     #[derive(Eq, PartialEq, Debug)]
81     enum Enum<A, B, C, D> {
82         Tuple(#[pin] A, B),
83         Struct {
84             #[pin]
85             f1: C,
86             f2: D,
87         },
88         Unit,
89     }
90 
91     let mut e = Enum::Tuple(1, 2);
92     let mut e = Pin::new(&mut e);
93 
94     match e.as_mut().project() {
95         EnumProj::Tuple(x, y) => {
96             let x: Pin<&mut i32> = x;
97             assert_eq!(*x, 1);
98             let y: &mut i32 = y;
99             assert_eq!(*y, 2);
100         }
101         EnumProj::Struct { f1, f2 } => {
102             let _: Pin<&mut i32> = f1;
103             let _: &mut i32 = f2;
104             unreachable!();
105         }
106         EnumProj::Unit => unreachable!(),
107     }
108 
109     assert_eq!(&*e, &Enum::Tuple(1, 2));
110 
111     let mut e = Enum::Struct { f1: 3, f2: 4 };
112     let mut e = Pin::new(&mut e);
113 
114     match e.as_mut().project() {
115         EnumProj::Tuple(x, y) => {
116             let _: Pin<&mut i32> = x;
117             let _: &mut i32 = y;
118             unreachable!();
119         }
120         EnumProj::Struct { f1, f2 } => {
121             let _: Pin<&mut i32> = f1;
122             assert_eq!(*f1, 3);
123             let _: &mut i32 = f2;
124             assert_eq!(*f2, 4);
125         }
126         EnumProj::Unit => unreachable!(),
127     }
128 
129     if let EnumProj::Struct { f1, f2 } = e.as_mut().project() {
130         let _: Pin<&mut i32> = f1;
131         assert_eq!(*f1, 3);
132         let _: &mut i32 = f2;
133         assert_eq!(*f2, 4);
134     }
135 }
136 
137 #[test]
enum_project_set()138 fn enum_project_set() {
139     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
140     #[derive(Eq, PartialEq, Debug)]
141     enum Enum {
142         V1(#[pin] u8),
143         V2(bool),
144     }
145 
146     let mut e = Enum::V1(25);
147     let mut e_orig = Pin::new(&mut e);
148     let e_proj = e_orig.as_mut().project();
149 
150     match e_proj {
151         EnumProj::V1(val) => {
152             let new_e = Enum::V2(val.as_ref().get_ref() == &25);
153             e_orig.set(new_e);
154         }
155         EnumProj::V2(_) => unreachable!(),
156     }
157 
158     assert_eq!(e, Enum::V2(true));
159 }
160 
161 #[test]
where_clause()162 fn where_clause() {
163     #[pin_project]
164     struct Struct<T>
165     where
166         T: Copy,
167     {
168         f: T,
169     }
170 
171     #[pin_project]
172     struct TupleStruct<T>(T)
173     where
174         T: Copy;
175 
176     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
177     enum Enum<T>
178     where
179         T: Copy,
180     {
181         V(T),
182     }
183 }
184 
185 #[test]
where_clause_and_associated_type_field()186 fn where_clause_and_associated_type_field() {
187     #[pin_project(project_replace)]
188     struct Struct1<I>
189     where
190         I: Iterator,
191     {
192         #[pin]
193         f1: I,
194         f2: I::Item,
195     }
196 
197     #[pin_project(project_replace)]
198     struct Struct2<I, J>
199     where
200         I: Iterator<Item = J>,
201     {
202         #[pin]
203         f1: I,
204         f2: J,
205     }
206 
207     #[pin_project(project_replace)]
208     struct Struct3<T>
209     where
210         T: 'static,
211     {
212         f: T,
213     }
214 
215     trait Static: 'static {}
216 
217     impl<T> Static for Struct3<T> {}
218 
219     #[pin_project(project_replace)]
220     struct TupleStruct<I>(#[pin] I, I::Item)
221     where
222         I: Iterator;
223 
224     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
225     enum Enum<I>
226     where
227         I: Iterator,
228     {
229         V1(#[pin] I),
230         V2(I::Item),
231     }
232 }
233 
234 #[test]
derive_copy()235 fn derive_copy() {
236     #[pin_project(project_replace)]
237     #[derive(Clone, Copy)]
238     struct Struct<T> {
239         f: T,
240     }
241 
242     fn is_copy<T: Copy>() {}
243 
244     is_copy::<Struct<u8>>();
245 }
246 
247 #[test]
move_out()248 fn move_out() {
249     struct NotCopy;
250 
251     #[pin_project(project_replace)]
252     struct Struct {
253         f: NotCopy,
254     }
255 
256     let x = Struct { f: NotCopy };
257     let _val: NotCopy = x.f;
258 
259     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
260     enum Enum {
261         V(NotCopy),
262     }
263 
264     let x = Enum::V(NotCopy);
265     #[allow(clippy::infallible_destructuring_match)]
266     let _val: NotCopy = match x {
267         Enum::V(val) => val,
268     };
269 }
270 
271 #[test]
trait_bounds_on_type_generics()272 fn trait_bounds_on_type_generics() {
273     #[pin_project(project_replace)]
274     pub struct Struct1<'a, T: ?Sized> {
275         f: &'a mut T,
276     }
277 
278     #[pin_project(project_replace)]
279     pub struct Struct2<'a, T: ::core::fmt::Debug> {
280         f: &'a mut T,
281     }
282 
283     #[pin_project(project_replace)]
284     pub struct Struct3<'a, T: core::fmt::Debug> {
285         f: &'a mut T,
286     }
287 
288     #[pin_project(project_replace)]
289     pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
290         f: &'a mut T,
291     }
292 
293     #[pin_project(project_replace)]
294     pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
295         f: &'a mut T,
296     }
297 
298     #[pin_project(project_replace)]
299     pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> {
300         f: &'a mut T,
301     }
302 
303     let _: Struct6<'_> = Struct6 { f: &mut [0_u8; 16] };
304 
305     #[pin_project(project_replace)]
306     pub struct Struct7<T: 'static> {
307         f: T,
308     }
309 
310     trait Static: 'static {}
311 
312     impl<T> Static for Struct7<T> {}
313 
314     #[pin_project(project_replace)]
315     pub struct Struct8<'a, 'b: 'a> {
316         f1: &'a u8,
317         f2: &'b u8,
318     }
319 
320     #[pin_project(project_replace)]
321     pub struct TupleStruct<'a, T: ?Sized>(&'a mut T);
322 
323     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
324     enum Enum<'a, T: ?Sized> {
325         V(&'a mut T),
326     }
327 }
328 
329 #[test]
overlapping_lifetime_names()330 fn overlapping_lifetime_names() {
331     #[pin_project(project_replace)]
332     pub struct Struct1<'pin, T> {
333         #[pin]
334         f: &'pin mut T,
335     }
336 
337     #[pin_project(project_replace)]
338     pub struct Struct2<'pin, 'pin_, 'pin__> {
339         #[pin]
340         f: &'pin &'pin_ &'pin__ (),
341     }
342 
343     pub trait Trait<'a> {}
344 
345     #[pin_project(project_replace)]
346     pub struct Hrtb<'pin___, T>
347     where
348         for<'pin> &'pin T: Unpin,
349         T: for<'pin> Trait<'pin>,
350         for<'pin, 'pin_, 'pin__> &'pin &'pin_ &'pin__ T: Unpin,
351     {
352         #[pin]
353         f: &'pin___ mut T,
354     }
355 
356     #[pin_project(PinnedDrop)]
357     pub struct PinnedDropStruct<'pin> {
358         #[pin]
359         f: &'pin (),
360     }
361 
362     #[pinned_drop]
363     impl PinnedDrop for PinnedDropStruct<'_> {
364         fn drop(self: Pin<&mut Self>) {}
365     }
366 
367     #[pin_project(UnsafeUnpin)]
368     pub struct UnsafeUnpinStruct<'pin> {
369         #[pin]
370         f: &'pin (),
371     }
372 
373     unsafe impl UnsafeUnpin for UnsafeUnpinStruct<'_> {}
374 
375     #[pin_project(!Unpin)]
376     pub struct NotUnpinStruct<'pin> {
377         #[pin]
378         f: &'pin (),
379     }
380 }
381 
382 #[test]
combine()383 fn combine() {
384     #[pin_project(PinnedDrop, UnsafeUnpin)]
385     pub struct PinnedDropWithUnsafeUnpin<T> {
386         #[pin]
387         f: T,
388     }
389 
390     #[pinned_drop]
391     impl<T> PinnedDrop for PinnedDropWithUnsafeUnpin<T> {
392         fn drop(self: Pin<&mut Self>) {}
393     }
394 
395     unsafe impl<T: Unpin> UnsafeUnpin for PinnedDropWithUnsafeUnpin<T> {}
396 
397     #[pin_project(PinnedDrop, !Unpin)]
398     pub struct PinnedDropWithNotUnpin<T> {
399         #[pin]
400         f: T,
401     }
402 
403     #[pinned_drop]
404     impl<T> PinnedDrop for PinnedDropWithNotUnpin<T> {
405         fn drop(self: Pin<&mut Self>) {}
406     }
407 
408     #[pin_project(UnsafeUnpin, project_replace)]
409     pub struct UnsafeUnpinWithReplace<T> {
410         #[pin]
411         f: T,
412     }
413 
414     unsafe impl<T: Unpin> UnsafeUnpin for UnsafeUnpinWithReplace<T> {}
415 
416     #[pin_project(!Unpin, project_replace)]
417     pub struct NotUnpinWithReplace<T> {
418         #[pin]
419         f: T,
420     }
421 }
422 
423 #[test]
private_type_in_public_type()424 fn private_type_in_public_type() {
425     #[pin_project(project_replace)]
426     pub struct PublicStruct<T> {
427         #[pin]
428         inner: PrivateStruct<T>,
429     }
430 
431     struct PrivateStruct<T>(T);
432 }
433 
434 #[allow(clippy::needless_lifetimes)]
435 #[test]
lifetime_project()436 fn lifetime_project() {
437     #[pin_project(project_replace)]
438     struct Struct1<T, U> {
439         #[pin]
440         pinned: T,
441         unpinned: U,
442     }
443 
444     #[pin_project(project_replace)]
445     struct Struct2<'a, T, U> {
446         #[pin]
447         pinned: &'a T,
448         unpinned: U,
449     }
450 
451     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
452     enum Enum<T, U> {
453         V {
454             #[pin]
455             pinned: T,
456             unpinned: U,
457         },
458     }
459 
460     impl<T, U> Struct1<T, U> {
461         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
462             self.project_ref().pinned
463         }
464         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
465             self.project().pinned
466         }
467         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
468             self.project_ref().pinned
469         }
470         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
471             self.project().pinned
472         }
473     }
474 
475     impl<'b, T, U> Struct2<'b, T, U> {
476         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b T> {
477             self.project_ref().pinned
478         }
479         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b T> {
480             self.project().pinned
481         }
482         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&&'b T> {
483             self.project_ref().pinned
484         }
485         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut &'b T> {
486             self.project().pinned
487         }
488     }
489 
490     impl<T, U> Enum<T, U> {
491         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
492             match self.project_ref() {
493                 EnumProjRef::V { pinned, .. } => pinned,
494             }
495         }
496         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
497             match self.project() {
498                 EnumProj::V { pinned, .. } => pinned,
499             }
500         }
501         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
502             match self.project_ref() {
503                 EnumProjRef::V { pinned, .. } => pinned,
504             }
505         }
506         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
507             match self.project() {
508                 EnumProj::V { pinned, .. } => pinned,
509             }
510         }
511     }
512 }
513 
514 mod visibility {
515     use pin_project::pin_project;
516 
517     #[pin_project(project_replace)]
518     pub(crate) struct S {
519         pub f: u8,
520     }
521 }
522 
523 #[test]
visibility()524 fn visibility() {
525     let mut x = visibility::S { f: 0 };
526     let x = Pin::new(&mut x);
527     let y = x.as_ref().project_ref();
528     let _: &u8 = y.f;
529     let y = x.project();
530     let _: &mut u8 = y.f;
531 }
532 
533 #[test]
trivial_bounds()534 fn trivial_bounds() {
535     #[pin_project(project_replace)]
536     pub struct NoGenerics {
537         #[pin]
538         f: PhantomPinned,
539     }
540 
541     assert_not_unpin!(NoGenerics);
542 }
543 
544 #[test]
dst()545 fn dst() {
546     #[pin_project]
547     struct Struct1<T: ?Sized> {
548         f: T,
549     }
550 
551     let mut x = Struct1 { f: 0_u8 };
552     let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x);
553     let _: &mut (dyn core::fmt::Debug) = x.project().f;
554 
555     #[pin_project]
556     struct Struct2<T: ?Sized> {
557         #[pin]
558         f: T,
559     }
560 
561     let mut x = Struct2 { f: 0_u8 };
562     let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x);
563     let _: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().f;
564 
565     #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
566     #[pin_project]
567     struct Struct3<T>
568     where
569         T: ?Sized,
570     {
571         f: T,
572     }
573 
574     #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
575     #[pin_project]
576     struct Struct4<T>
577     where
578         T: ?Sized,
579     {
580         #[pin]
581         f: T,
582     }
583 
584     #[pin_project(UnsafeUnpin)]
585     struct Struct5<T: ?Sized> {
586         f: T,
587     }
588 
589     #[pin_project(UnsafeUnpin)]
590     struct Struct6<T: ?Sized> {
591         #[pin]
592         f: T,
593     }
594 
595     #[pin_project(PinnedDrop)]
596     struct Struct7<T: ?Sized> {
597         f: T,
598     }
599 
600     #[pinned_drop]
601     impl<T: ?Sized> PinnedDrop for Struct7<T> {
602         fn drop(self: Pin<&mut Self>) {}
603     }
604 
605     #[pin_project(PinnedDrop)]
606     struct Struct8<T: ?Sized> {
607         #[pin]
608         f: T,
609     }
610 
611     #[pinned_drop]
612     impl<T: ?Sized> PinnedDrop for Struct8<T> {
613         fn drop(self: Pin<&mut Self>) {}
614     }
615 
616     #[pin_project(!Unpin)]
617     struct Struct9<T: ?Sized> {
618         f: T,
619     }
620 
621     #[pin_project(!Unpin)]
622     struct Struct10<T: ?Sized> {
623         #[pin]
624         f: T,
625     }
626 
627     #[pin_project]
628     struct Struct11<'a, T: ?Sized, U: ?Sized> {
629         f1: &'a mut T,
630         f2: U,
631     }
632 
633     #[pin_project]
634     struct TupleStruct1<T: ?Sized>(T);
635 
636     #[pin_project]
637     struct TupleStruct2<T: ?Sized>(#[pin] T);
638 
639     #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
640     #[pin_project]
641     struct TupleStruct3<T>(T)
642     where
643         T: ?Sized;
644 
645     #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
646     #[pin_project]
647     struct TupleStruct4<T>(#[pin] T)
648     where
649         T: ?Sized;
650 
651     #[pin_project(UnsafeUnpin)]
652     struct TupleStruct5<T: ?Sized>(T);
653 
654     #[pin_project(UnsafeUnpin)]
655     struct TupleStruct6<T: ?Sized>(#[pin] T);
656 
657     #[pin_project(PinnedDrop)]
658     struct TupleStruct7<T: ?Sized>(T);
659 
660     #[pinned_drop]
661     impl<T: ?Sized> PinnedDrop for TupleStruct7<T> {
662         fn drop(self: Pin<&mut Self>) {}
663     }
664 
665     #[pin_project(PinnedDrop)]
666     struct TupleStruct8<T: ?Sized>(#[pin] T);
667 
668     #[pinned_drop]
669     impl<T: ?Sized> PinnedDrop for TupleStruct8<T> {
670         fn drop(self: Pin<&mut Self>) {}
671     }
672 
673     #[pin_project(!Unpin)]
674     struct TupleStruct9<T: ?Sized>(T);
675 
676     #[pin_project(!Unpin)]
677     struct TupleStruct10<T: ?Sized>(#[pin] T);
678 
679     #[pin_project]
680     struct TupleStruct11<'a, T: ?Sized, U: ?Sized>(&'a mut T, U);
681 }
682 
683 #[test]
dyn_type()684 fn dyn_type() {
685     #[pin_project]
686     struct Struct1 {
687         f: dyn core::fmt::Debug,
688     }
689 
690     #[pin_project]
691     struct Struct2 {
692         #[pin]
693         f: dyn core::fmt::Debug,
694     }
695 
696     #[pin_project]
697     struct Struct3 {
698         f: dyn core::fmt::Debug + Send,
699     }
700 
701     #[pin_project]
702     struct Struct4 {
703         #[pin]
704         f: dyn core::fmt::Debug + Send,
705     }
706 
707     #[pin_project]
708     struct TupleStruct1(dyn core::fmt::Debug);
709 
710     #[pin_project]
711     struct TupleStruct2(#[pin] dyn core::fmt::Debug);
712 
713     #[pin_project]
714     struct TupleStruct3(dyn core::fmt::Debug + Send);
715 
716     #[pin_project]
717     struct TupleStruct4(#[pin] dyn core::fmt::Debug + Send);
718 }
719 
720 // TODO: how do we handle this? Should propagate #[repr(...)] to ProjectionOwned? The layout will be different from the original anyway due to PhantomData.
721 #[allow(clippy::trailing_empty_array)]
722 #[test]
parse_self()723 fn parse_self() {
724     macro_rules! mac {
725         ($($tt:tt)*) => {
726             $($tt)*
727         };
728     }
729 
730     pub trait Trait {
731         type Assoc;
732     }
733 
734     #[allow(clippy::type_repetition_in_bounds)]
735     #[pin_project(project_replace)]
736     pub struct Generics<T: Trait<Assoc = Self>>
737     where
738         Self: Trait<Assoc = Self>,
739         <Self as Trait>::Assoc: Sized,
740         mac!(Self): Trait<Assoc = mac!(Self)>,
741     {
742         _f: T,
743     }
744 
745     impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
746         type Assoc = Self;
747     }
748 
749     #[pin_project(project_replace)]
750     pub struct Struct {
751         _f1: Box<Self>,
752         _f2: Box<<Self as Trait>::Assoc>,
753         _f3: Box<mac!(Self)>,
754         _f4: [(); Self::ASSOC],
755         _f5: [(); Self::assoc()],
756         _f6: [(); mac!(Self::assoc())],
757     }
758 
759     impl Struct {
760         const ASSOC: usize = 1;
761         const fn assoc() -> usize {
762             0
763         }
764     }
765 
766     impl Trait for Struct {
767         type Assoc = Self;
768     }
769 
770     #[pin_project(project_replace)]
771     struct Tuple(
772         Box<Self>,
773         Box<<Self as Trait>::Assoc>,
774         Box<mac!(Self)>,
775         [(); Self::ASSOC],
776         [(); Self::assoc()],
777         [(); mac!(Self::assoc())],
778     );
779 
780     impl Tuple {
781         const ASSOC: usize = 1;
782         const fn assoc() -> usize {
783             0
784         }
785     }
786 
787     impl Trait for Tuple {
788         type Assoc = Self;
789     }
790 
791     #[pin_project(project = EnumProj, project_ref = EnumProjRef, project_replace = EnumProjOwn)]
792     enum Enum {
793         Struct {
794             _f1: Box<Self>,
795             _f2: Box<<Self as Trait>::Assoc>,
796             _f3: Box<mac!(Self)>,
797             _f4: [(); Self::ASSOC],
798             _f5: [(); Self::assoc()],
799             _f6: [(); mac!(Self::assoc())],
800         },
801         Tuple(
802             Box<Self>,
803             Box<<Self as Trait>::Assoc>,
804             Box<mac!(Self)>,
805             [(); Self::ASSOC],
806             [(); Self::assoc()],
807             [(); mac!(Self::assoc())],
808         ),
809     }
810 
811     impl Enum {
812         const ASSOC: usize = 1;
813         const fn assoc() -> usize {
814             0
815         }
816     }
817 
818     impl Trait for Enum {
819         type Assoc = Self;
820     }
821 }
822 
823 #[test]
824 fn no_infer_outlives() {
825     trait Trait<X> {
826         type Y;
827     }
828 
829     struct Struct1<A>(A);
830 
831     impl<X, T> Trait<X> for Struct1<T> {
832         type Y = Option<T>;
833     }
834 
835     #[pin_project(project_replace)]
836     struct Struct2<A, B> {
837         _f: <Struct1<A> as Trait<B>>::Y,
838     }
839 }
840 
841 // https://github.com/rust-lang/rust/issues/47949
842 // https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111
843 #[allow(clippy::many_single_char_names)]
844 #[test]
845 fn project_replace_panic() {
846     #[pin_project(project_replace)]
847     struct S<T, U> {
848         #[pin]
849         pinned: T,
850         unpinned: U,
851     }
852 
853     struct D<'a>(&'a mut bool, bool);
854     impl Drop for D<'_> {
855         fn drop(&mut self) {
856             *self.0 = true;
857             if self.1 {
858                 panic!();
859             }
860         }
861     }
862 
863     let (mut a, mut b, mut c, mut d) = (false, false, false, false);
864     let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
865         let mut x = S { pinned: D(&mut a, true), unpinned: D(&mut b, false) };
866         let _y = Pin::new(&mut x)
867             .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
868         // Previous `x.pinned` was dropped and panicked when `project_replace` is
869         // called, so this is unreachable.
870         unreachable!();
871     }));
872     assert!(res.is_err());
873     assert!(a);
874     assert!(b);
875     assert!(c);
876     assert!(d);
877 
878     let (mut a, mut b, mut c, mut d) = (false, false, false, false);
879     let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
880         let mut x = S { pinned: D(&mut a, false), unpinned: D(&mut b, true) };
881         {
882             let _y = Pin::new(&mut x)
883                 .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
884             // `_y` (previous `x.unpinned`) live to the end of this scope, so
885             // this is not unreachable.
886             // unreachable!();
887         }
888         unreachable!();
889     }));
890     assert!(res.is_err());
891     assert!(a);
892     assert!(b);
893     assert!(c);
894     assert!(d);
895 }
896