From 38bb5cfa9e93513828773fdc27bab905193b5f9d Mon Sep 17 00:00:00 2001 From: Boglarka Haag Date: Tue, 2 Jul 2024 15:20:40 +0200 Subject: [PATCH 1/2] [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 ee98bb6708..b1c7280982 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; } @@ -1093,6 +1097,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 } @@ -2497,14 +2505,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 db7db97c1e..6cec302a52 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 ffbf7ba718..bebe2e6b69 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -653,6 +653,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); [[nodiscard]] ir::ScriptFunction *FindFunction(const util::UString &name); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 98626c5624..441ab3d62d 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1929,4 +1929,20 @@ size_t &ETSChecker::ConstraintCheckScopesCount() return constraintCheckScopesCount_; } +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 28419dd5fc..94ccc610d3 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2605,6 +2605,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 845951b4b8..8d50fedc93 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 88e7cd5c08..70951ac9ca 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -958,7 +958,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 From e164bd14abc07651f69b5bcec353355db2cabdfd Mon Sep 17 00:00:00 2001 From: Boglarka Haag Date: Tue, 9 Jul 2024 09:48:44 +0200 Subject: [PATCH 2/2] [ArkTs] Segmentation fault on inheriting generated getter-setter Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IABOAY Reason: Segmentation fault occured when we tried to inherit from a class which implemented an interface with properties without implenting the getter-setters explicitly. Description: The generated getter-setters didn't changed the declaration's node from class property to the new method definition. Test scenarios (new, modified, affected functions): infer_igetter_setter_implementation_1.ets infer_igetter_setter_implementation_2.ets Signed-off-by: Haag Boglarka --- ets2panda/checker/ets/helpers.cpp | 20 ++++----- ets2panda/checker/ets/object.cpp | 4 +- ...herited_getter_setter_implementation_1.ets | 31 +++++++++++++ ...herited_getter_setter_implementation_2.ets | 43 +++++++++++++++++++ 4 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 ets2panda/test/runtime/ets/inherited_getter_setter_implementation_1.ets create mode 100644 ets2panda/test/runtime/ets/inherited_getter_setter_implementation_2.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 94ccc610d3..8153116748 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2651,8 +2651,6 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty functionScope->BindParamScope(paramScope); paramScope->BindFunctionScope(functionScope); - auto flags = ir::ModifierFlags::PUBLIC; - ArenaVector params(checker->Allocator()->Adapter()); ArenaVector stmts(checker->Allocator()->Adapter()); checker->GenerateGetterSetterBody(stmts, params, field, paramScope, isSetter); @@ -2666,7 +2664,7 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty auto *func = checker->AllocNode( checker->Allocator(), ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnn), - funcFlags, flags, true}); + funcFlags, ir::ModifierFlags::PUBLIC, true}); if (!isSetter) { func->AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); @@ -2676,20 +2674,20 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty body->SetScope(functionScope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *methodIdent = property->Key()->AsIdentifier()->Clone(checker->Allocator(), nullptr); - auto *decl = checker->Allocator()->New( - checker->Allocator(), property->Key()->AsIdentifier()->Name(), - property->Key()->AsIdentifier()->Variable()->Declaration()->Node()); - auto *var = functionScope->AddDecl(checker->Allocator(), decl, ScriptExtension::ETS); - var->AddFlag(varbinder::VariableFlags::METHOD); - - methodIdent->SetVariable(var); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *funcExpr = checker->AllocNode(func); funcExpr->SetRange(func->Range()); func->AddFlag(ir::ScriptFunctionFlags::METHOD); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *method = checker->AllocNode(ir::MethodDefinitionKind::METHOD, methodIdent, funcExpr, - flags, checker->Allocator(), false); + ir::ModifierFlags::PUBLIC, checker->Allocator(), false); + + auto *decl = checker->Allocator()->New(checker->Allocator(), + property->Key()->AsIdentifier()->Name(), method); + auto *var = functionScope->AddDecl(checker->Allocator(), decl, ScriptExtension::ETS); + var->AddFlag(varbinder::VariableFlags::METHOD); + + methodIdent->SetVariable(var); method->Id()->SetMutator(); method->SetRange(field->Range()); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 8d50fedc93..316828e999 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -871,7 +871,9 @@ void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) } auto newStatus = checker::CheckerStatus::IN_CLASS; - classType->SetEnclosingType(Context().ContainingClass()); + if (Context().ContainingClass() != classType) { + classType->SetEnclosingType(Context().ContainingClass()); + } if (classDef->IsInner()) { newStatus |= CheckerStatus::INNER_CLASS; diff --git a/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_1.ets b/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_1.ets new file mode 100644 index 0000000000..28636bc4db --- /dev/null +++ b/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_1.ets @@ -0,0 +1,31 @@ +/* + * 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. + */ + +interface I { + a: int +} + +class A implements I { + a: int; +} + +class B extends A {} + +function main() { + let b = new B(); + b.a = 1; + let c: int = b.a; + assert c == 1; +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_2.ets b/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_2.ets new file mode 100644 index 0000000000..8102ad95a3 --- /dev/null +++ b/ets2panda/test/runtime/ets/inherited_getter_setter_implementation_2.ets @@ -0,0 +1,43 @@ +/* + * 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. + */ + +interface I { + readonly a: boolean +} + +class A implements I { + a: boolean + b : boolean + constructor() { + this.a = false + this.b = false + } + + foo() { + this.b = true + } +} + +class B extends A { + constructor() { + super() + this.a = true + } +} + +function main() { + let b = new B() + assert(b.a) +} \ No newline at end of file -- Gitee