Move error message construction into checking functions

These were pulled out originally because error message construction was
so verbose that it detracted from being able to follow the logic of the
checks, but now that checks are broken up into finer granularity the
messages can be inlined.
diff --git a/syntax/check.rs b/syntax/check.rs
index 5a3590f..256a193 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -1,7 +1,8 @@
 use crate::syntax::atom::Atom::{self, *};
-use crate::syntax::{error, ident, Api, ExternFn, Ref, Struct, Ty1, Type, Types, Var};
+use crate::syntax::{error, ident, Api, ExternFn, Ref, Struct, Ty1, Type, Types};
 use proc_macro2::{Delimiter, Group, Ident, TokenStream};
-use quote::quote;
+use quote::{quote, ToTokens};
+use std::fmt::Display;
 use syn::{Error, Result};
 
 struct Check<'a> {
@@ -28,7 +29,7 @@
             Type::RustBox(ptr) => check_type_box(cx, ptr),
             Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
             Type::Ref(ty) => check_type_ref(cx, ty),
-            Type::Fn(_) => cx.errors.push(unimplemented_fn_type(ty)),
+            Type::Fn(_) => cx.error(ty, "function pointer support is not implemented yet"),
             _ => {}
         }
     }
@@ -53,54 +54,68 @@
     ident::check_all(cx.apis, cx.errors);
 }
 
+impl Check<'_> {
+    fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
+        self.errors.push(Error::new_spanned(sp, msg));
+    }
+}
+
 fn check_type_ident(cx: &mut Check, ident: &Ident) {
     if Atom::from(ident).is_none()
         && !cx.types.structs.contains_key(ident)
         && !cx.types.cxx.contains(ident)
         && !cx.types.rust.contains(ident)
     {
-        cx.errors.push(unsupported_type(ident));
+        cx.error(ident, "unsupported type");
     }
 }
 
 fn check_type_box(cx: &mut Check, ptr: &Ty1) {
     if let Type::Ident(ident) = &ptr.inner {
         if cx.types.cxx.contains(ident) {
-            cx.errors.push(unsupported_cxx_type_in_box(ptr));
+            cx.error(ptr, error::BOX_CXX_TYPE.msg);
         }
+
         if Atom::from(ident).is_none() {
             return;
         }
     }
-    cx.errors.push(unsupported_box_target(ptr));
+
+    cx.error(ptr, "unsupported target type of Box");
 }
 
 fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
     if let Type::Ident(ident) = &ptr.inner {
         if cx.types.rust.contains(ident) {
-            cx.errors.push(unsupported_rust_type_in_unique_ptr(ptr));
+            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
         }
+
         match Atom::from(ident) {
             None | Some(CxxString) => return,
             _ => {}
         }
     }
-    cx.errors.push(unsupported_unique_ptr_target(ptr));
+
+    cx.error(ptr, "unsupported unique_ptr target type");
 }
 
 fn check_type_ref(cx: &mut Check, ty: &Ref) {
     if let Type::Void(_) = ty.inner {
-        cx.errors.push(unsupported_reference_type(ty));
+        cx.error(ty, "unsupported reference type");
     }
 }
 
 fn check_api_struct(cx: &mut Check, strct: &Struct) {
     if strct.fields.is_empty() {
-        cx.errors.push(struct_empty(strct));
+        let span = span_for_struct_error(strct);
+        cx.error(span, "structs without any fields are not supported");
     }
+
     for field in &strct.fields {
         if is_unsized(cx, &field.ty) {
-            cx.errors.push(field_by_value(field, cx.types));
+            let desc = describe(cx, &field.ty);
+            let msg = format!("using {} by value is not supported", desc);
+            cx.error(field, msg);
         }
     }
 }
@@ -108,12 +123,17 @@
 fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
     for arg in &efn.args {
         if is_unsized(cx, &arg.ty) {
-            cx.errors.push(argument_by_value(arg, cx.types));
+            let desc = describe(cx, &arg.ty);
+            let msg = format!("passing {} by value is not supported", desc);
+            cx.error(arg, msg);
         }
     }
+
     if let Some(ty) = &efn.ret {
         if is_unsized(cx, ty) {
-            cx.errors.push(return_by_value(ty, cx.types));
+            let desc = describe(cx, ty);
+            let msg = format!("returning {} by value is not supported", desc);
+            cx.error(ty, msg);
         }
     }
 }
