diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 3b12394b2e27..bd469a73a447 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -143,8 +143,7 @@ auto MakeGetField(int line_num, const Expression* exp, std::string field) return e; } -auto MakeTuple(int line_num, - std::vector>* args) +auto MakeTuple(int line_num, std::vector* args) -> const Expression* { auto* e = new Expression(); e->line_num = line_num; @@ -152,14 +151,14 @@ auto MakeTuple(int line_num, int i = 0; bool seen_named_member = false; for (auto& arg : *args) { - if (arg.first == "") { + if (arg.name == "") { if (seen_named_member) { std::cerr << line_num << ": positional members must come before named members" << std::endl; exit(-1); } - arg.first = std::to_string(i); + arg.name = std::to_string(i); ++i; } else { seen_named_member = true; @@ -176,7 +175,7 @@ auto MakeUnit(int line_num) -> const Expression* { auto* unit = new Expression(); unit->line_num = line_num; unit->tag = ExpressionKind::Tuple; - auto* args = new std::vector>(); + auto* args = new std::vector(); unit->u.tuple.fields = args; return unit; } @@ -217,15 +216,14 @@ static void PrintOp(Operator op) { } } -static void PrintFields( - std::vector>* fields) { +static void PrintFields(std::vector* fields) { int i = 0; for (auto iter = fields->begin(); iter != fields->end(); ++iter, ++i) { if (i != 0) { std::cout << ", "; } - std::cout << iter->first << " = "; - PrintExp(iter->second); + std::cout << iter->name << " = "; + PrintExp(iter->expression); } } diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index d9778ec0cafc..18e2e34bbd4c 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -10,6 +10,17 @@ namespace Carbon { +struct Expression; + +// A FieldInitializer represents the initialization of a single tuple field. +struct FieldInitializer { + // The field name. For a positional field, this may be empty. + std::string name; + + // The expression that initializes the field. + const Expression* expression; +}; + enum class ExpressionKind { AutoT, BoolT, @@ -65,7 +76,7 @@ struct Expression { bool boolean; struct { - std::vector>* fields; + std::vector* fields; } tuple; struct { @@ -101,8 +112,7 @@ auto MakeCall(int line_num, const Expression* fun, const Expression* arg) -> const Expression*; auto MakeGetField(int line_num, const Expression* exp, std::string field) -> const Expression*; -auto MakeTuple(int line_num, - std::vector>* args) +auto MakeTuple(int line_num, std::vector* args) -> const Expression*; // Create an AST node for an empty tuple. auto MakeUnit(int line_num) -> const Expression*; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 87f712eeb7bf..a721bd3647ee 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -66,14 +66,14 @@ void Heap::CheckAlive(Address address, int line_num) { auto CopyVal(const Value* val, int line_num) -> const Value* { switch (val->tag) { case ValKind::TupleV: { - auto elts = new std::vector>(); - for (auto& i : *val->u.tuple.elts) { - const Value* elt = - CopyVal(state->heap.Read(i.second, line_num), line_num); - Address new_address = state->heap.AllocateValue(elt); - elts->push_back(make_pair(i.first, new_address)); + auto* elements = new std::vector(); + for (const TupleElement& element : *val->u.tuple.elements) { + const Value* new_element = + CopyVal(state->heap.Read(element.address, line_num), line_num); + Address new_address = state->heap.AllocateValue(new_element); + elements->push_back({.name = element.name, .address = new_address}); } - return MakeTupleVal(elts); + return MakeTupleVal(elements); } case ValKind::AltV: { const Value* arg = @@ -133,8 +133,8 @@ void Heap::DeallocateSubObjects(const Value* val) { DeallocateSubObjects(val->u.struct_val.inits); break; case ValKind::TupleV: - for (auto& elt : *val->u.tuple.elts) { - Deallocate(elt.second); + for (const TupleElement& element : *val->u.tuple.elements) { + Deallocate(element.address); } break; default: @@ -411,13 +411,13 @@ void DeallocateLocals(int line_num, Frame* frame) { void CreateTuple(Frame* frame, Action* act, const Expression* /*exp*/) { // { { (v1,...,vn) :: C, E, F} :: S, H} // -> { { `(v1,...,vn) :: C, E, F} :: S, H} - auto elts = new std::vector>(); + auto elements = new std::vector(); auto f = act->u.exp->u.tuple.fields->begin(); for (auto i = act->results.begin(); i != act->results.end(); ++i, ++f) { Address a = state->heap.AllocateValue(*i); // copy? - elts->push_back(make_pair(f->first, a)); + elements->push_back({.name = f->name, .address = a}); } - const Value* tv = MakeTupleVal(elts); + const Value* tv = MakeTupleVal(elements); frame->todo.Pop(1); frame->todo.Push(MakeValAct(tv)); } @@ -440,21 +440,21 @@ auto PatternMatch(const Value* p, const Value* v, Env values, case ValKind::TupleV: switch (v->tag) { case ValKind::TupleV: { - if (p->u.tuple.elts->size() != v->u.tuple.elts->size()) { + if (p->u.tuple.elements->size() != v->u.tuple.elements->size()) { std::cerr << "runtime error: arity mismatch in tuple pattern match" << std::endl; exit(-1); } - for (auto& elt : *p->u.tuple.elts) { - auto a = FindTupleField(elt.first, v); + for (const TupleElement& element : *p->u.tuple.elements) { + auto a = FindTupleField(element.name, v); if (a == std::nullopt) { - std::cerr << "runtime error: field " << elt.first << "not in "; + std::cerr << "runtime error: field " << element.name << "not in "; PrintValue(v, std::cerr); std::cerr << std::endl; exit(-1); } std::optional matches = PatternMatch( - state->heap.Read(elt.second, line_num), + state->heap.Read(element.address, line_num), state->heap.Read(*a, line_num), values, vars, line_num); if (!matches) { return std::nullopt; @@ -526,20 +526,20 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) { case ValKind::TupleV: { switch (val->tag) { case ValKind::TupleV: { - if (pat->u.tuple.elts->size() != val->u.tuple.elts->size()) { + if (pat->u.tuple.elements->size() != val->u.tuple.elements->size()) { std::cerr << "runtime error: arity mismatch in tuple pattern match" << std::endl; exit(-1); } - for (auto& elt : *pat->u.tuple.elts) { - auto a = FindTupleField(elt.first, val); + for (const TupleElement& element : *pat->u.tuple.elements) { + auto a = FindTupleField(element.name, val); if (a == std::nullopt) { - std::cerr << "runtime error: field " << elt.first << "not in "; + std::cerr << "runtime error: field " << element.name << "not in "; PrintValue(val, std::cerr); std::cerr << std::endl; exit(-1); } - PatternAssignment(state->heap.Read(elt.second, line_num), + PatternAssignment(state->heap.Read(element.address, line_num), state->heap.Read(*a, line_num), line_num); } break; @@ -629,7 +629,7 @@ void StepLvalue() { case ExpressionKind::Tuple: { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} - const Expression* e1 = (*exp->u.tuple.fields)[0].second; + const Expression* e1 = (*exp->u.tuple.fields)[0].expression; frame->todo.Push(MakeLvalAct(e1)); act->pos++; break; @@ -680,7 +680,7 @@ void StepExp() { if (exp->u.tuple.fields->size() > 0) { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} - const Expression* e1 = (*exp->u.tuple.fields)[0].second; + const Expression* e1 = (*exp->u.tuple.fields)[0].expression; frame->todo.Push(MakeExpAct(e1)); act->pos++; } else { @@ -1090,7 +1090,7 @@ void HandleValue() { // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} - const Expression* elt = (*exp->u.tuple.fields)[act->pos].second; + const Expression* elt = (*exp->u.tuple.fields)[act->pos].expression; frame->todo.Pop(1); frame->todo.Push(MakeLvalAct(elt)); } else { @@ -1122,7 +1122,7 @@ void HandleValue() { // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} - const Expression* elt = (*exp->u.tuple.fields)[act->pos].second; + const Expression* elt = (*exp->u.tuple.fields)[act->pos].expression; frame->todo.Pop(1); frame->todo.Push(MakeExpAct(elt)); } else { @@ -1467,8 +1467,7 @@ auto InterpProgram(std::list* fs) -> int { } InitGlobals(fs); - const Expression* arg = MakeTuple( - 0, new std::vector>()); + const Expression* arg = MakeTuple(0, new std::vector()); const Expression* call_main = MakeCall(0, MakeVar(0, "main"), arg); auto todo = Stack(MakeExpAct(call_main)); auto* scope = new Scope(globals, std::list()); diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 2cdfceef4a63..2463fd05efb6 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -57,11 +57,12 @@ auto ReifyType(const Value* t, int line_num) -> const Expression* { return MakeFunType(0, ReifyType(t->u.fun_type.param, line_num), ReifyType(t->u.fun_type.ret, line_num)); case ValKind::TupleV: { - auto args = new std::vector>(); - for (auto& field : *t->u.tuple.elts) { + auto args = new std::vector(); + for (const TupleElement& field : *t->u.tuple.elements) { args->push_back( - {field.first, - ReifyType(state->heap.Read(field.second, line_num), line_num)}); + {.name = field.name, + .expression = ReifyType(state->heap.Read(field.address, line_num), + line_num)}); } return MakeTuple(0, args); } @@ -172,9 +173,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values, } } case ExpressionKind::Tuple: { - auto new_args = - new std::vector>(); - auto arg_types = new std::vector>(); + auto new_args = new std::vector(); + auto arg_types = new std::vector(); auto new_types = types; if (expected && expected->tag != ValKind::TupleV) { std::cerr << e->line_num << ": compilation error, didn't expect a tuple" @@ -182,7 +182,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values, exit(-1); } if (expected && - e->u.tuple.fields->size() != expected->u.tuple.elts->size()) { + e->u.tuple.fields->size() != expected->u.tuple.elements->size()) { std::cerr << e->line_num << ": compilation error, tuples of different length" << std::endl; @@ -193,22 +193,23 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values, arg != e->u.tuple.fields->end(); ++arg, ++i) { const Value* arg_expected = nullptr; if (expected && expected->tag == ValKind::TupleV) { - if ((*expected->u.tuple.elts)[i].first != arg->first) { + if ((*expected->u.tuple.elements)[i].name != arg->name) { std::cerr << e->line_num << ": compilation error, field names do not match, " - << "expected " << (*expected->u.tuple.elts)[i].first - << " but got " << arg->first << std::endl; + << "expected " << (*expected->u.tuple.elements)[i].name + << " but got " << arg->name << std::endl; exit(-1); } - arg_expected = state->heap.Read((*expected->u.tuple.elts)[i].second, - e->line_num); + arg_expected = state->heap.Read( + (*expected->u.tuple.elements)[i].address, e->line_num); } - auto arg_res = - TypeCheckExp(arg->second, new_types, values, arg_expected, context); + auto arg_res = TypeCheckExp(arg->expression, new_types, values, + arg_expected, context); new_types = arg_res.types; - new_args->push_back(std::make_pair(arg->first, arg_res.exp)); + new_args->push_back({.name = arg->name, .expression = arg_res.exp}); arg_types->push_back( - {arg->first, state->heap.AllocateValue(arg_res.type)}); + {.name = arg->name, + .address = state->heap.AllocateValue(arg_res.type)}); } auto tuple_e = MakeTuple(e->line_num, new_args); auto tuple_t = MakeTupleVal(arg_types); @@ -241,12 +242,12 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values, << *e->u.get_field.field << std::endl; exit(-1); case ValKind::TupleV: - for (auto& field : *t->u.tuple.elts) { - if (*e->u.get_field.field == field.first) { + for (const TupleElement& field : *t->u.tuple.elements) { + if (*e->u.get_field.field == field.name) { auto new_e = MakeGetField(e->line_num, res.exp, *e->u.get_field.field); return TCResult(new_e, - state->heap.Read(field.second, e->line_num), + state->heap.Read(field.address, e->line_num), res.types); } } @@ -534,8 +535,7 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num) -> const Statement* { if (!stmt) { if (void_return) { - auto args = new std::vector>(); - return MakeReturn(line_num, MakeTuple(line_num, args)); + return MakeReturn(line_num, MakeUnit(line_num)); } else { std::cerr << "control-flow reaches end of non-void function without a return" @@ -586,11 +586,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num) case StatementKind::Continue: case StatementKind::VariableDefinition: if (void_return) { - auto args = - new std::vector>(); - return MakeSeq( - stmt->line_num, stmt, - MakeReturn(stmt->line_num, MakeTuple(stmt->line_num, args))); + return MakeSeq(stmt->line_num, stmt, + MakeReturn(stmt->line_num, MakeUnit(stmt->line_num))); } else { std::cerr << stmt->line_num @@ -718,10 +715,10 @@ auto StructDeclaration::TopLevel(TypeCheckContext& tops) const -> void { auto st = TypeOfStructDef(&definition, tops.types, tops.values); Address a = state->heap.AllocateValue(st); tops.values.Set(Name(), a); // Is this obsolete? - auto field_types = new std::vector>(); + auto field_types = new std::vector(); for (const auto& [field_name, field_value] : *st->u.struct_type.fields) { - field_types->push_back( - {field_name, state->heap.AllocateValue(field_value)}); + field_types->push_back({.name = field_name, + .address = state->heap.AllocateValue(field_value)}); } auto fun_ty = MakeFunTypeVal(MakeTupleVal(field_types), st); tops.types.Set(Name(), fun_ty); diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index b571dfa8373e..03fa2ae29896 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -42,9 +42,9 @@ auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool { auto FindTupleField(const std::string& name, const Value* tuple) -> std::optional
{ assert(tuple->tag == ValKind::TupleV); - for (const auto& i : *tuple->u.tuple.elts) { - if (i.first == name) { - return i.second; + for (const TupleElement& element : *tuple->u.tuple.elements) { + if (element.name == name) { + return element.address; } } return std::nullopt; @@ -89,11 +89,10 @@ auto MakeStructVal(const Value* type, const Value* inits) -> const Value* { return v; } -auto MakeTupleVal(std::vector>* elts) - -> const Value* { +auto MakeTupleVal(std::vector* elements) -> const Value* { auto* v = new Value(); v->tag = ValKind::TupleV; - v->u.tuple.elts = elts; + v->u.tuple.elements = elements; return v; } @@ -199,7 +198,7 @@ auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods) auto MakeVoidTypeVal() -> const Value* { auto* v = new Value(); v->tag = ValKind::TupleV; - v->u.tuple.elts = new std::vector>(); + v->u.tuple.elements = new std::vector(); return v; } @@ -239,16 +238,16 @@ auto PrintValue(const Value* val, std::ostream& out) -> void { case ValKind::TupleV: { out << "("; bool add_commas = false; - for (const auto& elt : *val->u.tuple.elts) { + for (const TupleElement& element : *val->u.tuple.elements) { if (add_commas) { out << ", "; } else { add_commas = true; } - out << elt.first << " = "; - state->heap.PrintAddress(elt.second, out); - out << "@" << elt.second; + out << element.name << " = "; + state->heap.PrintAddress(element.address, out); + out << "@" << element.address; } out << ")"; break; @@ -328,15 +327,17 @@ auto TypeEqual(const Value* t1, const Value* t2) -> bool { case ValKind::ChoiceTV: return *t1->u.choice_type.name == *t2->u.choice_type.name; case ValKind::TupleV: { - if (t1->u.tuple.elts->size() != t2->u.tuple.elts->size()) { + if (t1->u.tuple.elements->size() != t2->u.tuple.elements->size()) { return false; } - for (size_t i = 0; i < t1->u.tuple.elts->size(); ++i) { - if ((*t1->u.tuple.elts)[i].first != (*t2->u.tuple.elts)[i].first) { + for (size_t i = 0; i < t1->u.tuple.elements->size(); ++i) { + if ((*t1->u.tuple.elements)[i].name != + (*t2->u.tuple.elements)[i].name) { return false; } - if (!TypeEqual(state->heap.Read((*t1->u.tuple.elts)[i].second, 0), - state->heap.Read((*t2->u.tuple.elts)[i].second, 0))) { + if (!TypeEqual( + state->heap.Read((*t1->u.tuple.elements)[i].address, 0), + state->heap.Read((*t2->u.tuple.elements)[i].address, 0))) { return false; } } @@ -358,20 +359,21 @@ 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) +static auto FieldsValueEqual(std::vector* ts1, + std::vector* 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; }); + for (const TupleElement& element : *ts1) { + auto iter = std::find_if( + ts2->begin(), ts2->end(), + [&](const TupleElement& e2) { return e2.name == element.name; }); if (iter == ts2->end()) { return false; } - if (!ValueEqual(state->heap.Read(address, line_num), - state->heap.Read(iter->second, line_num), line_num)) { + if (!ValueEqual(state->heap.Read(element.address, line_num), + state->heap.Read(iter->address, line_num), line_num)) { return false; } } @@ -395,7 +397,8 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool { 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); + return FieldsValueEqual(v1->u.tuple.elements, v2->u.tuple.elements, + line_num); default: case ValKind::VarTV: case ValKind::IntTV: diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index f6d41bf9cfdc..482fc1999454 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -17,7 +17,6 @@ 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*; @@ -28,6 +27,15 @@ auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool; auto FindTupleField(const std::string& name, const Value* tuple) -> std::optional
; +// A TupleElement represents the value of a single tuple field. +struct TupleElement { + // The field name. + std::string name; + + // Location of the field's value. + Address address; +}; + enum class ValKind { IntV, FunV, @@ -82,7 +90,7 @@ struct Value { } alt; struct { - VarAddresses* elts; + std::vector* elements; } tuple; Address ptr; @@ -134,8 +142,7 @@ auto MakeFunVal(std::string name, const Value* param, const Statement* body) -> const Value*; auto MakePtrVal(Address addr) -> const Value*; auto MakeStructVal(const Value* type, const Value* inits) -> const Value*; -auto MakeTupleVal(std::vector>* elts) - -> const Value*; +auto MakeTupleVal(std::vector* elts) -> const Value*; auto MakeAltVal(std::string alt_name, std::string choice_name, Address argument) -> const Value*; auto MakeAltCons(std::string alt_name, std::string choice_name) -> const Value*; diff --git a/executable_semantics/syntax/paren_contents.cpp b/executable_semantics/syntax/paren_contents.cpp index 080b6c6bb0f9..bb494931e46e 100644 --- a/executable_semantics/syntax/paren_contents.cpp +++ b/executable_semantics/syntax/paren_contents.cpp @@ -16,12 +16,7 @@ const Expression* ParenContents::AsExpression(int line_number) const { } const Expression* ParenContents::AsTuple(int line_number) const { - auto vec = - new std::vector>(); - for (const FieldInitializer& initializer : fields_) { - vec->push_back({initializer.name, initializer.expression}); - } - return MakeTuple(line_number, vec); + return MakeTuple(line_number, new std::vector(fields_)); } } // namespace Carbon diff --git a/executable_semantics/syntax/paren_contents.h b/executable_semantics/syntax/paren_contents.h index f222ecdb836d..8fed4d1508a0 100644 --- a/executable_semantics/syntax/paren_contents.h +++ b/executable_semantics/syntax/paren_contents.h @@ -11,16 +11,6 @@ namespace Carbon { -// A FieldInitializer represents the initialization of a single tuple field. -struct FieldInitializer { - // The field name. An empty string indicates that this represents a - // positional field. - std::string name; - - // The expression that initializes the field. - const Expression* expression; -}; - // Represents the syntactic contents of an expression delimited by // parentheses. Such expressions can be interpreted as either tuples or // arbitrary expressions, depending on their context and the syntax of their diff --git a/executable_semantics/syntax/paren_contents_test.cpp b/executable_semantics/syntax/paren_contents_test.cpp index cec4b6e467bb..f22636eb8b84 100644 --- a/executable_semantics/syntax/paren_contents_test.cpp +++ b/executable_semantics/syntax/paren_contents_test.cpp @@ -47,10 +47,9 @@ TEST(ParenContentsTest, UnaryNoCommaAsTuple) { const Expression* tuple = contents.AsTuple(/*line_num=*/1); EXPECT_EQ(tuple->line_num, 1); ASSERT_EQ(tuple->tag, ExpressionKind::Tuple); - std::vector> fields = - *tuple->u.tuple.fields; + std::vector fields = *tuple->u.tuple.fields; ASSERT_EQ(fields.size(), 1); - EXPECT_EQ(fields[0].second->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[0].expression->tag, ExpressionKind::Integer); } TEST(ParenContentsTest, UnaryWithCommaAsExpression) { @@ -60,10 +59,9 @@ TEST(ParenContentsTest, UnaryWithCommaAsExpression) { const Expression* expression = contents.AsExpression(/*line_num=*/1); EXPECT_EQ(expression->line_num, 1); ASSERT_EQ(expression->tag, ExpressionKind::Tuple); - std::vector> fields = - *expression->u.tuple.fields; + std::vector fields = *expression->u.tuple.fields; ASSERT_EQ(fields.size(), 1); - EXPECT_EQ(fields[0].second->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[0].expression->tag, ExpressionKind::Integer); } TEST(ParenContentsTest, UnaryWithCommaAsTuple) { @@ -73,10 +71,9 @@ TEST(ParenContentsTest, UnaryWithCommaAsTuple) { const Expression* tuple = contents.AsTuple(/*line_num=*/1); EXPECT_EQ(tuple->line_num, 1); ASSERT_EQ(tuple->tag, ExpressionKind::Tuple); - std::vector> fields = - *tuple->u.tuple.fields; + std::vector fields = *tuple->u.tuple.fields; ASSERT_EQ(fields.size(), 1); - EXPECT_EQ(fields[0].second->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[0].expression->tag, ExpressionKind::Integer); } TEST(ParenContentsTest, BinaryAsExpression) { @@ -87,11 +84,10 @@ TEST(ParenContentsTest, BinaryAsExpression) { const Expression* expression = contents.AsExpression(/*line_num=*/1); EXPECT_EQ(expression->line_num, 1); ASSERT_EQ(expression->tag, ExpressionKind::Tuple); - std::vector> fields = - *expression->u.tuple.fields; + std::vector fields = *expression->u.tuple.fields; ASSERT_EQ(fields.size(), 2); - EXPECT_EQ(fields[0].second->tag, ExpressionKind::Integer); - EXPECT_EQ(fields[1].second->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[0].expression->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[1].expression->tag, ExpressionKind::Integer); } TEST(ParenContentsTest, BinaryAsTuple) { @@ -102,11 +98,10 @@ TEST(ParenContentsTest, BinaryAsTuple) { const Expression* tuple = contents.AsTuple(/*line_num=*/1); EXPECT_EQ(tuple->line_num, 1); ASSERT_EQ(tuple->tag, ExpressionKind::Tuple); - std::vector> fields = - *tuple->u.tuple.fields; + std::vector fields = *tuple->u.tuple.fields; ASSERT_EQ(fields.size(), 2); - EXPECT_EQ(fields[0].second->tag, ExpressionKind::Integer); - EXPECT_EQ(fields[1].second->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[0].expression->tag, ExpressionKind::Integer); + EXPECT_EQ(fields[1].expression->tag, ExpressionKind::Integer); } } // namespace diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index 9f85afa3f237..946b35776682 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -323,11 +323,7 @@ statement_list: ; return_type: // Empty - { - $$ = Carbon::MakeTuple( - yylineno, - new std::vector>()); - } + { $$ = Carbon::MakeUnit(yylineno); } | ARROW expression { $$ = $2; } ; @@ -362,9 +358,7 @@ alternative: | identifier { $$ = new std::pair( - $1, Carbon::MakeTuple( - yylineno, - new std::vector>())); + $1, Carbon::MakeUnit(yylineno)); } ; alternative_list: