Skip to content

Commit 153eaa2

Browse files
authored
feat: Minimize diagnostic noise when Pavex attributes emit an error (#559)
Related issue: #538
1 parent 0cbc412 commit 153eaa2

File tree

9 files changed

+83
-8
lines changed

9 files changed

+83
-8
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ We contributors to Pavex:
2020
- Oliver Barnes (@oliverbarnes)
2121
- Joe Hasson (@joehasson)
2222
- Peter Wischer (@peddermaster2)
23-
- Paras Sharma (@duckaet)
23+
- Paras Sharma (@Duckaet)

runtime/pavex_macros/src/utils/fn_like.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Machinery to abstract away the parsing and validation logic that's shared by all
22
//! Pavex components that accept function-like inputs.
33
use proc_macro2::TokenStream;
4-
use syn::ImplItemFn;
4+
use quote::quote;
5+
use syn::{ImplItemFn, visit_mut::VisitMut};
56

67
use crate::utils::{AnnotationCodegen, deny_unreachable_pub_attr, validation::must_be_public};
78

@@ -98,9 +99,17 @@ pub fn direct_entrypoint<M: CallableAnnotation>(
9899
Ok(output.emit(input))
99100
}
100101

101-
match _inner::<M>(metadata, input) {
102+
match _inner::<M>(metadata, input.clone()) {
102103
Ok(t) => t.into(),
103-
Err(t) => t,
104+
Err(error_tokens) => {
105+
let error_tokens = proc_macro2::TokenStream::from(error_tokens);
106+
let mut input_item: syn::Item = syn::parse2(input).expect("Input is not a valid syn::Item");
107+
crate::utils::PxStripper.visit_item_mut(&mut input_item);
108+
quote! {
109+
#error_tokens
110+
#input_item
111+
}.into()
112+
}
104113
}
105114
}
106115

runtime/pavex_macros/src/utils/type_like.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
//! Pavex components that accept type-like inputs.
33
use convert_case::{Case, Casing as _};
44
use proc_macro2::TokenStream;
5-
use quote::{ToTokens, format_ident};
6-
use syn::parse_quote;
5+
use quote::{quote, ToTokens, format_ident};
6+
use syn::{parse_quote, visit_mut::VisitMut};
77

88
use crate::utils::{AnnotationCodegen, deny_unreachable_pub_attr, validation::must_be_public};
99

@@ -214,9 +214,17 @@ pub fn entrypoint<M: TypeAnnotation>(
214214
Ok(output.emit(input))
215215
}
216216

217-
match _inner::<M>(metadata, input) {
217+
match _inner::<M>(metadata, input.clone()) {
218218
Ok(t) => t.into(),
219-
Err(t) => t,
219+
Err(error_tokens) => {
220+
let error_tokens = proc_macro2::TokenStream::from(error_tokens);
221+
let mut input_item: syn::Item = syn::parse2(input).expect("Input is not a valid syn::Item");
222+
crate::utils::PxStripper.visit_item_mut(&mut input_item);
223+
quote! {
224+
#error_tokens
225+
#input_item
226+
}.into()
227+
}
220228
}
221229
}
222230

runtime/pavex_macros/tests/config/fail/group_rexport.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ error: Star re-exports can't be annotated with #[pavex::config].
1111
|
1212
7 | pub use private::*;
1313
| ^^^^^^^^^^^^^^^^^^^
14+
15+
warning: unused import: `private::*`
16+
--> tests/config/fail/group_rexport.rs:7:9
17+
|
18+
7 | pub use private::*;
19+
| ^^^^^^^^^^
20+
|
21+
= note: `#[warn(unused_imports)]` on by default
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use pavex_macros::config;
2+
3+
#[config]
4+
pub struct MyConfig {
5+
pub value: String,
6+
}
7+
8+
fn main() {
9+
let _config = MyConfig {
10+
value: "test".to_string(),
11+
};
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: Missing field `key`
2+
--> tests/config/fail/missing_key_with_usage.rs:3:1
3+
|
4+
3 | #[config]
5+
| ^^^^^^^^^
6+
|
7+
= note: this error originates in the attribute macro `config` (in Nightly builds, run with -Z macro-backtrace for more info)

runtime/pavex_macros/tests/config/fail/not_public.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,17 @@ error: Configuration types must be public.
3939
|
4040
19 | pub(crate) use sub::A as A3;
4141
| ^^^^^^^^^^
42+
43+
warning: unused import: `sub::A as A2`
44+
--> tests/config/fail/not_public.rs:16:5
45+
|
46+
16 | use sub::A as A2;
47+
| ^^^^^^^^^^^^
48+
|
49+
= note: `#[warn(unused_imports)]` on by default
50+
51+
warning: unused import: `sub::A as A3`
52+
--> tests/config/fail/not_public.rs:19:16
53+
|
54+
19 | pub(crate) use sub::A as A3;
55+
| ^^^^^^^^^^^^
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use pavex_macros::get;
2+
3+
#[get]
4+
pub fn my_route() -> pavex::Response {
5+
pavex::Response::new(pavex::http::StatusCode::OK)
6+
}
7+
8+
fn main() {
9+
let _response = my_route();
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: Missing field `path`
2+
--> tests/route/fail/missing_path.rs:3:1
3+
|
4+
3 | #[get]
5+
| ^^^^^^
6+
|
7+
= note: this error originates in the attribute macro `get` (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)