Skip to content

Commit 7a9af94

Browse files
jnthntatumcopybara-github
authored andcommitted
Update TypeChecker builder to error when adding overloads that overlap with built-in macros.
PiperOrigin-RevId: 689157529
1 parent 974681c commit 7a9af94

3 files changed

Lines changed: 142 additions & 0 deletions

File tree

checker/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ cc_library(
9090
"//checker/internal:type_checker_impl",
9191
"//common:decl",
9292
"//common:type",
93+
"//internal:status_macros",
94+
"//parser:macro",
95+
"@com_google_absl//absl/base:no_destructor",
96+
"@com_google_absl//absl/container:flat_hash_map",
9397
"@com_google_absl//absl/container:flat_hash_set",
9498
"@com_google_absl//absl/functional:any_invocable",
9599
"@com_google_absl//absl/status",

checker/type_checker_builder.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
// limitations under the License.
1414
#include "checker/type_checker_builder.h"
1515

16+
#include <cstddef>
1617
#include <memory>
1718
#include <string>
1819
#include <utility>
20+
#include <vector>
1921

22+
#include "absl/base/no_destructor.h"
23+
#include "absl/container/flat_hash_map.h"
2024
#include "absl/status/status.h"
2125
#include "absl/status/statusor.h"
2226
#include "absl/strings/str_cat.h"
@@ -26,8 +30,51 @@
2630
#include "checker/type_checker.h"
2731
#include "common/decl.h"
2832
#include "common/type_introspector.h"
33+
#include "internal/status_macros.h"
34+
#include "parser/macro.h"
2935

3036
namespace cel {
37+
namespace {
38+
39+
const absl::flat_hash_map<std::string, std::vector<Macro>>& GetStdMacros() {
40+
static const absl::NoDestructor<
41+
absl::flat_hash_map<std::string, std::vector<Macro>>>
42+
kStdMacros({
43+
{"has", {HasMacro()}},
44+
{"all", {AllMacro()}},
45+
{"exists", {ExistsMacro()}},
46+
{"exists_one", {ExistsOneMacro()}},
47+
{"filter", {FilterMacro()}},
48+
{"map", {Map2Macro(), Map3Macro()}},
49+
{"optMap", {OptMapMacro()}},
50+
{"optFlatMap", {OptFlatMapMacro()}},
51+
});
52+
return *kStdMacros;
53+
}
54+
55+
absl::Status CheckStdMacroOverlap(const FunctionDecl& decl) {
56+
const auto& std_macros = GetStdMacros();
57+
auto it = std_macros.find(decl.name());
58+
if (it == std_macros.end()) {
59+
return absl::OkStatus();
60+
}
61+
const auto& macros = it->second;
62+
for (const auto& macro : macros) {
63+
bool macro_member = macro.is_receiver_style();
64+
size_t macro_arg_count = macro.argument_count() + (macro_member ? 1 : 0);
65+
for (const auto& ovl : decl.overloads()) {
66+
if (ovl.member() == macro_member &&
67+
ovl.args().size() == macro_arg_count) {
68+
return absl::InvalidArgumentError(absl::StrCat(
69+
"overload for name '", macro.function(), "' with ", macro_arg_count,
70+
" argument(s) overlaps with predefined macro"));
71+
}
72+
}
73+
}
74+
return absl::OkStatus();
75+
}
76+
77+
} // namespace
3178

3279
absl::StatusOr<std::unique_ptr<TypeChecker>> TypeCheckerBuilder::Build() && {
3380
if (env_.type_providers().empty() && env_.parent() == nullptr) {
@@ -61,6 +108,7 @@ absl::Status TypeCheckerBuilder::AddVariable(const VariableDecl& decl) {
61108
}
62109

63110
absl::Status TypeCheckerBuilder::AddFunction(const FunctionDecl& decl) {
111+
CEL_RETURN_IF_ERROR(CheckStdMacroOverlap(decl));
64112
bool inserted = env_.InsertFunctionIfAbsent(decl);
65113
if (!inserted) {
66114
return absl::AlreadyExistsError(
@@ -75,6 +123,8 @@ absl::Status TypeCheckerBuilder::MergeFunction(const FunctionDecl& decl) {
75123
return AddFunction(decl);
76124
}
77125

126+
CEL_RETURN_IF_ERROR(CheckStdMacroOverlap(decl));
127+
78128
FunctionDecl merged = *existing;
79129

80130
for (const auto& overload : decl.overloads()) {

checker/type_checker_builder_test.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,93 @@ TEST(TypeCheckerBuilderTest, AddLibraryForwardsErrors) {
139139
StatusIs(absl::StatusCode::kInternal, HasSubstr("test error")));
140140
}
141141

142+
TEST(TypeCheckerBuilderTest, AddFunctionOverlapsWithStdMacroError) {
143+
TypeCheckerBuilder builder;
144+
145+
ASSERT_OK_AND_ASSIGN(
146+
auto fn_decl, MakeFunctionDecl("map", MakeMemberOverloadDecl(
147+
"ovl_3", ListType(), ListType(),
148+
DynType(), DynType())));
149+
150+
EXPECT_THAT(builder.AddFunction(fn_decl),
151+
StatusIs(absl::StatusCode::kInvalidArgument,
152+
"overload for name 'map' with 3 argument(s) overlaps "
153+
"with predefined macro"));
154+
155+
fn_decl.set_name("filter");
156+
157+
EXPECT_THAT(builder.AddFunction(fn_decl),
158+
StatusIs(absl::StatusCode::kInvalidArgument,
159+
"overload for name 'filter' with 3 argument(s) overlaps "
160+
"with predefined macro"));
161+
162+
fn_decl.set_name("exists");
163+
164+
EXPECT_THAT(builder.AddFunction(fn_decl),
165+
StatusIs(absl::StatusCode::kInvalidArgument,
166+
"overload for name 'exists' with 3 argument(s) overlaps "
167+
"with predefined macro"));
168+
169+
fn_decl.set_name("exists_one");
170+
171+
EXPECT_THAT(builder.AddFunction(fn_decl),
172+
StatusIs(absl::StatusCode::kInvalidArgument,
173+
"overload for name 'exists_one' with 3 argument(s) "
174+
"overlaps with predefined macro"));
175+
176+
fn_decl.set_name("all");
177+
178+
EXPECT_THAT(builder.AddFunction(fn_decl),
179+
StatusIs(absl::StatusCode::kInvalidArgument,
180+
"overload for name 'all' with 3 argument(s) overlaps "
181+
"with predefined macro"));
182+
183+
fn_decl.set_name("optMap");
184+
185+
EXPECT_THAT(builder.AddFunction(fn_decl),
186+
StatusIs(absl::StatusCode::kInvalidArgument,
187+
"overload for name 'optMap' with 3 argument(s) overlaps "
188+
"with predefined macro"));
189+
190+
fn_decl.set_name("optFlatMap");
191+
192+
EXPECT_THAT(
193+
builder.AddFunction(fn_decl),
194+
StatusIs(absl::StatusCode::kInvalidArgument,
195+
"overload for name 'optFlatMap' with 3 argument(s) overlaps "
196+
"with predefined macro"));
197+
198+
ASSERT_OK_AND_ASSIGN(
199+
fn_decl, MakeFunctionDecl(
200+
"has", MakeOverloadDecl("ovl_1", BoolType(), DynType())));
201+
202+
EXPECT_THAT(builder.AddFunction(fn_decl),
203+
StatusIs(absl::StatusCode::kInvalidArgument,
204+
"overload for name 'has' with 1 argument(s) overlaps "
205+
"with predefined macro"));
206+
207+
ASSERT_OK_AND_ASSIGN(
208+
fn_decl, MakeFunctionDecl("map", MakeMemberOverloadDecl(
209+
"ovl_4", ListType(), ListType(),
210+
211+
DynType(), DynType(), DynType())));
212+
213+
EXPECT_THAT(builder.AddFunction(fn_decl),
214+
StatusIs(absl::StatusCode::kInvalidArgument,
215+
"overload for name 'map' with 4 argument(s) overlaps "
216+
"with predefined macro"));
217+
}
218+
219+
TEST(TypeCheckerBuilderTest, AddFunctionNoOverlapWithStdMacroError) {
220+
TypeCheckerBuilder builder;
221+
222+
ASSERT_OK_AND_ASSIGN(
223+
auto fn_decl,
224+
MakeFunctionDecl("has", MakeMemberOverloadDecl("ovl", BoolType(),
225+
DynType(), StringType())));
226+
227+
EXPECT_THAT(builder.AddFunction(fn_decl), IsOk());
228+
}
229+
142230
} // namespace
143231
} // namespace cel

0 commit comments

Comments
 (0)