From 8695e4af8df384154b1d911832342f9164e2e51c Mon Sep 17 00:00:00 2001 From: Ede Monus Date: Thu, 29 Feb 2024 10:28:16 +0100 Subject: [PATCH] Refactor inference of function's return type Now the ScriptFunction class holds references to the contained return statements, which gets filled up during the check of them. Fixes internal #13839 issue Change-Id: Id9fd07e3fe3f4d24ea7ca35943ff5d27b6b987e9 Signed-off-by: Ede Monus --- ets2panda/checker/ETSAnalyzer.cpp | 15 ++++-- ets2panda/checker/ETSAnalyzerHelpers.cpp | 9 ++-- ets2panda/checker/ets/dynamic.cpp | 37 ++++++++------ ets2panda/checker/ets/enum.cpp | 7 ++- ets2panda/checker/ets/function.cpp | 51 ++++++++++--------- ets2panda/checker/ets/helpers.cpp | 8 +-- .../lowering/ets/defaultParameterLowering.cpp | 7 ++- .../ets/interfacePropertyDeclarations.cpp | 12 ++--- .../ets/topLevelStmts/globalClassHandler.cpp | 15 ++++-- ets2panda/ir/base/scriptFunction.cpp | 9 ++-- ets2panda/ir/base/scriptFunction.h | 27 +++++++--- ets2panda/ir/statements/blockStatement.h | 10 +--- ets2panda/ir/statements/doWhileStatement.h | 8 +-- ets2panda/ir/statements/forInStatement.h | 8 +-- ets2panda/ir/statements/forOfStatement.h | 6 --- ets2panda/ir/statements/forUpdateStatement.h | 8 +-- ets2panda/ir/statements/ifStatement.h | 12 +---- ets2panda/ir/statements/labelledStatement.cpp | 2 +- ets2panda/ir/statements/labelledStatement.h | 8 +-- ets2panda/ir/statements/switchCaseStatement.h | 10 +--- ets2panda/ir/statements/switchStatement.cpp | 10 +--- ets2panda/ir/statements/switchStatement.h | 3 +- ets2panda/ir/statements/tryStatement.cpp | 16 +----- ets2panda/ir/statements/tryStatement.h | 3 +- ets2panda/ir/statements/whileStatement.h | 8 +-- ets2panda/parser/ETSparser.cpp | 12 +++-- ets2panda/parser/expressionParser.cpp | 11 +++- ets2panda/parser/parserImpl.cpp | 30 +++++++---- ets2panda/public/es2panda_lib.cpp | 3 +- .../test-lists/parser/parser-js-ignored.txt | 3 ++ 30 files changed, 175 insertions(+), 193 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 8884209dee..8082d9d922 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1830,7 +1830,8 @@ checker::Type *ETSAnalyzer::GetFunctionReturnType(ir::ReturnStatement *st, ir::S funcReturnType = returnTypeAnnotation->GetType(checker); if (st->argument_ == nullptr) { - if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalVoidType()) { + if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalVoidType() && + !funcReturnType->IsETSAsyncFuncReturnType()) { checker->ThrowTypeError("Missing return value.", st->Start()); } funcReturnType = checker->GlobalVoidType(); @@ -1857,10 +1858,13 @@ checker::Type *ETSAnalyzer::GetFunctionReturnType(ir::ReturnStatement *st, ir::S } else { // Case when function's return type should be inferred from return statement(s): if (containingFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) { - InferReturnType(checker, containingFunc, funcReturnType, st->argument_); + InferReturnType(checker, containingFunc, funcReturnType, + st->argument_); // This removes the NEED_RETURN_TYPE flag, so only the first return + // statement going to land here... } else { // All subsequent return statements: - ProcessReturnStatements(checker, containingFunc, funcReturnType, st, st->argument_); + ProcessReturnStatements(checker, containingFunc, funcReturnType, st, + st->argument_); // and the remaining return statements will get processed here. } } @@ -1888,6 +1892,11 @@ checker::Type *ETSAnalyzer::Check(ir::ReturnStatement *st) const } st->returnType_ = GetFunctionReturnType(st, containingFunc); + + if (containingFunc->ReturnTypeAnnotation() == nullptr) { + containingFunc->AddReturnStatement(st); + } + return nullptr; } diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index bc4ac968a0..d4bfbcc30c 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -111,11 +111,10 @@ void DoBodyTypeChecking(ETSChecker *checker, ir::MethodDefinition *node, ir::Scr scriptFunc->Body()->Check(checker); - // In case of inferred function's return type set it forcedly to all return statements; - if (scriptFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE) && - scriptFunc->ReturnTypeAnnotation() == nullptr && scriptFunc->Body() != nullptr && - scriptFunc->Body()->IsStatement()) { - scriptFunc->Body()->AsStatement()->SetReturnType(checker, scriptFunc->Signature()->ReturnType()); + if (scriptFunc->ReturnTypeAnnotation() == nullptr) { + for (auto &returnStatement : scriptFunc->ReturnStatements()) { + returnStatement->SetReturnType(checker, scriptFunc->Signature()->ReturnType()); + } } checker->Context().SetContainingSignature(nullptr); diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index 80ac4bd698..aa88bf411f 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -129,10 +129,11 @@ ir::ScriptFunction *ETSChecker::CreateDynamicCallIntrinsic(ir::Expression *calle params.push_back(param); info->params.push_back(param->Ident()->Variable()->AsLocalVariable()); } - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + + auto funcSignature = ir::FunctionSignature(nullptr, std::move(params), nullptr); auto *func = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), nullptr), nullptr, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::NONE}); + Allocator(), ir::ScriptFunction::ScriptFunctionData {nullptr, std::move(funcSignature), + ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::NONE}); func->SetScope(scope); scope->BindNode(func); @@ -268,23 +269,28 @@ std::pair ETSChecker::CreateScriptFuncti body->SetScope(scope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) id = AllocNode(compiler::Signatures::CCTOR, Allocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + auto signature = ir::FunctionSignature(nullptr, std::move(params), nullptr); + // clang-format off func = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::STATIC_BLOCK | - ir::ScriptFunctionFlags::EXPRESSION, - ir::ModifierFlags::STATIC}); + Allocator(), ir::ScriptFunction::ScriptFunctionData { + body, + std::move(signature), + ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::EXPRESSION, + ir::ModifierFlags::STATIC, + }); + // clang-format on } else { builder(scope, &statements, ¶ms); auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) id = AllocNode(compiler::Signatures::CTOR, Allocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + auto funcSignature = ir::FunctionSignature(nullptr, std::move(params), nullptr); func = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData { - ir::ScriptFunctionFlags::CONSTRUCTOR | ir::ScriptFunctionFlags::EXPRESSION, ir::ModifierFlags::PUBLIC}); + Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(funcSignature), + ir::ScriptFunctionFlags::CONSTRUCTOR | + ir::ScriptFunctionFlags::EXPRESSION, + ir::ModifierFlags::PUBLIC}); } func->SetScope(scope); @@ -578,10 +584,11 @@ ir::MethodDefinition *ETSChecker::CreateClassMethod(varbinder::ClassScope *class // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + + auto funcSignature = ir::FunctionSignature(nullptr, std::move(params), nullptr); auto *func = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::METHOD, modifierFlags}); + Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(funcSignature), + ir::ScriptFunctionFlags::METHOD, modifierFlags}); func->SetScope(scope); scope->BindNode(func); diff --git a/ets2panda/checker/ets/enum.cpp b/ets2panda/checker/ets/enum.cpp index 771ab0d6f2..206035f1ab 100644 --- a/ets2panda/checker/ets/enum.cpp +++ b/ets2panda/checker/ets/enum.cpp @@ -162,9 +162,12 @@ template flags |= ir::ModifierFlags::DECLARE; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + // clang-format off auto *const function = checker->AllocNode( - ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), bodyBlock, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::METHOD, flags, isDeclare}); + checker->Allocator(), ir::ScriptFunction::ScriptFunctionData { + bodyBlock, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), + ir::ScriptFunctionFlags::METHOD, flags, isDeclare}); + // clang-format on function->SetScope(functionScope); varbinder->AsETSBinder()->BuildInternalName(function); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index ad7093bf74..340dab4fc4 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1930,8 +1930,10 @@ ir::ScriptFunction *ETSChecker::CreateProxyFunc(ir::ArrowFunctionExpression *lam } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *func = Allocator()->New( - ir::FunctionSignature(nullptr, std::move(params), lambda->Function()->ReturnTypeAnnotation()), body, - ir::ScriptFunction::ScriptFunctionData {funcFlags, GetFlagsForProxyLambda(isStatic)}); + Allocator(), + ir::ScriptFunction::ScriptFunctionData { + body, ir::FunctionSignature(nullptr, std::move(params), lambda->Function()->ReturnTypeAnnotation()), + funcFlags, GetFlagsForProxyLambda(isStatic)}); func->SetScope(scope); if (!func->IsAsyncFunc()) { @@ -2223,10 +2225,10 @@ ir::MethodDefinition *ETSChecker::CreateLambdaImplicitCtor(ArenaVector(Allocator(), std::move(statements)); body->SetScope(scope); - auto *func = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::CONSTRUCTOR}); + auto *func = AllocNode( + Allocator(), + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::CONSTRUCTOR}); func->SetScope(scope); // Set the scopes @@ -2419,10 +2421,10 @@ ir::MethodDefinition *ETSChecker::CreateLambdaImplicitCtor(const lexer::SourceRa // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); - auto *func = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::CONSTRUCTOR}); + auto *func = AllocNode( + Allocator(), + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::CONSTRUCTOR}); func->SetScope(scope); // Bind the scopes scope->BindNode(func); @@ -2491,8 +2493,9 @@ ir::MethodDefinition *ETSChecker::CreateLambdaInvokeProto(util::StringView invok body->SetScope(scope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *func = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC}); + Allocator(), + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC}); func->SetScope(scope); scope->BindNode(func); @@ -3000,9 +3003,11 @@ ir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir: auto *nameId = AllocNode(name, Allocator()); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *scope = VarBinder()->Allocator()->New(Allocator(), paramScope); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *const func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), returnType), - body, ir::ScriptFunction::ScriptFunctionData {flags, modifiers}); + // clang-format off + auto *const func = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData { + body, ir::FunctionSignature(nullptr, std::move(params), returnType), flags, modifiers}); + // clang-format on func->SetScope(scope); func->SetIdent(nameId); if (body != nullptr && body->IsBlockStatement()) { @@ -3113,10 +3118,10 @@ void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr) } ArenaVector params(Allocator()->Adapter()); - auto *funcNode = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), trailingBlock, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::ARROW}); + auto *funcNode = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData {trailingBlock, + ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::ARROW}); funcNode->SetScope(funcScope); funcScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); @@ -3144,10 +3149,10 @@ ArenaVector ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallE auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(funcScope); - auto *funcNode = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::ARROW}); + auto *funcNode = AllocNode( + Allocator(), + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::ARROW}); funcNode->SetScope(funcScope); funcScope->BindNode(funcNode); auto *arrowFuncNode = AllocNode(Allocator(), funcNode); diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 3ec818dcc7..c45a3c923e 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2837,10 +2837,10 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty auto *body = checker->AllocNode(checker->Allocator(), std::move(stmts)); auto funcFlags = isSetter ? ir::ScriptFunctionFlags::SETTER : ir::ScriptFunctionFlags::GETTER; auto *const returnTypeAnn = isSetter ? nullptr : field->TypeAnnotation()->Clone(checker->Allocator(), nullptr); - auto *func = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - checker->AllocNode(ir::FunctionSignature(nullptr, std::move(params), returnTypeAnn), body, - ir::ScriptFunction::ScriptFunctionData {funcFlags, flags, true}); + auto *func = checker->AllocNode( + checker->Allocator(), + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnn), + funcFlags, flags, true}); func->SetRange(field->Range()); func->SetScope(functionScope); diff --git a/ets2panda/compiler/lowering/ets/defaultParameterLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParameterLowering.cpp index 880682ea72..1da70f9e68 100644 --- a/ets2panda/compiler/lowering/ets/defaultParameterLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParameterLowering.cpp @@ -210,8 +210,11 @@ ir::FunctionExpression *DefaultParameterLowering::CreateFunctionExpression( ir::AstNode *body = CreateFunctionBody(method, ctx, std::move(funcCallArgs)); - auto *funcNode = checker->AllocNode(std::move(signature), body, method->Function()->Flags(), - false, method->Function()->Language()); + auto *funcNode = checker->AllocNode( + checker->Allocator(), + ir::ScriptFunction::ScriptFunctionData { + body, std::move(signature), method->Function()->Flags(), {}, false, method->Function()->Language()}); + body->SetParent(funcNode); funcNode->AddModifier(method->Function()->Modifiers()); funcNode->SetRange({startLoc, endLoc}); diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index e5fb7fee43..53e8181d14 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -100,12 +100,12 @@ static ir::MethodDefinition *GenerateGetterOrSetter(checker::ETSChecker *const c auto signature = ir::FunctionSignature(nullptr, std::move(params), isSetter ? nullptr : field->TypeAnnotation()); - auto *func = isSetter ? checker->AllocNode( - std::move(signature), nullptr, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::SETTER, flags, true}) - : checker->AllocNode( - std::move(signature), nullptr, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::GETTER, flags, true}); + auto *func = checker->AllocNode( + checker->Allocator(), ir::ScriptFunction::ScriptFunctionData {nullptr, std::move(signature), + isSetter ? ir::ScriptFunctionFlags::SETTER + : ir::ScriptFunctionFlags::GETTER, + flags, true}); + func->SetRange(field->Range()); func->SetScope(functionScope); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index 66c8ff2453..e8a5d5e635 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -88,9 +88,12 @@ ir::MethodDefinition *GlobalClassHandler::CreateInitMethod() ArenaVector statements(allocator_->Adapter()); auto *initBody = NodeAllocator::Alloc(allocator_, allocator_, std::move(statements)); - auto *initFunc = - NodeAllocator::Alloc(allocator_, ir::FunctionSignature(nullptr, std::move(params), nullptr), - initBody, functionFlags, false, Language(Language::Id::ETS)); + auto funcSignature = ir::FunctionSignature(nullptr, std::move(params), nullptr); + + auto *initFunc = NodeAllocator::Alloc( + allocator_, allocator_, + ir::ScriptFunction::ScriptFunctionData { + initBody, std::move(funcSignature), functionFlags, {}, false, Language(Language::Id::ETS)}); initFunc->SetIdent(initIdent); initFunc->AddModifier(functionModifiers); @@ -162,9 +165,11 @@ ir::ClassStaticBlock *GlobalClassHandler::CreateCCtor(const ArenaVector(allocator_, allocator_, std::move(statements)); auto *func = NodeAllocator::Alloc( - allocator_, ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData {ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::HIDDEN, + allocator_, allocator_, + ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::HIDDEN, ir::ModifierFlags::STATIC, false, Language(Language::Id::ETS)}); + func->SetIdent(id); auto *funcExpr = NodeAllocator::Alloc(allocator_, func); diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index 3292f45dac..ee69383660 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -23,13 +23,14 @@ namespace ark::es2panda::ir { -ScriptFunction::ScriptFunction(FunctionSignature &&signature, AstNode *body, ScriptFunctionData &&data) +ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data) : AstNode(AstNodeType::SCRIPT_FUNCTION, data.flags), - irSignature_(std::move(signature)), - body_(body), + irSignature_(std::move(data.signature)), + body_(data.body), funcFlags_(data.funcFlags), declare_(data.declare), - lang_(data.lang) + lang_(data.lang), + returnStatements_(allocator->Adapter()) { for (auto *param : irSignature_.Params()) { param->SetParent(this); diff --git a/ets2panda/ir/base/scriptFunction.h b/ets2panda/ir/base/scriptFunction.h index 6101c12aeb..9dcf2884ef 100644 --- a/ets2panda/ir/base/scriptFunction.h +++ b/ets2panda/ir/base/scriptFunction.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H #define ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H +#include "ir/statements/returnStatement.h" #include "ir/astNode.h" #include "varbinder/scope.h" #include "util/enumbitops.h" @@ -38,6 +39,8 @@ class ScriptFunction : public AstNode { public: // Need to reduce the number of constructor parameters to pass OHOS CI code check struct ScriptFunctionData { + AstNode *body = nullptr; + FunctionSignature &&signature; ir::ScriptFunctionFlags funcFlags = ir::ScriptFunctionFlags::NONE; ir::ModifierFlags flags = ir::ModifierFlags::NONE; bool declare = false; @@ -50,13 +53,7 @@ public: NO_COPY_SEMANTIC(ScriptFunction); NO_MOVE_SEMANTIC(ScriptFunction); - explicit ScriptFunction(FunctionSignature &&signature, AstNode *body, ScriptFunctionData &&data); - - explicit ScriptFunction(FunctionSignature &&signature, AstNode *body, ir::ScriptFunctionFlags funcFlags, - bool declare, Language lang) - : ScriptFunction(std::move(signature), body, {funcFlags, {}, declare, lang}) - { - } + explicit ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data); [[nodiscard]] const Identifier *Id() const noexcept { @@ -88,6 +85,16 @@ public: return irSignature_.Params(); } + const ArenaVector &ReturnStatements() const + { + return returnStatements_; + } + + ArenaVector &ReturnStatements() + { + return returnStatements_; + } + [[nodiscard]] const TSTypeParameterDeclaration *TypeParams() const noexcept { return irSignature_.TypeParams(); @@ -108,6 +115,11 @@ public: return body_; } + void AddReturnStatement(ReturnStatement *returnStatement) + { + returnStatements_.push_back(returnStatement); + } + void SetBody(AstNode *body) noexcept { body_ = body; @@ -298,6 +310,7 @@ private: checker::Signature *signature_ {}; bool declare_; es2panda::Language lang_; + ArenaVector returnStatements_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h index b13c357fc7..5d25484704 100644 --- a/ets2panda/ir/statements/blockStatement.h +++ b/ets2panda/ir/statements/blockStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2024 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 @@ -66,14 +66,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - for (auto *statement : statements_) { - if (statement != nullptr) { - statement->SetReturnType(checker, type); - } - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/doWhileStatement.h b/ets2panda/ir/statements/doWhileStatement.h index 2a63bb2731..734fa98160 100644 --- a/ets2panda/ir/statements/doWhileStatement.h +++ b/ets2panda/ir/statements/doWhileStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2024 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 @@ -53,12 +53,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/forInStatement.h b/ets2panda/ir/statements/forInStatement.h index 7d8761d602..66dc9ef374 100644 --- a/ets2panda/ir/statements/forInStatement.h +++ b/ets2panda/ir/statements/forInStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -63,12 +63,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/forOfStatement.h b/ets2panda/ir/statements/forOfStatement.h index 5d61f1a802..9a85af45df 100644 --- a/ets2panda/ir/statements/forOfStatement.h +++ b/ets2panda/ir/statements/forOfStatement.h @@ -89,12 +89,6 @@ public: [[nodiscard]] ForOfStatement *Clone(ArenaAllocator *allocator, AstNode *parent) override; void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/forUpdateStatement.h b/ets2panda/ir/statements/forUpdateStatement.h index 5a172f4faf..7477d9252a 100644 --- a/ets2panda/ir/statements/forUpdateStatement.h +++ b/ets2panda/ir/statements/forUpdateStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -73,12 +73,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/ifStatement.h b/ets2panda/ir/statements/ifStatement.h index 3541f32ee2..328c785f35 100644 --- a/ets2panda/ir/statements/ifStatement.h +++ b/ets2panda/ir/statements/ifStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -58,16 +58,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (consequent_ != nullptr) { - consequent_->SetReturnType(checker, type); - } - if (alternate_ != nullptr) { - alternate_->SetReturnType(checker, type); - } - } - void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Dump(ir::SrcDumper *dumper) const override; diff --git a/ets2panda/ir/statements/labelledStatement.cpp b/ets2panda/ir/statements/labelledStatement.cpp index 7f5c185ba5..f0d65e3417 100644 --- a/ets2panda/ir/statements/labelledStatement.cpp +++ b/ets2panda/ir/statements/labelledStatement.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2024 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 diff --git a/ets2panda/ir/statements/labelledStatement.h b/ets2panda/ir/statements/labelledStatement.h index 82e5fe5cb0..be41578593 100644 --- a/ets2panda/ir/statements/labelledStatement.h +++ b/ets2panda/ir/statements/labelledStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -49,12 +49,6 @@ public: const ir::AstNode *GetReferencedStatement() const; void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/switchCaseStatement.h b/ets2panda/ir/statements/switchCaseStatement.h index a90befde22..c8bfb6425e 100644 --- a/ets2panda/ir/statements/switchCaseStatement.h +++ b/ets2panda/ir/statements/switchCaseStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -44,14 +44,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - for (auto *statement : consequent_) { - if (statement != nullptr) { - statement->SetReturnType(checker, type); - } - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/switchStatement.cpp b/ets2panda/ir/statements/switchStatement.cpp index 6b0d01ea01..755d568e25 100644 --- a/ets2panda/ir/statements/switchStatement.cpp +++ b/ets2panda/ir/statements/switchStatement.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -88,12 +88,4 @@ checker::Type *SwitchStatement::Check(checker::ETSChecker *const checker) return checker->GetAnalyzer()->Check(this); } -void SwitchStatement::SetReturnType(checker::ETSChecker *checker, checker::Type *type) -{ - for (auto *cs : cases_) { - if (cs != nullptr) { - cs->SetReturnType(checker, type); - } - } -} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/switchStatement.h b/ets2panda/ir/statements/switchStatement.h index fa533dc956..35eb529644 100644 --- a/ets2panda/ir/statements/switchStatement.h +++ b/ets2panda/ir/statements/switchStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -75,7 +75,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/tryStatement.cpp b/ets2panda/ir/statements/tryStatement.cpp index b74000469d..05e79264d6 100644 --- a/ets2panda/ir/statements/tryStatement.cpp +++ b/ets2panda/ir/statements/tryStatement.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -110,18 +110,4 @@ checker::Type *TryStatement::Check([[maybe_unused]] checker::ETSChecker *checker return checker->GetAnalyzer()->Check(this); } -void TryStatement::SetReturnType(checker::ETSChecker *checker, checker::Type *type) -{ - if (block_ != nullptr) { - block_->SetReturnType(checker, type); - } - if (finalizer_ != nullptr) { - finalizer_->SetReturnType(checker, type); - } - for (auto *catchClause : catchClauses_) { - if (catchClause != nullptr) { - catchClause->SetReturnType(checker, type); - } - } -} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/tryStatement.h b/ets2panda/ir/statements/tryStatement.h index f9b0b5c440..a861eaf9b1 100644 --- a/ets2panda/ir/statements/tryStatement.h +++ b/ets2panda/ir/statements/tryStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -83,7 +83,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/statements/whileStatement.h b/ets2panda/ir/statements/whileStatement.h index f9b00bb98f..ddac1e4ea7 100644 --- a/ets2panda/ir/statements/whileStatement.h +++ b/ets2panda/ir/statements/whileStatement.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -53,12 +53,6 @@ public: } void TransformChildren(const NodeTransformer &cb) override; - void SetReturnType(checker::ETSChecker *checker, checker::Type *type) override - { - if (body_ != nullptr) { - body_->SetReturnType(checker, type); - } - } void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index b2a5cf63c1..f35a5d1baa 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -788,8 +788,12 @@ ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus newStatus, ir::Identif } functionContext.AddFlag(throwMarker); - auto *funcNode = AllocNode(std::move(signature), body, functionContext.Flags(), false, - GetContext().GetLanguage()); + // clang-format off + auto *funcNode = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData { + body, std::move(signature), functionContext.Flags(), {}, false, GetContext().GetLanguage()}); + // clang-format on + funcNode->SetRange({startLoc, endLoc}); return funcNode; @@ -1507,8 +1511,8 @@ ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, i } auto *func = AllocNode( - std::move(signature), body, - ir::ScriptFunction::ScriptFunctionData {functionContext.Flags(), flags, true, GetContext().GetLanguage()}); + Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), functionContext.Flags(), flags, + true, GetContext().GetLanguage()}); if ((flags & ir::ModifierFlags::STATIC) == 0 && body == nullptr) { func->AddModifier(ir::ModifierFlags::ABSTRACT); diff --git a/ets2panda/parser/expressionParser.cpp b/ets2panda/parser/expressionParser.cpp index 275f6ca5b8..e6a519718b 100644 --- a/ets2panda/parser/expressionParser.cpp +++ b/ets2panda/parser/expressionParser.cpp @@ -325,9 +325,16 @@ ir::ArrowFunctionExpression *ParserImpl::ParseArrowFunctionExpressionBody(ArrowF endLoc = body->End(); } + // clang-format off funcNode = AllocNode( - ir::FunctionSignature(typeParamDecl, std::move(desc->params), returnTypeAnnotation), body, - arrowFunctionContext->Flags(), false, context_.GetLanguage()); + Allocator(), ir::ScriptFunction::ScriptFunctionData { + body, + ir::FunctionSignature(typeParamDecl, std::move(desc->params), returnTypeAnnotation), + arrowFunctionContext->Flags(), + {}, + false, + context_.GetLanguage()}); + // clang-format on funcNode->SetRange({desc->startLoc, endLoc}); auto *arrowFuncNode = AllocNode(Allocator(), funcNode); diff --git a/ets2panda/parser/parserImpl.cpp b/ets2panda/parser/parserImpl.cpp index 3e147ba831..e43f191861 100644 --- a/ets2panda/parser/parserImpl.cpp +++ b/ets2panda/parser/parserImpl.cpp @@ -570,11 +570,13 @@ ir::ClassElement *ParserImpl::ParseClassStaticBlock() ArenaVector statements = ParseStatementList(); auto *body = AllocNode(Allocator(), std::move(statements)); - auto *func = - AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunction::ScriptFunctionData { - ir::ScriptFunctionFlags::EXPRESSION | ir::ScriptFunctionFlags::STATIC_BLOCK, - ir::ModifierFlags::STATIC, false, context_.GetLanguage()}); + // clang-format off + auto *func = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData { + body, ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::EXPRESSION | ir::ScriptFunctionFlags::STATIC_BLOCK, + ir::ModifierFlags::STATIC, false, context_.GetLanguage()}); + // clang-format on auto *funcExpr = AllocNode(func); auto *staticBlock = AllocNode(funcExpr, Allocator()); @@ -657,10 +659,14 @@ ir::MethodDefinition *ParserImpl::BuildImplicitConstructor(ir::ClassDefinitionMo } auto *body = AllocNode(Allocator(), std::move(statements)); - auto *func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, - ir::ScriptFunctionFlags::CONSTRUCTOR | - ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED, - false, context_.GetLanguage()); + auto *func = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData {body, + ir::FunctionSignature(nullptr, std::move(params), nullptr), + ir::ScriptFunctionFlags::CONSTRUCTOR | + ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED, + {}, + false, + context_.GetLanguage()}); auto *funcExpr = AllocNode(func); auto *key = AllocNode("constructor", Allocator()); @@ -915,8 +921,10 @@ ir::ScriptFunction *ParserImpl::ParseFunction(ParserStatus newStatus) } functionContext.AddFlag(throw_marker); - auto *funcNode = AllocNode(std::move(signature), body, functionContext.Flags(), - isDeclare && letDeclare, context_.GetLanguage()); + auto *funcNode = AllocNode( + Allocator(), + ir::ScriptFunction::ScriptFunctionData { + body, std::move(signature), functionContext.Flags(), {}, isDeclare && letDeclare, context_.GetLanguage()}); funcNode->SetRange({startLoc, endLoc}); return funcNode; diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index c8479d0291..ae8e853a21 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -2012,7 +2012,8 @@ extern "C" es2panda_AstNode *CreateScriptFunction(es2panda_Context *context, es2 ir::FunctionSignature sig(irTypeParams, std::move(irParams), irReturnTypeAnnotation); auto func = allocator->New( - std::move(sig), nullptr, ir::ScriptFunction::ScriptFunctionData {irFunctionFlags, irModifierFlags, isDeclare}); + allocator, + ir::ScriptFunction::ScriptFunctionData {nullptr, std::move(sig), irFunctionFlags, irModifierFlags, isDeclare}); return reinterpret_cast(func); } diff --git a/ets2panda/test/test-lists/parser/parser-js-ignored.txt b/ets2panda/test/test-lists/parser/parser-js-ignored.txt index b626e32de2..1c178a7f1e 100644 --- a/ets2panda/test/test-lists/parser/parser-js-ignored.txt +++ b/ets2panda/test/test-lists/parser/parser-js-ignored.txt @@ -104,4 +104,7 @@ compiler/ets/n_assignGenericWithNullableTypeParamToNonNullable.ets # Related to void revert compiler/ets/lambda_infer_type/lambda_cast_infer_type_void.ets + +# panda#15575 compiler/ets/promiseVoid.ets + -- Gitee