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);