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 37namespace ark::es2panda { 38 39class UnionNormalizationTest : public testing::Test { 40public: 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 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 58 ArenaAllocator *Allocator() 59 { 60 return allocator_.get(); 61 } 62 63 parser::Program *Program() 64 { 65 return &program_; 66 } 67 68 checker::ETSChecker *Checker() 69 { 70 return &checker_; 71 } 72 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> 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> 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 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 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 174protected: 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 181private: 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 189TEST_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 209TEST_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 240TEST_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 272TEST_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 296TEST_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 328TEST_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 400TEST_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 460TEST_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 519TEST_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 580TEST_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