xso-proc: improve error message on type mismatch for extracted fields
Jonas Schäfer
created
The case this affects is a field like:
```
struct Foo {
#[xml(extract(fields(text(type_ = String)), namespace = .., name = ..))]
foo: ServiceType,
}
```
Before, we get this:
```
error[E0631]: type mismatch in closure arguments
--> muchopper/libmuchopper/src/xmpp/sjn_api.rs:188:10
|
188 | #[derive(AsXml)]
| ^^^^^
| |
| expected due to this
| found signature defined here
|
= note: expected closure signature `fn(&ServiceType) -> _`
found closure signature `fn(&'xso_proc_as_xml_iter_lifetime std::string::String) -> _`
note: required by a bound in `std::option::Option::<T>::map`
--> /home/jssfr/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1102:12
|
1100 | pub fn map<U, F>(self, f: F) -> Option<U>
| --- required by a bound in this associated function
1101 | where
1102 | F: FnOnce(T) -> U,
| ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
= note: this error originates in the derive macro `AsXml` (in Nightly builds, run with -Z macro-backtrace for more info)
```
Afterwards, this:
```
error[E0308]: mismatched types
--> muchopper/libmuchopper/src/xmpp/sjn_api.rs:207:20
|
206 | #[xml(extract(namespace = ECS, name = "service-type", fields(text(type_ = String))))]
| ------ expected due to this
207 | pub service_type: ServiceType,
| ^^^^^^^^^^^ expected `Option<&String>`, found `Option<&ServiceType>`
|
= note: expected enum `std::option::Option<&'xso_proc_as_xml_iter_lifetime std::string::String>`
found enum `std::option::Option<&ServiceType>`
```
skip-changelog, because this affects a feature which already has an
"Added" line in the changelog.
@@ -460,14 +460,22 @@ impl ExtractDef {
// about that in [`make_from_xml_builder_parts`] implementation
// corresponding to this code above, and we will not repeat it
// here.
+
+ // These sections with quote_spanned are used to improve error
+ // messages on type mismatches. Without these, the rustc errors
+ // will point at `#[derive(AsXml)]` only, instead of directly
+ // pointing at the sources of those types.
let cast = quote_spanned! { input_ty.span()=>
::core::option::Option::from(#bound_name)
};
+ let type_assert = quote_spanned! { inner_ty.span()=>
+ ::core::option::Option<#inner_ty>
+ };
(
quote! {
- ::xso::asxml::OptionAsXml::new(#cast.map(|#bound_name: #inner_ty| {
+ ::xso::asxml::OptionAsXml::new({ let x: #type_assert = #cast; x.map(|#bound_name: #inner_ty| {
#item_iter_ty_ident::new((#repack))
- }).transpose()?)
+ })}.transpose()?)
},
option_as_xml_ty(item_iter_ty),
)