Merge "Upgrade rust/crates/thiserror-impl to 1.0.29" am: 9042e02c46 am: b94155e333 am: 6f81fd4b00

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/thiserror-impl/+/1833325

Change-Id: Ifb23af654537d906e817624d8173824b4129050b
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 16f81ed..d146052 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "031fea6f3b82c72be11477e7550c6ae3579e6139"
+    "sha1": "c7dd271dcd92af17168746a809503ee392d6f6ad"
   }
 }
diff --git a/Android.bp b/Android.bp
index 41c72f0..b8ead4a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --dependencies --device.
+// This file is generated by cargo2android.py --run --device.
 // Do not modify this file as changes will be overridden on upgrade.
 
 package {
@@ -42,6 +42,8 @@
 rust_proc_macro {
     name: "libthiserror_impl",
     crate_name: "thiserror_impl",
+    cargo_env_compat: true,
+    cargo_pkg_version: "1.0.29",
     srcs: ["src/lib.rs"],
     edition: "2018",
     rustlibs: [
@@ -50,9 +52,3 @@
         "libsyn",
     ],
 }
-
-// dependent_library ["feature_list"]
-//   proc-macro2-1.0.28 "default,proc-macro"
-//   quote-1.0.9 "default,proc-macro"
-//   syn-1.0.74 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
-//   unicode-xid-0.2.2 "default"
diff --git a/Cargo.toml b/Cargo.toml
index 2f1e842..0a27665 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,17 +3,16 @@
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
 #
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 name = "thiserror-impl"
-version = "1.0.26"
+version = "1.0.29"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 description = "Implementation detail of the `thiserror` crate"
 license = "MIT OR Apache-2.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 39bbc3d..121f679 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "thiserror-impl"
-version = "1.0.26"
+version = "1.0.29"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
diff --git a/METADATA b/METADATA
index 24ef154..59c63eb 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/thiserror-impl/thiserror-impl-1.0.26.crate"
+    value: "https://static.crates.io/crates/thiserror-impl/thiserror-impl-1.0.29.crate"
   }
-  version: "1.0.26"
+  version: "1.0.29"
   license_type: NOTICE
   last_upgrade_date {
     year: 2021
-    month: 8
-    day: 9
+    month: 9
+    day: 22
   }
 }
diff --git a/src/ast.rs b/src/ast.rs
index 8698ecf..2aa7246 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -1,4 +1,5 @@
 use crate::attr::{self, Attrs};
