From c1d651fc153f400e22ab9abff1753e31a4eef2d3 Mon Sep 17 00:00:00 2001 From: "Jeremy G. Siek" Date: Wed, 21 Apr 2021 17:12:10 -0400 Subject: [PATCH] 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 * fix error in Geoffrey's edit Co-authored-by: Geoff Romer --- executable_semantics/BUILD | 3 ++ .../interpreter/typecheck.cpp | 3 +- executable_semantics/interpreter/value.cpp | 30 ++++++++++++++++++- executable_semantics/interpreter/value.h | 3 +- .../testdata/tuple_equality.6c | 13 ++++++++ .../testdata/tuple_equality.golden | 1 + .../testdata/tuple_equality2.6c | 13 ++++++++ .../testdata/tuple_equality2.golden | 1 + .../testdata/tuple_equality3.6c | 13 ++++++++ .../testdata/tuple_equality3.golden | 1 + 10 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 executable_semantics/testdata/tuple_equality.6c create mode 100644 executable_semantics/testdata/tuple_equality.golden create mode 100644 executable_semantics/testdata/tuple_equality2.6c create mode 100644 executable_semantics/testdata/tuple_equality2.golden create mode 100644 executable_semantics/testdata/tuple_equality3.6c create mode 100644 executable_semantics/testdata/tuple_equality3.golden diff --git a/executable_semantics/BUILD b/executable_semantics/BUILD index d8f0fd8b2ed2..e099060e5ec8 100644 --- a/executable_semantics/BUILD +++ b/executable_semantics/BUILD @@ -62,6 +62,9 @@ EXAMPLES = [ "struct2", "struct3", "tuple_assign", + "tuple_equality", + "tuple_equality2", + "tuple_equality3", "tuple_match", "tuple1", "tuple2", diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 0350a9827d57..763d1c76a336 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/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]); return TCResult(new_e, MakeBoolTypeVal(), new_types); 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); } break; diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 15df99a8fe97..f915293dd4f6 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -4,6 +4,7 @@ #include "executable_semantics/interpreter/value.h" +#include #include #include @@ -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 { if (v1->tag != v2->tag) { 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; case ValKind::FunV: 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::IntTV: case ValKind::BoolTV: @@ -384,7 +413,6 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool { case ValKind::ChoiceTV: case ValKind::ContinuationTV: return TypeEqual(v1, v2); - case ValKind::TupleV: case ValKind::StructV: case ValKind::AltV: case ValKind::VarPatV: diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index 13f4c3432bab..f6d41bf9cfdc 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -17,6 +17,7 @@ namespace Carbon { struct Value; using Address = unsigned int; using VarValues = std::list>; +using VarAddresses = std::vector>; auto FindInVarValues(const std::string& field, VarValues* inits) -> const Value*; @@ -81,7 +82,7 @@ struct Value { } alt; struct { - std::vector>* elts; + VarAddresses* elts; } tuple; Address ptr; diff --git a/executable_semantics/testdata/tuple_equality.6c b/executable_semantics/testdata/tuple_equality.6c new file mode 100644 index 000000000000..c8e421ed5c0c --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/tuple_equality.golden b/executable_semantics/testdata/tuple_equality.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/tuple_equality.golden @@ -0,0 +1 @@ +result: 0 diff --git a/executable_semantics/testdata/tuple_equality2.6c b/executable_semantics/testdata/tuple_equality2.6c new file mode 100644 index 000000000000..88059622ef3e --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/tuple_equality2.golden b/executable_semantics/testdata/tuple_equality2.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/tuple_equality2.golden @@ -0,0 +1 @@ +result: 0 diff --git a/executable_semantics/testdata/tuple_equality3.6c b/executable_semantics/testdata/tuple_equality3.6c new file mode 100644 index 000000000000..b958b18d81c6 --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/tuple_equality3.golden b/executable_semantics/testdata/tuple_equality3.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/tuple_equality3.golden @@ -0,0 +1 @@ +result: 0