From db6ee58b996244a08d488ac229dabf2ed78eea64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=AE=B6=E7=86=99?= Date: Wed, 18 Jun 2025 15:44:41 +0800 Subject: [PATCH] Fix es2panda compile crash bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICFL1B Signed-off-by: 梁家熙 --- ets2panda/checker/ETSAnalyzer.cpp | 5 ++ ets2panda/checker/ets/helpers.cpp | 9 ++- ets2panda/checker/ets/utilityTypeHandlers.cpp | 4 + ets2panda/ir/statements/classDeclaration.cpp | 16 ++++ ets2panda/ir/statements/classDeclaration.h | 2 + ets2panda/ir/statements/forOfStatement.cpp | 6 +- .../ast/parser/ets/invalid_of_testcase.ets | 35 +++++++++ .../ast/parser/ets/lambda_param_array.ets | 31 ++++++++ .../ast/parser/ets/record_generic_error.ets | 73 +++++++++++++++++++ 9 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 ets2panda/test/ast/parser/ets/invalid_of_testcase.ets create mode 100644 ets2panda/test/ast/parser/ets/lambda_param_array.ets create mode 100644 ets2panda/test/ast/parser/ets/record_generic_error.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 3aa4109c2e..2f4e8ae2ae 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1671,6 +1671,11 @@ static Type *TransformTypeForMethodReference(ETSChecker *checker, ir::Expression checker->LogError(diagnostic::OVERLOADED_METHOD_AS_VALUE, getUseSite()); return checker->GlobalTypeError(); } + + if (signatures.empty()) { + checker->LogError(diagnostic::NO_CALL_SIGNATURE, {"function"}, getUseSite()); + return checker->GlobalTypeError(); + } return functionType->MethodToArrow(checker); } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 553abd66e2..adce2577b1 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1492,8 +1492,9 @@ static void CollectAliasParametersForBoxing(Type *expandedAliasType, std::setIsETSObjectType()) { auto objectType = expandedAliasType->AsETSObjectType(); - needToBeBoxed = - objectType->GetDeclNode()->IsClassDefinition() || objectType->GetDeclNode()->IsTSInterfaceDeclaration(); + auto objectTypeNode = objectType->GetDeclNode(); + needToBeBoxed = objectTypeNode != nullptr && + (objectTypeNode->IsClassDefinition() || objectTypeNode->IsTSInterfaceDeclaration()); for (const auto typeArgument : objectType->TypeArguments()) { CollectAliasParametersForBoxing(typeArgument, parametersNeedToBeBoxed, needToBeBoxed); } @@ -2464,6 +2465,10 @@ void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunction Signature *maybeSubstitutedFunctionSig) { for (size_t i = 0; i < lambda->Params().size(); ++i) { + if (!lambda->Params().at(i)->IsETSParameterExpression()) { + LogError(diagnostic::NO_SUCH_SIG_WITH_TRAILING_LAMBDA, {}, lambda->Params().at(i)->Start()); + return; + } auto *const lambdaParam = lambda->Params().at(i)->AsETSParameterExpression()->Ident(); if (lambdaParam->TypeAnnotation() == nullptr) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index c267defa3c..14129de4c3 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -132,6 +132,10 @@ Type *ETSChecker::CreatePartialType(Type *const typeToBePartial) return HandleUnionForPartialType(typeToBePartial->AsETSUnionType()); } + if (typeToBePartial->IsTypeError()) { + return typeToBePartial; + } + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) return CreatePartialTypeClass(typeToBePartial->AsETSObjectType(), typeToBePartial->Variable()->Declaration()->Node()); diff --git a/ets2panda/ir/statements/classDeclaration.cpp b/ets2panda/ir/statements/classDeclaration.cpp index 398e74f231..0659ad3742 100644 --- a/ets2panda/ir/statements/classDeclaration.cpp +++ b/ets2panda/ir/statements/classDeclaration.cpp @@ -133,4 +133,20 @@ checker::VerifiedType ClassDeclaration::Check(checker::ETSChecker *checker) { return {this, checker->GetAnalyzer()->Check(this)}; } + +ClassDeclaration *ClassDeclaration::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *const clone = allocator->New(def_, allocator); + ArenaVector decorators(allocator->Adapter()); + for (auto *decorator : Decorators()) { + decorators.emplace_back(decorator->Clone(allocator, clone)->AsDecorator()); + } + clone->decorators_ = std::move(decorators); + if (parent != nullptr) { + clone->SetParent(parent); + } + clone->SetRange(range_); + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h index 5ea6d0e8d0..ab3ed24a51 100644 --- a/ets2panda/ir/statements/classDeclaration.h +++ b/ets2panda/ir/statements/classDeclaration.h @@ -86,6 +86,8 @@ public: void SetDefinition(ClassDefinition *def); + [[nodiscard]] ClassDeclaration *Clone(ArenaAllocator *allocator, AstNode *parent) override; + protected: explicit ClassDeclaration(AstNodeType type, ClassDefinition *const def, ArenaAllocator *const allocator) : Statement(type), def_(def), decorators_(allocator->Adapter()) diff --git a/ets2panda/ir/statements/forOfStatement.cpp b/ets2panda/ir/statements/forOfStatement.cpp index 953d282268..c1c8d1f6cc 100644 --- a/ets2panda/ir/statements/forOfStatement.cpp +++ b/ets2panda/ir/statements/forOfStatement.cpp @@ -29,7 +29,11 @@ checker::Type *ForOfStatement::CreateUnionIteratorTypes(checker::ETSChecker *che if (it->IsETSStringType()) { types.emplace_back(checker->GlobalCharBuiltinType()); } else if (it->IsETSObjectType()) { - types.emplace_back(this->CheckIteratorMethodForObject(checker, it->AsETSObjectType())); + auto *const objType = CheckIteratorMethodForObject(checker, it->AsETSObjectType()); + if (objType == nullptr) { + return nullptr; + } + types.emplace_back(objType); } else if (it->IsETSArrayType()) { types.emplace_back(it->AsETSArrayType()->ElementType()->Clone(checker)); types.back()->RemoveTypeFlag(checker::TypeFlag::CONSTANT); diff --git a/ets2panda/test/ast/parser/ets/invalid_of_testcase.ets b/ets2panda/test/ast/parser/ets/invalid_of_testcase.ets new file mode 100644 index 0000000000..56cb470368 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/invalid_of_testcase.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. + */ + +function processValue(value: string | number): void { + if (typeof value === 'string') { + for (const char of value) { + console.log(char); + } + } else { + console.log(value.toString()); + } +} + +const testValues: (string | number)[] = ['hello', 42, 'world', 7]; + +for (const item of testValues) { + processValue(item); +} + +/* @@? 18:16 Error SyntaxError: Identifier expected, got 'char'. */ +/* @@? 18:24 Error TypeError: Object type doesn't have proper iterator method. */ +/* @@? 18:24 Error TypeError: 'For-of' statement source expression is not of iterable type. */ +/* @@? 19:19 Error SyntaxError: Unexpected token 'char'. */ diff --git a/ets2panda/test/ast/parser/ets/lambda_param_array.ets b/ets2panda/test/ast/parser/ets/lambda_param_array.ets new file mode 100644 index 0000000000..51caba27ab --- /dev/null +++ b/ets2panda/test/ast/parser/ets/lambda_param_array.ets @@ -0,0 +1,31 @@ +/* + * 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 ResizeObserverEntry {} +class ResizeObserver { + constructor(callback: (entries: ResizeObserverEntry[]) => void) {} + disconnect(): void {} + observe(target: Element): void {} + unobserve(target: Element): void {} +} + +const resizeObserver = new ResizeObserver(([entry]) => { + // Dummy usage +}); + +/* @@? 20:21 Error TypeError: Cannot find type 'Element'. */ +/* @@? 21:23 Error TypeError: Cannot find type 'Element'. */ +/* @@? 24:43 Error TypeError: No matching call signature with trailing lambda */ +/* @@? 24:53 Error SyntaxError: Unexpected token '=>'. */ diff --git a/ets2panda/test/ast/parser/ets/record_generic_error.ets b/ets2panda/test/ast/parser/ets/record_generic_error.ets new file mode 100644 index 0000000000..39cbe808a7 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/record_generic_error.ets @@ -0,0 +1,73 @@ +/* + * 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 C { + x: string = ""; +} + +class D { + x: string = ""; +} + +// Define the assign function with compatible types +function assign>(target: T, source: Partial): void { + Object.assign(target as Record, source as Record); +} + +// Replace BaseObject with Record usage +type BaseObject = Record; + +class X { + x: T; + + constructor(init?: Partial) { + // Initialize x with an empty object or a partial initialization + this.x = {} as T; + if (init) { + assign(this.x, init); // Explicitly specify generic type T + } + } +} + +function foo(t: X, t2: X): Record { + // Manually merge fields from both objects + const merged: Record = {}; + const obj1: Record = t.x as Record; + const obj2: Record = t2.x as Record; + + // Shallow copy properties from obj1 + Object.keys(obj1).forEach((key: string) => { + merged[key] = obj1[key]; + }); + + // Shallow copy properties from obj2 + Object.keys(obj2).forEach((key: string) => { + merged[key] = obj2[key]; + }); + + return merged; +} + +/* @@? 25:42 Error TypeError: Cannot find type 'any'. */ +/* @@? 26:3 Error TypeError: No matching call signature for assign(Record, Record) */ +/* @@? 26:17 Error TypeError: Type 'Record' is not compatible with type 'Record' at index 1 */ +/* @@? 30:34 Error TypeError: Cannot find type 'any'. */ +/* @@? 37:14 Error TypeError: Target type for class composite needs to be an object type, found 'T' */ +/* @@? 52:5 Error TypeError: No matching indexing signature for $_set(String, Object|undefined) */ +/* @@? 52:12 Error TypeError: Cannot find index access method with the required signature. */ +/* @@? 52:19 Error TypeError: Type 'Object|undefined' is not compatible with type 'Object' at index 2 */ +/* @@? 57:5 Error TypeError: No matching indexing signature for $_set(String, Object|undefined) */ +/* @@? 57:12 Error TypeError: Cannot find index access method with the required signature. */ +/* @@? 57:19 Error TypeError: Type 'Object|undefined' is not compatible with type 'Object' at index 2 */ -- Gitee