Переглянути джерело

Fix equality for tuples (#446)

* fix tuple equality, added test cases

* added a comment to an old function

* Update executable_semantics/interpreter/value.cpp

Co-authored-by: Geoff Romer <gromer@google.com>

* fix error in Geoffrey's edit

Co-authored-by: Geoff Romer <gromer@google.com>
Jeremy G. Siek 5 роки тому
батько
коміт
c1d651fc15

+ 3 - 0
executable_semantics/BUILD

@@ -62,6 +62,9 @@ EXAMPLES = [
     "struct2",
     "struct2",
     "struct3",
     "struct3",
     "tuple_assign",
     "tuple_assign",
+    "tuple_equality",
+    "tuple_equality2",
+    "tuple_equality3",
     "tuple_match",
     "tuple_match",
     "tuple1",
     "tuple1",
     "tuple2",
     "tuple2",

+ 1 - 2
executable_semantics/interpreter/typecheck.cpp

@@ -288,8 +288,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
           ExpectType(e->line_num, "!", MakeBoolTypeVal(), ts[0]);
           ExpectType(e->line_num, "!", MakeBoolTypeVal(), ts[0]);
           return TCResult(new_e, MakeBoolTypeVal(), new_types);
           return TCResult(new_e, MakeBoolTypeVal(), new_types);
         case Operator::Eq:
         case Operator::Eq:
-          ExpectType(e->line_num, "==(1)", MakeIntTypeVal(), ts[0]);
-          ExpectType(e->line_num, "==(2)", MakeIntTypeVal(), ts[1]);
+          ExpectType(e->line_num, "==", ts[0], ts[1]);
           return TCResult(new_e, MakeBoolTypeVal(), new_types);
           return TCResult(new_e, MakeBoolTypeVal(), new_types);
       }
       }
       break;
       break;

+ 29 - 1
executable_semantics/interpreter/value.cpp

@@ -4,6 +4,7 @@
 
 
 #include "executable_semantics/interpreter/value.h"
 #include "executable_semantics/interpreter/value.h"
 
 
+#include <algorithm>
 #include <cassert>
 #include <cassert>
 #include <iostream>
 #include <iostream>
 
 
@@ -360,6 +361,31 @@ auto TypeEqual(const Value* t1, const Value* t2) -> bool {
   }
   }
 }
 }
 
 
+// Returns true if all the fields of the two tuples contain equal values
+// and returns false otherwise.
+static auto FieldsValueEqual(VarAddresses* ts1, VarAddresses* ts2, int line_num)
+    -> bool {
+  if (ts1->size() != ts2->size()) {
+    return false;
+  }
+  for (const auto& [name, address] : *ts1) {
+    auto iter =
+        std::find_if(ts2->begin(), ts2->end(),
+                     [name = name](const auto& p) { return p.first == name; });
+    if (iter == ts2->end()) {
+      return false;
+    }
+    if (!ValueEqual(state->heap[address], state->heap[iter->second],
+                    line_num)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Returns true if the two values are equal and returns false otherwise.
+//
+// This function implements the `==` operator of Carbon.
 auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
 auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
   if (v1->tag != v2->tag) {
   if (v1->tag != v2->tag) {
     return false;
     return false;
@@ -373,6 +399,9 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
       return v1->u.ptr == v2->u.ptr;
       return v1->u.ptr == v2->u.ptr;
     case ValKind::FunV:
     case ValKind::FunV:
       return v1->u.fun.body == v2->u.fun.body;
       return v1->u.fun.body == v2->u.fun.body;
+    case ValKind::TupleV:
+      return FieldsValueEqual(v1->u.tuple.elts, v2->u.tuple.elts, line_num);
+    default:
     case ValKind::VarTV:
     case ValKind::VarTV:
     case ValKind::IntTV:
     case ValKind::IntTV:
     case ValKind::BoolTV:
     case ValKind::BoolTV:
@@ -384,7 +413,6 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
     case ValKind::ChoiceTV:
     case ValKind::ChoiceTV:
     case ValKind::ContinuationTV:
     case ValKind::ContinuationTV:
       return TypeEqual(v1, v2);
       return TypeEqual(v1, v2);
-    case ValKind::TupleV:
     case ValKind::StructV:
     case ValKind::StructV:
     case ValKind::AltV:
     case ValKind::AltV:
     case ValKind::VarPatV:
     case ValKind::VarPatV:

+ 2 - 1
executable_semantics/interpreter/value.h

@@ -17,6 +17,7 @@ namespace Carbon {
 struct Value;
 struct Value;
 using Address = unsigned int;
 using Address = unsigned int;
 using VarValues = std::list<std::pair<std::string, const Value*>>;
 using VarValues = std::list<std::pair<std::string, const Value*>>;
+using VarAddresses = std::vector<std::pair<std::string, Address>>;
 
 
 auto FindInVarValues(const std::string& field, VarValues* inits)
 auto FindInVarValues(const std::string& field, VarValues* inits)
     -> const Value*;
     -> const Value*;
@@ -81,7 +82,7 @@ struct Value {
     } alt;
     } alt;
 
 
     struct {
     struct {
-      std::vector<std::pair<std::string, Address>>* elts;
+      VarAddresses* elts;
     } tuple;
     } tuple;
 
 
     Address ptr;
     Address ptr;

+ 13 - 0
executable_semantics/testdata/tuple_equality.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (Int,Int): t1 = (5, 2);
+  var (Int,Int): t2 = (5, 2);
+  if (t1 == t2) {
+    return 0;
+  } else {
+    return 1;
+  }
+}

+ 1 - 0
executable_semantics/testdata/tuple_equality.golden

@@ -0,0 +1 @@
+result: 0

+ 13 - 0
executable_semantics/testdata/tuple_equality2.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (Int,Int): t1 = (5, 2);
+  var (Int,Int): t2 = (5, 4);
+  if (t1 == t2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}

+ 1 - 0
executable_semantics/testdata/tuple_equality2.golden

@@ -0,0 +1 @@
+result: 0

+ 13 - 0
executable_semantics/testdata/tuple_equality3.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (Int,Int): t1 = (5, 2);
+  var (Int,Int): t2 = (5,);
+  if (t1 == t2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}

+ 1 - 0
executable_semantics/testdata/tuple_equality3.golden

@@ -0,0 +1 @@
+result: 0