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