]> git.lizzy.rs Git - rust.git/blob - src/test/ui/rfc-2091-track-caller/tracked-closure.rs
Rollup merge of #105955 - Nilstrieb:no-trivial-opt-wrappers-we-have-field-accesses...
[rust.git] / src / test / 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 }