diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index de023d46e1d1..88e0c81daa9d 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -68,7 +68,7 @@ static void PrintFields(llvm::raw_ostream& out, std::string_view separator) { llvm::ListSeparator sep; for (const auto& field : fields) { - out << sep << "." << field.name << separator << *field.expression; + out << sep << "." << field.name() << separator << *field.expression(); } } @@ -86,7 +86,7 @@ void Expression::Print(llvm::raw_ostream& out) const { } case Expression::Kind::TupleLiteral: out << "("; - PrintFields(out, cast(*this).Fields(), " = "); + PrintFields(out, cast(*this).fields(), " = "); out << ")"; break; case Expression::Kind::StructLiteral: diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index e3b503e83166..973d0c2a56b2 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -76,16 +76,24 @@ auto TupleExpressionFromParenContents( Nonnull arena, SourceLocation source_loc, const ParenContents& paren_contents) -> Nonnull; -// A FieldInitializer represents the initialization of a single tuple field. -struct FieldInitializer { +// A FieldInitializer represents the initialization of a single tuple or +// struct field. +class FieldInitializer { + public: FieldInitializer(std::string name, Nonnull expression) - : name(std::move(name)), expression(expression) {} + : name_(std::move(name)), expression_(expression) {} + auto name() const -> const std::string& { return name_; } + + auto expression() const -> Nonnull { return expression_; } + auto expression() -> Nonnull { return expression_; } + + private: // The field name. Cannot be empty. - std::string name; + std::string name_; // The expression that initializes the field. - Nonnull expression; + Nonnull expression_; }; enum class Operator { @@ -224,16 +232,18 @@ class TupleLiteral : public Expression { explicit TupleLiteral(SourceLocation source_loc, std::vector fields) - : Expression(Kind::TupleLiteral, source_loc), fields(std::move(fields)) {} + : Expression(Kind::TupleLiteral, source_loc), + fields_(std::move(fields)) {} static auto classof(const Expression* exp) -> bool { return exp->kind() == Kind::TupleLiteral; } - auto Fields() const -> const std::vector& { return fields; } + auto fields() const -> llvm::ArrayRef { return fields_; } + auto fields() -> llvm::MutableArrayRef { return fields_; } private: - std::vector fields; + std::vector fields_; }; // A non-empty literal value of a struct type. @@ -255,9 +265,8 @@ class StructLiteral : public Expression { return exp->kind() == Kind::StructLiteral; } - auto fields() const -> const std::vector& { - return fields_; - } + auto fields() const -> llvm::ArrayRef { return fields_; } + auto fields() -> llvm::MutableArrayRef { return fields_; } private: std::vector fields_; @@ -279,9 +288,8 @@ class StructTypeLiteral : public Expression { return exp->kind() == Kind::StructTypeLiteral; } - auto fields() const -> const std::vector& { - return fields_; - } + auto fields() const -> llvm::ArrayRef { return fields_; } + auto fields() -> llvm::MutableArrayRef { return fields_; } private: std::vector fields_; diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index 015f963218b2..f983efa640c7 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -22,8 +22,8 @@ using testing::IsEmpty; // Matches a FieldInitializer named `name` whose `expression` is an // `IntLiteral` MATCHER_P(IntFieldNamed, name, "") { - return arg.name == std::string(name) && - arg.expression->kind() == Expression::Kind::IntLiteral; + return arg.name() == std::string(name) && + arg.expression()->kind() == Expression::Kind::IntLiteral; } static auto FakeSourceLoc(int line_num) -> SourceLocation { @@ -42,7 +42,7 @@ TEST_F(ExpressionTest, EmptyAsExpression) { ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*expression).Fields(), IsEmpty()); + EXPECT_THAT(cast(*expression).fields(), IsEmpty()); } TEST_F(ExpressionTest, EmptyAsTuple) { @@ -52,7 +52,7 @@ TEST_F(ExpressionTest, EmptyAsTuple) { TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).Fields(), IsEmpty()); + EXPECT_THAT(cast(*tuple).fields(), IsEmpty()); } TEST_F(ExpressionTest, UnaryNoCommaAsExpression) { @@ -83,7 +83,7 @@ TEST_F(ExpressionTest, UnaryNoCommaAsTuple) { TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).Fields(), + EXPECT_THAT(cast(*tuple).fields(), ElementsAre(IntFieldNamed("0"))); } @@ -97,7 +97,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsExpression) { ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*expression).Fields(), + EXPECT_THAT(cast(*expression).fields(), ElementsAre(IntFieldNamed("0"))); } @@ -111,7 +111,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsTuple) { TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).Fields(), + EXPECT_THAT(cast(*tuple).fields(), ElementsAre(IntFieldNamed("0"))); } @@ -127,7 +127,7 @@ TEST_F(ExpressionTest, BinaryAsExpression) { ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*expression).Fields(), + EXPECT_THAT(cast(*expression).fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); } @@ -143,7 +143,7 @@ TEST_F(ExpressionTest, BinaryAsTuple) { TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).Fields(), + EXPECT_THAT(cast(*tuple).fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); } diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 2caebf5296e7..35438d3e2e24 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -201,11 +201,11 @@ auto Interpreter::CreateTuple(Nonnull act, // { { (v1,...,vn) :: C, E, F} :: S, H} // -> { { `(v1,...,vn) :: C, E, F} :: S, H} const auto& tup_lit = cast(*exp); - CHECK(act->results().size() == tup_lit.Fields().size()); + CHECK(act->results().size() == tup_lit.fields().size()); std::vector elements; for (size_t i = 0; i < act->results().size(); ++i) { elements.push_back( - {.name = tup_lit.Fields()[i].name, .value = act->results()[i]}); + {.name = tup_lit.fields()[i].name(), .value = act->results()[i]}); } return arena->New(std::move(elements)); @@ -217,7 +217,7 @@ auto Interpreter::CreateStruct(const std::vector& fields, CHECK(fields.size() == values.size()); std::vector elements; for (size_t i = 0; i < fields.size(); ++i) { - elements.push_back({.name = fields[i].name, .value = values[i]}); + elements.push_back({.name = fields[i].name(), .value = values[i]}); } return arena->New(std::move(elements)); @@ -448,13 +448,13 @@ auto Interpreter::StepLvalue() -> Transition { } case Expression::Kind::TupleLiteral: { if (act->pos() < - static_cast(cast(*exp).Fields().size())) { + static_cast(cast(*exp).fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} Nonnull elt = - cast(*exp).Fields()[act->pos()].expression; + cast(*exp).fields()[act->pos()].expression(); return Spawn{arena->New(elt)}; } else { return Done{CreateTuple(act, exp)}; @@ -516,13 +516,13 @@ auto Interpreter::StepExp() -> Transition { } case Expression::Kind::TupleLiteral: { if (act->pos() < - static_cast(cast(*exp).Fields().size())) { + static_cast(cast(*exp).fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} Nonnull elt = - cast(*exp).Fields()[act->pos()].expression; + cast(*exp).fields()[act->pos()].expression(); return Spawn{arena->New(elt)}; } else { return Done{CreateTuple(act, exp)}; @@ -532,7 +532,7 @@ auto Interpreter::StepExp() -> Transition { const auto& literal = cast(*exp); if (act->pos() < static_cast(literal.fields().size())) { Nonnull elt = - literal.fields()[act->pos()].expression; + literal.fields()[act->pos()].expression(); return Spawn{arena->New(elt)}; } else { return Done{CreateStruct(literal.fields(), act->results())}; @@ -542,11 +542,11 @@ auto Interpreter::StepExp() -> Transition { const auto& struct_type = cast(*exp); if (act->pos() < static_cast(struct_type.fields().size())) { return Spawn{arena->New( - struct_type.fields()[act->pos()].expression)}; + struct_type.fields()[act->pos()].expression())}; } else { VarValues fields; for (size_t i = 0; i < struct_type.fields().size(); ++i) { - fields.push_back({struct_type.fields()[i].name, act->results()[i]}); + fields.push_back({struct_type.fields()[i].name(), act->results()[i]}); } return Done{arena->New(std::move(fields))}; } diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 9443028b32a7..78bcf7b1437f 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -147,12 +147,18 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, } case Value::Kind::TupleValue: { if (arg->kind() != Value::Kind::TupleValue) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "type error in argument deduction\n" + << "expected: " << *param << "\n" + << "actual: " << *arg; } const auto& param_tup = cast(*param); const auto& arg_tup = cast(*arg); if (param_tup.Elements().size() != arg_tup.Elements().size()) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "mismatch in tuple sizes, expected " + << param_tup.Elements().size() << " but got " + << arg_tup.Elements().size(); } for (size_t i = 0; i < param_tup.Elements().size(); ++i) { if (param_tup.Elements()[i].name != arg_tup.Elements()[i].name) { @@ -168,12 +174,18 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, } case Value::Kind::StructType: { if (arg->kind() != Value::Kind::StructType) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "type error in argument deduction\n" + << "expected: " << *param << "\n" + << "actual: " << *arg; } const auto& param_struct = cast(*param); const auto& arg_struct = cast(*arg); if (param_struct.fields().size() != arg_struct.fields().size()) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "mismatch in struct field counts, expected " + << param_struct.fields().size() << " but got " + << arg_struct.fields().size(); } for (size_t i = 0; i < param_struct.fields().size(); ++i) { if (param_struct.fields()[i].first != arg_struct.fields()[i].first) { @@ -189,7 +201,10 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, } case Value::Kind::FunctionType: { if (arg->kind() != Value::Kind::FunctionType) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "type error in argument deduction\n" + << "expected: " << *param << "\n" + << "actual: " << *arg; } const auto& param_fn = cast(*param); const auto& arg_fn = cast(*arg); @@ -202,7 +217,10 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, } case Value::Kind::PointerType: { if (arg->kind() != Value::Kind::PointerType) { - ExpectType(source_loc, "argument deduction", param, arg); + FATAL_COMPILATION_ERROR(source_loc) + << "type error in argument deduction\n" + << "expected: " << *param << "\n" + << "actual: " << *arg; } return ArgumentDeduction(source_loc, deduced, cast(*param).Type(), @@ -341,11 +359,11 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, std::vector new_args; std::vector arg_types; auto new_types = types; - for (const auto& arg : cast(*e).Fields()) { - auto arg_res = TypeCheckExp(arg.expression, new_types, values); + for (auto& arg : cast(*e).fields()) { + auto arg_res = TypeCheckExp(arg.expression(), new_types, values); new_types = arg_res.types; - new_args.push_back(FieldInitializer(arg.name, arg_res.exp)); - arg_types.push_back({.name = arg.name, .value = arg_res.type}); + new_args.push_back(FieldInitializer(arg.name(), arg_res.exp)); + arg_types.push_back({.name = arg.name(), .value = arg_res.type}); } auto tuple_e = arena->New(e->source_loc(), new_args); auto tuple_t = arena->New(std::move(arg_types)); @@ -355,26 +373,26 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, std::vector new_args; VarValues arg_types; auto new_types = types; - for (const auto& arg : cast(*e).fields()) { - auto arg_res = TypeCheckExp(arg.expression, new_types, values); + for (auto& arg : cast(*e).fields()) { + auto arg_res = TypeCheckExp(arg.expression(), new_types, values); new_types = arg_res.types; - new_args.push_back(FieldInitializer(arg.name, arg_res.exp)); - arg_types.push_back({arg.name, arg_res.type}); + new_args.push_back(FieldInitializer(arg.name(), arg_res.exp)); + arg_types.push_back({arg.name(), arg_res.type}); } auto new_e = arena->New(e->source_loc(), new_args); auto type = arena->New(std::move(arg_types)); return TCExpression(new_e, type, new_types); } case Expression::Kind::StructTypeLiteral: { - const auto& struct_type = cast(*e); + auto& struct_type = cast(*e); std::vector new_args; auto new_types = types; - for (const auto& arg : struct_type.fields()) { - auto arg_res = TypeCheckExp(arg.expression, new_types, values); + for (auto& arg : struct_type.fields()) { + auto arg_res = TypeCheckExp(arg.expression(), new_types, values); new_types = arg_res.types; Nonnull type = interpreter.InterpExp(values, arg_res.exp); new_args.push_back( - FieldInitializer(arg.name, ReifyType(type, e->source_loc()))); + FieldInitializer(arg.name(), ReifyType(type, e->source_loc()))); } auto new_e = arena->New(e->source_loc(), new_args); Nonnull type;