]> git.proxmox.com Git - rustc.git/blob - tests/ui/rfc-2091-track-caller/tracked-closure.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / tests / ui / rfc-2091-track-caller / tracked-closure.rs
1 // run-pass
2
3 #![feature(stmt_expr_attributes)]
4 #![feature(closure_track_caller)]
5 #![feature(generator_trait)]
6 #![feature(generators)]
7
8 use std::ops::{Generator, GeneratorState};
9 use std::pin::Pin;
10 use std::panic::Location;
11
12 type Loc = &'static Location<'static>;
13
14 #[track_caller]
15 fn mono_invoke_fn<F: Fn(&'static str, bool) -> (&'static str, bool, Loc)>(
16 val: &F
17 ) -> (&'static str, bool, Loc) {
18 val("from_mono", false)
19 }
20
21 #[track_caller]
22 fn mono_invoke_fn_once<F: FnOnce(&'static str, bool) -> (&'static str, bool, Loc)>(
23 val: F
24 ) -> (&'static str, bool, Loc) {
25 val("from_mono", false)
26 }
27
28 #[track_caller]
29 fn dyn_invoke_fn_mut(
30 val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc)
31 ) -> (&'static str, bool, Loc) {
32 val("from_dyn", false)
33 }
34
35 #[track_caller]
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)
40 }
41
42
43 fn test_closure() {
44 let mut track_closure = #[track_caller] |first: &'static str, second: bool| {
45 (first, second, Location::caller())
46 };
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);
54
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!());
61
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!());
68
69
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);
77
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);
85
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);
92 }
93
94
95 #[track_caller]
96 fn mono_generator<F: Generator<String, Yield = (&'static str, String, Loc), Return = ()>>(
97 val: Pin<&mut F>
98 ) -> (&'static str, String, Loc) {
99 match val.resume("Mono".to_string()) {
100 GeneratorState::Yielded(val) => val,
101 _ => unreachable!()
102 }
103 }
104
105 #[track_caller]
106 fn dyn_generator(
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,
111 _ => unreachable!()
112 }
113 }
114
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());
119 };
120
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!());
128
129
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);
138
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,
143 _ => unreachable!()
144 };
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);
148
149 }
150
151 fn main() {
152 test_closure();
153 test_generator();
154 }