From 0fd0855da01b4a25bb73eaebf570080ceb93a50c Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Thu, 13 Apr 2023 01:24:29 +0200 Subject: [PATCH] Detect duplicate struct member names (#2764) Detect struct literal or struct type literal member duplicate name Closes #2762 --- explorer/interpreter/resolve_names.cpp | 17 +++++++++++++++-- .../fail_struct_literal_duplicate_member.carbon | 15 +++++++++++++++ ..._struct_type_literal_duplicate_member.carbon | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 explorer/testdata/struct/fail_struct_literal_duplicate_member.carbon create mode 100644 explorer/testdata/struct/fail_struct_type_literal_duplicate_member.carbon diff --git a/explorer/interpreter/resolve_names.cpp b/explorer/interpreter/resolve_names.cpp index e4aad27f9bd2..0e2c2e2ee709 100644 --- a/explorer/interpreter/resolve_names.cpp +++ b/explorer/interpreter/resolve_names.cpp @@ -320,19 +320,32 @@ auto NameResolver::ResolveNames(Expression& expression, CARBON_RETURN_IF_ERROR(ResolveNames(*field, enclosing_scope)); } break; - case ExpressionKind::StructLiteral: + case ExpressionKind::StructLiteral: { + std::set member_names; for (FieldInitializer& init : cast(expression).fields()) { CARBON_RETURN_IF_ERROR( ResolveNames(init.expression(), enclosing_scope)); + if (!member_names.insert(init.name()).second) { + return ProgramError(init.expression().source_loc()) + << "Duplicate name `" << init.name() << "` in struct literal"; + } } break; - case ExpressionKind::StructTypeLiteral: + } + case ExpressionKind::StructTypeLiteral: { + std::set member_names; for (FieldInitializer& init : cast(expression).fields()) { CARBON_RETURN_IF_ERROR( ResolveNames(init.expression(), enclosing_scope)); + if (!member_names.insert(init.name()).second) { + return ProgramError(init.expression().source_loc()) + << "Duplicate name `" << init.name() + << "` in struct type literal"; + } } break; + } case ExpressionKind::IdentifierExpression: { auto& identifier = cast(expression); CARBON_ASSIGN_OR_RETURN( diff --git a/explorer/testdata/struct/fail_struct_literal_duplicate_member.carbon b/explorer/testdata/struct/fail_struct_literal_duplicate_member.carbon new file mode 100644 index 000000000000..00d68caf137b --- /dev/null +++ b/explorer/testdata/struct/fail_struct_literal_duplicate_member.carbon @@ -0,0 +1,15 @@ +// 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 +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package ExplorerTest api; + +fn Main() -> i32 { + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_struct_literal_duplicate_member.carbon:[[@LINE+1]]: Duplicate name `x` in struct literal + var x: auto = {.x = 0, .x = 0}; + return 0; +} diff --git a/explorer/testdata/struct/fail_struct_type_literal_duplicate_member.carbon b/explorer/testdata/struct/fail_struct_type_literal_duplicate_member.carbon new file mode 100644 index 000000000000..c4d105204ec5 --- /dev/null +++ b/explorer/testdata/struct/fail_struct_type_literal_duplicate_member.carbon @@ -0,0 +1,15 @@ +// 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 +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package ExplorerTest api; + +fn Main() -> i32 { + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_struct_type_literal_duplicate_member.carbon:[[@LINE+1]]: Duplicate name `x` in struct type literal + var y: {.x: i32, .x: i32}; + return 0; +}