diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 784db8c36540..768de7788a13 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -31,8 +31,7 @@ auto ExpressionFromParenContents( auto TupleExpressionFromParenContents( Nonnull arena, SourceLocation source_loc, const ParenContents& paren_contents) -> Nonnull { - return arena->New( - source_loc, paren_contents.TupleElements(source_loc)); + return arena->New(source_loc, paren_contents.elements); } static void PrintOp(llvm::raw_ostream& out, Operator op) { @@ -85,11 +84,16 @@ void Expression::Print(llvm::raw_ostream& out) const { out << access.aggregate() << "." << access.field(); break; } - case Expression::Kind::TupleLiteral: + case Expression::Kind::TupleLiteral: { out << "("; - PrintFields(out, cast(*this).fields(), " = "); + llvm::ListSeparator sep; + for (Nonnull field : + cast(*this).fields()) { + out << sep << *field; + } out << ")"; break; + } case Expression::Kind::StructLiteral: out << "{"; PrintFields(out, cast(*this).fields(), " = "); diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 1391de742208..bd7e9e2a755a 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -92,8 +92,7 @@ auto TupleExpressionFromParenContents( Nonnull arena, SourceLocation source_loc, const ParenContents& paren_contents) -> Nonnull; -// A FieldInitializer represents the initialization of a single tuple or -// struct field. +// A FieldInitializer represents the initialization of a single struct field. class FieldInitializer { public: FieldInitializer(std::string name, Nonnull expression) @@ -247,7 +246,7 @@ class TupleLiteral : public Expression { : TupleLiteral(source_loc, {}) {} explicit TupleLiteral(SourceLocation source_loc, - std::vector fields) + std::vector> fields) : Expression(Kind::TupleLiteral, source_loc), fields_(std::move(fields)) {} @@ -255,11 +254,13 @@ class TupleLiteral : public Expression { return exp->kind() == Kind::TupleLiteral; } - auto fields() const -> llvm::ArrayRef { return fields_; } - auto fields() -> llvm::MutableArrayRef { return fields_; } + auto fields() const -> llvm::ArrayRef> { + return fields_; + } + auto fields() -> llvm::ArrayRef> { return fields_; } private: - std::vector fields_; + std::vector> fields_; }; // A non-empty literal value of a struct type. diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index 822bebd8ebf4..11b759c030fe 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -19,12 +19,8 @@ using llvm::cast; using testing::ElementsAre; 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; -} +// Matches any `IntLiteral`. +MATCHER(IntField, "") { return arg->kind() == Expression::Kind::IntLiteral; } static auto FakeSourceLoc(int line_num) -> SourceLocation { return SourceLocation("", line_num); @@ -63,8 +59,7 @@ TEST_F(ExpressionTest, UnaryNoCommaAsExpression) { // ) // ``` ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42)}, .has_trailing_comma = false}; Nonnull expression = @@ -75,22 +70,19 @@ TEST_F(ExpressionTest, UnaryNoCommaAsExpression) { TEST_F(ExpressionTest, UnaryNoCommaAsTuple) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42)}, .has_trailing_comma = false}; Nonnull tuple = TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).fields(), - ElementsAre(IntFieldNamed("0"))); + EXPECT_THAT(cast(*tuple).fields(), ElementsAre(IntField())); } TEST_F(ExpressionTest, UnaryWithCommaAsExpression) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42)}, .has_trailing_comma = true}; Nonnull expression = @@ -98,29 +90,25 @@ TEST_F(ExpressionTest, UnaryWithCommaAsExpression) { EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).fields(), - ElementsAre(IntFieldNamed("0"))); + ElementsAre(IntField())); } TEST_F(ExpressionTest, UnaryWithCommaAsTuple) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42)}, .has_trailing_comma = true}; Nonnull tuple = TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); - EXPECT_THAT(cast(*tuple).fields(), - ElementsAre(IntFieldNamed("0"))); + EXPECT_THAT(cast(*tuple).fields(), ElementsAre(IntField())); } TEST_F(ExpressionTest, BinaryAsExpression) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}, - {.name = std::nullopt, - .term = arena.New(FakeSourceLoc(3), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42), + arena.New(FakeSourceLoc(3), 42)}, .has_trailing_comma = true}; Nonnull expression = @@ -128,15 +116,13 @@ TEST_F(ExpressionTest, BinaryAsExpression) { EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).fields(), - ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); + ElementsAre(IntField(), IntField())); } TEST_F(ExpressionTest, BinaryAsTuple) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2), 42)}, - {.name = std::nullopt, - .term = arena.New(FakeSourceLoc(3), 42)}}, + .elements = {arena.New(FakeSourceLoc(2), 42), + arena.New(FakeSourceLoc(3), 42)}, .has_trailing_comma = true}; Nonnull tuple = @@ -144,7 +130,7 @@ TEST_F(ExpressionTest, BinaryAsTuple) { EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).fields(), - ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); + ElementsAre(IntField(), IntField())); } } // namespace diff --git a/executable_semantics/ast/paren_contents.h b/executable_semantics/ast/paren_contents.h index 73070b7069cc..153222e2b643 100644 --- a/executable_semantics/ast/paren_contents.h +++ b/executable_semantics/ast/paren_contents.h @@ -26,25 +26,12 @@ namespace Carbon { // either `Expression` or `Pattern`. template struct ParenContents { - struct Element { - std::optional name; - Nonnull term; - }; - - // If this object represents a single term, with no name and no trailing - // comma, this method returns that term. This typically means the parentheses - // can be interpreted as grouping. + // If this object represents a single term with no trailing comma, this + // method returns that term. This typically means the parentheses can be + // interpreted as grouping. auto SingleTerm() const -> std::optional>; - // Converts `elements` to std::vector. TupleElement must - // have a constructor that takes a std::string and a Nonnull. - // - // TODO: Find a way to deduce TupleElement from Term. - template - auto TupleElements(SourceLocation source_loc) const - -> std::vector; - - std::vector elements; + std::vector> elements; bool has_trailing_comma; }; @@ -52,37 +39,13 @@ struct ParenContents { template auto ParenContents::SingleTerm() const -> std::optional> { - if (elements.size() == 1 && !elements.front().name.has_value() && - !has_trailing_comma) { - return elements.front().term; + if (elements.size() == 1 && !has_trailing_comma) { + return elements.front(); } else { return std::nullopt; } } -template -template -auto ParenContents::TupleElements(SourceLocation source_loc) const - -> std::vector { - std::vector result; - int i = 0; - bool seen_named_member = false; - for (auto element : elements) { - if (element.name.has_value()) { - seen_named_member = true; - result.push_back(TupleElement(*element.name, element.term)); - } else { - if (seen_named_member) { - FATAL_PROGRAM_ERROR(source_loc) - << "positional members must come before named members"; - } - result.push_back(TupleElement(std::to_string(i), element.term)); - } - ++i; - } - return result; -} - } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_AST_PAREN_CONTENTS_H_ diff --git a/executable_semantics/ast/pattern.cpp b/executable_semantics/ast/pattern.cpp index 0c3a21d7f3e6..40ac58f59509 100644 --- a/executable_semantics/ast/pattern.cpp +++ b/executable_semantics/ast/pattern.cpp @@ -36,8 +36,8 @@ void Pattern::Print(llvm::raw_ostream& out) const { const auto& tuple = cast(*this); out << "("; llvm::ListSeparator sep; - for (const TuplePattern::Field& field : tuple.Fields()) { - out << sep << field.name << " = " << *field.pattern; + for (Nonnull field : tuple.Fields()) { + out << sep << *field; } out << ")"; break; @@ -69,9 +69,7 @@ auto TuplePatternFromParenContents(Nonnull arena, SourceLocation source_loc, const ParenContents& paren_contents) -> Nonnull { - return arena->New( - source_loc, - paren_contents.TupleElements(source_loc)); + return arena->New(source_loc, paren_contents.elements); } // Used by AlternativePattern for constructor initialization. Produces a helpful @@ -100,9 +98,7 @@ auto ParenExpressionToParenPattern(Nonnull arena, ParenContents result = { .elements = {}, .has_trailing_comma = contents.has_trailing_comma}; for (const auto& element : contents.elements) { - result.elements.push_back( - {.name = element.name, - .term = arena->New(element.term)}); + result.elements.push_back(arena->New(element)); } return result; } diff --git a/executable_semantics/ast/pattern.h b/executable_semantics/ast/pattern.h index 926543b80bd6..8a9eb736002e 100644 --- a/executable_semantics/ast/pattern.h +++ b/executable_semantics/ast/pattern.h @@ -114,30 +114,20 @@ class BindingPattern : public Pattern { // A pattern that matches a tuple value field-wise. class TuplePattern : public Pattern { public: - // Represents a portion of a tuple pattern corresponding to a single field. - struct Field { - Field(std::string name, Nonnull pattern) - : name(std::move(name)), pattern(pattern) {} - - // The field name. Cannot be empty - std::string name; - - // The pattern the field must match. - Nonnull pattern; - }; - - TuplePattern(SourceLocation source_loc, std::vector fields) + TuplePattern(SourceLocation source_loc, std::vector> fields) : Pattern(Kind::TuplePattern, source_loc), fields(std::move(fields)) {} static auto classof(const Pattern* pattern) -> bool { return pattern->kind() == Kind::TuplePattern; } - auto Fields() const -> llvm::ArrayRef { return fields; } - auto Fields() -> llvm::MutableArrayRef { return fields; } + auto Fields() const -> llvm::ArrayRef> { + return fields; + } + auto Fields() -> llvm::ArrayRef> { return fields; } private: - std::vector fields; + std::vector> fields; }; // Converts paren_contents to a Pattern, interpreting the parentheses as diff --git a/executable_semantics/ast/pattern_test.cpp b/executable_semantics/ast/pattern_test.cpp index edeaa7a2ca2f..36b9667dffed 100644 --- a/executable_semantics/ast/pattern_test.cpp +++ b/executable_semantics/ast/pattern_test.cpp @@ -19,11 +19,8 @@ using llvm::isa; using testing::ElementsAre; using testing::IsEmpty; -// Matches a TuplePattern::Field named `name` whose `pattern` is an -// `AutoPattern`. -MATCHER_P(AutoFieldNamed, name, "") { - return arg.name == std::string(name) && isa(*arg.pattern); -} +// Matches any `AutoPattern`. +MATCHER(AutoField, "") { return isa(*arg); } static auto FakeSourceLoc(int line_num) -> SourceLocation { return SourceLocation("", line_num); @@ -61,8 +58,7 @@ TEST_F(PatternTest, UnaryNoCommaAsPattern) { // ) // ``` ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2))}, .has_trailing_comma = false}; Nonnull pattern = @@ -73,48 +69,42 @@ TEST_F(PatternTest, UnaryNoCommaAsPattern) { TEST_F(PatternTest, UnaryNoCommaAsTuplePattern) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2))}, .has_trailing_comma = false}; Nonnull tuple = TuplePatternFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); - EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); + EXPECT_THAT(tuple->Fields(), ElementsAre(AutoField())); } TEST_F(PatternTest, UnaryWithCommaAsPattern) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2))}, .has_trailing_comma = true}; Nonnull pattern = PatternFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(pattern->source_loc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(*pattern)); - EXPECT_THAT(cast(*pattern).Fields(), - ElementsAre(AutoFieldNamed("0"))); + EXPECT_THAT(cast(*pattern).Fields(), ElementsAre(AutoField())); } TEST_F(PatternTest, UnaryWithCommaAsTuplePattern) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2))}, .has_trailing_comma = true}; Nonnull tuple = TuplePatternFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); - EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); + EXPECT_THAT(tuple->Fields(), ElementsAre(AutoField())); } TEST_F(PatternTest, BinaryAsPattern) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}, - {.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2)), + arena.New(FakeSourceLoc(2))}, .has_trailing_comma = true}; Nonnull pattern = @@ -122,22 +112,19 @@ TEST_F(PatternTest, BinaryAsPattern) { EXPECT_EQ(pattern->source_loc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(*pattern)); EXPECT_THAT(cast(*pattern).Fields(), - ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); + ElementsAre(AutoField(), AutoField())); } TEST_F(PatternTest, BinaryAsTuplePattern) { ParenContents contents = { - .elements = {{.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}, - {.name = std::nullopt, - .term = arena.New(FakeSourceLoc(2))}}, + .elements = {arena.New(FakeSourceLoc(2)), + arena.New(FakeSourceLoc(2))}, .has_trailing_comma = true}; Nonnull tuple = TuplePatternFromParenContents(&arena, FakeSourceLoc(1), contents); EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1)); - EXPECT_THAT(tuple->Fields(), - ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); + EXPECT_THAT(tuple->Fields(), ElementsAre(AutoField(), AutoField())); } } // namespace diff --git a/executable_semantics/interpreter/exec_program.cpp b/executable_semantics/interpreter/exec_program.cpp index a1ef015152df..b825e45c36b8 100644 --- a/executable_semantics/interpreter/exec_program.cpp +++ b/executable_semantics/interpreter/exec_program.cpp @@ -18,18 +18,17 @@ namespace Carbon { static void AddIntrinsics(Nonnull arena, std::vector>* declarations) { SourceLocation source_loc("", 0); - std::vector print_fields = {TuplePattern::Field( - "0", arena->New( - source_loc, "format_str", - arena->New( - arena->New(source_loc))))}; + std::vector> print_params = {arena->New( + source_loc, "format_str", + arena->New( + arena->New(source_loc)))}; auto print_return = arena->New( source_loc, arena->New(IntrinsicExpression::Intrinsic::Print), false); auto print = arena->New(arena->New( source_loc, "Print", std::vector(), - arena->New(source_loc, print_fields), + arena->New(source_loc, print_params), arena->New(arena->New(source_loc)), /*is_omitted_return_type=*/false, print_return)); declarations->insert(declarations->begin(), print); diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index e933decc5a0a..24e95e58dd20 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -201,20 +201,14 @@ auto Interpreter::CreateTuple(Nonnull act, // -> { { `(v1,...,vn) :: C, E, F} :: S, H} const auto& tup_lit = cast(*exp); 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]}); - } - - return arena->New(std::move(elements)); + return arena->New(act->results()); } auto Interpreter::CreateStruct(const std::vector& fields, const std::vector>& values) -> Nonnull { CHECK(fields.size() == values.size()); - std::vector elements; + std::vector elements; for (size_t i = 0; i < fields.size(); ++i) { elements.push_back({.name = fields[i].name(), .value = values[i]}); } @@ -247,15 +241,8 @@ auto Interpreter::PatternMatch(Nonnull p, Nonnull v, } Env values(arena); for (size_t i = 0; i < p_tup.Elements().size(); ++i) { - if (p_tup.Elements()[i].name != v_tup.Elements()[i].name) { - FATAL_PROGRAM_ERROR(source_loc) - << "Tuple field name '" << v_tup.Elements()[i].name - << "' does not match pattern field name '" - << p_tup.Elements()[i].name << "'"; - } - std::optional matches = - PatternMatch(p_tup.Elements()[i].value, - v_tup.Elements()[i].value, source_loc); + std::optional matches = PatternMatch( + p_tup.Elements()[i], v_tup.Elements()[i], source_loc); if (!matches) { return std::nullopt; } @@ -356,14 +343,9 @@ void Interpreter::PatternAssignment(Nonnull pat, << "arity mismatch in tuple pattern assignment:\n pattern: " << pat_tup << "\n value: " << val_tup; } - for (const TupleElement& pattern_element : pat_tup.Elements()) { - std::optional> value_field = - val_tup.FindField(pattern_element.name); - if (!value_field) { - FATAL_RUNTIME_ERROR(source_loc) - << "field " << pattern_element.name << "not in " << *val; - } - PatternAssignment(pattern_element.value, *value_field, source_loc); + for (size_t i = 0; i < pat_tup.Elements().size(); ++i) { + PatternAssignment(pat_tup.Elements()[i], val_tup.Elements()[i], + source_loc); } break; } @@ -453,7 +435,7 @@ auto Interpreter::StepLvalue() -> Transition { // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} return Spawn{arena->New( - &cast(*exp).fields()[act->pos()].expression())}; + cast(*exp).fields()[act->pos()])}; } else { return Done{CreateTuple(act, exp)}; } @@ -497,19 +479,13 @@ auto Interpreter::StepExp() -> Transition { } else { // { { v :: [][i] :: C, E, F} :: S, H} // -> { { v_i :: C, E, F} : S, H} - auto* tuple = dyn_cast(act->results()[0]); - if (tuple == nullptr) { + const auto& tuple = cast(*act->results()[0]); + int i = cast(*act->results()[1]).Val(); + if (i < 0 || i >= static_cast(tuple.Elements().size())) { FATAL_RUNTIME_ERROR_NO_LINE() - << "expected a tuple in field access, not " << *act->results()[0]; + << "index " << i << " out of range in " << tuple; } - std::string f = - std::to_string(cast(*act->results()[1]).Val()); - std::optional> field = tuple->FindField(f); - if (!field) { - FATAL_RUNTIME_ERROR_NO_LINE() - << "field " << f << " not in " << *tuple; - } - return Done{*field}; + return Done{tuple.Elements()[i]}; } } case Expression::Kind::TupleLiteral: { @@ -520,7 +496,7 @@ auto Interpreter::StepExp() -> Transition { // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} return Spawn{arena->New( - &cast(*exp).fields()[act->pos()].expression())}; + cast(*exp).fields()[act->pos()])}; } else { return Done{CreateTuple(act, exp)}; } @@ -603,11 +579,6 @@ auto Interpreter::StepExp() -> Transition { // { { v2 :: v1([]) :: C, E, F} :: S, H} // -> { {C',E',F'} :: {C, E, F} :: S, H} switch (act->results()[0]->kind()) { - case Value::Kind::NominalClassType: { - Nonnull arg = - CopyVal(arena, act->results()[1], exp->source_loc()); - return Done{arena->New(act->results()[0], arg)}; - } case Value::Kind::AlternativeConstructorValue: { const auto& alt = cast(*act->results()[0]); @@ -716,15 +687,9 @@ auto Interpreter::StepPattern() -> Transition { // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} - return Spawn{ - arena->New(tuple.Fields()[act->pos()].pattern)}; + return Spawn{arena->New(tuple.Fields()[act->pos()])}; } else { - std::vector elements; - for (size_t i = 0; i < tuple.Fields().size(); ++i) { - elements.push_back( - {.name = tuple.Fields()[i].name, .value = act->results()[i]}); - } - return Done{arena->New(std::move(elements))}; + return Done{arena->New(act->results())}; } } case Pattern::Kind::AlternativePattern: { diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index b391c8f3e014..73703cbc4f48 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -126,8 +126,8 @@ static auto IsConcreteType(Nonnull value) -> bool { // `auto` isn't a concrete type, it's a pattern that matches types. return false; case Value::Kind::TupleValue: - for (const TupleElement& field : cast(*value).Elements()) { - if (!IsConcreteType(field.value)) { + for (Nonnull field : cast(*value).Elements()) { + if (!IsConcreteType(field)) { return false; } } @@ -192,17 +192,16 @@ static auto IsImplicitlyConvertible(Nonnull source, case Value::Kind::TupleValue: switch (destination->kind()) { case Value::Kind::TupleValue: { - const std::vector& source_elements = + const std::vector>& source_elements = cast(*source).Elements(); - const std::vector& destination_elements = + const std::vector>& destination_elements = cast(*destination).Elements(); if (source_elements.size() != destination_elements.size()) { return false; } for (size_t i = 0; i < source_elements.size(); ++i) { - if (source_elements[i].name != destination_elements[i].name || - !IsImplicitlyConvertible(source_elements[i].value, - destination_elements[i].value)) { + if (!IsImplicitlyConvertible(source_elements[i], + destination_elements[i])) { return false; } } @@ -264,14 +263,9 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, << 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) { - FATAL_COMPILATION_ERROR(source_loc) - << "mismatch in tuple names, " << param_tup.Elements()[i].name - << " != " << arg_tup.Elements()[i].name; - } - deduced = ArgumentDeduction(source_loc, deduced, - param_tup.Elements()[i].value, - arg_tup.Elements()[i].value); + deduced = + ArgumentDeduction(source_loc, deduced, param_tup.Elements()[i], + arg_tup.Elements()[i]); } return deduced; } @@ -372,10 +366,9 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull type) } } case Value::Kind::TupleValue: { - std::vector elts; + std::vector> elts; for (const auto& elt : cast(*type).Elements()) { - auto t = Substitute(dict, elt.value); - elts.push_back({.name = elt.name, .value = t}); + elts.push_back(Substitute(dict, elt)); } return arena->New(elts); } @@ -439,17 +432,15 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, const Value& aggregate_type = index.aggregate().static_type(); switch (aggregate_type.kind()) { case Value::Kind::TupleValue: { - auto i = + const auto& tuple_type = cast(aggregate_type); + int i = cast(*interpreter.InterpExp(values, &index.offset())) .Val(); - std::string f = std::to_string(i); - std::optional> field_t = - cast(aggregate_type).FindField(f); - if (!field_t) { + if (i < 0 || i >= static_cast(tuple_type.Elements().size())) { FATAL_COMPILATION_ERROR(e->source_loc()) - << "field " << f << " is not in the tuple " << aggregate_type; + << "index " << i << " is out of range for type " << tuple_type; } - SetStaticType(&index, *field_t); + SetStaticType(&index, tuple_type.Elements()[i]); return TCResult(res.types); } default: @@ -457,15 +448,12 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, } } case Expression::Kind::TupleLiteral: { - std::vector new_args; - std::vector arg_types; + std::vector> arg_types; auto new_types = types; for (auto& arg : cast(*e).fields()) { - auto arg_res = TypeCheckExp(&arg.expression(), new_types, values); + auto arg_res = TypeCheckExp(arg, new_types, values); new_types = arg_res.types; - new_args.push_back(FieldInitializer(arg.name(), &arg.expression())); - arg_types.push_back( - {.name = arg.name(), .value = &arg.expression().static_type()}); + arg_types.push_back(&arg->static_type()); } SetStaticType(e, arena->New(std::move(arg_types))); return TCResult(new_types); @@ -542,18 +530,6 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, << "class " << t_class.Name() << " does not have a field named " << access.field(); } - case Value::Kind::TupleValue: { - const auto& tup = cast(aggregate_type); - for (const TupleElement& field : tup.Elements()) { - if (access.field() == field.name) { - SetStaticType(&access, field.value); - return TCResult(res.types); - } - } - FATAL_COMPILATION_ERROR(e->source_loc()) - << "tuple " << tup << " does not have a field named " - << access.field(); - } case Value::Kind::ChoiceType: { const auto& choice = cast(aggregate_type); for (const auto& vt : choice.Alternatives()) { @@ -778,8 +754,7 @@ auto TypeChecker::TypeCheckPattern( } case Pattern::Kind::TuplePattern: { auto& tuple = cast(*p); - std::vector new_fields; - std::vector field_types; + std::vector> field_types; auto new_types = types; if (expected && (*expected)->kind() != Value::Kind::TupleValue) { FATAL_COMPILATION_ERROR(p->source_loc()) << "didn't expect a tuple"; @@ -790,24 +765,15 @@ auto TypeChecker::TypeCheckPattern( << "tuples of different length"; } for (size_t i = 0; i < tuple.Fields().size(); ++i) { - TuplePattern::Field& field = tuple.Fields()[i]; + Nonnull field = tuple.Fields()[i]; std::optional> expected_field_type; if (expected) { - const TupleElement& expected_element = - cast(**expected).Elements()[i]; - if (expected_element.name != field.name) { - FATAL_COMPILATION_ERROR(tuple.source_loc()) - << "field names do not match, expected " - << expected_element.name << " but got " << field.name; - } - expected_field_type = expected_element.value; + expected_field_type = cast(**expected).Elements()[i]; } - auto field_result = TypeCheckPattern(field.pattern, new_types, values, - expected_field_type); + auto field_result = + TypeCheckPattern(field, new_types, values, expected_field_type); new_types = field_result.types; - new_fields.push_back(TuplePattern::Field(field.name, field.pattern)); - field_types.push_back( - {.name = field.name, .value = &field.pattern->static_type()}); + field_types.push_back(&field->static_type()); } SetStaticType(&tuple, arena->New(std::move(field_types))); return TCResult(new_types); @@ -1222,15 +1188,7 @@ void TypeChecker::TopLevel(Nonnull d, TypeCheckContext* tops) { auto st = TypeOfClassDef(&class_def, tops->types, tops->values); Address a = interpreter.AllocateValue(st); tops->values.Set(class_def.name(), a); // Is this obsolete? - std::vector field_types; - for (const auto& [field_name, field_value] : - cast(*st).Fields()) { - field_types.push_back({.name = field_name, .value = field_value}); - } - auto fun_ty = arena->New( - std::vector(), - arena->New(std::move(field_types)), st); - tops->types.Set(class_def.name(), fun_ty); + tops->types.Set(class_def.name(), st); break; } diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 092c4d8d5067..d83664ca5148 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -46,17 +46,7 @@ auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool { auto StructValue::FindField(const std::string& name) const -> std::optional> { - for (const TupleElement& element : elements_) { - if (element.name == name) { - return element.value; - } - } - return std::nullopt; -} - -auto TupleValue::FindField(const std::string& name) const - -> std::optional> { - for (const TupleElement& element : elements) { + for (const StructElement& element : elements_) { if (element.name == name) { return element.value; } @@ -80,20 +70,12 @@ auto GetMember(Nonnull arena, Nonnull v, } case Value::Kind::NominalClassValue: { std::optional> field = - cast(*cast(*v).Inits()).FindField(f); + cast(*cast(*v).Inits()).FindField(f); if (field == std::nullopt) { FATAL_RUNTIME_ERROR(source_loc) << "member " << f << " not in " << *v; } return *field; } - case Value::Kind::TupleValue: { - std::optional> field = - cast(*v).FindField(f); - if (!field) { - FATAL_RUNTIME_ERROR(source_loc) << "field " << f << " not in " << *v; - } - return *field; - } case Value::Kind::ChoiceType: { const auto& choice = cast(*v); if (!FindInVarValues(f, choice.Alternatives())) { @@ -130,9 +112,10 @@ auto SetFieldImpl(Nonnull arena, Nonnull value, } switch (value->kind()) { case Value::Kind::StructValue: { - std::vector elements = cast(*value).elements(); + std::vector elements = + cast(*value).elements(); auto it = std::find_if(elements.begin(), elements.end(), - [path_begin](const TupleElement& element) { + [path_begin](const StructElement& element) { return element.name == *path_begin; }); if (it == elements.end()) { @@ -148,17 +131,16 @@ auto SetFieldImpl(Nonnull arena, Nonnull value, path_begin, path_end, field_value, source_loc); } case Value::Kind::TupleValue: { - std::vector elements = cast(*value).Elements(); - auto it = std::find_if(elements.begin(), elements.end(), - [path_begin](const TupleElement& element) { - return element.name == *path_begin; - }); - if (it == elements.end()) { + std::vector> elements = + cast(*value).Elements(); + // TODO(geoffromer): update FieldPath to hold integers as well as strings. + int index = std::stoi(*path_begin); + if (index < 0 || static_cast(index) >= elements.size()) { FATAL_RUNTIME_ERROR(source_loc) - << "field " << *path_begin << " not in " << *value; + << "index " << *path_begin << " out of range in " << *value; } - it->value = SetFieldImpl(arena, it->value, path_begin + 1, path_end, - field_value, source_loc); + elements[index] = SetFieldImpl(arena, elements[index], path_begin + 1, + path_end, field_value, source_loc); return arena->New(elements); } default: @@ -203,7 +185,7 @@ void Value::Print(llvm::raw_ostream& out) const { const auto& struct_val = cast(*this); out << "{"; llvm::ListSeparator sep; - for (const TupleElement& element : struct_val.elements()) { + for (const StructElement& element : struct_val.elements()) { out << sep << "." << element.name << " = " << *element.value; } out << "}"; @@ -217,8 +199,8 @@ void Value::Print(llvm::raw_ostream& out) const { case Value::Kind::TupleValue: { out << "("; llvm::ListSeparator sep; - for (const TupleElement& element : cast(*this).Elements()) { - out << sep << element.name << " = " << *element.value; + for (Nonnull element : cast(*this).Elements()) { + out << sep << *element; } out << ")"; break; @@ -313,11 +295,9 @@ auto CopyVal(Nonnull arena, Nonnull val, SourceLocation source_loc) -> Nonnull { switch (val->kind()) { case Value::Kind::TupleValue: { - std::vector elements; - for (const TupleElement& element : cast(*val).Elements()) { - elements.push_back( - {.name = element.name, - .value = CopyVal(arena, element.value, source_loc)}); + std::vector> elements; + for (Nonnull element : cast(*val).Elements()) { + elements.push_back(CopyVal(arena, element, source_loc)); } return arena->New(std::move(elements)); } @@ -327,8 +307,8 @@ auto CopyVal(Nonnull arena, Nonnull val, return arena->New(alt.AltName(), alt.ChoiceName(), arg); } case Value::Kind::StructValue: { - std::vector elements; - for (const TupleElement& element : cast(*val).elements()) { + std::vector elements; + for (const StructElement& element : cast(*val).elements()) { elements.push_back( {.name = element.name, .value = CopyVal(arena, element.value, source_loc)}); @@ -435,8 +415,7 @@ auto TypeEqual(Nonnull t1, Nonnull t2) -> bool { return false; } for (size_t i = 0; i < tup1.Elements().size(); ++i) { - if (tup1.Elements()[i].name != tup2.Elements()[i].name || - !TypeEqual(tup1.Elements()[i].value, tup2.Elements()[i].value)) { + if (!TypeEqual(tup1.Elements()[i], tup2.Elements()[i])) { return false; } } @@ -459,16 +438,16 @@ auto TypeEqual(Nonnull t1, Nonnull t2) -> bool { // Returns true if all the fields of the two tuples contain equal values // and returns false otherwise. -static auto FieldsValueEqual(const std::vector& ts1, - const std::vector& ts2, +static auto FieldsValueEqual(const std::vector& ts1, + const std::vector& ts2, SourceLocation source_loc) -> bool { if (ts1.size() != ts2.size()) { return false; } - for (const TupleElement& element : ts1) { + for (const StructElement& element : ts1) { auto iter = std::find_if( ts2.begin(), ts2.end(), - [&](const TupleElement& e2) { return e2.name == element.name; }); + [&](const StructElement& e2) { return e2.name == element.name; }); if (iter == ts2.end()) { return false; } @@ -502,9 +481,21 @@ auto ValueEqual(Nonnull v1, Nonnull v2, return body1.has_value() == body2.has_value() && (!body1.has_value() || *body1 == *body2); } - case Value::Kind::TupleValue: - return FieldsValueEqual(cast(*v1).Elements(), - cast(*v2).Elements(), source_loc); + case Value::Kind::TupleValue: { + const std::vector>& elements1 = + cast(*v1).Elements(); + const std::vector>& elements2 = + cast(*v2).Elements(); + if (elements1.size() != elements2.size()) { + return false; + } + for (size_t i = 0; i < elements1.size(); ++i) { + if (!ValueEqual(elements1[i], elements2[i], source_loc)) { + return false; + } + } + return true; + } case Value::Kind::StructValue: return FieldsValueEqual(cast(*v1).elements(), cast(*v2).elements(), source_loc); diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index 85fde17342dd..534602c41059 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -94,12 +94,11 @@ auto FindInVarValues(const std::string& field, const VarValues& inits) -> std::optional>; auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool; -// A TupleElement represents the value of a single tuple or struct field. +// A StructElement represents the value of a single struct field. // -// TODO(geoffromer): Rename this, and look for ways to eliminate duplication -// among TupleElement, VarValues::value_type, FieldInitializer, -// TuplePattern::Field, and any similar types. -struct TupleElement { +// TODO(geoffromer): Look for ways to eliminate duplication among StructElement, +// VarValues::value_type, FieldInitializer, and any similar types. +struct StructElement { // The field name. std::string name; @@ -188,7 +187,7 @@ class BoolValue : public Value { // StructType instances. class StructValue : public Value { public: - explicit StructValue(std::vector elements) + explicit StructValue(std::vector elements) : Value(Kind::StructValue), elements_(std::move(elements)) { CHECK(!elements_.empty()) << "`{}` is represented as a StructType, not a StructValue."; @@ -198,7 +197,7 @@ class StructValue : public Value { return value->kind() == Kind::StructValue; } - auto elements() const -> const std::vector& { + auto elements() const -> const std::vector& { return elements_; } @@ -208,7 +207,7 @@ class StructValue : public Value { -> std::optional>; private: - std::vector elements_; + std::vector elements_; }; // A value of a nominal class type. @@ -278,26 +277,24 @@ class TupleValue : public Value { public: // An empty tuple, also known as the unit type. static auto Empty() -> Nonnull { - static const TupleValue empty = TupleValue(std::vector()); + static const TupleValue empty = + TupleValue(std::vector>()); return Nonnull(&empty); } - explicit TupleValue(std::vector elements) + explicit TupleValue(std::vector> elements) : Value(Kind::TupleValue), elements(std::move(elements)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::TupleValue; } - auto Elements() const -> const std::vector& { return elements; } - - // Returns the value of the field named `name` in this tuple, or - // nullopt if there is no such field. - auto FindField(const std::string& name) const - -> std::optional>; + auto Elements() const -> const std::vector>& { + return elements; + } private: - std::vector elements; + std::vector> elements; }; // A binding placeholder value. diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index e09db7721cb2..2cae5ba5087b 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -127,14 +127,12 @@ %type > variable_declaration %type > member %type >> member_list -%type ::Element> paren_expression_element %type > paren_expression_base %type > paren_expression_contents %type > paren_pattern %type > tuple_pattern %type > maybe_empty_tuple_pattern %type > paren_pattern_base -%type ::Element> paren_pattern_element %type > paren_pattern_contents %type > alternative %type > alternative_list @@ -396,12 +394,6 @@ paren_expression: paren_expression_base tuple: paren_expression_base { $$ = TupleExpressionFromParenContents(arena, context.source_loc(), $1); } ; -paren_expression_element: - expression - { $$ = {.name = std::nullopt, .term = $1}; } -| designator EQUAL expression - { $$ = {.name = $1, .term = $3}; } -; paren_expression_base: LEFT_PARENTHESIS RIGHT_PARENTHESIS { $$ = {.elements = {}, .has_trailing_comma = false}; } @@ -414,9 +406,9 @@ paren_expression_base: } ; paren_expression_contents: - paren_expression_element + expression { $$ = {.elements = {$1}, .has_trailing_comma = false}; } -| paren_expression_contents COMMA paren_expression_element +| paren_expression_contents COMMA expression { $$ = $1; $$.elements.push_back($3); @@ -501,31 +493,24 @@ paren_pattern_base: // is very different from the corresponding expression rule because is has to // enforce that requirement. paren_pattern_contents: - paren_pattern_element + non_expression_pattern { $$ = {.elements = {$1}, .has_trailing_comma = false}; } -| paren_expression_contents COMMA paren_pattern_element +| paren_expression_contents COMMA non_expression_pattern { $$ = ParenExpressionToParenPattern(arena, $1); $$.elements.push_back($3); } -| paren_pattern_contents COMMA paren_expression_element +| paren_pattern_contents COMMA expression { $$ = $1; - $$.elements.push_back({.name = $3.name, - .term = arena->New($3.term)}); + $$.elements.push_back(arena->New($3)); } -| paren_pattern_contents COMMA paren_pattern_element +| paren_pattern_contents COMMA non_expression_pattern { $$ = $1; $$.elements.push_back($3); } ; -paren_pattern_element: - non_expression_pattern - { $$ = {.name = std::nullopt, .term = $1}; } -| designator EQUAL non_expression_pattern - { $$ = {.name = $1, .term = $3}; } -; tuple_pattern: paren_pattern_base { $$ = TuplePatternFromParenContents(arena, context.source_loc(), $1); } ; @@ -536,7 +521,7 @@ maybe_empty_tuple_pattern: LEFT_PARENTHESIS RIGHT_PARENTHESIS { $$ = arena->New(context.source_loc(), - std::vector()); + std::vector>()); } | tuple_pattern { $$ = $1; } diff --git a/executable_semantics/testdata/basic_syntax/record.carbon b/executable_semantics/testdata/basic_syntax/record.carbon index c571f639a657..d136c44b35bd 100644 --- a/executable_semantics/testdata/basic_syntax/record.carbon +++ b/executable_semantics/testdata/basic_syntax/record.carbon @@ -12,7 +12,7 @@ package ExecutableSemanticsTest api; fn main() -> i32 { - var t2: (.x = i32, .y = i32) = (.x = 2, .y = 5); + var t2: {.x: i32, .y: i32} = {.x = 2, .y = 5}; t2.y = 3; return t2.y - t2.x - 1; // 3 - 2 - 1 } diff --git a/executable_semantics/testdata/function/fail_call_with_tuple.carbon b/executable_semantics/testdata/function/fail_call_with_tuple.carbon index 298cb4614d57..91f5e200cdff 100644 --- a/executable_semantics/testdata/function/fail_call_with_tuple.carbon +++ b/executable_semantics/testdata/function/fail_call_with_tuple.carbon @@ -7,7 +7,7 @@ // RUN: not executable_semantics --trace %s 2>&1 | \ // RUN: FileCheck --match-full-lines --allow-unused-prefixes %s // AUTOUPDATE: executable_semantics %s -// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/function/fail_call_with_tuple.carbon:19: type error in call: '(0 = (0 = i32, 1 = i32))' is not implicitly convertible to '(0 = i32, 1 = i32)' +// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/function/fail_call_with_tuple.carbon:19: type error in call: '((i32, i32))' is not implicitly convertible to '(i32, i32)' package ExecutableSemanticsTest api; diff --git a/executable_semantics/testdata/function/fail_named_params_order.carbon b/executable_semantics/testdata/function/fail_named_params_order.carbon deleted file mode 100644 index f49481341334..000000000000 --- a/executable_semantics/testdata/function/fail_named_params_order.carbon +++ /dev/null @@ -1,20 +0,0 @@ -// 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 -// -// RUN: not executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: not executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: PROGRAM ERROR: {{.*}}/executable_semantics/testdata/function/fail_named_params_order.carbon:14: positional members must come before named members - -package ExecutableSemanticsTest api; - -fn f(x: i32, .d = y: i32, z: i32, .e = a: i32) -> i32 { - return (x + y) - (z + a); -} - -fn main() -> i32 { - return 0; -} diff --git a/executable_semantics/testdata/function/named_params.carbon b/executable_semantics/testdata/function/named_params.carbon deleted file mode 100644 index 574adc0c2719..000000000000 --- a/executable_semantics/testdata/function/named_params.carbon +++ /dev/null @@ -1,20 +0,0 @@ -// 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 -// -// RUN: executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: result: 0 - -package ExecutableSemanticsTest api; - -fn f(x: i32, .d = y: i32) -> i32 { - return x + y; -} - -fn main() -> i32 { - return f(1, .d = 2) - 3; -} diff --git a/executable_semantics/testdata/tuple/fail_equality_type.carbon b/executable_semantics/testdata/tuple/fail_equality_type.carbon index 2a812b5a68c0..762a683804a8 100644 --- a/executable_semantics/testdata/tuple/fail_equality_type.carbon +++ b/executable_semantics/testdata/tuple/fail_equality_type.carbon @@ -5,8 +5,8 @@ // RUN: not executable_semantics %s 2>&1 2>&1 | FileCheck %s // AUTOUPDATE: executable_semantics %s // CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/tuple/fail_equality_type.carbon:16: type error in == -// CHECK: expected: (0 = i32, 1 = i32) -// CHECK: actual: (0 = i32) +// CHECK: expected: (i32, i32) +// CHECK: actual: (i32) package ExecutableSemanticsTest api; diff --git a/executable_semantics/testdata/tuple/fail_name_order.carbon b/executable_semantics/testdata/tuple/fail_name_order.carbon deleted file mode 100644 index ae991d850543..000000000000 --- a/executable_semantics/testdata/tuple/fail_name_order.carbon +++ /dev/null @@ -1,19 +0,0 @@ -// 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 -// -// RUN: not executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: not executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/tuple/fail_name_order.carbon:17: type error in name binding: '(y = i32, x = i32)' is not implicitly convertible to '(x = i32, y = i32)' - -package ExecutableSemanticsTest api; - -// Test the that field order matters for tuples. - -fn main() -> i32 { - var t: (.x = i32, .y = i32) = (.y = 2, .x = 3); - return 0; -} diff --git a/executable_semantics/testdata/tuple/fail_positional_order.carbon b/executable_semantics/testdata/tuple/fail_positional_order.carbon deleted file mode 100644 index 7f87a04129b4..000000000000 --- a/executable_semantics/testdata/tuple/fail_positional_order.carbon +++ /dev/null @@ -1,17 +0,0 @@ -// 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 -// -// RUN: not executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: not executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: PROGRAM ERROR: {{.*}}/executable_semantics/testdata/tuple/fail_positional_order.carbon:15: positional members must come before named members - -package ExecutableSemanticsTest api; - -fn main() -> i32 { - var t: auto = (.x = 2, 3); - return 0; -} diff --git a/executable_semantics/testdata/tuple/match_with_named.carbon b/executable_semantics/testdata/tuple/match_with_named.carbon deleted file mode 100644 index 489313373a98..000000000000 --- a/executable_semantics/testdata/tuple/match_with_named.carbon +++ /dev/null @@ -1,23 +0,0 @@ -// 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 -// -// RUN: executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: result: 0 - -package ExecutableSemanticsTest api; - -// Test matching with a mixture of positional and named fields. - -fn main() -> i32 { - var t: auto = (2, .x = 5); - match (t) { - case (a: auto, .x = b: auto) => - return a - b + 3; - } - return 1; -} diff --git a/executable_semantics/testdata/tuple/named.carbon b/executable_semantics/testdata/tuple/named.carbon deleted file mode 100644 index c1cbc542555a..000000000000 --- a/executable_semantics/testdata/tuple/named.carbon +++ /dev/null @@ -1,17 +0,0 @@ -// 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 -// -// RUN: executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: result: 0 - -package ExecutableSemanticsTest api; - -fn main() -> i32 { - var t: (i32, .x = i32) = (3, .x = 2); - return t.x + 1 - t[0]; -}