Skip to content

Commit d01c58e

Browse files
KaiJewsonandrewhickman
authored andcommitted
Add support for move option
1 parent abc3e4d commit d01c58e

File tree

9 files changed

+98
-26
lines changed

9 files changed

+98
-26
lines changed

src/lib.rs

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@
3737
extern crate proc_macro;
3838

3939
use proc_macro::TokenStream;
40-
use quote::quote;
40+
use proc_macro2::TokenStream as TokenStream2;
41+
use quote::{quote, ToTokens};
42+
use syn::parse::{self, Parse, ParseStream};
43+
use syn::Token;
4144

4245
/// Add context to errors from a function.
4346
///
@@ -55,32 +58,56 @@ use quote::quote;
5558
/// })().map_err(|err| err.context("context"))
5659
/// }
5760
/// ```
61+
///
62+
/// Sometimes you will receive borrowck errors, especially when returning references. These can
63+
/// often be fixed by setting the `move` option of the attribute macro. For example:
64+
///
65+
/// ```
66+
/// #[context(move, "context")]
67+
/// fn returns_reference(val: &mut u32) -> anyhow::Result<&mut u32> {
68+
/// Ok(&mut *val)
69+
/// }
70+
/// ```
5871
#[proc_macro_attribute]
5972
pub fn context(args: TokenStream, input: TokenStream) -> TokenStream {
60-
let args: proc_macro2::TokenStream = args.into();
73+
let Args(move_token, format_args) = syn::parse_macro_input!(args);
6174
let mut input = syn::parse_macro_input!(input as syn::ItemFn);
6275

6376
let body = &input.block;
6477
let return_ty = &input.sig.output;
65-
if input.sig.asyncness.is_some() {
66-
match return_ty {
78+
let new_body = if input.sig.asyncness.is_some() {
79+
let return_ty = match return_ty {
6780
syn::ReturnType::Default => {
68-
return syn::Error::new_spanned(return_ty, "function should return Result")
81+
return syn::Error::new_spanned(input, "function should return Result")
6982
.to_compile_error()
70-
.into()
71-
}
72-
syn::ReturnType::Type(_, return_ty) => {
73-
input.block.stmts = syn::parse_quote!(
74-
let result: #return_ty = async move { #body }.await;
75-
result.map_err(|err| err.context(format!(#args)).into())
76-
);
83+
.into();
7784
}
85+
syn::ReturnType::Type(_, return_ty) => return_ty,
86+
};
87+
quote! {
88+
let result: #return_ty = async #move_token { #body }.await;
89+
result.map_err(|err| err.context(format!(#format_args)).into())
7890
}
7991
} else {
80-
input.block.stmts = syn::parse_quote!(
81-
(|| #return_ty #body)().map_err(|err| err.context(format!(#args)).into())
82-
);
83-
}
92+
quote! {
93+
(#move_token || #return_ty #body)().map_err(|err| err.context(format!(#format_args)).into())
94+
}
95+
};
96+
input.block.stmts = vec![syn::Stmt::Expr(syn::Expr::Verbatim(new_body))];
8497

85-
quote!(#input).into()
98+
input.into_token_stream().into()
99+
}
100+
101+
struct Args(Option<Token![move]>, TokenStream2);
102+
impl Parse for Args {
103+
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
104+
let move_token = if input.peek(Token![move]) {
105+
let token = input.parse()?;
106+
input.parse::<Token![,]>()?;
107+
Some(token)
108+
} else {
109+
None
110+
};
111+
Ok(Self(move_token, input.parse()?))
112+
}
86113
}

tests/async_borrowing.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use fn_error_context::context;
22

33
#[context("context")]
4-
async fn borrows(val: &mut u32) -> anyhow::Result<&u32> {
5-
Ok(&*val)
4+
async fn borrows(x: &mut u32) -> anyhow::Result<&mut u32> {
5+
Ok(x)
66
}
77

8-
fn main() {
9-
}
8+
fn main() {}

tests/async_move.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use fn_error_context::context;
2+
3+
#[context(move, "context")]
4+
async fn borrows(val: &mut u32) -> anyhow::Result<&u32> {
5+
Ok(&*val)
6+
}
7+
8+
fn main() {}

tests/async_no_move.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use fn_error_context::context;
2+
3+
#[context("{}", context.as_ref())]
4+
async fn no_move(context: impl AsRef<str>) -> anyhow::Result<()> {
5+
context.as_ref();
6+
Ok(())
7+
}
8+
9+
fn main() {}

tests/async_without_return.stderr

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
error: function should return Result
2-
--> $DIR/async_without_return.rs:3:1
2+
--> $DIR/async_without_return.rs:4:1
33
|
4-
3 | #[context("context")]
5-
| ^^^^^^^^^^^^^^^^^^^^^
6-
|
7-
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
4+
4 | / async fn async_something() {
5+
5 | | }
6+
| |_^

tests/borrowing.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use fn_error_context::context;
2+
3+
#[context("context")]
4+
fn borrows(x: &mut u32) -> anyhow::Result<&mut u32> {
5+
Ok(x)
6+
}
7+
8+
fn main() {}

tests/move.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use fn_error_context::context;
2+
3+
#[context(move, "context")]
4+
fn foo(x: &mut u32) -> anyhow::Result<&u32> {
5+
Ok(&*x)
6+
}
7+
8+
fn main() {}

tests/no_move.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use fn_error_context::context;
2+
3+
#[context("{}", context.as_ref())]
4+
fn no_move(context: impl AsRef<str>) -> anyhow::Result<()> {
5+
context.as_ref();
6+
Ok(())
7+
}
8+
9+
fn main() {}

tests/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,10 @@ fn tests() {
1717
tests.pass("tests/fmt_named_arg.rs");
1818
tests.compile_fail("tests/async_without_return.rs");
1919
tests.compile_fail("tests/preserve_lint.rs");
20+
tests.pass("tests/borrowing.rs");
2021
tests.pass("tests/async_borrowing.rs");
22+
tests.pass("tests/no_move.rs");
23+
tests.pass("tests/async_no_move.rs");
24+
tests.pass("tests/move.rs");
25+
tests.pass("tests/async_move.rs");
2126
}

0 commit comments

Comments
 (0)