@@ -50,7 +50,7 @@ impl<'a> ToTokens for MethodBody<'a> {
50
50
let unwrapped = if ty_is_option {
51
51
TokenStream :: from ( TokenTree :: Ident ( bind. clone ( ) ) )
52
52
} else {
53
- quote_spanned ! { f . ty . span ( ) => & #this. #ident }
53
+ quote ! { & #this. #ident }
54
54
} ;
55
55
56
56
let display = if let Some ( ref fmt) = f. meta . fmt {
@@ -94,6 +94,16 @@ impl<'a> ToTokens for MethodBody<'a> {
94
94
} ;
95
95
96
96
let mut stmt = if f. meta . encoded {
97
+ // Set the expression's span to `f.ty` so that a trait bound error will appear
98
+ // at the field's position.
99
+ //
100
+ // ```
101
+ // #[derive(Request)] // <- Not here
102
+ // struct Foo {
103
+ // field: (),
104
+ // //~^ ERROR: `()` doesn't implement `std::fmt::Display`
105
+ // }
106
+ // ```
97
107
quote_spanned ! { f. ty. span( ) =>
98
108
#ser. serialize_parameter_encoded( #name, #display) ;
99
109
}
@@ -114,10 +124,23 @@ impl<'a> ToTokens for MethodBody<'a> {
114
124
} ;
115
125
}
116
126
if ty_is_option {
117
- stmt = quote_spanned ! { f. ty. span( ) =>
127
+ let tmp = Ident :: new ( "tmp" , f. ty . span ( ) ) ;
128
+ stmt = quote ! {
118
129
if let :: std:: option:: Option :: Some ( #bind) = :: std:: option:: Option :: as_ref( {
119
- let value = & #this. #ident;
120
- value
130
+ // Set the argument's span to `f.ty` so that a type error will appear
131
+ // at the field's position. The span resolves at call site, so we are
132
+ // binding `#tmp` to the ephemeral block to avoid name conflict.
133
+ //
134
+ // ```
135
+ // #[derive(Request)] // <- Not here
136
+ // struct Foo {
137
+ // #[oauth1(option = true)]
138
+ // field: (),
139
+ // //~^ expected enum `Option`, found `()`
140
+ // }
141
+ // ```
142
+ let #tmp = & #this. #ident;
143
+ #tmp
121
144
} ) {
122
145
#stmt
123
146
}
0 commit comments