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(), &regSpiller, 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