From ac6e91f5949eb8ac70a0e5a0b1fa52405e1a3fe0 Mon Sep 17 00:00:00 2001 From: Boglarka Haag Date: Tue, 2 Jul 2024 15:20:40 +0200 Subject: [PATCH] [ArkTs frontend] Inferred return type fix Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IAAQ83 Reason: There were issues with methods without explicit return type. In some cases it resulted in false CTE errors like when an abstract method implementation didn't have an expicit return type, in others it caused problems when the return value was assigned to a variable. Description: Checking orders were fixed. Extra checks were added to some steps to make sure everything has it's real type before comparing. Test scenarios (new, modified, affected functions): infer_imported_function_return_type.ets infer_overriding_function_return_type.ets infer_methed_type_1.ets infer_methed_type_2.ets infer_methed_type_3.ets infer_methed_type_4.ets Signed-off-by: Haag Boglarka --- ets2panda/checker/ETSAnalyzer.cpp | 24 +- ets2panda/checker/ETSAnalyzerHelpers.cpp | 4 + ets2panda/checker/ETSchecker.h | 1 + ets2panda/checker/ets/function.cpp | 16 + ets2panda/checker/ets/helpers.cpp | 3 + ets2panda/checker/ets/object.cpp | 8 + ets2panda/checker/types/ets/etsObjectType.cpp | 2 +- ...imported_function_return_type-expected.txt | 478 ++++++++++++ .../infer_imported_function_return_type.ets | 20 + ...rted_function_return_type_lib-expected.txt | 458 +++++++++++ ...nfer_imported_function_return_type_lib.ets | 22 + ...overriding_method_return_type-expected.txt | 710 ++++++++++++++++++ .../infer_overriding_method_return_type.ets | 24 + .../test/runtime/ets/infer_method_type_1.ets | 44 ++ .../test/runtime/ets/infer_method_type_2.ets | 28 + .../test/runtime/ets/infer_method_type_3.ets | 30 + .../test/runtime/ets/infer_method_type_4.ets | 41 + 17 files changed, 1905 insertions(+), 8 deletions(-) create mode 100644 ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type-expected.txt create mode 100644 ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type.ets create mode 100644 ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib-expected.txt create mode 100644 ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib.ets create mode 100644 ets2panda/test/parser/ets/infer_overriding_method_return_type-expected.txt create mode 100644 ets2panda/test/parser/ets/infer_overriding_method_return_type.ets create mode 100644 ets2panda/test/runtime/ets/infer_method_type_1.ets create mode 100644 ets2panda/test/runtime/ets/infer_method_type_2.ets create mode 100644 ets2panda/test/runtime/ets/infer_method_type_3.ets create mode 100644 ets2panda/test/runtime/ets/infer_method_type_4.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 6b6789ee59..4f1cb7d0c3 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -65,11 +65,15 @@ checker::Type *ETSAnalyzer::Check(ir::CatchClause *st) const checker::Type *ETSAnalyzer::Check(ir::ClassDefinition *node) const { ETSChecker *checker = GetETSChecker(); + if (node->TsType() == nullptr) { checker->BuildBasicClassProperties(node); } - checker->CheckClassDefinition(node); + if (!node->IsClassDefinitionChecked()) { + checker->CheckClassDefinition(node); + } + return nullptr; } @@ -1083,6 +1087,10 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) { checker::SavedCheckerContext savedCtx(checker, checker->Context().Status(), expr->Signature()->Owner()); expr->Signature()->OwnerVar()->Declaration()->Node()->Check(checker); + if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE) && + expr->Signature()->Function()->HasBody()) { + checker->CollectReturnStatements(expr->Signature()->Function()); + } returnType = expr->Signature()->ReturnType(); // NOTE(vpukhov): #14902 substituted signature is not updated } @@ -2478,14 +2486,16 @@ checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const checker::ETSObjectType *interfaceType {}; - if (st->TsType() == nullptr) { - interfaceType = checker->BuildBasicInterfaceProperties(st); - ASSERT(interfaceType != nullptr); - interfaceType->SetSuperType(checker->GlobalETSObjectType()); - checker->CheckInvokeMethodsLegitimacy(interfaceType); - st->SetTsType(interfaceType); + if (st->TsType() != nullptr) { + return st->TsType(); } + interfaceType = checker->BuildBasicInterfaceProperties(st); + ASSERT(interfaceType != nullptr); + interfaceType->SetSuperType(checker->GlobalETSObjectType()); + checker->CheckInvokeMethodsLegitimacy(interfaceType); + st->SetTsType(interfaceType); + checker::ScopeContext scopeCtx(checker, st->Scope()); auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interfaceType); diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index d892ccf2ee..040e6dffa4 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -85,6 +85,10 @@ void CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *exte !classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) { checker->ThrowTypeError("Extension function can only defined for class and interface type.", node->Start()); } + if (classType->Variable()->Declaration()->Node()->IsClassDefinition() && + !classType->Variable()->Declaration()->Node()->AsClassDefinition()->IsClassDefinitionChecked()) { + classType->Variable()->Declaration()->Node()->Check(checker); + } // NOTE(gogabr): should be done in a lowering ReplaceThisInExtensionMethod(checker, extensionFunc); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 46185b17fd..f994fce0ea 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -633,6 +633,7 @@ public: ETSObjectType *GetCachedFunctionalInterface(ir::ETSFunctionType *type); void CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectType *ifaceType); + void CollectReturnStatements(ir::AstNode *parent); ir::ETSParameterExpression *AddParam(util::StringView name, ir::TypeNode *type); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 75930ae11b..a28587c49d 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1876,4 +1876,20 @@ void ETSChecker::CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectTy functionalInterfaceCache_.emplace(hash, ifaceType); } +void ETSChecker::CollectReturnStatements(ir::AstNode *parent) +{ + parent->Iterate([this](ir::AstNode *childNode) -> void { + if (childNode->IsScriptFunction()) { + return; + } + + if (childNode->IsReturnStatement()) { + ir::ReturnStatement *returnStmt = childNode->AsReturnStatement(); + returnStmt->Check(this); + } + + CollectReturnStatements(childNode); + }); +} + } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a68f0cab73..c9483d4d89 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2160,6 +2160,9 @@ void ETSChecker::GenerateGetterSetterBody(ArenaVector &stmts, A memberExpression->SetTsType(field->TsType()); memberExpression->SetPropVar(field->Key()->Variable()->AsLocalVariable()); memberExpression->SetRange(classDef->Range()); + if (memberExpression->ObjType() == nullptr && classDef->TsType() != nullptr) { + memberExpression->SetObjectType(classDef->TsType()->AsETSObjectType()); + } if (!isSetter) { stmts.push_back(AllocNode(memberExpression)); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index aeb7272c09..575de767d2 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -714,6 +714,10 @@ void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::Sourc isSetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::SETTER); isExternal = (*abstractSignature)->Function()->IsExternal(); for (auto *const implemented : implementedSignatures) { + if (implemented->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) { + implemented->OwnerVar()->Declaration()->Node()->Check(this); + } + Signature *substImplemented = AdjustForTypeParameters(*abstractSignature, implemented); if (substImplemented == nullptr) { @@ -862,6 +866,10 @@ void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) { classDef->SetClassDefinitionChecked(); auto *classType = classDef->TsType()->AsETSObjectType(); + if (classType->SuperType() != nullptr) { + classType->SuperType()->GetDeclNode()->Check(this); + } + auto newStatus = checker::CheckerStatus::IN_CLASS; classType->SetEnclosingType(Context().ContainingClass()); diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 33c021fe04..ec9c3ed180 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -911,7 +911,7 @@ void ETSObjectType::InstantiateProperties() const } ASSERT(!propertiesInstantiated_); - checker->ResolveDeclaredMembersOfObject(this); + declNode_->Check(checker); for (auto *const it : baseType_->ConstructSignatures()) { auto *newSig = it->Substitute(relation_, substitution_); diff --git a/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type-expected.txt b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type-expected.txt new file mode 100644 index 0000000000..9df2f1fefb --- /dev/null +++ b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type-expected.txt @@ -0,0 +1,478 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./infer_imported_function_return_type_lib", + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 62 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 12 + } + } + }, + "imported": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 63 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 10 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 10 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "x", + "typeAnnotation": { + "type": "ETSUnionType", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "String", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 20 + } + } + }, + { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 19, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 19, + "column": 10 + } + } + }, + "init": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 19, + "column": 32 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 19, + "column": 33 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 34 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 20, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type.ets b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type.ets new file mode 100644 index 0000000000..fe40b45e95 --- /dev/null +++ b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type.ets @@ -0,0 +1,20 @@ +/* + * 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 + * + * 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 {foo} from "./infer_imported_function_return_type_lib"; + +function main() { + let x: String | int = foo(1); +} diff --git a/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib-expected.txt b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib-expected.txt new file mode 100644 index 0000000000..ef9faebfed --- /dev/null +++ b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib-expected.txt @@ -0,0 +1,458 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 20 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 20 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "param", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 16, + "column": 31 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 31 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "%", + "left": { + "type": "Identifier", + "name": "param", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 10 + }, + "end": { + "line": 18, + "column": 19 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "alternate": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "StringLiteral", + "value": "x", + "loc": { + "start": { + "line": 20, + "column": 12 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 16 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 20, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 20, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 33 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 23, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib.ets b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib.ets new file mode 100644 index 0000000000..cc8f36b064 --- /dev/null +++ b/ets2panda/test/compiler/ets/import_tests/infer_imported_function_return_type_lib.ets @@ -0,0 +1,22 @@ +/* + * 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 + * + * 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. + */ + +export function foo(param: int) { + if (param % 2 == 0) + { return 1; + } else { + return "x";} +} + diff --git a/ets2panda/test/parser/ets/infer_overriding_method_return_type-expected.txt b/ets2panda/test/parser/ets/infer_overriding_method_return_type-expected.txt new file mode 100644 index 0000000000..0a41ac4d4d --- /dev/null +++ b/ets2panda/test/parser/ets/infer_overriding_method_return_type-expected.txt @@ -0,0 +1,710 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "Base", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 16 + }, + "end": { + "line": 16, + "column": 20 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "method", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "method", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "number", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 20 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 20 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "Derived", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 14 + } + } + }, + "superClass": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Base", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 23 + }, + "end": { + "line": 20, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 23 + }, + "end": { + "line": 20, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 23 + }, + "end": { + "line": 20, + "column": 29 + } + } + }, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "method", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "method", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 16 + }, + "end": { + "line": 22, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 19 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 11 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 11 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 2 + }, + "end": { + "line": 24, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 28 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } +} diff --git a/ets2panda/test/parser/ets/infer_overriding_method_return_type.ets b/ets2panda/test/parser/ets/infer_overriding_method_return_type.ets new file mode 100644 index 0000000000..be2de8df6d --- /dev/null +++ b/ets2panda/test/parser/ets/infer_overriding_method_return_type.ets @@ -0,0 +1,24 @@ +/* + * 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 + * + * 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. + */ + +abstract class Base { + abstract method(): number; +} + +class Derived extends Base { + method() { + return 1.0 + }; +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/infer_method_type_1.ets b/ets2panda/test/runtime/ets/infer_method_type_1.ets new file mode 100644 index 0000000000..b4e953f69b --- /dev/null +++ b/ets2panda/test/runtime/ets/infer_method_type_1.ets @@ -0,0 +1,44 @@ +/* + * 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 + * + * 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 Pot { + private v: T + constructor(v: T) { + this.v = v + } + set(v: T) { + this.v = v; + return this; + } + get(): T { + return this.v; + } +} + +function main() { +let p = new Pot("") +let q = new Pot(0) + +p.set("a") +assert p.get() == "a" +q.set(1) +assert q.get() == 1 +p.set("b").set("c") +assert p.get() == "c" +p = p.set("d") +assert p.get() == "d" +q = q.set(2) +assert q.get() == 2 +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/infer_method_type_2.ets b/ets2panda/test/runtime/ets/infer_method_type_2.ets new file mode 100644 index 0000000000..446c463917 --- /dev/null +++ b/ets2panda/test/runtime/ets/infer_method_type_2.ets @@ -0,0 +1,28 @@ +/* + * 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 + * + * 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. + */ + +abstract class Base { + abstract method(): number; +} + +class Derived extends Base { + method() { + return 1.0 + }; +} + +function main() { + assert 1 == new Derived().method() +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/infer_method_type_3.ets b/ets2panda/test/runtime/ets/infer_method_type_3.ets new file mode 100644 index 0000000000..6acfb8b68b --- /dev/null +++ b/ets2panda/test/runtime/ets/infer_method_type_3.ets @@ -0,0 +1,30 @@ +/* + * 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 + * + * 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 A { + a = 1 +} + +class Base { + get foo() { + return new A(); + } +} + +class Derived extends Base { +} + +let y: A = new Derived().foo; +assert y.a == 1 diff --git a/ets2panda/test/runtime/ets/infer_method_type_4.ets b/ets2panda/test/runtime/ets/infer_method_type_4.ets new file mode 100644 index 0000000000..73eab25ee8 --- /dev/null +++ b/ets2panda/test/runtime/ets/infer_method_type_4.ets @@ -0,0 +1,41 @@ +/* + * 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 + * + * 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 A { + a: int + constructor(param: int) { + this.a = param + } +} + +class Base { + get foo() { + return new A(1); + } +} + +class Derived extends Base { + get foo() { + return new A(2); + } +} + +let x: Derived = new Derived(); +let y = x.foo; +assert y.a == 2; + +let v: Base = new Base(); +let w = v.foo; +assert w.a == 1; -- Gitee