1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17 #include <algorithm>
18
19 #include "checker/ETSAnalyzer.h"
20 #include "checker/ETSchecker.h"
21 #include "compiler/core/compilerImpl.h"
22 #include "compiler/core/ETSCompiler.h"
23 #include "compiler/core/ETSemitter.h"
24 #include "compiler/core/ETSGen.h"
25 #include "compiler/core/regSpiller.h"
26 #include "compiler/lowering/phase.h"
27 #include "es2panda.h"
28 #include "mem/arena_allocator.h"
29 #include "mem/pool_manager.h"
30 #include "public/public.h"
31 #include "util/arktsconfig.h"
32 #include "util/generateBin.h"
33 #include "varbinder/ETSBinder.h"
34 #include "test/utils/panda_executable_path_getter.h"
35 #include "checker/types/globalTypesHolder.h"
36
37 namespace ark::es2panda {
38
39 class UnionNormalizationTest : public testing::Test {
40 public:
UnionNormalizationTest()41 UnionNormalizationTest()
42 : allocator_(std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER)),
43 publicContext_ {std::make_unique<public_lib::Context>()},
44 program_ {parser::Program::NewProgram<varbinder::ETSBinder>(Allocator())},
45 es2pandaPath_ {test::utils::PandaExecutablePathGetter {}.Get()}
46 {
47 }
48
49 ~UnionNormalizationTest() override = default;
50
SetUpTestCase()51 static void SetUpTestCase()
52 {
53 constexpr auto COMPILER_SIZE = operator""_MB(256ULL);
54 mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0);
55 PoolManager::Initialize();
56 }
57
Allocator()58 ArenaAllocator *Allocator()
59 {
60 return allocator_.get();
61 }
62
Program()63 parser::Program *Program()
64 {
65 return &program_;
66 }
67
Checker()68 checker::ETSChecker *Checker()
69 {
70 return &checker_;
71 }
72
InitializeChecker(std::string_view fileName, std::string_view src)73 void InitializeChecker(std::string_view fileName, std::string_view src)
74 {
75 auto es2pandaPathPtr = es2pandaPath_.c_str();
76 ASSERT(es2pandaPathPtr);
77
78 InitializeChecker<parser::ETSParser, varbinder::ETSBinder, checker::ETSChecker, checker::ETSAnalyzer,
79 compiler::ETSCompiler, compiler::ETSGen, compiler::StaticRegSpiller,
80 compiler::ETSFunctionEmitter, compiler::ETSEmitter>(&es2pandaPathPtr, fileName, src,
81 &checker_, &program_);
82 }
83
84 template <typename CodeGen, typename RegSpiller, typename FunctionEmitter, typename Emitter, typename AstCompiler>
MakeCompileJob()85 public_lib::Context::CodeGenCb MakeCompileJob()
86 {
87 return [this](public_lib::Context *context, varbinder::FunctionScope *scope,
88 compiler::ProgramElement *programElement) -> void {
89 RegSpiller regSpiller;
90 AstCompiler astcompiler;
91 CodeGen cg(allocator_.get(), ®Spiller, context, scope, programElement, &astcompiler);
92 FunctionEmitter funcEmitter(&cg, programElement);
93 funcEmitter.Generate();
94 };
95 }
96
97 template <typename Parser, typename VarBinder, typename Checker, typename Analyzer, typename AstCompiler,
98 typename CodeGen, typename RegSpiller, typename FunctionEmitter, typename Emitter>
InitializeChecker(const char **argv, std::string_view fileName, std::string_view src, checker::ETSChecker *checker, parser::Program *program)99 void InitializeChecker(const char **argv, std::string_view fileName, std::string_view src,
100 checker::ETSChecker *checker, parser::Program *program)
101 {
102 auto options = std::make_unique<ark::es2panda::util::Options>();
103 if (!options->Parse(1, argv)) {
104 std::cerr << options->ErrorMsg() << std::endl;
105 return;
106 }
107
108 ark::Logger::ComponentMask mask {};
109 mask.set(ark::Logger::Component::ES2PANDA);
110 ark::Logger::InitializeStdLogging(ark::Logger::LevelFromString(options->LogLevel()), mask);
111
112 Compiler compiler(options->Extension(), options->ThreadCount());
113 SourceFile input(fileName, src, options->ParseModule());
114 compiler::CompilationUnit unit {input, *options, 0, options->Extension()};
115 auto getPhases = compiler::GetPhaseList(ScriptExtension::ETS);
116
117 program->MarkEntry();
118 auto parser =
119 Parser(program, unit.options.CompilerOptions(), static_cast<parser::ParserStatus>(unit.rawParserStatus));
120 auto analyzer = Analyzer(checker);
121 checker->SetAnalyzer(&analyzer);
122
123 auto *varbinder = program->VarBinder();
124 varbinder->SetProgram(program);
125
126 varbinder->SetContext(publicContext_.get());
127
128 auto emitter = Emitter(publicContext_.get());
129
130 auto config = public_lib::ConfigImpl {};
131 publicContext_->config = &config;
132 publicContext_->config->options = &unit.options;
133 publicContext_->sourceFile = &unit.input;
134 publicContext_->allocator = allocator_.get();
135 publicContext_->parser = &parser;
136 publicContext_->checker = checker;
137 publicContext_->analyzer = publicContext_->checker->GetAnalyzer();
138 publicContext_->emitter = &emitter;
139 publicContext_->parserProgram = program;
140
141 parser.ParseScript(unit.input, unit.options.CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB);
142 for (auto *phase : getPhases) {
143 if (!phase->Apply(publicContext_.get(), program)) {
144 return;
145 }
146 }
147 }
148
FindClassType(varbinder::ETSBinder *varbinder, std::string_view className)149 static checker::Type *FindClassType(varbinder::ETSBinder *varbinder, std::string_view className)
150 {
151 auto classDefs = varbinder->AsETSBinder()->GetRecordTable()->ClassDefinitions();
152 auto baseClass = std::find_if(classDefs.begin(), classDefs.end(), [className](ir::ClassDefinition *cdef) {
153 return cdef->Ident()->Name().Is(className);
154 });
155 if (baseClass == classDefs.end()) {
156 return nullptr;
157 }
158 return (*baseClass)->TsType();
159 }
160
FindTypeAlias(checker::ETSChecker *checker, std::string_view aliasName)161 static checker::Type *FindTypeAlias(checker::ETSChecker *checker, std::string_view aliasName)
162 {
163 auto *foundVar =
164 checker->Scope()->FindLocal(aliasName, varbinder::ResolveBindingOptions::TYPE_ALIASES)->AsLocalVariable();
165 if (foundVar == nullptr) {
166 return nullptr;
167 }
168 return foundVar->Declaration()->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation()->TsType();
169 }
170
171 NO_COPY_SEMANTIC(UnionNormalizationTest);
172 NO_MOVE_SEMANTIC(UnionNormalizationTest);
173
174 protected:
175 static constexpr uint8_t SIZE2 = 2;
176 static constexpr uint8_t SIZE3 = 3;
177 static constexpr uint8_t IDX0 = 0;
178 static constexpr uint8_t IDX1 = 1;
179 static constexpr uint8_t IDX2 = 2;
180
181 private:
182 std::unique_ptr<ArenaAllocator> allocator_;
183 std::unique_ptr<public_lib::Context> publicContext_;
184 parser::Program program_;
185 std::string es2pandaPath_;
186 checker::ETSChecker checker_;
187 };
188
TEST_F(UnionNormalizationTest, UnionWithObject)189 TEST_F(UnionNormalizationTest, UnionWithObject)
190 {
191 // Test normalization: int | Object | string ==> Object
192 InitializeChecker("_.sts", "");
193
194 auto checker = Checker();
195 ASSERT(checker);
196
197 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
198 unionConstituents.emplace_back(checker->GlobalIntType());
199 unionConstituents.emplace_back(checker->GetGlobalTypesHolder()->GlobalETSObjectType());
200 unionConstituents.emplace_back(checker->GetGlobalTypesHolder()->GlobalETSStringBuiltinType());
201
202 // Create union type, which will be normalized inside creation function
203 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
204 ASSERT_NE(normalizedType, nullptr);
205 ASSERT_TRUE(normalizedType->IsETSObjectType());
206 ASSERT_EQ(normalizedType, checker->GlobalETSObjectType());
207 }
208
TEST_F(UnionNormalizationTest, UnionWithIdenticalTypes1)209 TEST_F(UnionNormalizationTest, UnionWithIdenticalTypes1)
210 {
211 // Test normalization: number | Base | string | number ==> number | Base | string
212 InitializeChecker("_.sts", "class Base {}");
213
214 auto program = Program();
215 ASSERT(program);
216
217 auto *const baseType = FindClassType(program->VarBinder()->AsETSBinder(), "Base");
218 ASSERT_NE(baseType, nullptr);
219
220 auto checker = Checker();
221 ASSERT(checker);
222
223 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
224 unionConstituents.emplace_back(checker->GlobalDoubleType());
225 unionConstituents.emplace_back(baseType);
226 unionConstituents.emplace_back(checker->GlobalBuiltinETSStringType());
227 unionConstituents.emplace_back(checker->GlobalDoubleType());
228
229 // Create union type, which will be normalized inside creation function
230 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
231 ASSERT_NE(normalizedType, nullptr);
232 ASSERT_TRUE(normalizedType->IsETSUnionType());
233 auto *const unionType = normalizedType->AsETSUnionType();
234 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE3);
235 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
236 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), baseType);
237 ASSERT_EQ(unionType->ConstituentTypes().at(IDX2), checker->GlobalBuiltinETSStringType());
238 }
239
TEST_F(UnionNormalizationTest, DISABLED_UnionWithIdenticalTypes2)240 TEST_F(UnionNormalizationTest, DISABLED_UnionWithIdenticalTypes2)
241 {
242 // Test normalization: Base | int | Base | double | short | number ==> Base | number
243 InitializeChecker("_.sts", "class Base {}");
244
245 auto program = Program();
246 ASSERT(program);
247
248 auto *const baseType = FindClassType(program->VarBinder()->AsETSBinder(), "Base");
249 ASSERT_NE(baseType, nullptr);
250
251 auto checker = Checker();
252 ASSERT(checker);
253
254 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
255 unionConstituents.emplace_back(baseType);
256 unionConstituents.emplace_back(checker->GlobalIntType());
257 unionConstituents.emplace_back(baseType);
258 unionConstituents.emplace_back(checker->GlobalDoubleType());
259 unionConstituents.emplace_back(checker->GlobalShortType());
260 unionConstituents.emplace_back(checker->GlobalDoubleType());
261
262 // Create union type, which will be normalized inside creation function
263 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
264 ASSERT_NE(normalizedType, nullptr);
265 ASSERT_TRUE(normalizedType->IsETSUnionType());
266 auto *const unionType = normalizedType->AsETSUnionType();
267 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE2);
268 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), baseType);
269 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
270 }
271
TEST_F(UnionNormalizationTest, DISABLED_UnionWithNumeric1)272 TEST_F(UnionNormalizationTest, DISABLED_UnionWithNumeric1)
273 {
274 // Test normalization: boolean | int | double | short ==> boolean | double
275 InitializeChecker("_.sts", "");
276
277 auto checker = Checker();
278 ASSERT(checker);
279
280 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
281 unionConstituents.emplace_back(checker->GlobalETSBooleanType());
282 unionConstituents.emplace_back(checker->GlobalIntType());
283 unionConstituents.emplace_back(checker->GlobalDoubleType());
284 unionConstituents.emplace_back(checker->GlobalShortType());
285
286 // Create union type, which will be normalized inside creation function
287 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
288 ASSERT_NE(normalizedType, nullptr);
289 ASSERT_TRUE(normalizedType->IsETSUnionType());
290 auto *const unionType = normalizedType->AsETSUnionType();
291 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE2);
292 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), checker->GetGlobalTypesHolder()->GlobalETSBooleanBuiltinType());
293 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
294 }
295
TEST_F(UnionNormalizationTest, DISABLED_UnionWithNumeric2)296 TEST_F(UnionNormalizationTest, DISABLED_UnionWithNumeric2)
297 {
298 // Test normalization: string | int | Base | double | short ==> string | Base | double
299 InitializeChecker("_.sts", "class Base {}");
300
301 auto program = Program();
302 ASSERT(program);
303
304 auto *const baseType = FindClassType(program->VarBinder()->AsETSBinder(), "Base");
305 ASSERT_NE(baseType, nullptr);
306
307 auto checker = Checker();
308 ASSERT(checker);
309
310 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
311 unionConstituents.emplace_back(checker->GlobalBuiltinETSStringType());
312 unionConstituents.emplace_back(checker->GlobalIntType());
313 unionConstituents.emplace_back(baseType);
314 unionConstituents.emplace_back(checker->GlobalDoubleType());
315 unionConstituents.emplace_back(checker->GlobalShortType());
316
317 // Create union type, which will be normalized inside creation function
318 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
319 ASSERT_NE(normalizedType, nullptr);
320 ASSERT_TRUE(normalizedType->IsETSUnionType());
321 auto *const unionType = normalizedType->AsETSUnionType();
322 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE3);
323 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), checker->GlobalBuiltinETSStringType());
324 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), baseType);
325 ASSERT_EQ(unionType->ConstituentTypes().at(IDX2), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
326 }
327
TEST_F(UnionNormalizationTest, UnionWithSubTypes)328 TEST_F(UnionNormalizationTest, UnionWithSubTypes)
329 {
330 // Test 4 cases of normalization
331 static constexpr std::string_view SRC =
332 "\
333 class Base {}\
334 class Derived1 extends Base {}\
335 class Derived2 extends Base {}\
336 ";
337 InitializeChecker("_.sts", SRC);
338
339 auto program = Program();
340 ASSERT(program);
341
342 auto *const baseType = FindClassType(program->VarBinder()->AsETSBinder(), "Base");
343 ASSERT_NE(baseType, nullptr);
344 auto *const derived1Type = FindClassType(program->VarBinder()->AsETSBinder(), "Derived1");
345 ASSERT_NE(derived1Type, nullptr);
346 auto *const derived2Type = FindClassType(program->VarBinder()->AsETSBinder(), "Derived2");
347 ASSERT_NE(derived2Type, nullptr);
348
349 auto checker = Checker();
350 ASSERT(checker);
351
352 // Test normalization: Derived1 | Base ==> Base
353 ArenaVector<checker::Type *> unionConstituents1(checker->Allocator()->Adapter());
354 unionConstituents1.emplace_back(derived1Type);
355 unionConstituents1.emplace_back(baseType);
356
357 // Create union type, which will be normalized inside creation function
358 auto *const normalizedType1 = checker->CreateETSUnionType(std::move(unionConstituents1));
359 ASSERT_NE(normalizedType1, nullptr);
360 ASSERT_TRUE(normalizedType1->IsETSObjectType());
361 ASSERT_EQ(normalizedType1, baseType);
362
363 // Test normalization: Base | Derived2 ==> Base
364 ArenaVector<checker::Type *> unionConstituents2(checker->Allocator()->Adapter());
365 unionConstituents2.emplace_back(baseType);
366 unionConstituents2.emplace_back(derived2Type);
367
368 // Create union type, which will be normalized inside creation function
369 auto *const normalizedType2 = checker->CreateETSUnionType(std::move(unionConstituents2));
370 ASSERT_NE(normalizedType2, nullptr);
371 ASSERT_TRUE(normalizedType2->IsETSObjectType());
372 ASSERT_EQ(normalizedType2, baseType);
373
374 // Test normalization: Derived1 | Derived2 ==> Derived1 | Derived2
375 ArenaVector<checker::Type *> unionConstituents3(checker->Allocator()->Adapter());
376 unionConstituents3.emplace_back(derived1Type);
377 unionConstituents3.emplace_back(derived2Type);
378
379 // Create union type, which will be normalized inside creation function
380 auto *const normalizedType3 = checker->CreateETSUnionType(std::move(unionConstituents3));
381 ASSERT_NE(normalizedType3, nullptr);
382 auto *const unionType = normalizedType3->AsETSUnionType();
383 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE2);
384 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), derived1Type);
385 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), derived2Type);
386
387 // Test normalization: Derived2 | Base | Derived1 ==> Base
388 ArenaVector<checker::Type *> unionConstituents4(checker->Allocator()->Adapter());
389 unionConstituents4.emplace_back(derived1Type);
390 unionConstituents4.emplace_back(baseType);
391 unionConstituents4.emplace_back(derived2Type);
392
393 // Create union type, which will be normalized inside creation function
394 auto *const normalizedType4 = checker->CreateETSUnionType(std::move(unionConstituents4));
395 ASSERT_NE(normalizedType4, nullptr);
396 ASSERT_TRUE(normalizedType4->IsETSObjectType());
397 ASSERT_EQ(normalizedType4, baseType);
398 }
399
TEST_F(UnionNormalizationTest, DISABLED_UnionLinearization)400 TEST_F(UnionNormalizationTest, DISABLED_UnionLinearization)
401 {
402 // Test 3 cases of normalization
403 static constexpr std::string_view SRC =
404 "\
405 class Base {}\
406 class Derived1 extends Base {}\
407 class Derived2 extends Base {}\
408 type UT = int | string\
409 \
410 type UT1 = int | (int | string) | number\
411 type UT2 = int | UT | number\
412 type UT3 = int | (Derived2 | Base) | Derived1 | (string | number | short) | (int | string)\
413 ";
414 InitializeChecker("_.sts", SRC);
415
416 auto program = Program();
417 ASSERT(program);
418
419 auto *varbinder = program->VarBinder()->AsETSBinder();
420 auto *const baseType = FindClassType(varbinder, "Base");
421 ASSERT_NE(baseType, nullptr);
422 auto *const derived1Type = FindClassType(program->VarBinder()->AsETSBinder(), "Derived1");
423 ASSERT_NE(derived1Type, nullptr);
424 auto *const derived2Type = FindClassType(program->VarBinder()->AsETSBinder(), "Derived2");
425 ASSERT_NE(derived2Type, nullptr);
426
427 auto checker = Checker();
428 ASSERT(checker);
429
430 // Test normalization: int | (int | string) | number ==> string | number
431 auto *const ut1Type = FindTypeAlias(checker, "UT1");
432 ASSERT_NE(ut1Type, nullptr);
433 ASSERT_TRUE(ut1Type->IsETSUnionType());
434 auto *ut1 = ut1Type->AsETSUnionType();
435 ASSERT_EQ(ut1->ConstituentTypes().size(), SIZE2);
436 ASSERT_EQ(ut1->ConstituentTypes().at(IDX0), checker->GlobalBuiltinETSStringType());
437 ASSERT_EQ(ut1->ConstituentTypes().at(IDX1), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
438
439 // Test normalization: int | UT | number ==> string | number
440 auto *const ut2Type = FindTypeAlias(checker, "UT2");
441 ASSERT_NE(ut2Type, nullptr);
442 ASSERT_TRUE(ut2Type->IsETSUnionType());
443 auto *ut2 = ut2Type->AsETSUnionType();
444 ASSERT_EQ(ut2->ConstituentTypes().size(), SIZE2);
445 ASSERT_EQ(ut2->ConstituentTypes().at(IDX0), checker->GlobalBuiltinETSStringType());
446 ASSERT_EQ(ut2->ConstituentTypes().at(IDX1), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
447
448 // Test normalization:
449 // int | (Derived2 | Base) | Derived1 | (string | number | short) | (int | string) ==> Base | string | number
450 auto *const ut3Type = FindTypeAlias(checker, "UT3");
451 ASSERT_NE(ut3Type, nullptr);
452 ASSERT_TRUE(ut3Type->IsETSUnionType());
453 auto *ut3 = ut3Type->AsETSUnionType();
454 ASSERT_EQ(ut3->ConstituentTypes().size(), SIZE3);
455 ASSERT_EQ(ut3->ConstituentTypes().at(IDX0), baseType);
456 ASSERT_EQ(ut3->ConstituentTypes().at(IDX1), checker->GlobalBuiltinETSStringType());
457 ASSERT_EQ(ut3->ConstituentTypes().at(IDX2), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
458 }
459
TEST_F(UnionNormalizationTest, UnionStringLiterals1)460 TEST_F(UnionNormalizationTest, UnionStringLiterals1)
461 {
462 InitializeChecker("_.sts", "");
463
464 auto checker = Checker();
465 ASSERT(checker);
466
467 // Test normalization: string | "abc" ==> string
468 ArenaVector<checker::Type *> unionConstituents1(checker->Allocator()->Adapter());
469 unionConstituents1.emplace_back(checker->GlobalBuiltinETSStringType());
470 unionConstituents1.emplace_back(checker->CreateETSStringLiteralType("abc"));
471
472 // Create union type, which will be normalized inside creation function
473 auto *const normalizedType1 = checker->CreateETSUnionType(std::move(unionConstituents1));
474 ASSERT_NE(normalizedType1, nullptr);
475 ASSERT_TRUE(normalizedType1->IsETSObjectType());
476 ASSERT_EQ(normalizedType1, checker->GlobalBuiltinETSStringType());
477
478 // Test normalization: "abc" | string | string ==> string
479 ArenaVector<checker::Type *> unionConstituents2(checker->Allocator()->Adapter());
480 unionConstituents2.emplace_back(checker->CreateETSStringLiteralType("abc"));
481 unionConstituents2.emplace_back(checker->GlobalBuiltinETSStringType());
482 unionConstituents2.emplace_back(checker->GlobalBuiltinETSStringType());
483
484 // Create union type, which will be normalized inside creation function
485 auto *const normalizedType2 = checker->CreateETSUnionType(std::move(unionConstituents2));
486 ASSERT_NE(normalizedType2, nullptr);
487 ASSERT_TRUE(normalizedType2->IsETSObjectType());
488 ASSERT_EQ(normalizedType2, checker->GlobalBuiltinETSStringType());
489
490 // Test normalization: number | "abc" | string | "xy" ==> number | string
491 ArenaVector<checker::Type *> unionConstituents3(checker->Allocator()->Adapter());
492 unionConstituents3.emplace_back(checker->GlobalDoubleType());
493 unionConstituents3.emplace_back(checker->CreateETSStringLiteralType("abc"));
494 unionConstituents3.emplace_back(checker->GlobalBuiltinETSStringType());
495 unionConstituents3.emplace_back(checker->CreateETSStringLiteralType("xy"));
496
497 // Create union type, which will be normalized inside creation function
498 auto *const normalizedType3 = checker->CreateETSUnionType(std::move(unionConstituents3));
499 ASSERT_NE(normalizedType3, nullptr);
500 ASSERT_TRUE(normalizedType3->IsETSUnionType());
501 auto *const unionType = normalizedType3->AsETSUnionType();
502 ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE2);
503 ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
504 ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), checker->GlobalBuiltinETSStringType());
505
506 // Test normalization: "abcd" | "abcd" | "abcd" ==> "abcd"
507 ArenaVector<checker::Type *> unionConstituents4(checker->Allocator()->Adapter());
508 unionConstituents4.emplace_back(checker->CreateETSStringLiteralType("abcd"));
509 unionConstituents4.emplace_back(checker->CreateETSStringLiteralType("abcd"));
510 unionConstituents4.emplace_back(checker->CreateETSStringLiteralType("abcd"));
511
512 // Create union type, which will be normalized inside creation function
513 auto *const normalizedType4 = checker->CreateETSUnionType(std::move(unionConstituents4));
514 ASSERT_NE(normalizedType4, nullptr);
515 ASSERT_TRUE(normalizedType4->IsETSStringType());
516 ASSERT_EQ(normalizedType4->AsETSStringType()->GetValue(), "abcd");
517 }
518
TEST_F(UnionNormalizationTest, UnionStringLiterals2)519 TEST_F(UnionNormalizationTest, UnionStringLiterals2)
520 {
521 InitializeChecker("_.sts", "");
522
523 auto checker = Checker();
524 ASSERT(checker);
525
526 // Test absence of normalization: "ab1" | "bc2" | "cd3" ==> "ab1" | "bc2" | "cd3"
527 ArenaVector<checker::Type *> unionConstituents1(checker->Allocator()->Adapter());
528 unionConstituents1.emplace_back(checker->CreateETSStringLiteralType("ab1"));
529 unionConstituents1.emplace_back(checker->CreateETSStringLiteralType("bc2"));
530 unionConstituents1.emplace_back(checker->CreateETSStringLiteralType("cd3"));
531
532 // Create union type, which will be normalized inside creation function
533 auto *const normalizedType1 = checker->CreateETSUnionType(std::move(unionConstituents1));
534 ASSERT_NE(normalizedType1, nullptr);
535 ASSERT_TRUE(normalizedType1->IsETSUnionType());
536 auto *const unionType1 = normalizedType1->AsETSUnionType();
537 ASSERT_EQ(unionType1->ConstituentTypes().size(), SIZE3);
538 ASSERT_TRUE(unionType1->ConstituentTypes().at(IDX0)->IsETSStringType());
539 ASSERT_EQ(unionType1->ConstituentTypes().at(IDX0)->AsETSStringType()->GetValue(), "ab1");
540 ASSERT_TRUE(unionType1->ConstituentTypes().at(IDX1)->IsETSStringType());
541 ASSERT_EQ(unionType1->ConstituentTypes().at(IDX1)->AsETSStringType()->GetValue(), "bc2");
542 ASSERT_TRUE(unionType1->ConstituentTypes().at(IDX2)->IsETSStringType());
543 ASSERT_EQ(unionType1->ConstituentTypes().at(IDX2)->AsETSStringType()->GetValue(), "cd3");
544
545 // Test normalization: "ab1" | "bc2" | "ab1" ==> "ab1" | "bc2"
546 ArenaVector<checker::Type *> unionConstituents2(checker->Allocator()->Adapter());
547 unionConstituents2.emplace_back(checker->CreateETSStringLiteralType("ab1"));
548 unionConstituents2.emplace_back(checker->CreateETSStringLiteralType("bc2"));
549 unionConstituents2.emplace_back(checker->CreateETSStringLiteralType("ab1"));
550
551 // Create union type, which will be normalized inside creation function
552 auto *const normalizedType2 = checker->CreateETSUnionType(std::move(unionConstituents2));
553 ASSERT_NE(normalizedType2, nullptr);
554 ASSERT_TRUE(normalizedType2->IsETSUnionType());
555 auto *const unionType2 = normalizedType2->AsETSUnionType();
556 ASSERT_EQ(unionType2->ConstituentTypes().size(), SIZE2);
557 ASSERT_TRUE(unionType2->ConstituentTypes().at(IDX0)->IsETSStringType());
558 ASSERT_EQ(unionType2->ConstituentTypes().at(IDX0)->AsETSStringType()->GetValue(), "ab1");
559 ASSERT_TRUE(unionType2->ConstituentTypes().at(IDX1)->IsETSStringType());
560 ASSERT_EQ(unionType2->ConstituentTypes().at(IDX1)->AsETSStringType()->GetValue(), "bc2");
561
562 // Test absence of normalization: "ab1" | "bc2" | "cd3" | string | int ==> string | int
563 ArenaVector<checker::Type *> unionConstituents3(checker->Allocator()->Adapter());
564 unionConstituents3.emplace_back(checker->CreateETSStringLiteralType("ab1"));
565 unionConstituents3.emplace_back(checker->CreateETSStringLiteralType("bc2"));
566 unionConstituents3.emplace_back(checker->CreateETSStringLiteralType("cd3"));
567 unionConstituents3.emplace_back(checker->GlobalBuiltinETSStringType());
568 unionConstituents3.emplace_back(checker->GlobalIntType());
569
570 // Create union type, which will be normalized inside creation function
571 auto *const normalizedType3 = checker->CreateETSUnionType(std::move(unionConstituents3));
572 ASSERT_NE(normalizedType3, nullptr);
573 ASSERT_TRUE(normalizedType3->IsETSUnionType());
574 auto *const unionType3 = normalizedType3->AsETSUnionType();
575 ASSERT_EQ(unionType3->ConstituentTypes().size(), SIZE2);
576 ASSERT_EQ(unionType3->ConstituentTypes().at(IDX0), checker->GlobalBuiltinETSStringType());
577 ASSERT_EQ(unionType3->ConstituentTypes().at(IDX1), checker->GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
578 }
579
TEST_F(UnionNormalizationTest, DISABLED_UnionWithNever)580 TEST_F(UnionNormalizationTest, DISABLED_UnionWithNever)
581 {
582 // Test normalization: int | never | number ==> number
583 InitializeChecker("_.sts", "");
584
585 auto checker = Checker();
586 ASSERT(checker);
587
588 ArenaVector<checker::Type *> unionConstituents(checker->Allocator()->Adapter());
589 unionConstituents.emplace_back(checker->GlobalIntType());
590 unionConstituents.emplace_back(checker->GetGlobalTypesHolder()->GlobalBuiltinNeverType());
591 unionConstituents.emplace_back(checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
592
593 // Create union type, which will be normalized inside creation function
594 auto *const normalizedType = checker->CreateETSUnionType(std::move(unionConstituents));
595 ASSERT_NE(normalizedType, nullptr);
596 ASSERT_TRUE(normalizedType->IsETSObjectType());
597 ASSERT_EQ(normalizedType, checker->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
598 }
599
600 } // namespace ark::es2panda
601