// vim: tw=80
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, format_ident, quote};
use syn::{
    *,
    punctuated::Punctuated,
    spanned::Spanned
};


use crate::{
    AttrFormatter,
    HashSet,
    compile_error,
    concretize_args,
    declosurefy,
    expectation_visibility,
    gen_keyid,
    is_concretize,
    lifetimes_to_generic_params,
    lifetimes_to_generics,
    merge_generics,
    pat_is_self,
    split_lifetimes,
    staticize,
    supersuperfy,
    supersuperfy_generics,
};

/// Convert a trait object reference into a reference to a Boxed trait
///
/// # Returns
///
/// Returns `true` if it was necessary to box the type.
fn dedynify(ty: &mut Type) -> bool {
    if let Type::Reference(ref mut tr) = ty {
        if let Type::TraitObject(ref tto) = tr.elem.as_ref() {
            if let Some(lt) = &tr.lifetime {
                if lt.ident == "static" {
                    // For methods that return 'static references, the user can
                    // usually actually supply one, unlike nonstatic references.
                    // dedynify is unneeded and harmful in such cases.
                    //
                    // But we do need to add parens to prevent parsing errors
                    // when methods like returning add a `+ Send` to the output
                    // type.
                    *tr.elem = parse2(quote!((#tto))).unwrap();
                    return false;
                }
            }

            *tr.elem = parse2(quote!(Box<#tto>)).unwrap();
            return true;
        }
    }
    false
}

/// Convert a special reference type like "&str" into a reference to its owned
/// type like "&String".
fn destrify(ty: &mut Type) {
    if let Type::Reference(ref mut tr) = ty {
        if let Some(lt) = &tr.lifetime {
            if lt.ident == "static" {
                // For methods that return 'static references, the user can
                // usually actually supply one, unlike nonstatic references.
                // destrify is unneeded and harmful in such cases.
                return;
            }
        }

        let path_ty: TypePath = parse2(quote!(Path)).unwrap();
        let pathbuf_ty: Type = parse2(quote!(::std::path::PathBuf)).unwrap();

        let str_ty: TypePath = parse2(quote!(str)).unwrap();
        let string_ty: Type = parse2(quote!(::std::string::String)).unwrap();

        let cstr_ty: TypePath = parse2(quote!(CStr)).unwrap();
        let cstring_ty: Type = parse2(quote!(::std::ffi::CString)).unwrap();

        let osstr_ty: TypePath = parse2(quote!(OsStr)).unwrap();
        let osstring_ty: Type = parse2(quote!(::std::ffi::OsString)).unwrap();

        match tr.elem.as_ref() {
            Type::Path(ref path) if *path == cstr_ty =>
                *tr.elem = cstring_ty,
            Type::Path(ref path) if *path == osstr_ty =>
                *tr.elem = osstring_ty,
            Type::Path(ref path) if *path == path_ty =>
                *tr.elem = pathbuf_ty,
            Type::Path(ref path) if *path == str_ty =>
                *tr.elem = string_ty,
            Type::Slice(ts) => {
                let inner = (*ts.elem).clone();
                let mut segments = Punctuated::new();
                segments.push(format_ident!("std").into());
                segments.push(format_ident!("vec").into());
                let mut v: PathSegment = format_ident!("Vec").into();
                let mut abga_args = Punctuated::new();
                abga_args.push(GenericArgument::Type(inner));
                v.arguments = PathArguments::AngleBracketed(
                    AngleBracketedGenericArguments {
                        colon2_token: None,
                        lt_token: Token![<](Span::call_site()),
                        args: abga_args,
                        gt_token: Token![>](Span::call_site()),
                    }
                );
                segments.push(v);

                *tr.elem = Type::Path(TypePath {
                    qself: None,
                    path: Path {
                        leading_colon: Some(Token![::](Span::call_site())),
                        segments
                    }
                });
            },
            _ => (), // Nothing to do
        };
    }
}

/// Return the owned version of the input.
fn ownify(ty: &Type) -> Type {
    if let Type::Reference(ref tr) = &ty {
        if tr.lifetime.as_ref().is_some_and(|lt| lt.ident == "static")
        {
            // Just a static expectation
            ty.clone()
        } else {
            *tr.elem.clone()
        }
    } else {
        ty.clone()
    }
}

/// Add Send + Sync to a where clause
fn send_syncify(wc: &mut Option<WhereClause>, bounded_ty: Type) {
    let mut bounds = Punctuated::new();
    bounds.push(TypeParamBound::Trait(TraitBound {
        paren_token: None,
        modifier: TraitBoundModifier::None,
        lifetimes: None,
        path: Path {
            leading_colon: Some(<Token![::]>::default()),
            segments: [
                PathSegment::from(format_ident!("std")),
                PathSegment::from(format_ident!("marker")),
                PathSegment::from(format_ident!("Send")),
            ].into_iter().collect(),
        }
    }));
    bounds.push(TypeParamBound::Trait(TraitBound {
        paren_token: None,
        modifier: TraitBoundModifier::None,
        lifetimes: None,
        path: Path {
            leading_colon: Some(<Token![::]>::default()),
            segments: [
                PathSegment::from(format_ident!("std")),
                PathSegment::from(format_ident!("marker")),
                PathSegment::from(format_ident!("Sync")),
            ].into_iter().collect(),
        }
    }));
    if wc.is_none() {
        *wc = Some(WhereClause {
            where_token: <Token![where]>::default(),
            predicates: Punctuated::new()
        });
    }
    wc.as_mut().unwrap()
    .predicates.push(
        WherePredicate::Type(
            PredicateType {
                lifetimes: None,
                bounded_ty,
                colon_token: Default::default(),
                bounds
            }
        )
    );
}

/// Build a MockFunction.
#[derive(Clone, Copy, Debug)]
pub(crate) struct Builder<'a> {
    attrs: &'a [Attribute],
    call_levels: Option<usize>,
    concretize: bool,
    levels: usize,
    parent: Option<&'a Ident>,
    sig: &'a Signature,
    struct_: Option<&'a Ident>,
    struct_generics: Option<&'a Generics>,
    trait_: Option<&'a Ident>,
    vis: &'a Visibility
}

impl<'a> Builder<'a> {
    pub fn attrs(&mut self, attrs: &'a[Attribute]) -> &mut Self {
        self.attrs = attrs;
        if attrs.iter()
            .any(is_concretize)
        {
            self.concretize = true;
        }
        self
    }

    pub fn build(self) -> MockFunction {
        let mut argnames = Vec::new();
        let mut argty = Vec::new();
        let mut is_static = true;
        let mut predexprs = Vec::new();
        let mut predty = Vec::new();
        let mut refpredty = Vec::new();

        let (mut declosured_generics, declosured_inputs, call_exprs, sig) =
            if self.concretize {
                let (x, y, z, sig) = concretize_args(&self.sig.generics, self.sig);
                (x, y, z, sig)
            } else {
                let (x, y, z) = declosurefy(&self.sig.generics, &self.sig.inputs);
                (x, y, z, self.sig.clone())
            };
        // TODO: make concretize and declosurefy work for the same function

        for fa in declosured_inputs.iter() {
            if let FnArg::Typed(pt) = fa {
                let argname = (*pt.pat).clone();
                assert!(!pat_is_self(&argname));
                let aty = supersuperfy(&pt.ty, self.levels);
                if let Type::Reference(ref tr) = aty {
                    predexprs.push(quote!(#argname));
                    predty.push((*tr.elem).clone());
                    let tr2 = Type::Reference(TypeReference {
                        and_token: tr.and_token,
                        lifetime: None,
                        mutability: None,
                        elem: tr.elem.clone()
                    });
                    refpredty.push(tr2);
                } else {
                    predexprs.push(quote!(&#argname));
                    predty.push(aty.clone());
                    let tr = TypeReference {
                        and_token: Token![&](Span::call_site()),
                        lifetime: None,
                        mutability: None,
                        elem: Box::new(aty.clone())
                    };
                    refpredty.push(Type::Reference(tr));
                };
                argnames.push(argname);
                argty.push(aty.clone());
            } else {
                is_static = false;
            }
        }
        let (output, boxed) = match self.sig.output {
            ReturnType::Default => (
                Type::Tuple(TypeTuple {
                    paren_token: token::Paren::default(),
                    elems: Punctuated::new(),
                }),
                false,
            ),
            ReturnType::Type(_, ref ty) => {
                let mut output_ty = supersuperfy(ty, self.levels);
                destrify(&mut output_ty);
                let boxed = dedynify(&mut output_ty);
                (output_ty, boxed)
            }
        };
        supersuperfy_generics(&mut declosured_generics, self.levels);
        let owned_output = ownify(&output);
        let mut return_ref = false;
        let mut return_refmut = false;
        if let Type::Reference(ref tr) = &output {
            #[allow(clippy::unnecessary_map_or)]
            if tr.lifetime.as_ref().map_or(true, |lt| lt.ident != "static")
            {
                if tr.mutability.is_none() {
                    return_ref = true;
                } else {
                    return_refmut = true;
                }
            }
        };
        if is_static && (return_ref || return_refmut) {
            compile_error(self.sig.span(),
                "Mockall cannot mock static methods that return non-'static references.  It's unclear what the return value's lifetime should be.");
        }
        let struct_generics = self.struct_generics.cloned()
            .unwrap_or_default();
        let (type_generics, salifetimes, srlifetimes) = split_lifetimes(
            struct_generics.clone(),
            &declosured_inputs,
            &ReturnType::Type(<Token![->]>::default(),
                              Box::new(owned_output.clone()))
        );
        let srltg = lifetimes_to_generics(&srlifetimes);
        let (call_generics, malifetimes, mrlifetimes) = split_lifetimes(
            declosured_generics,
            &declosured_inputs,
            &ReturnType::Type(<Token![->]>::default(),
                              Box::new(owned_output.clone()))
        );
        let mrltg = lifetimes_to_generics(&mrlifetimes);
        let cgenerics = merge_generics(&type_generics, &call_generics);
        let egenerics = merge_generics(
            &merge_generics(&cgenerics, &srltg),
            &mrltg);
        let alifetimes = salifetimes.into_iter()
            .collect::<HashSet<LifetimeParam>>()
            .union(&malifetimes.into_iter().collect::<HashSet<_>>())
            .cloned()
            .collect();

        let fn_params = egenerics.type_params()
            .map(|tp| tp.ident.clone())
            .collect();
        let call_levels = self.call_levels.unwrap_or(self.levels);

        MockFunction {
            alifetimes,
            argnames,
            argty,
            attrs: self.attrs.to_vec(),
            call_exprs,
            call_generics,
            call_vis: expectation_visibility(self.vis, call_levels),
            concretize: self.concretize,
            egenerics,
            cgenerics,
            fn_params,
            is_static,
            mod_ident: self.parent.unwrap_or(&Ident::new("FIXME", Span::call_site())).clone(),
            output,
            owned_output,
            boxed,
            predexprs,
            predty,
            refpredty,
            return_ref,
            return_refmut,
            sig,
            struct_: self.struct_.cloned(),
            struct_generics,
            trait_: self.trait_.cloned(),
            type_generics,
            privmod_vis: expectation_visibility(self.vis, self.levels)
        }
    }

    /// How many levels of modules beneath the original function this one is
    /// nested.
    pub fn call_levels(&mut self, levels: usize) -> &mut Self {
        self.call_levels = Some(levels);
        self
    }

    /// How many levels of modules beneath the original function this one's
    /// private module is nested.
    pub fn levels(&mut self, levels: usize) -> &mut Self {
        self.levels = levels;
        self
    }

    /// # Arguments
    ///
    /// * sig:      The signature of the mockable function
    /// * v:        The visibility of the mockable function
    pub fn new(sig: &'a Signature, vis: &'a Visibility) -> Self {
        Builder {
            attrs: &[],
            concretize: false,
            levels: 0,
            call_levels: None,
            parent: None,
            sig,
            struct_: None,
            struct_generics: None,
            trait_: None,
            vis
        }
    }

    /// Supply the name of the parent module
    pub fn parent(&mut self, ident: &'a Ident) -> &mut Self {
        self.parent = Some(ident);
        self
    }

    /// Supply the name of the parent struct, if any
    pub fn struct_(&mut self, ident: &'a Ident) -> &mut Self {
        self.struct_= Some(ident);
        self
    }

    /// Supply the Generics of the parent struct, if any
    pub fn struct_generics(&mut self, generics: &'a Generics) -> &mut Self {
        self.struct_generics = Some(generics);
        self
    }

    /// Supply the name of the method's trait, if any
    pub fn trait_(&mut self, ident: &'a Ident) -> &mut Self {
        self.trait_ = Some(ident);
        self
    }
}

#[derive(Clone)]
pub(crate) struct MockFunction {
    /// Lifetimes of the mocked method that relate to the arguments but not the
    /// return value
    alifetimes: Punctuated<LifetimeParam, token::Comma>,
    /// Names of the method arguments
    argnames: Vec<Pat>,
    /// Types of the method arguments
    argty: Vec<Type>,
    /// any attributes on the original function, like #[inline]
    pub attrs: Vec<Attribute>,
    /// Expressions that should be used for Expectation::call's arguments
    call_exprs: Vec<TokenStream>,
    /// Generics used for the expectation call
    call_generics: Generics,
    /// Visibility of the mock function itself
    call_vis: Visibility,
    /// Are we turning generic arguments into concrete trait objects?
    concretize: bool,
    /// Generics of the Expectation object
    egenerics: Generics,
    /// Generics of the Common object
    cgenerics: Generics,
    /// The mock function's generic types as a list of types
    fn_params: Vec<Ident>,
    /// Is this for a static method or free function?
    is_static: bool,
    /// name of the function's parent module
    mod_ident: Ident,
    /// Output type of the Method, supersuperfied.
    output: Type,
    /// Owned version of the output type of the Method, supersuperfied.
    ///
    /// If the real output type is a non-'static reference, then it will differ
    /// from this field.
    owned_output: Type,
    /// True if the `owned_type` is boxed by `Box<>`.
    boxed: bool,
    /// Expressions that create the predicate arguments from the call arguments
    predexprs: Vec<TokenStream>,
    /// Types used for Predicates.  Will be almost the same as args, but every
    /// type will be a non-reference type.
    predty: Vec<Type>,
    /// Does the function return a non-'static reference?
    return_ref: bool,
    /// Does the function return a mutable reference?
    return_refmut: bool,
    /// References to every type in `predty`.
    refpredty: Vec<Type>,
    /// The signature of the mockable function
    sig: Signature,
    /// Name of the parent structure, if any
    struct_: Option<Ident>,
    /// Generics of the parent structure
    struct_generics: Generics,
    /// Name of this method's trait, if the method comes from a trait
    trait_: Option<Ident>,
    /// Type generics of the mock structure
    type_generics: Generics,
    /// Visibility of the expectation and its methods
    privmod_vis: Visibility
}

impl MockFunction {
    /// Return the mock function itself
    ///
    /// # Arguments
    ///
    /// * `modname`:    Name of the parent struct's private module
    // Supplying modname is an unfortunately hack.  Ideally MockFunction
    // wouldn't need to know that.
    pub fn call(&self, modname: Option<&Ident>) -> impl ToTokens {
        let attrs = AttrFormatter::new(&self.attrs)
            .must_use(true)
            .format();
        let call_exprs = &self.call_exprs;
        let (_, tg, _) = if self.is_method_generic() || self.is_static() {
            &self.egenerics
        } else {
            &self.call_generics
        }.split_for_impl();
        let tbf = tg.as_turbofish();
        let name = self.name();
        let sig = &self.sig;
        let (vis, dead_code) = if self.trait_.is_some() {
            (&Visibility::Inherited, quote!())
        } else {
            let dead_code = if let Visibility::Inherited = self.call_vis {
                // This private method may be a helper only used by the struct's
                // other methods, which we are mocking.  If so, the mock method
                // will be dead code.  But we can't simply eliminate it, because
                // it might also be used by other code in the same module.
                quote!(#[allow(dead_code)])
            } else {
                quote!()
            };
            (&self.call_vis, dead_code)
        };
        // Add #[no_mangle] attribute to preserve the function name
        // as-is, without mangling, for compatibility with C functions.
        let no_mangle = if let Some(ref abi) = self.sig.abi {
            if let Some(ref name) = abi.name {
                if name.value().ne("Rust") {
                    quote!(#[no_mangle])
                } else {
                    quote!()
                }
            } else {
                // This is the same as extern "C"
                quote!(#[no_mangle])
            }
        } else {
            quote!()
        };
        let substruct_obj: TokenStream = if let Some(trait_) = &self.trait_ {
            let ident = format_ident!("{}_expectations", trait_);
            quote!(#ident.)
        } else {
            quote!()
        };
        let call = if self.return_refmut {
            Ident::new("call_mut", Span::call_site())
        } else {
            Ident::new("call", Span::call_site())
        };
        let mut deref = quote!();
        if self.boxed {
            if self.return_ref {
                deref = quote!(&**);
            } else if self.return_refmut {
                deref = quote!(&mut **);
            }
        }
        if self.is_static {
            let outer_mod_path = self.outer_mod_path(modname);
            quote!(
                // Don't add a doc string.  The original is included in #attrs
                #(#attrs)*
                #dead_code
                #no_mangle
                #vis #sig {
                    #deref {
                        let __mockall_guard = #outer_mod_path::get_expectations()
                            .lock().unwrap();
                        std::panic::catch_unwind(std::panic::AssertUnwindSafe(move ||  {
                            __mockall_guard.#call #tbf(#(#call_exprs,)*)
                        })).unwrap_or_else(|__mockall_e| {
                            #outer_mod_path::get_expectations().clear_poison();
                            // Drain all expectations so other tests can run with a
                            // blank slate.  But ignore errors so we don't
                            // double-panic.
                            let _ = #outer_mod_path::get_expectations()
                                .lock()
                                .map(|mut g| g.checkpoint().collect::<Vec<_>>());
                            ::std::panic::resume_unwind(__mockall_e);
                        })
                    }
                }
            )
        } else {
            quote!(
                // Don't add a doc string.  The original is included in #attrs
                #(#attrs)*
                #dead_code
                #no_mangle
                #vis #sig {
                    #deref self.#substruct_obj #name.#call #tbf(#(#call_exprs,)*)
                }

            )
        }
    }

    /// Return this method's contribution to its parent's checkpoint method
    pub fn checkpoint(&self) -> impl ToTokens {
        let attrs = AttrFormatter::new(&self.attrs)
            .doc(false)
            .format();
        let inner_mod_ident = self.inner_mod_ident();
        if self.is_static {
            quote!(
                #(#attrs)*
                {
                    let __mockall_timeses = #inner_mod_ident::get_expectations().lock()
                        .unwrap()
                        .checkpoint()
                        .collect::<Vec<_>>();
                }
            )
        } else {
            let name = &self.name();
            quote!(#(#attrs)* { self.#name.checkpoint(); })
        }
    }

    /// Return a function that creates a Context object for this function
    ///
    /// # Arguments
    ///
    /// * `modname`:    Name of the parent struct's private module
    // Supplying modname is an unfortunately hack.  Ideally MockFunction
    // wouldn't need to know that.
    pub fn context_fn(&self, modname: Option<&Ident>) -> impl ToTokens {
        let attrs = AttrFormatter::new(&self.attrs)
            .doc(false)
            .format();
        let context_docstr = format!("Create a [`Context`]({}{}/struct.Context.html) for mocking the `{}` method",
            modname.map(|m| format!("{m}/")).unwrap_or_default(),
            self.inner_mod_ident(),
            self.name());
        let context_ident = format_ident!("{}_context", self.name());
        let (_, tg, _) = self.type_generics.split_for_impl();
        let outer_mod_path = self.outer_mod_path(modname);
        let v = &self.call_vis;
        quote!(
            #(#attrs)*
            #[doc = #context_docstr]
            #v fn #context_ident() -> #outer_mod_path::Context #tg
            {
                #outer_mod_path::Context::default()
            }
        )
    }

    /// Generate a code fragment that will print a description of the
    /// invocation.
    ///
    /// # Returns
    ///
    /// A tuple consisting of a format string and a code fragment suitable for
    /// passing to `format!`.  For example: `("MyType::MyMethod(\"{:?}\",
    /// \"{:?}\")", x, y)`.
    fn desc(&self) -> (impl ToTokens, impl ToTokens) {
        let argnames = &self.argnames;
        let name = if let Some(s) = &self.struct_ {
            format!("{}::{}", s, self.sig.ident)
        } else {
            format!("{}::{}", self.mod_ident, self.sig.ident)
        };
        #[allow(clippy::literal_string_with_formatting_args)]
        let fields = vec!["{:?}"; argnames.len()].join(", ");
        let fstr = format!("{name}({fields})");
        (quote!(#fstr), quote!(#((&&::mockall::ArgPrinter(&#argnames)).debug_string()),*)) 
    }

    /// Generate code for the expect_ method
    ///
    /// # Arguments
    ///
    /// * `modname`:    Name of the parent struct's private module
    /// * `self_args`:  If supplied, these are the
    ///                 AngleBracketedGenericArguments of the self type of the
    ///                 trait impl.  e.g. The `T` in `impl Foo for Bar<T>`.
    // Supplying modname is an unfortunately hack.  Ideally MockFunction
    // wouldn't need to know that.
    pub fn expect(&self, modname: &Ident, self_args: Option<&PathArguments>)
        -> impl ToTokens
    {
        let attrs = AttrFormatter::new(&self.attrs)
            .doc(false)
            .format();
        let name = self.name();
        let expect_ident = format_ident!("expect_{}", name);
        let expectation_obj = self.expectation_obj(self_args);
        let funcname = &self.sig.ident;
        let (_, tg, _) = if self.is_method_generic() {
            &self.egenerics
        } else {
            &self.call_generics
        }.split_for_impl();
        let (ig, _, wc) = self.call_generics.split_for_impl();
        let mut wc = wc.cloned();
        if self.is_method_generic() && (self.return_ref || self.return_refmut) {
            // Add Senc + Sync, required for downcast, since Expectation
            // stores an Option<#owned_output>
            send_syncify(&mut wc, self.owned_output.clone());
        }
        let tbf = tg.as_turbofish();
        let vis = &self.call_vis;

        #[cfg(not(feature = "nightly_derive"))]
        let must_use = quote!(#[must_use =
                "Must set return value when not using the \"nightly\" feature"
            ]);
        #[cfg(feature = "nightly_derive")]
        let must_use = quote!();

        let substruct_obj = if let Some(trait_) = &self.trait_ {
            let ident = format_ident!("{trait_}_expectations");
            quote!(#ident.)
        } else {
            quote!()
        };
        let docstr = format!("Create an [`Expectation`]({}/{}/struct.Expectation.html) for mocking the `{}` method",
            modname, self.inner_mod_ident(), funcname);
        quote!(
            #must_use
            #[doc = #docstr]
            #(#attrs)*
            #vis fn #expect_ident #ig(&mut self)
               -> &mut #modname::#expectation_obj
               #wc
            {
                self.#substruct_obj #name.expect #tbf()
            }
        )
    }

    /// Return the name of this function's expecation object
    fn expectation_obj(&self, self_args: Option<&PathArguments>)
        -> impl ToTokens
    {
        let inner_mod_ident = self.inner_mod_ident();
        if let Some(PathArguments::AngleBracketed(abga)) = self_args {
            // staticize any lifetimes that might be present in the Expectation
            // object but not in the self args.  These come from the method's
            // return type.
            let mut abga2 = abga.clone();
            for _ in self.egenerics.lifetimes() {
                let lt = Lifetime::new("'static", Span::call_site());
                let la = GenericArgument::Lifetime(lt);
                abga2.args.insert(0, la);
            }
            assert!(!self.is_method_generic(),
                "specific impls with generic methods are TODO");
            quote!(#inner_mod_ident::Expectation #abga2)
        } else {
            // staticize any lifetimes.  This is necessary for methods that
            // return non-static types, because the Expectation itself must be
            // 'static.
            let segenerics = staticize(&self.egenerics);
            let (_, tg, _) = segenerics.split_for_impl();
            quote!(#inner_mod_ident::Expectation #tg)
        }
    }

    /// Return the name of this function's expecations object
    pub fn expectations_obj(&self) -> impl ToTokens {
        let inner_mod_ident = self.inner_mod_ident();
        if self.is_method_generic() {
            quote!(#inner_mod_ident::GenericExpectations)
        } else {
            quote!(#inner_mod_ident::Expectations)
        }
    }

    pub fn field_definition(&self, modname: Option<&Ident>) -> TokenStream {
        let name = self.name();
        let attrs = AttrFormatter::new(&self.attrs)
            .doc(false)
            .format();
        let expectations_obj = &self.expectations_obj();
        if self.is_method_generic() {
            quote!(#(#attrs)* #name: #modname::#expectations_obj)
        } else {
            // staticize any lifetimes.  This is necessary for methods that
            // return non-static types, because the Expectation itself must be
            // 'static.
            let segenerics = staticize(&self.egenerics);
            let (_, tg, _) = segenerics.split_for_impl();
            quote!(#(#attrs)* #name: #modname::#expectations_obj #tg)
        }
    }

    /// Human-readable name of the mock function
    fn funcname(&self) -> String {
        if let Some(si) = &self.struct_ {
            format!("{}::{}", si, self.name())
        } else {
            format!("{}", self.name())
        }
    }

    fn hrtb(&self) -> Option<BoundLifetimes> {
        if self.alifetimes.is_empty() {
            None
        } else {
            let lifetimes = lifetimes_to_generic_params(&self.alifetimes);
            Some(BoundLifetimes {
                lifetimes,
                lt_token: <Token![<]>::default(),
                gt_token: <Token![>]>::default(),
                .. Default::default()
            })
        }
    }

    fn is_expectation_generic(&self) -> bool {
        self.egenerics.params.iter().any(|p| {
            matches!(p, GenericParam::Type(_) | GenericParam::Const(_))
        }) || self.egenerics.where_clause.is_some()
    }

    /// Is the mock method generic (as opposed to a non-generic method of a
    /// generic mock struct)?
    pub fn is_method_generic(&self) -> bool {
        self.call_generics.params.iter().any(|p| {
            matches!(p, GenericParam::Type(_) | GenericParam::Const(_))
        }) || self.call_generics.where_clause.is_some()
    }

    fn outer_mod_path(&self, modname: Option<&Ident>) -> Path {
        let mut path = if let Some(m) = modname {
            Path::from(PathSegment::from(m.clone()))
        } else {
            Path { leading_colon: None, segments: Punctuated::new() }
        };
        path.segments.push(PathSegment::from(self.inner_mod_ident()));
        path
    }

    fn inner_mod_ident(&self) -> Ident {
        format_ident!("__{}", &self.name())
    }

    pub fn is_static(&self) -> bool {
        self.is_static
    }

    pub fn name(&self) -> &Ident {
        &self.sig.ident
    }

    /// Generate code for this function's private module
    pub fn priv_module(&self) -> impl ToTokens {
        let attrs = AttrFormatter::new(&self.attrs)
            .doc(false)
            .format();
        let common = &Common{f: self};
        let context = &Context{f: self};
        let expectation: Box<dyn ToTokens> = if self.return_ref {
            Box::new(RefExpectation{f: self})
        } else if self.return_refmut {
            Box::new(RefMutExpectation{f: self})
        } else {
            Box::new(StaticExpectation{f: self})
        };
        let expectations: Box<dyn ToTokens> = if self.return_ref {
            Box::new(RefExpectations{f: self})
        } else if self.return_refmut {
            Box::new(RefMutExpectations{f: self})
        } else {
            Box::new(StaticExpectations{f: self})
        };
        let generic_expectations = GenericExpectations{f: self};
        let guard: Box<dyn ToTokens> = if self.is_expectation_generic() {
            Box::new(GenericExpectationGuard{f: self})
        } else {
            Box::new(ConcreteExpectationGuard{f: self})
        };
        let matcher = &Matcher{f: self};
        let std_mutexguard = if self.is_static {
            quote!(use ::std::sync::MutexGuard;)
        } else {
            quote!()
        };
        let inner_mod_ident = self.inner_mod_ident();
        let rfunc: Box<dyn ToTokens> = if self.return_ref {
            Box::new(RefRfunc{f: self})
        } else if self.return_refmut {
            Box::new(RefMutRfunc{f: self})
        } else {
            Box::new(StaticRfunc{f: self})
        };
        quote!(
            #(#attrs)*
            #[allow(missing_docs)]
            #[allow(clippy::too_many_arguments, clippy::indexing_slicing)]
            pub mod #inner_mod_ident {
                use super::*;
                use ::mockall::CaseTreeExt;
                #std_mutexguard
                use ::std::{
                    boxed::Box,
                    mem,
                    ops::{DerefMut, Range},
                    sync::Mutex,
                    vec::Vec,
                };
                #rfunc
                #matcher
                #common
                #expectation
                #expectations
                #generic_expectations
                #guard
                #context
            }
        )
    }
}

/// Holds parts of the expectation that are common for all output types
struct Common<'a> {
    f: &'a MockFunction
}

impl ToTokens for Common<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let predty = &self.f.predty;
        let hrtb = self.f.hrtb();
        let funcname = self.f.funcname();
        let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let refpredty = &self.f.refpredty;
        let with_generics_idents = (0..self.f.predty.len())
            .map(|i| format_ident!("MockallMatcher{i}"))
            .collect::<Vec<_>>();
        let with_generics = with_generics_idents.iter()
            .zip(self.f.predty.iter())
            .map(|(id, mt)|
                quote!(#id: #hrtb ::mockall::Predicate<#mt> + ::std::marker::Send + 'static, )
            ).collect::<TokenStream>();
        let with_args = self.f.argnames.iter()
            .zip(with_generics_idents.iter())
            .map(|(argname, id)| quote!(#argname: #id, ))
            .collect::<TokenStream>();
        let boxed_withargs = argnames.iter()
            .map(|aa| quote!(Box::new(#aa), ))
            .collect::<TokenStream>();
        let with_method = if self.f.concretize {
            quote!(
                // No `with` method when concretizing generics
            )
        } else {
            quote!(
                fn with<#with_generics>(&mut self, #with_args)
                    {
                        let mut __mockall_guard = self.matcher.lock().unwrap();
                        *__mockall_guard.deref_mut() =
                            Matcher::Pred(Box::new((#boxed_withargs)));
                    }
            )
        };

        quote!(
            /// Holds the stuff that is independent of the output type
            struct Common #ig #wc {
                matcher: Mutex<Matcher #tg>,
                seq_handle: Option<::mockall::SeqHandle>,
                times: ::mockall::Times
            }

            impl #ig std::default::Default for Common #tg #wc
            {
                fn default() -> Self {
                    Common {
                        matcher: Mutex::new(Matcher::default()),
                        seq_handle: None,
                        times: ::mockall::Times::default()
                    }
                }
            }

            impl #ig Common #tg #wc {
                fn call<F: Fn() -> ::std::string::String>(&self, desc: F) {
                    self.times.call()
                        .unwrap_or_else(|m| {
                            let desc = std::format!(
                                "{}", self.matcher.lock().unwrap());
                            panic!("{}: Expectation({}) {}", #funcname, desc,
                                m);
                        });
                    self.verify_sequence(desc);
                    if ::mockall::ExpectedCalls::TooFew 
                        != self.times.is_satisfied() {
                        self.satisfy_sequence()
                    } else {
                        self.called_sequence()
                    }
                }

                fn in_sequence(
                    &mut self,
                    __mockall_seq: &mut ::mockall::Sequence)
                    -> &mut Self
                {
                    self.seq_handle = Some(__mockall_seq.next_handle(
                        ::mockall::times_to_minimum_call_count(&self.times)
                    ));
                    self
                }

                fn is_done(&self) -> bool {
                    self.times.is_done() | self.is_history_sequence()
                }

                #[allow(clippy::ptr_arg)]
                #[allow(clippy::ref_option)]
                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
                    self.matcher.lock().unwrap().matches(#(#argnames, )*)
                }

                /// Forbid this expectation from ever being called.
                fn never(&mut self) {
                    self.times.never();
                }

                fn satisfy_sequence(&self) {
                    if let Some(__mockall_handle) = &self.seq_handle {
                        __mockall_handle.satisfy()
                    }
                }

                fn called_sequence(&self) {
                    if let Some(__mockall_handle) = &self.seq_handle {
                        __mockall_handle.called()
                    }
                }

                fn is_history_sequence(&self) -> bool {
                    if let Some(__mockall_handle) = &self.seq_handle {
                        __mockall_handle.is_history()
                    } else {
                        false
                    }
                }

                /// Expect this expectation to be called any number of times
                /// contained with the given range.
                fn times<MockallR>(&mut self, __mockall_r: MockallR)
                    where MockallR: Into<::mockall::TimesRange>
                {
                    self.times.times(__mockall_r)
                }

                #with_method

                fn withf<MockallF>(&mut self, __mockall_f: MockallF)
                    where MockallF: #hrtb Fn(#( #refpredty, )*)
                                    -> bool + ::std::marker::Send + 'static
                {
                    let mut __mockall_guard = self.matcher.lock().unwrap();
                    *__mockall_guard.deref_mut() =
                         Matcher::Func(Box::new(__mockall_f));
                }

                fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
                    where MockallF: #hrtb Fn(#( #refpredty, )*)
                                    -> bool + 'static
                {
                    let mut __mockall_guard = self.matcher.lock().unwrap();
                    *__mockall_guard.deref_mut() =
                         Matcher::FuncSt(
                             ::mockall::Fragile::new(Box::new(__mockall_f))
                        );
                }

                fn verify_sequence<F: Fn() -> ::std::string::String>(&self, desc: F) {
                    if let Some(__mockall_handle) = &self.seq_handle {
                        __mockall_handle.verify(desc)
                    }
                }
            }

            impl #ig Drop for Common #tg #wc {
                fn drop(&mut self) {
                    if !::std::thread::panicking() {
                        let desc = std::format!(
                            "{}", self.matcher.lock().unwrap());
                        match self.times.is_satisfied() {
                            ::mockall::ExpectedCalls::TooFew => {
                                panic!("{}: Expectation({}) called {} time(s) which is fewer than expected {}",
                                    #funcname,
                                    desc,
                                    self.times.count(),
                                    self.times.minimum());
                            },
                            ::mockall::ExpectedCalls::TooMany => {
                                panic!("{}: Expectation({}) called {} time(s) which is more than expected {}",
                                    #funcname,
                                    desc,
                                    self.times.count(),
                                    self.times.maximum());
                            },
                            _ => ()
                        }
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

/// Generates methods that are common for all Expectation types
struct CommonExpectationMethods<'a> {
    f: &'a MockFunction
}

impl ToTokens for CommonExpectationMethods<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let hrtb = self.f.hrtb();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let predty = &self.f.predty;
        let with_generics_idents = (0..self.f.predty.len())
            .map(|i| format_ident!("MockallMatcher{i}"))
            .collect::<Vec<_>>();
        let with_generics = with_generics_idents.iter()
            .zip(self.f.predty.iter())
            .map(|(id, mt)|
                quote!(#id: #hrtb ::mockall::Predicate<#mt> + ::std::marker::Send + 'static, )
            ).collect::<TokenStream>();
        let with_args = self.f.argnames.iter()
            .zip(with_generics_idents.iter())
            .map(|(argname, id)| quote!(#argname: #id, ))
            .collect::<TokenStream>();
        let v = &self.f.privmod_vis;
        let with_method = if self.f.concretize {
            quote!(
                // No `with` method when concretizing generics
            )
        } else {
            quote!(
                /// Set matching criteria for this Expectation.
                ///
                /// The matching predicate can be anything implemening the
                /// [`Predicate`](../../../mockall/trait.Predicate.html) trait.  Only
                /// one matcher can be set per `Expectation` at a time.
                #v fn with<#with_generics>(&mut self, #with_args) -> &mut Self
                {
                    self.common.with(#(#argnames, )*);
                    self
                }
            )
        };
        quote!(
            /// Add this expectation to a
            /// [`Sequence`](../../../mockall/struct.Sequence.html).
            #v fn in_sequence(&mut self, __mockall_seq: &mut ::mockall::Sequence)
                -> &mut Self
            {
                self.common.in_sequence(__mockall_seq);
                self
            }

            fn is_done(&self) -> bool {
                self.common.is_done()
            }

            /// Validate this expectation's matcher.
            #[allow(clippy::ptr_arg)]
            #[allow(clippy::ref_option)]
            fn matches #lg (&self, #(#argnames: &#predty, )*) -> bool {
                self.common.matches(#(#argnames, )*)
            }

            /// Forbid this expectation from ever being called.
            #v fn never(&mut self) -> &mut Self {
                self.common.never();
                self
            }

            /// Create a new, default, [`Expectation`](struct.Expectation.html)
            #v fn new() -> Self {
                Self::default()
            }

            /// Expect this expectation to be called exactly once.  Shortcut for
            /// [`times(1)`](#method.times).
            #v fn once(&mut self) -> &mut Self {
                self.times(1)
            }

            /// Restrict the number of times that that this method may be called.
            ///
            /// The argument may be:
            /// * A fixed number: `.times(4)`
            /// * Various types of range:
            ///   - `.times(5..10)`
            ///   - `.times(..10)`
            ///   - `.times(5..)`
            ///   - `.times(5..=10)`
            ///   - `.times(..=10)`
            /// * The wildcard: `.times(..)`
            #v fn times<MockallR>(&mut self, __mockall_r: MockallR) -> &mut Self
                where MockallR: Into<::mockall::TimesRange>
            {
                self.common.times(__mockall_r);
                self
            }

            #with_method

            /// Set a matching function for this Expectation.
            ///
            /// This is equivalent to calling [`with`](#method.with) with a
            /// function argument, like `with(predicate::function(f))`.
            #v fn withf<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
                where MockallF: #hrtb Fn(#(&#predty, )*)
                                -> bool + ::std::marker::Send + 'static
            {
                self.common.withf(__mockall_f);
                self
            }

            /// Single-threaded version of [`withf`](#method.withf).
            /// Can be used when the argument type isn't `Send`.
            #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
                where MockallF: #hrtb Fn(#(&#predty, )*)
                                -> bool + 'static
            {
                self.common.withf_st(__mockall_f);
                self
            }
        ).to_tokens(tokens);
    }
}

/// Holds the moethods of the Expectations object that are common for all
/// Expectation types
struct CommonExpectationsMethods<'a> {
    f: &'a MockFunction
}

impl ToTokens for CommonExpectationsMethods<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let v = &self.f.privmod_vis;
        quote!(
            /// A collection of [`Expectation`](struct.Expectations.html)
            /// objects.  Users will rarely if ever use this struct directly.
            #[doc(hidden)]
            #v struct Expectations #ig ( Vec<Expectation #tg>) #wc;

            impl #ig Expectations #tg #wc {
                /// Verify that all current expectations are satisfied and clear
                /// them.
                #v fn checkpoint(&mut self) -> std::vec::Drain<Expectation #tg>
                {
                    self.0.drain(..)
                }

                /// Create a new expectation for this method.
                #v fn expect(&mut self) -> &mut Expectation #tg
                {
                    self.0.push(Expectation::default());
                    let __mockall_l = self.0.len();
                    &mut self.0[__mockall_l - 1]
                }

                #v const fn new() -> Self {
                    Self(Vec::new())
                }
            }
            #[allow(single_use_lifetimes)]
            impl #ig Default for Expectations #tg #wc
            {
                fn default() -> Self {
                    Expectations::new()
                }
            }
        ).to_tokens(tokens);
    }
}

/// The ExpectationGuard structure for static methods with no generic types
struct ExpectationGuardCommonMethods<'a> {
    f: &'a MockFunction
}

impl ToTokens for ExpectationGuardCommonMethods<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if !self.f.is_static {
            return;
        }

        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (_, tg, _) = self.f.egenerics.split_for_impl();
        let keyid = gen_keyid(&self.f.egenerics);
        let expectations = if self.f.is_expectation_generic() {
            quote!(self.guard
                   .store
                   .get_mut(&::mockall::Key::new::#keyid())
                   .unwrap()
                   .downcast_mut::<Expectations #tg>()
                   .unwrap())
        } else {
            quote!(self.guard)
        };
        let hrtb = self.f.hrtb();
        let output = &self.f.output;
        let predty = &self.f.predty;
        let with_generics_idents = (0..self.f.predty.len())
            .map(|i| format_ident!("MockallMatcher{i}"))
            .collect::<Vec<_>>();
        let with_generics = with_generics_idents.iter()
            .zip(self.f.predty.iter())
            .map(|(id, mt)|
                quote!(#id: #hrtb ::mockall::Predicate<#mt> + ::std::marker::Send + 'static, )
            ).collect::<TokenStream>();
        let with_args = self.f.argnames.iter()
            .zip(with_generics_idents.iter())
            .map(|(argname, id)| quote!(#argname: #id, ))
            .collect::<TokenStream>();
        let v = &self.f.privmod_vis;
        let with_method = if self.f.concretize {
            quote!()
        } else {
                quote!(
                /// Just like
                /// [`Expectation::with`](struct.Expectation.html#method.with)
                #v fn with<#with_generics> (&mut self, #with_args)
                    -> &mut Expectation #tg
                {
                    #expectations.0[self.i].with(#(#argnames, )*)
                }
            )
        };
        quote!(
            /// Just like
            /// [`Expectation::in_sequence`](struct.Expectation.html#method.in_sequence)
            #v fn in_sequence(&mut self,
                __mockall_seq: &mut ::mockall::Sequence)
                -> &mut Expectation #tg
            {
                #expectations.0[self.i].in_sequence(__mockall_seq)
            }

            /// Just like
            /// [`Expectation::never`](struct.Expectation.html#method.never)
            #v fn never(&mut self) -> &mut Expectation #tg {
                #expectations.0[self.i].never()
            }

            /// Just like
            /// [`Expectation::once`](struct.Expectation.html#method.once)
            #v fn once(&mut self) -> &mut Expectation #tg {
                #expectations.0[self.i].once()
            }

            /// Just like
            /// [`Expectation::return_const`](struct.Expectation.html#method.return_const)
            #v fn return_const<MockallOutput>
            (&mut self, __mockall_c: MockallOutput)
                -> &mut Expectation #tg
                where MockallOutput: Clone + Into<#output> + ::std::marker::Send + 'static
            {
                #expectations.0[self.i].return_const(__mockall_c)
            }

            /// Just like
            /// [`Expectation::return_const_st`](struct.Expectation.html#method.return_const_st)
            #v fn return_const_st<MockallOutput>
            (&mut self, __mockall_c: MockallOutput)
                -> &mut Expectation #tg
                where MockallOutput: Clone + Into<#output> + 'static
            {
                #expectations.0[self.i].return_const_st(__mockall_c)
            }

            /// Just like
            /// [`Expectation::returning`](struct.Expectation.html#method.returning)
            #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb FnMut(#(#argty, )*)
                    -> #output + ::std::marker::Send + 'static
            {
                #expectations.0[self.i].returning(__mockall_f)
            }

            /// Just like
            /// [`Expectation::return_once`](struct.Expectation.html#method.return_once)
            #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb FnOnce(#(#argty, )*)
                                -> #output + ::std::marker::Send + 'static
            {
                #expectations.0[self.i].return_once(__mockall_f)
            }

            /// Just like
            /// [`Expectation::return_once_st`](struct.Expectation.html#method.return_once_st)
            #v fn return_once_st<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb FnOnce(#(#argty, )*)
                                -> #output + 'static
            {
                #expectations.0[self.i].return_once_st(__mockall_f)
            }


            /// Just like
            /// [`Expectation::returning_st`](struct.Expectation.html#method.returning_st)
            #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb FnMut(#(#argty, )*)
                                -> #output + 'static
            {
                #expectations.0[self.i].returning_st(__mockall_f)
            }

            /// Just like
            /// [`Expectation::times`](struct.Expectation.html#method.times)
            #v fn times<MockallR>(&mut self, __mockall_r: MockallR)
                -> &mut Expectation #tg
                where MockallR: Into<::mockall::TimesRange>
            {
                #expectations.0[self.i].times(__mockall_r)
            }

            #with_method

            /// Just like
            /// [`Expectation::withf`](struct.Expectation.html#method.withf)
            #v fn withf<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb Fn(#(&#predty, )*)
                                -> bool + ::std::marker::Send + 'static
            {
                #expectations.0[self.i].withf(__mockall_f)
            }

            /// Just like
            /// [`Expectation::withf_st`](struct.Expectation.html#method.withf_st)
            #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
                -> &mut Expectation #tg
                where MockallF: #hrtb Fn(#(&#predty, )*)
                                -> bool + 'static
            {
                #expectations.0[self.i].withf_st(__mockall_f)
            }
        ).to_tokens(tokens);
    }
}

/// The ExpectationGuard structure for static methods with no generic types
struct ConcreteExpectationGuard<'a> {
    f: &'a MockFunction
}

impl ToTokens for ConcreteExpectationGuard<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if !self.f.is_static {
            return;
        }

        let common_methods = ExpectationGuardCommonMethods{f: self.f};
        let (_, tg, _) = self.f.egenerics.split_for_impl();
        let ltdef = LifetimeParam::new(
            Lifetime::new("'__mockall_lt", Span::call_site())
        );
        let mut e_generics = self.f.egenerics.clone();
        e_generics.lt_token.get_or_insert(<Token![<]>::default());
        e_generics.params.push(GenericParam::Lifetime(ltdef));
        e_generics.gt_token.get_or_insert(<Token![>]>::default());
        let (e_ig, e_tg, e_wc) = e_generics.split_for_impl();
        let (ei_ig, _, _) = e_generics.split_for_impl();
        let v = &self.f.privmod_vis;
        quote!(
            #[doc(hidden)]
            #v fn get_expectations() -> &'static ::std::sync::Mutex<Expectations> {
                static EXPECTATIONS:
                    ::std::sync::Mutex<Expectations #tg> =
                    ::std::sync::Mutex::new(Expectations::new());
                &EXPECTATIONS
            }

            /// Like an [`&Expectation`](struct.Expectation.html) but
            /// protected by a Mutex guard.  Useful for mocking static
            /// methods.  Forwards accesses to an `Expectation` object.
            // We must return the MutexGuard to the caller so he can
            // configure the expectation.  But we can't bundle both the
            // guard and the &Expectation into the same structure; the
            // borrow checker won't let us.  Instead we'll record the
            // expectation's position within the Expectations vector so we
            // can proxy its methods.
            //
            // ExpectationGuard is only defined for expectations that return
            // 'static return types.
            #v struct ExpectationGuard #e_ig #e_wc {
                guard: MutexGuard<'__mockall_lt, Expectations #tg>,
                i: usize
            }

            #[allow(clippy::unused_unit)]
            impl #ei_ig ExpectationGuard #e_tg #e_wc
            {
                // Should only be called from the mockall_derive generated
                // code
                #[doc(hidden)]
                #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, Expectations #tg>)
                    -> Self
                {
                    __mockall_guard.expect(); // Drop the &Expectation
                    let __mockall_i = __mockall_guard.0.len() - 1;
                    ExpectationGuard{guard: __mockall_guard, i: __mockall_i}
                }

                #common_methods
            }
        ).to_tokens(tokens);
    }
}

/// The ExpectationGuard structure for static methods with generic types
struct GenericExpectationGuard<'a> {
    f: &'a MockFunction
}

impl ToTokens for GenericExpectationGuard<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if !self.f.is_static {
            return;
        }

        let common_methods = ExpectationGuardCommonMethods{f: self.f};
        let (_, tg, _) = self.f.egenerics.split_for_impl();
        let keyid = gen_keyid(&self.f.egenerics);
        let ltdef = LifetimeParam::new(
            Lifetime::new("'__mockall_lt", Span::call_site())
        );
        let mut egenerics = self.f.egenerics.clone();
        egenerics.lt_token.get_or_insert(<Token![<]>::default());
        egenerics.params.push(GenericParam::Lifetime(ltdef));
        egenerics.gt_token.get_or_insert(<Token![>]>::default());
        let (e_ig, e_tg, e_wc) = egenerics.split_for_impl();
        let fn_params = &self.f.fn_params;
        let tbf = tg.as_turbofish();
        let v = &self.f.privmod_vis;
        quote!(
            #[doc(hidden)]
            #v fn get_expectations() -> &'static ::std::sync::Mutex<GenericExpectations> {
                static CELL: ::std::sync::OnceLock<::std::sync::Mutex<GenericExpectations>> = ::std::sync::OnceLock::new();
                CELL.get_or_init(|| ::std::sync::Mutex::new(GenericExpectations::new()))
            }

            /// Like an [`&Expectation`](struct.Expectation.html) but
            /// protected by a Mutex guard.  Useful for mocking static
            /// methods.  Forwards accesses to an `Expectation` object.
            #v struct ExpectationGuard #e_ig #e_wc{
                guard: MutexGuard<'__mockall_lt, GenericExpectations>,
                i: usize,
                _phantom: ::std::marker::PhantomData<(#(#fn_params,)*)>,
            }

            #[allow(clippy::unused_unit)]
            impl #e_ig ExpectationGuard #e_tg #e_wc
            {
                // Should only be called from the mockall_derive generated
                // code
                #[doc(hidden)]
                #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, GenericExpectations>)
                    -> Self
                {
                    let __mockall_ee: &mut Expectations #tg =
                        __mockall_guard.store.entry(
                            ::mockall::Key::new::#keyid()
                        ).or_insert_with(||
                            Box::new(Expectations #tbf ::new()))
                        .downcast_mut()
                        .unwrap();
                    __mockall_ee.expect();    // Drop the &Expectation
                    let __mockall_i = __mockall_ee.0.len() - 1;
                    ExpectationGuard{guard: __mockall_guard, i: __mockall_i,
                        _phantom: ::std::marker::PhantomData}
                }

                #common_methods
            }
        ).to_tokens(tokens);
    }
}

/// Generates Context, which manages the context for expectations of static
/// methods.
struct Context<'a> {
    f: &'a MockFunction
}

impl ToTokens for Context<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if !self.f.is_static {
            return;
        }

        let ltdef = LifetimeParam::new(
            Lifetime::new("'__mockall_lt", Span::call_site())
        );
        let mut egenerics = self.f.egenerics.clone();
        egenerics.lt_token.get_or_insert(<Token![<]>::default());
        egenerics.params.push(GenericParam::Lifetime(ltdef));
        egenerics.gt_token.get_or_insert(<Token![>]>::default());
        let (_, e_tg, _) = egenerics.split_for_impl();
        let (ty_ig, ty_tg, ty_wc) = self.f.type_generics.split_for_impl();
        let mut meth_generics = self.f.call_generics.clone();
        let ltdef = LifetimeParam::new(
            Lifetime::new("'__mockall_lt", Span::call_site())
        );
        meth_generics.params.push(GenericParam::Lifetime(ltdef));
        let (meth_ig, _meth_tg, meth_wc) = meth_generics.split_for_impl();
        let ctx_fn_params = self.f.struct_generics.type_params()
            .map(|tp| tp.ident.clone())
            .collect::<Punctuated::<Ident, Token![,]>>();
        let v = &self.f.privmod_vis;

        #[cfg(not(feature = "nightly_derive"))]
        let must_use = quote!(#[must_use =
                "Must set return value when not using the \"nightly\" feature"
            ]);
        #[cfg(feature = "nightly_derive")]
        let must_use = quote!();

        quote!(
            /// Manages the context for expectations of static methods.
            ///
            /// Expectations on this method will be validated and cleared when
            /// the `Context` object drops.  The `Context` object does *not*
            /// provide any form of synchronization, so multiple tests that set
            /// expectations on the same static method must provide their own.
            #[must_use = "Context only serves to create expectations" ]
            #v struct Context #ty_ig #ty_wc {
                // Prevent "unused type parameter" errors
                // Surprisingly, PhantomData<Fn(generics)> is Send even if
                // generics are not, unlike PhantomData<generics>
                _phantom: ::std::marker::PhantomData<
                    Box<dyn Fn(#ctx_fn_params) + ::std::marker::Send>
                >
            }
            impl #ty_ig Context #ty_tg #ty_wc {
                /// Verify that all current expectations for this method are
                /// satisfied and clear them.
                #v fn checkpoint(&self) {
                    Self::do_checkpoint()
                }
                #[doc(hidden)]
                #v fn do_checkpoint() {
                    let __mockall_timeses = get_expectations()
                        .lock()
                        .unwrap()
                        .checkpoint()
                        .collect::<Vec<_>>();
                }

                /// Create a new expectation for this method.
                #must_use
                #v fn expect #meth_ig ( &self,) -> ExpectationGuard #e_tg
                    #meth_wc
                {
                    ExpectationGuard::new(get_expectations().lock().unwrap())
                }
            }
            impl #ty_ig Default for Context #ty_tg #ty_wc {
                fn default() -> Self {
                    Context {_phantom: std::marker::PhantomData}
                }
            }
            impl #ty_ig Drop for Context #ty_tg #ty_wc {
                fn drop(&mut self) {
                    if ! ::std::thread::panicking() {
                        // Verify expectations are satisfied
                        Self::do_checkpoint();
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

struct Matcher<'a> {
    f: &'a MockFunction
}

impl ToTokens for Matcher<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
        let argnames = &self.f.argnames;
        let braces = argnames.iter()
            .fold(String::new(), |mut acc, _argname| {
                if acc.is_empty() {
                    acc.push_str("{}");
                } else {
                    acc.push_str(", {}");
                }
                acc
            });
        let fn_params = &self.f.fn_params;
        let hrtb = self.f.hrtb();
        let indices = (0..argnames.len())
            .map(|i| {
                syn::Index::from(i)
            }).collect::<Vec<_>>();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let pred_matches = argnames.iter().enumerate()
            .map(|(i, argname)| {
                let idx = syn::Index::from(i);
                quote!(__mockall_pred.#idx.eval(#argname),)
            }).collect::<TokenStream>();
        let preds = if self.f.concretize {
            quote!(())
        } else {
            self.f.predty.iter()
            .map(|t| quote!(Box<dyn #hrtb ::mockall::Predicate<#t> + ::std::marker::Send>,))
            .collect::<TokenStream>()
        };
        let predty = &self.f.predty;
        let refpredty = &self.f.refpredty;
        let predmatches_body = if self.f.concretize {
            quote!()
        } else {
            quote!(Matcher::Pred(__mockall_pred) => [#pred_matches].iter().all(|__mockall_x| *__mockall_x),)
        };
        let preddbg_body = if self.f.concretize {
            quote!()
        } else {
            quote!(
                Matcher::Pred(__mockall_p) => {
                    write!(__mockall_fmt, #braces,
                        #(__mockall_p.#indices,)*)
                }
            )
        };
        quote!(
            enum Matcher #ig #wc {
                Always,
                Func(Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool + ::std::marker::Send>),
                // Version of Matcher::Func for closures that aren't Send
                FuncSt(::mockall::Fragile<Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool>>),
                Pred(Box<(#preds)>),
                // Prevent "unused type parameter" errors
                // Surprisingly, PhantomData<Fn(generics)> is Send even if
                // generics are not, unlike PhantomData<generics>
                _Phantom(Box<dyn Fn(#(#fn_params,)*) + ::std::marker::Send>)
            }
            impl #ig Matcher #tg #wc {
                #[allow(clippy::ptr_arg)]
                #[allow(clippy::ref_option)]
                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
                    match self {
                        Matcher::Always => true,
                        Matcher::Func(__mockall_f) =>
                            __mockall_f(#(#argnames, )*),
                        Matcher::FuncSt(__mockall_f) =>
                            (__mockall_f.get())(#(#argnames, )*),
                        #predmatches_body
                        _ => unreachable!()
                    }
                }
            }

            impl #ig Default for Matcher #tg #wc {
                #[allow(unused_variables)]
                fn default() -> Self {
                    Matcher::Always
                }
            }

            impl #ig ::std::fmt::Display for Matcher #tg #wc {
                fn fmt(&self, __mockall_fmt: &mut ::std::fmt::Formatter<'_>)
                    -> ::std::fmt::Result
                {
                    match self {
                        Matcher::Always => write!(__mockall_fmt, "<anything>"),
                        Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
                        Matcher::FuncSt(_) => write!(__mockall_fmt, "<single threaded function>"),
                        #preddbg_body
                        _ => unreachable!(),
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

struct RefRfunc<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefRfunc<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let fn_params = &self.f.fn_params;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let owned_output = &self.f.owned_output;

        #[cfg(not(feature = "nightly_derive"))]
        let default_err_msg =
            "Returning default values requires the \"nightly\" feature";
        #[cfg(feature = "nightly_derive")]
        let default_err_msg =
            "Can only return default values for types that impl std::Default";

        quote!(
            enum Rfunc #ig #wc {
                Default(Option<#owned_output>),
                Const(#owned_output),
                // Prevent "unused type parameter" errors Surprisingly,
                // PhantomData<Fn(generics)> is Send even if generics are not,
                // unlike PhantomData<generics>
                _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + ::std::marker::Send>>)
            }

            impl #ig  Rfunc #tg #wc {
                fn call #lg (&self)
                    -> std::result::Result<&#owned_output, &'static str>
                {
                    match self {
                        Rfunc::Default(Some(ref __mockall_o)) => {
                            ::std::result::Result::Ok(__mockall_o)
                        },
                        Rfunc::Default(None) => {
                            Err(#default_err_msg)
                        },
                        Rfunc::Const(ref __mockall_o) => {
                            ::std::result::Result::Ok(__mockall_o)
                        },
                        Rfunc::_Phantom(_) => unreachable!()
                    }
                }
            }

            #[allow(single_use_lifetimes)]
            impl #ig std::default::Default for Rfunc #tg #wc
            {
                fn default() -> Self {
                    use ::mockall::ReturnDefault;
                    Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
                                ::maybe_return_default())
                }
            }
        ).to_tokens(tokens);
    }
}

struct RefMutRfunc<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefMutRfunc<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let fn_params = &self.f.fn_params;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let owned_output = &self.f.owned_output;
        let output = &self.f.output;

        #[cfg(not(feature = "nightly_derive"))]
        let default_err_msg =
            "Returning default values requires the \"nightly\" feature";
        #[cfg(feature = "nightly_derive")]
        let default_err_msg =
            "Can only return default values for types that impl std::Default";

        quote!(
            #[allow(clippy::unused_unit)]
            enum Rfunc #ig #wc {
                Default(Option<#owned_output>),
                Mut((Box<dyn FnMut(#(#argty, )*) -> #owned_output + ::std::marker::Send + ::std::marker::Sync>),
                    Option<#owned_output>),
                // Version of Rfunc::Mut for closures that aren't Send
                MutSt((::mockall::Fragile<
                           Box<dyn FnMut(#(#argty, )*) -> #owned_output >>
                       ), Option<#owned_output>
                ),
                Var(#owned_output),
                // Prevent "unused type parameter" errors Surprisingly,
                // PhantomData<Fn(generics)> is Send even if generics are not,
                // unlike PhantomData<generics>
                _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + ::std::marker::Send>>)
            }

            impl #ig  Rfunc #tg #wc {
                fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
                    -> std::result::Result<#output, &'static str>
                {
                    match self {
                        Rfunc::Default(Some(ref mut __mockall_o)) => {
                            ::std::result::Result::Ok(__mockall_o)
                        },
                        Rfunc::Default(None) => {
                            Err(#default_err_msg)
                        },
                        Rfunc::Mut(ref mut __mockall_f, ref mut __mockall_o) =>
                        {
                            *__mockall_o = Some(__mockall_f(#(#argnames, )*));
                            if let Some(ref mut __mockall_o2) = __mockall_o {
                                ::std::result::Result::Ok(__mockall_o2)
                            } else {
                                unreachable!()
                            }
                        },
                        Rfunc::MutSt(ref mut __mockall_f, ref mut __mockall_o)=>
                        {
                            *__mockall_o = Some((__mockall_f.get_mut())(
                                    #(#argnames, )*)
                            );
                            if let Some(ref mut __mockall_o2) = __mockall_o {
                                ::std::result::Result::Ok(__mockall_o2)
                            } else {
                                unreachable!()
                            }
                        },
                        Rfunc::Var(ref mut __mockall_o) => {
                            ::std::result::Result::Ok(__mockall_o)
                        },
                        Rfunc::_Phantom(_) => unreachable!()
                    }
                }
            }

            #[allow(single_use_lifetimes)]
            impl #ig std::default::Default for Rfunc #tg #wc
            {
                fn default() -> Self {
                    use ::mockall::ReturnDefault;
                    Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
                                ::maybe_return_default())
                }
            }
        ).to_tokens(tokens);
    }
}

struct StaticRfunc<'a> {
    f: &'a MockFunction
}

impl ToTokens for StaticRfunc<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let fn_params = &self.f.fn_params;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let hrtb = self.f.hrtb();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        quote!(
            #[allow(clippy::unused_unit)]
            enum Rfunc #ig #wc {
                Default,
                // Indicates that a `return_once` expectation has already
                // returned
                Expired,
                Mut(Box<dyn #hrtb FnMut(#(#argty, )*) -> #output + ::std::marker::Send>),
                // Version of Rfunc::Mut for closures that aren't Send
                MutSt(::mockall::Fragile<
                    Box<dyn #hrtb FnMut(#(#argty, )*) -> #output >>
                ),
                Once(Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output + ::std::marker::Send>),
                // Version of Rfunc::Once for closure that aren't Send
                OnceSt(::mockall::Fragile<
                    Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output>>
                ),
                // Prevent "unused type parameter" errors Surprisingly,
                // PhantomData<Fn(generics)> is Send even if generics are not,
                // unlike PhantomData<generics>
                _Phantom(Box<dyn Fn(#(#fn_params,)*) + ::std::marker::Send>)
            }

            impl #ig  Rfunc #tg #wc {
                fn call_mut #lg (&mut self, #( #argnames: #argty, )* )
                    -> std::result::Result<#output, &'static str>
                {
                    match self {
                        Rfunc::Default => {
                            use ::mockall::ReturnDefault;
                            ::mockall::DefaultReturner::<#output>
                                ::return_default()
                        },
                        Rfunc::Expired => {
                            Err("called twice, but it returns by move")
                        },
                        Rfunc::Mut(__mockall_f) => {
                            ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
                        },
                        Rfunc::MutSt(__mockall_f) => {
                            ::std::result::Result::Ok((__mockall_f.get_mut())(#(#argnames,)*))
                        },
                        Rfunc::Once(_) => {
                            if let Rfunc::Once(mut __mockall_f) =
                                mem::replace(self, Rfunc::Expired) {
                                ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
                            } else {
                                unreachable!()
                            }
                        },
                        Rfunc::OnceSt(_) => {
                            if let Rfunc::OnceSt(mut __mockall_f) =
                                mem::replace(self, Rfunc::Expired) {
                                ::std::result::Result::Ok((__mockall_f.into_inner())(#(#argnames,)*))
                            } else {
                                unreachable!()
                            }
                        },
                        Rfunc::_Phantom(_) => unreachable!()
                    }
                }
            }

            #[allow(single_use_lifetimes)]
            impl #ig std::default::Default for Rfunc #tg #wc
            {
                fn default() -> Self {
                    Rfunc::Default
                }
            }
        ).to_tokens(tokens);
    }
}

/// An expectation type for functions that take a &self and return a reference
struct RefExpectation<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefExpectation<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let common_methods = CommonExpectationMethods{f: self.f};
        let (desc_fmt, desc_args) = self.f.desc();
        let funcname = self.f.funcname();
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();

        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        let owned_output = &self.f.owned_output;
        let v = &self.f.privmod_vis;
        quote!(
            /// Expectation type for methods taking a `&self` argument and
            /// returning immutable references.  This is the type returned by
            /// the `expect_*` methods.
            #v struct Expectation #ig #wc {
                common: Common #common_tg,
                rfunc: Rfunc #tg,
            }

            #[allow(clippy::unused_unit)]
            impl #ig Expectation #tg #wc {
                /// Call this [`Expectation`] as if it were the real method.
                #v fn call #lg (&self, #(#argnames: #argty, )*) -> #output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    self.common.call(|| std::format!(#desc_fmt, #desc_args));
                    self.rfunc.call().unwrap_or_else(|m| {
                        let desc = std::format!(
                            "{}", self.common.matcher.lock().unwrap());
                        panic!("{}: Expectation({}) {}", #funcname, desc,
                            m);
                    })
                }

                /// Return a reference to a constant value from the `Expectation`
                #v fn return_const(&mut self, __mockall_o: #owned_output)
                    -> &mut Self
                {
                    self.rfunc = Rfunc::Const(__mockall_o);
                    self
                }

                #common_methods
            }
            #[allow(single_use_lifetimes)]
            impl #ig Default for Expectation #tg #wc
            {
                fn default() -> Self {
                    Expectation {
                        common: Common::default(),
                        rfunc: Rfunc::default()
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

/// For methods that take &mut self and return a reference
struct RefMutExpectation<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefMutExpectation<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let common_methods = CommonExpectationMethods{f: self.f};
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (desc_fmt, desc_args) = self.f.desc();
        let funcname = self.f.funcname();
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let owned_output = &self.f.owned_output;
        let v = &self.f.privmod_vis;
        quote!(
            /// Expectation type for methods taking a `&mut self` argument and
            /// returning references.  This is the type returned by the
            /// `expect_*` methods.
            #v struct Expectation #ig #wc {
                common: Common #common_tg,
                rfunc: Rfunc #tg
            }

            #[allow(clippy::unused_unit)]
            impl #ig Expectation #tg #wc {
                /// Simulating calling the real method for this expectation
                #v fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
                    -> &mut #owned_output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    self.common.call(|| std::format!(#desc_fmt, #desc_args));
                    let desc = std::format!(
                        "{}", self.common.matcher.lock().unwrap());
                    self.rfunc.call_mut(#(#argnames, )*).unwrap_or_else(|m| {
                            panic!("{}: Expectation({}) {}", #funcname, desc,
                                   m);
                    })
                }

                /// Convenience method that can be used to supply a return value
                /// for a `Expectation`.  The value will be returned by mutable
                /// reference.
                #v fn return_var(&mut self, __mockall_o: #owned_output) -> &mut Self
                {
                    self.rfunc = Rfunc::Var(__mockall_o);
                    self
                }

                /// Supply a closure that the `Expectation` will use to create its
                /// return value.  The return value will be returned by mutable
                /// reference.
                #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
                    -> &mut Self
                    where MockallF: FnMut(#(#argty, )*) -> #owned_output + ::std::marker::Send + ::std::marker::Sync + 'static
                {
                    self.rfunc = Rfunc::Mut(Box::new(__mockall_f), None);
                    self
                }

                /// Single-threaded version of [`returning`](#method.returning).
                /// Can be used when the argument or return type isn't `Send`.
                #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
                    -> &mut Self
                    where MockallF: FnMut(#(#argty, )*) -> #owned_output + 'static
                {
                    self.rfunc = Rfunc::MutSt(
                        ::mockall::Fragile::new(Box::new(__mockall_f)), None);
                    self
                }

                #common_methods
            }
            #[allow(single_use_lifetimes)]
            impl #ig Default for Expectation #tg #wc
            {
                fn default() -> Self {
                    Expectation {
                        common: Common::default(),
                        rfunc: Rfunc::default()
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

/// An expectation type for functions return a `'static` value
struct StaticExpectation<'a> {
    f: &'a MockFunction
}

impl ToTokens for StaticExpectation<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let common_methods = CommonExpectationMethods{f: self.f};
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (desc_fmt, desc_args) = self.f.desc();
        let hrtb = self.f.hrtb();
        let funcname = self.f.funcname();
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        let v = &self.f.privmod_vis;

        quote!(
            /// Expectation type for methods that return a `'static` type.
            /// This is the type returned by the `expect_*` methods.
            #v struct Expectation #ig #wc {
                common: Common #common_tg,
                rfunc: Mutex<Rfunc #tg>,
            }

            #[allow(clippy::unused_unit)]
            impl #ig Expectation #tg #wc {
                /// Call this [`Expectation`] as if it were the real method.
                #[doc(hidden)]
                #v fn call #lg (&self, #(#argnames: #argty, )* ) -> #output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    self.common.call(|| std::format!(#desc_fmt, #desc_args));
                    self.rfunc.lock().unwrap().call_mut(#(#argnames, )*)
                        .unwrap_or_else(|message| {
                            let desc = std::format!(
                                "{}", self.common.matcher.lock().unwrap());
                            panic!("{}: Expectation({}) {}", #funcname, desc,
                                   message);
                        })
                }

                /// Return a constant value from the `Expectation`
                ///
                /// The output type must be `Clone`.  The compiler can't always
                /// infer the proper type to use with this method; you will
                /// usually need to specify it explicitly.  i.e.
                /// `return_const(42i32)` instead of `return_const(42)`.
                // We must use Into<#output> instead of #output because where
                // clauses don't accept equality constraints.
                // https://github.com/rust-lang/rust/issues/20041
                #[allow(unused_variables)]
                #v fn return_const<MockallOutput>(&mut self,
                    __mockall_c: MockallOutput)
                    -> &mut Self
                    where MockallOutput: Clone + Into<#output> + ::std::marker::Send + 'static
                {
                    self.returning(move |#(#argnames, )*| __mockall_c.clone().into())
                }

                /// Single-threaded version of
                /// [`return_const`](#method.return_const).  This is useful for
                /// return types that are not `Send`.
                ///
                /// The output type must be `Clone`.  The compiler can't always
                /// infer the proper type to use with this method; you will
                /// usually need to specify it explicitly.  i.e.
                /// `return_const(42i32)` instead of `return_const(42)`.
                ///
                /// It is a runtime error to call the mock method from a
                /// different thread than the one that originally called this
                /// method.
                // We must use Into<#output> instead of #output because where
                // clauses don't accept equality constraints.
                // https://github.com/rust-lang/rust/issues/20041
                #[allow(unused_variables)]
                #v fn return_const_st<MockallOutput>(&mut self,
                    __mockall_c: MockallOutput)
                    -> &mut Self
                    where MockallOutput: Clone + Into<#output> + 'static
                {
                    self.returning_st(move |#(#argnames, )*| __mockall_c.clone().into())
                }

                /// Supply an `FnOnce` closure that will provide the return
                /// value for this Expectation.  This is useful for return types
                /// that aren't `Clone`.  It will be an error to call this
                /// method multiple times.
                #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
                    -> &mut Self
                    where MockallF: #hrtb FnOnce(#(#argty, )*)
                                    -> #output + ::std::marker::Send + 'static
                {
                    {
                        let mut __mockall_guard = self.rfunc.lock().unwrap();
                        *__mockall_guard.deref_mut() =
                            Rfunc::Once(Box::new(__mockall_f));
                    }
                    self
                }

                /// Single-threaded version of
                /// [`return_once`](#method.return_once).  This is useful for
                /// return types that are neither `Send` nor `Clone`.
                ///
                /// It is a runtime error to call the mock method from a
                /// different thread than the one that originally called this
                /// method.  It is also a runtime error to call the method more
                /// than once.
                #v fn return_once_st<MockallF>(&mut self, __mockall_f:
                                                  MockallF) -> &mut Self
                    where MockallF: #hrtb FnOnce(#(#argty, )*)
                                    -> #output + 'static
                {
                    {
                        let mut __mockall_guard = self.rfunc.lock().unwrap();
                        *__mockall_guard.deref_mut() = Rfunc::OnceSt(
                            ::mockall::Fragile::new(Box::new(__mockall_f)));
                    }
                    self
                }

                /// Supply a closure that will provide the return value for this
                /// `Expectation`.  The method's arguments are passed to the
                /// closure by value.
                #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
                    -> &mut Self
                    where MockallF: #hrtb FnMut(#(#argty, )*)
                                    -> #output + ::std::marker::Send + 'static
                {
                    {
                        let mut __mockall_guard = self.rfunc.lock().unwrap();
                        *__mockall_guard.deref_mut() =
                            Rfunc::Mut(Box::new(__mockall_f));
                    }
                    self
                }

                /// Single-threaded version of [`returning`](#method.returning).
                /// Can be used when the argument or return type isn't `Send`.
                ///
                /// It is a runtime error to call the mock method from a
                /// different thread than the one that originally called this
                /// method.
                #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
                    -> &mut Self
                    where MockallF: #hrtb FnMut(#(#argty, )*)
                                    -> #output + 'static
                {
                    {
                        let mut __mockall_guard = self.rfunc.lock().unwrap();
                        *__mockall_guard.deref_mut() = Rfunc::MutSt(
                            ::mockall::Fragile::new(Box::new(__mockall_f)));
                    }
                    self
                }

                #common_methods
            }
            #[allow(single_use_lifetimes)]
            impl #ig Default for Expectation #tg #wc
            {
                fn default() -> Self {
                    Expectation {
                        common: Common::default(),
                        rfunc: Mutex::new(Rfunc::default())
                    }
                }
            }
        ).to_tokens(tokens);
    }
}

/// An collection of RefExpectation's
struct RefExpectations<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefExpectations<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let common_methods = CommonExpectationsMethods{f: self.f};
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        let predexprs = &self.f.predexprs;
        let v = &self.f.privmod_vis;
        let (desc_fmt, desc_args) = self.f.desc();
        let no_match_msg = quote!(
            concat!(#desc_fmt, ": No matching expectation found"), #desc_args);
        quote!(
            #common_methods
            impl #ig Expectations #tg #wc {
                /// Simulate calling the real method.  Every current expectation
                /// will be checked in FIFO order and the first one with
                /// matching arguments will be used.
                #v fn call #lg (&self, #(#argnames: #argty, )* )
                    -> #output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    let __mockall_e = self.0.iter()
                        .find(|__mockall_e|
                              __mockall_e.matches(#(#predexprs, )*) &&
                              (!__mockall_e.is_done() || self.0.len() == 1))
                        .unwrap_or_else(|| panic!(#no_match_msg));
                    __mockall_e.call(#(#argnames),*)
                }

            }
        ).to_tokens(tokens);
    }
}

/// An collection of RefMutExpectation's
struct RefMutExpectations<'a> {
    f: &'a MockFunction
}

impl ToTokens for RefMutExpectations<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let common_methods = CommonExpectationsMethods{f: self.f};
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        let predexprs = &self.f.predexprs;
        let v = &self.f.privmod_vis;
        let (desc_fmt, desc_args) = self.f.desc();
        let no_match_msg = quote!(
            concat!(#desc_fmt, ": No matching expectation found"), #desc_args);
        quote!(
            #common_methods
            impl #ig Expectations #tg #wc {
                /// Simulate calling the real method.  Every current expectation
                /// will be checked in FIFO order and the first one with
                /// matching arguments will be used.
                #v fn call_mut #lg (&mut self, #(#argnames: #argty, )* )
                    -> #output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    let __mockall_n = self.0.len();
                    let __mockall_e = self.0.iter_mut()
                        .find(|__mockall_e|
                              __mockall_e.matches(#(#predexprs, )*) &&
                              (!__mockall_e.is_done() || __mockall_n == 1))
                        .unwrap_or_else(|| panic!(#no_match_msg));
                    __mockall_e.call_mut(#(#argnames, )*)
                }

            }
        ).to_tokens(tokens);
    }
}

/// An collection of Expectation's for methods returning static values
struct StaticExpectations<'a> {
    f: &'a MockFunction
}

impl ToTokens for StaticExpectations<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let common_methods = CommonExpectationsMethods{f: self.f};
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let lg = lifetimes_to_generics(&self.f.alifetimes);
        let output = &self.f.output;
        let predexprs = &self.f.predexprs;
        let v = &self.f.privmod_vis;
        let (desc_fmt, desc_args) = self.f.desc();
        let no_match_msg = quote!(
            concat!(#desc_fmt, ": No matching expectation found"), #desc_args);
        quote!(
            #common_methods
            impl #ig Expectations #tg #wc {
                /// Simulate calling the real method.  Every current expectation
                /// will be checked in FIFO order and the first one with
                /// matching arguments will be used.
                #v fn call #lg (&self, #(#argnames: #argty, )* )
                    -> #output
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    let __mockall_e = self.0.iter()
                        .find(|__mockall_e|
                              __mockall_e.matches(#(#predexprs, )*) &&
                              (!__mockall_e.is_done() || self.0.len() == 1))
                        .unwrap_or_else(|| panic!(#no_match_msg));
                    __mockall_e.call(#(#argnames, )*)
                }

            }
        ).to_tokens(tokens);
    }
}

struct GenericExpectations<'a> {
    f: &'a MockFunction
}

impl ToTokens for GenericExpectations<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if ! self.f.is_expectation_generic() {
            return;
        }
        if ! self.f.is_static() && ! self.f.is_method_generic() {
            return;
        }

        let ge = StaticGenericExpectations{f: self.f};
        let v = &self.f.privmod_vis;
        quote!(
            /// A collection of [`Expectation`](struct.Expectations.html)
            /// objects for a generic method.  Users will rarely if ever use
            /// this struct directly.
            #[doc(hidden)]
            #[derive(Default)]
            #v struct GenericExpectations{
                store: std::collections::hash_map::HashMap<::mockall::Key,
                               Box<dyn ::mockall::AnyExpectations>>
            }
            impl GenericExpectations {
                /// Verify that all current expectations are satisfied and clear
                /// them.  This applies to all sets of generic parameters!
                #v fn checkpoint(&mut self) ->
                    std::collections::hash_map::Drain<::mockall::Key,
                               Box<dyn ::mockall::AnyExpectations>>
                {
                    self.store.drain()
                }

                #v fn new() -> Self {
                    Self::default()
                }
            }
            #ge
        ).to_tokens(tokens);
    }
}

/// Generates methods for GenericExpectations for methods returning static
/// values
struct StaticGenericExpectations<'a> {
    f: &'a MockFunction
}

impl ToTokens for StaticGenericExpectations<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let argnames = &self.f.argnames;
        let argty = &self.f.argty;
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let keyid = gen_keyid(&self.f.egenerics);
        let mut any_wc = wc.cloned();
        if self.f.return_ref || self.f.return_refmut {
            // Add Senc + Sync, required for downcast, since Expectation
            // stores an Option<#owned_output>
            send_syncify(&mut any_wc, self.f.owned_output.clone());
        }
        let tbf = tg.as_turbofish();
        let output = &self.f.output;
        let v = &self.f.privmod_vis;
        let (call, get, self_, downcast) = if self.f.return_refmut {
            (format_ident!("call_mut"),
             format_ident!("get_mut"),
             quote!(&mut self),
             format_ident!("downcast_mut"))
        } else {
            (format_ident!("call"),
             format_ident!("get"),
             quote!(&self),
             format_ident!("downcast_ref"))
        };
        let (desc_fmt, desc_args) = self.f.desc();
        let no_match_msg = quote!(
            concat!(#desc_fmt, ": No matching expectation found"), #desc_args);
        quote!(
            impl #ig ::mockall::AnyExpectations for Expectations #tg #any_wc {}
            impl GenericExpectations {
                /// Simulating calling the real method.
                #v fn #call #ig (#self_, #(#argnames: #argty, )* )
                    -> #output #wc
                {
                    use ::mockall::{ViaDebug, ViaNothing};
                    let __mockall_e = self.store.#get(&::mockall::Key::new::#keyid())
                        .unwrap_or_else(|| panic!(#no_match_msg));
                    __mockall_e.#downcast::<Expectations #tg>()
                    .unwrap()
                    .#call(#(#argnames, )*)
                }

                /// Create a new Expectation.
                #v fn expect #ig (&mut self) -> &mut Expectation #tg #any_wc
                {
                    self.store.entry(::mockall::Key::new::#keyid())
                        .or_insert_with(|| Box::new(Expectations #tbf::new()))
                        .downcast_mut::<Expectations #tg>()
                        .unwrap()
                        .expect()
                }
            }
        ).to_tokens(tokens)
    }
}

