diff --git a/ets2panda/aot/main.cpp b/ets2panda/aot/main.cpp index 6772ec2a051b1633694c7890eab5e831a1cb7f84..420240cb0ee8c3f829f32ba08e3e68afa017d0f0 100644 --- a/ets2panda/aot/main.cpp +++ b/ets2panda/aot/main.cpp @@ -101,6 +101,15 @@ static int CompileMultipleFiles(es2panda::Compiler &compiler, std::vector &parserInputs, unsigned int returnCode) +{ + for (auto *input : parserInputs) { + delete input; + } + parserInputs.clear(); + return returnCode; +} + static int CompileFromConfig(es2panda::Compiler &compiler, util::Options *options, util::DiagnosticEngine &diagnosticEngine) { @@ -111,6 +120,7 @@ static int CompileFromConfig(es2panda::Compiler &compiler, util::Options *option } std::vector inputs {}; + std::vector parserInputs; unsigned int overallRes = 0; for (auto &[src, dst] : compilationList) { std::ifstream inputStream(src); @@ -120,14 +130,14 @@ static int CompileFromConfig(es2panda::Compiler &compiler, util::Options *option } std::stringstream ss; ss << inputStream.rdbuf(); - auto *parserInput = new std::string(ss.str()); + parserInputs.push_back(new std::string(ss.str())); inputStream.close(); - es2panda::SourceFile input(src, *parserInput, options->IsModule(), std::string_view(dst)); + es2panda::SourceFile input(src, *parserInputs.back(), options->IsModule(), std::string_view(dst)); inputs.push_back(input); } if (options->IsPermArena() && (options->GetExtension() == util::gen::extension::ETS)) { - return CompileMultipleFiles(compiler, inputs, options, diagnosticEngine); + return ReleaseInputsAndReturn(parserInputs, CompileMultipleFiles(compiler, inputs, options, diagnosticEngine)); } for (auto &input : inputs) { @@ -141,7 +151,7 @@ static int CompileFromConfig(es2panda::Compiler &compiler, util::Options *option overallRes |= static_cast(res); } } - return overallRes; + return ReleaseInputsAndReturn(parserInputs, overallRes); } static std::optional> InitializePlugins(std::vector const &names, diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 50390d0209c6e53a92617c2fbd8685d7c4a81a3a..3ad10ac0a1158db97eee77ae9108afeff0dfc05b 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -30,6 +30,7 @@ #include "types/typeFlag.h" #include "util/es2pandaMacros.h" +#include #include namespace ark::es2panda::checker { @@ -2476,6 +2477,31 @@ checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const return objType; } +static void CheckInterfacePropertyCovered(ETSChecker *checker, const ir::ObjectExpression *expr, + checker::ETSObjectType *objType) +{ + std::set propertyNames; + + for (ir::Expression *propExpr : expr->Properties()) { + ir::Expression *key = propExpr->AsProperty()->Key(); + + util::StringView pname; + if (key->IsStringLiteral()) { + pname = key->AsStringLiteral()->Str(); + } else if (key->IsIdentifier()) { + pname = key->AsIdentifier()->Name(); + } + propertyNames.insert(pname); + } + + for (auto *prop : objType->GetAllProperties()) { + if (propertyNames.find(prop->Name()) == propertyNames.end() && + !IsPropertyOptional(prop, checker->GetTypeOfVariable(prop))) { + checker->LogError(diagnostic::PROPERTY_MISSING, {prop->Name(), objType->Name()}, expr->Start()); + } + } +} + void ETSAnalyzer::CheckObjectExprProps(const ir::ObjectExpression *expr, checker::ETSObjectType *objectTypeForProperties, checker::PropertySearchFlags searchFlags) const @@ -2528,6 +2554,8 @@ void ETSAnalyzer::CheckObjectExprProps(const ir::ObjectExpression *expr, if (objType->HasObjectFlag(ETSObjectFlags::REQUIRED)) { checker->ValidateObjectLiteralForRequiredType(objType, expr); + } else if (objType->HasObjectFlag(checker::ETSObjectFlags::INTERFACE)) { + CheckInterfacePropertyCovered(checker, expr, objType); } } diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 9c54d7de71e51e93a42adb637ea575b1384bbeef..0a27aadae20de1e95c82fc862dfb7b0999132fb3 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1617,7 +1617,7 @@ static bool AppendSignatureInfoParam(ETSChecker *checker, SignatureInfo *sigInfo if (!param->IsOptional()) { ++sigInfo->minArgCount; } - ES2PANDA_ASSERT(!param->IsOptional() || + ES2PANDA_ASSERT(!param->IsOptional() || param->Ident()->TsType()->IsTypeError() || checker->Relation()->IsSupertypeOf(param->Ident()->TsType(), checker->GlobalETSUndefinedType())); return true; } diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index 6341a07915301bb57b18aec8fe648f1f1b01d5b0..3bc326155822b3d444b65c31076f1d1d42cf44ae 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -525,6 +525,35 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla newClassDefinition->Variable()->SetTsType(nullptr); } +static void SetupFunctionParams(ir::ScriptFunction *function, varbinder::FunctionParamScope *paramScope, + checker::ETSChecker *checker) +{ + for (auto *params : function->Params()) { + auto *paramExpr = params->AsETSParameterExpression(); + if (paramExpr->Ident()->TypeAnnotation() == nullptr) { + paramExpr->Ident()->SetTsTypeAnnotation(nullptr); + } else { + auto *unionType = + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + checker->ProgramAllocNode( + ArenaVector( + {paramExpr->Ident()->TypeAnnotation(), + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + checker->ProgramAllocNode(checker->ProgramAllocator())}, + checker->ProgramAllocator()->Adapter()), + checker->ProgramAllocator()); + paramExpr->Ident()->SetTsTypeAnnotation(unionType); + unionType->SetParent(paramExpr->Ident()); + } + auto [paramVar, node] = paramScope->AddParamDecl(checker->ProgramAllocator(), checker->VarBinder(), paramExpr); + if (node != nullptr) { + checker->VarBinder()->ThrowRedeclaration(node->Start(), paramVar->Name(), paramVar->Declaration()->Type()); + } + + paramExpr->SetVariable(paramVar); + } +} + // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic ir::MethodDefinition *ETSChecker::CreateNullishAccessor(ir::MethodDefinition *const accessor, ir::TSInterfaceDeclaration *interface) @@ -572,27 +601,8 @@ ir::MethodDefinition *ETSChecker::CreateNullishAccessor(ir::MethodDefinition *co ProgramAllocator()->Adapter()), ProgramAllocator())); } else { - for (auto *params : function->Params()) { - auto *paramExpr = params->AsETSParameterExpression(); - - auto *unionType = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode( - ArenaVector({paramExpr->Ident()->TypeAnnotation(), - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(ProgramAllocator())}, - ProgramAllocator()->Adapter()), - ProgramAllocator()); - paramExpr->Ident()->SetTsTypeAnnotation(unionType); - unionType->SetParent(paramExpr->Ident()); - - auto [paramVar, node] = paramScope->AddParamDecl(ProgramAllocator(), VarBinder(), paramExpr); - if (node != nullptr) { - VarBinder()->ThrowRedeclaration(node->Start(), paramVar->Name(), paramVar->Declaration()->Type()); - } - - paramExpr->SetVariable(paramVar); - } + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + SetupFunctionParams(function, paramScope, this); } nullishAccessor->SetOverloads(ArenaVector(ProgramAllocator()->Adapter())); diff --git a/ets2panda/checker/ts/destructuringContext.cpp b/ets2panda/checker/ts/destructuringContext.cpp index b3f516e2b8800af19064d364d879d5e4c8a8ce20..7fcbc2e9d905ac4dee37558f8e74a2cdf537f4a7 100644 --- a/ets2panda/checker/ts/destructuringContext.cpp +++ b/ets2panda/checker/ts/destructuringContext.cpp @@ -157,6 +157,7 @@ void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *ass ES2PANDA_ASSERT(defaultType != nullptr); if (validateDefault && assignmentPattern->Right()->IsObjectExpression() && assignmentPattern->Left()->IsObjectPattern()) { + ES2PANDA_ASSERT(defaultType != nullptr); ValidateObjectLiteralType(defaultType->AsObjectType(), assignmentPattern->Left()->AsObjectPattern()); } diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 5b08e72fe6e600776d6686a52e1bd0f32e7d4ef2..0a724cf0d7e6f21d80a75d3dfc640b4b1a9d6e4e 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -675,8 +675,7 @@ void ETSGen::BranchIfIsInstance(const ir::AstNode *const node, const VReg srcReg void ETSGen::IsInstance(const ir::AstNode *const node, const VReg srcReg, const checker::Type *target) { target = Checker()->GetApparentType(target); - ES2PANDA_ASSERT(target != nullptr); - ES2PANDA_ASSERT(target->IsETSReferenceType() && GetAccumulatorType() != nullptr); + ES2PANDA_ASSERT(target != nullptr && target->IsETSReferenceType() && GetAccumulatorType() != nullptr); if (target->IsETSAnyType()) { // should be IsSupertypeOf(target, source) LoadAccumulatorBoolean(node, true); @@ -1978,6 +1977,7 @@ static std::optional> SelectL ES2PANDA_ASSERT(alhs != nullptr && arhs != nullptr); alhs = alhs->IsETSStringType() ? checker->GlobalBuiltinETSStringType() : alhs; arhs = arhs->IsETSStringType() ? checker->GlobalBuiltinETSStringType() : arhs; + ES2PANDA_ASSERT(alhs != nullptr && arhs != nullptr); if (!alhs->IsETSObjectType() || !arhs->IsETSObjectType()) { return std::nullopt; } diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 8aea0d5139bdc7265b746ebac9a767967831edb6..cd36b35536ca68b350e211dba1cc2ac976942337 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -389,10 +389,21 @@ static bool ExecuteParsingAndCompiling(const CompilationUnit &unit, public_lib:: return !context->diagnosticEngine->IsAnyError(); } +static pandasm::Program *ClearContextAndReturnProgam(public_lib::Context *context, pandasm::Program *program) +{ + context->config = nullptr; + context->parser = nullptr; + context->ClearCheckers(); + context->ClearAnalyzers(); + context->phaseManager = nullptr; + context->parserProgram = nullptr; + context->emitter = nullptr; + return program; +} + template -static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *compilerImpl, - [[maybe_unused]] public_lib::Context *context) +static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *compilerImpl, public_lib::Context *context) { ir::DisableContextHistory(); auto config = public_lib::ConfigImpl {}; @@ -438,11 +449,11 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp context->GetChecker()->Initialize(varbinder); if (!ExecuteParsingAndCompiling(unit, context)) { - return nullptr; + return ClearContextAndReturnProgam(context, nullptr); } MarkAsLowered(program); - return EmitProgram(compilerImpl, context, unit); + return ClearContextAndReturnProgam(context, EmitProgram(compilerImpl, context, unit)); } pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit, public_lib::Context *context) diff --git a/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp index 901046c0779895a5ad1c2f3ea9c424f54a5eefae..2c7afb91de09f6858c4fe0525b746f225d4ed6b4 100644 --- a/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp @@ -98,6 +98,7 @@ static void TransformFunction(public_lib::Context *ctx, ir::ScriptFunction *func } if (param->AsETSParameterExpression()->TypeAnnotation() == nullptr) { // #23134 ES2PANDA_ASSERT(ctx->diagnosticEngine->IsAnyError()); + param->AsETSParameterExpression()->SetInitializer(nullptr); continue; } defaultParams.push_back(param->AsETSParameterExpression()); diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index 8db2e4c678fc9769adbcfd0cfafe417f656c7ac7..7e515ade280dd78092e65c5dd5ff2ff324bcae97 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -167,6 +167,7 @@ template auto *const arrayClassProp = AllocNode( arrayIdent, arrayExpr, typeAnnotation, ir::ModifierFlags::STATIC | ir::ModifierFlags::PRIVATE | ir::ModifierFlags::READONLY, Allocator(), false); + ES2PANDA_ASSERT(arrayClassProp != nullptr); arrayClassProp->SetParent(enumClass); enumClass->EmplaceBody(arrayClassProp); @@ -345,6 +346,7 @@ void EnumLoweringPhase::CreateCCtorForEnumClass(ir::ClassDefinition *const enumC ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::HIDDEN, ir::ModifierFlags::STATIC, Language(Language::Id::ETS)}); + ES2PANDA_ASSERT(func != nullptr); func->SetIdent(id); id->SetParent(func); @@ -354,6 +356,7 @@ void EnumLoweringPhase::CreateCCtorForEnumClass(ir::ClassDefinition *const enumC auto *const methodDef = AllocNode(ir::MethodDefinitionKind::METHOD, identClone, funcExpr, ir::ModifierFlags::PRIVATE | ir::ModifierFlags::STATIC, Allocator(), false); + ES2PANDA_ASSERT(methodDef != nullptr); methodDef->SetParent(enumClass); enumClass->EmplaceBody(methodDef); } diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index c5a750ef4538fe80e89d750b8958610e26b9c6ee..9ffb2732ec79529dfbc8f6fae64ab9a5ed0e3395 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -78,6 +78,7 @@ ir::FunctionSignature InterfacePropertyDeclarationsPhase::GenerateGetterOrSetter if (isSetter) { auto paramIdent = field->Key()->AsIdentifier()->Clone(ctx->Allocator(), nullptr); + ES2PANDA_ASSERT(paramIdent != nullptr); paramIdent->SetTsTypeAnnotation(field->TypeAnnotation()->Clone(ctx->Allocator(), nullptr)); paramIdent->TypeAnnotation()->SetParent(paramIdent); @@ -86,6 +87,7 @@ ir::FunctionSignature InterfacePropertyDeclarationsPhase::GenerateGetterOrSetter InitScopesPhaseETS::RunExternalNode(paramIdent, varbinder); auto *const paramExpression = ctx->AllocNode(paramIdent, false, ctx->Allocator()); + ES2PANDA_ASSERT(paramExpression != nullptr); paramExpression->SetRange(paramIdent->Range()); auto [paramVar, node] = paramScope->AddParamDecl(ctx->Allocator(), varbinder, paramExpression); if (node != nullptr) { @@ -109,6 +111,7 @@ ir::MethodDefinition *InterfacePropertyDeclarationsPhase::GenerateGetterOrSetter auto classScope = NearestScope(field); auto *paramScope = ctx->Allocator()->New(ctx->Allocator(), classScope); auto *functionScope = ctx->Allocator()->New(ctx->Allocator(), paramScope); + ES2PANDA_ASSERT(functionScope != nullptr); functionScope->BindParamScope(paramScope); paramScope->BindFunctionScope(functionScope); @@ -256,6 +259,7 @@ ir::Expression *InterfacePropertyDeclarationsPhase::UpdateInterfaceProperties(pu } auto newInterface = ctx->AllocNode(std::move(newPropertyList)); + ES2PANDA_ASSERT(newInterface != nullptr); newInterface->SetRange(interface->Range()); newInterface->SetParent(interface->Parent()); diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp index 2e0b7f832828cc433c8c1ba42d5b2a46c36a4c2b..c57d29aa9c42cc26a8043da38705095c8a7b9e2e 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp @@ -71,7 +71,7 @@ ir::Expression *ObjectIndexLowering::ProcessIndexSetAccess(parser::ETSParser *pa memberExpression->Property(), assignmentExpression->Right()); setter = loweringResult; } - ES2PANDA_ASSERT(loweringResult != nullptr); + ES2PANDA_ASSERT(loweringResult != nullptr && setter != nullptr); loweringResult->SetParent(assignmentExpression->Parent()); loweringResult->SetRange(assignmentExpression->Range()); setter->AddModifier(ir::ModifierFlags::ARRAY_SETTER); diff --git a/ets2panda/compiler/lowering/ets/objectIterator.cpp b/ets2panda/compiler/lowering/ets/objectIterator.cpp index fa649a253b355362e9b22d1131806ce514227d1b..94293d00790f41d5e44f62ce58d8702276c3e6fb 100644 --- a/ets2panda/compiler/lowering/ets/objectIterator.cpp +++ b/ets2panda/compiler/lowering/ets/objectIterator.cpp @@ -159,6 +159,7 @@ ir::Statement *ObjectIteratorLowering::ProcessObjectIterator(public_lib::Context loopVariableIdent = declaration->Declarators().at(0U)->Id()->AsIdentifier()->Clone(allocator, nullptr); } else if (left->IsIdentifier()) { loopVariableIdent = Gensym(allocator); + ES2PANDA_ASSERT(loopVariableIdent != nullptr); loopVariableIdent->SetName(left->AsIdentifier()->Name()); } else { ES2PANDA_UNREACHABLE(); @@ -167,7 +168,7 @@ ir::Statement *ObjectIteratorLowering::ProcessObjectIterator(public_lib::Context // Parse ArkTS code string and create corresponding AST nodes auto *const parser = ctx->parser->AsETSParser(); - ES2PANDA_ASSERT(parser != nullptr); + ES2PANDA_ASSERT(parser != nullptr && nextIdent != nullptr && iterIdent != nullptr); auto *const loweringResult = parser->CreateFormattedStatement( whileStatement, iterIdent, forOfStatement->Right(), nextIdent, iterIdent->Clone(allocator, nullptr), diff --git a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp index b593f51c3ea2f5a501ea4eab9d648872a500e33a..0a17664868cd5e997a8ef6118da133af8e2287ca 100644 --- a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp @@ -192,6 +192,7 @@ static void GenerateNewStatements(public_lib::Context *ctx, ir::ObjectExpression // Generating: let : = new (); auto *genSymIdent = Gensym(allocator); auto *type = ctx->AllocNode(classType, allocator); + ES2PANDA_ASSERT(genSymIdent != nullptr && type != nullptr); ss << "let @@I" << addNode(genSymIdent) << ": @@T" << addNode(type) << " = new @@T" << addNode(type->Clone(allocator, nullptr)) << "();" << std::endl; @@ -225,7 +226,6 @@ static void GenerateNewStatements(public_lib::Context *ctx, ir::ObjectExpression if (isAnonymous && CheckReadonlyAndUpdateCtorArgs(keyIdent, value, ctorArgumentsMap)) { continue; } - ES2PANDA_ASSERT(genSymIdent != nullptr); ss << "@@I" << addNode(genSymIdent->Clone(allocator, nullptr)) << ".@@I" << addNode(keyIdent); if (value->IsBlockExpression()) { diff --git a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp index 952da6e17e77bb3262b7b5d53183e18593c055f4..8378bdad0be5a2cce5625e4a1ea982738ba4f879 100644 --- a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp @@ -34,9 +34,13 @@ static ir::BlockExpression *CreateRestArgsBlockExpression(public_lib::Context *c ArenaVector blockStatements(allocator->Adapter()); const auto arraySymbol = Gensym(allocator); + ES2PANDA_ASSERT(arraySymbol != nullptr); const auto argumentSymbol = Gensym(allocator); + ES2PANDA_ASSERT(argumentSymbol != nullptr); const auto iteratorIndex = Gensym(allocator); + ES2PANDA_ASSERT(iteratorIndex != nullptr); const auto iteratorSymbol = Gensym(allocator); + ES2PANDA_ASSERT(iteratorSymbol != nullptr); const auto elementType = checker->GetElementTypeOfArray(spreadElement->Argument()->TsType()); auto *typeNode = allocator->New(elementType, allocator); blockStatements.push_back( @@ -51,7 +55,6 @@ static ir::BlockExpression *CreateRestArgsBlockExpression(public_lib::Context *c args.emplace_back(argumentSymbol->Clone(allocator, nullptr)); ss << "@@I3[@@I4] = @@I5;"; args.emplace_back(arraySymbol->Clone(allocator, nullptr)); - ES2PANDA_ASSERT(iteratorIndex != nullptr); args.emplace_back(iteratorIndex->Clone(allocator, nullptr)); args.emplace_back(iteratorSymbol->Clone(allocator, nullptr)); ss << "@@I6 = @@I7 + 1;"; @@ -116,6 +119,7 @@ static ir::Expression *CreateRestArgsArray(public_lib::Context *context, ArenaVe // ss << "Array.from<@@T4>(@@I5);"; // Now: // NOTE: refactor me! + ES2PANDA_ASSERT(genSymIdent != nullptr && genSymIdent2 != nullptr); ss << "let @@I1 : FixedArray<@@T2> = @@E3;"; ss << "let @@I4 : Array<@@T5> = new Array<@@T6>(@@I7.length);"; ss << "for (let i = 0; i < @@I8.length; ++i) { @@I9[i] = @@I10[i]}"; diff --git a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp index 14aff4b6162842269fd1bdc94c1ecb81d9f4eee3..d584a899fa689733b93f2db1a09c3ad8ac222032 100644 --- a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp @@ -213,6 +213,7 @@ ir::ArrayExpression *CreateArrayExpression(public_lib::Context *ctx, const Arena for (auto tupleElementAnno : newRestParams) { auto &tupleElementName = tupleElementAnno->AsETSParameterExpression()->Ident()->AsIdentifier()->Name(); ir::Expression *arg = ctx->AllocNode(tupleElementName, allocator); + ES2PANDA_ASSERT(arg != nullptr); arg->SetParent(arrayExpr); elements.push_back(arg); } @@ -268,7 +269,9 @@ ir::ScriptFunction *CreateNewScriptFunction(public_lib::Context *ctx, ir::Script ArenaVector annotationUsages {allocator->Adapter()}; for (auto *annotationUsage : scriptFunc->Annotations()) { - annotationUsages.push_back(annotationUsage->Clone(allocator, newScriptFunc)->AsAnnotationUsage()); + auto *newAnnotationUsage = annotationUsage->Clone(allocator, newScriptFunc); + ES2PANDA_ASSERT(newAnnotationUsage != nullptr); + annotationUsages.push_back(newAnnotationUsage->AsAnnotationUsage()); } newScriptFunc->SetAnnotations(std::move(annotationUsages)); diff --git a/ets2panda/compiler/lowering/ets/spreadLowering.cpp b/ets2panda/compiler/lowering/ets/spreadLowering.cpp index 416e61cd70cc1a7e495a3c02326c7aa44612bae5..fe71baaaf67590f856dc015f7b303a87fae37d15 100644 --- a/ets2panda/compiler/lowering/ets/spreadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/spreadLowering.cpp @@ -87,6 +87,7 @@ static ir::Identifier *CreateNewArrayDeclareStatement(public_lib::Context *ctx, auto *const allocator = ctx->allocator; auto *const parser = ctx->parser->AsETSParser(); ir::Identifier *newArrayId = Gensym(allocator); + ES2PANDA_ASSERT(newArrayId != nullptr); checker::Type *arrayElementType = checker->GetElementTypeOfArray(array->TsType()); // NOTE: If arrayElementType is ETSUnionType(String|Int) or ETSObjectType(private constructor) or ..., we cannot @@ -335,6 +336,7 @@ static ir::BlockExpression *CreateLoweredExpressionForArray(public_lib::Context ir::Identifier *newArrayId = CreateNewArrayDeclareStatement(ctx, array, statements, newArrayLengthId); ES2PANDA_ASSERT(newArrayId != nullptr); ir::Identifier *newArrayIndexId = Gensym(allocator); + ES2PANDA_ASSERT(newArrayIndexId != nullptr); statements.emplace_back( parser->CreateFormattedStatement("let @@I1 = 0", newArrayIndexId->Clone(allocator, nullptr))); std::vector newArrayAndIndex {newArrayId->Clone(allocator, nullptr), diff --git a/ets2panda/compiler/lowering/ets/stringComparison.cpp b/ets2panda/compiler/lowering/ets/stringComparison.cpp index e25361a7102bac98a576822d2bf4b416c8ff4858..68d18c745e13857b8c481ae05cb54c014c1ffd4d 100644 --- a/ets2panda/compiler/lowering/ets/stringComparison.cpp +++ b/ets2panda/compiler/lowering/ets/stringComparison.cpp @@ -84,6 +84,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp auto *zeroExpr = checker->AllocNode(lexer::Number(int32_t(0))); auto *const callee = checker->AllocNode("compareTo", checker->Allocator()); ES2PANDA_ASSERT(callee != nullptr); + ES2PANDA_ASSERT(checker->GlobalBuiltinETSStringType() != nullptr); auto *var = checker->GlobalBuiltinETSStringType()->GetProperty(callee->AsIdentifier()->Name(), checker::PropertySearchFlags::SEARCH_METHOD); callee->SetVariable(var); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index 63ee3413895e9c4325faca5556212787c9c89769..857b07c9a05c26cb536034e9bbbdeea6f8cda9be 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -159,6 +159,7 @@ ir::ClassDeclaration *GlobalClassHandler::CreateTransformedClass(ir::ETSModule * { auto className = ns->Ident()->Name(); auto *ident = NodeAllocator::Alloc(allocator_, className, allocator_); + ES2PANDA_ASSERT(ident != nullptr); ident->SetRange(ns->Ident()->Range()); auto *classDef = NodeAllocator::Alloc(allocator_, allocator_, ident, @@ -168,6 +169,8 @@ ir::ClassDeclaration *GlobalClassHandler::CreateTransformedClass(ir::ETSModule * classDef->SetRange(ns->Range()); classDef->AddModifier(ns->Modifiers()); auto *classDecl = NodeAllocator::Alloc(allocator_, classDef, allocator_); + ES2PANDA_ASSERT(classDecl != nullptr); + classDecl->SetRange(ns->Range()); classDecl->AddModifier(ns->Modifiers()); classDef->SetNamespaceTransformed(); ArenaVector annotations {allocator_->Adapter()}; @@ -427,6 +430,7 @@ ir::MethodDefinition *GlobalClassHandler::CreateGlobalMethod(const std::string_v const auto functionFlags = ir::ScriptFunctionFlags::NONE; auto functionModifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC; auto ident = NodeAllocator::Alloc(allocator_, name, allocator_); + ES2PANDA_ASSERT(ident != nullptr); auto body = NodeAllocator::ForceSetParent(allocator_, allocator_, std::move(statements)); auto funcSignature = ir::FunctionSignature(nullptr, ArenaVector(allocator_->Adapter()), nullptr); @@ -439,9 +443,12 @@ ir::MethodDefinition *GlobalClassHandler::CreateGlobalMethod(const std::string_v func->AddModifier(functionModifiers); auto *funcExpr = NodeAllocator::Alloc(allocator_, func); + auto *identClone = ident->Clone(allocator_, nullptr); + ES2PANDA_ASSERT(identClone != nullptr); auto *methodDef = NodeAllocator::Alloc(allocator_, ir::MethodDefinitionKind::METHOD, - ident->Clone(allocator_, nullptr)->AsExpression(), - funcExpr, functionModifiers, allocator_, false); + identClone->AsExpression(), funcExpr, + functionModifiers, allocator_, false); + ES2PANDA_ASSERT(methodDef != nullptr); auto minBound = lexer::SourcePosition(globalProgram_); auto maxBound = lexer::SourcePosition(globalProgram_); if (!body->Statements().empty()) { @@ -498,6 +505,7 @@ void GlobalClassHandler::AddInitCallToStaticBlock(ir::ClassDefinition *globalCla auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); auto exprStmt = NodeAllocator::Alloc(allocator_, callExpr); + ES2PANDA_ASSERT(exprStmt != nullptr); exprStmt->SetParent(blockBody); blockBody->AddStatement(exprStmt); } @@ -598,6 +606,7 @@ ir::ClassStaticBlock *GlobalClassHandler::CreateStaticBlock(ir::ClassDefinition auto *funcExpr = NodeAllocator::Alloc(allocator_, func); auto *staticBlock = NodeAllocator::Alloc(allocator_, funcExpr, allocator_); + ES2PANDA_ASSERT(staticBlock != nullptr); staticBlock->AddModifier(ir::ModifierFlags::STATIC); staticBlock->SetRange({classDef->Start(), classDef->Start()}); return staticBlock; @@ -648,6 +657,7 @@ ir::ClassDeclaration *GlobalClassHandler::CreateGlobalClass(const parser::Progra const auto rangeToStartOfFile = lexer::SourceRange(lexer::SourcePosition(globalProgram), lexer::SourcePosition(globalProgram)); auto *ident = NodeAllocator::Alloc(allocator_, compiler::Signatures::ETS_GLOBAL, allocator_); + ES2PANDA_ASSERT(ident != nullptr); ident->SetRange(rangeToStartOfFile); auto *classDef = NodeAllocator::Alloc(allocator_, allocator_, ident, ir::ClassDefinitionModifiers::GLOBAL, @@ -655,6 +665,7 @@ ir::ClassDeclaration *GlobalClassHandler::CreateGlobalClass(const parser::Progra ES2PANDA_ASSERT(classDef != nullptr); classDef->SetRange(rangeToStartOfFile); auto *classDecl = NodeAllocator::Alloc(allocator_, classDef, allocator_); + ES2PANDA_ASSERT(classDecl != nullptr); classDecl->SetRange(rangeToStartOfFile); return classDecl; diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp index a5abdb80a0c90ccb91bf45aa3d008e944b584258..2ec4129350c4f25fe2933c2ba7fa249bfa4c4814 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp @@ -75,6 +75,7 @@ void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *fu auto *method = util::NodeAllocator::ForceSetParent( allocator_, methodKind, funcDecl->Function()->Id()->Clone(allocator_, nullptr), funcExpr, funcDecl->Function()->Modifiers(), allocator_, false); + ES2PANDA_ASSERT(method != nullptr && method->Function() != nullptr); method->SetRange(funcDecl->Range()); method->Function()->SetAnnotations(funcDecl->Annotations()); @@ -97,6 +98,7 @@ void GlobalDeclTransformer::VisitVariableDeclaration(ir::VariableDeclaration *va currentModule_->AsETSModule()->Program()->IsPackage(); auto *field = util::NodeAllocator::ForceSetParent( allocator_, id->Clone(allocator_, nullptr), declarator->Init(), typeAnn, modifiers, allocator_, false); + ES2PANDA_ASSERT(field != nullptr); field->SetInitInStaticBlock(needInitializeInStaticBlock); field->SetRange(declarator->Range()); @@ -104,7 +106,9 @@ void GlobalDeclTransformer::VisitVariableDeclaration(ir::VariableDeclaration *va ArenaVector propAnnotations(allocator_->Adapter()); for (auto *annotationUsage : varDecl->Annotations()) { ES2PANDA_ASSERT(annotationUsage != nullptr); - propAnnotations.push_back(annotationUsage->Clone(allocator_, field)->AsAnnotationUsage()); + auto annotationUsageClone = annotationUsage->Clone(allocator_, field); + ES2PANDA_ASSERT(annotationUsageClone != nullptr); + propAnnotations.push_back(annotationUsageClone->AsAnnotationUsage()); } field->SetAnnotations(std::move(propAnnotations)); } @@ -172,12 +176,14 @@ ir::Identifier *GlobalDeclTransformer::RefIdent(const util::StringView &name) ir::ExpressionStatement *GlobalDeclTransformer::InitTopLevelProperty(ir::ClassProperty *classProperty) { const auto initializer = classProperty->Value(); + ES2PANDA_ASSERT(classProperty->Id() != nullptr); if (classProperty->IsConst() || initializer == nullptr) { classProperty->SetStart(classProperty->Id()->Start()); return nullptr; } auto const ident = RefIdent(classProperty->Id()->Name()); + ES2PANDA_ASSERT(ident != nullptr); ident->SetRange(classProperty->Id()->Range()); initializer->SetParent(nullptr); @@ -188,6 +194,7 @@ ir::ExpressionStatement *GlobalDeclTransformer::InitTopLevelProperty(ir::ClassPr assignmentExpression->SetTsType(initializer->TsType()); auto expressionStatement = util::NodeAllocator::Alloc(allocator_, assignmentExpression); + ES2PANDA_ASSERT(expressionStatement != nullptr); expressionStatement->SetRange(classProperty->Range()); classProperty->SetRange({ident->Start(), initializer->End()}); diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index aba0545179c38049cc67eca93b8c66cf50fc1b2d..1710ce3ed435369006874e8868836757f14cc2ca 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -57,6 +57,7 @@ static ir::ClassDefinition *GetUnionAccessClass(public_lib::Context *ctx, varbin util::UString unionFieldClassName(util::StringView(name), allocator); auto *ident = ctx->AllocNode(unionFieldClassName.View(), allocator); auto [decl, var] = varbinder->NewVarDecl(ident->Start(), ident->Name()); + ES2PANDA_ASSERT(ident != nullptr); ident->SetVariable(var); auto classCtx = varbinder::LexicalScope(varbinder); @@ -65,6 +66,7 @@ static ir::ClassDefinition *GetUnionAccessClass(public_lib::Context *ctx, varbin ES2PANDA_ASSERT(classDef != nullptr); classDef->SetScope(classCtx.GetScope()); auto *classDecl = ctx->AllocNode(classDef, allocator); + ES2PANDA_ASSERT(classDecl != nullptr); classDef->Scope()->BindNode(classDecl->Definition()); decl->BindNode(classDef); var->SetScope(classDef->Scope()); @@ -84,8 +86,9 @@ static std::tuple CreateNamedA { auto *allocator = ctx->Allocator(); auto *checker = ctx->GetChecker()->AsETSChecker(); - - auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); + auto apparentType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType())); + ES2PANDA_ASSERT(apparentType != nullptr); + auto unionType = apparentType->AsETSUnionType(); auto *const accessClass = GetUnionAccessClass(ctx, varbinder, GetAccessClassName(unionType)); auto methodName = expr->TsType()->AsETSFunctionType()->Name(); @@ -104,7 +107,7 @@ static std::tuple CreateNamedA nullptr, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnno), // CC-OFFNXT(G.FMT.02-CPP) project code style ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC}); - ES2PANDA_ASSERT(func != nullptr); + ES2PANDA_ASSERT(func != nullptr && methodIdent != nullptr); func->SetIdent(methodIdent->Clone(allocator, nullptr)); // Create the synthetic function node @@ -124,7 +127,7 @@ static std::tuple CreateNamedA auto boundCtx = varbinder::BoundContext(varbinder->AsETSBinder()->GetRecordTable(), accessClass, true); CheckLoweredNode(varbinder->AsETSBinder(), checker, method); } - + ES2PANDA_ASSERT(method->Id() != nullptr && method->TsType() != nullptr); return {method->Id()->Variable()->AsLocalVariable(), method->TsType()->AsETSFunctionType()->CallSignatures().front()}; } @@ -135,7 +138,9 @@ static varbinder::LocalVariable *CreateNamedAccessProperty(public_lib::Context * auto *const allocator = ctx->Allocator(); auto *checker = ctx->GetChecker()->AsETSChecker(); - auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); + auto apparentType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType())); + ES2PANDA_ASSERT(apparentType != nullptr); + auto unionType = apparentType->AsETSUnionType(); auto *const accessClass = GetUnionAccessClass(ctx, varbinder, GetAccessClassName(unionType)); auto propName = expr->Property()->AsIdentifier()->Name(); auto fieldType = expr->TsType(); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 780c1346a8de45da66b1ccd3040cffeef8875a04..94db1887d7a1c843dd3d7155e8df1401b3c4a36c 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -989,6 +989,7 @@ void InitScopesPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) } const auto methodName = method->Id(); + ES2PANDA_ASSERT(methodName != nullptr); auto *const clsScope = VarBinder()->GetScope()->AsClassScope(); auto options = method->IsStatic() @@ -1029,8 +1030,9 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden methodName->SetVariable(var); } for (auto *overload : method->Overloads()) { - ES2PANDA_ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) || - (overload->Function()->Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)); + ES2PANDA_ASSERT(overload->Id() != nullptr && + ((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) || + (overload->Function()->Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD))); overload->Id()->SetVariable(var); overload->SetParent(var->Declaration()->Node()); } @@ -1210,6 +1212,7 @@ void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) auto *curScope = VarBinder()->GetScope(); const auto methodName = method->Id(); + ES2PANDA_ASSERT(methodName != nullptr); auto res = curScope->Find(methodName->Name(), method->IsStatic() ? varbinder::ResolveBindingOptions::ALL_STATIC : varbinder::ResolveBindingOptions::ALL_NON_STATIC); diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp index 3ea2df1f3241ca2f974408c575931391a8afedc9..f1a78d5555550fe1dd38ca0629d3b1b98c1a215d 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp @@ -618,6 +618,7 @@ void TSDeclGen::GenFunctionType(const checker::ETSFunctionType *etsFunctionType, const bool isSetter = methodDef != nullptr ? methodDef->Kind() == ir::MethodDefinitionKind::SET : false; // CC-OFFNXT(G.FMT.14-CPP) project code style const auto *sig = GetFuncSignature(etsFunctionType, methodDef); + ES2PANDA_ASSERT(sig != nullptr); if (sig->HasFunction()) { GenTypeParameters(sig->Function()->TypeParams()); const auto *funcBody = sig->Function()->Body(); diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index abeb5ba7b8533042cbb7196ce9dc7d0e6e369515..b2cc884429621d8bbd3dc2ee93b97c1175cff8f5 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -143,7 +143,7 @@ export abstract class BaseMode { this.isBuildConfigModified = buildConfig.isBuildConfigModified as boolean | undefined; this.hasCleanWorker = false; this.byteCodeHar = buildConfig.byteCodeHar as boolean; - this.es2pandaMode = buildConfig?.es2pandaMode ?? ES2PANDA_MODE.RUN; + this.es2pandaMode = buildConfig?.es2pandaMode ?? ES2PANDA_MODE.RUN_PARALLEL; this.skipDeclCheck = buildConfig?.skipDeclCheck as boolean ?? true; } diff --git a/ets2panda/ir/brokenTypeNode.cpp b/ets2panda/ir/brokenTypeNode.cpp index 110222066dbaa978f61131669aba4f5c5f98cdc8..05ef63679f55f15117eaf0cf22f9f0ef00f2546b 100644 --- a/ets2panda/ir/brokenTypeNode.cpp +++ b/ets2panda/ir/brokenTypeNode.cpp @@ -72,6 +72,7 @@ checker::VerifiedType BrokenTypeNode::Check([[maybe_unused]] checker::ETSChecker BrokenTypeNode *BrokenTypeNode::Clone(ArenaAllocator *const allocator, AstNode *const parent) { auto *const clone = allocator->New(allocator); + ES2PANDA_ASSERT(clone != nullptr); if (parent != nullptr) { clone->SetParent(parent); } diff --git a/ets2panda/ir/statements/tryStatement.cpp b/ets2panda/ir/statements/tryStatement.cpp index 82d74865c48fce0170ee8973f5dd46710dd83e83..acc5b4d085afe04bd1a49cb404958b038ad7b90d 100644 --- a/ets2panda/ir/statements/tryStatement.cpp +++ b/ets2panda/ir/statements/tryStatement.cpp @@ -125,7 +125,13 @@ TryStatement::TryStatement(TryStatement const &other, ArenaAllocator *allocator) finalizerInsertions_(allocator->Adapter()), finallyCanCompleteNormally_(other.finallyCanCompleteNormally_) { - block_ = other.block_ == nullptr ? nullptr : other.block_->Clone(allocator, this)->AsBlockStatement(); + if (other.block_ == nullptr) { + block_ = nullptr; + } else { + auto *blockClone = other.block_->Clone(allocator, this); + ES2PANDA_ASSERT(blockClone != nullptr); + block_ = blockClone->AsBlockStatement(); + } for (auto &cc : other.catchClauses_) { if (cc == nullptr) { catchClauses_.push_back(nullptr); diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp index 25f14ade82f72d5931bfe9502f0959f89638d253..b07bf528784b9e9d8997cc493fbfde4834650122 100644 --- a/ets2panda/ir/ts/tsTupleType.cpp +++ b/ets2panda/ir/ts/tsTupleType.cpp @@ -89,6 +89,7 @@ checker::Type *GetNumberIndexType(ArenaVector numberIndexTypes, static void SetMemberVarType(checker::Type *memberType, varbinder::LocalVariable *memberVar) { + ES2PANDA_ASSERT(memberType != nullptr); memberType->SetVariable(memberVar); memberVar->SetTsType(memberType); } diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 3c6f3c73de5b11cc81019dc1f47be32d191c59da..a5b2030b296f917421319b0f8accd4c33a0568d3 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -155,7 +155,7 @@ void ETSParser::ParseFileHeaderFlag(lexer::SourcePosition startLoc, ArenaVector< ir::Expression *fileHeaderFlag = ParseStringLiteral(); auto *exprStatementNode = AllocNode(fileHeaderFlag); - + ES2PANDA_ASSERT(exprStatementNode != nullptr); exprStatementNode->SetRange({startLoc, fileHeaderFlag->End()}); ConsumeSemicolon(exprStatementNode); if (statements != nullptr) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 8bbfeecf694dc10ae08b6d088c63f2ba02987d40..0ce7879c46a24d290936f0508380d2b02031972f 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -18,7 +18,6 @@ #include "util/arktsconfig.h" #include "util/importPathManager.h" -#include "util/recursiveGuard.h" #include "innerSourceParser.h" #include "TypedParser.h" #include "ir/base/classDefinition.h" @@ -460,7 +459,6 @@ private: friend class ExternalSourceParser; friend class InnerSourceParser; - friend ir::Expression *HandleLeftParanthesis(ETSParser *parser, ExpressionParseFlags flags); private: uint32_t namespaceNestedRank_; @@ -470,7 +468,6 @@ private: parser::Program *globalProgram_; std::vector insertingNodes_ {}; std::unique_ptr importPathManager_ {nullptr}; - RecursiveContext recursiveCtx_; }; class ExternalSourceParser { diff --git a/ets2panda/parser/ETSparserExpressions.cpp b/ets2panda/parser/ETSparserExpressions.cpp index 707d44ad1b567490b390a61158a971ea58c2bbf9..7422c412b5111d45bb65aa0f52958e16842cffa7 100644 --- a/ets2panda/parser/ETSparserExpressions.cpp +++ b/ets2panda/parser/ETSparserExpressions.cpp @@ -321,26 +321,20 @@ ir::Expression *ETSParser::ParsePrimaryExpressionWithLiterals(ExpressionParseFla } } -// This function is used to handle the left parenthesis in the expression parsing. -ir::Expression *HandleLeftParanthesis(ETSParser *parser, ExpressionParseFlags flags) +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags) { - TrackRecursive trackRecursive(parser->recursiveCtx_); + TrackRecursive trackRecursive(RecursiveCtx()); if (!trackRecursive) { - parser->LogError(diagnostic::DEEP_NESTING); - while (parser->Lexer()->GetToken().Type() != lexer::TokenType::EOS) { - parser->Lexer()->NextToken(); + LogError(diagnostic::DEEP_NESTING); + while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { + Lexer()->NextToken(); } - return parser->AllocBrokenExpression(parser->Lexer()->GetToken().Loc()); + return AllocBrokenExpression(Lexer()->GetToken().Loc()); } - return parser->ParseCoverParenthesizedExpressionAndArrowParameterList(flags); -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags) -{ switch (Lexer()->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - return HandleLeftParanthesis(this, flags); + return ParseCoverParenthesizedExpressionAndArrowParameterList(flags); } case lexer::TokenType::KEYW_THIS: { return ParseThisExpression(); diff --git a/ets2panda/parser/TSparser.cpp b/ets2panda/parser/TSparser.cpp index 4c41a234a3ed0717b0f5940f822f92b59b496a69..69368d4accaa49116bfee617847af2661966416e 100644 --- a/ets2panda/parser/TSparser.cpp +++ b/ets2panda/parser/TSparser.cpp @@ -754,7 +754,7 @@ ir::TSTypeParameter *TSParser::ParseMappedTypeParameter() lexer::SourcePosition endLoc = constraint->End(); auto *typeParameter = AllocNode(paramName, constraint, nullptr, Allocator()); - + ES2PANDA_ASSERT(typeParameter != nullptr); typeParameter->SetRange({startLoc, endLoc}); return typeParameter; diff --git a/ets2panda/parser/TypedParser.cpp b/ets2panda/parser/TypedParser.cpp index 581e8dde2695d6a6b698eb2799ec66883c236bff..474bfaa6efcff784b93eb36a25e5a3d217b9ffaf 100644 --- a/ets2panda/parser/TypedParser.cpp +++ b/ets2panda/parser/TypedParser.cpp @@ -296,7 +296,7 @@ ir::TSModuleDeclaration *TypedParser::ParseAmbientExternalModuleDeclaration(cons name = AllocNode(Lexer()->GetToken().String()); } - + ES2PANDA_ASSERT(name != nullptr); name->SetRange(Lexer()->GetToken().Loc()); Lexer()->NextToken(); @@ -511,6 +511,7 @@ ir::Statement *TypedParser::ParseInterfaceDeclaration(bool isStatic) auto members = ParseTypeLiteralOrInterface(); auto *body = AllocNode(std::move(members)); + ES2PANDA_ASSERT(body != nullptr); body->SetRange({bodyStart, Lexer()->GetToken().End()}); const auto isExternal = IsExternal(); diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index 4f134e6a2ab3df30c418f76ab28e0e50d9a6c4e4..6c9ef85562dc1eccc908aaf9a92dc1e3eb8220fe 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -26,6 +26,7 @@ #include "parser/program/program.h" #include "util/diagnosticEngine.h" #include "util/helpers.h" +#include "util/recursiveGuard.h" namespace ark::es2panda::lexer { class RegExpParser; @@ -574,6 +575,11 @@ protected: const std::function &parseElement, lexer::SourcePosition *sourceEnd = nullptr, bool allowTrailingSep = false); + RecursiveContext &RecursiveCtx() + { + return recursiveCtx_; + } + private: bool GetCanBeForInOf(ir::Expression *leftNode, ir::AstNode *initNode); Program *program_; @@ -584,6 +590,7 @@ private: const util::Options *options_; util::DiagnosticEngine &diagnosticEngine_; public_lib::Context *ctx_ {nullptr}; + RecursiveContext recursiveCtx_; }; } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/statementParser.cpp b/ets2panda/parser/statementParser.cpp index 00a7aae2d608009decf775a404edd7b2236d2d15..aa8941392c94f93c558847fa101f5e805e803858 100644 --- a/ets2panda/parser/statementParser.cpp +++ b/ets2panda/parser/statementParser.cpp @@ -63,6 +63,7 @@ #include "lexer/lexer.h" #include "lexer/token/letters.h" #include "lexer/token/sourceLocation.h" +#include "util/recursiveGuard.h" #include "util/ustring.h" #include "generated/diagnostic.h" @@ -91,6 +92,14 @@ ir::Statement *ParserImpl::ParseStatementLiteralIdentHelper(StatementParsingFlag // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStatementPunctuatorsHelper(StatementParsingFlags flags) { + TrackRecursive trackRecursive(RecursiveCtx()); + if (!trackRecursive) { + LogError(diagnostic::DEEP_NESTING); + while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { + Lexer()->NextToken(); + } + return AllocBrokenStatement(Lexer()->GetToken().Loc()); + } switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: return ParseBlockStatement(); diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index b3cd4ade2b4619c18aa50c9089bc265a130b0ba7..f11571c8e487acf486231bfb0351088061b8d62f 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -176,11 +176,10 @@ struct Context { checkers_.push_back(checker); } - void DestoryCheckers() + // NOTE(zhelyapov): It's calling side responsibility to release resources + void ClearCheckers() { - for (auto item : checkers_) { - delete item; - } + checkers_.clear(); } checker::SemanticAnalyzer *GetAnalyzer() const; @@ -190,11 +189,10 @@ struct Context { return analyzers_.push_back(analyzer); } - void DestoryAnalyzers() + // NOTE(zhelyapov): It's calling side responsibility to release resources + void ClearAnalyzers() { - for (auto item : analyzers_) { - delete item; - } + analyzers_.clear(); } void MarkGenAbcForExternal(std::unordered_set &genAbcList, public_lib::ExternalSource &extSources); diff --git a/ets2panda/test/ast/compiler/ets/readonly_interface_porperty_missing.ets b/ets2panda/test/ast/compiler/ets/readonly_interface_porperty_missing.ets new file mode 100644 index 0000000000000000000000000000000000000000..eaf5d9dc4a47eba79d8032a951229c4c78fabd27 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/readonly_interface_porperty_missing.ets @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface A{ + readonly name: string; +} + +function createA(): A{ + return /* @@ label */{}; +} + +/* @@@ label Error TypeError: Property 'name' is missing but required in type 'A'. */ + diff --git a/ets2panda/test/ast/compiler/ets/type_error_processing/param_typeannotation_null.ets b/ets2panda/test/ast/compiler/ets/type_error_processing/param_typeannotation_null.ets new file mode 100644 index 0000000000000000000000000000000000000000..e23f26a1e73d09f55811c7adb00e3db7161d0a8f --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/type_error_processing/param_typeannotation_null.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface inter { + get value(): Double; + set value(A = Int.MAX_VALUE + 1); +} + +function foo(i: Partial>): void {} + +/* @@? 18:15 Error TypeError: The type of parameter 'A' cannot be inferred */ +/* @@? 18:17 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ diff --git a/ets2panda/test/benchmarks/README.md b/ets2panda/test/benchmarks/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4774895e4db5c49249240e6836aa8118bbf646b5 --- /dev/null +++ b/ets2panda/test/benchmarks/README.md @@ -0,0 +1,76 @@ +# Logic +- Run es2panda for benchmark files from this directory +- Dump perfmetrics to `/test-current-perf.txt` for current es2panda +- Dump perfmetrics to `/test-pre_merge-perf.txt` for another (pre-merge) es2panda +- Dump comparison report to `/test-report.txt` in format like `time=-90.00ms (-1.9%)` + +### Static mode +If `actual_perf > max_perf * (1 + static_regression)` - an error occurs. Example: +``` +[PERF REGRESSION] Failed for bench_1-current-perf.txt: Memory exceeded threshold. + Limit: 5.0%, Actual: +406.25% + Base: 32.00MB, New: 162.00MB + Threshold: < 33.60MB +``` + +If `actual_perf < max_perf * (1 + 3 * static_regression)` - an error occurs. Example: +``` +[UPDATE REQUIRED] Very good perf for bench_1-current-perf.txt: Please update *-max.txt. + Hint: use flag '--dump-perf-metrics' and Release build of es2panda. +``` + +### Dynamic mode +If `actual_perf > pre_merge_perf * dynamic_regression` - an error occurs (the same as in static mode). + +### Errors reporting +Errors are printed to the console and also to `/error_log.txt`. + +# Arguments +- `--mode` - 'static' to compare with `*-max.txt` files. 'dynamic' to compare with pre-merge es2panda. +- `--es2panda` - Path to current es2panda (aka /bin/es2panda) +- `--es2panda-pre-merge` - Path to pre-merge es2panda (aka /bin/es2panda) +- `--test-dir` - Path to test directory with test files +- `--work-dir` - Path to the working temp folder with gen, intermediate and report folders +- `--dynamic-regression` - Acceptable regression compared to the another (pre-merge) es2panda +- `--static-regression` - Acceptable regression compared to static vales from `*-max.txt` files +- `--runs` - The number of runs to average +- `--werror` - Warnings as errors + +# Max values +Each file have companion: for `test.ets` companion is `test-max.txt`. This file contains max values for metrics. + +# Local reproduction +```bash +# static mode +python3 /ets2panda/test/benchmarks/runner/runner.py --mode=static --es2panda=/bin/es2panda --work-dir=/e2p_benchmarks --test-dir=/ets2panda/test/benchmarks + +# dynamic mode +python3 /ets2panda/test/benchmarks/runner/runner.py --mode=dynamic --es2panda=/bin/es2panda --work-dir=/e2p_benchmarks --test-dir=/ets2panda/test/benchmarks --es2panda-pre-merge=/bin/es2panda +``` +See `--help` if needed. + +# CI +You can download artifacts for this job with perf stat. + +# Artifacts example + +test-perf.txt +``` +================ es2panda perf metrics (Averaged over 3 runs) ================ +:@phases : time=891.00ms mem=140.00MB +:@phases/ConstantExpressionLowering : time=233.00ms mem=0.26MB +:@phases/TopLevelStatements : time=193.00ms mem=79.00MB +:@phases/ResolveIdentifiers : time=83.40ms mem=6.00MB +:@phases/CheckerPhase : time=78.60ms mem=19.00MB +``` + +test-report.txt +``` +Performance Comparison: 'bench_1-max.txt' vs 'bench_1-current-perf.txt' +================================================================================ +:@EmitProgram : time=+2.90ms (+4.6%) mem=+0.00MB (+0.0%) +:@GenerateProgram : time=+4.67ms (+6.7%) mem=0.00MB (0.0%) +:@GenerateProgram/OptimizeBytecode : time=0.00ms (0.0%) mem=0.00MB (0.0%) +:@phases : time=+22.67ms (+2.6%) mem=+0.00MB (+0.0%) +:@phases/AmbientLowering : time=-0.07ms (-0.6%) mem=0.00MB (0.0%) +``` diff --git a/ets2panda/test/benchmarks/bench_1-max.txt b/ets2panda/test/benchmarks/bench_1-max.txt new file mode 100644 index 0000000000000000000000000000000000000000..81e3099f82e7696cbb68e727ae0288f68b6eb4ce --- /dev/null +++ b/ets2panda/test/benchmarks/bench_1-max.txt @@ -0,0 +1,66 @@ +================ es2panda perf metrics (Averaged over 500 runs) ================ + +:@phases : time=1472.50ms mem=159.89MB +:@GenerateProgram : time=439.95ms mem=0.00MB +:@phases/ConstantExpressionLowering : time=374.76ms mem=0.30MB +:@phases/TopLevelStatements : time=273.61ms mem=81.00MB +:@GenerateProgram/OptimizeBytecode : time=264.15ms mem=0.00MB +:@EmitProgram : time=148.99ms mem=31.22MB +:@phases/CheckerPhase : time=132.83ms mem=23.28MB +:@phases/ResolveIdentifiers : time=112.03ms mem=6.00MB +:@phases/InterfaceObjectLiteralLowering : time=81.20ms mem=7.00MB +:@phases/LambdaObjectConversion : time=74.07ms mem=5.00MB +:@phases/ScopesInitPhase : time=62.35ms mem=13.79MB +:@phases/PartialExportClassGen : time=45.10ms mem=8.00MB +:@phases/Unbox : time=29.11ms mem=0.74MB +:@phases/OptionalLowering : time=25.61ms mem=0.99MB +:@phases/ResizableArrayConvert : time=22.40ms mem=0.51MB +:@phases/InterfacePropertyDeclarationsPhase : time=21.20ms mem=1.00MB +:@phases/EnumLoweringPhase : time=19.05ms mem=0.81MB +:@phases/EnumPostCheckLoweringPhase : time=18.67ms mem=0.00MB +:@phases/OverloadMappingLowering : time=18.01ms mem=0.00MB +:@phases/DeclareOverloadLowering : time=17.97ms mem=0.00MB +:@phases/PromiseVoidInferencePhase : time=17.90ms mem=0.00MB +:@phases/InsertOptionalParametersAnnotation : time=17.38ms mem=0.74MB +:@phases/AmbientLowering : time=17.22ms mem=0.00MB +:@phases/ExpressionLambdaConstruction : time=17.15ms mem=0.00MB +:@phases/GradualTypeNarrowing : time=16.99ms mem=1.88MB +:@phases/DefaultParametersInConstructorLowering : time=16.67ms mem=0.52MB +:@phases/ObjectIndexLowering : time=3.65ms mem=0.71MB +:@phases/CreateGenericBridges : time=3.36ms mem=0.00MB +:@phases/ArrayLiteralLowering : time=3.24ms mem=0.52MB +:@phases/BoxingForLocals : time=1.64ms mem=0.00MB +:@phases/ObjectLiteralLowering : time=1.50ms mem=0.23MB +:@phases/PrimitiveConversion : time=1.26ms mem=0.00MB +:@phases/OpAssignmentLowering : time=1.22ms mem=0.00MB +:@phases/UnionLowering : time=0.95ms mem=0.00MB +:@phases/StringConstructorLowering : time=0.74ms mem=0.00MB +:@phases/OptionalArgumentsLowering : time=0.67ms mem=0.03MB +:@phases/LateInitializationConvert : time=0.63ms mem=0.00MB +:@phases/TypeFromLowering : time=0.63ms mem=0.00MB +:@phases/DefaultParametersLowering : time=0.62ms mem=0.00MB +:@phases/ExpandBracketsPhase : time=0.60ms mem=0.00MB +:@phases/CapturedVariables : time=0.57ms mem=0.00MB +:@phases/RestTupleConstructionPhase : time=0.54ms mem=0.00MB +:@phases/SpreadConstructionPhase : time=0.51ms mem=0.00MB +:@phases/DynamicImport : time=0.51ms mem=0.00MB +:@phases/StringComparisonLowering : time=0.47ms mem=0.00MB +:@phases/RestArgsLowering : time=0.37ms mem=0.00MB +:@phases/BigIntLowering : time=0.36ms mem=0.00MB +:@phases/ObjectIteratorLowering : time=0.32ms mem=0.00MB +:@phases/StringConstantsLowering : time=0.32ms mem=0.00MB +:@phases/SetterLowering : time=0.31ms mem=0.00MB +:@phases/RecordLowering : time=0.31ms mem=0.00MB +:@phases/ExtentionAccessorPhase : time=0.31ms mem=0.00MB +:@phases/AsyncMethodLowering : time=0.31ms mem=0.00MB +:@phases/AnnotationCopyPostLowering : time=0.28ms mem=0.00MB +:@phases/AnnotationCopyLowering : time=0.28ms mem=0.00MB +:@phases/SetJumpTargetPhase : time=0.26ms mem=0.00MB +:@phases/plugins-after-parse : time=0.01ms mem=0.00MB +:@phases/ExportAnonymousConstPhase : time=0.00ms mem=0.00MB +:@phases/plugins-after-lowering : time=0.00ms mem=0.00MB +:@phases/DeclGenPhase : time=0.00ms mem=0.00MB +:@phases/plugins-after-bind : time=0.00ms mem=0.00MB +:@phases/PackageImplicitImport : time=0.00ms mem=0.00MB +:@phases/plugins-after-check : time=0.00ms mem=0.00MB +:@phases/CFGBuilder : time=0.00ms mem=0.00MB diff --git a/ets2panda/test/benchmarks/bench_1.ets b/ets2panda/test/benchmarks/bench_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a200b8c29d28a7b0b7332f96f72f3e5dbe958c30 --- /dev/null +++ b/ets2panda/test/benchmarks/bench_1.ets @@ -0,0 +1,1569 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// --------------------------------------------------------------------------------------------------------------------- +// AccessBinaryTrees.ets +// --------------------------------------------------------------------------------------------------------------------- + +class TreeNode { + private left: TreeNode | null; + private right: TreeNode | null; + private item: int; + + constructor(left: TreeNode | null, right: TreeNode | null, item: int) { + this.left = left; + this.right = right; + this.item = item; + } + + public itemCheck(): int { + if (this.left == null) + return this.item; + else + return this.item + this.left!.itemCheck() - this.right!.itemCheck(); + } +} + +export class AccessBinaryTrees { + static readonly startDepth = 4; + static readonly endDepth = 7; + static readonly expected = -4; + + static bottomUpTree(item: int, depth: int): TreeNode { + if (depth > 0) { + return new TreeNode( + AccessBinaryTrees.bottomUpTree(2*item - 1, depth-1), + AccessBinaryTrees.bottomUpTree(2*item, depth-1), + item + ); + } + return new TreeNode(null, null, item); + } + + public run(): void { + let ret: int = 0; + + for (let n: int = AccessBinaryTrees.startDepth; n <= AccessBinaryTrees.endDepth; n++) { + let minDepth: int = AccessBinaryTrees.startDepth; + let maxDepth: int = max(minDepth + 2, n); + let stretchDepth: int = maxDepth + 1; + let check: int = AccessBinaryTrees.bottomUpTree(0, stretchDepth).itemCheck(); + + let longLivedTree = AccessBinaryTrees.bottomUpTree(0, maxDepth); + + for (let depth = minDepth; depth <= maxDepth; depth += 2) { + let iterations: int = 1 << (maxDepth - depth + minDepth); + + check = 0; + for (let i: int = 1; i <= iterations; i++) { + check += AccessBinaryTrees.bottomUpTree(i, depth).itemCheck(); + check += AccessBinaryTrees.bottomUpTree(-i, depth).itemCheck(); + } + } + + ret += longLivedTree.itemCheck(); + } + + arktest.assertEQ(ret, AccessBinaryTrees.expected, "Incorrect result") + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// RestTuple6.ets +// --------------------------------------------------------------------------------------------------------------------- + +class A2 {} +class B2 {} + +class C2 { + foo(...p: [A2, B2]): boolean { + return p[0] == p[1] + } + + moo(a:int, ...p: [A2, B2]): boolean { + return p[0] == p[1] + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// GenericBridges_02.ets +// --------------------------------------------------------------------------------------------------------------------- + +interface B3 { + f23(v: B3): B3; +} + +class C3 implements B3 { + + f13(v: T3): T3 { + return v; + } + + f23(v: C3): C3 { + return new C3(); + } + + f23(v: B3): B3 { + return this.f23(v as C3); + } + + f33(v: T3|string): string { + return "C3.f33"; + } + + f43(v: C3|Numeric): string { + return "C3.f43"; + } + + f53(x: T1|Z3|C3[]): string { + return "C3.f53"; + } + + f63(x: C3, y: C3): string { + return "C3.f63"; + } + + f73(x: T3, y: C3): string { + return "C3.f73"; + } + + f83(x: string): string { + return "C3.f83"; + } + + f93(z: Z3, y: T1): string { + return "C3.f93"; + } +} + +class D3 extends C3 { + f13(v: string): string { + return "D3.f13"; + } + + f13(v: Numeric|string|C3): string { + return this.f13(v as string); + } + + f13(v: Int): Int { + return 7; + } + + f23(v: D3): D3 { + return new D3(); + } + + f33(v: string): string { + return "D3.f33"; + } + + f43(v: D3): string { + return "D3.f43"; + } + + f43 (x: int, y: int): int { + return x + y; + } + + f53(x: string|W3|C3[]): string { + return "D3.f53"; + } + + f63(): string { + return "D3.f63"; + } + +// f73(x: string, y: D3): string { +// return "D3.f73"; +// } + + f83(x: string): string { + return "D3.f83"; + } + + f93(z: W3, y: string): string { + return "D3.f93-1"; + } + + f93(z: W3, y: Int): string { + return "D3.f93-2"; + } +} + +class F3 extends D3 {} + +class G3 extends C3 {} + +class E3 extends C3 { + + f13(v: U3): Integral { + if (v instanceof Int) { + return new Int(7); + } else if (v instanceof Long) { + return new Long(8); + } else { + return new Int(-1); + } + } + + f23(v: E3): E3 { + return new E3(); + } + + f33(){} + + f43(x:int, y: int): int { return x + y; } + +// f73(x: U3, y: E3): string { +// return "E3.f73"; +// } +} + +function foo13(c: C3) { + arktest.assertEQ(c.f13(0), 7) + arktest.assertEQ(c.f23(c).f13(0), 7) + arktest.assertEQ(c.f53(""), "C3.f53") + arktest.assertEQ(c.f63(c, c), "C3.f63") +} + +function foo23(c: C3) { + arktest.assertEQ(c.f13(0), 8) + arktest.assertEQ(c.f23(c).f13(0), 8) + arktest.assertEQ(c.f53(""), "C3.f53") + arktest.assertEQ(c.f73(3, c), "E3.f73") +} + +function ttt3(c: C3): void { + arktest.assertEQ(c.f13("ah"), "D3.f13") + arktest.assertEQ(c.f23(c).f13("ah"), "D3.f13") + arktest.assertEQ((c.f23(c as B3) as C3).f13("ah"), "D3.f13") + arktest.assertEQ(c.f33("ah"), "D3.f33") + arktest.assertEQ(c.f43(c), "D3.f43") + arktest.assertEQ(c.f53("ah"), "D3.f53") + arktest.assertEQ(c.f63(c, c), "C3.f63") + arktest.assertEQ((c as D3).f63(), "D3.f63") + arktest.assertEQ(c.f73("ah", c), "D3.f73") + arktest.assertEQ(c.f83(""), "D3.f83") + arktest.assertEQ(c.f93("", ""), "C3.f93") + arktest.assertEQ((c as D3).f93("", 0), "D3.f93-2") +} + +// --------------------------------------------------------------------------------------------------------------------- +// ArrowArity.ets +// --------------------------------------------------------------------------------------------------------------------- + +type S4 = string + +function xassert4(a: S4, b: S4) { arktest.assertEQ(a, b) } + +function p0call4(f: () => S4, a: S4[]) { + return f() +} +function p1call4(f: (p1: S4) => S4, a: S4[]) { + return f(a[0]) +} +function p2call4(f: (p1: S4, p2: S4) => S4, a: S4[]) { + return f(a[0], a[1]) +} +function p012call4(f: () => S4, a: S4[]) { + return p0call4(f, a) + p1call4(f, a) + p2call4(f, a) +} +function p_12call4(f: (p1: S4) => S4, a: S4[]) { + return p1call4(f, a) + p2call4(f, a) +} +function p__2call4(f: (p1: S4, p2: S4) => S4, a: S4[]) { + return p2call4(f, a) +} + +function r0__call4(f: (p1?: S4, p2?: S4) => S4, a: S4[]) { + return f() + f(a[0]) + f(a[0], a[1]) +} +function r_1_call4(f: (p1: S4, p2?: S4) => S4, a: S4[]) { + return f(a[0]) + f(a[0], a[1]) +} + +function testBasicArity4() { + let args = ["a", "b"] + let f0 = () => "/f0:" + let f1 = (a1: S4) => "/f1:" + a1 + let f2 = (a1: S4, a2: S4) => "/f2:" + a1 + a2 + + xassert4(p012call4(f0, args), "/f0:/f0:/f0:") + xassert4(p_12call4(f0, args), "/f0:/f0:") + xassert4(p_12call4(f1, args), "/f1:a/f1:a") + xassert4(p__2call4(f0, args), "/f0:") + xassert4(p__2call4(f1, args), "/f1:a") + xassert4(p__2call4(f2, args), "/f2:ab") + + xassert4(r0__call4(f0, args), "/f0:/f0:/f0:") + xassert4(r_1_call4(f0, args), "/f0:/f0:") + xassert4(r_1_call4(f1, args), "/f1:a/f1:a") +} +testBasicArity4(); + +function testOptionalArity4() { + let args = ["a", "b"] + let tou = (v?: string) => v ?? "u" + let f0 = (a1?: S4, a2?: S4) => "/f0:" + tou(a1) + tou(a2) + let f1 = (a1: S4, a2?: S4) => "/f1:" + a1 + tou(a2) + let f2 = (a1: S4, a2: S4) => "/f2:" + a1 + a2 + + xassert4(p012call4(f0, args), "/f0:uu/f0:au/f0:ab") + xassert4(p_12call4(f0, args), "/f0:au/f0:ab") + xassert4(p_12call4(f1, args), "/f1:au/f1:ab") + xassert4(p__2call4(f0, args), "/f0:ab") + xassert4(p__2call4(f1, args), "/f1:ab") + xassert4(p__2call4(f2, args), "/f2:ab") + + xassert4(r0__call4(f0, args), "/f0:uu/f0:au/f0:ab") + xassert4(r_1_call4(f0, args), "/f0:au/f0:ab") + xassert4(r_1_call4(f1, args), "/f1:au/f1:ab") +} +testOptionalArity4(); + +function testDfltArity4() { + let args = ["a", "b"] + let f0 = (a1: S4 = "x", a2: S4 = "y") => "/f0:" + a1 + a2 + let f1 = (a1: S4, a2: S4 = "y") => "/f1:" + a1 + a2 + let f2 = (a1: S4, a2: S4) => "/f2:" + a1 + a2 + + xassert4(p012call4(f0, args), "/f0:xy/f0:ay/f0:ab") + xassert4(p_12call4(f0, args), "/f0:ay/f0:ab") + xassert4(p_12call4(f1, args), "/f1:ay/f1:ab") + xassert4(p__2call4(f0, args), "/f0:ab") + xassert4(p__2call4(f1, args), "/f1:ab") + xassert4(p__2call4(f2, args), "/f2:ab") + + xassert4(r0__call4(f0, args), "/f0:xy/f0:ay/f0:ab") + xassert4(r_1_call4(f0, args), "/f0:ay/f0:ab") + xassert4(r_1_call4(f1, args), "/f1:ay/f1:ab") +} +testDfltArity4() + +function testDfltEvaluation4() { + let counter = "c" + let inc = () => (counter += "x") + let f = (a: string = inc()) => a + xassert4(f("a"), "a") + xassert4(f(), "cx") + xassert4(f(), "cxx") + xassert4(f(undefined), "cxxx") +} +testDfltEvaluation4() + +function testArrowExprCalls4() { + let x = (a1: S4, a2?: S4, a3?: S4) => a1 + (a2 ?? "u") + (a3 ?? "u") + xassert4(x("a"), "auu") + xassert4(x("a", "b"), "abu") + xassert4(x("a", "b", "c"), "abc") + + xassert4(((a?: S4) => a ?? "u")(), "u") + // xassert4(((a?: S4) => a ?? "u")("a"), "a") // #22952: broken +} +testArrowExprCalls4() + +class X4 { + constructor(v: (p?: T4) => T4) { this.fv = v } + get f() { return this.fv } + fv: (p?: T4) => T4 +} +function gcall4(x: X4, a: T4) { + (x.f)(); + (x.f)(a); + (x.fv)(); + (x.fv)(a); +} +function testGenerics4() { + let res: string = ":" + let fn = (a?: string) => { + res += (a ?? "D"); + return res; + }; + gcall4(new X4(fn), "a") // #22952: inference fails + xassert4(res, ":DaDa") +} +testGenerics4(); + +function foo4(a1: S4, a2?: S4) { return a1 + (a2 ?? "D") } +function testFuncRef4() { + let f = (a1: S4, a2?: S4) => foo4(a1, a2) // #22952: foo4 is overloaded + xassert4(f("a"), "aD") + xassert4(f("a", undefined), "aD") + xassert4(f("a", "b"), "ab") +} +testFuncRef4(); + +// --------------------------------------------------------------------------------------------------------------------- +// OptionalChains.ets +// --------------------------------------------------------------------------------------------------------------------- + +function assert_n5(v: Object | null | undefined) { arktest.assertTrue(v === null); } +function assert_u5(v: Object | null | undefined) { arktest.assertTrue(v === undefined); } +function assert_o5(v: Object | null | undefined) { arktest.assertTrue(v !== null && v !== undefined); } +function assert_npe5(f: () => void) { + try { + f(); + } catch (e: NullPointerError) { + return; + } + arktest.assertTrue(false, "npe was not thrown") +} + +class Link5 { + m(): Link5 { return this; } + f: Link5 = this; + a: Link5[] = [(this)]; + c: () => Link5 = () => this + + om(): Link5 | null { return this.m() } + of: Link5 | null = this.f; + oa: Link5[] | null = this.a; + oc: (() => Link5) | null = this.c; + + nm(): Link5 | null { return null } + nf: Link5 | null = null; + na: Link5[] | null = null; + nc: (() => Link5) | null = null; + + static noevalFlag = true; + noeval(): Link5 { if (Link5.noevalFlag) { throw new Error("never evaluated"); } return this; } +} + +function test15(l: Link5 | null, nl: Link5 | null) { + assert_o5(l?.m()); + assert_o5(l?.f); + assert_o5(l?.a[0]); + assert_o5(l?.c()); + assert_o5(l?.of!.f); + + assert_u5(nl?.m()); + assert_u5(nl?.f); + assert_u5(nl?.a[0]); + assert_u5(nl?.c()); + assert_u5(nl?.of!.f); + assert_u5(nl?.nf!.f); + + nl?.m().noeval(); + nl?.f.noeval(); + nl?.a[0].noeval(); + nl?.c().noeval(); + nl?.of!.f.noeval(); + assert_npe5(() => { nl?.of!.f! }); +} + +function test25(l: Link5 | null, nl: Link5 | null) { + assert_o5(l?.m().f.a[0].c()); + assert_o5(l?.f.m().c().a[0]); + assert_o5(l?.a[0].c().f.m()); + assert_o5(l?.c().m().a[0].f); + assert_o5(l?.c().m().of!.a[0].oc!().f); + + assert_u5(nl?.m().f.a[0].c()); + assert_u5(nl?.f.m().c().a[0]); + assert_u5(nl?.a[0].c().f.m()); + assert_u5(nl?.c().m().a[0].f); + assert_u5(nl?.c().m().of!.a[0].oc!().f); + + nl?.m().f.a[0].c().noeval(); + nl?.f.m().c().a[0].noeval(); + nl?.a[0].c().f.m().noeval(); + nl?.c().m().a[0].f.noeval(); + nl?.c().m().of!.a[0].oc!().f.noeval(); +} + +function test35(l: Link5 | null, nl: Link5 | null) { + assert_o5(l?.om()?.of?.oa?.[0].oc?.()); + assert_o5(l?.of?.om()?.oc?.().oa?.[0]); + assert_o5(l?.oa?.[0]?.oc?.().of?.om()); + assert_o5(l?.oc?.().om()?.oa?.[0].of); + assert_o5(l?.oc?.().om()?.of!.oa?.[0].oc!().of); + + assert_u5(nl?.om()?.of?.oa?.[0].oc?.()); + assert_u5(nl?.of?.om()?.oc?.().oa?.[0]); + assert_u5(nl?.oa?.[0]?.oc?.().of?.om()); + assert_u5(nl?.oc?.().om()?.oa?.[0].of); + assert_u5(nl?.oc!().om()?.of!.oa![0].oc!().of); + + nl?.om()?.of?.oa?.[0].oc?.().noeval(); + nl?.of?.om()?.oc?.().oa?.[0].noeval(); + nl?.oa?.[0]?.oc?.().of?.om()?.noeval(); + nl?.oc?.().om()?.oa?.[0].of?.noeval(); + nl?.oc?.().om()?.of!.oa?.[0].oc!().of?.noeval(); +} + +function test45(l: Link5 | null, nl: Link5 | null) { + assert_npe5(() => { nl?.of! }); + nl?.of!.f; +} + +function test55(l: Link5 | null, nl: Link5 | null) { + l?.f.a[0]?.f.c(); + nl?.f.a[0]?.f.c().noeval(); + assert_npe5(() => { nl?.f.a[0]?.f.c()! }); + assert_npe5(() => { (nl?.f?.a)?.[0].f! }); + assert_u5(l?.f.a[0].nf?.a[0].noeval()?.m()); + + let u: Link5 | undefined = l?.f.oc?.().na?.[0].noeval().f?.oa?.[0]; +} + +// --------------------------------------------------------------------------------------------------------------------- +// UnionAsAndInstanceof.ets +// --------------------------------------------------------------------------------------------------------------------- + +function assert_ccexc6(f: () => void) { + try { + f(); + } catch (e) { + arktest.assertTrue(e instanceof ClassCastError) + return; + } + arktest.assertTrue(false, "exception expected") +} + +function assert_nothrow6(f: () => void) { + try { + f(); + } catch (e) { + arktest.assertTrue(false, "unexpected exception") + } +} + +class A6 { } +class B6 { } +class C6 { } + +function foo6(x: Object | null | undefined) { return x as Object } + +function test_nullsafety6() { + // Handling of Object may be a bit different, so test it separately + // let f = ... until inference in form ((p)=>expr)(a) is broken + assert_ccexc6(() => { let f = ((x: Object | null | undefined) => x as Object); f(null); }); + assert_ccexc6(() => { let f = ((x: Object | null | undefined) => x as Object); f(undefined); }); + assert_ccexc6(() => { let f = ((x: Object | null) => x as Object); f(null); }); + assert_ccexc6(() => { let f = ((x: Object | undefined) => x as Object); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: Object | null | undefined) => x as Object | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: Object | null | undefined) => x as Object | null); f(undefined); }); + assert_ccexc6(() => { let f = ((x: Object | null) => x as Object | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: Object | undefined) => x as Object | null); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6); f(undefined); }); + assert_ccexc6(() => { let f = ((x: A6 | null) => x as A6); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | undefined) => x as A6); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | null); f(undefined); }); + assert_ccexc6(() => { let f = ((x: A6 | null) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | undefined) => x as A6 | null); f(undefined); }); + + + assert_nothrow6(() => { let f = ((x: Object | null | undefined) => x as Object); f(new Object()); }); + assert_nothrow6(() => { let f = ((x: Object | null | undefined) => x as Object); f(new Object); }); + assert_nothrow6(() => { let f = ((x: Object | null) => x as Object); f(new Object()); }); + assert_nothrow6(() => { let f = ((x: Object | undefined) => x as Object); f(new Object()); }); + + assert_nothrow6(() => { let f = ((x: Object | null | undefined) => x as Object | undefined); f(new Object()); }); + assert_nothrow6(() => { let f = ((x: Object | null | undefined) => x as Object | null); f(new Object()); }); + assert_nothrow6(() => { let f = ((x: Object | null) => x as Object | undefined); f(new Object()); }); + assert_nothrow6(() => { let f = ((x: Object | undefined) => x as Object | null); f(new Object()); }); + + assert_nothrow6(() => { let f = ((x: A6 | null | undefined) => x as A6); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | null | undefined) => x as A6); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | null) => x as A6); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | undefined) => x as A6); f(new A6()); }); + + assert_nothrow6(() => { let f = ((x: A6 | null | undefined) => x as A6 | undefined); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | null | undefined) => x as A6 | null); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | null) => x as A6 | undefined); f(new A6()); }); + assert_nothrow6(() => { let f = ((x: A6 | undefined) => x as A6 | null); f(new A6()); }); +} + +function test_unions6() { + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6) => x as A6); f(new C6()); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6) => x as A6 | B6); f(new C6()); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6 | null) => x as A6 | B6); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6 | undefined) => x as A6 | B6); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | null); f(undefined); }); + assert_ccexc6(() => { let f = ((x: A6 | null) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | undefined) => x as A6 | null); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6) => x as A6); f(new C6()); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6) => x as A6 | B6); f(new C6()); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6 | null) => x as A6 | B6); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | B6 | C6 | undefined) => x as A6 | B6); f(undefined); }); + + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | null | undefined) => x as A6 | null); f(undefined); }); + assert_ccexc6(() => { let f = ((x: A6 | null) => x as A6 | undefined); f(null); }); + assert_ccexc6(() => { let f = ((x: A6 | undefined) => x as A6 | null); f(undefined); }); +} + +// --------------------------------------------------------------------------------------------------------------------- +// UncheckedCasts.ets +// --------------------------------------------------------------------------------------------------------------------- + +function assert_ccexc7(f: () => void) { + try { + f(); + } catch (e) { + arktest.assertTrue(e instanceof ClassCastError) + return; + } + arktest.assertTrue(false, "exception expected") +} + +class A7 { } +class B7 { } +class C7 { } +class X7 { } + +function erase7(x: Object | null | undefined): T7 { return x as T7; } + +function test_substitution7() { + assert_ccexc7(() => { erase7(null); }) + assert_ccexc7(() => { erase7(undefined); }) + assert_ccexc7(() => { erase7(null); }) + assert_ccexc7(() => { erase7(undefined); }) + + assert_ccexc7(() => { erase7(null); }) + assert_ccexc7(() => { erase7(undefined); }) + assert_ccexc7(() => { erase7(null); }) + assert_ccexc7(() => { erase7(undefined); }) + + assert_ccexc7(() => { erase7(undefined); }) + assert_ccexc7(() => { erase7(new Object()); }) + assert_ccexc7(() => { erase7(new B7()); }) + + assert_ccexc7(() => { erase7(undefined); }) + assert_ccexc7(() => { erase7(new Object()); }) + assert_ccexc7(() => { erase7(new C7()); }) + + assert_ccexc7(() => { erase7>(new B7[0]); }) +} + +class Erased7 { + constructor(x: Object | null | undefined) { this.t7 = x as T7; } + t7: T7; +} + +function test_substitution_memberexpr7() { + assert_ccexc7(() => { new Erased7(null).t7; }) + assert_ccexc7(() => { new Erased7(undefined).t7; }) + assert_ccexc7(() => { new Erased7(null).t7; }) + assert_ccexc7(() => { new Erased7(undefined).t7; }) + + assert_ccexc7(() => { new Erased7(null).t7; }) + assert_ccexc7(() => { new Erased7(undefined).t7; }) + assert_ccexc7(() => { new Erased7(null).t7; }) + assert_ccexc7(() => { new Erased7(undefined).t7; }) + + assert_ccexc7(() => { new Erased7(undefined).t7; }) + assert_ccexc7(() => { new Erased7(new Object()).t7; }) + assert_ccexc7(() => { new Erased7(new B7()).t7; }) + + assert_ccexc7(() => { new Erased7(undefined).t7; }) + assert_ccexc7(() => { new Erased7(new Object()).t7; }) + assert_ccexc7(() => { new Erased7(new C7()).t7; }) + + assert_ccexc7(() => { new Erased7>(new B7[0]).t7; }) +} + +function cast_to_tparam7(x: Object | null | undefined) { x as T7; } + +function test_constraint7() { + assert_ccexc7(() => { cast_to_tparam7(undefined); }) + assert_ccexc7(() => { cast_to_tparam7(new Object()); }) + assert_ccexc7(() => { cast_to_tparam7(new C7()); }) +} + +function to_basetype7(x: Object | null | undefined) { return x as X7; } + +function test_basetype7() { + assert_ccexc7(() => { to_basetype7(null); }) + assert_ccexc7(() => { to_basetype7(undefined); }) + assert_ccexc7(() => { to_basetype7(new Object()); }) + assert_ccexc7(() => { to_basetype7(new C7()); }) +} + +// --------------------------------------------------------------------------------------------------------------------- +// partialTypeRuntime_2.ets +// --------------------------------------------------------------------------------------------------------------------- + +class Class18 { fld: Number = 2; } + +function test_18(): void { + let class1_partial: Partial = {fld: 3}; + arktest.assertEQ(class1_partial.fld, 3) + class1_partial.fld = undefined; + arktest.assertTrue(class1_partial.fld === undefined) +} + +// ----------------------------------------------- + +class Class28 { + fld: Number = 2; + foo(a0: Partial) { + a0.fld = undefined; + } +} + +function test_28(): void { + let class2_original: Class28 = new Class28(); + let class2_partial: Partial = {fld: 3}; + arktest.assertEQ(class2_partial.fld, 3) + class2_original.foo(class2_partial); + arktest.assertTrue(class2_partial.fld === undefined) +} + +// ----------------------------------------------- + +class Class38 { + mmeb: Number = 2; + foo(a0: Partial){ + a0.mmeb = undefined; + } +} + +class Class48 extends Class38 {} + +class Class58 extends Class48 { + mmeb: Number = 2; + foo(a0: Partial){ + a0.mmeb = undefined; + } +} + +function test_38(): void { + let class3_original: Class38 = new Class38(); + let class5_original: Class38 = new Class58(); + let class3_partial: Partial = {mmeb: 8}; + let class5_partial: Partial = {mmeb: 10}; + class3_original.foo(class5_partial); + class5_original.foo(class3_partial); + arktest.assertTrue(class3_partial.mmeb === undefined) + arktest.assertTrue(class5_partial.mmeb === undefined) +} + +// ----------------------------------------------- + +class Class68 { + mmeb: Number = 2; + foo(a0: Partial){ + if(this.mmeb == 3){ + return; + } + + this.bar(a0); + } + bar(a0: Partial){ + this.mmeb = 3; + this.foo(a0); + } +} + +class Class78 { fld: Number = 6;} + +class Class88 { + baz(a0: Partial){ + a0.fld = undefined; + } +} + +function test_48(): void { + let class7_partial: Partial = {fld: 8}; + let class6_original: Class68 = new Class68(); + class6_original.foo(class7_partial); +} + +// ----------------------------------------------- + +class Class98 { fld: Number = 8; } + +class Class108 extends Class98 { memb: Number = 9; } + +function test_58(): void { + let class10_partial: Partial = {memb: 7, fld: 5}; + + arktest.assertEQ(class10_partial.memb, 7) + arktest.assertEQ(class10_partial.fld, 5) + + class10_partial.memb = undefined; + class10_partial.fld = undefined; + + arktest.assertTrue(class10_partial.memb === undefined) + arktest.assertTrue(class10_partial.fld === undefined) +} + +//--------------------------------------- + + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_01.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C33 { + bar(): string { + return "Class C33"; + } +} + +function foo33(c: Object|null|undefined): string { + if (c instanceof string) { + arktest.assertEQ(c.length, 11) + c = "Case 1"; + } else if (c instanceof C33) { + arktest.assertEQ(c.bar(), "Class C33") + c = "Case 2"; + } else if (c instanceof Int) { + arktest.assertEQ(c * 7, 49) + c = "Case 3"; + } else if (c instanceof null) { + arktest.assertEQ(c, null) + c = "Case 4"; + } else { + c = "Case 5"; + } + + arktest.assertEQ(c.length, 6) + return c; +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_02.ets +// --------------------------------------------------------------------------------------------------------------------- + +class A31 { + bar(): string { + return "Class A31"; + } +} + +class B31 extends A31 {} + +class C31 extends B31 { + bar(): string { + return "Class C31"; + } +} + +function foo31(c: Int|String|A31|null|undefined): void { + if (c instanceof String) { + arktest.assertEQ(c.length, 11) + } else if (c instanceof C31) { + arktest.assertEQ(c.bar(), "Class C31") + } else if (c instanceof Int) { + arktest.assertEQ(c * c, 49) + } else if (c === undefined) { + arktest.assertEQ(c, undefined) + } else { + arktest.assertEQ(c, null) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_03.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C32 { + constructor() {} + + constructor(a: int) { + this.x = a; + } + + bar(): string { + return "Class C32"; + } + + baz(): int { + return this.x; + } + + private x: int = 7; +} + +function foo32(c: Object|null|undefined): string { + if (c instanceof string && (c.length == 11 || c == "Test")) { + c = "Case 1"; + } else if (c instanceof C32 && c.baz() == 7) { + arktest.assertEQ(c.bar(), "Class C32") + c = "Case 2"; + } else if (c instanceof Int && c >= 0) { + arktest.assertTrue(c >= 0) + c = "Case 3"; + } else if (c instanceof null) { + arktest.assertEQ(c, null) + c = "Case 4"; + } else { + c = "Case 5"; + } + + arktest.assertEQ(c.length, 6) + return c; +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_04.ets +// --------------------------------------------------------------------------------------------------------------------- + +function fooAnd34(x: String|null, y: String|null): string { + if (x != null && y != null) { + return x + " " + y; + } else if (x == null && y == null) { + return "null"; + } else if (x != null && y == null) { + return x; + } else if (x == null && y != null) { + return y; + } else { + throw new Error("Unreachable"); + } +} + +function fooOr134(x: String|null, y: String|null): string { + if (x != null || y != null) { + return "case 1"; + } else if (x == null && y == null) { + return "null"; + } else { + throw new Error("Unreachable"); + } +} + +function fooOr234(x: String|null, y: String|null): string { + if (x == null || y == null) { + return "case 1"; + } else if (x != null && y != null) { + return x + " " + y; + } else { + throw new Error("Unreachable"); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_05.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C35 { + readonly a: boolean + constructor(a_: boolean = false) { + this.a = a_; + } +} + +function foo135(x: C35|null|undefined): string { + if (x == null || !x.a) { + return x != null ? "false1" : "null"; + } else { + return x.a ? "true2" : "false2"; + } +} + +function foo235(x: C35|null|undefined): string { + if (x != null && x.a) { + return "true"; + } else { + return x != null ? "false" : "null"; + } +} + +function bar35(x: C35|null|undefined, y: boolean, z: boolean): string { + if ((x instanceof C35 && y) || (x instanceof C35 && z)) { + return (x.a ? "true1" : "false1") + y + z; + } else { + return (x != null ? (x.a ? "true2" : "false2") : "null") + y + z; + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_06.ets +// --------------------------------------------------------------------------------------------------------------------- + +function foo36(x: int): string +{ + let rc: string|undefined = "default"; + + label1: switch(x) { + case 0: + rc = "case 0"; + case 1: { + let rc1: string|undefined = ():string => {return "case 1";}(); + label2: switch(rc) { + case "default": + rc = undefined; + break label2; + default: + break label1; + } + rc = rc1; + break; + } + case 2: + rc = undefined; + let rc2: string|null = ():string => {return "case 2";}(); + return rc2; + case 3: + rc = "case 3"; + break; + case 4: + rc = undefined; + default: + return rc != null ? rc :"case 4" + case 5: + rc = "case 5"; + } + + return rc; +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_08.ets +// --------------------------------------------------------------------------------------------------------------------- + +function foo37(flag37: boolean): int { + + let x: int|undefined = 0; + let y: int|undefined = 1; + let z: int|undefined = 2; + let w: int|undefined = 3; + + try { + y = 1; + if (flag37) { + throw new Error(); + } + } catch(ex: NullPointerError) { + z = 2; + } catch(ex) { + w = undefined; + } + + return x + y! + z + w!; +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_09.ets +// --------------------------------------------------------------------------------------------------------------------- + +class A38 { + prev_: A38|undefined = undefined; + next_: A38|undefined = undefined; + + m() { + const prev = this.prev_; + const next = this.next_; + + if (prev) { + this.prev_ = undefined; + prev.next_ = next; + } + + if (next) { + this.next_ = undefined; + next.prev_ = prev; + } + + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_10.ets +// --------------------------------------------------------------------------------------------------------------------- + +interface It39 { +} + +class Cl39 implements It39 { + + constructor(p: T39) { + this.x = p; + } + + static resolve(value: U|It39): Cl39 { + if (value instanceof Cl39) { + return value as Cl39; + } + return new Cl39(value as U); + } + + x: T39; + + print(): string { + if (this.x == undefined) { + return "value is " + this.x; + } + else if (this.x instanceof string) { + return "string: '" + this.x + "'"; + } else { + return "number = " + this.x; + } + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_11.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C41 {} + +function foo41(arg?: boolean): C41 | undefined { + if (arg == undefined) { + return undefined; + } + return arg == false ? undefined : new C41(); +} + +function bar41(arg?: boolean): C41 | undefined { + if (arg == true) return new C41(); + return arg == false ? undefined : new C41(); +} + +function baz41(arg?: boolean): int { + if (arg == undefined) return 0; + arktest.assertEQ(typeof arg, "boolean") + return 1; +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_13.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C43 {} + +function foo43(arg?: number): C43 | undefined { + if (arg == 5) return new C43(); + return arg == 3 ? undefined : new C43(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_14.ets +// --------------------------------------------------------------------------------------------------------------------- + +class A44 { + A44(a44?: T44 | number[]) { + if (a44 instanceof Error) { + return this.D(a44); + } else if (a44 instanceof undefined) { + return this.B(a44); + } else if (a44 instanceof number[]) { + return this.E(a44); + } else { + return this.C(a44); + } + } + + B(b: undefined) { + return "undefined"; + } + + C(c: T44) { + return "Generic"; + } + + D(d: Error) { + return "Error"; + } + + E(e: number[]) { + return "number[]" + } +} + +let a44 = new A44(); +arktest.assertEQ(a44.A44(Error()), "Error"); +arktest.assertEQ(a44.A44(undefined), "undefined"); +arktest.assertEQ(a44.A44(1), "Generic"); +arktest.assertEQ(a44.A44([1, 2, 3]), "number[]") + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_15.ets +// --------------------------------------------------------------------------------------------------------------------- + +// Issue #22779 - smart cast in return statement +function isEmpty45(text?: string): boolean { + return text === undefined || text === null || text.length === 0 +} + +// Some other examples +function foo45(text?: string): boolean { + let a: boolean = (text === undefined || text === null || text.length == 0) ? true : false + let b: boolean = text === undefined || text === null || text.length == 0 + let c: boolean = !(text !== undefined) || text === null || text.length == 0 + let d: boolean = (text !== undefined && text !== null) ? text.length == 0 : true + let e: boolean = (text != undefined && text != null) ? text.length == 0 : true + return a && b && c && d && e +} + +// --------------------------------------------------------------------------------------------------------------------- +// SmartCast_16.ets +// --------------------------------------------------------------------------------------------------------------------- + +class C45 { + readonly fld: T45 + constructor(p: T45) { + this.fld = p + } +} + +type NestedC45 = String | C45 | Error + + +function main(): void { + // ----------------------------------------------------------------------------------------------------------------- + // AccessBinaryTrees.ets + // ----------------------------------------------------------------------------------------------------------------- + + let a = new AccessBinaryTrees; + a.run(); + + // ----------------------------------------------------------------------------------------------------------------- + // ArrayLiteral.ets + // ----------------------------------------------------------------------------------------------------------------- + + let a1: byte = 2; + let b1: short = 20000; + let c1: int = 2000000; + let d1: long = 200000000000; + let e1: float = 2.2f; + let f1: double = 2.2222222222; + let g1: double[] = [a1, b1, c1, d1, e1, f1]; + arktest.assertEQ(g1[0], 2) + arktest.assertEQ(g1[1], 20000) + arktest.assertEQ(g1[2], 2000000) + arktest.assertEQ(g1[3], 200000000000) + arktest.assertEQ(g1[4], (Double.toFloat(2.2))) + arktest.assertEQ(g1[5], 2.2222222222) + + const h1: byte = 2; + const i1: short = 2; + const j1: int = 2; + const k1: long = 2; + const l1: float = 2.0f; + const m1: double = 2.0; + const n1: byte[] = [h1, Short.toByte(i1), j1, Long.toByte(k1), Float.toByte(l1), Double.toByte(m1)]; + arktest.assertEQ(n1[0], 2) + arktest.assertEQ(n1[1], 2) + arktest.assertEQ(n1[2], 2) + arktest.assertEQ(n1[3], 2) + arktest.assertEQ(n1[4], 2) + arktest.assertEQ(n1[5], 2) + + let o1: Object[] = [1, 1.1, "testStr", new Int(2), d1, k1]; + arktest.assertEQ(o1[0] as Int, 1) + arktest.assertEQ(o1[1] as Double, 1.1) + arktest.assertTrue((o1[2] as String).equals("testStr")) + arktest.assertEQ(o1[3] as Int, 2) + arktest.assertEQ(o1[4] as Long, 200000000000) + arktest.assertEQ(o1[5] as Long, 2) + + let p1: long[] = [new Int(3), new Short(2 as short), new Long(4)]; + arktest.assertEQ(p1[0], 3) + arktest.assertEQ(p1[1], 2) + arktest.assertEQ(p1[2], 4) + + // ----------------------------------------------------------------------------------------------------------------- + // RestTuple6.ets + // ----------------------------------------------------------------------------------------------------------------- + + let a12: [A2, B2] = [new A2, new B2] + arktest.assertTrue((new C2()).foo(...a12) == false) + arktest.assertTrue((new C2()).moo(12, ...a12) == false) + arktest.assertTrue((new C2()).foo(...[new A2, new B2]) == false) + arktest.assertTrue((new C2()).moo(12, ...[new A2, new B2]) == false) + arktest.assertTrue((new C2()).foo(...[new A2, new B2] as [A2, B2]) == false) + arktest.assertTrue((new C2()).moo(12, ...[new A2, new B2] as [A2, B2]) == false) + arktest.assertTrue((new C2()).foo(new A2, new B2) == false) + arktest.assertTrue((new C2()).moo(12, new A2, new B2) == false) + + // ----------------------------------------------------------------------------------------------------------------- + // GenericBridges_02.ets + // ----------------------------------------------------------------------------------------------------------------- + + ttt3(new D3()) + let c3: C3 = new E3(); + foo13(c3); + foo23(new E3()); + + // ----------------------------------------------------------------------------------------------------------------- + // OptionalChains.ets + // ----------------------------------------------------------------------------------------------------------------- + + test15(new Link5(), null) + test25(new Link5(), null) + test35(new Link5(), null) + test45(new Link5(), null) + test55(new Link5(), null) + + // ----------------------------------------------------------------------------------------------------------------- + // UnionAsAndInstanceof.ets + // ----------------------------------------------------------------------------------------------------------------- + + test_nullsafety6(); + test_unions6(); + + // ----------------------------------------------------------------------------------------------------------------- + // UncheckedCasts.ets + // ----------------------------------------------------------------------------------------------------------------- + + test_substitution7(); + test_substitution_memberexpr7(); + test_constraint7(); + test_basetype7(); + + // ----------------------------------------------------------------------------------------------------------------- + // partialTypeRuntime_2.ets + // ----------------------------------------------------------------------------------------------------------------- + + test_18(); + test_28(); + test_38(); + test_48(); + test_58(); + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_01.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(foo33("Test string"), "Case 1") + arktest.assertEQ(foo33(new Int(7)), "Case 3") + arktest.assertEQ(foo33(new C33()), "Case 2") + arktest.assertEQ(foo33(null), "Case 4") + arktest.assertEQ(foo33(undefined), "Case 5") + arktest.assertEQ(foo33(new Number(3.0)), "Case 5") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_02.ets + // ----------------------------------------------------------------------------------------------------------------- + + foo31("Test string"); + foo31(new Int(7)); + foo31(new C31()); + foo31(null); + foo31(undefined); + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_03.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(foo32("Test string"), "Case 1") + arktest.assertEQ(foo32("Test"), "Case 1") + arktest.assertEQ(foo32("Test string 2"), "Case 5") + arktest.assertEQ(foo32("test"), "Case 5") + + arktest.assertEQ(foo32(new Int(5)), "Case 3") + arktest.assertEQ(foo32(new Int(0)), "Case 3") + arktest.assertEQ(foo32(new Int(-5)), "Case 5") + + arktest.assertEQ(foo32(new C32(7)), "Case 2") + arktest.assertEQ(foo32(new C32()), "Case 2") + arktest.assertEQ(foo32(new C32(17)), "Case 5") + + arktest.assertEQ(foo32(null), "Case 4") + + arktest.assertEQ(foo32(undefined), "Case 5") + arktest.assertEQ(foo32(new Number(3.0)), "Case 5") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_04.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(fooAnd34("Test", "string"), "Test string") + arktest.assertEQ(fooAnd34("Test", null), "Test") + arktest.assertEQ(fooAnd34(null, "string"), "string") + arktest.assertEQ(fooAnd34(null, null), "null") + + arktest.assertEQ(fooOr134("Test", "string"), "case 1") + arktest.assertEQ(fooOr134("Test", null), "case 1") + arktest.assertEQ(fooOr134(null, "string"), "case 1") + arktest.assertEQ(fooOr134(null, null), "null") + + arktest.assertEQ(fooOr234("Test", "string"), "Test string") + arktest.assertEQ(fooOr234("Test", null), "case 1") + arktest.assertEQ(fooOr234(null, "string"), "case 1") + arktest.assertEQ(fooOr234(null, null), "case 1") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_05.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(foo135(null), "null") + arktest.assertEQ(foo235(null), "null") + arktest.assertEQ(bar35(null, true, true), "nulltruetrue") + arktest.assertEQ(bar35(null, true, false), "nulltruefalse") + arktest.assertEQ(bar35(null, false, true), "nullfalsetrue") + arktest.assertEQ(bar35(null, false, false), "nullfalsefalse") + + arktest.assertEQ(foo135(undefined), "null") + arktest.assertEQ(foo235(undefined), "null") + arktest.assertEQ(bar35(undefined, true, true), "nulltruetrue") + arktest.assertEQ(bar35(undefined, true, false), "nulltruefalse") + arktest.assertEQ(bar35(undefined, false, true), "nullfalsetrue") + arktest.assertEQ(bar35(undefined, false, false), "nullfalsefalse") + + let c = new C35(); + arktest.assertEQ(foo135(c), "false1") + arktest.assertEQ(foo235(c), "false") + arktest.assertEQ(bar35(c, true, true), "false1truetrue") + arktest.assertEQ(bar35(c, true, false), "false1truefalse") + arktest.assertEQ(bar35(c, false, true), "false1falsetrue") + arktest.assertEQ(bar35(c, false, false), "false2falsefalse") + + c = new C35(true); + arktest.assertEQ(foo135(c), "true2") + arktest.assertEQ(foo235(c), "true") + arktest.assertEQ(bar35(c, true, true), "true1truetrue") + arktest.assertEQ(bar35(c, true, false), "true1truefalse") + arktest.assertEQ(bar35(c, false, true), "true1falsetrue") + arktest.assertEQ(bar35(c, false, false), "true2falsefalse") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_06.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(foo36(0), "case 0") + arktest.assertEQ(foo36(1), "case 1") + arktest.assertEQ(foo36(2), "case 2") + arktest.assertEQ(foo36(3), "case 3") + arktest.assertEQ(foo36(4), "case 4") + arktest.assertEQ(foo36(5), "case 5") + arktest.assertEQ(foo36(7), "default") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_07.ets + // ----------------------------------------------------------------------------------------------------------------- + + let x363: int | boolean | string = 7; + arktest.assertEQ(x363, 7) + x363--; + arktest.assertEQ(x363, 6) + x363 = x363 == 7; + arktest.assertTrue(!x363) + x363 = !x363; + arktest.assertEQ(x363, true) + x363 = "x363 = " + x363.toString(); + arktest.assertEQ(x363, "x363 = true") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_08.ets + // ----------------------------------------------------------------------------------------------------------------- + + let flag37: boolean = false; + arktest.assertEQ(foo37(flag37), 6) + try { + foo37(!flag37); + } catch(ex) { + flag37 = true; + } + arktest.assertTrue(flag37) + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_10.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(Cl39.resolve(undefined).print(), "value is undefined") + arktest.assertEQ(Cl39.resolve("test").print(), "string: 'test'") + arktest.assertEQ(Cl39.resolve(5.5).print(), "number = 5.5") + arktest.assertEQ(Cl39.resolve(new Int(8)).print(), "number = 8") + + arktest.assertEQ(Cl39.resolve(new Cl39(null)).print(), "value is null") + arktest.assertEQ(Cl39.resolve(new Cl39("TEST")).print(), "string: 'TEST'") + arktest.assertEQ(Cl39.resolve(new Cl39(7.7)).print(), "number = 7.7") + arktest.assertEQ(Cl39.resolve(new Cl39(new Int(-8))).print(), "number = -8") + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_11.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertTrue(foo41(true) instanceof C41) + arktest.assertEQ(foo41(false), undefined) + arktest.assertEQ(foo41(), undefined) + + arktest.assertTrue(bar41(true) instanceof C41) + arktest.assertEQ(bar41(false), undefined) + arktest.assertTrue(bar41() instanceof C41) + + arktest.assertEQ(baz41(true), 1) + arktest.assertEQ(baz41(false), 1) + arktest.assertEQ(baz41(), 0) + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_12.ets + // ----------------------------------------------------------------------------------------------------------------- + + let resolve42: ((value: string) => void) | null = null; + + let p42 = new Promise((_resolve: (value: string)=> void): void => { + resolve42 = _resolve; + }); + + resolve42!("abc"); // no smart cast! + + let x42: Number|String|undefined = "test1"; + let y42: Number|String|undefined = "test2" + let z42: Number|String|undefined = 7 + + let lam42: () => void = () => { + let y42: Number|String|undefined = 2; // hides outer declaration! + x42 = z42; + let tmp: number = y42; // smart cast is used + arktest.assertEQ(tmp, 2); + }; + + if (x42 instanceof string) { + let tmp: string = x42 as string; // no smart cast! + arktest.assertEQ(tmp, "test1"); + } + + lam42(); + + arktest.assertEQ(x42, 7); + + if (y42 instanceof string) { + let tmp: string = y42; // smart cast is used + arktest.assertEQ(tmp, "test2"); + } + + let w42: number = z42; // smart cast is used + arktest.assertEQ(w42, 7) + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_13.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertTrue(foo43(5) instanceof C43) + arktest.assertEQ(foo43(3), undefined) + arktest.assertTrue(foo43(undefined) instanceof C43) + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_15.ets + // ----------------------------------------------------------------------------------------------------------------- + + arktest.assertEQ(isEmpty45(), true) + arktest.assertEQ(isEmpty45(""), true) + arktest.assertEQ(isEmpty45("a"), false) + arktest.assertEQ(foo45(), true) + + // ----------------------------------------------------------------------------------------------------------------- + // SmartCast_16.ets + // ----------------------------------------------------------------------------------------------------------------- + + let x45: NestedC45 = new C45>(new C45(new Error())) + let ok45 = x45 instanceof C45 && x45.fld instanceof C45 && x45.fld.fld instanceof Error + let aaa = ok45 ? 0 : 1 + +} diff --git a/ets2panda/test/benchmarks/etsstdlib-max.txt b/ets2panda/test/benchmarks/etsstdlib-max.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab8a25fbeba5dce556305e95ec236cb135547251 --- /dev/null +++ b/ets2panda/test/benchmarks/etsstdlib-max.txt @@ -0,0 +1,66 @@ +================ es2panda perf metrics (Averaged over 500 runs) ================ + +:@phases : time=4770.18ms mem=324.00MB +:@GenerateProgram : time=2571.34ms mem=0.00MB +:@GenerateProgram/OptimizeBytecode : time=1896.82ms mem=0.00MB +:@phases/CheckerPhase : time=1781.74ms mem=81.00MB +:@EmitProgram : time=485.84ms mem=130.58MB +:@phases/Unbox : time=437.00ms mem=38.00MB +:@phases/ConstantExpressionLowering : time=363.29ms mem=0.28MB +:@phases/LambdaObjectConversion : time=328.18ms mem=22.00MB +:@phases/TopLevelStatements : time=277.34ms mem=83.00MB +:@phases/GradualTypeNarrowing : time=198.37ms mem=19.00MB +:@phases/ResolveIdentifiers : time=123.95ms mem=5.13MB +:@phases/OpAssignmentLowering : time=116.33ms mem=18.00MB +:@phases/InterfaceObjectLiteralLowering : time=76.22ms mem=7.00MB +:@phases/ScopesInitPhase : time=60.61ms mem=13.00MB +:@phases/ObjectIndexLowering : time=52.64ms mem=1.90MB +:@phases/PartialExportClassGen : time=50.08ms mem=8.00MB +:@phases/CreateGenericBridges : time=43.00ms mem=3.00MB +:@phases/RestArgsLowering : time=42.90ms mem=4.00MB +:@phases/BoxingForLocals : time=41.18ms mem=1.88MB +:@phases/PrimitiveConversion : time=39.01ms mem=4.00MB +:@phases/ArrayLiteralLowering : time=38.51ms mem=4.00MB +:@phases/LateInitializationConvert : time=38.24ms mem=0.00MB +:@phases/ObjectIteratorLowering : time=30.96ms mem=1.00MB +:@phases/UnionLowering : time=25.90ms mem=0.04MB +:@phases/ObjectLiteralLowering : time=25.72ms mem=0.00MB +:@phases/OptionalArgumentsLowering : time=25.23ms mem=0.22MB +:@phases/StringConstructorLowering : time=25.14ms mem=0.00MB +:@phases/TypeFromLowering : time=24.09ms mem=0.00MB +:@phases/ExpandBracketsPhase : time=23.46ms mem=0.00MB +:@phases/SetterLowering : time=23.02ms mem=0.27MB +:@phases/StringComparisonLowering : time=21.98ms mem=0.00MB +:@phases/RecordLowering : time=21.10ms mem=0.00MB +:@phases/ExtentionAccessorPhase : time=20.90ms mem=0.00MB +:@phases/InterfacePropertyDeclarationsPhase : time=20.54ms mem=1.00MB +:@phases/DynamicImport : time=20.29ms mem=0.00MB +:@phases/BigIntLowering : time=19.61ms mem=0.00MB +:@phases/EnumPostCheckLoweringPhase : time=19.03ms mem=0.21MB +:@phases/ResizableArrayConvert : time=18.56ms mem=0.48MB +:@phases/EnumLoweringPhase : time=18.53ms mem=0.83MB +:@phases/RestTupleConstructionPhase : time=18.49ms mem=0.23MB +:@phases/DefaultParametersLowering : time=18.43ms mem=0.26MB +:@phases/OptionalLowering : time=18.42ms mem=0.49MB +:@phases/AsyncMethodLowering : time=18.41ms mem=0.00MB +:@phases/OverloadMappingLowering : time=18.02ms mem=0.00MB +:@phases/SpreadConstructionPhase : time=17.69ms mem=0.00MB +:@phases/DeclareOverloadLowering : time=17.58ms mem=0.00MB +:@phases/PromiseVoidInferencePhase : time=17.22ms mem=0.00MB +:@phases/AnnotationCopyPostLowering : time=16.95ms mem=0.00MB +:@phases/AnnotationCopyLowering : time=16.86ms mem=0.00MB +:@phases/InsertOptionalParametersAnnotation : time=16.86ms mem=0.48MB +:@phases/AmbientLowering : time=16.77ms mem=0.00MB +:@phases/CapturedVariables : time=16.71ms mem=0.00MB +:@phases/ExpressionLambdaConstruction : time=16.60ms mem=0.03MB +:@phases/DefaultParametersInConstructorLowering : time=16.21ms mem=0.51MB +:@phases/SetJumpTargetPhase : time=16.00ms mem=0.00MB +:@phases/DeclGenPhase : time=0.02ms mem=0.00MB +:@phases/plugins-after-parse : time=0.01ms mem=0.00MB +:@phases/plugins-after-lowering : time=0.00ms mem=0.00MB +:@phases/plugins-after-bind : time=0.00ms mem=0.00MB +:@phases/CFGBuilder : time=0.00ms mem=0.00MB +:@phases/StringConstantsLowering : time=0.00ms mem=0.00MB +:@phases/plugins-after-check : time=0.00ms mem=0.00MB +:@phases/ExportAnonymousConstPhase : time=0.00ms mem=0.00MB +:@phases/PackageImplicitImport : time=0.00ms mem=0.00MB diff --git a/ets2panda/test/benchmarks/runner/arg_parser.py b/ets2panda/test/benchmarks/runner/arg_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..40cf4e5e8f1de82bcf3d3c86a5a612ad76564ef2 --- /dev/null +++ b/ets2panda/test/benchmarks/runner/arg_parser.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import argparse +import os + + +def parse_arguments() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Cpp headers parser to .yaml") + + parser.add_argument("--mode", "-m", type=str, required=True, help="Mode: 'static' or 'dynamic'") + parser.add_argument("--es2panda", "-e", type=str, required=True, help="Path to current es2panda") + parser.add_argument("--es2panda-pre-merge", "-c", type=str, required=False, help="Path to pre_merge es2panda") + parser.add_argument("--test-dir", "-t", type=str, required=True, help="Path to test directory with test files") + parser.add_argument("--work-dir", "-a", type=str, required=True, help="Path to the working temp folder") + parser.add_argument("--werror", "-w", action="store_true", help="Warnings as errors") + parser.add_argument( + "--dynamic-regression", + "-d", + type=float, + required=False, + default=0.05, + help="Acceptable regression compared to the pre_merge", + ) + parser.add_argument( + "--static-regression", + "-s", + type=float, + required=False, + default=0.1, + help="Acceptable regression compared to static measurement", + ) + parser.add_argument("--runs", "-n", type=int, required=False, default=25, help="Number of times to run the command") + + return parser.parse_args() + + +def check_arguments(args: argparse.Namespace) -> argparse.Namespace: + if args.mode not in ["static", "dynamic"]: + raise RuntimeError(f"Invalid mode: {args.mode}\nSee --help for more.") + if not os.path.isfile(args.es2panda): + raise RuntimeError(f"Bad path to current es2panda: {args.es2panda}\nSee --help for more.") + if args.mode == "dynamic" and not os.path.isfile(args.es2panda_pre_merge): + raise RuntimeError(f"Bad path to pre_merge es2panda: {args.es2panda_pre_merge}\nSee --help for more.") + if not os.path.isdir(args.test_dir): + raise RuntimeError(f"Bad path to test_dir: {args.test_dir}\nSee --help for more.") + if args.dynamic_regression > 1 or args.dynamic_regression < -1: + raise RuntimeError( + f"Static regression must be in value range [-1, 1], current: {args.dynamic_regression}\n" + "See --help for more." + ) + if args.static_regression > 1 or args.static_regression < -1: + raise RuntimeError( + f"Static regression must be in value range [-1, 1], current: {args.static_regression}\n" + "See --help for more." + ) + + return args diff --git a/ets2panda/test/benchmarks/runner/benchmark_comparator.py b/ets2panda/test/benchmarks/runner/benchmark_comparator.py new file mode 100644 index 0000000000000000000000000000000000000000..4e521f82f5a5521746483a9c4715a1a8d6b6c6b5 --- /dev/null +++ b/ets2panda/test/benchmarks/runner/benchmark_comparator.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from pathlib import Path +from typing import Dict, Optional, Tuple, List, Callable + +from metrics_utils import parse_perf_file, format_diff, format_time_ms, format_mem_mb + + +def _get_phase_comparison(phase: str, base: Optional[Dict], new: Optional[Dict]) -> Tuple[str, str, str]: + if base and new: + label = phase + time_diff = new["time_ns"] - base["time_ns"] + mem_diff = new["mem_bytes"] - base["mem_bytes"] + time_str = format_diff(time_diff, base["time_ns"], format_time_ms) + mem_str = format_diff(mem_diff, base["mem_bytes"], format_mem_mb) + elif new: + label = f"{phase} [NEW]" + time_str = f"+{format_time_ms(new['time_ns'])}" + mem_str = f"+{format_mem_mb(new['mem_bytes'])}" + elif base: + label = f"{phase} [REMOVED]" + time_str = f"-{format_time_ms(base['time_ns'])}" + mem_str = f"-{format_mem_mb(base['mem_bytes'])}" + else: + return "", "", "" + return label, time_str, mem_str + + +def _write_report(report_path: Path, base_name: str, new_name: str, results: List[Dict]) -> None: + if not results: + print("No common or unique phases to compare.") + return + + max_phase_len = max(len(r["phase"]) for r in results) + header = f"Performance Comparison: '{base_name}' vs '{new_name}'\n" + "=" * 80 + + lines = [header] + for r in results: + phase_str = f":@{r['phase']}" + lines.append(f"{phase_str:<{max_phase_len + 3}}: time={r['time_str']:<25} mem={r['mem_str']:<25}") + + report_path.write_text("\n".join(lines), encoding="utf-8") + print(f"\n✅ Comparison finished! Results saved to: {report_path}") + + +def _print_and_log(level: str, msg: str, log_dir: Path) -> None: + if level == "Error": + print(f"\n❌ {msg}") + path = log_dir / "error_log.txt" + else: + print(f"\n⚠️ {msg}") + path = log_dir / "warning_log.txt" + with os.fdopen(os.open(path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, mode=511), "a", encoding="utf-8") as f: + f.write(msg + "\n") + + +def _check_regression( + metric_name: str, + base_data: Dict, + new_data: Dict, + regression: float, + perf_name: str, + log_dir: Path, + is_static: bool = False, +) -> None: + format_func: Callable[[float], str] + success = True + if metric_name == "Time": + key = "time_ns" + format_func = format_time_ms + elif metric_name == "Memory": + key = "mem_bytes" + format_func = format_mem_mb + else: + raise RuntimeError(f"Unsupported metric: {metric_name}") + + base_sum = sum(base_data.get(p, {}).get(key, 0) for p in ["phases", "EmitProgram"]) + new_sum = sum(new_data.get(p, {}).get(key, 0) for p in ["phases", "EmitProgram"]) + + upper_threshold = base_sum * (1 + regression) + if new_sum > upper_threshold: + msg = ( + f"[PERF REGRESSION] Failed for {perf_name}: {metric_name} exceeded upper threshold.\n" + f"\tLimit: {regression:.1%}, Actual: +{((new_sum / base_sum) - 1) * 100:.2f}%\n" + f"\tBase: {format_func(base_sum)}, New: {format_func(new_sum)}\n" + f"\tThreshold: < {format_func(upper_threshold)}\n" + ) + _print_and_log("Error", msg, log_dir) + success = False + + lower_threshold = base_sum * (1 - regression * 3) + if is_static and new_sum < lower_threshold: + msg = ( + f"[UPDATE REQUIRED] Very good perf for {perf_name}: {metric_name} exceeded lower threshold.\n" + f"\tLimit: -{regression * 3:.1%}, Actual: {((new_sum / base_sum) - 1) * 100:.2f}%\n" + f"\tBase: {format_func(base_sum)}, New: {format_func(new_sum)}\n" + f"\tThreshold: > {format_func(lower_threshold)}\n\n" + "Please update *-max.txt.\n" + ) + _print_and_log("Warning", msg, log_dir) + success = False + + if success: + print(f"\n✅ {metric_name} regression check for {perf_name} finished!") + + +def compare_perf_files( + new_perf_path: Path, base_perf_path: Path, report_path: Path, regression: float, log_dir: Path +) -> None: + base_data = parse_perf_file(base_perf_path) + new_data = parse_perf_file(new_perf_path) + + if not new_data: + raise RuntimeError("New perf data is empty") + if not base_data: + raise RuntimeError("Base perf data is empty") + + is_static = base_perf_path.name.find("-max.txt") != -1 + _check_regression("Time", base_data, new_data, regression, new_perf_path.name, log_dir, is_static) + _check_regression("Memory", base_data, new_data, regression, new_perf_path.name, log_dir, is_static) + results = [] + all_phases = sorted(list(set(base_data.keys()) | set(new_data.keys()))) + + for phase in all_phases: + label, time_str, mem_str = _get_phase_comparison(phase, base_data.get(phase), new_data.get(phase)) + if label: + results.append({"phase": label, "time_str": time_str, "mem_str": mem_str}) + + _write_report(report_path, base_perf_path.name, new_perf_path.name, results) diff --git a/ets2panda/test/benchmarks/runner/benchmark_runner.py b/ets2panda/test/benchmarks/runner/benchmark_runner.py new file mode 100644 index 0000000000000000000000000000000000000000..5d632a0992f2bc4d65711b8e41bd2bd34e2726c9 --- /dev/null +++ b/ets2panda/test/benchmarks/runner/benchmark_runner.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import subprocess +import re +from collections import defaultdict +from pathlib import Path +from typing import List, Dict, Union, DefaultDict + +from metrics_utils import parse_metric_value, format_time_ms, format_mem_mb + + +def run_and_parse(command: List) -> Dict: + print(f"Executing: {' '.join(command)}") + try: + result = subprocess.run(command, capture_output=True, text=True, check=True, encoding="utf-8") + except (FileNotFoundError, subprocess.CalledProcessError) as e: + print(f"Error executing command: {e}") + if isinstance(e, subprocess.CalledProcessError): + print(f"Stderr:\n{e.stderr}") + return {} + + line_regex = re.compile(r":@(?P[\w\/-]+)\s*:\s*time=(?P