diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index a42ab34a91a218ba1a24a059e7b8b652a1ab3103..1738cb4b73e4e7c03b72469bf31e84a0a1250c02 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -285,6 +285,8 @@ public: varbinder::Variable *GetExtensionFuncVarInFunctionScope(const ir::MemberExpression *const memberExpr); varbinder::Variable *ResolveInstanceExtension(const ir::MemberExpression *memberExpr); void CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig); + ArenaVector ExtractFromIfStatement( + const ArenaVector &stmts); void CheckThisOrSuperCallInConstructor(ETSObjectType *classType, Signature *ctorSig); void CheckExpressionsInConstructor(const ArenaVector &arguments); ArenaVector CheckMemberOrCallOrObjectExpressionInConstructor(const ir::Expression *arg); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 7303f27a93e7fd98bbd3105183cd30c64e14ebec..a31ab0a591ff2e92a7aa10b9fe02e0403290dcdb 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -1450,21 +1450,23 @@ void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig } auto &stmts = ctorSig->Function()->Body()->AsBlockStatement()->Statements(); - const auto thisCall = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { + + auto extendStmts = ExtractFromIfStatement(stmts); + const auto thisCall = std::find_if(extendStmts.begin(), extendStmts.end(), [](const ir::Statement *stmt) { return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() && stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression(); }); // There is an alternate constructor invocation, no need for super constructor invocation - if (thisCall != stmts.end()) { + if (thisCall != extendStmts.end()) { return; } - const auto superExpr = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { + const auto superExpr = std::find_if(extendStmts.begin(), extendStmts.end(), [](const ir::Statement *stmt) { return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() && stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression(); }); // There is no super expression - if (superExpr == stmts.end()) { + if (superExpr == extendStmts.end()) { const auto superTypeCtorSigs = classType->SuperType()->ConstructSignatures(); const auto superTypeCtorSig = std::find_if(superTypeCtorSigs.begin(), superTypeCtorSigs.end(), [](const Signature *sig) { return sig->MinArgCount() == 0; }); @@ -1477,6 +1479,36 @@ void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig } } +// Extract statements under the if and else conditions of one or more layers in 'stmts' +ArenaVector ETSChecker::ExtractFromIfStatement( + const ArenaVector &stmts) +{ + ArenaVector newStmts(ProgramAllocator()->Adapter()); + auto tryExtractFromIfStatement = [&](const auto &self, const ir::Statement *stmt) -> bool { + if (!stmt->IsIfStatement()) { + return false; + } + auto ifStmt = stmt->AsIfStatement(); + if (ifStmt->Consequent() != nullptr && ifStmt->Consequent()->IsBlockStatement()) { + self(self, ifStmt->Consequent()->AsBlockStatement()->Statements()); + } + if (ifStmt->Alternate() && ifStmt->Alternate()->IsBlockStatement()) { + self(self, ifStmt->Alternate()->AsBlockStatement()->Statements()); + } + + return true; + }; + auto extractor = [&](const auto &self, const ArenaVector &statements) -> void { + for (const auto &stmt : statements) { + if (!tryExtractFromIfStatement(self, stmt)) { + newStmts.push_back(stmt); + } + } + }; + extractor(extractor, stmts); + return newStmts; +} + void ETSChecker::CheckThisOrSuperCallInConstructor(ETSObjectType *classType, Signature *ctorSig) { if (classType == GlobalETSObjectType()) { @@ -1847,11 +1879,6 @@ ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjec LogError(diagnostic::CTOR_CLASS_NOT_FIRST, {msg}, node->Start()); return classType; } - - if (sig->Function()->Body()->AsBlockStatement()->Statements().front() != node->Parent()->Parent()) { - LogError(diagnostic::CTOR_CLASS_NOT_FIRST, {msg}, node->Start()); - return classType; - } } if (HasStatus(checker::CheckerStatus::IN_STATIC_CONTEXT)) { diff --git a/ets2panda/test/runtime/ets/constructor_super_under_ifstmt.ets b/ets2panda/test/runtime/ets/constructor_super_under_ifstmt.ets new file mode 100644 index 0000000000000000000000000000000000000000..c6a35271b7e2b7008d6c3a577652399e084dcf48 --- /dev/null +++ b/ets2panda/test/runtime/ets/constructor_super_under_ifstmt.ets @@ -0,0 +1,35 @@ +/* + * 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. + */ + +class ColoredPoint { + color: number; + constructor(color: number) { + this.color = color + } +} + +class BWPoint extends ColoredPoint { + constructor(black: boolean) { + if (black) { + super(0) + } else { + super(1) + } + } +} + +function main() { + arktest.assertEQ(new BWPoint(false).color, 1) +}