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.

Change summary

xso-proc/src/field/child.rs | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

Detailed changes

xso-proc/src/field/child.rs 🔗

@@ -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),
             )