@@ -132,10 +152,10 @@
         }
     }
 
-    cx.errors.push(Error::new_spanned(
+    cx.error(
         efn,
         "&mut return type is not allowed unless there is a &mut argument",
-    ));
+    );
 }
 
 fn check_multiple_arg_lifetimes(cx: &mut Check, efn: &ExternFn) {
@@ -152,10 +172,10 @@
     }
 
     if reference_args != 1 {
-        cx.errors.push(Error::new_spanned(
+        cx.error(
             efn,
             "functions that return a reference must take exactly one input reference",
-        ));
+        );
     }
 }
 
@@ -168,6 +188,13 @@
     ident == CxxString || cx.types.cxx.contains(ident) || cx.types.rust.contains(ident)
 }
 
+fn span_for_struct_error(strct: &Struct) -> TokenStream {
+    let struct_token = strct.struct_token;
+    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
+    brace_token.set_span(strct.brace_token.span);
+    quote!(#struct_token #brace_token)
+}
+
 fn combine_errors(errors: Vec<Error>) -> Result<()> {
     let mut iter = errors.into_iter();
     let mut all_errors = match iter.next() {
@@ -180,14 +207,14 @@
     Err(all_errors)
 }
 
-fn describe(ty: &Type, types: &Types) -> String {
+fn describe(cx: &mut Check, ty: &Type) -> String {
     match ty {
         Type::Ident(ident) => {
-            if types.structs.contains_key(ident) {
+            if cx.types.structs.contains_key(ident) {
                 "struct".to_owned()
-            } else if types.cxx.contains(ident) {
+            } else if cx.types.cxx.contains(ident) {
                 "C++ type".to_owned()
-            } else if types.rust.contains(ident) {
+            } else if cx.types.rust.contains(ident) {
                 "opaque Rust type".to_owned()
             } else if Atom::from(ident) == Some(CxxString) {
                 "C++ string".to_owned()
@@ -203,57 +230,3 @@
         Type::Void(_) => "()".to_owned(),
     }
 }
-
-fn unsupported_type(ident: &Ident) -> Error {
-    Error::new(ident.span(), "unsupported type")
-}
-
-fn unsupported_reference_type(ty: &Ref) -> Error {
-    Error::new_spanned(ty, "unsupported reference type")
-}
-
-fn unsupported_cxx_type_in_box(unique_ptr: &Ty1) -> Error {
-    Error::new_spanned(unique_ptr, error::BOX_CXX_TYPE.msg)
-}
-
-fn unsupported_box_target(unique_ptr: &Ty1) -> Error {
-    Error::new_spanned(unique_ptr, "unsupported target type of Box")
-}
-
-fn unsupported_rust_type_in_unique_ptr(unique_ptr: &Ty1) -> Error {
-    Error::new_spanned(unique_ptr, "unique_ptr of a Rust type is not supported yet")
-}
-
-fn unsupported_unique_ptr_target(unique_ptr: &Ty1) -> Error {
-    Error::new_spanned(unique_ptr, "unsupported unique_ptr target type")
-}
-
-fn struct_empty(strct: &Struct) -> Error {
-    let struct_token = strct.struct_token;
-    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
-    brace_token.set_span(strct.brace_token.span);
-    let span = quote!(#struct_token #brace_token);
-    Error::new_spanned(span, "structs without any fields are not supported")
-}
-
-fn field_by_value(field: &Var, types: &Types) -> Error {
-    let desc = describe(&field.ty, types);
-    let message = format!("using {} by value is not supported", desc);
-    Error::new_spanned(field, message)
-}
-
-fn argument_by_value(arg: &Var, types: &Types) -> Error {
-    let desc = describe(&arg.ty, types);
-    let message = format!("passing {} by value is not supported", desc);
-    Error::new_spanned(arg, message)
-}
-
-fn return_by_value(ty: &Type, types: &Types) -> Error {
-    let desc = describe(ty, types);
-    let message = format!("returning {} by value is not supported", desc);
-    Error::new_spanned(ty, message)
-}
-
-fn unimplemented_fn_type(ty: &Type) -> Error {
-    Error::new_spanned(ty, "function pointer support is not implemented yet")
-}