[vm] Fix equality of closures instantiated from the same closure

TEST=co19/LanguageFeatures/Constructor-tear-offs/equality_A03_t01
TEST=co19/LanguageFeatures/Constructor-tear-offs/equality_A03_t02
TEST=co19/LanguageFeatures/Constructor-tear-offs/equality_A03_t04

Fixes https://github.com/dart-lang/sdk/issues/47317

Change-Id: I380cbabe5406f1a8cd5ccf180eb392f36f77f164
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215620
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 77800d4..908fc31 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -40,22 +40,22 @@
     return false;
   }
   const auto& other_closure = Closure::Cast(other);
-  // Closures that are not implicit closures (tear-offs) are unique.
   const auto& func_a = Function::Handle(zone, receiver.function());
-  if (!func_a.IsImplicitClosureFunction()) {
-    return false;
-  }
   const auto& func_b = Function::Handle(zone, other_closure.function());
-  if (!func_b.IsImplicitClosureFunction()) {
-    return false;
-  }
-  // If the closure functions are not the same, check the function's name and
-  // owner, as multiple function objects could exist for the same function due
-  // to hot reload.
-  if (func_a.ptr() != func_b.ptr() &&
-      (func_a.name() != func_b.name() || func_a.Owner() != func_b.Owner() ||
-       func_a.is_static() != func_b.is_static())) {
-    return false;
+  // Check that functions match.
+  if (func_a.ptr() != func_b.ptr()) {
+    // Closure functions that are not implicit closures (tear-offs) are unique.
+    if (!func_a.IsImplicitClosureFunction() ||
+        !func_b.IsImplicitClosureFunction()) {
+      return false;
+    }
+    // If the closure functions are not the same, check the function's name and
+    // owner, as multiple function objects could exist for the same function due
+    // to hot reload.
+    if ((func_a.name() != func_b.name() || func_a.Owner() != func_b.Owner() ||
+         func_a.is_static() != func_b.is_static())) {
+      return false;
+    }
   }
   // Check that the delayed type argument vectors match.
   if (receiver.delayed_type_arguments() !=
@@ -72,11 +72,25 @@
       return false;
     }
   }
-  if (!func_a.is_static()) {
-    // Check that the both receiver instances are the same.
-    const Context& context_a = Context::Handle(zone, receiver.context());
-    const Context& context_b = Context::Handle(zone, other_closure.context());
-    return context_a.At(0) == context_b.At(0);
+  if (func_a.IsImplicitClosureFunction() &&
+      func_b.IsImplicitClosureFunction()) {
+    if (!func_a.is_static()) {
+      // Check that the both receiver instances are the same.
+      const Context& context_a = Context::Handle(zone, receiver.context());
+      const Context& context_b = Context::Handle(zone, other_closure.context());
+      return context_a.At(0) == context_b.At(0);
+    }
+  } else {
+    // Non-identical closures which are not tear-offs can be equal only if
+    // they are different instantiations of the same generic closure.
+    if (!func_a.IsGeneric() || receiver.IsGeneric() ||
+        (receiver.context() != other_closure.context()) ||
+        (receiver.instantiator_type_arguments() !=
+         other_closure.instantiator_type_arguments()) ||
+        (receiver.function_type_arguments() !=
+         other_closure.function_type_arguments())) {
+      return false;
+    }
   }
   return true;
 }