+use crate::generics::ParamsInScope;
 use proc_macro2::Span;
 use syn::{
     Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Member, Result,
@@ -38,6 +39,7 @@
     pub attrs: Attrs<'a>,
     pub member: Member,
     pub ty: &'a Type,
+    pub contains_generic: bool,
 }
 
 impl<'a> Input<'a> {
@@ -56,8 +58,9 @@
 impl<'a> Struct<'a> {
     fn from_syn(node: &'a DeriveInput, data: &'a DataStruct) -> Result<Self> {
         let mut attrs = attr::get(&node.attrs)?;
+        let scope = ParamsInScope::new(&node.generics);
         let span = attrs.span().unwrap_or_else(Span::call_site);
-        let fields = Field::multiple_from_syn(&data.fields, span)?;
+        let fields = Field::multiple_from_syn(&data.fields, &scope, span)?;
         if let Some(display) = &mut attrs.display {
             display.expand_shorthand(&fields);
         }
@@ -74,12 +77,13 @@
 impl<'a> Enum<'a> {
     fn from_syn(node: &'a DeriveInput, data: &'a DataEnum) -> Result<Self> {
         let attrs = attr::get(&node.attrs)?;
+        let scope = ParamsInScope::new(&node.generics);
         let span = attrs.span().unwrap_or_else(Span::call_site);
         let variants = data
             .variants
             .iter()
             .map(|node| {
-                let mut variant = Variant::from_syn(node, span)?;
+                let mut variant = Variant::from_syn(node, &scope, span)?;
                 if let display @ None = &mut variant.attrs.display {
                     *display = attrs.display.clone();
                 }
@@ -102,28 +106,37 @@
 }
 
 impl<'a> Variant<'a> {
-    fn from_syn(node: &'a syn::Variant, span: Span) -> Result<Self> {
+    fn from_syn(node: &'a syn::Variant, scope: &ParamsInScope<'a>, span: Span) -> Result<Self> {
         let attrs = attr::get(&node.attrs)?;
         let span = attrs.span().unwrap_or(span);
         Ok(Variant {
             original: node,
             attrs,
             ident: node.ident.clone(),
-            fields: Field::multiple_from_syn(&node.fields, span)?,
+            fields: Field::multiple_from_syn(&node.fields, scope, span)?,
         })
     }
 }
 
 impl<'a> Field<'a> {
-    fn multiple_from_syn(fields: &'a Fields, span: Span) -> Result<Vec<Self>> {
+    fn multiple_from_syn(
+        fields: &'a Fields,
+        scope: &ParamsInScope<'a>,
+        span: Span,
+    ) -> Result<Vec<Self>> {
         fields
             .iter()
             .enumerate()
-            .map(|(i, field)| Field::from_syn(i, field, span))
+            .map(|(i, field)| Field::from_syn(i, field, scope, span))
             .collect()
     }
 
-    fn from_syn(i: usize, node: &'a syn::Field, span: Span) -> Result<Self> {
+    fn from_syn(
+        i: usize,
+        node: &'a syn::Field,
+        scope: &ParamsInScope<'a>,
+        span: Span,
+    ) -> Result<Self> {
         Ok(Field {
             original: node,
             attrs: attr::get(&node.attrs)?,
@@ -134,6 +147,7 @@
                 })
             }),
             ty: &node.ty,
+            contains_generic: scope.intersects(&node.ty),
         })
     }
 }
diff --git a/src/attr.rs b/src/attr.rs
index 1ab1e28..9963fd6 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -1,5 +1,6 @@
 use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
 use quote::{format_ident, quote, ToTokens};
+use std::collections::BTreeSet as Set;
 use std::iter::FromIterator;
 use syn::parse::{Nothing, ParseStream};
 use syn::{
@@ -21,6 +22,7 @@
     pub fmt: LitStr,
     pub args: TokenStream,
     pub has_bonus_display: bool,
+    pub implied_bounds: Set<(usize, Trait)>,
 }
 
 #[derive(Copy, Clone)]
@@ -29,6 +31,19 @@
     pub span: Span,
 }
 
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
+pub enum Trait {
+    Debug,
+    Display,
+    Octal,
+    LowerHex,
+    UpperHex,
+    Pointer,
+    Binary,
+    LowerExp,
+    UpperExp,
+}
+
 pub fn get(input: &[Attribute]) -> Result<Attrs> {
     let mut attrs = Attrs {
         display: None,
@@ -91,6 +106,7 @@
             fmt: input.parse()?,
             args: parse_token_expr(input, false)?,
             has_bonus_display: false,
+            implied_bounds: Set::new(),
         };
         if attrs.display.is_some() {
             return Err(Error::new_spanned(
@@ -188,3 +204,10 @@
         });
     }
 }
+
+impl ToTokens for Trait {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let trait_name = format_ident!("{}", format!("{:?}", self));
+        tokens.extend(quote!(std::fmt::#trait_name));
+    }
+}
diff --git a/src/expand.rs b/src/expand.rs
index 789eee6..435ad48 100644
--- a/src/expand.rs
+++ b/src/expand.rs
@@ -1,8 +1,13 @@
 use crate::ast::{Enum, Field, Input, Struct};
+use crate::attr::Trait;
+use crate::generics::InferredBounds;
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, quote_spanned, ToTokens};
+use std::collections::BTreeSet as Set;
 use syn::spanned::Spanned;
-use syn::{Data, DeriveInput, Member, PathArguments, Result, Type, Visibility};
+use syn::{
+    Data, DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type, Visibility,
+};
 
 pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
     let input = Input::from_syn(node)?;
@@ -16,14 +21,23 @@
 fn impl_struct(input: Struct) -> TokenStream {
     let ty = &input.ident;
     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let mut error_inferred_bounds = InferredBounds::new();
 
     let source_body = if input.attrs.transparent.is_some() {
-        let only_field = &input.fields[0].member;
+        let only_field = &input.fields[0];
+        if only_field.contains_generic {
+            error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
+        }
+        let member = &only_field.member;
         Some(quote! {
-            std::error::Error::source(self.#only_field.as_dyn_error())
+            std::error::Error::source(self.#member.as_dyn_error())
         })
     } else if let Some(source_field) = input.source_field() {
         let source = &source_field.member;
+        if source_field.contains_generic {
+            let ty = unoptional_type(source_field.ty);
+            error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
+        }
         let asref = if type_is_option(source_field.ty) {
             Some(quote_spanned!(source.span()=> .as_ref()?))
         } else {
@@ -58,7 +72,9 @@
                     self.#source.as_dyn_error().backtrace()
                 }
             };
-            let combinator = if type_is_option(backtrace_field.ty) {
+            let combinator = if source == backtrace {
+                source_backtrace
+            } else if type_is_option(backtrace_field.ty) {
                 quote! {
                     #source_backtrace.or(self.#backtrace.as_ref())
                 }
@@ -87,12 +103,15 @@
         }
     });
 
+    let mut display_implied_bounds = Set::new();
     let display_body = if input.attrs.transparent.is_some() {
         let only_field = &input.fields[0].member;
+        display_implied_bounds.insert((0, Trait::Display));
         Some(quote! {
             std::fmt::Display::fmt(&self.#only_field, __formatter)
         })
     } else if let Some(display) = &input.attrs.display {
+        display_implied_bounds = display.implied_bounds.clone();
         let use_as_display = if display.has_bonus_display {
             Some(quote! {
                 #[allow(unused_imports)]
@@ -112,14 +131,18 @@
         None
     };
     let display_impl = display_body.map(|body| {
+        let mut display_inferred_bounds = InferredBounds::new();
+        for (field, bound) in display_implied_bounds {
+            let field = &input.fields[field];
+            if field.contains_generic {
+                display_inferred_bounds.insert(field.ty, bound);
+            }
+        }
+        let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
         quote! {
             #[allow(unused_qualifications)]
-            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
-                #[allow(
-                    // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
-                    clippy::nonstandard_macro_braces,
-                    clippy::used_underscore_binding,
-                )]
+            impl #impl_generics std::fmt::Display for #ty #ty_generics #display_where_clause {
+                #[allow(clippy::used_underscore_binding)]
                 fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                     #body
                 }
@@ -128,8 +151,8 @@
     });
 
     let from_impl = input.from_field().map(|from_field| {
-        let backtrace_field = input.backtrace_field();
-        let from = from_field.ty;
+        let backtrace_field = input.distinct_backtrace_field();
+        let from = unoptional_type(from_field.ty);
         let body = from_initializer(from_field, backtrace_field);
         quote! {
             #[allow(unused_qualifications)]
@@ -143,10 +166,16 @@
     });
 
     let error_trait = spanned_error_trait(input.original);
+    if input.generics.type_params().next().is_some() {
+        let self_token = <Token![Self]>::default();
+        error_inferred_bounds.insert(self_token, Trait::Debug);
+        error_inferred_bounds.insert(self_token, Trait::Display);
+    }
+    let error_where_clause = error_inferred_bounds.augment_where_clause(input.generics);
 
     quote! {
         #[allow(unused_qualifications)]
-        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
+        impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause {
             #source_method
             #backtrace_method
         }
@@ -158,18 +187,27 @@
 fn impl_enum(input: Enum) -> TokenStream {
     let ty = &input.ident;
     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let mut error_inferred_bounds = InferredBounds::new();
 
     let source_method = if input.has_source() {
         let arms = input.variants.iter().map(|variant| {
             let ident = &variant.ident;
             if variant.attrs.transparent.is_some() {
-                let only_field = &variant.fields[0].member;
+                let only_field = &variant.fields[0];
+                if only_field.contains_generic {
+                    error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
+                }
+                let member = &only_field.member;
                 let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
                 quote! {
-                    #ty::#ident {#only_field: transparent} => #source,
+                    #ty::#ident {#member: transparent} => #source,
                 }
             } else if let Some(source_field) = variant.source_field() {
                 let source = &source_field.member;
+                if source_field.contains_generic {
+                    let ty = unoptional_type(source_field.ty);
+                    error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
+                }
                 let asref = if type_is_option(source_field.ty) {
                     Some(quote_spanned!(source.span()=> .as_ref()?))
                 } else {
@@ -238,6 +276,27 @@
                         }
                     }
                 }
+                (Some(backtrace_field), Some(source_field))
+                    if backtrace_field.member == source_field.member =>
+                {
+                    let backtrace = &backtrace_field.member;
+                    let varsource = quote!(source);
+                    let source_backtrace = if type_is_option(source_field.ty) {
+                        quote_spanned! {backtrace.span()=>
+                            #varsource.as_ref().and_then(|source| source.as_dyn_error().backtrace())
+                        }
+                    } else {
+                        quote_spanned! {backtrace.span()=>
+                            #varsource.as_dyn_error().backtrace()
+                        }
+                    };
+                    quote! {
+                        #ty::#ident {#backtrace: #varsource, ..} => {
+                            use thiserror::private::AsDynError;
+                            #source_backtrace
+                        }
+                    }
+                }
                 (Some(backtrace_field), _) => {
                     let backtrace = &backtrace_field.member;
                     let body = if type_is_option(backtrace_field.ty) {
@@ -267,6 +326,7 @@
     };
 
     let display_impl = if input.has_display() {
+        let mut display_inferred_bounds = InferredBounds::new();
         let use_as_display = if input.variants.iter().any(|v| {
             v.attrs
                 .display
@@ -286,34 +346,41 @@
             None
         };
         let arms = input.variants.iter().map(|variant| {
+            let mut display_implied_bounds = Set::new();
             let display = match &variant.attrs.display {
-                Some(display) => display.to_token_stream(),
+                Some(display) => {
+                    display_implied_bounds = display.implied_bounds.clone();
+                    display.to_token_stream()
+                }
                 None => {
                     let only_field = match &variant.fields[0].member {
                         Member::Named(ident) => ident.clone(),
                         Member::Unnamed(index) => format_ident!("_{}", index),
                     };
+                    display_implied_bounds.insert((0, Trait::Display));
                     quote!(std::fmt::Display::fmt(#only_field, __formatter))
                 }
             };
+            for (field, bound) in display_implied_bounds {
+                let field = &variant.fields[field];
+                if field.contains_generic {
+                    display_inferred_bounds.insert(field.ty, bound);
+                }
+            }
             let ident = &variant.ident;
             let pat = fields_pat(&variant.fields);
             quote! {
                 #ty::#ident #pat => #display
             }
         });
+        let arms = arms.collect::<Vec<_>>();
+        let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
         Some(quote! {
             #[allow(unused_qualifications)]
-            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
+            impl #impl_generics std::fmt::Display for #ty #ty_generics #display_where_clause {
                 fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                     #use_as_display
-                    #[allow(
-                        unused_variables,
-                        deprecated,
-                        // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
-                        clippy::nonstandard_macro_braces,
-                        clippy::used_underscore_binding,
-                    )]
+                    #[allow(unused_variables, deprecated, clippy::used_underscore_binding)]
                     match #void_deref self {
                         #(#arms,)*
                     }
@@ -326,9 +393,9 @@
 
     let from_impls = input.variants.iter().filter_map(|variant| {
         let from_field = variant.from_field()?;
-        let backtrace_field = variant.backtrace_field();
+        let backtrace_field = variant.distinct_backtrace_field();
         let variant = &variant.ident;
-        let from = from_field.ty;
+        let from = unoptional_type(from_field.ty);
         let body = from_initializer(from_field, backtrace_field);
         Some(quote! {
             #[allow(unused_qualifications)]
@@ -342,10 +409,16 @@
     });
 
     let error_trait = spanned_error_trait(input.original);
+    if input.generics.type_params().next().is_some() {
+        let self_token = <Token![Self]>::default();
+        error_inferred_bounds.insert(self_token, Trait::Debug);
+        error_inferred_bounds.insert(self_token, Trait::Display);
+    }
+    let error_where_clause = error_inferred_bounds.augment_where_clause(input.generics);
 
     quote! {
         #[allow(unused_qualifications)]
-        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
+        impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause {
             #source_method
             #backtrace_method
         }
@@ -371,6 +444,11 @@
 
 fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
     let from_member = &from_field.member;
+    let some_source = if type_is_option(from_field.ty) {
+        quote!(std::option::Option::Some(source))
+    } else {
+        quote!(source)
+    };
     let backtrace = backtrace_field.map(|backtrace_field| {
         let backtrace_member = &backtrace_field.member;
         if type_is_option(backtrace_field.ty) {
@@ -384,25 +462,43 @@
         }
     });
     quote!({
-        #from_member: source,
+        #from_member: #some_source,
         #backtrace
     })
 }
 
 fn type_is_option(ty: &Type) -> bool {
+    type_parameter_of_option(ty).is_some()
+}
+
+fn unoptional_type(ty: &Type) -> TokenStream {
+    let unoptional = type_parameter_of_option(ty).unwrap_or(ty);
+    quote!(#unoptional)
+}
+
+fn type_parameter_of_option(ty: &Type) -> Option<&Type> {
     let path = match ty {
         Type::Path(ty) => &ty.path,
-        _ => return false,
+        _ => return None,
     };
 
     let last = path.segments.last().unwrap();
     if last.ident != "Option" {
-        return false;
+        return None;
     }
 
-    match &last.arguments {
-        PathArguments::AngleBracketed(bracketed) => bracketed.args.len() == 1,
-        _ => false,
+    let bracketed = match &last.arguments {
+        PathArguments::AngleBracketed(bracketed) => bracketed,
+        _ => return None,
+    };
+
+    if bracketed.args.len() != 1 {
+        return None;
+    }
+
+    match &bracketed.args[0] {
+        GenericArgument::Type(arg) => Some(arg),
+        _ => None,
     }
 }
 
diff --git a/src/fmt.rs b/src/fmt.rs
index e12e94b..807dfb9 100644
--- a/src/fmt.rs
+++ b/src/fmt.rs
@@ -1,8 +1,8 @@
 use crate::ast::Field;
-use crate::attr::Display;
+use crate::attr::{Display, Trait};
 use proc_macro2::TokenTree;
 use quote::{format_ident, quote_spanned};
-use std::collections::HashSet as Set;
+use std::collections::{BTreeSet as Set, HashMap as Map};
 use syn::ext::IdentExt;
 use syn::parse::{ParseStream, Parser};
 use syn::{Ident, Index, LitStr, Member, Result, Token};
@@ -12,7 +12,10 @@
     pub fn expand_shorthand(&mut self, fields: &[Field]) {
         let raw_args = self.args.clone();
         let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
-        let fields: Set<Member> = fields.iter().map(|f| f.member.clone()).collect();
+        let mut member_index = Map::new();
+        for (i, field) in fields.iter().enumerate() {
+            member_index.insert(&field.member, i);
+        }
 
         let span = self.fmt.span();
         let fmt = self.fmt.value();
@@ -20,6 +23,7 @@
         let mut out = String::new();
         let mut args = self.args.clone();
         let mut has_bonus_display = false;
+        let mut implied_bounds = Set::new();
 
         let mut has_trailing_comma = false;
         if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
@@ -47,7 +51,7 @@
                         Ok(index) => Member::Unnamed(Index { index, span }),
                         Err(_) => return,
                     };
-                    if !fields.contains(&member) {
+                    if !member_index.contains_key(&member) {
                         out += &int;
                         continue;
                     }
@@ -60,6 +64,24 @@
                 }
                 _ => continue,
             };
+            if let Some(&field) = member_index.get(&member) {
+                let end_spec = match read.find('}') {
+                    Some(end_spec) => end_spec,
+                    None => return,
+                };
+                let bound = match read[..end_spec].chars().next_back() {
+                    Some('?') => Trait::Debug,
+                    Some('o') => Trait::Octal,
+                    Some('x') => Trait::LowerHex,
+                    Some('X') => Trait::UpperHex,
+                    Some('p') => Trait::Pointer,
+                    Some('b') => Trait::Binary,
+                    Some('e') => Trait::LowerExp,
+                    Some('E') => Trait::UpperExp,
+                    Some(_) | None => Trait::Display,
+                };
+                implied_bounds.insert((field, bound));
+            }
             let local = match &member {
                 Member::Unnamed(index) => format_ident!("_{}", index),
                 Member::Named(ident) => ident.clone(),
@@ -82,7 +104,7 @@
                 args.extend(quote_spanned!(span=> ,));
             }
             args.extend(quote_spanned!(span=> #formatvar = #local));
-            if read.starts_with('}') && fields.contains(&member) {
+            if read.starts_with('}') && member_index.contains_key(&member) {
                 has_bonus_display = true;
                 args.extend(quote_spanned!(span=> .as_display()));
             }
@@ -93,6 +115,7 @@
         self.fmt = LitStr::new(&out, self.fmt.span());
         self.args = args;
         self.has_bonus_display = has_bonus_display;
+        self.implied_bounds = implied_bounds;
     }
 }
 
diff --git a/src/generics.rs b/src/generics.rs
new file mode 100644
index 0000000..254c2ed
--- /dev/null
+++ b/src/generics.rs
@@ -0,0 +1,82 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use std::collections::btree_map::Entry;
+use std::collections::{BTreeMap as Map, BTreeSet as Set};
+use syn::punctuated::Punctuated;
+use syn::{parse_quote, GenericArgument, Generics, Ident, PathArguments, Token, Type, WhereClause};
+
+pub struct ParamsInScope<'a> {
+    names: Set<&'a Ident>,
+}
+
+impl<'a> ParamsInScope<'a> {
+    pub fn new(generics: &'a Generics) -> Self {
+        ParamsInScope {
+            names: generics.type_params().map(|param| &param.ident).collect(),
+        }
+    }
+
+    pub fn intersects(&self, ty: &Type) -> bool {
+        let mut found = false;
+        crawl(self, ty, &mut found);
+        found
+    }
+}
+
+fn crawl(in_scope: &ParamsInScope, ty: &Type, found: &mut bool) {
+    if let Type::Path(ty) = ty {
+        if ty.qself.is_none() {
+            if let Some(ident) = ty.path.get_ident() {
+                if in_scope.names.contains(ident) {
+                    *found = true;
+                }
+            }
+        }
+        for segment in &ty.path.segments {
+            if let PathArguments::AngleBracketed(arguments) = &segment.arguments {
+                for arg in &arguments.args {
+                    if let GenericArgument::Type(ty) = arg {
+                        crawl(in_scope, ty, found);
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub struct InferredBounds {
+    bounds: Map<String, (Set<String>, Punctuated<TokenStream, Token![+]>)>,
+    order: Vec<TokenStream>,
+}
+
+impl InferredBounds {
+    pub fn new() -> Self {
+        InferredBounds {
+            bounds: Map::new(),
+            order: Vec::new(),
+        }
+    }
+
+    pub fn insert(&mut self, ty: impl ToTokens, bound: impl ToTokens) {
+        let ty = ty.to_token_stream();
+        let bound = bound.to_token_stream();
+        let entry = self.bounds.entry(ty.to_string());
+        if let Entry::Vacant(_) = entry {
+            self.order.push(ty);
+        }
+        let (set, tokens) = entry.or_default();
+        if set.insert(bound.to_string()) {
+            tokens.push(bound);
+        }
+    }
+
+    pub fn augment_where_clause(&self, generics: &Generics) -> WhereClause {
+        let mut generics = generics.clone();
+        let where_clause = generics.make_where_clause();
+        for ty in &self.order {
+            let (_set, bounds) = &self.bounds[&ty.to_string()];
+            where_clause.predicates.push(parse_quote!(#ty: #bounds));
+        }
+        generics.where_clause.unwrap()
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index f0577d4..a4d5ae7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,7 @@
 mod attr;
 mod expand;
 mod fmt;
+mod generics;
 mod prop;
 mod valid;
 
diff --git a/src/prop.rs b/src/prop.rs
index 059b74b..6d8a924 100644
--- a/src/prop.rs
+++ b/src/prop.rs
@@ -13,6 +13,11 @@
     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
         backtrace_field(&self.fields)
     }
+
+    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
+        let backtrace_field = self.backtrace_field()?;
+        distinct_backtrace_field(backtrace_field, self.from_field())
+    }
 }
 
 impl Enum<'_> {
@@ -54,6 +59,11 @@
     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
         backtrace_field(&self.fields)
     }
+
+    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
+        let backtrace_field = self.backtrace_field()?;
+        distinct_backtrace_field(backtrace_field, self.from_field())
+    }
 }
 
 impl Field<'_> {
@@ -100,6 +110,20 @@
     None
 }
 
+// The #[backtrace] field, if it is not the same as the #[from] field.
+fn distinct_backtrace_field<'a, 'b>(
+    backtrace_field: &'a Field<'b>,
+    from_field: Option<&Field>,
+) -> Option<&'a Field<'b>> {
+    if from_field.map_or(false, |from_field| {
+        from_field.member == backtrace_field.member
+    }) {
+        None
+    } else {
+        Some(backtrace_field)
+    }
+}
+
 fn type_is_backtrace(ty: &Type) -> bool {
     let path = match ty {
         Type::Path(ty) => &ty.path,