+ });
+ }
+ );
+ }
+}
+
+/// Tries to determine the type for universal function call to be used instead of the closure
+fn get_ufcs_type_name(
+ cx: &LateContext<'_, '_>,
+ method_def_id: def_id::DefId,
+ self_arg: &Expr,
+) -> std::option::Option<String> {
+ let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0].sty;
+ let actual_type_of_self = &cx.tables.node_id_to_type(self_arg.hir_id).sty;
+
+ if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
+ //if the method expectes &self, ufcs requires explicit borrowing so closure can't be removed
+ return match (expected_type_of_self, actual_type_of_self) {
+ (ty::Ref(_, _, _), ty::Ref(_, _, _)) => Some(cx.tcx.item_path_str(trait_id)),
+ (l, r) => match (l, r) {
+ (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => None,
+ (_, _) => Some(cx.tcx.item_path_str(trait_id)),
+ },
+ };
+ }
+
+ cx.tcx.impl_of_method(method_def_id).and_then(|_| {
+ //a type may implicitly implement other types methods (e.g. Deref)
+ if match_types(expected_type_of_self, actual_type_of_self) {
+ return Some(get_type_name(cx, &actual_type_of_self));
+ }
+ None
+ })
+}
+
+fn match_types(lhs: &ty::TyKind<'_>, rhs: &ty::TyKind<'_>) -> bool {
+ match (lhs, rhs) {
+ (ty::Bool, ty::Bool)
+ | (ty::Char, ty::Char)
+ | (ty::Int(_), ty::Int(_))
+ | (ty::Uint(_), ty::Uint(_))
+ | (ty::Str, ty::Str) => true,
+ (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
+ | (ty::Array(t1, _), ty::Array(t2, _))
+ | (ty::Slice(t1), ty::Slice(t2)) => match_types(&t1.sty, &t2.sty),
+ (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
+ (_, _) => false,
+ }
+}
+
+fn get_type_name(cx: &LateContext<'_, '_>, kind: &ty::TyKind<'_>) -> String {
+ match kind {
+ ty::Adt(t, _) => cx.tcx.item_path_str(t.did),
+ ty::Ref(_, r, _) => get_type_name(cx, &r.sty),
+ _ => kind.to_string(),
+ }
+}
+
+fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
+ for (closure_input, function_arg) in closure_inputs.zip(call_args) {
+ if let PatKind::Binding(_, _, _, ident, _) = closure_input.pat.node {
+ // XXXManishearth Should I be checking the binding mode here?
+ if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
+ if p.segments.len() != 1 {
+ // If it's a proper path, it can't be a local variable
+ return false;