3 #![feature(stmt_expr_attributes)]
4 #![feature(closure_track_caller)]
5 #![feature(generator_trait)]
6 #![feature(generators)]
8 use std
::ops
::{Generator, GeneratorState}
;
10 use std
::panic
::Location
;
12 type Loc
= &'
static Location
<'
static>;
15 fn mono_invoke_fn
<F
: Fn(&'
static str, bool
) -> (&'
static str, bool
, Loc
)>(
17 ) -> (&'
static str, bool
, Loc
) {
18 val("from_mono", false)
22 fn mono_invoke_fn_once
<F
: FnOnce(&'
static str, bool
) -> (&'
static str, bool
, Loc
)>(
24 ) -> (&'
static str, bool
, Loc
) {
25 val("from_mono", false)
30 val
: &mut dyn FnMut(&'
static str, bool
) -> (&'
static str, bool
, Loc
)
31 ) -> (&'
static str, bool
, Loc
) {
32 val("from_dyn", false)
36 fn dyn_invoke_fn_once(
37 val
: Box
<dyn FnOnce(&'
static str, bool
) -> (&'
static str, bool
, Loc
)>
38 ) -> (&'
static str, bool
, Loc
) {
39 val("from_dyn", false)
44 let mut track_closure
= #[track_caller] |first: &'static str, second: bool| {
45 (first
, second
, Location
::caller())
47 let (first_arg
, first_bool
, first_loc
) = track_closure("first_arg", true);
48 let first_line
= line
!() - 1;
49 assert_eq
!(first_arg
, "first_arg");
50 assert_eq
!(first_bool
, true);
51 assert_eq
!(first_loc
.file(), file
!());
52 assert_eq
!(first_loc
.line(), first_line
);
53 assert_eq
!(first_loc
.column(), 46);
55 let (dyn_arg
, dyn_bool
, dyn_loc
) = dyn_invoke_fn_mut(&mut track_closure
);
56 assert_eq
!(dyn_arg
, "from_dyn");
57 assert_eq
!(dyn_bool
, false);
58 // `FnMut::call_mut` does not have `#[track_caller]`,
59 // so this will not match
60 assert_ne
!(dyn_loc
.file(), file
!());
62 let (dyn_arg
, dyn_bool
, dyn_loc
) = dyn_invoke_fn_once(Box
::new(track_closure
));
63 assert_eq
!(dyn_arg
, "from_dyn");
64 assert_eq
!(dyn_bool
, false);
65 // `FnOnce::call_once` does not have `#[track_caller]`
66 // so this will not match
67 assert_ne
!(dyn_loc
.file(), file
!());
70 let (mono_arg
, mono_bool
, mono_loc
) = mono_invoke_fn(&track_closure
);
71 let mono_line
= line
!() - 1;
72 assert_eq
!(mono_arg
, "from_mono");
73 assert_eq
!(mono_bool
, false);
74 assert_eq
!(mono_loc
.file(), file
!());
75 assert_eq
!(mono_loc
.line(), mono_line
);
76 assert_eq
!(mono_loc
.column(), 43);
78 let (mono_arg
, mono_bool
, mono_loc
) = mono_invoke_fn_once(track_closure
);
79 let mono_line
= line
!() - 1;
80 assert_eq
!(mono_arg
, "from_mono");
81 assert_eq
!(mono_bool
, false);
82 assert_eq
!(mono_loc
.file(), file
!());
83 assert_eq
!(mono_loc
.line(), mono_line
);
84 assert_eq
!(mono_loc
.column(), 43);
86 let non_tracked_caller
= || Location
::caller();
87 let non_tracked_line
= line
!() - 1; // This is the line of the closure, not its caller
88 let non_tracked_loc
= non_tracked_caller();
89 assert_eq
!(non_tracked_loc
.file(), file
!());
90 assert_eq
!(non_tracked_loc
.line(), non_tracked_line
);
91 assert_eq
!(non_tracked_loc
.column(), 33);
96 fn mono_generator
<F
: Generator
<String
, Yield
= (&'
static str, String
, Loc
), Return
= ()>>(
98 ) -> (&'
static str, String
, Loc
) {
99 match val
.resume("Mono".to_string()) {
100 GeneratorState
::Yielded(val
) => val
,
107 val
: Pin
<&mut dyn Generator
<String
, Yield
= (&'
static str, String
, Loc
), Return
= ()>>
108 ) -> (&'
static str, String
, Loc
) {
109 match val
.resume("Dyn".to_string()) {
110 GeneratorState
::Yielded(val
) => val
,
115 fn test_generator() {
116 let generator
= #[track_caller] |arg: String| {
117 yield ("first", arg
.clone(), Location
::caller());
118 yield ("second", arg
.clone(), Location
::caller());
121 let mut pinned
= Box
::pin(generator
);
122 let (dyn_ret
, dyn_arg
, dyn_loc
) = dyn_generator(pinned
.as_mut());
123 assert_eq
!(dyn_ret
, "first");
124 assert_eq
!(dyn_arg
, "Dyn".to_string());
125 // The `Generator` trait does not have `#[track_caller]` on `resume`, so
126 // this will not match.
127 assert_ne
!(dyn_loc
.file(), file
!());
130 let (mono_ret
, mono_arg
, mono_loc
) = mono_generator(pinned
.as_mut());
131 let mono_line
= line
!() - 1;
132 assert_eq
!(mono_ret
, "second");
133 // The generator ignores the argument to the second `resume` call
134 assert_eq
!(mono_arg
, "Dyn".to_string());
135 assert_eq
!(mono_loc
.file(), file
!());
136 assert_eq
!(mono_loc
.line(), mono_line
);
137 assert_eq
!(mono_loc
.column(), 42);
139 let non_tracked_generator
= || { yield Location::caller(); }
;
140 let non_tracked_line
= line
!() - 1; // This is the line of the generator, not its caller
141 let non_tracked_loc
= match Box
::pin(non_tracked_generator
).as_mut().resume(()) {
142 GeneratorState
::Yielded(val
) => val
,
145 assert_eq
!(non_tracked_loc
.file(), file
!());
146 assert_eq
!(non_tracked_loc
.line(), non_tracked_line
);
147 assert_eq
!(non_tracked_loc
.column(), 44);