Join trivial reasons in one message
diff --git a/syntax/trivial.rs b/syntax/trivial.rs
index 7a77937..85184d8 100644
--- a/syntax/trivial.rs
+++ b/syntax/trivial.rs
@@ -1,8 +1,8 @@
 use crate::syntax::set::OrderedSet as Set;
-use crate::syntax::{Api, Enum, ExternFn, ExternType, RustName, Struct, Type};
+use crate::syntax::{Api, Enum, ExternFn, Pair, RustName, Struct, Type};
 use proc_macro2::Ident;
 use std::collections::BTreeMap as Map;
-use std::fmt::Display;
+use std::fmt::{self, Display};
 
 #[derive(Copy, Clone)]
 pub enum TrivialReason<'a> {
@@ -101,31 +101,146 @@
     required_trivial
 }
 
-impl<'a> TrivialReason<'a> {
-    pub fn describe_in_context(&self, ety: &ExternType) -> String {
-        match self {
-            TrivialReason::BoxTarget => format!("Box<{}>", ety.name.rust),
-            TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
-            _ => self.to_string(),
-        }
+// Context:
+// "type {type} should be trivially move constructible and trivially destructible in C++ to be used as {what} in Rust"
+// "needs a cxx::ExternType impl in order to be used as {what}"
+pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a {
+    struct Description<'a> {
+        name: &'a Pair,
+        reasons: &'a [TrivialReason<'a>],
     }
-}
 
-impl<'a> Display for TrivialReason<'a> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            TrivialReason::StructField(strct) => write!(f, "a field of `{}`", strct.name.rust),
-            TrivialReason::FunctionArgument(efn) => write!(f, "an argument of `{}`", efn.name.rust),
-            TrivialReason::FunctionReturn(efn) => {
-                write!(f, "a return value of `{}`", efn.name.rust)
+    impl<'a> Display for Description<'a> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            let mut field_of = Set::new();
+            let mut argument_of = Set::new();
+            let mut return_of = Set::new();
+            let mut box_target = false;
+            let mut vec_element = false;
+            let mut unpinned_mut = Set::new();
+
+            for reason in self.reasons {
+                match reason {
+                    TrivialReason::StructField(strct) => {
+                        field_of.insert(&strct.name.rust);
+                    }
+                    TrivialReason::FunctionArgument(efn) => {
+                        argument_of.insert(&efn.name.rust);
+                    }
+                    TrivialReason::FunctionReturn(efn) => {
+                        return_of.insert(&efn.name.rust);
+                    }
+                    TrivialReason::BoxTarget => box_target = true,
+                    TrivialReason::VecElement => vec_element = true,
+                    TrivialReason::UnpinnedMutArg(efn) => {
+                        unpinned_mut.insert(&efn.name.rust);
+                    }
+                }
             }
-            TrivialReason::BoxTarget => write!(f, "in a Box<...>"),
-            TrivialReason::VecElement => write!(f, "a Vec<...> element"),
-            TrivialReason::UnpinnedMutArg(efn) => write!(
-                f,
-                "a non-pinned mutable reference argument of {}",
-                efn.name.rust
-            ),
+
+            let mut clauses = Vec::new();
+            if !field_of.is_empty() {
+                clauses.push(Clause::Set {
+                    article: "a",
+                    desc: "field of",
+                    set: &field_of,
+                });
+            }
+            if !argument_of.is_empty() {
+                clauses.push(Clause::Set {
+                    article: "an",
+                    desc: "argument of",
+                    set: &argument_of,
+                });
+            }
+            if !return_of.is_empty() {
+                clauses.push(Clause::Set {
+                    article: "a",
+                    desc: "return value of",
+                    set: &return_of,
+                });
+            }
+            if box_target {
+                clauses.push(Clause::Ty1 {
+                    article: "type",
+                    desc: "Box",
+                    param: self.name,
+                });
+            }
+            if vec_element {
+                clauses.push(Clause::Ty1 {
+                    article: "a",
+                    desc: "vector element in Vec",
+                    param: self.name,
+                });
+            }
+            if !unpinned_mut.is_empty() {
+                clauses.push(Clause::Set {
+                    article: "a",
+                    desc: "non-pinned mutable reference argument of",
+                    set: &unpinned_mut,
+                });
+            }
+
+            for (i, clause) in clauses.iter().enumerate() {
+                if i == 0 {
+                    write!(f, "{} ", clause.article())?;
+                } else if i + 1 < clauses.len() {
+                    write!(f, ", ")?;
+                } else {
+                    write!(f, " or ")?;
+                }
+                clause.fmt(f)?;
+            }
+
+            Ok(())
         }
     }
+
+    enum Clause<'a> {
+        Set {
+            article: &'a str,
+            desc: &'a str,
+            set: &'a Set<&'a Ident>,
+        },
+        Ty1 {
+            article: &'a str,
+            desc: &'a str,
+            param: &'a Pair,
+        },
+    }
+
+    impl<'a> Clause<'a> {
+        fn article(&self) -> &'a str {
+            match self {
+                Clause::Set { article, .. } | Clause::Ty1 { article, .. } => article,
+            }
+        }
+
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            match self {
+                Clause::Set {
+                    article: _,
+                    desc,
+                    set,
+                } => {
+                    write!(f, "{} ", desc)?;
+                    for (i, ident) in set.iter().take(3).enumerate() {
+                        if i > 0 {
+                            write!(f, ", ")?;
+                        }
+                        write!(f, "`{}`", ident)?;
+                    }
+                    Ok(())
+                }
+                Clause::Ty1 {
+                    article: _,
+                    desc,
+                    param,
+                } => write!(f, "{}<{}>", desc, param.rust),
+            }
+        }
+    }
+
+    Description { name, reasons }
 }