polonius_the_crab/macros.rs
1#[allow(unused)]
2use super::{
3 exit_polonius,
4 polonius,
5 polonius_break,
6 polonius_break_dependent,
7 polonius_continue,
8 polonius_loop,
9 polonius_return,
10 polonius_try,
11};
12
13/// Convenient entry-point to this crate's logic.
14///
15/// - See the [top-level docs][crate] for more info.
16///
17/// ## Usage
18///
19/** - ```rust
20 use ::polonius_the_crab::prelude::*;
21
22 # fn foo (arg: &mut ()) -> &mut () {
23 let mut a_mut_binding: &mut _ = // …
24 # arg;
25 # type SomeRetType<'__> = &'__ mut ();
26 # let some_cond = || true;
27 # let some_other_cond = || true;
28 # use ::core::convert::identity as stuff;
29
30 // the lifetime placeholder has to be
31 // named `'polonius` !!
32 // vvvvvvvvv
33 let x = polonius!(|a_mut_binding| -> SomeRetType<'polonius> {
34 let some_dependent_type = stuff(a_mut_binding);
35 if some_cond() {
36 polonius_return!(some_dependent_type);
37 }
38 if some_other_cond() {
39 exit_polonius!(42);
40 unreachable!();
41 }
42 42
43 });
44 assert_eq!(x, 42);
45 stuff(a_mut_binding) // macro gave it back
46 // …
47 # }
48 ``` */
49///
50/// ### Generic parameters
51///
52/// They Just Work™.
53///
54/** - ```rust
55 use ::polonius_the_crab::prelude::*;
56
57 fn get_or_insert<'map, 'v, K, V : ?Sized> (
58 mut map: &'map mut ::std::collections::HashMap<K, &'v V>,
59 key: &'_ K,
60 fallback_value: &'v V,
61 ) -> &'map &'v V
62 where
63 K : ::core::hash::Hash + Eq + Clone,
64 V : ::core::fmt::Debug,
65 {
66 polonius!(|map| -> &'polonius &'v V {
67 if let Some(v) = map.get(key) {
68 dbg!(v);
69 polonius_return!(v);
70 }
71 });
72 map.insert(key.clone(), fallback_value);
73 &map[key]
74 }
75 ``` */
76#[macro_export]
77macro_rules! polonius {(
78 |$var:ident $(,)?| -> $Ret:ty
79 $body:block
80 $(,)?
81) => (
82 match
83 $crate::polonius::<
84 _,
85 _,
86 $crate::ForLt!(<'polonius> = $crate::ඞ::Dependent<$Ret>),
87 >(
88 $var,
89 |mut $var: &mut _| {
90 // silence the unused `mut` warning.
91 #[allow(clippy::self_assignment)] {
92 $var = $var;
93 }
94 $crate::PoloniusResult::Owned(
95 if true
96 $body
97 else {
98 // avoid a dead-code warning
99 $crate::ඞ::None.unwrap()
100 }
101 )
102 },
103 )
104 {
105 | $crate::PoloniusResult::Borrowing(ret) => return ret.return_no_break(),
106 | $crate::PoloniusResult::Owned { value, input_borrow, .. } => {
107 $var = input_borrow;
108 value
109 },
110 }
111)}
112
113impl<T> ඞ::Dependent<T> {
114 pub
115 fn return_no_break (self)
116 -> T
117 {
118 match self {
119 | Self::Return(it) => it,
120 | Self::Break(unreachable) => match unreachable {},
121 }
122 }
123}
124
125/// See [`polonius!`] for more info.
126#[macro_export]
127macro_rules! polonius_return {( $e:expr $(,)? ) => (
128 return $crate::PoloniusResult::Borrowing($crate::ඞ::Dependent::Return($e))
129)}
130
131/// See [`polonius!`] for more info.
132#[macro_export]
133macro_rules! exit_polonius {( $($e:expr $(,)?)? ) => (
134 return $crate::PoloniusResult::Owned(
135 ($($e ,)? (),).0
136 )
137)}
138
139/// Perform the `?` operation inside a [`polonius!`] or [`polonius_loop!`] block.
140///
141/// - Only [`Result`] and [`Option`] are supported (_e.g._, no `ControlFlow`).
142///
143/// See [`polonius!`] for more info.
144///
145/// ## Example
146///
147/** - ```rust
148 use {
149 ::polonius_the_crab::prelude::*,
150 ::std::collections::HashMap,
151 };
152
153 enum Error { /* … */ }
154
155 fn fallible_operation (value: &'_ i32)
156 -> Result<(), Error>
157 {
158 // …
159 # Ok(())
160 }
161
162 fn get_or_insert (
163 mut map: &'_ mut HashMap<i32, i32>,
164 ) -> Result<&'_ i32, Error>
165 {
166 polonius!(|map| -> Result<&'polonius i32, Error> {
167 if let Some(value) = map.get(&22) {
168 // fallible_operation(value)?;
169 polonius_try!(fallible_operation(value));
170 polonius_return!(Ok(value));
171 }
172 });
173 map.insert(22, 42);
174 Ok(&map[&22])
175 }
176 ``` */
177#[macro_export]
178macro_rules! polonius_try {( $e:expr $(,)? ) => (
179 match $crate::ඞ::Try::branch($e) {
180 | $crate::ඞ::Ok(it) => it,
181 | $crate::ඞ::Err(residual) => {
182 $crate::polonius_return!(
183 $crate::ඞ::Residual::with_output(residual)
184 )
185 },
186 }
187)}
188
189/// Convenience support for the `loop { … polonius!(…) }` pattern.
190///
191/// ### Example
192///
193/** - ```rust
194 #![forbid(unsafe_code)]
195 use {
196 ::polonius_the_crab::{
197 prelude::*,
198 },
199 ::std::{
200 collections::HashMap,
201 },
202 };
203
204 enum Value {
205 Alive(i32),
206 Daed,
207 }
208
209 // Notice how this example, *despite its usage of the fancy `.entry()` API
210 // of `HashMap`s*, still needs `polonius_the_crab` to work!
211 fn get_first_alive_from_base_or_insert (
212 mut map: &'_ mut HashMap<usize, Value>,
213 base: usize,
214 default_value: i32,
215 ) -> &'_ i32
216 {
217 let mut idx = base;
218 // (loop {
219 polonius_loop!(|map| -> &'polonius i32 {
220 use ::std::collections::hash_map::*;
221 // return(
222 polonius_return!(
223 match map.entry(idx) {
224 | Entry::Occupied(entry) => match entry.into_mut() {
225 // Found a value!
226 | &mut Value::Alive(ref val) => val,
227 // "tombstone", keep searching
228 | &mut Value::Daed => {
229 idx += 1;
230 // continue;
231 polonius_continue!();
232 },
233 },
234 | Entry::Vacant(slot) => match slot.insert(Value::Alive(default_value)) {
235 | &mut Value::Alive(ref val) => val,
236 | &mut Value::Daed => unreachable!(),
237 },
238 }
239 );
240 });
241 unreachable!();
242 }
243 ``` */
244///
245/// <details class="custom"><summary>Error message without <code>::polonius_the_crab</code></summary>
246///
247/** - ```rust ,compile_fail
248 # compile_error!("compiler error message"); /*
249 error[E0499]: cannot borrow `*map` as mutable more than once at a time
250 --> src/lib.rs:222:18
251 |
252 22 | mut map: &'_ mut HashMap<usize, Value>,
253 | - let's call the lifetime of this reference `'1`
254 ...
255 33 | match map.entry(idx) {
256 | ^^^ `*map` was mutably borrowed here in the previous iteration of the loop
257 ...
258 45 | | &mut Value::Alive(ref val) => val,
259 | --- returning this value requires that `*map` be borrowed for `'1`
260 # */
261 ``` */
262///
263/// ___
264///
265/// </details>
266///
267/// ## `break`s
268///
269/// Whilst `return` and `continue`s inside a [`polonius_loop!`] invocation are
270/// quite straight-forward, `break` is actually more subtle and difficult
271/// to use.
272///
273/// <details class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
274///
275/// Indeed, compare the `break` semantics of the following two snippets:
276///
277/** - ```rust ,ignore
278 let mut i = 0;
279 let found = loop {
280 match collection.get_mut(&i) {
281 Some(entry) => if entry.is_empty() {
282 break entry; // 👈
283 } else {
284 // …
285 },
286 None => i += 1,
287 }
288 };
289 ``` */
290///
291/// _vs._
292///
293/** - ```rust ,ignore
294 let mut i = 0;
295 let position = loop {
296 match collection.get_mut(&i) {
297 Some(entry) => if entry.is_empty() {
298 break i; // 👈
299 } else {
300 // this requires polonius{,_the_crab} btw
301 return entry;
302 },
303 None => i += 1,
304 }
305 };
306 ``` */
307///
308/// With the former, we have a **dependent** / borrowing-from-`collection`
309/// `entry` value, which is the one we want to `break`:
310///
311/// - this requires `polonius{,_the_crab}` (independently of the presence of
312/// return-of-dependent-value statements);
313///
314/// Whereas with the latter, we are `break`ing `i`, an integer/index, that is,
315/// a **non-dependent** value.
316///
317/// - this wouldn't require `polonius{,_the_crab}` if it weren't for the
318/// `return entry` statement which does return a dependent item.
319///
320/// So, with the former, we can't use `collection` while `entry` is alive[^1] ,
321/// whereas with the latter we perfectly can.
322///
323/// All these differences, which are type-system-based, represent information
324/// which is unaccessible for the `polonius…!` family of macros, so a
325/// single/unified `polonius_break!` macro for both things, for instance, would
326/// be unable to make such a difference: unnecessary compile errors would then
327/// ensue!
328///
329/// The solution is then to feature not one but _two_ `break`-ing macros,
330/// depending on whether the value which we want to break **depends on/borrows**
331/// the `&'polonius mut`-borrowed state.
332///
333/// - If yes, use [`polonius_break_dependent!`];
334///
335/// - this, in turn, **requires an additional `'polonius`-infected
336/// `break` type annotation** for the proper lifetimes to come into play:
337///
338/// <code>[polonius_loop!]\(|var| -\> … <span style="color: green; font-weight: bolder;">, break: … {</span></code>
339///
340/// - Else, use [`polonius_break!`] \(in which case the `break` type annotation
341/// should not be used\).
342///
343/// ### Examples
344///
345/** - ```rust
346 use {
347 ::polonius_the_crab::{
348 prelude::*,
349 },
350 ::std::{
351 collections::HashMap,
352 },
353 };
354
355 fn break_entry (mut coll: &'_ mut HashMap<i32, String>)
356 -> &'_ mut String
357 {
358 let mut i = 0;
359 // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
360 let found = polonius_loop!(|coll| -> _, break: &'polonius mut String {
361 match coll.get_mut(&i) {
362 Some(entry) => if entry.is_empty() {
363 polonius_break_dependent!(entry); // 👈
364 } else {
365 // …
366 },
367 None => i += 1,
368 }
369 });
370 found.push('!');
371 found
372 }
373 ``` */
374///
375/// _vs._
376///
377/** - ```rust
378 use {
379 ::polonius_the_crab::{
380 prelude::*,
381 },
382 ::std::{
383 collections::HashMap,
384 },
385 };
386
387 fn break_index (mut coll: &'_ mut HashMap<i32, String>)
388 -> &'_ mut String
389 {
390 let mut i = 0;
391 let position = polonius_loop!(|coll| -> &'polonius mut String {
392 match coll.get_mut(&i) {
393 Some(entry) => if entry.is_empty() {
394 polonius_break!(i); // 👈
395 } else {
396 polonius_return!(entry);
397 },
398 None => i += 1,
399 }
400 });
401 // Re-using `coll` is fine if not using the `dependent` flavor of break.
402 coll.get_mut(&i).unwrap()
403 }
404 ``` */
405///
406/// </details>
407///
408/// [^1]: In practice, with `polonius_break_dependent!` we won't be able to
409/// reuse `coll` anymore in the function. If this is a problem for you, you'll
410/// have no other choice but to refactor your loop into a smaller helper
411/// function so as to replace that `break` with a `return`.
412#[macro_export]
413macro_rules! polonius_loop {(
414 | $var:ident $(,)? | -> $Ret:ty $(, break: $Break:ty)?
415 $body:block
416 $(,)?
417) => (
418 loop {
419 match
420 $crate::polonius::<
421 _,
422 _,
423 $crate::ForLt!(<'polonius>
424 = $crate::ඞ::Dependent< $Ret $(, $Break)? >
425 ),
426 >(
427 &mut *$var,
428 |mut $var: &mut _| {
429 // silence the unused `mut` warning.
430 #[allow(clippy::self_assignment)] {
431 $var = $var;
432 }
433 let () =
434 if true
435 $body
436 else {
437 // avoid a dead-code warning
438 $crate::ඞ::core::option::Option::None.unwrap()
439 }
440 ;
441 $crate::polonius_continue!();
442 },
443 )
444 {
445 | $crate::PoloniusResult::Borrowing(dependent) => match dependent {
446 | $crate::ඞ::Dependent::Return(return_value) => return return_value,
447 | $crate::ඞ::Dependent::Break(break_value) => $crate::ඞ::first! {
448 $((
449 break if false { loop {} } else { break_value }
450 ) (if $Break type else))? ({
451 let _: $crate::ඞ::dependent_break_without_break_ty_annotation = break_value;
452 match break_value {}
453 })
454 },
455 },
456 | $crate::PoloniusResult::Owned { value, input_borrow, .. } => {
457 $var = input_borrow;
458 match value {
459 | $crate::ඞ::core::ops::ControlFlow::Break(value) => {
460 break if false { loop {} } else { value };
461 },
462 | $crate::ඞ::core::ops::ControlFlow::Continue(()) => continue,
463 }
464 },
465 }
466 }
467)}
468
469/// `break` a **non-dependent value** out of a [`polonius_loop!`].
470///
471/// - When the value to `break` with is **a dependent value** / a value that
472/// is _borrowing_ from the input, consider using
473/// [`polonius_break_dependent!`] instead.
474///
475/// ## Example
476///
477/** - ```rust
478 use {
479 ::std::{
480 collections::HashMap,
481 },
482 ::polonius_the_crab::{
483 *,
484 },
485 };
486
487 fn example (mut map: &'_ mut HashMap<u8, i32>)
488 -> Option<&'_ mut i32>
489 {
490 let mut i = 0;
491 let x = polonius_loop!(|map| -> Option<&'polonius mut i32> {
492 if let Some(entry) = map.get_mut(&i) {
493 polonius_return!(Some(entry));
494 }
495 i += 1;
496 if i == 42 {
497 polonius_break!(i);
498 }
499 });
500 assert_eq!(x, i);
501 // Access to the "captured" `map` is still possible if using `polonius_break!`
502 // (and thus no `break: …` annotation on the "closure")
503 map.clear();
504 None
505 }
506 ``` */
507///
508#[macro_export]
509macro_rules! polonius_break {( $($e:expr $(,)?)? ) => (
510 return $crate::PoloniusResult::Owned(
511 $crate::ඞ::core::ops::ControlFlow::Break(
512 ($($e ,)? () ,).0
513 )
514 )
515)}
516
517/// `break` a **dependent value** out of a [`polonius_loop!`].
518///
519/// To be used in conjunction with a
520/// <code>[polonius_loop!]\(|var| -\> …<span style="color: green; font-weight: bolder;">, break: …</span> {</code> invocation.
521///
522/// - If the `, break: …` type annotation is forgotten, then invocations to
523/// `polonius_break_dependent!` will fail with an error message complaining
524/// about `cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ`
525///
526/// ## Example
527///
528/** - ```rust
529 use {
530 ::std::{
531 collections::HashMap,
532 },
533 ::polonius_the_crab::{
534 *,
535 },
536 };
537
538 fn example (mut map: &'_ mut HashMap<u8, i32>)
539 {
540 let mut i = 0;
541 // needed for `polonius_break_dependent!` to work.
542 // vvvvvvvvvvvvvvvvvvvvvvvvvvv
543 let entry = polonius_loop!(|map| -> _, break: &'polonius mut i32 {
544 // ^^^^^^^^^
545 // don't forget the special annotation PoloniusResult.
546 if let Some(entry) = map.get_mut(&i) {
547 polonius_break_dependent!(entry);
548 }
549 i += 1;
550 });
551 // `map` was consumed by the loop, and is thus unusable.
552 // But the `break_dependent!`-yielded items is allowed to still be
553 // borrowing it.
554 *entry = 0;
555 }
556 ``` */
557///
558/// Now let's compare it to what happens when [`polonius_break!`] is
559/// (incorrectly) used in its stead:
560///
561/// #### Incorrect usage
562///
563/// The following **fails to compile**:
564///
565/** - ```rust ,compile_fail
566 use {
567 ::std::{
568 collections::HashMap,
569 },
570 ::polonius_the_crab::{
571 *,
572 },
573 };
574
575 fn example (mut map: &'_ mut HashMap<u8, i32>)
576 {
577 let mut i = 0;
578 let entry = polonius_loop!(|map| -> _ {
579 if let Some(entry) = map.get_mut(&i) {
580 polonius_break!(entry);
581 }
582 i += 1;
583 });
584 *entry = 0;
585 }
586 ``` */
587///
588/// with the following error message:
589///
590/** ```rust, compile_fail
591 # compile_error!("compiler error message"); /*
592 error: lifetime may not live long enough
593 --> src/lib.rs:467:13
594 |
595 16 | let entry = polonius_loop!(|map| -> _ {
596 | _________________-
597 17 | | if let Some(entry) = map.get_mut(&i) {
598 18 | | polonius_break!(entry);
599 | | ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
600 19 | | }
601 20 | | i += 1;
602 21 | | });
603 | | -
604 | | |
605 | |______let's call the lifetime of this reference `'1`
606 | return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>
607 # */
608 ``` */
609///
610/// Using `RUSTC_BOOTSTRAP=1 cargo rustc --profile-check -- -Zmacro-backtrace`
611/// to "improve" the error message, we can get:
612///
613/** ```rust ,compile_fail
614 # compile_error!("compiler error message"); /*
615 error: lifetime may not live long enough
616 --> polonius-the-crab/src/lib.rs:442:12
617 |
618 351 | |mut $var: &mut _| {
619 | - - return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>
620 | |
621 | let's call the lifetime of this reference `'1`
622 ...
623 441 | / macro_rules! polonius_break {( $($e:expr $(,)?)? ) => (
624 442 | | return $crate::ඞ::core::result::Result::Err(
625 | |____________^
626 443 | || $crate::ඞ::core::ops::ControlFlow::Break(
627 444 | || ($($e ,)? () ,).0
628 445 | || )
629 446 | || )
630 | ||_____^ returning this value requires that `'1` must outlive `'2`
631 447 | | )}
632 | |__- in this expansion of `polonius_break!`
633 |
634 ::: src/lib.rs:552:13
635 |
636 18 | polonius_break!(entry);
637 | ----------------------- in this macro invocation
638 # */
639 ``` */
640///
641/// Which may be a bit better at hinting that we have a borrowing problem with
642/// `polonius_break!`, whereby the returned value cannot reach some borrowing /
643/// lifetime requirements (those stemming from an actually-dependent break
644/// value).
645#[macro_export]
646macro_rules! polonius_break_dependent {( $e:expr $(,)? ) => (
647 return $crate::PoloniusResult::Borrowing(
648 $crate::ඞ::Dependent::Break($e)
649 )
650)}
651
652/// `continue` to the next iteration of a [`polonius_loop!`].
653#[macro_export]
654macro_rules! polonius_continue {() => (
655 return $crate::PoloniusResult::Owned(
656 $crate::ඞ::core::ops::ControlFlow::<_>::Continue(())
657 )
658)}
659
660// macro internals
661#[doc(hidden)] /** Not part of the public API */ pub
662mod ඞ {
663 #![allow(nonstandard_style)]
664
665 pub use ::core::{self, prelude::v1::*};
666
667 pub use crate::r#try::{Try, Residual};
668
669 pub
670 enum cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
671 {}
672
673 pub
674 enum Dependent<Return, Break = Never> {
675 Return(Return),
676 Break(Break),
677 }
678
679 use {
680 cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
681 as
682 Never,
683 };
684
685 pub
686 type dependent_break_without_break_ty_annotation =
687 cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
688 ;
689
690 #[doc(hidden)] /** Not part of the public API */ #[macro_export]
691 macro_rules! ඞ_first {(
692 ( $($tt:tt)* )
693 $($rest:tt)*
694 ) => (
695 $($tt)*
696 )} pub use ඞ_first as first;
697}