From a0e213844b829d8e662b227010fe21d91b4443e6 Mon Sep 17 00:00:00 2001 From: liyue Date: Thu, 14 Dec 2023 06:47:08 +0000 Subject: [PATCH 01/24] Fix: Property lookup failure with type alias Issue: #I8OB54 Test: type-alias-call1.ets type-alias-call2.ets Signed-off-by: liyue Change-Id: Ib120e0f17bae64069daaf56484d95c2c448f767b --- ets2panda/checker/ETSAnalyzer.cpp | 57 +- ets2panda/checker/ETSchecker.h | 1 + ets2panda/checker/ets/object.cpp | 46 + .../ets/test-type-alias-call1-expected.txt | 645 +++++++++++++ .../test/parser/ets/test-type-alias-call1.ets | 22 + .../ets/test-type-alias-call2-expected.txt | 783 +++++++++++++++ .../test/parser/ets/test-type-alias-call2.ets | 24 + .../ets/test-type-alias-call3-expected.txt | 647 +++++++++++++ .../test/parser/ets/test-type-alias-call3.ets | 22 + .../ets/test-type-alias-call4-expected.txt | 647 +++++++++++++ .../test/parser/ets/test-type-alias-call4.ets | 22 + .../ets/test-type-alias-call5-expected.txt | 839 ++++++++++++++++ .../test/parser/ets/test-type-alias-call5.ets | 25 + .../ets/test-type-alias-call6-expected.txt | 908 ++++++++++++++++++ .../test/parser/ets/test-type-alias-call6.ets | 26 + .../test/parser/ets/test-type-alias-call7.ets | 17 + .../test/parser/ets/test-type-alias-call8.ets | 22 + .../test-lists/parser/parser-ets-ignored.txt | 2 + 18 files changed, 4748 insertions(+), 7 deletions(-) create mode 100644 ets2panda/test/parser/ets/test-type-alias-call1-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call1.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call2-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call2.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call3-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call3.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call4-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call4.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call5-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call5.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call6-expected.txt create mode 100644 ets2panda/test/parser/ets/test-type-alias-call6.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call7.ets create mode 100644 ets2panda/test/parser/ets/test-type-alias-call8.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 6ce1e33e3f..7fd8429aa9 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -21,6 +21,8 @@ #include "checker/ets/typeRelationContext.h" #include "util/helpers.h" +#include + namespace panda::es2panda::checker { ETSChecker *ETSAnalyzer::GetETSChecker() const @@ -973,9 +975,41 @@ checker::Type *ETSAnalyzer::Check(ir::BlockExpression *st) const UNREACHABLE(); } -ArenaVector &ChooseSignatures(checker::Type *callee_type, bool is_constructor_call, - bool is_functional_interface) +ArenaVector GetUnionTypeSignatures(ETSChecker *checker, checker::ETSUnionType *ets_union_type) { + ArenaVector call_signatures(checker->Allocator()->Adapter()); + + for (auto *constituent_type : ets_union_type->ConstituentTypes()) { + if (constituent_type->IsETSObjectType()) { + ArenaVector tmp_call_signatures(checker->Allocator()->Adapter()); + tmp_call_signatures = constituent_type->AsETSObjectType() + ->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures(); + call_signatures.insert(call_signatures.end(), tmp_call_signatures.begin(), tmp_call_signatures.end()); + } + if (constituent_type->IsETSFunctionType()) { + ArenaVector tmp_call_signatures(checker->Allocator()->Adapter()); + tmp_call_signatures = constituent_type->AsETSFunctionType()->CallSignatures(); + call_signatures.insert(call_signatures.end(), tmp_call_signatures.begin(), tmp_call_signatures.end()); + } + if (constituent_type->IsETSUnionType()) { + ArenaVector tmp_call_signatures(checker->Allocator()->Adapter()); + tmp_call_signatures = GetUnionTypeSignatures(checker, constituent_type->AsETSUnionType()); + call_signatures.insert(call_signatures.end(), tmp_call_signatures.begin(), tmp_call_signatures.end()); + } + } + + return call_signatures; +} + +ArenaVector &ChooseSignatures(ETSChecker *checker, checker::Type *callee_type, + bool is_constructor_call, bool is_functional_interface, + bool is_union_type_with_functional_interface) +{ + static ArenaVector union_signatures(checker->Allocator()->Adapter()); + union_signatures.clear(); if (is_constructor_call) { return callee_type->AsETSObjectType()->ConstructSignatures(); } @@ -986,6 +1020,10 @@ ArenaVector &ChooseSignatures(checker::Type *callee_type, bool is_c ->AsETSFunctionType() ->CallSignatures(); } + if (is_union_type_with_functional_interface) { + union_signatures = GetUnionTypeSignatures(checker, callee_type->AsETSUnionType()); + return union_signatures; + } return callee_type->AsETSFunctionType()->CallSignatures(); } @@ -1003,7 +1041,8 @@ checker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression } checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *callee_type, - bool is_constructor_call, bool is_functional_interface) + bool is_constructor_call, bool is_functional_interface, + bool is_union_type_with_functional_interface) { bool extension_function_type = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(callee_type); @@ -1014,7 +1053,8 @@ checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *ex if (extension_function_type) { return ResolveCallExtensionFunction(callee_type->AsETSFunctionType(), checker, expr); } - auto &signatures = ChooseSignatures(callee_type, is_constructor_call, is_functional_interface); + auto &signatures = ChooseSignatures(checker, callee_type, is_constructor_call, is_functional_interface, + is_union_type_with_functional_interface); checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start()); if (signature->Function()->IsExtensionMethod()) { checker->ThrowTypeError({"No matching call signature"}, expr->Start()); @@ -1026,6 +1066,9 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ { ETSChecker *checker = GetETSChecker(); bool is_constructor_call = expr->IsETSConstructorCall(); + bool is_union_type_with_functional_interface = + callee_type->IsETSUnionType() && + callee_type->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool is_functional_interface = callee_type->IsETSObjectType() && callee_type->AsETSObjectType()->HasObjectFlag( checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool ets_extension_func_helper_type = callee_type->IsETSExtensionFuncHelperType(); @@ -1036,12 +1079,12 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ } if (!is_functional_interface && !callee_type->IsETSFunctionType() && !is_constructor_call && - !ets_extension_func_helper_type) { + !ets_extension_func_helper_type && !is_union_type_with_functional_interface) { checker->ThrowTypeError("This expression is not callable.", expr->Start()); } - checker::Signature *signature = - ResolveSignature(checker, expr, callee_type, is_constructor_call, is_functional_interface); + checker::Signature *signature = ResolveSignature(checker, expr, callee_type, is_constructor_call, + is_functional_interface, is_union_type_with_functional_interface); checker->CheckObjectLiteralArguments(signature, expr->Arguments()); checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 1783bf654d..0bbab207fb 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -180,6 +180,7 @@ public: Type *GetCommonClass(Type *source, Type *target); ETSObjectType *GetClosestCommonAncestor(ETSObjectType *source, ETSObjectType *target); ETSObjectType *GetTypeargumentedLUB(ETSObjectType *source, ETSObjectType *target); + bool HasETSFunctionType(ir::TypeNode *type_annotation); // Type creation ByteType *CreateByteType(int8_t value); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index de5ecff0c9..7eb2c01c4f 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -55,6 +55,7 @@ #include "checker/types/ets/etsDynamicType.h" #include "checker/types/ets/types.h" #include "checker/ets/typeRelationContext.h" +#include "ir/ets/etsUnionType.h" namespace panda::es2panda::checker { ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type) @@ -405,6 +406,12 @@ void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) if (class_prop->TypeAnnotation() != nullptr && class_prop->TypeAnnotation()->IsETSFunctionType()) { type->AddProperty(it->AsLocalVariable()); it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } else if (class_prop->TypeAnnotation() != nullptr && class_prop->TypeAnnotation()->IsETSTypeReference()) { + bool has_function_type = HasETSFunctionType(class_prop->TypeAnnotation()); + if (has_function_type) { + type->AddProperty(it->AsLocalVariable()); + it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } } } @@ -418,6 +425,12 @@ void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) if (class_prop->TypeAnnotation() != nullptr && class_prop->TypeAnnotation()->IsETSFunctionType()) { type->AddProperty(it->AsLocalVariable()); it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } else if (class_prop->TypeAnnotation() != nullptr && class_prop->TypeAnnotation()->IsETSTypeReference()) { + bool has_function_type = HasETSFunctionType(class_prop->TypeAnnotation()); + if (has_function_type) { + type->AddProperty(it->AsLocalVariable()); + it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } } } @@ -473,6 +486,39 @@ void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) type->AddObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS); } +bool ETSChecker::HasETSFunctionType(ir::TypeNode *type_annotation) +{ + if (type_annotation->IsETSFunctionType()) { + return true; + } + std::unordered_set children_set; + + if (type_annotation->IsETSTypeReference()) { + auto *type_decl = + type_annotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration(); + if (type_decl != nullptr && type_decl->IsTypeAliasDecl()) { + type_annotation = type_decl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation(); + if (type_annotation->IsETSUnionType()) { + for (auto *type : type_annotation->AsETSUnionType()->Types()) { + if (type->IsETSTypeReference()) { + children_set.insert(type); + } + } + } else { + children_set.insert(type_annotation); + } + } + + for (auto *child : children_set) { + if (HasETSFunctionType(child)) { + return true; + } + } + } + + return false; +} + std::vector ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *obj_type) { std::vector abstracts; diff --git a/ets2panda/test/parser/ets/test-type-alias-call1-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call1-expected.txt new file mode 100644 index 0000000000..9488599338 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call1-expected.txt @@ -0,0 +1,645 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 29 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 17, + "column": 6 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 20 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 18, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 22 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 22 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 23 + }, + "end": { + "line": 20, + "column": 24 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 25 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 24 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 21, + "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": 22, + "column": 2 + }, + "end": { + "line": 22, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 22, + "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": 23, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call1.ets b/ets2panda/test/parser/ets/test-type-alias-call1.ets new file mode 100644 index 0000000000..2899e73c52 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call1.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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. + */ + +type Callback = (n: int) => int +class A { + public callback: Callback + public increment() { + this.callback(1) + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call2-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call2-expected.txt new file mode 100644 index 0000000000..8913c68014 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call2-expected.txt @@ -0,0 +1,783 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 26 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 17, + "column": 5 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 6 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 6 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 19, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 12 + }, + "end": { + "line": 20, + "column": 20 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 22 + }, + "end": { + "line": 20, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 22 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 22 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 12 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 21 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 21 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 13 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 14 + }, + "end": { + "line": 22, + "column": 22 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 22 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 23 + }, + "end": { + "line": 22, + "column": 24 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 25 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 24 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 21 + }, + "end": { + "line": 23, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 21 + }, + "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": 19, + "column": 9 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "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": 25, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call2.ets b/ets2panda/test/parser/ets/test-type-alias-call2.ets new file mode 100644 index 0000000000..93b91c0087 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call2.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 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. + */ + +type First = (n: int) => int +type Second = First +type Callback = Second +class A { + public callback: Callback + public increment() { + this.callback(1) + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call3-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call3-expected.txt new file mode 100644 index 0000000000..1076dcd57a --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call3-expected.txt @@ -0,0 +1,647 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 29 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 17, + "column": 6 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + "accessibility": "public", + "static": true, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 18, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 10 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 20 + }, + "end": { + "line": 20, + "column": 21 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 22 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 24 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 21, + "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": 22, + "column": 2 + }, + "end": { + "line": 22, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 22, + "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": 23, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call3.ets b/ets2panda/test/parser/ets/test-type-alias-call3.ets new file mode 100644 index 0000000000..89743c8d48 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call3.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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. + */ + +type Callback = (n: int) => int +class A { + public static callback: Callback + public increment() { + A.callback(1) + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call4-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call4-expected.txt new file mode 100644 index 0000000000..9c15b8c34f --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call4-expected.txt @@ -0,0 +1,647 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 24 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 29 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 17, + "column": 6 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + "accessibility": "public", + "static": true, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 18, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 29 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 19, + "column": 11 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 19 + }, + "end": { + "line": 19, + "column": 28 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 19 + }, + "end": { + "line": 19, + "column": 28 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 10 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 20 + }, + "end": { + "line": 20, + "column": 21 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 22 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 28 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 28 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 21, + "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": 22, + "column": 2 + }, + "end": { + "line": 22, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 22, + "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": 23, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call4.ets b/ets2panda/test/parser/ets/test-type-alias-call4.ets new file mode 100644 index 0000000000..d02aa961d9 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call4.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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. + */ + +type Callback = (n: int) => int +class A { + public static callback: Callback + public static increment() { + A.callback(1) + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call5-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call5-expected.txt new file mode 100644 index 0000000000..f26b502997 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call5-expected.txt @@ -0,0 +1,839 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 26 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 6 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 6 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSUnionType", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 24 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 25 + }, + "end": { + "line": 18, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 25 + }, + "end": { + "line": 18, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 25 + }, + "end": { + "line": 18, + "column": 32 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 32 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 20 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 22 + }, + "end": { + "line": 21, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 22 + }, + "end": { + "line": 21, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 22 + }, + "end": { + "line": 21, + "column": 31 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 31 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 12 + }, + "end": { + "line": 22, + "column": 21 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 12 + }, + "end": { + "line": 22, + "column": 21 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 13 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 14 + }, + "end": { + "line": 23, + "column": 22 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 22 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 23, + "column": 23 + }, + "end": { + "line": 23, + "column": 24 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 26 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 24 + }, + "end": { + "line": 24, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 21 + }, + "end": { + "line": 24, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 21 + }, + "end": { + "line": 24, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 24, + "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": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 25, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 25, + "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": 26, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call5.ets b/ets2panda/test/parser/ets/test-type-alias-call5.ets new file mode 100644 index 0000000000..8a7f8a3e98 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call5.ets @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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. + */ + +type First = (n: int) => int; +type Second = First +type Callback = First | Second; + +class A { + public callback: Callback; + public increment() { + this.callback(1); + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call6-expected.txt b/ets2panda/test/parser/ets/test-type-alias-call6-expected.txt new file mode 100644 index 0000000000..3a470a4b77 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call6-expected.txt @@ -0,0 +1,908 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 26 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 6 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 17, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Third", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 6 + }, + "end": { + "line": 18, + "column": 11 + } + } + }, + "typeAnnotation": { + "type": "ETSUnionType", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "First", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Second", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 18, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 18, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 18, + "column": 29 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 29 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 6 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Third", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 7 + }, + "end": { + "line": 21, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 12 + }, + "end": { + "line": 22, + "column": 20 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Callback", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 22 + }, + "end": { + "line": 22, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 22 + }, + "end": { + "line": 22, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 22 + }, + "end": { + "line": 22, + "column": 31 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 12 + }, + "end": { + "line": 22, + "column": 31 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 12 + }, + "end": { + "line": 23, + "column": 21 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "increment", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 12 + }, + "end": { + "line": 23, + "column": 21 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 13 + } + } + }, + "property": { + "type": "Identifier", + "name": "callback", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 24, + "column": 23 + }, + "end": { + "line": 24, + "column": 24 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 26 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 24 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 21 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 21 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 25, + "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": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 26, + "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": 27, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call6.ets b/ets2panda/test/parser/ets/test-type-alias-call6.ets new file mode 100644 index 0000000000..8801b22e54 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call6.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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. + */ + +type First = (n: int) => int; +type Second = First; +type Third = First | Second; +type Callback = Third; + +class A { + public callback: Callback; + public increment() { + this.callback(1); + } +} diff --git a/ets2panda/test/parser/ets/test-type-alias-call7.ets b/ets2panda/test/parser/ets/test-type-alias-call7.ets new file mode 100644 index 0000000000..cc764f60c6 --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call7.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 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. + */ + +type Callback = (n: int) => int +export type {Callback} diff --git a/ets2panda/test/parser/ets/test-type-alias-call8.ets b/ets2panda/test/parser/ets/test-type-alias-call8.ets new file mode 100644 index 0000000000..27b26e180a --- /dev/null +++ b/ets2panda/test/parser/ets/test-type-alias-call8.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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 type { Callback } from './test-type-alias-call3.ets'; +class A { + public callback: Callback + public increment(){ + this.callback(1) + } +} diff --git a/ets2panda/test/test-lists/parser/parser-ets-ignored.txt b/ets2panda/test/test-lists/parser/parser-ets-ignored.txt index e69de29bb2..5ca2201c3d 100644 --- a/ets2panda/test/test-lists/parser/parser-ets-ignored.txt +++ b/ets2panda/test/test-lists/parser/parser-ets-ignored.txt @@ -0,0 +1,2 @@ +parser/ets/test-type-alias-call7.ets +parser/ets/test-type-alias-call8.ets \ No newline at end of file -- Gitee From 34127ad023bc2895759bca4f98e4fe65c18cca7f Mon Sep 17 00:00:00 2001 From: Zhelyapov Aleksey Date: Thu, 30 Nov 2023 21:00:38 +0300 Subject: [PATCH 02/24] Fix issue #14105 (additive operations on chars) Signed-off-by: Zhelyapov Aleksey --- ets2panda/checker/ets/helpers.cpp | 4 ++++ ets2panda/compiler/core/ETSGen.h | 1 + 2 files changed, 5 insertions(+) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index d9d2cf1fdd..c119b4f9d2 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -775,6 +775,10 @@ std::tuple ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Ty return {GlobalLongType(), both_const}; } + if (unboxed_l->IsCharType() && unboxed_r->IsCharType()) { + return {GlobalCharType(), both_const}; + } + return {GlobalIntType(), both_const}; } diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 61c79b6af6..2a0e360fa6 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -840,6 +840,7 @@ private: case checker::TypeFlag::ETS_BOOLEAN: case checker::TypeFlag::BYTE: case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: case checker::TypeFlag::INT: { Ra().Emit(node, lhs, if_false); break; -- Gitee From d5770a94c3278ef3ae5ccbfdc0fb1b367e121630 Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Mon, 13 Nov 2023 12:16:40 +0100 Subject: [PATCH 03/24] [ArkTS frontend] Static and instance entities of class type can have identical names Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8QN9Q Fixes the internal issue #14273. Reason: The specification changed and now allows to have static and instance method with same name. Description: Modified to frontend implementation not to throw CTE in the new and valid cases. Test scenarios: All existing tests pass (CTS, runtime, parser, ets-func-tests), added new tests cover new cases. Change-Id: Ie3fadffd4d81286a452d47f487158525808e59dc Signed-off-by: Csaba Osztrogonac --- ...-instance-field-redeclaration-expected.txt | 1 + .../class-instance-field-redeclaration.ets | 19 ++++++++++++ ...ss-static-field-redeclaration-expected.txt | 1 + .../ets/class-static-field-redeclaration.ets | 19 ++++++++++++ .../runtime/ets/class-fields-same-name.ets | 31 +++++++++++++++++++ .../ets-runtime/ets-runtime-ignored.txt | 3 ++ ets2panda/varbinder/scope.cpp | 14 +++++++-- 7 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 ets2panda/test/parser/ets/class-instance-field-redeclaration-expected.txt create mode 100644 ets2panda/test/parser/ets/class-instance-field-redeclaration.ets create mode 100644 ets2panda/test/parser/ets/class-static-field-redeclaration-expected.txt create mode 100644 ets2panda/test/parser/ets/class-static-field-redeclaration.ets create mode 100644 ets2panda/test/runtime/ets/class-fields-same-name.ets diff --git a/ets2panda/test/parser/ets/class-instance-field-redeclaration-expected.txt b/ets2panda/test/parser/ets/class-instance-field-redeclaration-expected.txt new file mode 100644 index 0000000000..95028a2c18 --- /dev/null +++ b/ets2panda/test/parser/ets/class-instance-field-redeclaration-expected.txt @@ -0,0 +1 @@ +SyntaxError: Variable 'foo' has already been declared. [class-instance-field-redeclaration.ets:18:5] diff --git a/ets2panda/test/parser/ets/class-instance-field-redeclaration.ets b/ets2panda/test/parser/ets/class-instance-field-redeclaration.ets new file mode 100644 index 0000000000..3f2f82c517 --- /dev/null +++ b/ets2panda/test/parser/ets/class-instance-field-redeclaration.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 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 { + foo: int = 10; + foo: int = 20; +} diff --git a/ets2panda/test/parser/ets/class-static-field-redeclaration-expected.txt b/ets2panda/test/parser/ets/class-static-field-redeclaration-expected.txt new file mode 100644 index 0000000000..7b1e62f304 --- /dev/null +++ b/ets2panda/test/parser/ets/class-static-field-redeclaration-expected.txt @@ -0,0 +1 @@ +SyntaxError: Variable 'foo' has already been declared. [class-static-field-redeclaration.ets:18:12] diff --git a/ets2panda/test/parser/ets/class-static-field-redeclaration.ets b/ets2panda/test/parser/ets/class-static-field-redeclaration.ets new file mode 100644 index 0000000000..3c6d509fc0 --- /dev/null +++ b/ets2panda/test/parser/ets/class-static-field-redeclaration.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 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 { + static foo: int = 10; + static foo: int = 20; +} diff --git a/ets2panda/test/runtime/ets/class-fields-same-name.ets b/ets2panda/test/runtime/ets/class-fields-same-name.ets new file mode 100644 index 0000000000..ab04034da7 --- /dev/null +++ b/ets2panda/test/runtime/ets/class-fields-same-name.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 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 { + public static foo: int = 10 + public foo: int = 20 +} + +class D extends C { + public static foo: int = 30 + public foo: int = 40 +} + +function main(): void { + assert (C.foo == 10) + assert (new C().foo == 20) + assert (D.foo == 30) + assert (new D().foo == 40) +} diff --git a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt index 586ace81ba..e6e752e1bf 100644 --- a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt +++ b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt @@ -34,3 +34,6 @@ trailing-lambda-with-capture.ets # ignored until union types are properly implemented and non nullish base type of array types can be properly handled notNullMultidimensionalArray.ets + +# ignored until verifier can't handle if a field name can be static and non-static at the same time +class-fields-same-name.ets diff --git a/ets2panda/varbinder/scope.cpp b/ets2panda/varbinder/scope.cpp index 7d685b6aa3..46c3c1366c 100644 --- a/ets2panda/varbinder/scope.cpp +++ b/ets2panda/varbinder/scope.cpp @@ -744,8 +744,18 @@ Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Var SetBindingProps(new_decl, &props, is_static); - if (FindLocal(new_decl->Name(), ResolveBindingOptions::ALL) != nullptr) { - return nullptr; + const auto *found_var = FindLocal(new_decl->Name(), ResolveBindingOptions::ALL); + if (found_var != nullptr) { + if (!new_decl->IsLetOrConstDecl()) { + return nullptr; + } + + found_var = FindLocal(new_decl->Name(), + ResolveBindingOptions::ALL ^ (is_static ? ResolveBindingOptions::VARIABLES + : ResolveBindingOptions::STATIC_VARIABLES)); + if (found_var != nullptr) { + return nullptr; + } } auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, new_decl, extension); -- Gitee From fd6ca45b6faec42eedb5f5d1b10367133059b5d9 Mon Sep 17 00:00:00 2001 From: Kira Prokopenko Date: Mon, 11 Dec 2023 18:15:45 +0300 Subject: [PATCH 04/24] Description: rename hashCode method into internal, as it was removed from Object class Testing: see ggwatcher cs 11378 Signed-off-by: Kira Prokopenko --- .../test/compiler/ets/override18-expected.txt | 34 +++++++++---------- ets2panda/test/compiler/ets/override18.ets | 4 +-- .../test/compiler/ets/override19-expected.txt | 34 +++++++++---------- ets2panda/test/compiler/ets/override19.ets | 4 +-- ets2panda/test/runtime/ets/array-object.ets | 8 ++--- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/ets2panda/test/compiler/ets/override18-expected.txt b/ets2panda/test/compiler/ets/override18-expected.txt index 198ef735ad..a3d01a0fb6 100644 --- a/ets2panda/test/compiler/ets/override18-expected.txt +++ b/ets2panda/test/compiler/ets/override18-expected.txt @@ -174,7 +174,7 @@ "type": "MethodDefinition", "key": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -183,7 +183,7 @@ }, "end": { "line": 20, - "column": 13 + "column": 15 } } }, @@ -198,7 +198,7 @@ "type": "ScriptFunction", "id": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -207,7 +207,7 @@ }, "end": { "line": 20, - "column": 13 + "column": 15 } } }, @@ -220,11 +220,11 @@ "loc": { "start": { "line": 20, - "column": 16 + "column": 18 }, "end": { "line": 20, - "column": 19 + "column": 21 } } }, @@ -263,7 +263,7 @@ "loc": { "start": { "line": 20, - "column": 19 + "column": 21 }, "end": { "line": 22, @@ -274,7 +274,7 @@ "loc": { "start": { "line": 20, - "column": 13 + "column": 15 }, "end": { "line": 22, @@ -285,7 +285,7 @@ "loc": { "start": { "line": 20, - "column": 13 + "column": 15 }, "end": { "line": 22, @@ -907,7 +907,7 @@ }, "property": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -916,7 +916,7 @@ }, "end": { "line": 30, - "column": 22 + "column": 24 } } }, @@ -929,7 +929,7 @@ }, "end": { "line": 30, - "column": 22 + "column": 24 } } }, @@ -942,7 +942,7 @@ }, "end": { "line": 30, - "column": 24 + "column": 26 } } }, @@ -952,11 +952,11 @@ "loc": { "start": { "line": 30, - "column": 28 + "column": 30 }, "end": { "line": 30, - "column": 29 + "column": 31 } } }, @@ -967,7 +967,7 @@ }, "end": { "line": 30, - "column": 29 + "column": 31 } } }, @@ -979,7 +979,7 @@ }, "end": { "line": 30, - "column": 29 + "column": 31 } } } diff --git a/ets2panda/test/compiler/ets/override18.ets b/ets2panda/test/compiler/ets/override18.ets index f822161147..e6494ec0c6 100644 --- a/ets2panda/test/compiler/ets/override18.ets +++ b/ets2panda/test/compiler/ets/override18.ets @@ -17,7 +17,7 @@ interface J{ toString(): String { return ""; } - hashCode():int{ + $_hashCode():int{ return 4; } } @@ -27,5 +27,5 @@ class JImpl implements J{ function main(): void { let o: JImpl = new JImpl() - assert o.hashCode() == 4 + assert o.$_hashCode() == 4 } diff --git a/ets2panda/test/compiler/ets/override19-expected.txt b/ets2panda/test/compiler/ets/override19-expected.txt index b7d5f654a9..c84d605809 100644 --- a/ets2panda/test/compiler/ets/override19-expected.txt +++ b/ets2panda/test/compiler/ets/override19-expected.txt @@ -189,7 +189,7 @@ "type": "MethodDefinition", "key": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -198,7 +198,7 @@ }, "end": { "line": 20, - "column": 22 + "column": 24 } } }, @@ -213,7 +213,7 @@ "type": "ScriptFunction", "id": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -222,7 +222,7 @@ }, "end": { "line": 20, - "column": 22 + "column": 24 } } }, @@ -235,11 +235,11 @@ "loc": { "start": { "line": 20, - "column": 26 + "column": 28 }, "end": { "line": 20, - "column": 29 + "column": 31 } } }, @@ -277,7 +277,7 @@ "loc": { "start": { "line": 20, - "column": 30 + "column": 32 }, "end": { "line": 22, @@ -288,7 +288,7 @@ "loc": { "start": { "line": 20, - "column": 22 + "column": 24 }, "end": { "line": 22, @@ -299,7 +299,7 @@ "loc": { "start": { "line": 20, - "column": 22 + "column": 24 }, "end": { "line": 22, @@ -983,7 +983,7 @@ }, "property": { "type": "Identifier", - "name": "hashCode", + "name": "$_hashCode", "decorators": [], "loc": { "start": { @@ -992,7 +992,7 @@ }, "end": { "line": 30, - "column": 22 + "column": 24 } } }, @@ -1005,7 +1005,7 @@ }, "end": { "line": 30, - "column": 22 + "column": 24 } } }, @@ -1018,7 +1018,7 @@ }, "end": { "line": 30, - "column": 24 + "column": 26 } } }, @@ -1028,11 +1028,11 @@ "loc": { "start": { "line": 30, - "column": 28 + "column": 30 }, "end": { "line": 30, - "column": 29 + "column": 31 } } }, @@ -1043,7 +1043,7 @@ }, "end": { "line": 30, - "column": 29 + "column": 31 } } }, @@ -1055,7 +1055,7 @@ }, "end": { "line": 30, - "column": 29 + "column": 31 } } } diff --git a/ets2panda/test/compiler/ets/override19.ets b/ets2panda/test/compiler/ets/override19.ets index 45fb347bb3..81a7465867 100644 --- a/ets2panda/test/compiler/ets/override19.ets +++ b/ets2panda/test/compiler/ets/override19.ets @@ -17,7 +17,7 @@ class O{ override toString(): String { return ""; } - override hashCode(): int { + override $_hashCode(): int { return 4; } } @@ -27,5 +27,5 @@ class OExt extends O{ function main(): void { let o: OExt = new OExt() - assert o.hashCode() == 4 + assert o.$_hashCode() == 4 } diff --git a/ets2panda/test/runtime/ets/array-object.ets b/ets2panda/test/runtime/ets/array-object.ets index 0228add708..9e656739d9 100644 --- a/ets2panda/test/runtime/ets/array-object.ets +++ b/ets2panda/test/runtime/ets/array-object.ets @@ -27,11 +27,11 @@ function main(): void { object.toString(); // TypeError: Cannot access property of non-object or non-enum type -// arr1.hashCode(); -// arr2.hashCode(); -// object_array.hashCode(); +// arr1.$_hashCode(); +// arr2.$_hashCode(); +// object_array.$_hashCode(); - object.hashCode(); + object.$_hashCode(); assert(arr1 == arr1); assert(arr1 == object_array); -- Gitee From ae7619f2a6817f8892aaa165fb7d63b942755971 Mon Sep 17 00:00:00 2001 From: Molokanov Yaroslav Date: Tue, 19 Dec 2023 15:43:24 +0300 Subject: [PATCH 05/24] Array inference issue resolving Error during compilation literal array as argument in function call context Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8RWAM Testing: ets2panda/test/runtime/ets/array_inf.ets Signed-off-by: Molokanov Yaroslav --- ets2panda/checker/ets/function.cpp | 5 ++++ ets2panda/checker/ets/typeRelationContext.h | 2 +- ets2panda/ir/expressions/arrayExpression.cpp | 22 ++++++++++++++++ ets2panda/ir/expressions/arrayExpression.h | 4 +++ ets2panda/test/runtime/ets/array_inf.ets | 27 ++++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/runtime/ets/array_inf.ets diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 04d093b1f3..b88f2aaf38 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -256,6 +256,11 @@ Signature *ETSChecker::ValidateSignature(Signature *signature, const ir::TSTypeP return nullptr; } + if (argument->IsArrayExpression()) { + argument->AsArrayExpression()->GetPrefferedTypeFromFuncParam( + this, substituted_sig->Function()->Params()[index], flags); + } + auto *const argument_type = argument->Check(this); if (auto const invocation_ctx = checker::InvocationContext( diff --git a/ets2panda/checker/ets/typeRelationContext.h b/ets2panda/checker/ets/typeRelationContext.h index d0148f37d9..ca9ebda4a7 100644 --- a/ets2panda/checker/ets/typeRelationContext.h +++ b/ets2panda/checker/ets/typeRelationContext.h @@ -69,7 +69,7 @@ public: relation->SetNode(nullptr); relation->SetFlags(TypeRelationFlag::NONE); - assignable_ = true; + assignable_ = relation->IsTrue(); } bool IsAssignable() const diff --git a/ets2panda/ir/expressions/arrayExpression.cpp b/ets2panda/ir/expressions/arrayExpression.cpp index b1b2ef87a7..575c72d4b7 100644 --- a/ets2panda/ir/expressions/arrayExpression.cpp +++ b/ets2panda/ir/expressions/arrayExpression.cpp @@ -379,4 +379,26 @@ checker::Type *ArrayExpression::Check(checker::ETSChecker *checker) { return checker->GetAnalyzer()->Check(this); } + +void ArrayExpression::GetPrefferedTypeFromFuncParam(checker::ETSChecker *checker, Expression *param, + checker::TypeRelationFlag flags) +{ + if (preferred_type_ != nullptr) { + return; + } + auto param_type = param->Check(checker); + if (param_type->IsETSArrayType()) { + param_type = param_type->AsETSArrayType()->ElementType(); + } + bool is_assignable = true; + for (auto elem : elements_) { + auto assign_ctx = checker::AssignmentContext(checker->Relation(), elem, elem->Check(checker), param_type, + elem->Start(), {""}, checker::TypeRelationFlag::NO_THROW | flags); + is_assignable &= assign_ctx.IsAssignable(); + } + if (is_assignable) { + preferred_type_ = param->Check(checker); + } +} + } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h index cd5f4132d0..f2699692ac 100644 --- a/ets2panda/ir/expressions/arrayExpression.h +++ b/ets2panda/ir/expressions/arrayExpression.h @@ -18,6 +18,7 @@ #include "ir/expression.h" #include "ir/validationInfo.h" +#include "checker/types/ets/etsArrayType.h" namespace panda::es2panda::checker { class ETSAnalyzer; @@ -140,6 +141,9 @@ public: v->Accept(this); } + void GetPrefferedTypeFromFuncParam(checker::ETSChecker *checker, Expression *param, + checker::TypeRelationFlag flags); + private: ArenaVector decorators_; ArenaVector elements_; diff --git a/ets2panda/test/runtime/ets/array_inf.ets b/ets2panda/test/runtime/ets/array_inf.ets new file mode 100644 index 0000000000..5c09324c73 --- /dev/null +++ b/ets2panda/test/runtime/ets/array_inf.ets @@ -0,0 +1,27 @@ +class A { + foo(p: Object[]): int { + let s = 0 + for (let v of p) { + s += v instanceof A ? 1 : 0 + } + return s + } + bar(p: A[]): int { + let s = 0 + for (let v of p) { + s += v instanceof A ? 1 : 0 + } + return s + } +} + + +class B extends A{} + +function main() { + assert new A().foo([new Object(), new Long(), new Int()]) == 0 + assert new A().foo([new A(), new A(), new Object()]) == 2 + assert new A().foo(["aaa", new A(), new Object()]) == 1 + assert new A().foo([1, "hello", new A()]) == 1 + assert new A().bar([new B(), new B(), new A()]) == 3 +} -- Gitee From 2c55994faa96ee0870ac440e84b0c16d8b84d0f4 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Tue, 12 Dec 2023 13:53:17 +0300 Subject: [PATCH 06/24] Fix incorrect interface override behavior Allow override with different method return values in case of the interfaces Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8MXLR Testing: new runtime test to check correct interface override behavior Signed-off-by: Konstantin Kuznetsov --- ets2panda/checker/ets/helpers.cpp | 2 +- .../ets/InterfaceOverrideReturnTypes.ets | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/runtime/ets/InterfaceOverrideReturnTypes.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index c119b4f9d2..35d2b15156 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1565,7 +1565,7 @@ bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *func_type, Signatu void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *func_type, Signature *signature) { for (auto *it : func_type->CallSignatures()) { - SavedTypeRelationFlagsContext strf_ctx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + SavedTypeRelationFlagsContext strf_ctx(Relation(), TypeRelationFlag::NONE); Relation()->IsIdenticalTo(it, signature); if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { std::stringstream ss; diff --git a/ets2panda/test/runtime/ets/InterfaceOverrideReturnTypes.ets b/ets2panda/test/runtime/ets/InterfaceOverrideReturnTypes.ets new file mode 100644 index 0000000000..87e57dfd1c --- /dev/null +++ b/ets2panda/test/runtime/ets/InterfaceOverrideReturnTypes.ets @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022-2023 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 A { + foo(): A +} + +interface B extends A { + foo(): B +} + +class C implements A { + private value: string; + + foo(): A { + this.value = "foo(): A" + return new C(); + } + + getValue(): string { + return this.value; + } +} + +class D implements B { + private value: string; + + foo(): B { + this.value = "foo(): B" + return new D(); + } + + getValue(): string { + return this.value; + } +} + +function main() { + let c = new C(); + c.foo(); + assert c.getValue() == "foo(): A" + + let d = new D(); + d.foo(); + assert d.getValue() == "foo(): B" +} -- Gitee From 69634941fbb9b12f0bb68733efc10786f80142b4 Mon Sep 17 00:00:00 2001 From: aakmaev Date: Mon, 25 Dec 2023 03:31:25 +0300 Subject: [PATCH 07/24] Replace LUB with union in conditional expression Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8QX1C?from=project-issue Signed-off-by: Akmaev Alexey --- ets2panda/checker/ETSAnalyzer.cpp | 2 +- ets2panda/checker/ETSchecker.h | 7 +++ ets2panda/checker/types/ets/etsObjectType.cpp | 11 +++++ ets2panda/checker/types/ets/etsUnionType.cpp | 17 ++++++- ets2panda/compiler/core/ETSCompiler.cpp | 6 ++- .../compiler/lowering/ets/unionLowering.cpp | 32 +++++++++---- .../expressions/literals/undefinedLiteral.cpp | 13 +++++ .../expressions/literals/undefinedLiteral.h | 3 ++ ...ression.ets => conditionalExpression1.ets} | 0 .../runtime/ets/conditionalExpression2.ets | 40 ++++++++++++++++ .../runtime/ets/conditionalExpressionLUB.ets | 10 ++-- .../test/unit/union_normalization_test.cpp | 48 +++++++++++++++++++ 12 files changed, 171 insertions(+), 18 deletions(-) rename ets2panda/test/runtime/ets/{conditionalExpression.ets => conditionalExpression1.ets} (100%) create mode 100644 ets2panda/test/runtime/ets/conditionalExpression2.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 7fd8429aa9..aa57637bac 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1228,7 +1228,7 @@ checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const builtin_alternate_type = alternate_type; } - expr->SetTsType(checker->FindLeastUpperBound(builtin_conseq_type, builtin_alternate_type)); + expr->SetTsType(checker->CreateETSUnionType(builtin_conseq_type, builtin_alternate_type)); } } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 0bbab207fb..a82b214e5c 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -194,6 +194,13 @@ public: ETSStringType *CreateETSStringLiteralType(util::StringView value); ETSArrayType *CreateETSArrayType(Type *element_type); Type *CreateETSUnionType(ArenaVector &&constituent_types); + template + Type *CreateETSUnionType(Types &&...types) + { + ArenaVector constituent_types(Allocator()->Adapter()); + (constituent_types.push_back(types), ...); + return CreateETSUnionType(std::move(constituent_types)); + } ETSFunctionType *CreateETSFunctionType(Signature *signature); ETSFunctionType *CreateETSFunctionType(Signature *signature, util::StringView name); ETSFunctionType *CreateETSFunctionType(ir::ScriptFunction *func, Signature *signature, util::StringView name); diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 3964d454fa..8b74d27413 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -609,6 +609,17 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) relation->Result(false); auto *const ets_checker = relation->GetChecker()->AsETSChecker(); + if (source->IsETSUnionType()) { + bool res = std::all_of(source->AsETSUnionType()->ConstituentTypes().begin(), + source->AsETSUnionType()->ConstituentTypes().end(), [this, relation](Type *ct) { + relation->Result(false); + IsSupertypeOf(relation, ct); + return relation->IsTrue(); + }); + relation->Result(res); + return; + } + // 3.8.3 Subtyping among Array Types auto const *const base = GetConstOriginalBaseType(); if (base == ets_checker->GlobalETSObjectType() && source->IsETSArrayType()) { diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 18d2fcbde0..270824e945 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -161,12 +161,24 @@ void ETSUnionType::LinearizeAndEraseIdentical(TypeRelation *relation, ArenaVecto } } constituent_types = copied_constituents; + // Removing subtypes should be in the next iteration, especially needed for proper literals removal + auto check_subtyping = [relation](Type *lhs, Type *rhs) { + if (lhs == rhs) { + return false; + } + relation->Result(false); + lhs->IsSupertypeOf(relation, rhs); + bool inheritance_relation = relation->IsTrue(); + rhs->IsSupertypeOf(relation, lhs); + inheritance_relation = inheritance_relation || relation->IsTrue(); + return inheritance_relation; + }; // Secondly, remove identical types auto cmp_it = constituent_types.begin(); while (cmp_it != constituent_types.end()) { auto it = std::next(cmp_it); while (it != constituent_types.end()) { - if (relation->IsIdenticalTo(*it, *cmp_it)) { + if (relation->IsIdenticalTo(*it, *cmp_it) && !check_subtyping(*it, *cmp_it)) { it = constituent_types.erase(it); } else { ++it; @@ -196,9 +208,10 @@ void ETSUnionType::NormalizeTypes(TypeRelation *relation, ArenaVector &c while (cmp_it != constituent_types.end()) { auto new_end = std::remove_if( constituent_types.begin(), constituent_types.end(), [relation, checker, cmp_it, number_found](Type *ct) { + bool both_constants = (*cmp_it)->HasTypeFlag(TypeFlag::CONSTANT) && ct->HasTypeFlag(TypeFlag::CONSTANT); relation->Result(false); (*cmp_it)->IsSupertypeOf(relation, ct); - bool remove_subtype = ct != *cmp_it && relation->IsTrue(); + bool remove_subtype = ct != *cmp_it && !both_constants && relation->IsTrue(); bool remove_numeric = number_found && ct->IsETSObjectType() && ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) && diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 2ae78aa607..46fb246baa 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -788,7 +788,11 @@ void ETSCompiler::Compile(const ir::ConditionalExpression *expr) const expr->Alternate()->Compile(etsg); etsg->ApplyConversion(expr->Alternate()); etsg->SetLabel(expr, end_label); - etsg->SetAccumulatorType(expr->TsType()); + if (expr->TsType()->IsETSUnionType()) { + etsg->SetAccumulatorType(expr->TsType()->AsETSUnionType()->GetLeastUpperBoundType()); + } else { + etsg->SetAccumulatorType(expr->TsType()); + } } void ETSCompiler::Compile([[maybe_unused]] const ir::DirectEvalExpression *expr) const diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index 6460b49506..603c42b6f7 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -26,6 +26,8 @@ #include "ir/astNode.h" #include "ir/expression.h" #include "ir/opaqueTypeNode.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/undefinedLiteral.h" #include "ir/expressions/binaryExpression.h" #include "ir/expressions/identifier.h" #include "ir/expressions/memberExpression.h" @@ -155,9 +157,9 @@ ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *checker, ir: } if (source_type != nullptr && expr->Expr()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) { if (expr->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { - auto *const boxed_expr_type = checker::BoxingConverter::ETSTypeFromSource(checker, expr->TsType()); - auto *const as_expr = GenAsExpression(checker, boxed_expr_type, expr->Expr(), expr); - as_expr->SetBoxingUnboxingFlags(expr->Expr()->GetBoxingUnboxingFlags()); + auto *const as_expr = GenAsExpression(checker, source_type, expr->Expr(), expr); + as_expr->SetBoxingUnboxingFlags( + checker->GetUnboxingFlag(checker->ETSBuiltinTypeAsPrimitiveType(source_type))); expr->Expr()->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::NONE); expr->SetExpr(as_expr); } @@ -182,15 +184,24 @@ ir::BinaryExpression *GenInstanceofExpr(checker::ETSChecker *checker, ir::Expres rhs_type = checker::conversion::Boxing(checker->Relation(), constituent_type); checker->Relation()->SetNode(nullptr); } - auto *const rhs_expr = - checker->Allocator()->New(rhs_type->AsETSObjectType()->Name(), checker->Allocator()); + if (constituent_type->IsETSStringType()) { + rhs_type = checker->GlobalBuiltinETSStringType(); + } + ir::Expression *rhs_expr; + if (rhs_type->IsETSUndefinedType()) { + rhs_expr = checker->Allocator()->New(); + } else if (rhs_type->IsETSNullType()) { + rhs_expr = checker->Allocator()->New(); + } else { + rhs_expr = checker->Allocator()->New(rhs_type->AsETSObjectType()->Name(), checker->Allocator()); + auto rhs_var = NearestScope(union_node)->Find(rhs_expr->AsIdentifier()->Name()); + rhs_expr->AsIdentifier()->SetVariable(rhs_var.variable); + } auto *const instanceof_expr = checker->Allocator()->New(lhs_expr, rhs_expr, lexer::TokenType::KEYW_INSTANCEOF); lhs_expr->SetParent(instanceof_expr); rhs_expr->SetParent(instanceof_expr); - auto rhs_var = NearestScope(union_node)->Find(rhs_expr->Name()); - rhs_expr->SetVariable(rhs_var.variable); - rhs_expr->SetTsType(rhs_var.variable->TsType()); + rhs_expr->SetTsType(rhs_type); instanceof_expr->SetOperationType(checker->GlobalETSObjectType()); instanceof_expr->SetTsType(checker->GlobalETSBooleanType()); return instanceof_expr; @@ -272,7 +283,10 @@ ir::Expression *ProcessOperandsInBinaryExpr(checker::ETSChecker *checker, ir::Bi bool is_lhs_union; ir::Expression *union_node = (is_lhs_union = expr->Left()->TsType()->IsETSUnionType()) ? expr->Left() : expr->Right(); - auto *const as_expression = GenAsExpression(checker, constituent_type, union_node, expr); + checker::Type *type_to_cast = constituent_type->IsETSNullLike() + ? union_node->TsType()->AsETSUnionType()->GetLeastUpperBoundType() + : constituent_type; + auto *const as_expression = GenAsExpression(checker, type_to_cast, union_node, expr); if (is_lhs_union) { expr->SetLeft(as_expression); expr->SetRight(SetBoxFlagOrGenAsExpression(checker, constituent_type, expr->Right())); diff --git a/ets2panda/ir/expressions/literals/undefinedLiteral.cpp b/ets2panda/ir/expressions/literals/undefinedLiteral.cpp index 27bddb8b40..3d28d6c06b 100644 --- a/ets2panda/ir/expressions/literals/undefinedLiteral.cpp +++ b/ets2panda/ir/expressions/literals/undefinedLiteral.cpp @@ -56,4 +56,17 @@ checker::Type *UndefinedLiteral::Check([[maybe_unused]] checker::ETSChecker *che SetTsType(checker->GlobalETSUndefinedType()); return TsType(); } + +// NOLINTNEXTLINE(google-default-arguments) +UndefinedLiteral *UndefinedLiteral::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + if (auto *const clone = allocator->New(); clone != nullptr) { + if (parent != nullptr) { + clone->SetParent(parent); + } + return clone; + } + + throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR); +} } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/literals/undefinedLiteral.h b/ets2panda/ir/expressions/literals/undefinedLiteral.h index 818867cde5..2de04789a1 100644 --- a/ets2panda/ir/expressions/literals/undefinedLiteral.h +++ b/ets2panda/ir/expressions/literals/undefinedLiteral.h @@ -23,6 +23,9 @@ class UndefinedLiteral : public Literal { public: explicit UndefinedLiteral() : Literal(AstNodeType::UNDEFINED_LITERAL) {} + // NOLINTNEXTLINE(google-default-arguments) + [[nodiscard]] UndefinedLiteral *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; + void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/test/runtime/ets/conditionalExpression.ets b/ets2panda/test/runtime/ets/conditionalExpression1.ets similarity index 100% rename from ets2panda/test/runtime/ets/conditionalExpression.ets rename to ets2panda/test/runtime/ets/conditionalExpression1.ets diff --git a/ets2panda/test/runtime/ets/conditionalExpression2.ets b/ets2panda/test/runtime/ets/conditionalExpression2.ets new file mode 100644 index 0000000000..59805a5873 --- /dev/null +++ b/ets2panda/test/runtime/ets/conditionalExpression2.ets @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021-2023 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 foo(form?: String) { + const f = (form == undefined) ? "abc" : form! + switch (f) { + case "abc": + return 41 + case "xyz": + return 42 + default: + return 0 + } +} + +class A{} + +function main(): void { + assert foo() == 41: "Error! foo() must be equal 41"; + assert foo("xyz") == 42: "Error! foo(\"xyz\") must be equal 42"; + assert foo("NFD") == 0: "Error! foo(\"NFD\") must be equal 0"; + let x = foo() == 41 ? new A() : undefined; + assert x instanceof A; + let y = foo("wxyz") == 42 ? "TRUE" : new A(); + assert y instanceof A; + y = "JK"; + assert y == "JK"; +} diff --git a/ets2panda/test/runtime/ets/conditionalExpressionLUB.ets b/ets2panda/test/runtime/ets/conditionalExpressionLUB.ets index 3b36957fde..6d20bf0e10 100644 --- a/ets2panda/test/runtime/ets/conditionalExpressionLUB.ets +++ b/ets2panda/test/runtime/ets/conditionalExpressionLUB.ets @@ -61,23 +61,23 @@ function sameTypeLUB(): void { function objectLUB(): void { let a : A = new A(); let b : Int = 2; - let c = true ? a : b; // Object + let c = true ? a : b; // A | Int assert(foo(c) == 1); let arr : Int[] | null = null; - let d = true ? a : arr; // Object + let d = true ? a : arr; // A | Int[] | null assert(foo(d) == 1); } function forkSubtypeLUB(): void { let a : F = new F(); let b : D = new D(); - let c = true ? a : b; // A + let c = true ? a : b; // F | D => call most specific foo(A) assert(foo(c) == 2); let d : A = new A(); - let e = true ? a : b; // A + let e = true ? a : d; // F | A => normalize to A assert(foo(e) == 2); let f : B = new B(); - let g = true ? a : f; // B + let g = true ? a : f; // F | B => normalize to B assert(foo(g) == 3); } diff --git a/ets2panda/test/unit/union_normalization_test.cpp b/ets2panda/test/unit/union_normalization_test.cpp index 6da53b1a0b..cbffadb1fd 100644 --- a/ets2panda/test/unit/union_normalization_test.cpp +++ b/ets2panda/test/unit/union_normalization_test.cpp @@ -433,6 +433,54 @@ TEST_F(UnionNormalizationTest, UnionLinearization) ASSERT_EQ(ut3->ConstituentTypes().at(IDX2), checker.GetGlobalTypesHolder()->GlobalDoubleBuiltinType()); } +TEST_F(UnionNormalizationTest, UnionStringLiterals) +{ + // NOLINTNEXTLINE(modernize-avoid-c-arrays) + const char *argv = "../../../bin/es2panda"; + checker::ETSChecker checker; + auto program = parser::Program::NewProgram(Allocator()); + InitializeChecker(&argv, "_.ets", "", &checker, &program); + + // Test normalization: string | "abc" ==> string + ArenaVector union_constituents1(checker.Allocator()->Adapter()); + union_constituents1.emplace_back(checker.GlobalBuiltinETSStringType()); + union_constituents1.emplace_back(checker.CreateETSStringLiteralType("abc")); + + // Create union type, which will be normalized inside creation function + auto *const normalized_type1 = checker.CreateETSUnionType(std::move(union_constituents1)); + ASSERT_NE(normalized_type1, nullptr); + ASSERT_TRUE(normalized_type1->IsETSObjectType()); + ASSERT_EQ(normalized_type1, checker.GlobalBuiltinETSStringType()); + + // Test normalization: "abc" | string | string ==> string + ArenaVector union_constituents2(checker.Allocator()->Adapter()); + union_constituents2.emplace_back(checker.CreateETSStringLiteralType("abc")); + union_constituents2.emplace_back(checker.GlobalBuiltinETSStringType()); + union_constituents2.emplace_back(checker.GlobalBuiltinETSStringType()); + + // Create union type, which will be normalized inside creation function + auto *const normalized_type2 = checker.CreateETSUnionType(std::move(union_constituents2)); + ASSERT_NE(normalized_type2, nullptr); + ASSERT_TRUE(normalized_type2->IsETSObjectType()); + ASSERT_EQ(normalized_type2, checker.GlobalBuiltinETSStringType()); + + // Test normalization: number | "abc" | string | "xy" ==> number | string + ArenaVector union_constituents3(checker.Allocator()->Adapter()); + union_constituents3.emplace_back(checker.GlobalDoubleType()); + union_constituents3.emplace_back(checker.CreateETSStringLiteralType("abc")); + union_constituents3.emplace_back(checker.GlobalBuiltinETSStringType()); + union_constituents3.emplace_back(checker.CreateETSStringLiteralType("xy")); + + // Create union type, which will be normalized inside creation function + auto *const normalized_type3 = checker.CreateETSUnionType(std::move(union_constituents3)); + ASSERT_NE(normalized_type3, nullptr); + ASSERT_TRUE(normalized_type3->IsETSUnionType()); + auto *const union_type = normalized_type3->AsETSUnionType(); + ASSERT_EQ(union_type->ConstituentTypes().size(), SIZE2); + ASSERT_EQ(union_type->ConstituentTypes().at(IDX0), checker.GetGlobalTypesHolder()->GlobalDoubleBuiltinType()); + ASSERT_EQ(union_type->ConstituentTypes().at(IDX1), checker.GlobalBuiltinETSStringType()); +} + TEST_F(UnionNormalizationTest, UnionWithNever) { // Test normalization: int | never | number ==> number -- Gitee From a24e35dce53f23868574e69154611bb2c857c605 Mon Sep 17 00:00:00 2001 From: Maxim Logaev Date: Wed, 13 Dec 2023 17:47:18 +0300 Subject: [PATCH 08/24] Added bitwise operations on float Signed-off-by: Maxim Logaev --- ets2panda/checker/ETSAnalyzer.cpp | 8 +- ets2panda/checker/ETSchecker.cpp | 15 ++ ets2panda/checker/ETSchecker.h | 10 +- ets2panda/checker/ets/arithmetic.cpp | 54 +++- ets2panda/checker/ets/arithmetic.h | 71 ++--- ets2panda/compiler/core/ETSCompiler.cpp | 9 +- .../runtime/ets/BitwiseOperationsOnFloat.ets | 252 ++++++++++++++++++ 7 files changed, 366 insertions(+), 53 deletions(-) create mode 100644 ets2panda/test/runtime/ets/BitwiseOperationsOnFloat.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index aa57637bac..b671d228cf 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1559,17 +1559,17 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const break; } case lexer::TokenType::PUNCTUATOR_TILDE: { - if (operand_type == nullptr || !operand_type->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { - checker->ThrowTypeError("Bad operand type, the type of the operand must be integral type.", + if (operand_type == nullptr || !operand_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", expr->Argument()->Start()); } if (operand_type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { - expr->SetTsType(checker->BitwiseNegateIntegralType(operand_type, expr)); + expr->SetTsType(checker->BitwiseNegateNumericType(operand_type, expr)); break; } - expr->SetTsType(operand_type); + expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operand_type)); break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 86acb390af..868b01a6b5 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -344,4 +344,19 @@ void ETSChecker::HandleUpdatedCallExpressionNode(ir::CallExpression *call_expr) VarBinder()->AsETSBinder()->HandleCustomNodes(call_expr); } +Type *ETSChecker::SelectGlobalIntegerTypeForNumeric(Type *type) +{ + switch (ETSType(type)) { + case checker::TypeFlag::FLOAT: { + return GlobalIntType(); + } + case checker::TypeFlag::DOUBLE: { + return GlobalLongType(); + } + default: { + return type; + } + } +} + } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index a82b214e5c..a74c5db6cf 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -30,6 +30,7 @@ #include "ir/ts/tsTypeParameterInstantiation.h" #include "util/enumbitops.h" #include "util/ustring.h" +#include "utils/bit_utils.h" #include "checker/resolveResult.h" #include "macros.h" @@ -38,6 +39,7 @@ #include #include #include +#include namespace panda::es2panda::varbinder { class VarBinder; @@ -223,7 +225,7 @@ public: // Arithmetic Type *NegateNumericType(Type *type, ir::Expression *node); - Type *BitwiseNegateIntegralType(Type *type, ir::Expression *node); + Type *BitwiseNegateNumericType(Type *type, ir::Expression *node); std::tuple CheckBinaryOperator(ir::Expression *left, ir::Expression *right, ir::Expression *expr, lexer::TokenType operation_type, lexer::SourcePosition pos, bool force_promotion = false); @@ -263,6 +265,7 @@ public: checker::Type *CheckBinaryOperatorNullishCoalescing(ir::Expression *right, lexer::SourcePosition pos, checker::Type *left_type, checker::Type *right_type); Type *HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operation_type); + Type *HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operation_type); void FlagExpressionWithUnboxing(Type *type, Type *unboxed_type, ir::Expression *type_expression); template Type *PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operation_type); @@ -533,6 +536,7 @@ public: bool ExtensionETSFunctionType(checker::Type *type); void ValidateTupleMinElementSize(ir::ArrayExpression *array_expr, ETSTupleType *tuple); void ModifyPreferredType(ir::ArrayExpression *array_expr, Type *new_preferred_type); + Type *SelectGlobalIntegerTypeForNumeric(Type *type); // Exception ETSObjectType *CheckExceptionOrErrorType(checker::Type *type, lexer::SourcePosition pos); @@ -663,8 +667,8 @@ private: template UType HandleModulo(UType left_value, UType right_value); - template - UType HandleBitWiseArithmetic(UType left_value, UType right_value, lexer::TokenType operation_type); + template + Type *HandleBitWiseArithmetic(Type *left_value, Type *right_value, lexer::TokenType operation_type); template typename TargetType::UType GetOperand(Type *type); diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index fe8d0cd473..6ff49a3e30 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -68,7 +68,7 @@ Type *ETSChecker::NegateNumericType(Type *type, ir::Expression *node) return result; } -Type *ETSChecker::BitwiseNegateIntegralType(Type *type, ir::Expression *node) +Type *ETSChecker::BitwiseNegateNumericType(Type *type, ir::Expression *node) { ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL)); @@ -97,6 +97,16 @@ Type *ETSChecker::BitwiseNegateIntegralType(Type *type, ir::Expression *node) result = CreateLongType(static_cast(~static_cast(type->AsLongType()->GetValue()))); break; } + case TypeFlag::FLOAT: { + result = CreateIntType( + ~static_cast(CastFloatToInt(type->AsFloatType()->GetValue()))); + break; + } + case TypeFlag::DOUBLE: { + result = CreateLongType( + ~static_cast(CastFloatToInt(type->AsDoubleType()->GetValue()))); + break; + } default: { UNREACHABLE(); } @@ -200,13 +210,13 @@ checker::Type *ETSChecker::CheckBinaryOperatorShift(ir::Expression *left, ir::Ex FlagExpressionWithUnboxing(left_type, unboxed_l, left); FlagExpressionWithUnboxing(right_type, unboxed_r, right); - if (promoted_left_type == nullptr || !promoted_left_type->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL) || - promoted_right_type == nullptr || !promoted_right_type->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { - ThrowTypeError("Bad operand type, the types of the operands must be integral type.", pos); + if (promoted_left_type == nullptr || !promoted_left_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) || + promoted_right_type == nullptr || !promoted_right_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); } if (promoted_left_type->HasTypeFlag(TypeFlag::CONSTANT) && promoted_right_type->HasTypeFlag(TypeFlag::CONSTANT)) { - return HandleArithmeticOperationOnTypes(promoted_left_type, promoted_right_type, operation_type); + return HandleBitwiseOperationOnTypes(promoted_left_type, promoted_right_type, operation_type); } switch (ETSType(promoted_left_type)) { @@ -219,10 +229,12 @@ checker::Type *ETSChecker::CheckBinaryOperatorShift(ir::Expression *left, ir::Ex case TypeFlag::CHAR: { return GlobalCharType(); } - case TypeFlag::INT: { + case TypeFlag::INT: + case TypeFlag::FLOAT: { return GlobalIntType(); } - case TypeFlag::LONG: { + case TypeFlag::LONG: + case TypeFlag::DOUBLE: { return GlobalLongType(); } default: { @@ -249,20 +261,20 @@ checker::Type *ETSChecker::CheckBinaryOperatorBitwise(ir::Expression *left, ir:: } auto [promotedType, bothConst] = - ApplyBinaryOperatorPromotion(unboxed_l, unboxed_r, TypeFlag::ETS_INTEGRAL, !is_equal_op); + ApplyBinaryOperatorPromotion(unboxed_l, unboxed_r, TypeFlag::ETS_NUMERIC, !is_equal_op); FlagExpressionWithUnboxing(left_type, unboxed_l, left); FlagExpressionWithUnboxing(right_type, unboxed_r, right); if (promotedType == nullptr && !bothConst) { - ThrowTypeError("Bad operand type, the types of the operands must be integral type.", pos); + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); } if (bothConst) { - return HandleArithmeticOperationOnTypes(left_type, right_type, operation_type); + return HandleBitwiseOperationOnTypes(left_type, right_type, operation_type); } - return promotedType; + return SelectGlobalIntegerTypeForNumeric(promotedType); } checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir::Expression *right, ir::Expression *expr, @@ -603,6 +615,26 @@ Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexe return PerformArithmeticOperationOnTypes(left, right, operation_type); } +Type *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operation_type) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return HandleBitWiseArithmetic(left, right, operation_type); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return HandleBitWiseArithmetic(left, right, operation_type); + } + + if (left->IsLongType() || right->IsLongType()) { + return HandleBitWiseArithmetic(left, right, operation_type); + } + + return HandleBitWiseArithmetic(left, right, operation_type); +} + void ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxed_type, ir::Expression *type_expression) { if (type->IsETSObjectType() && (unboxed_type != nullptr)) { diff --git a/ets2panda/checker/ets/arithmetic.h b/ets2panda/checker/ets/arithmetic.h index 0eb9a97929..c521113a21 100644 --- a/ets2panda/checker/ets/arithmetic.h +++ b/ets2panda/checker/ets/arithmetic.h @@ -17,7 +17,6 @@ #define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H #include "checker/ETSchecker.h" -#include "checker/types/ets/etsBooleanType.h" namespace panda::es2panda::checker { @@ -137,7 +136,7 @@ Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lex break; } default: { - result = HandleBitWiseArithmetic(left_value, right_value, operation_type); + UNREACHABLE(); } } @@ -172,63 +171,69 @@ inline DoubleType::UType panda::es2panda::checker::ETSChecker::HandleModulo -UType ETSChecker::HandleBitWiseArithmetic(UType left_value, UType right_value, lexer::TokenType operation_type) +template +inline IntegerUType CastIfFloat(FloatOrIntegerUType num) +{ + if constexpr (std::is_floating_point_v) { + return CastFloatToInt(num); + } else { + return num; + } +} + +template +Type *ETSChecker::HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operation_type) { - using UnsignedType = std::make_unsigned_t; - auto unsigned_left_value = static_cast(left_value); - auto unsigned_right_value = static_cast(right_value); - size_t mask = std::numeric_limits::digits - 1U; - size_t shift = static_cast(unsigned_right_value) & mask; + using IntegerUType = typename IntegerType::UType; + using UnsignedUType = std::make_unsigned_t; + + UnsignedUType result = 0; + UnsignedUType unsigned_left_value = CastIfFloat(GetOperand(left)); + UnsignedUType unsigned_right_value = CastIfFloat(GetOperand(right)); + + auto mask = std::numeric_limits::digits - 1U; + auto shift = unsigned_right_value & mask; switch (operation_type) { case lexer::TokenType::PUNCTUATOR_BITWISE_AND: case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { - return unsigned_left_value & unsigned_right_value; + result = unsigned_left_value & unsigned_right_value; + break; } case lexer::TokenType::PUNCTUATOR_BITWISE_OR: case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { - return unsigned_left_value | unsigned_right_value; + result = unsigned_left_value | unsigned_right_value; + break; } case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { - return unsigned_left_value ^ unsigned_right_value; + result = unsigned_left_value ^ unsigned_right_value; + break; } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { - static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); - return unsigned_left_value << shift; + static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); + result = unsigned_left_value << shift; + break; } case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { - static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); - return left_value >> shift; // NOLINT(hicpp-signed-bitwise) + static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8); + result = static_cast(unsigned_left_value) >> shift; // NOLINT(hicpp-signed-bitwise) + break; } case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { - static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); - return unsigned_left_value >> shift; + static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); + result = unsigned_left_value >> shift; + break; } default: { UNREACHABLE(); } } -} - -template <> -inline FloatType::UType ETSChecker::HandleBitWiseArithmetic( - [[maybe_unused]] FloatType::UType left_value, [[maybe_unused]] FloatType::UType right_value, - [[maybe_unused]] lexer::TokenType operation_type) -{ - return 0.0; -} -template <> -inline DoubleType::UType ETSChecker::HandleBitWiseArithmetic( - [[maybe_unused]] DoubleType::UType left_value, [[maybe_unused]] DoubleType::UType right_value, - [[maybe_unused]] lexer::TokenType operation_type) -{ - return 0.0; + return Allocator()->New(result); } } // namespace panda::es2panda::checker diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 46fb246baa..eeea65e26a 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -551,8 +551,7 @@ void ETSCompiler::Compile(const ir::BinaryExpression *expr) const etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); expr->Right()->Compile(etsg); etsg->ApplyConversion(expr->Right(), expr->OperationType()); - if (expr->OperatorType() >= lexer::TokenType::PUNCTUATOR_LEFT_SHIFT && - expr->OperatorType() <= lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT) { + if (expr->OperationType()->IsIntType()) { etsg->ApplyCast(expr->Right(), expr->OperationType()); } @@ -1069,7 +1068,13 @@ void ETSCompiler::Compile(const ir::UnaryExpression *expr) const if (!etsg->TryLoadConstantExpression(expr->Argument())) { expr->Argument()->Compile(etsg); } + etsg->ApplyConversion(expr->Argument(), nullptr); + + if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_TILDE) { + etsg->ApplyCast(expr->Argument(), expr->TsType()); + } + etsg->Unary(expr, expr->OperatorType()); } diff --git a/ets2panda/test/runtime/ets/BitwiseOperationsOnFloat.ets b/ets2panda/test/runtime/ets/BitwiseOperationsOnFloat.ets new file mode 100644 index 0000000000..816928325c --- /dev/null +++ b/ets2panda/test/runtime/ets/BitwiseOperationsOnFloat.ets @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2023 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 And(a: double, b: double): long { + return a & b +} + +function Or(a: double, b: double): long { + return a | b +} + +function Xor(a: double, b: double): long { + return a ^ b +} + +function LeftShift(a: double, b: double): long { + return a << b +} + +function RightShift(a: double, b: double): long { + return a >> b +} + +function UnsignedRightShift(a: double, b: double): long { + return a >>> b +} + +function Inversion(a: double): long { + return ~a; +} + +function main(): void { + /* ---- Compile time tests ---- */ + + // Testing "and" operator: + assert (542.910991 & -1903.2040221) == 16 + assert (-542.910991 & 1903.2040221) == 1378 + assert (-542.910991 & -1903.2040221) == -1920 + assert (9E120 & 56.75) == 56 + assert (0.0 & 0.0) == 0 + assert (NaN & 42.131330352) == 0 + assert (-NaN & -23432.34110144432) == 0 + assert (Infinity & -94.24445985981884) == 9223372036854775714 + assert (-Infinity & 94.24445985981884) == 0 + + // Testing "or" operator: + assert (542.910991 | 1903.2040221) == 1919 + assert (542.910991 | -1903.2040221) == -1377 + assert (-542.910991 | 1903.2040221) == -17 + assert (-542.910991 | -1903.2040221) == -525 + assert (9E120 | 0) == 9223372036854775807 + assert (824E3 | 21.018763) == 824021 + assert (1.0 | 0.1) == 1 + assert (NaN | 0.2) == 0 + assert (-NaN | 0.3) == 0 + assert (Infinity | 0.4) == 9223372036854775807 + assert (-Infinity | 0.5) == -9223372036854775808 + + // Testing "xor" operator: + assert (542.910991 ^ 1903.2040221) == 1393 + assert (542.910991 ^ -1903.2040221) == -1393 + assert (-542.910991 ^ 1903.2040221) == -1395 + assert (-542.910991 ^ -1903.2040221) == 1395 + assert (49509.2348100001 ^ 49509.2348100001) == 0 + assert (9E120 ^ 1.2) == 9223372036854775806 + assert (824E3 ^ 21.018763) == 824021 + assert (NaN ^ 99854258.24) == 99854258 + assert (-NaN ^ 30483040.293244) == 30483040 + assert (Infinity ^ 1.2) == 9223372036854775806 + assert (-Infinity ^ 10049329.80001) == -9223372036844726479 + + // Testing "left shift" operator: + assert (1E-100 << 0.0) == 0 + assert (0.00003 << 12.13) == 0 + assert (42.109 << 0.0120939) == 42 + assert (1.409240940 << 17.3) == 131072 + assert (4342435.309421 << 3.1) == 34739480 + assert (9010034745.3449093132 << 7.000000000001) == 1153284447360 + assert (-423.14981 << 20.32) == -443547648 + assert (500.13 << 128.3440) == 500 + assert (500.45 << 121.10000002) == -1729382256910270464 + assert (NaN << 330.3911) == 0 + assert (-NaN << 12.91213) == 0 + assert (Infinity << 1.0092) == -2 + assert (-Infinity << 1.0092) == 0 + assert (-52242.2301 << -8.7) == -1297036692682702848 + assert (52242.2301 << -8.7) == 1297036692682702848 + + // Testing "right shift" operator: + assert (1E-100 >> 0.0) == 0 + assert (0.00003 >> 12.13) == 0 + assert (42.109 >> 0.0120939) == 42 + assert (1.409240940 >> 17.3) == 0 + assert (4342435.309421 >> 3.1) == 542804 + assert (9010034.3449093132 >> 3.000000000001) == 1126254 + assert (-4599090490.24 >> 11) == -2245650 + assert (500.13 >> 128.3440) == 500 + assert (500.45 >> 121.10000002) == 0 + assert (NaN >> 11.000003) == 0 + assert (-NaN >> 7.912130001) == 0 + assert (Infinity >> 61) == 3 + assert (-Infinity >> 61) == -4 + assert (132090941883.34343 >> -32.2) == 30 + assert (-132090941883.34343 >> -32.2) == -31 + + // Testing "unsigned right shift" operator: + assert (1E-100 >>> 0.0) == 0 + assert (0.00003 >>> 12.13) == 0 + assert (42.109 >>> 0.0120939) == 42 + assert (1.409240940 >>> 17.3) == 0 + assert (4342435.309421 >>> 3.1) == 542804 + assert (9010034.3449093132 >>> 3.000000000001) == 1126254 + assert (-4599090490.24 >>> 11) == 9007199252495342 + assert (500.13 >>> 128.3440) == 500 + assert (500.45 >>> 121.10000002) == 0 + assert (NaN >>> 11.000003) == 0 + assert (-NaN >>> 7.912130001) == 0 + assert (Infinity >>> 61.8) == 3 + assert (-Infinity >>> 61.8) == 4 + assert (132090941883.34343 >>> -32.2) == 30 + assert (-132090941883.34343 >>> -32.2) == 4294967265 + + // Testing "bitwise complement" operator + assert ~0 == -1 + assert ~0.000034 == -1 + assert ~39530.93 == -39531 + assert ~93718001.5424230894 == -93718002 + assert ~Infinity == -9223372036854775808 + assert ~-Infinity == 9223372036854775807 + assert ~NaN == -1 + assert ~-NaN == -1 + assert ~1E210 == -9223372036854775808 + assert ~-1E210 == 9223372036854775807 + assert ~56E5 == -5600001 + assert ~-56E5 == 5599999 + + /* ---- Run time tests ---- */ + + // Testing "and" operator: + assert And(542.910991, -1903.2040221) == 16 + assert And(-542.910991, 1903.2040221) == 1378 + assert And(-542.910991, -1903.2040221) == -1920 + assert And(9E120, 56.75) == 56 + assert And(0.0, 0.0) == 0 + assert And(NaN, 42.131330352) == 0 + assert And(-NaN, -23432.34110144432) == 0 + assert And(Infinity, -94.24445985981884) == 9223372036854775714 + assert And(-Infinity, 94.24445985981884) == 0 + + // Testing "or" operator: + assert Or(542.910991, 1903.2040221) == 1919 + assert Or(542.910991, -1903.2040221) == -1377 + assert Or(-542.910991, 1903.2040221) == -17 + assert Or(-542.910991, -1903.2040221) == -525 + assert Or(9E120, 0) == 9223372036854775807 + assert Or(824E3, 21.018763) == 824021 + assert Or(1.0, 0.1) == 1 + assert Or(NaN, 0.2) == 0 + assert Or(-NaN, 0.3) == 0 + assert Or(Infinity, 0.4) == 9223372036854775807 + assert Or(-Infinity, 0.5) == -9223372036854775808 + + // Testing "xor" operator: + assert Xor(542.910991, 1903.2040221) == 1393 + assert Xor(542.910991, -1903.2040221) == -1393 + assert Xor(-542.910991, 1903.2040221) == -1395 + assert Xor(-542.910991, -1903.2040221) == 1395 + assert Xor(49509.2348100001, 49509.2348100001) == 0 + assert Xor(9E120, 1.2) == 9223372036854775806 + assert Xor(824E3, 21.018763) == 824021 + assert Xor(NaN, 99854258.24) == 99854258 + assert Xor(-NaN, 30483040.293244) == 30483040 + assert Xor(Infinity, 1.2) == 9223372036854775806 + assert Xor(-Infinity, 10049329.80001) == -9223372036844726479 + + // Testing "left shift" operator: + assert LeftShift(1E-100, 0.0) == 0 + assert LeftShift(0.00003, 12.13) == 0 + assert LeftShift(42.109, 0.0120939) == 42 + assert LeftShift(1.409240940, 17.3) == 131072 + assert LeftShift(4342435.309421, 3.1) == 34739480 + assert LeftShift(9010034745.3449093132, 7.000000000001) == 1153284447360 + assert LeftShift(-423.14981, 20.32) == -443547648 + assert LeftShift(500.13, 128.3440) == 500 + assert LeftShift(500.45, 121.10000002) == -1729382256910270464 + assert LeftShift(NaN, 330.3911) == 0 + assert LeftShift(-NaN, 12.91213) == 0 + assert LeftShift(Infinity, 1.0092) == -2 + assert LeftShift(-Infinity, 1.0092) == 0 + assert LeftShift(-52242.2301, -8.7) == -1297036692682702848 + assert LeftShift(52242.2301,-8.7) == 1297036692682702848 + + // Testing "right shift" operator: + assert RightShift(1E-100, 0.0) == 0 + assert RightShift(0.00003, 12.13) == 0 + assert RightShift(42.109, 0.0120939) == 42 + assert RightShift(1.409240940, 17.3) == 0 + assert RightShift(4342435.309421, 3.1) == 542804 + assert RightShift(9010034.3449093132, 3.000000000001) == 1126254 + assert RightShift(-4599090490.24, 11) == -2245650 + assert RightShift(500.13, 128.3440) == 500 + assert RightShift(500.45, 121.10000002) == 0 + assert RightShift(NaN, 11.000003) == 0 + assert RightShift(-NaN, 7.912130001) == 0 + assert RightShift(Infinity, 61) == 3 + assert RightShift(-Infinity, 61) == -4 + assert RightShift(132090941883.34343, -32.2) == 30 + assert RightShift(-132090941883.34343, -32.2) == -31 + + // Testing "unsigned right shift" operator: + assert UnsignedRightShift(1E-100, 0.0) == 0 + assert UnsignedRightShift(0.00003,12.13) == 0 + assert UnsignedRightShift(42.109, 0.0120939) == 42 + assert UnsignedRightShift(1.409240940, 17.3) == 0 + assert UnsignedRightShift(4342435.309421, 3.1) == 542804 + assert UnsignedRightShift(9010034.3449093132, 3.000000000001) == 1126254 + assert UnsignedRightShift(-4599090490.24, 11) == 9007199252495342 + assert UnsignedRightShift(500.13, 128.3440) == 500 + assert UnsignedRightShift(500.45, 121.10000002) == 0 + assert UnsignedRightShift(NaN, 11.000003) == 0 + assert UnsignedRightShift(-NaN, 7.912130001) == 0 + assert UnsignedRightShift(Infinity, 61.8) == 3 + assert UnsignedRightShift(-Infinity, 61.8) == 4 + assert UnsignedRightShift(132090941883.34343, -32.2) == 30 + assert UnsignedRightShift(-132090941883.34343, -32.2) == 4294967265 + + // Testing "bitwise complement" operator + assert Inversion(0) == -1 + assert Inversion(0.000034) == -1 + assert Inversion(39530.93) == -39531 + assert Inversion(93718001.5424230894) == -93718002 + assert Inversion(Infinity) == -9223372036854775808 + assert Inversion(-Infinity) == 9223372036854775807 + assert Inversion(NaN) == -1 + assert Inversion(-NaN) == -1 + assert Inversion(1E210) == -9223372036854775808 + assert Inversion(-1E210) == 9223372036854775807 + assert Inversion(56E5) == -5600001 + assert Inversion(-56E5) == 5599999 +} -- Gitee From 3ea47a979c1e6881900118dcbcd814c7a4c5d4c4 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Mon, 25 Dec 2023 10:42:16 +0300 Subject: [PATCH 09/24] Fix incorrect CTE message on instanceof A Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8PGFU Testing: added negative compile-time cts tests Signed-off-by: Konstantin Kuznetsov --- ets2panda/parser/ASparser.cpp | 5 +++- ets2panda/parser/ASparser.h | 5 +++- ets2panda/parser/ETSparser.cpp | 34 ++++++++++++++++++++--- ets2panda/parser/ETSparser.h | 8 +++--- ets2panda/parser/TSparser.cpp | 5 +++- ets2panda/parser/TSparser.h | 5 +++- ets2panda/parser/expressionParser.cpp | 39 ++++++++++++++++++--------- ets2panda/parser/parserFlags.h | 1 + ets2panda/parser/parserImpl.h | 8 ++++-- 9 files changed, 85 insertions(+), 25 deletions(-) diff --git a/ets2panda/parser/ASparser.cpp b/ets2panda/parser/ASparser.cpp index b74d7243cf..e3e06504f7 100644 --- a/ets2panda/parser/ASparser.cpp +++ b/ets2panda/parser/ASparser.cpp @@ -15,6 +15,7 @@ #include "ASparser.h" +#include "parserFlags.h" #include "util/helpers.h" #include "varbinder/privateBinding.h" #include "varbinder/scope.h" @@ -1350,7 +1351,9 @@ ir::AstNode *ASParser::ParseImportDefaultSpecifier(ArenaVector *s return nullptr; } -ir::Expression *ASParser::ParseCoverParenthesizedExpressionAndArrowParameterList() +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ASParser::ParseCoverParenthesizedExpressionAndArrowParameterList( + [[maybe_unused]] ExpressionParseFlags flags) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer::SourcePosition start = Lexer()->GetToken().Start(); diff --git a/ets2panda/parser/ASparser.h b/ets2panda/parser/ASparser.h index dbbf869c47..fc7cdf98b6 100644 --- a/ets2panda/parser/ASparser.h +++ b/ets2panda/parser/ASparser.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_CORE_AS_PARSER_H #include "TypedParser.h" +#include "parserFlags.h" namespace panda::es2panda::parser { class ASParser : public TypedParser { @@ -74,7 +75,9 @@ private: const ArenaVector ¶ms, ParserStatus new_status, ParserStatus context_status) override; ir::AstNode *ParseImportDefaultSpecifier(ArenaVector *specifiers) override; std::tuple ParseInterfacePropertyKey() override; - ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList() override; + // NOLINTNEXTLINE(google-default-arguments) + ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( + ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; ir::Expression *ParsePrefixAssertionExpression() override; ir::Statement *ParseConstStatement(StatementParsingFlags flags) override; ir::AnnotatedExpression *ParseVariableDeclaratorKey(VariableParsingFlags flags) override; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index a78f3e1ad6..38d474a2fc 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -3806,7 +3806,7 @@ ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags) return ParseCharLiteral(); } case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - return ParseCoverParenthesizedExpressionAndArrowParameterList(); + return ParseCoverParenthesizedExpressionAndArrowParameterList(flags); } case lexer::TokenType::KEYW_THIS: { return ParseThisExpression(); @@ -3907,7 +3907,8 @@ ir::ArrowFunctionExpression *ETSParser::ParseArrowFunctionExpression() return arrow_func_node; } -ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterList() +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterList(ExpressionParseFlags flags) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); if (IsArrowFunctionExpressionStart()) { @@ -3917,7 +3918,12 @@ ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterLis lexer::SourcePosition start = Lexer()->GetToken().Start(); Lexer()->NextToken(); - ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); + ExpressionParseFlags new_flags = ExpressionParseFlags::ACCEPT_COMMA; + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + new_flags |= ExpressionParseFlags::INSTANCEOF; + }; + + ir::Expression *expr = ParseExpression(new_flags); if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { ThrowSyntaxError("Unexpected token, expected ')'"); @@ -4595,6 +4601,24 @@ bool ETSParser::IsStructKeyword() const Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT); } +void ETSParser::ValidateInstanceOfExpression(ir::Expression *expr) +{ + ValidateGroupedExpression(expr); + lexer::TokenType token_type = Lexer()->GetToken().Type(); + if (token_type == lexer::TokenType::PUNCTUATOR_LESS_THAN) { + auto options = TypeAnnotationParsingOptions::NO_OPTS; + + // Run checks to validate type declarations + // Should provide helpful messages with incorrect declarations like the following: + // instanceof A; + ThrowSyntaxError("Invalid right-hand side in 'instanceof' expression"); + } +} + // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags) { @@ -4606,6 +4630,10 @@ ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags) } ir::Expression *unary_expression_node = ParseUnaryOrPrefixUpdateExpression(flags); + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + ValidateInstanceOfExpression(unary_expression_node); + } + ir::Expression *assignment_expression = ParseAssignmentExpression(unary_expression_node, flags); if (Lexer()->GetToken().NewLine()) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index ec1f1667de..ffbbf5b088 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_CORE_ETS_PARSER_H #include +#include "parserFlags.h" #include "util/arktsconfig.h" #include "TypedParser.h" @@ -192,7 +193,9 @@ private: void ValidateForInStatement() override; - ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList() override; + // NOLINTNEXTLINE(google-default-arguments) + ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( + ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; ir::Statement *ParseTryStatement() override; ir::DebuggerStatement *ParseDebuggerStatement() override; void ParseExport(lexer::SourcePosition start_loc); @@ -264,6 +267,7 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseEnumDeclaration(bool is_const = false, bool is_static = false) override; ir::Expression *ParseLaunchExpression(ExpressionParseFlags flags); + void ValidateInstanceOfExpression(ir::Expression *expr); void ValidateRestParameter(ir::Expression *param) override; void CheckIndexAccessMethod(ir::ScriptFunction const *function, const lexer::SourcePosition &position) const; @@ -320,7 +324,6 @@ private: ir::Statement *CreateStatement(std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view source_code, std::vector &inserting_nodes, std::string_view file_name = DEFAULT_SOURCE_FILE); - // NOLINTEND(google-default-arguments) template ir::Statement *CreateFormattedStatement(std::string_view const source_code, std::string_view const file_name, @@ -338,7 +341,6 @@ private: std::string_view file_name = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); - // NOLINTEND(google-default-arguments) friend class ExternalSourceParser; friend class InnerSourceParser; diff --git a/ets2panda/parser/TSparser.cpp b/ets2panda/parser/TSparser.cpp index 29781c637d..3204d0899d 100644 --- a/ets2panda/parser/TSparser.cpp +++ b/ets2panda/parser/TSparser.cpp @@ -15,6 +15,7 @@ #include "TSparser.h" +#include "parserFlags.h" #include "util/helpers.h" #include "varbinder/privateBinding.h" #include "varbinder/scope.h" @@ -2600,7 +2601,9 @@ ir::Statement *TSParser::ParseExportDeclaration(StatementParsingFlags flags) } } -ir::Expression *TSParser::ParseCoverParenthesizedExpressionAndArrowParameterList() +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *TSParser::ParseCoverParenthesizedExpressionAndArrowParameterList( + [[maybe_unused]] ExpressionParseFlags flags) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer::SourcePosition start = Lexer()->GetToken().Start(); diff --git a/ets2panda/parser/TSparser.h b/ets2panda/parser/TSparser.h index 376f7f0a2e..3e660ea9a0 100644 --- a/ets2panda/parser/TSparser.h +++ b/ets2panda/parser/TSparser.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_CORE_TS_PARSER_H #include "TypedParser.h" +#include "parserFlags.h" namespace panda::es2panda::ir { class Decorator; @@ -123,7 +124,9 @@ private: const ArenaVector ¶ms, ParserStatus new_status, ParserStatus context_status) override; ir::AstNode *ParseImportDefaultSpecifier(ArenaVector *specifiers) override; ir::Statement *ParseExportDeclaration(StatementParsingFlags flags) override; - ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList() override; + // NOLINTNEXTLINE(google-default-arguments) + ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( + ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; ir::Statement *ParseConstStatement(StatementParsingFlags flags) override; ir::Statement *ParsePotentialConstEnum(VariableParsingFlags flags) override; void ParseCatchParamTypeAnnotation(ir::AnnotatedExpression *param) override; diff --git a/ets2panda/parser/expressionParser.cpp b/ets2panda/parser/expressionParser.cpp index 09d10d8642..ecfdfd2f83 100644 --- a/ets2panda/parser/expressionParser.cpp +++ b/ets2panda/parser/expressionParser.cpp @@ -420,7 +420,9 @@ void ParserImpl::ValidateArrowFunctionRestParameter([[maybe_unused]] ir::SpreadE } } -ir::Expression *ParserImpl::ParseCoverParenthesizedExpressionAndArrowParameterList() +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ParserImpl::ParseCoverParenthesizedExpressionAndArrowParameterList( + [[maybe_unused]] ExpressionParseFlags flags) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer::SourcePosition start = lexer_->GetToken().Start(); @@ -492,6 +494,20 @@ void ParserImpl::CheckInvalidDestructuring(const ir::AstNode *object) const }); } +void ParserImpl::ValidateGroupedExpression(ir::Expression *lhs_expression) +{ + lexer::TokenType token_type = lexer_->GetToken().Type(); + if (lhs_expression->IsGrouped() && token_type != lexer::TokenType::PUNCTUATOR_ARROW) { + if (lhs_expression->IsSequenceExpression()) { + for (auto *seq : lhs_expression->AsSequenceExpression()->Sequence()) { + ValidateParenthesizedExpression(seq); + } + } else { + ValidateParenthesizedExpression(lhs_expression); + } + } +} + void ParserImpl::ValidateParenthesizedExpression(ir::Expression *lhs_expression) { switch (lhs_expression->Type()) { @@ -542,17 +558,9 @@ ir::Expression *ParserImpl::ParsePrefixAssertionExpression() ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhs_expression, ExpressionParseFlags flags) { - lexer::TokenType token_type = lexer_->GetToken().Type(); - if (lhs_expression->IsGrouped() && token_type != lexer::TokenType::PUNCTUATOR_ARROW) { - if (lhs_expression->IsSequenceExpression()) { - for (auto *seq : lhs_expression->AsSequenceExpression()->Sequence()) { - ValidateParenthesizedExpression(seq); - } - } else { - ValidateParenthesizedExpression(lhs_expression); - } - } + ValidateGroupedExpression(lhs_expression); + lexer::TokenType token_type = lexer_->GetToken().Type(); switch (token_type) { case lexer::TokenType::PUNCTUATOR_QUESTION_MARK: { lexer_->NextToken(); @@ -1191,7 +1199,7 @@ void ParserImpl::CreateAmendedBinaryExpression(ir::Expression *const left, ir::E SetAmendedChildExpression(right, binary_expr); } -ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) +ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left, ExpressionParseFlags flags) { lexer::TokenType operator_type = lexer_->GetToken().Type(); ASSERT(lexer::Token::IsBinaryToken(operator_type)); @@ -1206,7 +1214,12 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) lexer_->NextToken(); - ir::Expression *right_expr = ParseExpression(ExpressionParseFlags::DISALLOW_YIELD); + ExpressionParseFlags new_flags = ExpressionParseFlags::DISALLOW_YIELD; + if ((operator_type == lexer::TokenType::KEYW_INSTANCEOF) || ((flags & ExpressionParseFlags::INSTANCEOF) != 0)) { + new_flags |= ExpressionParseFlags::INSTANCEOF; + } + + ir::Expression *right_expr = ParseExpression(new_flags); ir::ConditionalExpression *conditional_expr = nullptr; if (right_expr->IsConditionalExpression() && !right_expr->IsGrouped()) { diff --git a/ets2panda/parser/parserFlags.h b/ets2panda/parser/parserFlags.h index 792114ad56..6d71e66beb 100644 --- a/ets2panda/parser/parserFlags.h +++ b/ets2panda/parser/parserFlags.h @@ -60,6 +60,7 @@ enum class ExpressionParseFlags : uint32_t { IMPORT = 1U << 10U, POTENTIAL_CLASS_LITERAL = 1U << 11U, IN_FOR = 1U << 12U, + INSTANCEOF = 1U << 13U, }; DEFINE_BITOPS(ExpressionParseFlags) diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index b6f43c0471..7d0d74e3d9 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -229,13 +229,15 @@ protected: // ExpressionParser.Cpp ir::Expression *ParseKeywordExpression(); - ir::Expression *ParseBinaryExpression(ir::Expression *left); + ir::Expression *ParseBinaryExpression(ir::Expression *left, + ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); void ValidateUpdateExpression(ir::Expression *return_expression, bool is_chain_expression); ir::Expression *ParseMemberExpression(bool ignore_call_expression = false, ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); ir::MetaProperty *ParsePotentialNewTarget(); void CheckInvalidDestructuring(const ir::AstNode *object) const; void ValidateParenthesizedExpression(ir::Expression *lhs_expression); + void ValidateGroupedExpression(ir::Expression *lhs_expression); ir::Expression *ParseImportExpression(); ir::Expression *ParseOptionalChain(ir::Expression *left_side_expr); ir::Expression *ParsePropertyKey(ExpressionParseFlags flags); @@ -482,7 +484,9 @@ protected: virtual void ThrowIllegalNewLineErrorAfterThrow(); virtual void ThrowIfVarDeclaration(VariableParsingFlags flags); virtual ir::Expression *ParsePrefixAssertionExpression(); - virtual ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList(); + // NOLINTNEXTLINE(google-default-arguments) + virtual ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( + ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); virtual void ThrowErrorIfStaticConstructor(ir::ModifierFlags flags); virtual std::tuple ParseComputedClassFieldOrIndexSignature(ir::Expression **prop_name); // NOLINTNEXTLINE(google-default-arguments) -- Gitee From 240cb6f5ff756c645b62d280ced1840b6510c68b Mon Sep 17 00:00:00 2001 From: Redkin Mikhail Date: Tue, 12 Dec 2023 17:10:43 +0300 Subject: [PATCH 10/24] Title: Support ambient declarations Issue: ##I8NV89:Ambient declaration implementation Testing: All required pre-merge tests passed. Results are available in the ggwatcher Signed-off-by: Redkin Mikhail --- ets2panda/checker/ets/enum.cpp | 22 +- ets2panda/compiler/core/ETSfunction.cpp | 6 + ets2panda/ir/ts/tsEnumDeclaration.h | 14 +- ets2panda/lexer/scripts/keywords.yaml | 1 + ets2panda/parser/ETSparser.cpp | 33 +- ets2panda/parser/context/parserContext.h | 3 +- .../test/parser/ets/declare_enum-expected.txt | 268 ++++++++++++ ets2panda/test/parser/ets/declare_enum.ets | 19 + .../parser/ets/declare_namespace-expected.txt | 290 ++++++++++++ .../test/parser/ets/declare_namespace.ets | 16 + .../ets/declare_namespace_2-expected.txt | 411 ++++++++++++++++++ .../test/parser/ets/declare_namespace_2.ets | 18 + .../test/parser/ets/declare_type-expected.txt | 194 +++++++++ ets2panda/test/parser/ets/declare_type.ets | 16 + 14 files changed, 1296 insertions(+), 15 deletions(-) create mode 100644 ets2panda/test/parser/ets/declare_enum-expected.txt create mode 100644 ets2panda/test/parser/ets/declare_enum.ets create mode 100644 ets2panda/test/parser/ets/declare_namespace-expected.txt create mode 100644 ets2panda/test/parser/ets/declare_namespace.ets create mode 100644 ets2panda/test/parser/ets/declare_namespace_2-expected.txt create mode 100644 ets2panda/test/parser/ets/declare_namespace_2.ets create mode 100644 ets2panda/test/parser/ets/declare_type-expected.txt create mode 100644 ets2panda/test/parser/ets/declare_type.ets diff --git a/ets2panda/checker/ets/enum.cpp b/ets2panda/checker/ets/enum.cpp index 30c36a8dc1..7259535dd0 100644 --- a/ets2panda/checker/ets/enum.cpp +++ b/ets2panda/checker/ets/enum.cpp @@ -139,7 +139,7 @@ template varbinder::FunctionParamScope *const param_scope, ArenaVector &¶ms, ArenaVector &&body, - ir::TypeNode *const return_type_annotation) + ir::TypeNode *const return_type_annotation, bool is_declare) { auto *const function_scope = varbinder->Allocator()->New(checker->Allocator(), param_scope); @@ -149,9 +149,15 @@ template auto *const body_block = checker->Allocator()->New(checker->Allocator(), std::move(body)); body_block->SetScope(function_scope); + auto flags = ir::ModifierFlags::PUBLIC; + + if (is_declare) { + flags |= ir::ModifierFlags::DECLARE; + } + auto *const function = checker->Allocator()->New( ir::FunctionSignature(nullptr, std::move(params), return_type_annotation), body_block, - ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC, false, Language(Language::Id::ETS)); + ir::ScriptFunctionFlags::METHOD, flags, is_declare, Language(Language::Id::ETS)); function->SetScope(function_scope); varbinder->AsETSBinder()->BuildInternalName(function); @@ -335,7 +341,7 @@ ETSEnumType::Method ETSChecker::CreateEnumFromIntMethod(ir::Identifier *const na auto *const enum_type_annotation = MakeTypeReference(Allocator(), enum_type->GetName()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), enum_type_annotation); + std::move(body), enum_type_annotation, enum_type->GetDecl()->IsDeclare()); function->AddFlag(ir::ScriptFunctionFlags::THROWS); auto *const ident = MakeQualifiedIdentifier(Allocator(), enum_type->GetDecl(), ETSEnumType::FROM_INT_METHOD_NAME); @@ -372,7 +378,7 @@ ETSEnumType::Method ETSChecker::CreateEnumToStringMethod(ir::Identifier *const s auto *const string_type_annotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), string_type_annotation); + std::move(body), string_type_annotation, enum_type->GetDecl()->IsDeclare()); auto *const function_ident = MakeQualifiedIdentifier(Allocator(), enum_type->GetDecl(), ETSEnumType::TO_STRING_METHOD_NAME); @@ -410,7 +416,7 @@ ETSEnumType::Method ETSChecker::CreateEnumGetValueMethod(ir::Identifier *const v auto *const int_type_annotation = Allocator()->New(ir::PrimitiveType::INT); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), int_type_annotation); + std::move(body), int_type_annotation, enum_type->GetDecl()->IsDeclare()); auto *const function_ident = MakeQualifiedIdentifier(Allocator(), enum_type->GetDecl(), ETSEnumType::GET_VALUE_METHOD_NAME); @@ -449,7 +455,7 @@ ETSEnumType::Method ETSChecker::CreateEnumGetNameMethod(ir::Identifier *const na auto *const string_type_annotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), string_type_annotation); + std::move(body), string_type_annotation, enum_type->GetDecl()->IsDeclare()); auto *const function_ident = MakeQualifiedIdentifier(Allocator(), enum_type->GetDecl(), ETSEnumType::GET_NAME_METHOD_NAME); @@ -573,7 +579,7 @@ ETSEnumType::Method ETSChecker::CreateEnumValueOfMethod(ir::Identifier *const na auto *const enum_type_annotation = MakeTypeReference(Allocator(), enum_type->GetName()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), enum_type_annotation); + std::move(body), enum_type_annotation, enum_type->GetDecl()->IsDeclare()); function->AddFlag(ir::ScriptFunctionFlags::THROWS); auto *const function_ident = @@ -605,7 +611,7 @@ ETSEnumType::Method ETSChecker::CreateEnumValuesMethod(ir::Identifier *const ite Allocator()->New(MakeTypeReference(Allocator(), enum_type->GetName())); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), param_scope, std::move(params), - std::move(body), enum_array_type_annotation); + std::move(body), enum_array_type_annotation, enum_type->GetDecl()->IsDeclare()); auto *const function_ident = MakeQualifiedIdentifier(Allocator(), enum_type->GetDecl(), ETSEnumType::VALUES_METHOD_NAME); diff --git a/ets2panda/compiler/core/ETSfunction.cpp b/ets2panda/compiler/core/ETSfunction.cpp index bddfa6ec04..75a1cb7e4b 100644 --- a/ets2panda/compiler/core/ETSfunction.cpp +++ b/ets2panda/compiler/core/ETSfunction.cpp @@ -146,6 +146,12 @@ void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *blo void ETSFunction::CompileFunction(ETSGen *etsg) { + const auto *decl = etsg->RootNode()->AsScriptFunction(); + + if (decl->IsDeclare()) { + return; + } + CompileSourceBlock(etsg, etsg->RootNode()->AsScriptFunction()->Body()->AsBlockStatement()); } diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index a0d0c168b6..319538c67e 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -31,16 +31,20 @@ class TSEnumMember; class TSEnumDeclaration : public TypedStatement { public: explicit TSEnumDeclaration(ArenaAllocator *allocator, Identifier *key, ArenaVector &&members, - bool is_const, bool is_static = false) + bool is_const, bool is_static = false, bool is_declare = false) : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), decorators_(allocator->Adapter()), key_(key), members_(std::move(members)), - is_const_(is_const) + is_const_(is_const), + is_declare_(is_declare) { if (is_static) { AddModifier(ModifierFlags::STATIC); } + if (is_declare) { + AddModifier(ModifierFlags::DECLARE); + } } bool IsScopeBearer() const override @@ -88,6 +92,11 @@ public: return is_const_; } + bool IsDeclare() const + { + return is_declare_; + } + const ArenaVector &Decorators() const { return decorators_; @@ -131,6 +140,7 @@ private: ArenaVector members_; util::StringView internal_name_; bool is_const_; + bool is_declare_; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/lexer/scripts/keywords.yaml b/ets2panda/lexer/scripts/keywords.yaml index 690264b098..287aa83198 100644 --- a/ets2panda/lexer/scripts/keywords.yaml +++ b/ets2panda/lexer/scripts/keywords.yaml @@ -296,6 +296,7 @@ keywords: - name: 'namespace' token: KEYW_NAMESPACE + keyword: [ets] keyword_like: [as, ts] - name: 'native' diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 38d474a2fc..150e17f0e7 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -778,6 +778,8 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorRewind(saved_pos); @@ -1576,6 +1580,9 @@ ir::AstNode *ETSParser::ParseClassElement([[maybe_unused]] const ArenaVectorGetToken().Type(); + if (type == lexer::TokenType::KEYW_FUNCTION || type == lexer::TokenType::KEYW_LET || + type == lexer::TokenType::KEYW_CONST) { + Lexer()->NextToken(); + } + } + + auto *member_name = ExpectIdentifier(); if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { @@ -1726,6 +1741,15 @@ ir::Statement *ETSParser::ParseTypeDeclaration(bool allow_static) case lexer::TokenType::KEYW_INTERFACE: { return ParseInterfaceDeclaration(false); } + case lexer::TokenType::KEYW_NAMESPACE: { + if (!InAmbientContext()) { + ThrowSyntaxError("Namespaces are declare only"); + } + GetContext().Status() |= ParserStatus::IN_NAMESPACE; + auto *ns = ParseClassDeclaration(modifiers, ir::ModifierFlags::STATIC); + GetContext().Status() &= ~ParserStatus::IN_NAMESPACE; + return ns; + } case lexer::TokenType::KEYW_CLASS: { return ParseClassDeclaration(modifiers); } @@ -4295,7 +4319,7 @@ ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, co } auto *const enum_declaration = - AllocNode(Allocator(), key, std::move(members), is_const, is_static); + AllocNode(Allocator(), key, std::move(members), is_const, is_static, InAmbientContext()); enum_declaration->SetRange({enum_start, Lexer()->GetToken().End()}); Lexer()->NextToken(); // eat '}' @@ -4691,6 +4715,7 @@ void ETSParser::CheckDeclare() case lexer::TokenType::KEYW_CLASS: case lexer::TokenType::KEYW_NAMESPACE: case lexer::TokenType::KEYW_ENUM: + case lexer::TokenType::KEYW_TYPE: case lexer::TokenType::KEYW_ABSTRACT: case lexer::TokenType::KEYW_INTERFACE: { return; diff --git a/ets2panda/parser/context/parserContext.h b/ets2panda/parser/context/parserContext.h index 2751b480be..631188ce5d 100644 --- a/ets2panda/parser/context/parserContext.h +++ b/ets2panda/parser/context/parserContext.h @@ -26,7 +26,7 @@ namespace panda::es2panda::parser { class Program; -enum class ParserStatus : uint32_t { +enum class ParserStatus : uint64_t { NO_OPTS = 0U, DIRECT_EVAL = 1U << 0U, @@ -65,6 +65,7 @@ enum class ParserStatus : uint32_t { IN_DEFAULT_IMPORTS = 1U << 29U, IN_EXTENSION_FUNCTION = 1U << 30U, FUNCTION_HAS_RETURN_STATEMENT = 1U << 31U, + IN_NAMESPACE = 1ULL << 32ULL, }; DEFINE_BITOPS(ParserStatus) diff --git a/ets2panda/test/parser/ets/declare_enum-expected.txt b/ets2panda/test/parser/ets/declare_enum-expected.txt new file mode 100644 index 0000000000..99104b7475 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_enum-expected.txt @@ -0,0 +1,268 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSEnumDeclaration", + "id": { + "type": "Identifier", + "name": "Enum", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + "members": [ + { + "type": "TSEnumMember", + "id": { + "type": "Identifier", + "name": "AAA", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + { + "type": "TSEnumMember", + "id": { + "type": "Identifier", + "name": "BBB", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 8 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 8 + } + } + } + ], + "const": false, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 19, + "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": 20, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/declare_enum.ets b/ets2panda/test/parser/ets/declare_enum.ets new file mode 100644 index 0000000000..44b78d6bf6 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_enum.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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. + */ + +declare enum Enum { + AAA, + BBB +} diff --git a/ets2panda/test/parser/ets/declare_namespace-expected.txt b/ets2panda/test/parser/ets/declare_namespace-expected.txt new file mode 100644 index 0000000000..bd586f4105 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_namespace-expected.txt @@ -0,0 +1,290 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "name", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "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": 16, + "column": 26 + }, + "end": { + "line": 16, + "column": 26 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 24 + }, + "end": { + "line": 16, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 26 + } + } + }, + { + "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": 17, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/declare_namespace.ets b/ets2panda/test/parser/ets/declare_namespace.ets new file mode 100644 index 0000000000..47849cb880 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_namespace.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +declare namespace name {} diff --git a/ets2panda/test/parser/ets/declare_namespace_2-expected.txt b/ets2panda/test/parser/ets/declare_namespace_2-expected.txt new file mode 100644 index 0000000000..ef0198eda6 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_namespace_2-expected.txt @@ -0,0 +1,411 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "NAME", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + { + "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": 24 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 18, + "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": 19, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/declare_namespace_2.ets b/ets2panda/test/parser/ets/declare_namespace_2.ets new file mode 100644 index 0000000000..fb6d637df3 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_namespace_2.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022 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. + */ + +declare namespace NAME { + foo():void; +} diff --git a/ets2panda/test/parser/ets/declare_type-expected.txt b/ets2panda/test/parser/ets/declare_type-expected.txt new file mode 100644 index 0000000000..0259aa62df --- /dev/null +++ b/ets2panda/test/parser/ets/declare_type-expected.txt @@ -0,0 +1,194 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "t", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 15 + } + } + }, + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + { + "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": 17, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/declare_type.ets b/ets2panda/test/parser/ets/declare_type.ets new file mode 100644 index 0000000000..0ee4caa1c1 --- /dev/null +++ b/ets2panda/test/parser/ets/declare_type.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +declare type t = int; -- Gitee From 2ace3bb15b4e7f3556a9f1af4926316f0729b8c4 Mon Sep 17 00:00:00 2001 From: Redkin_Mikhail Date: Mon, 25 Dec 2023 06:17:20 +0300 Subject: [PATCH 11/24] Title: Fix varargs in new class instance expressions Issue: #14731 Generic varargs with wmpty call list Testing: All required pre-merge tests passed. Results are available in the ggwatcher Signed-off-by: Redkin_Mikhail --- ets2panda/compiler/core/ETSCompiler.cpp | 27 + .../ir/ets/etsNewClassInstanceExpression.h | 7 +- .../ets/class_def_varargs_1-expected.txt | 916 ++++++++++++++++++ .../test/compiler/ets/class_def_varargs_1.ets | 22 + .../ets/class_def_varargs_2-expected.txt | 721 ++++++++++++++ .../test/compiler/ets/class_def_varargs_2.ets | 23 + 6 files changed, 1715 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/compiler/ets/class_def_varargs_1-expected.txt create mode 100644 ets2panda/test/compiler/ets/class_def_varargs_1.ets create mode 100644 ets2panda/test/compiler/ets/class_def_varargs_2-expected.txt create mode 100644 ets2panda/test/compiler/ets/class_def_varargs_2.ets diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index eeea65e26a..3fad191fc2 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -290,6 +290,32 @@ static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, etsg->CallDynamic(node, obj_reg, qname_reg, signature, arguments); } +static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::ETSNewClassInstanceExpression *expr) +{ + if (expr->GetSignature()->RestVar() != nullptr) { + std::size_t const argument_count = expr->GetArguments().size(); + std::size_t const parameter_count = expr->GetSignature()->MinArgCount(); + ASSERT(argument_count >= parameter_count); + + auto &arguments = const_cast &>(expr->GetArguments()); + std::size_t i = parameter_count; + + if (i < argument_count && expr->GetArguments()[i]->IsSpreadElement()) { + arguments[i] = expr->GetArguments()[i]->AsSpreadElement()->Argument(); + } else { + ArenaVector elements(checker->Allocator()->Adapter()); + for (; i < argument_count; ++i) { + elements.emplace_back(expr->GetArguments()[i]); + } + auto *array_expression = checker->AllocNode(std::move(elements), checker->Allocator()); + array_expression->SetParent(const_cast(expr)); + array_expression->SetTsType(expr->GetSignature()->RestVar()->TsType()); + arguments.erase(expr->GetArguments().begin() + parameter_count, expr->GetArguments().end()); + arguments.emplace_back(array_expression); + } + } +} + void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const { ETSGen *etsg = GetETSGen(); @@ -298,6 +324,7 @@ void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const auto *name = expr->GetTypeRef()->AsETSTypeReference()->Part()->Name(); CreateDynamicObject(expr, etsg, obj_reg, name, expr->signature_, expr->GetArguments()); } else { + ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); etsg->InitObject(expr, expr->signature_, expr->GetArguments()); } diff --git a/ets2panda/ir/ets/etsNewClassInstanceExpression.h b/ets2panda/ir/ets/etsNewClassInstanceExpression.h index 031531ca74..6f4dd092a4 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.h @@ -70,11 +70,16 @@ public: return type_reference_; } - [[nodiscard]] ArenaVector GetArguments() const noexcept + [[nodiscard]] const ArenaVector &GetArguments() const noexcept { return arguments_; } + [[nodiscard]] checker::Signature *GetSignature() const noexcept + { + return signature_; + } + void SetSignature(checker::Signature *const signature) noexcept { signature_ = signature; diff --git a/ets2panda/test/compiler/ets/class_def_varargs_1-expected.txt b/ets2panda/test/compiler/ets/class_def_varargs_1-expected.txt new file mode 100644 index 0000000000..a040ec6969 --- /dev/null +++ b/ets2panda/test/compiler/ets/class_def_varargs_1-expected.txt @@ -0,0 +1,916 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "Foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 10 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 16, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 16, + "column": 13 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "accessibility": "public", + "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": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "o", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 20 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 23 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 23 + }, + "end": { + "line": 17, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 23 + }, + "end": { + "line": 17, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 27 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "of", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "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": "of", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "vl", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 21 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 18, + "column": 25 + }, + "end": { + "line": 18, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 30 + }, + "end": { + "line": 18, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 31 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Foo", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 34 + }, + "end": { + "line": 18, + "column": 37 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 38 + }, + "end": { + "line": 18, + "column": 39 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 38 + }, + "end": { + "line": 18, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 38 + }, + "end": { + "line": 18, + "column": 40 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 37 + }, + "end": { + "line": 18, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 34 + }, + "end": { + "line": 18, + "column": 42 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 34 + }, + "end": { + "line": 18, + "column": 42 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 18, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 18, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "r", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 19, + "column": 16 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Foo", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 23 + }, + "end": { + "line": 19, + "column": 26 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 29 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 26 + }, + "end": { + "line": 19, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 23 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 23 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 19, + "column": 19 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 20, + "column": 15 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "Identifier", + "name": "r", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 16 + }, + "end": { + "line": 20, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 41 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 21, + "column": 6 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 22, + "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": 23, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/class_def_varargs_1.ets b/ets2panda/test/compiler/ets/class_def_varargs_1.ets new file mode 100644 index 0000000000..1bfff16890 --- /dev/null +++ b/ets2panda/test/compiler/ets/class_def_varargs_1.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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 Foo { + constructor(...o: T[]) {} + static of(...vl: int[]) : Foo { + const r = new Foo() + return r + } +} diff --git a/ets2panda/test/compiler/ets/class_def_varargs_2-expected.txt b/ets2panda/test/compiler/ets/class_def_varargs_2-expected.txt new file mode 100644 index 0000000000..6cdfc1a60f --- /dev/null +++ b/ets2panda/test/compiler/ets/class_def_varargs_2-expected.txt @@ -0,0 +1,721 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "accessibility": "public", + "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": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "items", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 21 + }, + "end": { + "line": 17, + "column": 26 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Object", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 36 + }, + "end": { + "line": 17, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 37 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 17, + "column": 37 + }, + "end": { + "line": 17, + "column": 39 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 39 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 39 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 39 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 18, + "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 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "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": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 10 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 17 + }, + "end": { + "line": 21, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 17 + }, + "end": { + "line": 21, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 17 + }, + "end": { + "line": 21, + "column": 19 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 21, + "column": 13 + }, + "end": { + "line": 21, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 19 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 19 + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + "right": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 13 + }, + "end": { + "line": 22, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 13 + }, + "end": { + "line": 22, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 13 + }, + "end": { + "line": 22, + "column": 15 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 15 + }, + "end": { + "line": 22, + "column": 16 + } + } + }, + { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 22, + "column": 18 + }, + "end": { + "line": 22, + "column": 19 + } + } + }, + { + "type": "NumberLiteral", + "value": 3, + "loc": { + "start": { + "line": 22, + "column": 21 + }, + "end": { + "line": 22, + "column": 22 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 23, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 23, + "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": 24, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/class_def_varargs_2.ets b/ets2panda/test/compiler/ets/class_def_varargs_2.ets new file mode 100644 index 0000000000..46f74c9970 --- /dev/null +++ b/ets2panda/test/compiler/ets/class_def_varargs_2.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 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 { + constructor(... items :Object[]){} +} + +function main() { + let a = new A; + a = new A(1, 2, 3) +} -- Gitee From 182e997bb86a654de73ddb8cfbe44b1d0253fab3 Mon Sep 17 00:00:00 2001 From: Vadim Lomovtsev Date: Tue, 7 Nov 2023 17:52:24 +0300 Subject: [PATCH 12/24] Implement I8EM2T ArkTS: struct translation Description: The struct keyword is directly expanded to class ComponentExample extends CommonStruct0. Hardcoded. This allows much less flexibility in case we want to change this expansion later. Follow construction: struct ComponentExample { } Will be expanded as: final class ComponentExample extends CommonStruct0 { } Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8EM2T Testing: File ets2panda/test/compiler/ets/StructTest1.ets contains test Signed-off-by: Vadim Lomovtsev Signed-off-by: Stanislav Malishevskiy --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + .../compiler/lowering/ets/structLowering.cpp | 113 ++ .../compiler/lowering/ets/structLowering.h | 31 + ets2panda/compiler/lowering/phase.cpp | 83 +- .../compiler/ets/StructTest1-expected.txt | 1216 ++++++++++++++ ets2panda/test/compiler/ets/StructTest1.ets | 29 + .../compiler/ets/StructTest2-expected.txt | 1413 +++++++++++++++++ ets2panda/test/compiler/ets/StructTest2.ets | 29 + .../check_exported_default_class-expected.txt | 4 +- .../check_exported_default_class.ets | 2 +- .../ets-runtime/ets-runtime-ignored.txt | 7 + .../test-lists/parser/parser-ets-ignored.txt | 13 +- 13 files changed, 2908 insertions(+), 34 deletions(-) create mode 100644 ets2panda/compiler/lowering/ets/structLowering.cpp create mode 100644 ets2panda/compiler/lowering/ets/structLowering.h create mode 100644 ets2panda/test/compiler/ets/StructTest1-expected.txt create mode 100644 ets2panda/test/compiler/ets/StructTest1.ets create mode 100644 ets2panda/test/compiler/ets/StructTest2-expected.txt create mode 100644 ets2panda/test/compiler/ets/StructTest2.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 30bba267c9..cd0161e3fb 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -162,6 +162,7 @@ libes2panda_sources = [ "compiler/lowering/ets/objectIndexAccess.cpp", "compiler/lowering/ets/opAssignment.cpp", "compiler/lowering/ets/promiseVoid.cpp", + "compiler/lowering/ets/structLowering.cpp", "compiler/lowering/ets/tupleLowering.cpp", "compiler/lowering/ets/unionLowering.cpp", "compiler/lowering/phase.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index a5c6d1294c..7dcb21989c 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -159,6 +159,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/unionLowering.cpp compiler/lowering/ets/expandBrackets.cpp compiler/lowering/ets/promiseVoid.cpp + compiler/lowering/ets/structLowering.cpp ir/astDump.cpp ir/srcDump.cpp ir/astNode.cpp diff --git a/ets2panda/compiler/lowering/ets/structLowering.cpp b/ets2panda/compiler/lowering/ets/structLowering.cpp new file mode 100644 index 0000000000..e1100319b4 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/structLowering.cpp @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2023 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. + */ + +#include "structLowering.h" +#include "checker/ETSchecker.h" +#include "compiler/core/compilerContext.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classProperty.h" +#include "ir/astNode.h" +#include "ir/expression.h" +#include "ir/opaqueTypeNode.h" +#include "ir/expressions/identifier.h" +#include "ir/statements/classDeclaration.h" +#include "ir/ts/tsAsExpression.h" +#include "type_helper.h" + +namespace panda::es2panda::compiler { + +const char *const STRUCT_CLASS_NAME = "CommonStruct0"; + +std::string_view StructLowering::Name() +{ + static std::string const NAME = "struct-class-extention"; + return NAME; +} + +ir::ETSTypeReference *CreateStructTypeReference(checker::ETSChecker *checker, + ir::ETSStructDeclaration *ets_struc_declaration) +{ + auto *allocator = checker->Allocator(); + + ArenaVector params(allocator->Adapter()); + + ir::TSTypeParameterInstantiation *type_param_self_inst = nullptr; + + if (ets_struc_declaration->Definition()->TypeParams() != nullptr && + !ets_struc_declaration->Definition()->TypeParams()->Params().empty()) { + ArenaVector self_params(allocator->Adapter()); + ir::ETSTypeReferencePart *reference_part = nullptr; + + for (const auto ¶m : ets_struc_declaration->Definition()->TypeParams()->Params()) { + auto *ident_ref = checker->AllocNode(param->AsTSTypeParameter()->Name()->Name(), allocator); + ident_ref->AsIdentifier()->SetReference(); + + reference_part = checker->AllocNode(ident_ref, nullptr, nullptr); + + auto *type_reference = checker->AllocNode(reference_part); + + self_params.push_back(type_reference); + } + + type_param_self_inst = checker->AllocNode(std::move(self_params)); + } + + auto *ident_self_ref = + checker->AllocNode(ets_struc_declaration->Definition()->Ident()->Name(), allocator); + ident_self_ref->AsIdentifier()->SetReference(); + + auto *reference_self_part = + checker->AllocNode(ident_self_ref, type_param_self_inst, nullptr); + + auto *self_type_reference = checker->AllocNode(reference_self_part); + + params.push_back(self_type_reference); + + auto *type_param_inst = checker->AllocNode(std::move(params)); + + auto *ident_ref = checker->AllocNode(util::StringView(STRUCT_CLASS_NAME), allocator); + ident_ref->AsIdentifier()->SetReference(); + auto *reference_part = checker->AllocNode(ident_ref, type_param_inst, nullptr); + + auto *type_reference = checker->AllocNode(reference_part); + + return type_reference; +} + +bool StructLowering::Perform(public_lib::Context *ctx, parser::Program *program) +{ + for (auto &[_, ext_programs] : program->ExternalSources()) { + (void)_; + for (auto *ext_prog : ext_programs) { + Perform(ctx, ext_prog); + } + } + + checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + + program->Ast()->TransformChildrenRecursively([checker](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsETSStructDeclaration()) { + auto *type_ref = CreateStructTypeReference(checker, ast->AsETSStructDeclaration()); + ast->AsETSStructDeclaration()->Definition()->SetSuper(type_ref); + ast->AsETSStructDeclaration()->Definition()->AddModifier(ir::ModifierFlags::FINAL); + } + + return ast; + }); + + return true; +} + +} // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/structLowering.h b/ets2panda/compiler/lowering/ets/structLowering.h new file mode 100644 index 0000000000..3513322a03 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/structLowering.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2023 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_STRUCT_LOWERING_H +#define ES2PANDA_COMPILER_LOWERING_STRUCT_LOWERING_H + +#include "compiler/lowering/phase.h" + +namespace panda::es2panda::compiler { + +class StructLowering : public Phase { +public: + std::string_view Name() override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; +}; + +} // namespace panda::es2panda::compiler + +#endif // ES2PANDA_COMPILER_LOWERING_STRUCT_LOWERING_H diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index b64e813bc5..6231339684 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -29,6 +29,7 @@ #include "compiler/lowering/ets/opAssignment.h" #include "compiler/lowering/ets/tupleLowering.h" #include "compiler/lowering/ets/unionLowering.h" +#include "compiler/lowering/ets/structLowering.h" #include "public/es2panda_lib.h" #include "compiler/lowering/ets/promiseVoid.h" @@ -52,52 +53,74 @@ static TupleLowering TUPLE_LOWERING; // Can be only applied after checking phas static UnionLowering UNION_LOWERING; static ExpandBracketsPhase EXPAND_BRACKETS_PHASE; static PromiseVoidLowering PROMISE_VOID_LOWERING; +static StructLowering STRUCT_LOWERING; static PluginPhase PLUGINS_AFTER_PARSE {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; static PluginPhase PLUGINS_AFTER_CHECK {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase PLUGINS_AFTER_LOWERINGS {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; -std::vector GetPhaseList(ScriptExtension ext) +// clang-format off +std::vector GetETSPhaseList() { static ScopesInitPhaseETS scopes_phase_ets; + return { + &scopes_phase_ets, + &PLUGINS_AFTER_PARSE, + &PROMISE_VOID_LOWERING, + &STRUCT_LOWERING, + &LAMBDA_LOWERING, + &INTERFACE_PROP_DECL_PHASE, + &CHECKER_PHASE, + &PLUGINS_AFTER_CHECK, + &GENERATE_TS_DECLARATIONS_PHASE, + &OP_ASSIGNMENT_LOWERING, + &OBJECT_INDEX_LOWERING, + &TUPLE_LOWERING, + &UNION_LOWERING, + &EXPAND_BRACKETS_PHASE, + &PLUGINS_AFTER_LOWERINGS, + }; +} +// clang-format on + +std::vector GetASPhaseList() +{ static ScopesInitPhaseAS scopes_phase_as; + return { + &scopes_phase_as, + &CHECKER_PHASE, + }; +} + +std::vector GetTSPhaseList() +{ static ScopesInitPhaseTs scopes_phase_ts; + return { + &scopes_phase_ts, + &CHECKER_PHASE, + }; +} + +std::vector GetJSPhaseList() +{ static ScopesInitPhaseJs scopes_phase_js; + return { + &scopes_phase_js, + &CHECKER_PHASE, + }; +} +std::vector GetPhaseList(ScriptExtension ext) +{ switch (ext) { case ScriptExtension::ETS: - return { - &scopes_phase_ets, - &PLUGINS_AFTER_PARSE, - &PROMISE_VOID_LOWERING, - &LAMBDA_LOWERING, - &INTERFACE_PROP_DECL_PHASE, - &CHECKER_PHASE, - &PLUGINS_AFTER_CHECK, - &GENERATE_TS_DECLARATIONS_PHASE, - &OP_ASSIGNMENT_LOWERING, - &OBJECT_INDEX_LOWERING, - &TUPLE_LOWERING, - &UNION_LOWERING, - &EXPAND_BRACKETS_PHASE, - &PLUGINS_AFTER_LOWERINGS, - }; - + return GetETSPhaseList(); case ScriptExtension::AS: - return std::vector { - &scopes_phase_as, - &CHECKER_PHASE, - }; + return GetASPhaseList(); case ScriptExtension::TS: - return std::vector { - &scopes_phase_ts, - &CHECKER_PHASE, - }; + return GetTSPhaseList(); case ScriptExtension::JS: - return std::vector { - &scopes_phase_js, - &CHECKER_PHASE, - }; + return GetJSPhaseList(); default: UNREACHABLE(); } diff --git a/ets2panda/test/compiler/ets/StructTest1-expected.txt b/ets2panda/test/compiler/ets/StructTest1-expected.txt new file mode 100644 index 0000000000..50b26e4766 --- /dev/null +++ b/ets2panda/test/compiler/ets/StructTest1-expected.txt @@ -0,0 +1,1216 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "CommonStruct0", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 20 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "K", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 23 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "value": { + "type": "NumberLiteral", + "value": 5, + "loc": { + "start": { + "line": 17, + "column": 20 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 19 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "GetF", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "GetF", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "property": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 22 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 10 + }, + "end": { + "line": 19, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 24 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + { + "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": 21, + "column": 2 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 24 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + { + "type": "ETSStructDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 8 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + "superClass": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CommonStruct0", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "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": 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 + } + } + }, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 7 + } + } + }, + "value": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 24, + "column": 15 + }, + "end": { + "line": 24, + "column": 16 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 16 + } + } + }, + { + "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": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 25, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 25, + "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 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 10 + }, + "end": { + "line": 27, + "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": 27, + "column": 10 + }, + "end": { + "line": 27, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 15 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 8 + }, + "end": { + "line": 28, + "column": 9 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 20 + }, + "end": { + "line": 28, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 20 + }, + "end": { + "line": 28, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 20 + }, + "end": { + "line": 28, + "column": 23 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 28, + "column": 16 + }, + "end": { + "line": 28, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 8 + }, + "end": { + "line": 28, + "column": 23 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 28, + "column": 4 + }, + "end": { + "line": 28, + "column": 23 + } + } + } + ], + "loc": { + "start": { + "line": 27, + "column": 23 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 14 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 14 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 1 + }, + "end": { + "line": 29, + "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": 29, + "column": 2 + } + } +} diff --git a/ets2panda/test/compiler/ets/StructTest1.ets b/ets2panda/test/compiler/ets/StructTest1.ets new file mode 100644 index 0000000000..711e89a2f6 --- /dev/null +++ b/ets2panda/test/compiler/ets/StructTest1.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021-2023 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 CommonStruct0 { + public f: Int = 5; + public GetF() : Int { + return this.f; + } +} + +struct CE { + x: Int = 1; +} + +function main(): void { + let a: CE = new CE; +} \ No newline at end of file diff --git a/ets2panda/test/compiler/ets/StructTest2-expected.txt b/ets2panda/test/compiler/ets/StructTest2-expected.txt new file mode 100644 index 0000000000..5e9b0511ba --- /dev/null +++ b/ets2panda/test/compiler/ets/StructTest2-expected.txt @@ -0,0 +1,1413 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "CommonStruct0", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 20 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "K", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 23 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "value": { + "type": "NumberLiteral", + "value": 5, + "loc": { + "start": { + "line": 17, + "column": 20 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 19 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 21 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "GetF", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "GetF", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 21 + } + } + }, + "property": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 22 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 10 + }, + "end": { + "line": 19, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 24 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 15 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + } + }, + { + "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": 21, + "column": 2 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 24 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + { + "type": "ETSStructDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 8 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "K", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 23, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 23, + "column": 13 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 23, + "column": 13 + } + } + }, + "superClass": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CommonStruct0", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "K", + "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": 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": 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 + } + } + }, + "implements": [], + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 7 + } + } + }, + "accessibility": "public", + "static": false, + "readonly": false, + "declare": false, + "optional": false, + "computed": false, + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "K", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 11 + } + } + }, + "definite": false, + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 11 + } + } + }, + { + "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": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 14 + }, + "end": { + "line": 25, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 25, + "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 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 10 + }, + "end": { + "line": 27, + "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": 27, + "column": 10 + }, + "end": { + "line": 27, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 13 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 14 + }, + "end": { + "line": 28, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 14 + }, + "end": { + "line": 28, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 14 + }, + "end": { + "line": 28, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 28, + "column": 13 + }, + "end": { + "line": 28, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 11 + }, + "end": { + "line": 28, + "column": 20 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 8 + }, + "end": { + "line": 28, + "column": 9 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "CE", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 25 + }, + "end": { + "line": 28, + "column": 27 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 32 + } + } + } + ], + "loc": { + "start": { + "line": 28, + "column": 27 + }, + "end": { + "line": 28, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 25 + }, + "end": { + "line": 28, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 25 + }, + "end": { + "line": 28, + "column": 33 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 28, + "column": 21 + }, + "end": { + "line": 28, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 8 + }, + "end": { + "line": 28, + "column": 35 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 28, + "column": 4 + }, + "end": { + "line": 28, + "column": 35 + } + } + } + ], + "loc": { + "start": { + "line": 27, + "column": 23 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 14 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 14 + }, + "end": { + "line": 29, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 1 + }, + "end": { + "line": 29, + "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": 29, + "column": 2 + } + } +} diff --git a/ets2panda/test/compiler/ets/StructTest2.ets b/ets2panda/test/compiler/ets/StructTest2.ets new file mode 100644 index 0000000000..88f388511e --- /dev/null +++ b/ets2panda/test/compiler/ets/StructTest2.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021-2023 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 CommonStruct0 { + public f: Int = 5; + public GetF() : Int { + return this.f; + } +} + +struct CE { + x: K; +} + +function main(): void { + let a: CE = new CE(); +} \ No newline at end of file diff --git a/ets2panda/test/parser/ets/import_tests/check_exported_default_class-expected.txt b/ets2panda/test/parser/ets/import_tests/check_exported_default_class-expected.txt index d13c5c166f..b91e824038 100644 --- a/ets2panda/test/parser/ets/import_tests/check_exported_default_class-expected.txt +++ b/ets2panda/test/parser/ets/import_tests/check_exported_default_class-expected.txt @@ -13,7 +13,7 @@ }, "end": { "line": 16, - "column": 76 + "column": 75 } } }, @@ -54,7 +54,7 @@ }, "end": { "line": 16, - "column": 77 + "column": 76 } } }, diff --git a/ets2panda/test/parser/ets/import_tests/check_exported_default_class.ets b/ets2panda/test/parser/ets/import_tests/check_exported_default_class.ets index 03c02fe1ec..836eeba03d 100644 --- a/ets2panda/test/parser/ets/import_tests/check_exported_default_class.ets +++ b/ets2panda/test/parser/ets/import_tests/check_exported_default_class.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import ExportDefaultClass from "import_tests/modules/struct_default_module"; +import ExportDefaultClass from "import_tests/modules/class_default_module"; function main() { let test_class: ExportDefaultClass = new ExportDefaultClass(); diff --git a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt index e6e752e1bf..b4b2ab58ce 100644 --- a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt +++ b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored.txt @@ -37,3 +37,10 @@ notNullMultidimensionalArray.ets # ignored until verifier can't handle if a field name can be static and non-static at the same time class-fields-same-name.ets + +# Disabled temporarily #I8EM2T implementation struct directly expanded to class +struct-identifier.ets +struct-init.ets +struct-init2.ets +struct_implements.ets +top_level_03.ets diff --git a/ets2panda/test/test-lists/parser/parser-ets-ignored.txt b/ets2panda/test/test-lists/parser/parser-ets-ignored.txt index 5ca2201c3d..de27323be4 100644 --- a/ets2panda/test/test-lists/parser/parser-ets-ignored.txt +++ b/ets2panda/test/test-lists/parser/parser-ets-ignored.txt @@ -1,2 +1,13 @@ parser/ets/test-type-alias-call7.ets -parser/ets/test-type-alias-call8.ets \ No newline at end of file +parser/ets/test-type-alias-call8.ets + +# Disabled temporarily #I8EM2T implementation struct directly expanded to class +parser/ets/struct_init.ets +parser/ets/struct_static_initializer.ets +parser/ets/struct_identifier.ets +parser/ets/struct_invalid_extends1.ets +parser/ets/struct_templete.ets +parser/ets/import_tests/modules/struct_module.ets +parser/ets/import_tests/check_exported_default_struct.ets +parser/ets/import_tests/modules/struct_default_module.ets +parser/ets/import_tests/check_exported_struct.ets -- Gitee From b2d5d9aceaf169b4f6079c22a7e4661cbbc46106 Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Tue, 26 Dec 2023 17:55:14 +0300 Subject: [PATCH 13/24] Title: Fix the build static invoke Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8RLJQ Description: Fix the build static invoke for template instantiate method Test: ${ARK_SOURCE_DIR}/tests/tests-u-runner/runner.sh ${ARK_SOURCE_DIR} --ets-run time --build-dir="${ARK_BUILD_DIR}" --heap-verifier="fail_on_verification:pre:into:b efore_g1_concurrent:post" --timeout=30 --force-generate --test-file generic-function1.ets Signed-off-by: Anna Antipina --- ets2panda/checker/ets/helpers.cpp | 16 +++++++- .../test/runtime/ets/generic-function1.ets | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/runtime/ets/generic-function1.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 35d2b15156..f19c280b50 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2618,6 +2618,19 @@ void ETSChecker::ModifyPreferredType(ir::ArrayExpression *const array_expr, Type } } +std::string GenerateImplicitInstantiateArg(varbinder::LocalVariable *instantiate_method, const std::string &class_name) +{ + auto call_signatures = instantiate_method->TsType()->AsETSFunctionType()->CallSignatures(); + ASSERT(!call_signatures.empty()); + auto method_owner = std::string(call_signatures[0]->Owner()->Name()); + std::string implicit_instantiate_argument = "()=>{return new " + class_name + "()"; + if (method_owner != class_name) { + implicit_instantiate_argument.append(" as " + method_owner); + } + implicit_instantiate_argument.append("}"); + return implicit_instantiate_argument; +} + bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolved_type) { ASSERT(ident->Parent()->IsCallExpression()); @@ -2661,7 +2674,8 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons call_expr->SetCallee(transformed_callee); if (instantiate_method != nullptr) { - std::string implicit_instantiate_argument = "()=>{return new " + std::string(class_name) + "()}"; + std::string implicit_instantiate_argument = + GenerateImplicitInstantiateArg(instantiate_method, std::string(class_name)); parser::Program program(Allocator(), VarBinder()); es2panda::CompilerOptions options; diff --git a/ets2panda/test/runtime/ets/generic-function1.ets b/ets2panda/test/runtime/ets/generic-function1.ets new file mode 100644 index 0000000000..dec1e8fb55 --- /dev/null +++ b/ets2panda/test/runtime/ets/generic-function1.ets @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 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 { + static instantiate(factory: () => T, content: () => void): T { + const instance = factory() + instance.__initializeStruct() + content() + return instance + } + __initializeStruct(): A { + return this + } +} + +class B extends A { + constructor() {} + override __initializeStruct(): A { + return this + } +} + +export function main(): int { + console.println("Start") + + B(){} + + return 0; +} -- Gitee From f782f6a1c60caca39836274dc4523d3025a8c914 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Fri, 13 Oct 2023 16:46:47 +0300 Subject: [PATCH 14/24] Add bigint support Adds compiler support for BigInt objects and literals. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8GCKE Testing: Runtime Tests: see `ets2panda/test/runtime/ets/BigInt.ets` Ets Func Tests: see `static_core/plugins/ets/tests/ets_func_tests/spec/bigint` Signed-off-by: Konstantin Kuznetsov --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ETSAnalyzer.cpp | 43 +- ets2panda/checker/ETSchecker.cpp | 10 + ets2panda/checker/ETSchecker.h | 7 + ets2panda/checker/ets/arithmetic.cpp | 232 +++++-- ets2panda/checker/ets/helpers.cpp | 2 +- ets2panda/checker/ets/typeCreation.cpp | 213 +++--- ets2panda/checker/types/ets/etsBigIntType.cpp | 44 ++ ets2panda/checker/types/ets/etsBigIntType.h | 66 ++ ets2panda/checker/types/ets/etsObjectType.h | 3 +- ets2panda/checker/types/ets/types.h | 1 + ets2panda/checker/types/globalTypesHolder.cpp | 12 + ets2panda/checker/types/globalTypesHolder.h | 4 + ets2panda/checker/types/type.cpp | 5 + ets2panda/checker/types/type.h | 8 + ets2panda/compiler/base/condition.cpp | 52 ++ ets2panda/compiler/base/condition.h | 1 + ets2panda/compiler/core/ETSCompiler.cpp | 100 ++- ets2panda/compiler/core/ETSGen.cpp | 80 ++- ets2panda/compiler/core/ETSGen.h | 12 + ets2panda/compiler/scripts/signatures.yaml | 129 ++++ .../ir/expressions/literals/bigIntLiteral.cpp | 1 + .../ir/expressions/literals/bigIntLiteral.h | 6 +- ets2panda/ir/expressions/unaryExpression.cpp | 1 + ets2panda/lexer/ETSLexer.h | 14 + ets2panda/test/runtime/ets/BigInt.ets | 643 ++++++++++++++++++ 27 files changed, 1523 insertions(+), 168 deletions(-) create mode 100644 ets2panda/checker/types/ets/etsBigIntType.cpp create mode 100644 ets2panda/checker/types/ets/etsBigIntType.h create mode 100644 ets2panda/test/runtime/ets/BigInt.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index cd0161e3fb..0e6805a900 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -65,6 +65,7 @@ libes2panda_sources = [ "checker/types/ets/doubleType.cpp", "checker/types/ets/etsArrayType.cpp", "checker/types/ets/etsAsyncFuncReturnType.cpp", + "checker/types/ets/etsBigIntType.cpp", "checker/types/ets/etsBooleanType.cpp", "checker/types/ets/etsDynamicType.cpp", "checker/types/ets/etsEnumType.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 7dcb21989c..1313e981c0 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -396,6 +396,7 @@ set(ES2PANDA_LIB_SRC checker/types/ets/etsFunctionType.cpp checker/types/ets/etsObjectType.cpp checker/types/ets/etsStringType.cpp + checker/types/ets/etsBigIntType.cpp checker/types/ets/etsTupleType.cpp checker/types/ets/etsTypeParameter.cpp checker/types/ets/etsUnionType.cpp diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index b671d228cf..3b04d8f582 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1541,6 +1541,38 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const auto unboxed_operand_type = is_cond_expr ? checker->ETSBuiltinTypeAsConditionalType(arg_type) : checker->ETSBuiltinTypeAsPrimitiveType(arg_type); + if (arg_type != nullptr && arg_type->IsETSBigIntType() && + arg_type->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: { + checker::Type *type = checker->CreateETSBigIntLiteralType(arg_type->AsETSBigIntType()->GetValue()); + + // We do not need this const anymore as we are negating the bigint object in runtime + type->RemoveTypeFlag(checker::TypeFlag::CONSTANT); + expr->argument_->SetTsType(type); + expr->SetTsType(type); + return expr->TsType(); + } + default: + // Handled below + // NOTE(kkonsw): handle other unary operators for bigint literals + break; + } + } + + if (arg_type != nullptr && arg_type->IsETSBigIntType()) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_TILDE: { + expr->SetTsType(arg_type); + return expr->TsType(); + } + default: + break; + } + } + switch (expr->OperatorType()) { case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_PLUS: { @@ -1606,7 +1638,7 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const } } - if (arg_type->IsETSObjectType() && (unboxed_operand_type != nullptr) && + if ((arg_type != nullptr) && arg_type->IsETSObjectType() && (unboxed_operand_type != nullptr) && unboxed_operand_type->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxed_operand_type)); } @@ -1636,6 +1668,11 @@ checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const } } + if (operand_type->IsETSBigIntType()) { + expr->SetTsType(operand_type); + return expr->TsType(); + } + auto unboxed_type = checker->ETSBuiltinTypeAsPrimitiveType(operand_type); if (unboxed_type == nullptr || !unboxed_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", @@ -1658,7 +1695,9 @@ checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::YieldExpression *expr) co // compile methods for LITERAL EXPRESSIONS in alphabetical order checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::BigIntLiteral *expr) const { - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + expr->SetTsType(checker->CreateETSBigIntLiteralType(expr->Str())); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 868b01a6b5..08adfd216f 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -226,6 +226,11 @@ Type *ETSChecker::GlobalETSStringLiteralType() const return GetGlobalTypesHolder()->GlobalETSStringLiteralType(); } +Type *ETSChecker::GlobalETSBigIntType() const +{ + return GetGlobalTypesHolder()->GlobalETSBigIntBuiltinType(); +} + Type *ETSChecker::GlobalWildcardType() const { return GetGlobalTypesHolder()->GlobalWildcardType(); @@ -246,6 +251,11 @@ ETSObjectType *ETSChecker::GlobalBuiltinETSStringType() const return AsETSObjectType(&GlobalTypesHolder::GlobalETSStringBuiltinType); } +ETSObjectType *ETSChecker::GlobalBuiltinETSBigIntType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalETSBigIntBuiltinType); +} + ETSObjectType *ETSChecker::GlobalBuiltinTypeType() const { return AsETSObjectType(&GlobalTypesHolder::GlobalTypeBuiltinType); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index a74c5db6cf..6b9add7581 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -28,6 +28,7 @@ #include "checker/types/globalTypesHolder.h" #include "ir/ts/tsTypeParameter.h" #include "ir/ts/tsTypeParameterInstantiation.h" +#include "lexer/token/tokenType.h" #include "util/enumbitops.h" #include "util/ustring.h" #include "utils/bit_utils.h" @@ -100,11 +101,13 @@ public: Type *GlobalETSNullType() const; Type *GlobalETSUndefinedType() const; Type *GlobalETSStringLiteralType() const; + Type *GlobalETSBigIntType() const; Type *GlobalWildcardType() const; ETSObjectType *GlobalETSObjectType() const; ETSObjectType *GlobalETSNullishObjectType() const; ETSObjectType *GlobalBuiltinETSStringType() const; + ETSObjectType *GlobalBuiltinETSBigIntType() const; ETSObjectType *GlobalBuiltinTypeType() const; ETSObjectType *GlobalBuiltinExceptionType() const; ETSObjectType *GlobalBuiltinErrorType() const; @@ -193,6 +196,7 @@ public: LongType *CreateLongType(int64_t value); ShortType *CreateShortType(int16_t value); CharType *CreateCharType(char16_t value); + ETSBigIntType *CreateETSBigIntLiteralType(util::StringView value); ETSStringType *CreateETSStringLiteralType(util::StringView value); ETSArrayType *CreateETSArrayType(Type *element_type); Type *CreateETSUnionType(ArenaVector &&constituent_types); @@ -226,6 +230,7 @@ public: // Arithmetic Type *NegateNumericType(Type *type, ir::Expression *node); Type *BitwiseNegateNumericType(Type *type, ir::Expression *node); + bool CheckBinaryOperatorForBigInt(Type *left, Type *right, ir::Expression *expr, lexer::TokenType op); std::tuple CheckBinaryOperator(ir::Expression *left, ir::Expression *right, ir::Expression *expr, lexer::TokenType operation_type, lexer::SourcePosition pos, bool force_promotion = false); @@ -660,6 +665,8 @@ private: void CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends); void SetUpTypeParameterConstraint(ir::TSTypeParameter *param); + ETSObjectType *UpdateGlobalType(ETSObjectType *obj_type, util::StringView name); + ETSObjectType *UpdateBoxedGlobalType(ETSObjectType *obj_type, util::StringView name); ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *decl_node, ETSObjectFlags flags); void CheckProgram(parser::Program *program, bool run_analysis = false); diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 6ff49a3e30..7595d94e77 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -136,6 +136,44 @@ Type *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer: return PerformRelationOperationOnTypes(left, right, operation_type); } +bool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, ir::Expression *expr, lexer::TokenType op) +{ + if ((left == nullptr) || (right == nullptr)) { + return false; + } + + if (!left->IsETSBigIntType()) { + return false; + } + + if (!right->IsETSBigIntType()) { + return false; + } + + if (expr->IsBinaryExpression()) { + ir::BinaryExpression *be = expr->AsBinaryExpression(); + if (be->OperatorType() == lexer::TokenType::PUNCTUATOR_STRICT_EQUAL) { + // Handle strict comparison as normal comparison for bigint objects + be->SetOperator(lexer::TokenType::PUNCTUATOR_EQUAL); + } + } + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::KEYW_INSTANCEOF: + // This is handled in the main CheckBinaryOperator function + return false; + default: + break; + } + + // Remove const flag - currently there are no compile time operations for bigint + left->RemoveTypeFlag(TypeFlag::CONSTANT); + right->RemoveTypeFlag(TypeFlag::CONSTANT); + + return true; +} + checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod(ir::Expression *left, ir::Expression *right, lexer::TokenType operation_type, lexer::SourcePosition pos, bool is_equal_op, checker::Type *const left_type, @@ -175,6 +213,11 @@ checker::Type *ETSChecker::CheckBinaryOperatorPlus(ir::Expression *left, ir::Exp } if (left_type->IsETSStringType() || right_type->IsETSStringType()) { + if (operation_type == lexer::TokenType::PUNCTUATOR_MINUS || + operation_type == lexer::TokenType::PUNCTUATOR_MINUS_EQUAL) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + return HandleStringConcatenation(left_type, right_type); } @@ -489,83 +532,87 @@ Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *right, le return FindLeastUpperBound(non_nullish_left_type, right_type); } -// NOLINTNEXTLINE(readability-function-size) -std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, - ir::Expression *expr, lexer::TokenType operation_type, - lexer::SourcePosition pos, bool force_promotion) +using CheckBinaryFunction = std::function; + +std::map &GetCheckMap() { - checker::Type *const left_type = left->Check(this); - checker::Type *const right_type = right->Check(this); - const bool is_logical_extended_operator = (operation_type == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || - (operation_type == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); - Type *unboxed_l = is_logical_extended_operator ? ETSBuiltinTypeAsConditionalType(left_type) - : ETSBuiltinTypeAsPrimitiveType(left_type); - Type *unboxed_r = is_logical_extended_operator ? ETSBuiltinTypeAsConditionalType(right_type) - : ETSBuiltinTypeAsPrimitiveType(right_type); + static std::map check_map = { + {lexer::TokenType::PUNCTUATOR_MULTIPLY, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_DIVIDE, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, + + {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus}, + {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus}, + {lexer::TokenType::PUNCTUATOR_PLUS, &ETSChecker::CheckBinaryOperatorPlus}, + {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus}, + + {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, + {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, + {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, + {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, + {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, + {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, + + {lexer::TokenType::PUNCTUATOR_BITWISE_OR, &ETSChecker::CheckBinaryOperatorBitwise}, + {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, + {lexer::TokenType::PUNCTUATOR_BITWISE_AND, &ETSChecker::CheckBinaryOperatorBitwise}, + {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, + {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, &ETSChecker::CheckBinaryOperatorBitwise}, + {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, + }; + + return check_map; +} +struct BinaryOperatorParams { + ir::Expression *left; + ir::Expression *right; + ir::Expression *expr; + lexer::TokenType operation_type; + lexer::SourcePosition pos; + bool is_equal_op; +}; + +struct TypeParams { + checker::Type *left_type; + checker::Type *right_type; + Type *unboxed_l; + Type *unboxed_r; +}; + +static std::tuple CheckBinaryOperatorHelper(ETSChecker *checker, + const BinaryOperatorParams &binary_params, + const TypeParams &type_params) +{ + ir::Expression *left = binary_params.left; + ir::Expression *right = binary_params.right; + lexer::SourcePosition pos = binary_params.pos; + checker::Type *const left_type = type_params.left_type; + checker::Type *const right_type = type_params.right_type; + Type *unboxed_l = type_params.unboxed_l; + Type *unboxed_r = type_params.unboxed_r; checker::Type *ts_type {}; - bool is_equal_op = (operation_type > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && - operation_type < lexer::TokenType::PUNCTUATOR_ARROW) && - !force_promotion; - - switch (operation_type) { - case lexer::TokenType::PUNCTUATOR_MULTIPLY: - case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: - case lexer::TokenType::PUNCTUATOR_DIVIDE: - case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: - case lexer::TokenType::PUNCTUATOR_MOD: - case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { - ts_type = CheckBinaryOperatorMulDivMod(left, right, operation_type, pos, is_equal_op, left_type, right_type, - unboxed_l, unboxed_r); - break; - } - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { - if (left_type->IsETSStringType() || right_type->IsETSStringType()) { - ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); - } - - [[fallthrough]]; - } - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { - ts_type = CheckBinaryOperatorPlus(left, right, operation_type, pos, is_equal_op, left_type, right_type, - unboxed_l, unboxed_r); - break; - } - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: - case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { - ts_type = CheckBinaryOperatorShift(left, right, operation_type, pos, is_equal_op, left_type, right_type, - unboxed_l, unboxed_r); - break; - } - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: - case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: - case lexer::TokenType::PUNCTUATOR_BITWISE_AND: - case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: - case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: - case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { - ts_type = CheckBinaryOperatorBitwise(left, right, operation_type, pos, is_equal_op, left_type, right_type, - unboxed_l, unboxed_r); - break; - } + switch (binary_params.operation_type) { case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { - ts_type = CheckBinaryOperatorLogical(left, right, expr, pos, left_type, right_type, unboxed_l, unboxed_r); + ts_type = checker->CheckBinaryOperatorLogical(left, right, binary_params.expr, pos, left_type, right_type, + unboxed_l, unboxed_r); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - return CheckBinaryOperatorStrictEqual(left, pos, left_type, right_type); + return checker->CheckBinaryOperatorStrictEqual(left, pos, left_type, right_type); } case lexer::TokenType::PUNCTUATOR_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { - std::tuple res = - CheckBinaryOperatorEqual(left, right, operation_type, pos, left_type, right_type, unboxed_l, unboxed_r); + std::tuple res = checker->CheckBinaryOperatorEqual( + left, right, binary_params.operation_type, pos, left_type, right_type, unboxed_l, unboxed_r); if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) { return res; } @@ -575,18 +622,18 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: case lexer::TokenType::PUNCTUATOR_GREATER_THAN: case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { - return CheckBinaryOperatorLessGreater(left, right, operation_type, pos, is_equal_op, left_type, right_type, - unboxed_l, unboxed_r); + return checker->CheckBinaryOperatorLessGreater(left, right, binary_params.operation_type, pos, + binary_params.is_equal_op, left_type, right_type, unboxed_l, + unboxed_r); } case lexer::TokenType::KEYW_INSTANCEOF: { - return CheckBinaryOperatorInstanceOf(pos, left_type, right_type); + return checker->CheckBinaryOperatorInstanceOf(pos, left_type, right_type); } case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { - ts_type = CheckBinaryOperatorNullishCoalescing(right, pos, left_type, right_type); + ts_type = checker->CheckBinaryOperatorNullishCoalescing(right, pos, left_type, right_type); break; } default: { - // NOTE UNREACHABLE(); break; } @@ -595,6 +642,51 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, return {ts_type, ts_type}; } +std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + ir::Expression *expr, lexer::TokenType op, + lexer::SourcePosition pos, bool force_promotion) +{ + checker::Type *const left_type = left->Check(this); + checker::Type *const right_type = right->Check(this); + if ((left_type == nullptr) || (right_type == nullptr)) { + ThrowTypeError("Unexpected type error in binary expression", pos); + } + + const bool is_logical_extended_operator = + (op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || (op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); + Type *unboxed_l = is_logical_extended_operator ? ETSBuiltinTypeAsConditionalType(left_type) + : ETSBuiltinTypeAsPrimitiveType(left_type); + Type *unboxed_r = is_logical_extended_operator ? ETSBuiltinTypeAsConditionalType(right_type) + : ETSBuiltinTypeAsPrimitiveType(right_type); + + checker::Type *ts_type {}; + bool is_equal_op = + (op > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && op < lexer::TokenType::PUNCTUATOR_ARROW) && !force_promotion; + + if (CheckBinaryOperatorForBigInt(left_type, right_type, expr, op)) { + switch (op) { + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + return {GlobalETSBooleanType(), GlobalETSBooleanType()}; + default: + return {left_type, right_type}; + } + }; + + auto check_map = GetCheckMap(); + if (check_map.find(op) != check_map.end()) { + auto check = check_map[op]; + ts_type = check(this, left, right, op, pos, is_equal_op, left_type, right_type, unboxed_l, unboxed_r); + return {ts_type, ts_type}; + } + + BinaryOperatorParams binary_params {left, right, expr, op, pos, is_equal_op}; + TypeParams type_params {left_type, right_type, unboxed_l, unboxed_r}; + return CheckBinaryOperatorHelper(this, binary_params, type_params); +} + Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operation_type) { ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index f19c280b50..a85e51ff5e 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1669,7 +1669,7 @@ bool ETSChecker::IsTypeBuiltinType(const Type *type) const bool ETSChecker::IsReferenceType(const Type *type) { return type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || type->IsETSNullLike() || - type->IsETSStringType() || type->IsETSTypeParameter() || type->IsETSUnionType(); + type->IsETSStringType() || type->IsETSTypeParameter() || type->IsETSUnionType() || type->IsETSBigIntType(); } const ir::AstNode *ETSChecker::FindJumpTarget(ir::AstNodeType node_type, const ir::AstNode *node, diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 243fd35895..f673d9c562 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include #include "checker/ETSchecker.h" #include "checker/ets/boxingConverter.h" #include "checker/types/ets/byteType.h" @@ -34,6 +35,7 @@ #include "varbinder/ETSBinder.h" #include "parser/program/program.h" #include "util/helpers.h" +#include "checker/types/ts/bigintType.h" namespace panda::es2panda::checker { ByteType *ETSChecker::CreateByteType(int8_t value) @@ -102,6 +104,11 @@ CharType *ETSChecker::CreateCharType(char16_t value) return Allocator()->New(value); } +ETSBigIntType *ETSChecker::CreateETSBigIntLiteralType(util::StringView value) +{ + return Allocator()->New(Allocator(), GlobalBuiltinETSBigIntType(), value); +} + ETSStringType *ETSChecker::CreateETSStringLiteralType(util::StringView value) { return Allocator()->New(Allocator(), GlobalBuiltinETSStringType(), value); @@ -206,9 +213,126 @@ ETSExtensionFuncHelperType *ETSChecker::CreateETSExtensionFuncHelperType(ETSFunc return Allocator()->New(class_method_type, extension_function_type); } +std::map &GetNameToTypeIdMap() +{ + static std::map name_to_type_id = { + {compiler::Signatures::BUILTIN_BIGINT_CLASS, GlobalTypeId::ETS_BIG_INT_BUILTIN}, + {compiler::Signatures::BUILTIN_STRING_CLASS, GlobalTypeId::ETS_STRING_BUILTIN}, + {compiler::Signatures::BUILTIN_OBJECT_CLASS, GlobalTypeId::ETS_OBJECT_BUILTIN}, + {compiler::Signatures::BUILTIN_EXCEPTION_CLASS, GlobalTypeId::ETS_EXCEPTION_BUILTIN}, + {compiler::Signatures::BUILTIN_ERROR_CLASS, GlobalTypeId::ETS_ERROR_BUILTIN}, + {compiler::Signatures::BUILTIN_TYPE_CLASS, GlobalTypeId::ETS_TYPE_BUILTIN}, + {compiler::Signatures::BUILTIN_PROMISE_CLASS, GlobalTypeId::ETS_PROMISE_BUILTIN}, + {compiler::Signatures::BUILTIN_BOX_CLASS, GlobalTypeId::ETS_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_BOOLEAN_BOX_CLASS, GlobalTypeId::ETS_BOOLEAN_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_BYTE_BOX_CLASS, GlobalTypeId::ETS_BYTE_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_CHAR_BOX_CLASS, GlobalTypeId::ETS_CHAR_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_SHORT_BOX_CLASS, GlobalTypeId::ETS_SHORT_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_INT_BOX_CLASS, GlobalTypeId::ETS_INT_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_LONG_BOX_CLASS, GlobalTypeId::ETS_LONG_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS, GlobalTypeId::ETS_FLOAT_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS, GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN}, + {compiler::Signatures::BUILTIN_VOID_CLASS, GlobalTypeId::ETS_VOID_BUILTIN}, + }; + + return name_to_type_id; +} + +std::map> &GetNameToGlobalTypeMap() +{ + static std::map> name_to_global_type = { + {compiler::Signatures::BUILTIN_BIGINT_CLASS, &ETSChecker::GlobalBuiltinETSBigIntType}, + {compiler::Signatures::BUILTIN_STRING_CLASS, &ETSChecker::GlobalBuiltinETSStringType}, + {compiler::Signatures::BUILTIN_OBJECT_CLASS, &ETSChecker::GlobalETSObjectType}, + {compiler::Signatures::BUILTIN_EXCEPTION_CLASS, &ETSChecker::GlobalBuiltinExceptionType}, + {compiler::Signatures::BUILTIN_ERROR_CLASS, &ETSChecker::GlobalBuiltinErrorType}, + {compiler::Signatures::BUILTIN_TYPE_CLASS, &ETSChecker::GlobalBuiltinTypeType}, + {compiler::Signatures::BUILTIN_PROMISE_CLASS, &ETSChecker::GlobalBuiltinPromiseType}, + {compiler::Signatures::BUILTIN_VOID_CLASS, &ETSChecker::GlobalBuiltinVoidType}, + }; + + return name_to_global_type; +} + +std::map> &GetNameToGlobalBoxTypeMap() +{ + static std::map> name_to_global_box_type = { + {compiler::Signatures::BUILTIN_BOX_CLASS, &ETSChecker::GlobalETSObjectType}, + {compiler::Signatures::BUILTIN_BOOLEAN_BOX_CLASS, &ETSChecker::GlobalETSBooleanType}, + {compiler::Signatures::BUILTIN_BYTE_BOX_CLASS, &ETSChecker::GlobalByteType}, + {compiler::Signatures::BUILTIN_CHAR_BOX_CLASS, &ETSChecker::GlobalCharType}, + {compiler::Signatures::BUILTIN_SHORT_BOX_CLASS, &ETSChecker::GlobalShortType}, + {compiler::Signatures::BUILTIN_INT_BOX_CLASS, &ETSChecker::GlobalIntType}, + {compiler::Signatures::BUILTIN_LONG_BOX_CLASS, &ETSChecker::GlobalLongType}, + {compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS, &ETSChecker::GlobalFloatType}, + {compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS, &ETSChecker::GlobalDoubleType}, + }; + + return name_to_global_box_type; +} + +ETSObjectType *ETSChecker::UpdateBoxedGlobalType(ETSObjectType *obj_type, util::StringView name) +{ + auto name_to_global_box_type = GetNameToGlobalBoxTypeMap(); + auto name_to_type_id = GetNameToTypeIdMap(); + + if (name_to_global_box_type.find(name) != name_to_global_box_type.end()) { + std::function global_type = name_to_global_box_type[name]; + if (GlobalBuiltinBoxType(global_type(this)) != nullptr) { + return GlobalBuiltinBoxType(global_type(this)); + } + + auto id = name_to_type_id.find(name); + if (id != name_to_type_id.end()) { + GetGlobalTypesHolder()->GlobalTypes()[static_cast(id->second)] = obj_type; + } + } + + return obj_type; +} + +ETSObjectType *ETSChecker::UpdateGlobalType(ETSObjectType *obj_type, util::StringView name) +{ + auto name_to_global_type = GetNameToGlobalTypeMap(); + auto name_to_type_id = GetNameToTypeIdMap(); + + if (name_to_global_type.find(name) != name_to_global_type.end()) { + std::function global_type = name_to_global_type[name]; + if (global_type(this) != nullptr) { + return global_type(this); + } + + auto id = name_to_type_id.find(name); + if (id != name_to_type_id.end()) { + GetGlobalTypesHolder()->GlobalTypes()[static_cast(id->second)] = obj_type; + } + + if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { + auto *nullish = CreateNullishType(obj_type, checker::TypeFlag::NULLISH, Allocator(), Relation(), + GetGlobalTypesHolder()); + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_NULLISH_OBJECT)] = nullish; + } + } + + return obj_type; +} + ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *decl_node, ETSObjectFlags flags) { + if (name == compiler::Signatures::BUILTIN_BIGINT_CLASS) { + if (GlobalBuiltinETSBigIntType() != nullptr) { + return GlobalBuiltinETSBigIntType(); + } + + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BIG_INT_BUILTIN)] = + CreateNewETSObjectType(name, decl_node, flags | ETSObjectFlags::BUILTIN_BIGINT); + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BIG_INT)] = + Allocator()->New(Allocator(), GlobalBuiltinETSBigIntType()); + + return GlobalBuiltinETSBigIntType(); + } + if (name == compiler::Signatures::BUILTIN_STRING_CLASS) { if (GlobalBuiltinETSStringType() != nullptr) { return GlobalBuiltinETSStringType(); @@ -222,93 +346,12 @@ ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView nam } auto *obj_type = CreateNewETSObjectType(name, decl_node, flags); - - if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { - if (GlobalETSObjectType() != nullptr) { - return GlobalETSObjectType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_OBJECT_BUILTIN)] = obj_type; - auto *nullish = - CreateNullishType(obj_type, checker::TypeFlag::NULLISH, Allocator(), Relation(), GetGlobalTypesHolder()); - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_NULLISH_OBJECT)] = nullish; - } else if (name == compiler::Signatures::BUILTIN_EXCEPTION_CLASS) { - if (GlobalBuiltinExceptionType() != nullptr) { - return GlobalBuiltinExceptionType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_EXCEPTION_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_ERROR_CLASS) { - if (GlobalBuiltinErrorType() != nullptr) { - return GlobalBuiltinErrorType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_ERROR_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_TYPE_CLASS) { - if (GlobalBuiltinTypeType() != nullptr) { - return GlobalBuiltinTypeType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_TYPE_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_PROMISE_CLASS) { - if (GlobalBuiltinPromiseType() != nullptr) { - return GlobalBuiltinPromiseType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_PROMISE_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalETSObjectType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalETSObjectType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_BOOLEAN_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalETSBooleanType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalETSBooleanType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BOOLEAN_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_BYTE_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalByteType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalByteType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BYTE_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_CHAR_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalCharType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalCharType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_CHAR_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_SHORT_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalShortType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalShortType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_SHORT_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_INT_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalIntType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalIntType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_INT_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_LONG_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalLongType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalLongType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_LONG_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalFloatType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalFloatType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_FLOAT_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalFloatType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalFloatType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_FLOAT_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalDoubleType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalDoubleType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN)] = obj_type; - } else if (name == compiler::Signatures::BUILTIN_VOID_CLASS) { - if (GlobalBuiltinVoidType() != nullptr) { - return GlobalBuiltinVoidType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_VOID_BUILTIN)] = obj_type; + auto name_to_global_box_type = GetNameToGlobalBoxTypeMap(); + if (name_to_global_box_type.find(name) != name_to_global_box_type.end()) { + return UpdateBoxedGlobalType(obj_type, name); } - return obj_type; + return UpdateGlobalType(obj_type, name); } ETSObjectType *ETSChecker::CreateETSObjectType(util::StringView name, ir::AstNode *decl_node, ETSObjectFlags flags) diff --git a/ets2panda/checker/types/ets/etsBigIntType.cpp b/ets2panda/checker/types/ets/etsBigIntType.cpp new file mode 100644 index 0000000000..883554170c --- /dev/null +++ b/ets2panda/checker/types/ets/etsBigIntType.cpp @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021-2023 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. + */ + +#include "etsBigIntType.h" + +namespace panda::es2panda::checker { +void ETSBigIntType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSBigIntType()) { + relation->Result(true); + return; + } + + relation->Result(false); +} + +void ETSBigIntType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (source->IsETSBigIntType()) { + relation->Result(true); + return; + } + + relation->Result(false); +} + +Type *ETSBigIntType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *global_types) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsBigIntType.h b/ets2panda/checker/types/ets/etsBigIntType.h new file mode 100644 index 0000000000..5703107e89 --- /dev/null +++ b/ets2panda/checker/types/ets/etsBigIntType.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021-2023 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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BIGINT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BIGINT_TYPE_H + +#include "checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class ETSBigIntType : public ETSObjectType { +public: + explicit ETSBigIntType(ArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) + : ETSObjectType(allocator, + ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_BIGINT | ETSObjectFlags::RESOLVED_SUPER) + { + SetSuperType(super); + } + + explicit ETSBigIntType(ArenaAllocator *allocator, ETSObjectType *super, util::StringView value) + : ETSObjectType(allocator, + ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_BIGINT | ETSObjectFlags::RESOLVED_SUPER), + value_(value) + { + SetSuperType(super); + AddTypeFlag(TypeFlag::CONSTANT); + AddTypeFlag(TypeFlag::BIGINT_LITERAL); + variable_ = super->Variable(); + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *global_types) override; + + void ToString(std::stringstream &ss) const override + { + ss << lexer::TokenToString(lexer::TokenType::KEYW_BIGINT); + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::BUILTIN_BIGINT; + } + + util::StringView GetValue() const + { + return value_; + } + +private: + util::StringView value_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index b978b6b48a..ce2fbc5ffd 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -48,6 +48,7 @@ enum class ETSObjectFlags : uint32_t { CHECKED_INVOKE_LEGITIMACY = 1U << 18U, UNDEFINED_TYPE = 1U << 19U, + BUILTIN_BIGINT = 1U << 22U, BUILTIN_STRING = 1U << 23U, BUILTIN_BOOLEAN = 1U << 24U, BUILTIN_BYTE = 1U << 25U, @@ -60,7 +61,7 @@ enum class ETSObjectFlags : uint32_t { UNBOXABLE_TYPE = BUILTIN_BOOLEAN | BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG | BUILTIN_FLOAT | BUILTIN_DOUBLE, - BUILTIN_TYPE = BUILTIN_STRING | UNBOXABLE_TYPE, + BUILTIN_TYPE = BUILTIN_STRING | BUILTIN_BIGINT | UNBOXABLE_TYPE, VALID_SWITCH_TYPE = BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG | BUILTIN_STRING | ENUM, GLOBAL_CLASS = CLASS | GLOBAL, diff --git a/ets2panda/checker/types/ets/types.h b/ets2panda/checker/types/ets/types.h index 1f798ee532..ceb2e87ade 100644 --- a/ets2panda/checker/types/ets/types.h +++ b/ets2panda/checker/types/ets/types.h @@ -30,6 +30,7 @@ #include "etsUnionType.h" #include "etsVoidType.h" #include "etsStringType.h" +#include "etsBigIntType.h" #include "etsObjectType.h" #include "etsDynamicType.h" #include "etsArrayType.h" diff --git a/ets2panda/checker/types/globalTypesHolder.cpp b/ets2panda/checker/types/globalTypesHolder.cpp index 5c6eb9a07b..6fcac6fa77 100644 --- a/ets2panda/checker/types/globalTypesHolder.cpp +++ b/ets2panda/checker/types/globalTypesHolder.cpp @@ -42,6 +42,7 @@ #include "checker/types/ets/shortType.h" #include "checker/types/ets/etsBooleanType.h" #include "checker/types/ets/etsStringType.h" +#include "checker/types/ets/etsBigIntType.h" #include "checker/types/ets/etsVoidType.h" #include "checker/types/ets/etsObjectType.h" #include "checker/types/ets/wildcardType.h" @@ -126,6 +127,7 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) : builtin_name_m builtin_name_mappings_.emplace("ClassNotFoundException", GlobalTypeId::ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN); builtin_name_mappings_.emplace("ClassCastException", GlobalTypeId::ETS_CLASS_CAST_EXCEPTION_BUILTIN); builtin_name_mappings_.emplace("String", GlobalTypeId::ETS_STRING_BUILTIN); + builtin_name_mappings_.emplace("BigInt", GlobalTypeId::ETS_BIG_INT_BUILTIN); builtin_name_mappings_.emplace("StringBuilder", GlobalTypeId::ETS_STRING_BUILDER_BUILTIN); builtin_name_mappings_.emplace("Type", GlobalTypeId::ETS_TYPE_BUILTIN); builtin_name_mappings_.emplace("Types", GlobalTypeId::ETS_TYPES_BUILTIN); @@ -511,6 +513,16 @@ Type *GlobalTypesHolder::GlobalETSStringBuiltinType() return global_types_.at(static_cast(GlobalTypeId::ETS_STRING_BUILTIN)); } +Type *GlobalTypesHolder::GlobalETSBigIntBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_BIG_INT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalETSBigIntLiteralType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_BIG_INT)); +} + Type *GlobalTypesHolder::GlobalStringBuilderBuiltinType() { return global_types_.at(static_cast(GlobalTypeId::ETS_STRING_BUILDER_BUILTIN)); diff --git a/ets2panda/checker/types/globalTypesHolder.h b/ets2panda/checker/types/globalTypesHolder.h index e0e370b459..8808a17352 100644 --- a/ets2panda/checker/types/globalTypesHolder.h +++ b/ets2panda/checker/types/globalTypesHolder.h @@ -109,6 +109,8 @@ enum class GlobalTypeId { ETS_FLOAT_BOX_BUILTIN, ETS_DOUBLE_BOX_BUILTIN, ETS_NEVER_BUILTIN, + ETS_BIG_INT_BUILTIN, + ETS_BIG_INT, COUNT, }; @@ -185,6 +187,8 @@ public: Type *GlobalClassNotFoundExceptionBuiltinType(); [[nodiscard]] Type *GlobalClassCastExceptionBuiltinType() const noexcept; Type *GlobalETSStringBuiltinType(); + Type *GlobalETSBigIntBuiltinType(); + Type *GlobalETSBigIntLiteralType(); Type *GlobalStringBuilderBuiltinType(); Type *GlobalTypeBuiltinType(); Type *GlobalTypesBuiltinType(); diff --git a/ets2panda/checker/types/type.cpp b/ets2panda/checker/types/type.cpp index c28e55dcf5..054852e1b2 100644 --- a/ets2panda/checker/types/type.cpp +++ b/ets2panda/checker/types/type.cpp @@ -61,6 +61,11 @@ bool Type::IsETSStringType() const return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::STRING); } +bool Type::IsETSBigIntType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_BIGINT); +} + bool Type::IsETSAsyncFuncReturnType() const { return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::ASYNC_FUNC_RETURN_TYPE); diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 3f5185007d..0d8a0da4a3 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -43,6 +43,7 @@ class ETSTypeParameter; TYPE_MAPPING(DECLARE_TYPENAMES) #undef DECLARE_TYPENAMES class ETSStringType; +class ETSBigIntType; using Substitution = ArenaMap; @@ -84,6 +85,7 @@ public: #undef TYPE_AS_CASTS bool IsETSStringType() const; + bool IsETSBigIntType() const; bool IsETSNullType() const; bool IsETSUndefinedType() const; bool IsETSNullLike() const; @@ -105,6 +107,12 @@ public: return reinterpret_cast(this); } + const ETSBigIntType *AsETSBigIntType() const + { + ASSERT(IsETSObjectType()); + return reinterpret_cast(this); + } + bool IsETSDynamicType() const { return IsETSObjectType() && HasTypeFlag(TypeFlag::ETS_DYNAMIC_FLAG); diff --git a/ets2panda/compiler/base/condition.cpp b/ets2panda/compiler/base/condition.cpp index d2abcf9569..73d41b3740 100644 --- a/ets2panda/compiler/base/condition.cpp +++ b/ets2panda/compiler/base/condition.cpp @@ -187,8 +187,60 @@ void Condition::CompileLogicalAndExpr(ETSGen *etsg, const ir::BinaryExpression * etsg->SetLabel(bin_expr, return_right_true_label); } +bool Condition::CompileBinaryExprForBigInt(ETSGen *etsg, const ir::BinaryExpression *expr, Label *false_label) +{ + if ((expr->Left()->TsType() == nullptr) || (expr->Right()->TsType() == nullptr)) { + return false; + } + + if (!expr->Left()->TsType()->IsETSBigIntType()) { + return false; + } + + if (!expr->Right()->TsType()->IsETSBigIntType()) { + return false; + } + + std::string_view signature = compiler::Signatures::ANY; + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN; + break; + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN_EQUAL; + break; + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN; + break; + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN_EQUAL; + break; + default: + // Other operations are handled in the CompileBinaryExpr function + return false; + } + + auto ttctx = TargetTypeContext(etsg, expr->OperationType()); + RegScope rs(etsg); + VReg lhs = etsg->AllocReg(); + expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); + expr->Right()->Compile(etsg); + etsg->ApplyConversion(expr->Right(), expr->OperationType()); + compiler::VReg rhs = etsg->AllocReg(); + etsg->StoreAccumulator(expr, rhs); + etsg->CallBigIntBinaryComparison(expr, lhs, rhs, signature); + etsg->BranchIfFalse(expr, false_label); + + return true; +} + bool Condition::CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label) { + if (CompileBinaryExprForBigInt(etsg, bin_expr, false_label)) { + return true; + } + switch (bin_expr->OperatorType()) { case lexer::TokenType::PUNCTUATOR_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: diff --git a/ets2panda/compiler/base/condition.h b/ets2panda/compiler/base/condition.h index 6380ba538e..30b3b27cad 100644 --- a/ets2panda/compiler/base/condition.h +++ b/ets2panda/compiler/base/condition.h @@ -42,6 +42,7 @@ private: static bool CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); static void CompileLogicalAndExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); static void CompileLogicalOrExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); + static bool CompileBinaryExprForBigInt(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 3fad191fc2..c19489b0e3 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -550,9 +550,83 @@ static void CompileLogical(compiler::ETSGen *etsg, const ir::BinaryExpression *e etsg->SetAccumulatorType(expr->TsType()); } +std::map &GetBigintSignatures() +{ + static std::map bigint_signatures = { + {lexer::TokenType::PUNCTUATOR_PLUS, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_ADD}, + {lexer::TokenType::PUNCTUATOR_MINUS, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_SUBTRACT}, + {lexer::TokenType::PUNCTUATOR_MULTIPLY, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_MULTIPLY}, + {lexer::TokenType::PUNCTUATOR_DIVIDE, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_DIVIDE}, + {lexer::TokenType::PUNCTUATOR_MOD, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_MODULE}, + {lexer::TokenType::PUNCTUATOR_BITWISE_OR, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_OR}, + {lexer::TokenType::PUNCTUATOR_BITWISE_AND, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_AND}, + {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_XOR}, + {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LEFT_SHIFT}, + {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_RIGHT_SHIFT}, + {lexer::TokenType::PUNCTUATOR_GREATER_THAN, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN}, + {lexer::TokenType::PUNCTUATOR_LESS_THAN, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN}, + {lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL, + compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN_EQUAL}, + {lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN_EQUAL}, + }; + + return bigint_signatures; +} + +static bool CompileBigInt(compiler::ETSGen *etsg, const ir::BinaryExpression *expr) +{ + if ((expr->Left()->TsType() == nullptr) || (expr->Right()->TsType() == nullptr)) { + return false; + } + + if (!expr->Left()->TsType()->IsETSBigIntType()) { + return false; + } + + if (!expr->Right()->TsType()->IsETSBigIntType()) { + return false; + } + + auto map = GetBigintSignatures(); + if (map.find(expr->OperatorType()) == map.end()) { + return false; + } + + const checker::Type *operation_type = expr->OperationType(); + auto ttctx = compiler::TargetTypeContext(etsg, operation_type); + compiler::RegScope rs(etsg); + compiler::VReg lhs = etsg->AllocReg(); + expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, operation_type); + expr->Right()->Compile(etsg); + etsg->ApplyConversion(expr->Right(), operation_type); + compiler::VReg rhs = etsg->AllocReg(); + etsg->StoreAccumulator(expr, rhs); + + std::string_view signature = map.at(expr->OperatorType()); + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + etsg->CallBigIntBinaryComparison(expr, lhs, rhs, signature); + break; + default: + etsg->CallBigIntBinaryOperator(expr, lhs, rhs, signature); + break; + } + + return true; +} + void ETSCompiler::Compile(const ir::BinaryExpression *expr) const { ETSGen *etsg = GetETSGen(); + + if (CompileBigInt(etsg, expr)) { + return; + } + if (etsg->TryLoadConstantExpression(expr)) { return; } @@ -1120,7 +1194,16 @@ void ETSCompiler::Compile(const ir::UpdateExpression *expr) const lref.GetValue(); expr->Argument()->SetBoxingUnboxingFlags(argument_unboxing_flags); etsg->ApplyConversion(expr->Argument(), nullptr); - etsg->Update(expr, expr->OperatorType()); + + if (expr->Argument()->TsType()->IsETSBigIntType()) { + compiler::RegScope rs(etsg); + compiler::VReg value_reg = etsg->AllocReg(); + etsg->StoreAccumulator(expr->Argument(), value_reg); + etsg->UpdateBigInt(expr, value_reg, expr->OperatorType()); + } else { + etsg->Update(expr, expr->OperatorType()); + } + expr->Argument()->SetBoxingUnboxingFlags(argument_boxing_flags); etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); lref.SetValue(); @@ -1137,7 +1220,12 @@ void ETSCompiler::Compile(const ir::UpdateExpression *expr) const expr->Argument()->SetBoxingUnboxingFlags(argument_unboxing_flags); etsg->ApplyConversion(expr->Argument(), nullptr); - etsg->Update(expr, expr->OperatorType()); + + if (expr->Argument()->TsType()->IsETSBigIntType()) { + etsg->UpdateBigInt(expr, original_value_reg, expr->OperatorType()); + } else { + etsg->Update(expr, expr->OperatorType()); + } expr->Argument()->SetBoxingUnboxingFlags(argument_boxing_flags); etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); @@ -1153,7 +1241,13 @@ void ETSCompiler::Compile([[maybe_unused]] const ir::YieldExpression *expr) cons // compile methods for LITERAL EXPRESSIONS in alphabetical order void ETSCompiler::Compile([[maybe_unused]] const ir::BigIntLiteral *expr) const { - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::TargetTypeContext ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); + compiler::RegScope rs {etsg}; + etsg->LoadAccumulatorBigInt(expr, expr->Str()); + const compiler::VReg value = etsg->AllocReg(); + etsg->StoreAccumulator(expr, value); + etsg->CreateBigIntObject(expr, value); } void ETSCompiler::Compile(const ir::BooleanLiteral *expr) const diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 7022338e47..9ebbed8041 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -611,6 +611,11 @@ void ETSGen::LoadThis(const ir::AstNode *node) LoadAccumulator(node, GetThisReg()); } +void ETSGen::CreateBigIntObject(const ir::AstNode *node, VReg arg0) +{ + Ra().Emit(node, Signatures::BUILTIN_BIGINT_CTOR, arg0, dummy_reg_); +} + void ETSGen::CreateLambdaObjectFromIdentReference(const ir::AstNode *node, ir::ClassDefinition *lambda_obj) { auto *ctor = lambda_obj->TsType()->AsETSObjectType()->ConstructSignatures()[0]; @@ -851,6 +856,19 @@ void ETSGen::GuardUncheckedType(const ir::AstNode *node, const checker::Type *un } } +void ETSGen::LoadConstantObject(const ir::Expression *node, const checker::Type *type) +{ + if (type->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { + LoadAccumulatorBigInt(node, type->AsETSObjectType()->AsETSBigIntType()->GetValue()); + const VReg value = AllocReg(); + StoreAccumulator(node, value); + CreateBigIntObject(node, value); + } else { + LoadAccumulatorString(node, type->AsETSObjectType()->AsETSStringType()->GetValue()); + SetAccumulatorType(node->TsType()); + } +} + bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) { const auto *type = node->TsType(); @@ -895,8 +913,7 @@ bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) break; } case checker::TypeFlag::ETS_OBJECT: { - LoadAccumulatorString(node, type->AsETSObjectType()->AsETSStringType()->GetValue()); - SetAccumulatorType(node->TsType()); + LoadConstantObject(node, type); break; } default: { @@ -2134,7 +2151,10 @@ void ETSGen::BinaryEqualityRef(const ir::AstNode *node, bool test_equal, VReg lh StoreAccumulator(node, rhs); LoadAccumulator(node, lhs); - if (GetVRegType(lhs)->IsETSStringType()) { + + if (GetVRegType(lhs)->IsETSBigIntType()) { + CallThisStatic1(node, lhs, Signatures::BUILTIN_BIGINT_EQUALS, rhs); + } else if (GetVRegType(lhs)->IsETSStringType()) { CallThisStatic1(node, lhs, Signatures::BUILTIN_STRING_EQUALS, rhs); } else { CallThisVirtual1(node, lhs, Signatures::BUILTIN_OBJECT_EQUALS, rhs); @@ -2227,6 +2247,13 @@ void ETSGen::Unary(const ir::AstNode *node, lexer::TokenType op) void ETSGen::UnaryMinus(const ir::AstNode *node) { + if (GetAccumulatorType()->IsETSBigIntType()) { + const VReg value = AllocReg(); + StoreAccumulator(node, value); + CallThisStatic0(node, value, Signatures::BUILTIN_BIGINT_NEGATE); + return; + } + switch (checker::ETSChecker::ETSType(GetAccumulatorType())) { case checker::TypeFlag::LONG: { Sa().Emit(node); @@ -2255,6 +2282,14 @@ void ETSGen::UnaryMinus(const ir::AstNode *node) void ETSGen::UnaryTilde(const ir::AstNode *node) { + if (GetAccumulatorType()->IsETSBigIntType()) { + const VReg value = AllocReg(); + StoreAccumulator(node, value); + CallThisStatic0(node, value, Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_NOT); + SetAccumulatorType(Checker()->GlobalETSBigIntType()); + return; + } + switch (checker::ETSChecker::ETSType(GetAccumulatorType())) { case checker::TypeFlag::LONG: { Sa().Emit(node); @@ -2299,6 +2334,23 @@ void ETSGen::Update(const ir::AstNode *node, lexer::TokenType op) } } +void ETSGen::UpdateBigInt(const ir::Expression *node, VReg arg, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { + CallBigIntUnaryOperator(node, arg, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_INCREMENT); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { + CallBigIntUnaryOperator(node, arg, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_DECREMENT); + break; + } + default: { + UNREACHABLE(); + } + } +} + void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) { RegScope rs(this); @@ -2390,6 +2442,28 @@ void ETSGen::BuildString(const ir::Expression *node) SetAccumulatorType(node->TsType()); } +void ETSGen::CallBigIntUnaryOperator(const ir::Expression *node, VReg arg, const util::StringView signature) +{ + LoadAccumulator(node, arg); + CallThisStatic0(node, arg, signature); + SetAccumulatorType(Checker()->GlobalETSBigIntType()); +} + +void ETSGen::CallBigIntBinaryOperator(const ir::Expression *node, VReg lhs, VReg rhs, const util::StringView signature) +{ + LoadAccumulator(node, lhs); + CallThisStatic1(node, lhs, signature, rhs); + SetAccumulatorType(Checker()->GlobalETSBigIntType()); +} + +void ETSGen::CallBigIntBinaryComparison(const ir::Expression *node, VReg lhs, VReg rhs, + const util::StringView signature) +{ + LoadAccumulator(node, lhs); + CallThisStatic1(node, lhs, signature, rhs); + SetAccumulatorType(Checker()->GlobalETSBooleanType()); +} + void ETSGen::BuildTemplateString(const ir::TemplateLiteral *node) { RegScope rs(this); diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 2a0e360fa6..5aaa0c3d2c 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -98,6 +98,7 @@ public: void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); void Unary(const ir::AstNode *node, lexer::TokenType op); void Update(const ir::AstNode *node, lexer::TokenType op); + void UpdateBigInt(const ir::Expression *node, VReg arg, lexer::TokenType op); bool TryLoadConstantExpression(const ir::Expression *node); void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *if_false); @@ -387,6 +388,12 @@ public: SetAccumulatorType(Checker()->GlobalETSStringLiteralType()); } + void LoadAccumulatorBigInt(const ir::AstNode *node, util::StringView str) + { + Sa().Emit(node, str); + SetAccumulatorType(Checker()->GlobalETSBigIntType()); + } + void LoadAccumulatorNull(const ir::AstNode *node, const checker::Type *type) { Sa().Emit(node); @@ -551,6 +558,9 @@ public: void NewArray(const ir::AstNode *node, VReg arr, VReg dim, const checker::Type *arr_type); void NewObject(const ir::AstNode *node, VReg ctor, util::StringView name); void BuildString(const ir::Expression *node); + void CallBigIntUnaryOperator(const ir::Expression *node, VReg arg, util::StringView signature); + void CallBigIntBinaryOperator(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); + void CallBigIntBinaryComparison(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); void BuildTemplateString(const ir::TemplateLiteral *node); void InitObject(const ir::AstNode *node, checker::Signature *signature, const ArenaVector &arguments) @@ -635,6 +645,7 @@ public: } #endif // PANDA_WITH_ETS + void CreateBigIntObject(const ir::AstNode *node, VReg arg0); void CreateLambdaObjectFromIdentReference(const ir::AstNode *node, ir::ClassDefinition *lambda_obj); void CreateLambdaObjectFromMemberReference(const ir::AstNode *node, ir::Expression *obj, ir::ClassDefinition *lambda_obj); @@ -661,6 +672,7 @@ private: void EmitUnboxedCall(const ir::AstNode *node, std::string_view signature_flag, const checker::Type *target_type, const checker::Type *boxed_type); + void LoadConstantObject(const ir::Expression *node, const checker::Type *type); void StringBuilderAppend(const ir::AstNode *node, VReg builder); void AppendString(const ir::Expression *bin_expr, VReg builder); void StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg builder); diff --git a/ets2panda/compiler/scripts/signatures.yaml b/ets2panda/compiler/scripts/signatures.yaml index be3639d81f..5c46319853 100644 --- a/ets2panda/compiler/scripts/signatures.yaml +++ b/ets2panda/compiler/scripts/signatures.yaml @@ -257,6 +257,9 @@ builtins: - name: Error package: PKG_ESCOMPAT ref: BUILTIN_ERROR + - name: BigInt + package: PKG_ESCOMPAT + ref: BUILTIN_BIGINT - name: AssertionError package: PKG_ESCOMPAT ref: BUILTIN_ASSERTION_ERROR @@ -337,6 +340,132 @@ signatures: return_type: PRIMITIVE_VOID ref: BUILTIN_ASSERTION_ERROR_CTOR + - callee: BUILTIN_BIGINT + method_name: $CTOR + params: [BUILTIN_STRING] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BIGINT_CTOR + + - callee: BUILTIN_BIGINT + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BIGINT_CTOR_EMPTY + + - callee: BUILTIN_BIGINT + method_name: equals + params: [BUILTIN_BIGINT] + return_type: PRIMITIVE_BOOLEAN + ref: BUILTIN_BIGINT_EQUALS + + - callee: BUILTIN_BIGINT + method_name: negate + params: [] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_NEGATE + + - callee: BUILTIN_BIGINT + method_name: operatorAdd + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_ADD + + - callee: BUILTIN_BIGINT + method_name: operatorSubtract + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_SUBTRACT + + - callee: BUILTIN_BIGINT + method_name: operatorMultiply + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_MULTIPLY + + - callee: BUILTIN_BIGINT + method_name: operatorDivide + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_DIVIDE + + - callee: BUILTIN_BIGINT + method_name: operatorModule + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_MODULE + + - callee: BUILTIN_BIGINT + method_name: operatorBitwiseOr + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_BITWISE_OR + + - callee: BUILTIN_BIGINT + method_name: operatorBitwiseAnd + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_BITWISE_AND + + - callee: BUILTIN_BIGINT + method_name: operatorBitwiseXor + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_BITWISE_XOR + + - callee: BUILTIN_BIGINT + method_name: operatorGreaterThan + params: [BUILTIN_BIGINT] + return_type: PRIMITIVE_BOOLEAN + ref: BUILTIN_BIGINT_OPERATOR_GREATER_THAN + + - callee: BUILTIN_BIGINT + method_name: operatorLessThan + params: [BUILTIN_BIGINT] + return_type: PRIMITIVE_BOOLEAN + ref: BUILTIN_BIGINT_OPERATOR_LESS_THAN + + - callee: BUILTIN_BIGINT + method_name: operatorGreaterThanEqual + params: [BUILTIN_BIGINT] + return_type: PRIMITIVE_BOOLEAN + ref: BUILTIN_BIGINT_OPERATOR_GREATER_THAN_EQUAL + + - callee: BUILTIN_BIGINT + method_name: operatorLessThanEqual + params: [BUILTIN_BIGINT] + return_type: PRIMITIVE_BOOLEAN + ref: BUILTIN_BIGINT_OPERATOR_LESS_THAN_EQUAL + + - callee: BUILTIN_BIGINT + method_name: operatorLeftShift + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_LEFT_SHIFT + + - callee: BUILTIN_BIGINT + method_name: operatorRightShift + params: [BUILTIN_BIGINT] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_RIGHT_SHIFT + + - callee: BUILTIN_BIGINT + method_name: operatorIncrement + params: [] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_INCREMENT + + - callee: BUILTIN_BIGINT + method_name: operatorDecrement + params: [] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_DECREMENT + + - callee: BUILTIN_BIGINT + method_name: operatorBitwiseNot + params: [] + return_type: BUILTIN_BIGINT + ref: BUILTIN_BIGINT_OPERATOR_BITWISE_NOT + - callee: BUILTIN_THROWABLE method_name: $CTOR params: [] diff --git a/ets2panda/ir/expressions/literals/bigIntLiteral.cpp b/ets2panda/ir/expressions/literals/bigIntLiteral.cpp index a12339916c..e3fbbd8c8f 100644 --- a/ets2panda/ir/expressions/literals/bigIntLiteral.cpp +++ b/ets2panda/ir/expressions/literals/bigIntLiteral.cpp @@ -19,6 +19,7 @@ #include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" #include "ir/astDump.h" +#include "checker/ETSchecker.h" #include "ir/srcDump.h" namespace panda::es2panda::ir { diff --git a/ets2panda/ir/expressions/literals/bigIntLiteral.h b/ets2panda/ir/expressions/literals/bigIntLiteral.h index 0ae06c2640..424c37bcb1 100644 --- a/ets2panda/ir/expressions/literals/bigIntLiteral.h +++ b/ets2panda/ir/expressions/literals/bigIntLiteral.h @@ -42,10 +42,10 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Dump(ir::SrcDumper *dumper) const override; - void Compile(compiler::PandaGen *pg) const override; + void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; - checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check(checker::ETSChecker *checker) override; + checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; void Accept(ASTVisitorT *v) override { diff --git a/ets2panda/ir/expressions/unaryExpression.cpp b/ets2panda/ir/expressions/unaryExpression.cpp index 82601c41bf..77160e124d 100644 --- a/ets2panda/ir/expressions/unaryExpression.cpp +++ b/ets2panda/ir/expressions/unaryExpression.cpp @@ -16,6 +16,7 @@ #include "unaryExpression.h" #include "varbinder/variable.h" +#include "checker/types/typeFlag.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" diff --git a/ets2panda/lexer/ETSLexer.h b/ets2panda/lexer/ETSLexer.h index 6c7c7b43e9..1349e8a8ad 100644 --- a/ets2panda/lexer/ETSLexer.h +++ b/ets2panda/lexer/ETSLexer.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_CORE_ETS_LEXER_H #include "lexer/lexer.h" +#include "token/letters.h" namespace panda::es2panda::lexer { class ETSLexer final : public Lexer { @@ -40,12 +41,25 @@ public: void ScanNumberLeadingZero() override { const auto saved_lexer_position = Save(); + + bool allow_bigint = false; + if (Iterator().Peek() == LEX_CHAR_LOWERCASE_N) { + // 0n is the only allowed bigint literal with leading 0 + allow_bigint = true; + } + try { ScanNumberLeadingZeroImpl(); } catch (...) { Rewind(saved_lexer_position); ScanNumberLeadingZeroImpl(); } + + if ((GetToken().flags_ & TokenFlags::NUMBER_BIGINT) != 0) { + if (!allow_bigint) { + ThrowError("Invalid BigInt number"); + } + } } void CheckNumberLiteralEnd() override; diff --git a/ets2panda/test/runtime/ets/BigInt.ets b/ets2panda/test/runtime/ets/BigInt.ets new file mode 100644 index 0000000000..d2fa645b16 --- /dev/null +++ b/ets2panda/test/runtime/ets/BigInt.ets @@ -0,0 +1,643 @@ +/* + * Copyright (c) 2023 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 test_bitwise_and(): void { + assert new BigInt("10").operatorBitwiseAnd(new BigInt("2")).toString().equals("2"); + assert new BigInt("256").operatorBitwiseAnd(new BigInt("1")).toString().equals("0"); + assert new BigInt("3124378143267041203423").operatorBitwiseAnd(new BigInt("43621978")).toString().equals("41948250"); + assert new BigInt("256").operatorBitwiseAnd(new BigInt("256")).toString().equals("256"); + assert new BigInt("12345678").operatorBitwiseAnd(new BigInt("1234")).toString().equals("66"); +} + +function test_bitwise_or(): void { + assert new BigInt("10").operatorBitwiseOr(new BigInt("2")).toString().equals("10"); + assert new BigInt("256").operatorBitwiseOr(new BigInt("1")).toString().equals("257"); + assert new BigInt("256").operatorBitwiseOr(new BigInt("256")).toString().equals("256"); + assert new BigInt("3124378143267041203423").operatorBitwiseOr(new BigInt("43621978")).toString().equals("3124378143267042877151"); + assert new BigInt("12345678").operatorBitwiseOr(new BigInt("1234")).toString().equals("12346846"); +} + +function test_bitwise_xor(): void { + assert new BigInt("10").operatorBitwiseXor(new BigInt("2")).toString().equals("8"); + assert new BigInt("256").operatorBitwiseXor(new BigInt("1")).toString().equals("257"); + assert new BigInt("256").operatorBitwiseXor(new BigInt("256")).toString().equals("0"); + assert new BigInt("3124378143267041203423").operatorBitwiseXor(new BigInt("43621978")).toString().equals("3124378143267000928901"); + assert new BigInt("12345678").operatorBitwiseXor(new BigInt("1234")).toString().equals("12346780"); +} + +function test_left_shift(): void { + assert new BigInt("0").operatorLeftShift(new BigInt("0")).toString().equals("0"); + assert new BigInt("0").operatorLeftShift(new BigInt("1")).toString().equals("0"); + assert new BigInt("1").operatorLeftShift(new BigInt("0")).toString().equals("1"); + assert new BigInt("10").operatorLeftShift(new BigInt("2")).toString().equals("40"); + assert new BigInt("255").operatorLeftShift(new BigInt("41")).toString().equals("560750930165760"); + assert new BigInt("65535").operatorLeftShift(new BigInt("60")).toString().equals("75556710804409716572160"); + assert new BigInt("4294967295").operatorLeftShift(new BigInt("5")).toString().equals("137438953440"); + assert new BigInt("18446744073709551615").operatorLeftShift(new BigInt("6")).toString().equals("1180591620717411303360"); + assert new BigInt("1275418875248948586535904902545412130").operatorLeftShift(new BigInt("123")).toString().equals("13562579802667292602585801202159372574330573695725523059072421474640855040"); + assert new BigInt("2").operatorLeftShift(new BigInt("218")).toString().equals("842498333348457493583344221469363458551160763204392890034487820288"); + assert new BigInt("-1").operatorLeftShift(new BigInt("0")).toString().equals("-1"); + assert new BigInt("-12").operatorLeftShift(new BigInt("4")).toString().equals("-192"); + assert new BigInt("-255").operatorLeftShift(new BigInt("19")).toString().equals("-133693440"); + assert new BigInt("-65535").operatorLeftShift(new BigInt("73")).toString().equals("-618960574909724398159134720"); + assert new BigInt("-4294967295").operatorLeftShift(new BigInt("24")).toString().equals("-72057594021150720"); + assert new BigInt("-18446744073709551615").operatorLeftShift(new BigInt("31")).toString().equals("-39614081257132168794624491520"); + assert new BigInt("-4095059032950818422890113130149234924134").operatorLeftShift(new BigInt("103")).toString().equals("-41528832328721100931613913139905162112381494314462183326283215847555072"); +} + +function test_right_shift(): void { + assert new BigInt("-200").operatorRightShift(new BigInt("2")).toString().equals("-50"); + assert new BigInt("-12").operatorRightShift(new BigInt("2")).toString().equals("-3"); + assert new BigInt("-1").operatorRightShift(new BigInt("0")).toString().equals("-1"); + assert new BigInt("0").operatorRightShift(new BigInt("0")).toString().equals("0"); + assert new BigInt("0").operatorRightShift(new BigInt("1")).toString().equals("0"); + assert new BigInt("1").operatorRightShift(new BigInt("0")).toString().equals("1"); + assert new BigInt("55").operatorRightShift(new BigInt("2")).toString().equals("13"); + assert new BigInt("-50").operatorRightShift(new BigInt("2")).toString().equals("-13"); + assert new BigInt("255").operatorRightShift(new BigInt("4")).toString().equals("15"); + assert new BigInt("255").operatorRightShift(new BigInt("8")).toString().equals("0"); + assert new BigInt("65535").operatorRightShift(new BigInt("10")).toString().equals("63"); + assert new BigInt("4294967295").operatorRightShift(new BigInt("17")).toString().equals("32767"); + assert new BigInt("4294967295").operatorRightShift(new BigInt("48")).toString().equals("0"); + assert new BigInt("18446744073709551615").operatorRightShift(new BigInt("55")).toString().equals("511"); + assert new BigInt("4930493049034092989191918392837727383823827").operatorRightShift(new BigInt("129")).toString().equals("7244"); + assert new BigInt("34930693049034092980065918370009389341341932481328231493102392100010239").operatorRightShift(new BigInt("41")).toString().equals("15884640128676479880626138024130973163365493965706369405371"); + assert new BigInt("34095405903900293499034024029409200000000000000000000094049304394284993939382949384984981018480144184891848991934893429489324901148449849382222222222222888384932890000103010381803018300103180381030084545225875678328499213403403984398439489384984287113383827387373382328328194394892948392222219791749717949183748237").operatorRightShift(new BigInt("511")).toString().equals("5085903091997271218878067997324523590835536101241386224503069830700984460490307918626942225457432781938207872710051592009243523341752202627425621983245162030428"); + assert new BigInt("-255").operatorRightShift(new BigInt("2")).toString().equals("-64"); + assert new BigInt("-65535").operatorRightShift(new BigInt("12")).toString().equals("-16"); + assert new BigInt("-4294967295").operatorRightShift(new BigInt("18")).toString().equals("-16384"); + assert new BigInt("-18446744073709551615").operatorRightShift(new BigInt("38")).toString().equals("-67108864"); + assert new BigInt("-4095059032950818422890113130149234924134").operatorRightShift(new BigInt("99")).toString().equals("-6460863952"); + assert new BigInt("-3294302940940294094923040592059302590950294502940294029029409029429042942049028100104029439420990952").operatorRightShift(new BigInt("100")).toString().equals("-2598746800062401791237527125433630339355687972972274247737341685088307"); +} + +function test_module(): void { + assert new BigInt("10").operatorModule(new BigInt("3")).toString().equals("1"); + assert new BigInt("10").operatorModule(new BigInt("-3")).toString().equals("1"); + assert new BigInt("-10").operatorModule(new BigInt("3")).toString().equals("-1"); + assert new BigInt("-10").operatorModule(new BigInt("-3")).toString().equals("-1"); + assert new BigInt("100").operatorModule(new BigInt("50")).toString().equals("0"); + assert new BigInt("100").operatorModule(new BigInt("-50")).toString().equals("0"); + assert new BigInt("-100").operatorModule(new BigInt("50")).toString().equals("0"); + assert new BigInt("-100").operatorModule(new BigInt("-50")).toString().equals("0"); + assert new BigInt("3124378143267041203423").operatorModule(new BigInt("43621978")).toString().equals("18802883"); + assert new BigInt("-3124378143267041203423").operatorModule(new BigInt("43621978")).toString().equals("-18802883"); + assert new BigInt("3124378143267041203423").operatorModule(new BigInt("-43621978")).toString().equals("18802883"); + assert new BigInt("-3124378143267041203423").operatorModule(new BigInt("-43621978")).toString().equals("-18802883"); + assert new BigInt("100").operatorModule(new BigInt("250")).toString().equals("100"); + assert new BigInt("-100").operatorModule(new BigInt("250")).toString().equals("-100"); + assert new BigInt("100").operatorModule(new BigInt("-250")).toString().equals("100"); + assert new BigInt("-100").operatorModule(new BigInt("-250")).toString().equals("-100"); + assert new BigInt("0").operatorModule(new BigInt("8")).toString().equals("0"); +} + +function test_divide(): void { + assert new BigInt("10").operatorDivide(new BigInt("3")).toString().equals("3"); + assert new BigInt("-10").operatorDivide(new BigInt("3")).toString().equals("-3"); + assert new BigInt("10").operatorDivide(new BigInt("-3")).toString().equals("-3"); + assert new BigInt("-10").operatorDivide(new BigInt("-3")).toString().equals("3"); + assert new BigInt("100").operatorDivide(new BigInt("50")).toString().equals("2"); + assert new BigInt("100").operatorDivide(new BigInt("-50")).toString().equals("-2"); + assert new BigInt("-100").operatorDivide(new BigInt("50")).toString().equals("-2"); + assert new BigInt("-100").operatorDivide(new BigInt("-50")).toString().equals("2"); + assert new BigInt("3124378143267041203423").operatorDivide(new BigInt("43621978")).toString().equals("71623944775430"); + assert new BigInt("-3124378143267041203423").operatorDivide(new BigInt("43621978")).toString().equals("-71623944775430"); + assert new BigInt("3124378143267041203423").operatorDivide(new BigInt("-43621978")).toString().equals("-71623944775430"); + assert new BigInt("-3124378143267041203423").operatorDivide(new BigInt("-43621978")).toString().equals("71623944775430"); + assert new BigInt("100").operatorDivide(new BigInt("250")).toString().equals("0"); + assert new BigInt("100").operatorDivide(new BigInt("-250")).toString().equals("0"); + assert new BigInt("-100").operatorDivide(new BigInt("250")).toString().equals("0"); + assert new BigInt("-100").operatorDivide(new BigInt("-250")).toString().equals("0"); + assert new BigInt("65000").operatorDivide(new BigInt("100")).toString().equals("650"); + assert new BigInt("65000").operatorDivide(new BigInt("-100")).toString().equals("-650"); + assert new BigInt("-65000").operatorDivide(new BigInt("100")).toString().equals("-650"); + assert new BigInt("-65000").operatorDivide(new BigInt("-100")).toString().equals("650"); +} + +function test_unary_minus(): void { + assert new BigInt("10").negate().toString().equals("-10"); + assert new BigInt("1000").negate().toString().equals("-1000"); + assert new BigInt("-1").negate().toString().equals("1"); + assert new BigInt("-10").negate().toString().equals("10"); + assert new BigInt("-100").negate().toString().equals("100"); + assert new BigInt("0").negate().toString().equals("0"); +} + +function test_plus(): void { + assert new BigInt("10").operatorAdd(new BigInt("20")).toString() == "30"; + assert new BigInt("1000").operatorAdd(new BigInt("10")).toString() == "1010"; + assert new BigInt("-10").operatorAdd(new BigInt("9")).toString() == "-1"; + assert new BigInt("-10").operatorAdd(new BigInt("10")).toString() == "0"; + assert new BigInt("-100").operatorAdd(new BigInt("10")).toString() == "-90"; + assert new BigInt("100").operatorAdd(new BigInt("10")).toString() == "110"; + assert new BigInt("65535").operatorAdd(new BigInt("65535")).toString() == "131070"; + assert new BigInt("65500").operatorAdd(new BigInt("1")).toString().equals("65501"); + assert new BigInt("65500").operatorAdd(new BigInt("-1")).toString().equals("65499"); + assert new BigInt("-65500").operatorAdd(new BigInt("-1")).toString().equals("-65501"); + assert new BigInt("-65500").operatorAdd(new BigInt("1")).toString().equals("-65499"); + assert new BigInt("-65500").operatorAdd(new BigInt("100000")).toString().equals("34500"); + assert new BigInt("100").operatorAdd(new BigInt("0")).toString().equals("100"); + assert new BigInt("-100").operatorAdd(new BigInt("0")).toString().equals("-100"); + assert new BigInt("-10").operatorAdd(new BigInt("-10")).toString().equals("-20"); +} + +function test_minus(): void { + assert new BigInt("10").operatorSubtract(new BigInt("2")).toString().equals("8"); + assert new BigInt("2").operatorSubtract(new BigInt("10")).toString().equals("-8"); + assert new BigInt("-10").operatorSubtract(new BigInt("-2")).toString().equals("-8"); + assert new BigInt("-100").operatorSubtract(new BigInt("1")).toString().equals("-101"); + assert new BigInt("-100").operatorSubtract(new BigInt("-1")).toString().equals("-99"); + assert new BigInt("-1000").operatorSubtract(new BigInt("10")).toString().equals("-1010"); + assert new BigInt("1237840127434312471243").operatorSubtract(new BigInt("234112342314526914672342143621463921469")).toString().equals("-234112342314526913434502016187151450226"); + assert new BigInt("-1237840127434312471243").operatorSubtract(new BigInt("234112342314526914672342143621463921469")).toString().equals("-234112342314526915910182271055776392712"); + assert new BigInt("1237840127434312471243").operatorSubtract(new BigInt("-234112342314526914672342143621463921469")).toString().equals("234112342314526915910182271055776392712"); + assert new BigInt("-1237840127434312471243").operatorSubtract(new BigInt("-234112342314526914672342143621463921469")).toString().equals("234112342314526913434502016187151450226"); + assert new BigInt("-1000").operatorSubtract(new BigInt("-10")).toString().equals("-990"); + assert new BigInt("-100").operatorSubtract(new BigInt("0")).toString().equals("-100"); + assert new BigInt("0").operatorSubtract(new BigInt("-100")).toString().equals("100"); + assert new BigInt("0").operatorSubtract(new BigInt("100")).toString().equals("-100"); + assert new BigInt("65500").operatorSubtract(new BigInt("1")).toString().equals("65499"); + assert new BigInt("65500").operatorSubtract(new BigInt("-1")).toString().equals("65501"); + assert new BigInt("-65500").operatorSubtract(new BigInt("-1")).toString().equals("-65499"); + assert new BigInt("-65500").operatorSubtract(new BigInt("1")).toString().equals("-65501"); + assert new BigInt("65500").operatorSubtract(new BigInt("100000")).toString().equals("-34500"); + assert new BigInt("49798775").operatorSubtract(new BigInt("43621978")).toString().equals("6176797"); + assert new BigInt("10").operatorSubtract(new BigInt("20")).toString().equals("-10"); +} + +function test_multiply(): void { + assert new BigInt("10").operatorMultiply(new BigInt("10")).toString() == "100"; + assert new BigInt("0").operatorMultiply(new BigInt("50")).toString() == "0"; + assert new BigInt("1").operatorMultiply(new BigInt("50")).toString() == "50"; + assert new BigInt("50").operatorMultiply(new BigInt("5")).toString() == "250"; + assert new BigInt("50").operatorMultiply(new BigInt("-5")).toString() == "-250"; + assert new BigInt("-1").operatorMultiply(new BigInt("-5")).toString() == "5"; + assert new BigInt("0").operatorMultiply(new BigInt("0")).toString() == "0"; + assert new BigInt("123").operatorMultiply(new BigInt("1")).toString() == "123"; + assert new BigInt("1234").operatorMultiply(new BigInt("987")).toString() == "1217958"; + assert new BigInt("3241847031247230147213740214703214721047312").operatorMultiply(new BigInt("412343124123421347812304712431421204731024")).toString() == "1336753332794721625246945391107220242430725631478413717131017736872102322242538207488"; + assert new BigInt("-3241847031247230147213740214703214721047312").operatorMultiply(new BigInt("-412343124123421347812304712431421204731024")).toString() == "1336753332794721625246945391107220242430725631478413717131017736872102322242538207488"; + assert new BigInt("-3241847031247230147213740214703214721047312").operatorMultiply(new BigInt("412343124123421347812304712431421204731024")).toString() == "-1336753332794721625246945391107220242430725631478413717131017736872102322242538207488"; + assert new BigInt("3241847031247230147213740214703214721047312").operatorMultiply(new BigInt("-412343124123421347812304712431421204731024")).toString() == "-1336753332794721625246945391107220242430725631478413717131017736872102322242538207488"; + assert new BigInt("256").operatorMultiply(new BigInt("256")).toString() == "65536"; +} + +function test_create_empty_bigint(): void { + let a = new BigInt() + assert a.positive() + assert a.toString() == "0" + + let b = new BigInt("") + assert b.positive() + assert b.toString() == "0" +} + +function test_invalid_bigint(): void { + // NOTE(kkonsw): implement validation +} + +function test_bigint_as_string(): void { + assert new BigInt("10").toString() == "10" + assert new BigInt("1000").toString() == "1000" + assert new BigInt("-1000").toString() == "-1000" + assert new BigInt("-1").toString() == "-1" + assert new BigInt("-10").toString() == "-10" + assert new BigInt("-100").toString() == "-100" + assert new BigInt("-100000000000000").toString() == "-100000000000000" + assert new BigInt("0").toString() == "0" +} + +function test_type(): void { + let num0 = 0n; + let num1 = 100_100_100_100_100_100n + let num2 = -57896044618658097711785492504343953926634992332820282019728792003956564819967n + + assert (num0 instanceof bigint) + assert (num1 instanceof bigint) + assert (num2 instanceof bigint) +} + +function test_assignment(): void { + let a = -24059059045444224545405903904190343043049209420234290480n + let b = a + assert (a instanceof bigint) + assert (b instanceof bigint) + assert (a.toString() == b.toString()); + + a = 123n; + assert (a instanceof bigint) + assert (a.toString() == "123"); + assert (a == 123n); + + const zero = 0n; + let c = zero; + assert (zero instanceof bigint) + assert (c instanceof bigint) + assert (zero.toString() == c.toString()); +} + +function test_compare(): void { + const a = 24400569094091093912039019089543850580328542852805043n + const b = 34034240244909504590902901119302940942904944029040950n + + assert 44493059209094029409209402940924902n < 140044940590459049067274048929058908989042385n + assert 44493059209094029409209402940924902n < a + assert a < 34034240244909504590902901119302940942904944029040950n + assert a < b + + assert 44493059209094029409209402940924902n <= 140044940590459049067274048929058908989042385n + assert 44493059209094029409209402940924902n <= a + assert a <= 34034240244909504590902901119302940942904944029040950n + assert a <= b + + assert 44493059209094029409209402940924902n <= 44493059209094029409209402940924902n + assert 24400569094091093912039019089543850580328542852805043n <= a + assert a <= 24400569094091093912039019089543850580328542852805043n + assert a <= a + + assert 40044940590459049067274048929058908989042385n > 44493059209094029409209402940924902n + assert 34034240244909504590902901119302940942904944029040950n > a + assert a > 140044940590459049067274048929058908989042385n + assert b > a + + assert 40044940590459049067274048929058908989042385n >= 44493059209094029409209402940924902n + assert 34034240244909504590902901119302940942904944029040950n >= a + assert a >= 140044940590459049067274048929058908989042385n + assert b >= a + + assert 44493059209094029409209402940924902n <= 44493059209094029409209402940924902n + assert 24400569094091093912039019089543850580328542852805043n <= a + assert a <= 24400569094091093912039019089543850580328542852805043n + assert a <= a +} + +function test_literals() : void { + let num0 = 0n + assert (num0.toString() == "0") + + let num1 = 127n + assert (num1.toString() == "127") + + let num2 = 32767n + assert (num2.toString() == "32767") + + let num3 = 2147483647n + assert (num3.toString() == "2147483647") + + let num4 = 9223372036854775807n + assert (num4.toString() == "9223372036854775807") + + let num5 = 170141183460469231731687303715884105727n + assert (num5.toString() == "170141183460469231731687303715884105727") + + let num6 = 57896044618658097711785492504343953926634992332820282019728792003956564819967n + assert (num6.toString() == "57896044618658097711785492504343953926634992332820282019728792003956564819967") + + let num1_n = -128n + assert (num1_n.toString() == "-128") + + let num2_n = -32768n + assert (num2_n.toString() == "-32768") + + let num3_n = -2147483648n + assert (num3_n.toString() == "-2147483648") + + let num4_n = -9223372036854775808n + assert (num4_n.toString() == "-9223372036854775808") + + let num5_n = -170141183460469231731687303715884105728n + assert (num5_n.toString() == "-170141183460469231731687303715884105728") + + let num6_n = -57896044618658097711785492504343953926634992332820282019728792003956564819968n + assert (num6_n.toString() == "-57896044618658097711785492504343953926634992332820282019728792003956564819968") + + let num1_sep = 1_991_653_125_841_217_555_434419_9091_123000000_3_3313_5775_3282_29n + assert (num1_sep.toString() == "19916531258412175554344199091123000000333135775328229") + + let num2_sep = -422_12_3333_9844_3333_3443_34111_43434_1111_11_1_3_3_411909_990081n + assert (num2_sep.toString() == "-4221233339844333334433411143434111111133411909990081") + + let num0_t: bigint = 0n + assert (num0_t.toString() == "0") + + let num1_t: bigint = 57896044618658097711785492504343953926634992332820282019728792003956564819967n + assert (num1_t.toString() == "57896044618658097711785492504343953926634992332820282019728792003956564819967") + + let num2_t: bigint = -9223372036854775808n + assert (num2_t.toString() == "-9223372036854775808") + + let num3_t: bigint = 1_991_653_125_841_217_555_434419_9091_123000000_3_3313_5775_3282_29n + assert (num3_t.toString() == "19916531258412175554344199091123000000333135775328229") + + let num4_t: bigint = -422_12_3333_9844_3333_3443_34111_43434_1111_11_1_3_3_411909_990081n + assert (num4_t.toString() == "-4221233339844333334433411143434111111133411909990081") + + const num0_c = 0n + assert (num0_c.toString() == "0") + + const num1_c = 1267650600228229401496703205376n + assert (num1_c.toString() == "1267650600228229401496703205376") + + const num2_c = -1427247692705959881058285969449495136382746624n + assert (num2_c.toString() == "-1427247692705959881058285969449495136382746624") + + const num3_c = 4_000_000_000_000_000_000_000_100n + assert (num3_c.toString() == "4000000000000000000000100") + + const num4_c: bigint = -7777777_666666_55555_4444_333_22_1n + assert (num4_c.toString() == "-7777777666666555554444333221") +} + +function test_cast(): void { + const v = 1559053 + const b: byte = 44 + const s: short = -17600 + const i: int = 1150483640 + const l: long = -8223372036854775808 + + // NOTE(kkonsw): casts currently do not work +} + +function test_bigint_methods(): void { + const b: byte = 44 + const s: short = -17600 + const i: int = 1150483640 + const l: long = -8223372036854775808 + + /* Testing BigInt constructor */ + let n0 = new BigInt(0) + assert n0 == 0n + assert(n0.toString() == "0") + + let n1 = new BigInt(654093) + assert(n1.toString() == "654093") + assert n1 == 654093n + + let n2 = new BigInt(b) + assert(n2.toString() == "44") + assert n2 == 44n + + let n3 = new BigInt(s) + assert(n3.toString() == "-17600") + assert n3 == -17600n + + let n4 = new BigInt(i) + assert(n4.toString() == "1150483640") + assert n4 == 1150483640n + + let n5 = new BigInt(l) + assert(n5.toString() == "-8223372036854775808") + assert n5 == -8223372036854775808n + + let dec = new BigInt("-12392320390239294724747283477947923471101032") + assert dec == -12392320390239294724747283477947923471101032n + + const n7 = 12392320390239294724747283477947923471101032n + + /* Testing asIntN() static method */ + // assert BigInt.asIntN(0, n7) == 0n + // assert BigInt.asIntN(8, n7) == 104n + // assert BigInt.asIntN(16, n7) == 27752n + // assert BigInt.asIntN(32, n7) == -737317784n + // assert BigInt.asIntN(64, n7) == -7098331616643290008n + + /* Testing asUintN() static method */ + // assert BigInt.asUintN(0, n7) == 0n + // assert BigInt.asUintN(8, n7) == 104n + // assert BigInt.asUintN(16, n7) == 27752n + // assert BigInt.asUintN(32, n7) == 3557649512n + // assert BigInt.asUintN(64, n7) == 11348412457066261608n +} + +function test_unary(): void { + let n = -128n + assert (n.toString() == "-128") + + let a = 123n; + assert(a == 123n); + assert(a.toString() == "123"); + + a = -123n; + assert(a == -123n); + assert(a.toString() == "-123"); + + a = 123n + assert(a == 123n); + assert(a.toString() == "123"); + + a = -a; + assert(a == -123n); + assert(a.toString() == "-123"); + + a = -a; + assert(a == 123n); + assert(a.toString() == "123"); + + let e: bigint; + assert(a == 123n); + assert(a.toString() == "123"); + e = -a; + + // Check that original value does not change + assert(a == 123n); + assert(a.toString() == "123"); + assert(e == -123n); + assert(e.toString() == "-123"); + e = a; + assert(e == 123n); + assert(e.toString() == "123"); + + let b = -123n; + assert(b == -123n) + assert(b.toString() == "-123"); + + let c = -(123n); + assert(c == -123n) + assert(c.toString() == "-123"); + + // Double unary minus + let d = -(-123n); + assert(d == 123n); + assert(d.toString() == "123"); + + // Triple unary minux + let f = -(-(-123n)); + assert(f == -123n); + assert(f.toString() == "-123"); + + a = new BigInt(321); + assert(a.toString() == "321") + assert(a == 321n) + + b = -a; + assert(a.toString() == "321") + assert(a == 321n) + assert(b == -321n); + assert(b.toString() == "-321"); +} + +function test_multiplication(): void { + const a = 23443495146314363289895841n + const b = 245000234343499329134n + const c = -245000234343499329134n + + /* Multiplication testing (*) */ + assert 978667632325344545n * 4534000101n == 4437279143808543031889799045n + assert a * b == 5743661804677708098900659843374372544236731694n + assert a * c == -5743661804677708098900659843374372544236731694n + assert a * 0n == 0n + assert c * 0n == 0n + + + /* Division testing (/) */ + assert 39735235034886462n / 89221422n == 445355321n + assert a / b == 95687n + assert a / c == -95687n + assert 0n / a == 0n + + let err = false; + try { + a / 0n + } catch (e) { + if (e instanceof Error) { + err = true + } + } + assert err + + /* Remainder of the division (%) */ + assert 493433405047004109n % 111114444n == 18100749n + assert a % b == a % c + assert 0n % a == 0n + + err = false; + try { + a % 0n + } catch (e) { + if (e instanceof Error) { + err = true + } + } + assert err +} + +function test_addition_1(): void { + const a = 97567789101304567800013210071n + const b = -533923234343411557221n + const c = 0n; + + /* Minus testing (-) */ + assert (-a == -97567789101304567800013210071n) + assert (-b == 533923234343411557221n) + assert (-c == -0n) + assert (-(-a) == a) + assert (-(-b) == b) + assert (-(-c) == c) + + /* Plus testing (+) */ + assert +a == a + assert +b == b + assert +c == 0n +} + +function test_addition_2(): void { + const a = 18446744073709551616n; + const b = 36893488147419103232n; + const c = -10000000000000000000n; + + /* Addition testing (+) */ + assert 999999999999999n + 1n == 1000000000000000n + assert a + b == 55340232221128654848n + assert a + a == b + assert a + c == 8446744073709551616n + assert a + b + b == 92233720368547758080n +} + +function test_subtraction(): void { + const a = 18446744073709551616n; + const b = 36893488147419103232n; + const c = -10000000000000000000n; + + // /* Subtraction testing (-) */ + assert 999999999999999n - 1n == 999999999999998n + assert b - a == a + assert a - b == -18446744073709551616n + assert b - a - a == 0n +} + +function test_inc_dec(): void { + const a = 340282366920938463463374607431768211456n + const b = -2313455919991034304490n + + /* Increment testing */ + /* Decrement testing */ +} + +function test_shift(): void { + const a = 245599210405555256299145n + + /* Testing left shift (<<) */ + assert a << 100n == 311333986486181324779687697000809288883015536628203520n + assert a << 0n == a + + /* Testing right shift (>>) */ + assert a >> 60n == 213023n + assert a >> 0n == a +} + +function test_bitwise(): void { + const a = 123456789123456789123456789123456789123456789123456789n + let b = 123456790n + const zero = 0n + + /* Testing bitwise NOT (~) */ + assert ~zero == -1n + assert ~a == -123456789123456789123456789123456789123456789123456790n + + /* Testing bitwise AND (&) */ + /* Testing bitwise XOR (^) */ + /* Testing bitwise OR (|) */ +} + +function main() : void { + test_create_empty_bigint(); + test_bigint_as_string(); + test_invalid_bigint(); + test_multiply(); + test_plus(); + test_minus(); + test_unary_minus(); + test_divide(); + test_module(); + test_bitwise_and(); + test_bitwise_or(); + test_bitwise_xor(); + test_left_shift(); + test_right_shift(); + test_type(); + test_assignment(); + test_compare(); + test_literals(); + test_cast(); + test_bigint_methods(); + test_unary(); + test_multiplication(); + test_addition_1(); + test_addition_2(); + test_subtraction(); + test_inc_dec(); + test_shift(); + test_bitwise(); +} -- Gitee From b3933c5b38b0bce42f0930e7d6bff492571a23cd Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Thu, 28 Dec 2023 14:01:23 +0300 Subject: [PATCH 15/24] Title: Fix a bug when importing identical interfaces Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8S5EF Description: Fix a bug when importing identical interfaces from different files Test: ${ARK_SOURCE_DIR}/tests/tests-u-runner/runner.sh ${ARK_SOURCE_DIR} --parser --build-dir="${ARK_BUILD_DIR}" --force-generate --test-file parser/ets/import_tests/import_interface_test.ets Signed-off-by: Anna Antipina --- ets2panda/parser/ETSparser.cpp | 4 +- .../import_interface_test-expected.txt | 1162 +++++++++++++++++ .../import_tests/import_interface_test.ets | 32 + .../import_interface_test_1-expected.txt | 291 +++++ .../import_tests/import_interface_test_1.ets | 18 + .../import_interface_test_2-expected.txt | 552 ++++++++ .../import_tests/import_interface_test_2.ets | 22 + 7 files changed, 2080 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test.ets create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test_1-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test_1.ets create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test_2-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/import_interface_test_2.ets diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 150e17f0e7..a150b7a125 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -187,7 +187,9 @@ void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVecto end(items)); for (const auto &item : items) { - parsed_sources_.push_back(ResolveImportPath(item)); + auto resolved = ResolveImportPath(item); + resolved_parsed_sources_.emplace(item, resolved); + parsed_sources_.push_back(resolved); } }; diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test-expected.txt b/ets2panda/test/parser/ets/import_tests/import_interface_test-expected.txt new file mode 100644 index 0000000000..dcc9310ba5 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test-expected.txt @@ -0,0 +1,1162 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./", + "loc": { + "start": { + "line": 16, + "column": 25 + }, + "end": { + "line": 16, + "column": 52 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "MyClass", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 17 + } + } + }, + "imported": { + "type": "Identifier", + "name": "MyClass", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 53 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./", + "loc": { + "start": { + "line": 17, + "column": 31 + }, + "end": { + "line": 17, + "column": 58 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "imported": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 23 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 59 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "MyClass2", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 19, + "column": 15 + } + } + }, + "superClass": null, + "implements": [ + { + "type": "TSClassImplements", + "expression": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 42 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 42 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 27 + }, + "end": { + "line": 19, + "column": 42 + } + } + } + ], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 9 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 9 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 20, + "column": 13 + }, + "end": { + "line": 20, + "column": 16 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 21, + "column": 16 + }, + "end": { + "line": 21, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 22, + "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": 23, + "column": 2 + }, + "end": { + "line": 23, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 41 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 23, + "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 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 25, + "column": 10 + }, + "end": { + "line": 25, + "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": 25, + "column": 10 + }, + "end": { + "line": 25, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "myclass1", + "decorators": [], + "loc": { + "start": { + "line": 26, + "column": 11 + }, + "end": { + "line": 26, + "column": 19 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "MyClass", + "decorators": [], + "loc": { + "start": { + "line": 26, + "column": 26 + }, + "end": { + "line": 26, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 26 + }, + "end": { + "line": 26, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 26 + }, + "end": { + "line": 26, + "column": 34 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 26, + "column": 22 + }, + "end": { + "line": 26, + "column": 36 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 11 + }, + "end": { + "line": 26, + "column": 36 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 36 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "myclass2", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 11 + }, + "end": { + "line": 27, + "column": 19 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "MyClass2", + "decorators": [], + "loc": { + "start": { + "line": 27, + "column": 26 + }, + "end": { + "line": 27, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 26 + }, + "end": { + "line": 27, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 26 + }, + "end": { + "line": 27, + "column": 35 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 27, + "column": 22 + }, + "end": { + "line": 27, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 11 + }, + "end": { + "line": 27, + "column": 37 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 37 + } + } + }, + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "+", + "left": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "myclass1", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 10 + }, + "end": { + "line": 28, + "column": 18 + } + } + }, + "property": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 19 + }, + "end": { + "line": 28, + "column": 23 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 28, + "column": 10 + }, + "end": { + "line": 28, + "column": 23 + } + } + }, + "arguments": [], + "optional": false, + "loc": { + "start": { + "line": 28, + "column": 10 + }, + "end": { + "line": 28, + "column": 25 + } + } + }, + "right": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "myclass2", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 36 + } + } + }, + "property": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 37 + }, + "end": { + "line": 28, + "column": 41 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 41 + } + } + }, + "arguments": [], + "optional": false, + "loc": { + "start": { + "line": 28, + "column": 28 + }, + "end": { + "line": 28, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 44 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 3, + "loc": { + "start": { + "line": 28, + "column": 48 + }, + "end": { + "line": 28, + "column": 49 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 49 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 29, + "column": 16 + }, + "end": { + "line": 29, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 9 + }, + "end": { + "line": 29, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 28, + "column": 51 + }, + "end": { + "line": 30, + "column": 6 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 28, + "column": 5 + }, + "end": { + "line": 30, + "column": 6 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 31, + "column": 12 + }, + "end": { + "line": 31, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 31, + "column": 5 + }, + "end": { + "line": 31, + "column": 13 + } + } + } + ], + "loc": { + "start": { + "line": 25, + "column": 17 + }, + "end": { + "line": 32, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 14 + }, + "end": { + "line": 32, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 14 + }, + "end": { + "line": 32, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 32, + "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": 33, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test.ets b/ets2panda/test/parser/ets/import_tests/import_interface_test.ets new file mode 100644 index 0000000000..24a8dd3bb4 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 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 { MyClass } from './import_interface_test_2'; +import { SameInterface } from './import_interface_test_1'; + +class MyClass2 implements SameInterface { + test(): int { + return 2; + } +} + +function main() { + const myclass1 = new MyClass(); + const myclass2 = new MyClass2(); + if ((myclass1.test() + myclass2.test()) == 3) { + return 0 + } + return 1 +} diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test_1-expected.txt b/ets2panda/test/parser/ets/import_tests/import_interface_test_1-expected.txt new file mode 100644 index 0000000000..ba2937c493 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test_1-expected.txt @@ -0,0 +1,291 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSInterfaceDeclaration", + "body": { + "type": "TSInterfaceBody", + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 17, + "column": 12 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "declare": true, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 16 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 32 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "id": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 31 + } + } + }, + "extends": [], + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 19, + "column": 1 + } + } + }, + { + "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": 19, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test_1.ets b/ets2panda/test/parser/ets/import_tests/import_interface_test_1.ets new file mode 100644 index 0000000000..6dd7e5a267 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test_1.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 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 interface SameInterface { + test():int; +} diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test_2-expected.txt b/ets2panda/test/parser/ets/import_tests/import_interface_test_2-expected.txt new file mode 100644 index 0000000000..016b5bf188 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test_2-expected.txt @@ -0,0 +1,552 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./", + "loc": { + "start": { + "line": 16, + "column": 31 + }, + "end": { + "line": 16, + "column": 58 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "imported": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 23 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 59 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "MyClass", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 14 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "superClass": null, + "implements": [ + { + "type": "TSClassImplements", + "expression": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "SameInterface", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 33 + }, + "end": { + "line": 18, + "column": 46 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 33 + }, + "end": { + "line": 18, + "column": 48 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 33 + }, + "end": { + "line": 18, + "column": 48 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 33 + }, + "end": { + "line": 18, + "column": 48 + } + } + } + ], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 9 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "test", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 9 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 19, + "column": 13 + }, + "end": { + "line": 19, + "column": 16 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 16 + }, + "end": { + "line": 20, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 9 + }, + "end": { + "line": 20, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 21, + "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": 22, + "column": 2 + }, + "end": { + "line": 22, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 47 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 8 + }, + "end": { + "line": 22, + "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": 22, + "column": 2 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/import_interface_test_2.ets b/ets2panda/test/parser/ets/import_tests/import_interface_test_2.ets new file mode 100644 index 0000000000..44c393de33 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_interface_test_2.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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 { SameInterface } from './import_interface_test_1'; + +export class MyClass implements SameInterface { + test(): int { + return 1; + } +} \ No newline at end of file -- Gitee From b16fb5d61bce1c6335364a3f7e5fc79fbe7d65b9 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Tue, 26 Dec 2023 19:58:28 +0300 Subject: [PATCH 16/24] Implement IsSupertypeOf relation, implement default TypeParam constraint Signed-off-by: Vsevolod Pukhov --- ets2panda/checker/ETSAnalyzer.cpp | 5 +-- ets2panda/checker/ETSchecker.h | 4 +- ets2panda/checker/checker.h | 6 +++ ets2panda/checker/ets/conversion.cpp | 18 ++++---- ets2panda/checker/ets/function.cpp | 31 ++++---------- ets2panda/checker/ets/helpers.cpp | 42 +++++++++++-------- ets2panda/checker/ets/object.cpp | 35 +++++++++------- ets2panda/checker/ets/typeRelationContext.cpp | 28 ++++++------- ets2panda/checker/types/ets/etsObjectType.cpp | 15 ++----- .../checker/types/ets/etsTypeParameter.cpp | 35 +++++----------- .../checker/types/ets/etsTypeParameter.h | 19 +-------- ets2panda/checker/types/ets/etsUnionType.cpp | 24 ++++------- ets2panda/checker/types/ets/etsUnionType.h | 1 + ets2panda/checker/types/type.cpp | 5 +++ ets2panda/checker/types/type.h | 1 + ets2panda/checker/types/typeRelation.cpp | 23 ++++++++++ ets2panda/checker/types/typeRelation.h | 3 +- ets2panda/compiler/core/ETSGen.cpp | 6 ++- ets2panda/ir/expressions/memberExpression.cpp | 2 +- ets2panda/ir/ts/tsTypeAliasDeclaration.h | 17 +++++++- ets2panda/parser/ETSparser.cpp | 2 +- ets2panda/test/runtime/ets/NoConstraint.ets | 29 +++++++++++++ .../test-lists/parser/parser-js-ignored.txt | 9 ++++ 23 files changed, 199 insertions(+), 161 deletions(-) create mode 100644 ets2panda/test/runtime/ets/NoConstraint.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 3b04d8f582..27894723e2 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1156,7 +1156,7 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const // NOTE(vpukhov): #14902 substituted signature is not updated } expr->SetOptionalType(return_type); - if (expr->IsOptional() && callee_type->IsNullishOrNullLike()) { + if (expr->IsOptional() && checker->MayHaveNulllikeValue(expr->Callee()->Check(checker))) { checker->Relation()->SetNode(expr); return_type = checker->CreateOptionalResultType(return_type); checker->Relation()->SetNode(nullptr); @@ -2753,6 +2753,7 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const { ETSChecker *checker = GetETSChecker(); if (st->TypeParams() != nullptr) { + st->SetTypeParameterTypes(checker->CreateTypeForTypeParameters(st->TypeParams())); for (auto *const param : st->TypeParams()->Params()) { const auto *const res = st->TypeAnnotation()->FindChild([¶m](const ir::AstNode *const node) { if (!node->IsIdentifier()) { @@ -2767,8 +2768,6 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const {"Type alias generic parameter '", param->Name()->Name(), "' is not used in type annotation"}, param->Start()); } - - checker->SetUpParameterType(param); } } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 6b9add7581..d20eb82595 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -182,6 +182,7 @@ public: Type *FindLeastUpperBound(Type *source, Type *target); static Type *GetApparentType(Type *type); static Type const *GetApparentType(Type const *type); + Type *MaybePromotedBuiltinType(Type *type) const; Type *GetCommonClass(Type *source, Type *target); ETSObjectType *GetClosestCommonAncestor(ETSObjectType *source, ETSObjectType *target); ETSObjectType *GetTypeargumentedLUB(ETSObjectType *source, ETSObjectType *target); @@ -300,6 +301,7 @@ public: { return Allocator()->New>(Allocator()->Adapter()); } + ArenaVector CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const *type_params); [[nodiscard]] bool EnhanceSubstitutionForType(const ArenaVector &type_params, Type *param_type, Type *argument_type, Substitution *substitution, ArenaUnorderedSet *instantiated_type_params); @@ -659,8 +661,6 @@ private: return is_construct ? &dynamic_new_intrinsics_ : &dynamic_call_intrinsics_; } - ArenaVector CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *type_params); - using Type2TypeMap = std::unordered_map; void CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends); diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index d411772aa9..04d7708dfb 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -134,6 +134,11 @@ public: return unchecked_castable_results_; } + RelationHolder &SupertypeResults() + { + return supertype_results_; + } + std::unordered_set &TypeStack() { return type_stack_; @@ -212,6 +217,7 @@ private: RelationHolder assignable_results_; RelationHolder comparable_results_; RelationHolder unchecked_castable_results_; + RelationHolder supertype_results_; std::unordered_set type_stack_; }; diff --git a/ets2panda/checker/ets/conversion.cpp b/ets2panda/checker/ets/conversion.cpp index 226eb0a571..4d4833b4af 100644 --- a/ets2panda/checker/ets/conversion.cpp +++ b/ets2panda/checker/ets/conversion.cpp @@ -52,20 +52,17 @@ void WideningNarrowingPrimitive(TypeRelation *const relation, ByteType *const so void WideningReference(TypeRelation *const relation, ETSObjectType *const source, ETSObjectType *const target) { - relation->Result(false); - target->IsSupertypeOf(relation, source); + relation->IsSupertypeOf(target, source); } void WideningReference(TypeRelation *const relation, ETSArrayType *const source, ETSObjectType *const target) { - relation->Result(false); - target->IsSupertypeOf(relation, source); + relation->IsSupertypeOf(target, source); } void WideningReference(TypeRelation *const relation, ETSArrayType *const source, ETSArrayType *const target) { - relation->Result(false); - target->IsSupertypeOf(relation, source); + relation->IsSupertypeOf(target, source); } namespace { @@ -80,7 +77,7 @@ bool IsAllowedNarrowingReferenceConversion(TypeRelation *const relation, Type *c // - S is not a subtype of T relation->Result(false); - if (target->IsSupertypeOf(relation, source), relation->IsTrue()) { + if (relation->IsSupertypeOf(target, source)) { return false; } @@ -97,8 +94,7 @@ bool IsAllowedNarrowingReferenceConversion(TypeRelation *const relation, Type *c // 1. S and T are class types, and either |S| <: |T| or |T| <: |S|. // NOTE: use type erased S and T relation->Result(false); - if ((t->IsSupertypeOf(relation, s), relation->IsTrue()) || - (s->IsSupertypeOf(relation, t), relation->IsTrue())) { + if (relation->IsSupertypeOf(t, s) || relation->IsSupertypeOf(s, t)) { return true; } @@ -116,7 +112,7 @@ bool IsAllowedNarrowingReferenceConversion(TypeRelation *const relation, Type *c // 4. S is a class type, T is an interface type, and S names a class that is marked as final and that // implements the interface named by T. if (s->HasObjectFlag(ETSObjectFlags::CLASS) && t->HasObjectFlag(ETSObjectFlags::INTERFACE) && - s->GetDeclNode()->IsFinal() && (s->IsSupertypeOf(relation, t), relation->IsTrue())) { + s->GetDeclNode()->IsFinal() && relation->IsSupertypeOf(s, t)) { return true; } @@ -130,7 +126,7 @@ bool IsAllowedNarrowingReferenceConversion(TypeRelation *const relation, Type *c // implements the interface named by S. relation->Result(false); if (s->HasObjectFlag(ETSObjectFlags::INTERFACE) && t->HasObjectFlag(ETSObjectFlags::CLASS) && - t->GetDeclNode()->IsFinal() && (t->IsSupertypeOf(relation, s), relation->IsTrue())) { + t->GetDeclNode()->IsFinal() && relation->IsSupertypeOf(t, s)) { return true; } } diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index b88f2aaf38..54fe77d410 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -67,6 +67,7 @@ namespace panda::es2panda::checker { +// NOTE: #14993 merge with InstantiationContext::ValidateTypeArg bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *type_param, Type *type_argument, const Substitution *substitution) { @@ -76,21 +77,8 @@ bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *type_param, Type *ty if (!type_argument->IsETSTypeParameter() && !IsReferenceType(type_argument)) { return false; } - if (type_argument->IsETSUnionType()) { - auto const &constitutent = type_argument->AsETSUnionType()->ConstituentTypes(); - return std::all_of(constitutent.begin(), constitutent.end(), [this, type_param, substitution](Type *type_arg) { - return IsCompatibleTypeArgument(type_param->AsETSTypeParameter(), type_arg, substitution); - }); - } - - if (auto *constraint = type_param->GetConstraintType(); constraint != nullptr) { - constraint = constraint->Substitute(Relation(), substitution); - constraint->IsSupertypeOf(Relation(), type_argument); - if (!Relation()->IsTrue()) { - return false; - } - } - return true; + auto *constraint = type_param->GetConstraintType()->Substitute(Relation(), substitution); + return Relation()->IsSupertypeOf(constraint, type_argument); } /* A very rough and imprecise partial type inference */ @@ -1056,9 +1044,9 @@ bool ETSChecker::IsOverridableIn(Signature *signature) return false; } - if (signature->HasSignatureFlag(SignatureFlags::PUBLIC)) { - return FindAncestorGivenByType(signature->Function(), ir::AstNodeType::TS_INTERFACE_DECLARATION) == nullptr || - signature->HasSignatureFlag(SignatureFlags::STATIC); + // NOTE: #15095 workaround, separate internal visibility check + if (signature->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::INTERNAL)) { + return true; } return signature->HasSignatureFlag(SignatureFlags::PROTECTED); @@ -1080,7 +1068,6 @@ bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source) if (Relation()->IsTrue()) { CheckThrowMarkers(source, target); - CheckStaticHide(target, source); if (source->HasSignatureFlag(SignatureFlags::STATIC)) { return false; } @@ -1199,7 +1186,8 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) (it_subst->Function()->IsGetter() && !signature->Function()->IsGetter())) { continue; } - } else if (!IsMethodOverridesOther(it_subst, signature)) { + } + if (!IsMethodOverridesOther(it_subst, signature)) { continue; } @@ -2606,8 +2594,7 @@ bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const // - If R1 is a reference type then R1, adapted to the type parameters of d2 (link to generic methods), is a // subtype of R2. ASSERT(r1->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT) || r1->IsETSTypeParameter()); - r2->IsSupertypeOf(Relation(), r1); - return Relation()->IsTrue(); + return Relation()->IsSupertypeOf(r2, r1); } std::string ETSChecker::GetAsyncImplName(const util::StringView &name) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a85e51ff5e..8b5b137960 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -169,37 +169,43 @@ Type *ETSChecker::CreateOptionalResultType(Type *type) return CreateNullishType(type, checker::TypeFlag::UNDEFINED, Allocator(), Relation(), GetGlobalTypesHolder()); } -bool ETSChecker::MayHaveNullValue(const Type *type) const +// NOTE(vpukhov): #14595 could be implemented with relation +template +static bool MatchConstitutentOrConstraint(P const &pred, const Type *type) { - if (type->ContainsNull() || type->IsETSNullType()) { + if (pred(type)) { return true; } + if (type->IsETSUnionType()) { + for (auto const &ctype : type->AsETSUnionType()->ConstituentTypes()) { + if (MatchConstitutentOrConstraint(pred, ctype)) { + return true; + } + } + return false; + } if (type->IsETSTypeParameter()) { - return MayHaveNullValue(type->AsETSTypeParameter()->EffectiveConstraint(this)); + return MatchConstitutentOrConstraint(pred, type->AsETSTypeParameter()->GetConstraintType()); } return false; } +bool ETSChecker::MayHaveNullValue(const Type *type) const +{ + const auto pred = [](const Type *t) { return t->ContainsNull() || t->IsETSNullType(); }; + return MatchConstitutentOrConstraint(pred, type); +} + bool ETSChecker::MayHaveUndefinedValue(const Type *type) const { - if (type->ContainsUndefined() || type->IsETSUndefinedType()) { - return true; - } - if (type->IsETSTypeParameter()) { - return MayHaveUndefinedValue(type->AsETSTypeParameter()->EffectiveConstraint(this)); - } - return false; + const auto pred = [](const Type *t) { return t->ContainsUndefined() || t->IsETSUndefinedType(); }; + return MatchConstitutentOrConstraint(pred, type); } bool ETSChecker::MayHaveNulllikeValue(const Type *type) const { - if (type->IsNullishOrNullLike()) { - return true; - } - if (type->IsETSTypeParameter()) { - return MayHaveNulllikeValue(type->AsETSTypeParameter()->EffectiveConstraint(this)); - } - return false; + const auto pred = [](const Type *t) { return t->IsNullishOrNullLike(); }; + return MatchConstitutentOrConstraint(pred, type); } bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type) @@ -354,7 +360,7 @@ Type *ETSChecker::GuaranteedTypeForUncheckedCast(Type *base, Type *substituted) if (!base->IsETSTypeParameter()) { return nullptr; } - auto *constr = base->AsETSTypeParameter()->EffectiveConstraint(this); + auto *constr = base->AsETSTypeParameter()->GetConstraintType(); // Constraint is supertype of TypeArg AND TypeArg is supertype of Constraint return Relation()->IsIdenticalTo(substituted, constr) ? nullptr : constr; } diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 7eb2c01c4f..bcf80ce470 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "boxingConverter.h" #include "varbinder/variableFlags.h" #include "checker/ets/castingContext.h" #include "checker/types/ets/etsObjectType.h" @@ -166,7 +167,7 @@ ArenaVector ETSChecker::GetInterfaces(ETSObjectType *type) return type->Interfaces(); } -ArenaVector ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *type_params) +ArenaVector ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const *type_params) { ArenaVector result {Allocator()->Adapter()}; checker::ScopeContext scope_ctx(this, type_params->Scope()); @@ -248,12 +249,14 @@ void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param) ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start()); } param_type->SetConstraintType(constraint); + } else { + param_type->SetConstraintType(GlobalETSNullishObjectType()); } + if (param->DefaultType() != nullptr) { traverse_referenced(param->DefaultType()); - auto *const dflt = param->DefaultType()->GetType(this); // NOTE: #14993 ensure default matches constraint - param_type->SetDefaultType(dflt); + param_type->SetDefaultType(MaybePromotedBuiltinType(param->DefaultType()->GetType(this))); } } @@ -264,6 +267,8 @@ ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const para param_type->AddTypeFlag(TypeFlag::GENERIC); param_type->SetDeclNode(param); param_type->SetVariable(param->Variable()); + // NOTE: #15026 recursive type parameter workaround + param_type->SetConstraintType(GlobalETSNullishObjectType()); param->Name()->Variable()->SetTsType(param_type); return param_type; @@ -1527,22 +1532,25 @@ Type *ETSChecker::FindLeastUpperBound(Type *source, Type *target) Type *ETSChecker::GetApparentType(Type *type) { - if (type->IsETSTypeParameter()) { - auto *const param = type->AsETSTypeParameter(); - return param->HasConstraint() ? param->GetConstraintType() : param; + while (type->IsETSTypeParameter()) { + type = type->AsETSTypeParameter()->GetConstraintType(); } return type; } Type const *ETSChecker::GetApparentType(Type const *type) { - if (type->IsETSTypeParameter()) { - auto *const param = type->AsETSTypeParameter(); - return param->HasConstraint() ? param->GetConstraintType() : param; + while (type->IsETSTypeParameter()) { + type = type->AsETSTypeParameter()->GetConstraintType(); } return type; } +Type *ETSChecker::MaybePromotedBuiltinType(Type *type) const +{ + return type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) ? checker::BoxingConverter::ETSTypeFromSource(this, type) : type; +} + Type *ETSChecker::GetCommonClass(Type *source, Type *target) { SavedTypeRelationFlagsContext checker_ctx(this->Relation(), TypeRelationFlag::IGNORE_TYPE_PARAMETERS); @@ -1551,13 +1559,11 @@ Type *ETSChecker::GetCommonClass(Type *source, Type *target) return source; } - target->IsSupertypeOf(Relation(), source); - if (Relation()->IsTrue()) { + if (Relation()->IsSupertypeOf(target, source)) { return target; } - source->IsSupertypeOf(Relation(), target); - if (Relation()->IsTrue()) { + if (Relation()->IsSupertypeOf(source, target)) { return source; } @@ -1590,8 +1596,7 @@ ETSObjectType *ETSChecker::GetClosestCommonAncestor(ETSObjectType *source, ETSOb auto *source_base = GetOriginalBaseType(source); auto *source_type = source_base == nullptr ? source : source_base; - target_type->IsSupertypeOf(Relation(), source_type); - if (Relation()->IsTrue()) { + if (Relation()->IsSupertypeOf(target_type, source_type)) { // NOTE: TorokG. Extending the search to find intersection types return target_type; } diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index cbc061f0b9..0413974023 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -14,6 +14,7 @@ */ #include "typeRelationContext.h" +#include "boxingConverter.h" #include "varbinder/scope.h" #include "varbinder/variable.h" #include "varbinder/declaration.h" @@ -61,12 +62,15 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType extends "Comparable", we will get an error here. */ - auto const get_types = [this, &type_args, type](size_t idx) -> std::pair { + auto const is_defaulted = [type_args](size_t idx) { + return type_args == nullptr || idx >= type_args->Params().size(); + }; + + auto const get_types = [this, &type_args, type, is_defaulted](size_t idx) -> std::pair { auto *type_param = type->TypeArguments().at(idx)->AsETSTypeParameter(); - if (type_args != nullptr && idx < type_args->Params().size()) { - return {type_param, type_args->Params().at(idx)->GetType(checker_)}; - } - return {type_param, type_param->GetDefaultType()}; + return {type_param, is_defaulted(idx) + ? type_param->GetDefaultType() + : checker_->MaybePromotedBuiltinType(type_args->Params().at(idx)->GetType(checker_))}; }; auto *const substitution = checker_->NewSubstitution(); @@ -88,7 +92,7 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType if (!ValidateTypeArg(constraint, type_arg) && type_args != nullptr && !checker_->Relation()->NoThrowGenericTypeAlias()) { checker_->ThrowTypeError({"Type '", type_arg, "' is not assignable to constraint type '", constraint, "'."}, - type_args->Params().at(idx)->Start()); + is_defaulted(idx) ? pos : type_args->Params().at(idx)->Start()); } } @@ -97,16 +101,10 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType bool InstantiationContext::ValidateTypeArg(Type *constraint_type, Type *type_arg) { - if (!ETSChecker::IsReferenceType(type_arg)) { - return false; - } - - if (type_arg->IsETSUnionType()) { - auto const &constituent_types = type_arg->AsETSUnionType()->ConstituentTypes(); - return std::all_of(constituent_types.begin(), constituent_types.end(), - [this, constraint_type](Type *c_type) { return ValidateTypeArg(constraint_type, c_type); }); + // NOTE: #14993 enforce ETSChecker::IsReferenceType + if (type_arg->IsWildcardType()) { + return true; } - return checker_->Relation()->IsAssignableTo(type_arg, constraint_type); } diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 8b74d27413..45d0171b19 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -436,7 +436,7 @@ void ETSObjectType::AssignmentTarget(TypeRelation *const relation, Type *source) return; } - IsSupertypeOf(relation, source); + relation->IsSupertypeOf(this, source); } bool ETSObjectType::CastWideningNarrowing(TypeRelation *const relation, Type *const target, TypeFlag unbox_flags, @@ -627,11 +627,6 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) return; } - if (source->IsETSTypeParameter()) { - source->AsETSTypeParameter()->ConstraintIsSubtypeOf(relation, this); - return; - } - if (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE | ETSObjectFlags::NULL_TYPE)) { @@ -642,7 +637,7 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) return; } // All classes and interfaces are subtypes of Object - if (base == ets_checker->GlobalETSObjectType()) { + if (base == ets_checker->GlobalETSObjectType() || base == ets_checker->GlobalETSNullishObjectType()) { relation->Result(true); return; } @@ -654,16 +649,14 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) ETSObjectType *source_obj = source->AsETSObjectType(); if (auto *source_super = source_obj->SuperType(); source_super != nullptr) { - IsSupertypeOf(relation, source_super); - if (relation->IsTrue()) { + if (relation->IsSupertypeOf(this, source_super)) { return; } } if (HasObjectFlag(ETSObjectFlags::INTERFACE)) { for (auto *itf : source_obj->Interfaces()) { - IsSupertypeOf(relation, itf); - if (relation->IsTrue()) { + if (relation->IsSupertypeOf(this, itf)) { return; } } diff --git a/ets2panda/checker/types/ets/etsTypeParameter.cpp b/ets2panda/checker/types/ets/etsTypeParameter.cpp index d19a6ef116..f3ea0c6799 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -70,14 +70,13 @@ void ETSTypeParameter::AssignmentTarget([[maybe_unused]] TypeRelation *relation, return; } - IsSupertypeOf(relation, source); + relation->IsSupertypeOf(this, source); } void ETSTypeParameter::Cast(TypeRelation *relation, Type *target) { - if (target->IsSupertypeOf(relation, this), relation->IsTrue()) { + if (relation->IsSupertypeOf(target, this)) { relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST); - relation->Result(true); return; } @@ -90,9 +89,8 @@ void ETSTypeParameter::Cast(TypeRelation *relation, Type *target) void ETSTypeParameter::CastTarget(TypeRelation *relation, Type *source) { - if (IsSupertypeOf(relation, source), relation->IsTrue()) { + if (relation->IsSupertypeOf(this, source)) { relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST); - relation->Result(true); return; } @@ -101,12 +99,12 @@ void ETSTypeParameter::CastTarget(TypeRelation *relation, Type *source) void ETSTypeParameter::IsSupertypeOf([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) { - if (Identical(relation, source), relation->IsTrue()) { - return; - } + relation->Result(false); +} - if (source->IsETSTypeParameter()) { - source->AsETSTypeParameter()->ConstraintIsSubtypeOf(relation, this); +void ETSTypeParameter::IsSubtypeOf([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->IsSupertypeOf(target, GetConstraintType())) { return; } @@ -157,27 +155,14 @@ Type *ETSTypeParameter::Substitute(TypeRelation *relation, const Substitution *s return this; } -Type *ETSTypeParameter::EffectiveConstraint(ETSChecker const *checker) const -{ - return HasConstraint() ? GetConstraintType() : checker->GlobalETSNullishObjectType(); -} - void ETSTypeParameter::ToAssemblerType(std::stringstream &ss) const { - if (HasConstraint()) { - GetConstraintType()->ToAssemblerType(ss); - } else { - ss << compiler::Signatures::BUILTIN_OBJECT; - } + GetConstraintType()->ToAssemblerType(ss); } void ETSTypeParameter::ToDebugInfoType(std::stringstream &ss) const { - if (HasConstraint()) { - GetConstraintType()->ToDebugInfoType(ss); - } else { - ETSObjectType::DebugInfoTypeFromName(ss, compiler::Signatures::BUILTIN_OBJECT); - } + GetConstraintType()->ToDebugInfoType(ss); } ETSTypeParameter *ETSTypeParameter::GetOriginal() const diff --git a/ets2panda/checker/types/ets/etsTypeParameter.h b/ets2panda/checker/types/ets/etsTypeParameter.h index d39645a555..79657fa0b6 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.h +++ b/ets2panda/checker/types/ets/etsTypeParameter.h @@ -57,16 +57,10 @@ public: Type *GetConstraintType() const { + ASSERT(constraint_ != nullptr); return constraint_; } - bool HasConstraint() const - { - return GetConstraintType() != nullptr; - } - - Type *EffectiveConstraint(ETSChecker const *checker) const; - void ToString(std::stringstream &ss) const override; void Identical(TypeRelation *relation, Type *other) override; void AssignmentTarget(TypeRelation *relation, Type *source) override; @@ -74,19 +68,10 @@ public: void Cast(TypeRelation *relation, Type *target) override; void CastTarget(TypeRelation *relation, Type *source) override; void IsSupertypeOf(TypeRelation *relation, Type *source) override; + void IsSubtypeOf(TypeRelation *relation, Type *target) override; Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *global_types) override; Type *Substitute(TypeRelation *relation, const Substitution *substitution) override; - bool ConstraintIsSubtypeOf(TypeRelation *relation, Type *target) - { - if (HasConstraint()) { - target->IsSupertypeOf(relation, GetConstraintType()); - } else { - relation->Result(false); - } - return relation->IsTrue(); - } - void ToAssemblerType(std::stringstream &ss) const override; void ToDebugInfoType(std::stringstream &ss) const override; diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 270824e945..98653a9732 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -209,8 +209,7 @@ void ETSUnionType::NormalizeTypes(TypeRelation *relation, ArenaVector &c auto new_end = std::remove_if( constituent_types.begin(), constituent_types.end(), [relation, checker, cmp_it, number_found](Type *ct) { bool both_constants = (*cmp_it)->HasTypeFlag(TypeFlag::CONSTANT) && ct->HasTypeFlag(TypeFlag::CONSTANT); - relation->Result(false); - (*cmp_it)->IsSupertypeOf(relation, ct); + relation->IsSupertypeOf((*cmp_it), ct); bool remove_subtype = ct != *cmp_it && !both_constants && relation->IsTrue(); bool remove_numeric = number_found && ct->IsETSObjectType() && ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && @@ -298,27 +297,20 @@ void ETSUnionType::Cast(TypeRelation *relation, Type *target) void ETSUnionType::IsSupertypeOf(TypeRelation *relation, Type *source) { - relation->Result(false); - - if (source->IsETSUnionType()) { - for (auto const &source_ctype : source->AsETSUnionType()->ConstituentTypes()) { - if (IsSupertypeOf(relation, source_ctype), !relation->IsTrue()) { - return; - } + for (auto const &ctype : ConstituentTypes()) { + if (relation->IsSupertypeOf(ctype, source)) { + return; } - return; } +} +void ETSUnionType::IsSubtypeOf(TypeRelation *relation, Type *target) +{ for (auto const &ctype : ConstituentTypes()) { - if (ctype->IsSupertypeOf(relation, source), relation->IsTrue()) { + if (!relation->IsSupertypeOf(target, ctype)) { return; } } - - if (source->IsETSTypeParameter()) { - source->AsETSTypeParameter()->ConstraintIsSubtypeOf(relation, this); - return; - } } void ETSUnionType::CastTarget(TypeRelation *relation, Type *source) diff --git a/ets2panda/checker/types/ets/etsUnionType.h b/ets2panda/checker/types/ets/etsUnionType.h index 39dc90ec1f..2c6da2652c 100644 --- a/ets2panda/checker/types/ets/etsUnionType.h +++ b/ets2panda/checker/types/ets/etsUnionType.h @@ -43,6 +43,7 @@ public: void Cast(TypeRelation *relation, Type *target) override; void CastTarget(TypeRelation *relation, Type *source) override; void IsSupertypeOf(TypeRelation *relation, Type *source) override; + void IsSubtypeOf(TypeRelation *relation, Type *target) override; Type *FindTypeIsCastableToThis(ir::Expression *node, TypeRelation *relation, Type *source) const; Type *FindTypeIsCastableToSomeType(ir::Expression *node, TypeRelation *relation, Type *target) const; Type *FindUnboxableType() const; diff --git a/ets2panda/checker/types/type.cpp b/ets2panda/checker/types/type.cpp index 054852e1b2..239bcf0080 100644 --- a/ets2panda/checker/types/type.cpp +++ b/ets2panda/checker/types/type.cpp @@ -120,6 +120,11 @@ void Type::IsSupertypeOf(TypeRelation *const relation, [[maybe_unused]] Type *so relation->Result(false); } +void Type::IsSubtypeOf(TypeRelation *const relation, [[maybe_unused]] Type *target) +{ + relation->Result(false); +} + Type *Type::AsSuper([[maybe_unused]] Checker *checker, [[maybe_unused]] varbinder::Variable *source_var) { return nullptr; diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 0d8a0da4a3..b0bd53e4b0 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -251,6 +251,7 @@ public: virtual void Cast(TypeRelation *relation, Type *target); virtual void CastTarget(TypeRelation *relation, Type *source); virtual void IsSupertypeOf(TypeRelation *relation, Type *source); + virtual void IsSubtypeOf(TypeRelation *relation, Type *target); virtual Type *AsSuper(Checker *checker, varbinder::Variable *source_var); virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *global_types); diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index a3453c5190..2e0b44bf40 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -173,6 +173,29 @@ bool TypeRelation::IsCastableTo(Type *const source, Type *const target) return result_ == RelationResult::TRUE; } +bool TypeRelation::IsSupertypeOf(Type *super, Type *sub) +{ + result_ = CacheLookup(super, sub, checker_->SupertypeResults(), RelationType::SUPERTYPE); + + if (result_ == RelationResult::CACHE_MISS) { + if (IsIdenticalTo(super, sub)) { + return true; + } + + result_ = RelationResult::FALSE; + + if (super->IsSupertypeOf(this, sub), !IsTrue()) { + sub->IsSubtypeOf(this, super); + } + + if (flags_ == TypeRelationFlag::NONE) { + checker_->SupertypeResults().cached.insert({{super->Id(), sub->Id()}, {result_, RelationType::SUPERTYPE}}); + } + } + + return result_ == RelationResult::TRUE; +} + void TypeRelation::RaiseError(const std::string &err_msg, const lexer::SourcePosition &loc) const { checker_->ThrowTypeError(err_msg, loc); diff --git a/ets2panda/checker/types/typeRelation.h b/ets2panda/checker/types/typeRelation.h index 4e7cff3141..b7f5002b6f 100644 --- a/ets2panda/checker/types/typeRelation.h +++ b/ets2panda/checker/types/typeRelation.h @@ -69,7 +69,7 @@ enum class TypeRelationFlag : uint32_t { enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS, ERROR }; -enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL, UNCHECKED_CASTABLE }; +enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL, UNCHECKED_CASTABLE, SUPERTYPE }; DEFINE_BITOPS(TypeRelationFlag) @@ -265,6 +265,7 @@ public: bool IsAssignableTo(Type *source, Type *target); bool IsComparableTo(Type *source, Type *target); bool IsCastableTo(Type *source, Type *target); + bool IsSupertypeOf(Type *super, Type *sub); void RaiseError(const std::string &err_msg, const lexer::SourcePosition &loc) const; void RaiseError(std::initializer_list list, const lexer::SourcePosition &loc) const; diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 9ebbed8041..f2cf172a27 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -841,6 +841,10 @@ void ETSGen::CheckedReferenceNarrowing(const ir::AstNode *node, const checker::T { ASSERT(target->HasTypeFlag(TYPE_FLAG_BYTECODE_REF) && !target->IsETSNullLike()); // NOTE(vpukhov): implement for nulllike and union targets + if (target == Checker()->GlobalETSNullishObjectType()) { + SetAccumulatorType(target); + return; + } Sa().Emit(node, ToAssemblerType(target)); SetAccumulatorType(target); @@ -1629,7 +1633,7 @@ void ETSGen::CastToArrayOrObject(const ir::AstNode *const node, const checker::T return; } - if (target_type->IsETSTypeParameter() && target_type->AsETSTypeParameter()->HasConstraint()) { + if (target_type->IsETSTypeParameter()) { CheckedReferenceNarrowing(node, target_type->AsETSTypeParameter()->GetConstraintType()); } else if (target_type->IsETSObjectType()) { CheckedReferenceNarrowing(node, target_type->AsETSObjectType()->GetConstOriginalBaseType()); diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 68cfc53cbb..1ff530e538 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -221,7 +221,7 @@ checker::Type *MemberExpression::AdjustType(checker::ETSChecker *checker, checke if (PropVar() != nullptr) { unchecked_type_ = checker->GuaranteedTypeForUncheckedPropertyAccess(PropVar()); } - if (IsOptional() && Object()->TsType()->IsNullishOrNullLike()) { + if (IsOptional() && checker->MayHaveNulllikeValue(Object()->TsType())) { checker->Relation()->SetNode(this); type = checker->CreateOptionalResultType(type); checker->Relation()->SetNode(nullptr); diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h index 9c4415dd5a..ef4ddcb84c 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -34,6 +34,7 @@ public: decorators_(allocator->Adapter()), id_(id), type_params_(type_params), + type_param_types_(allocator->Adapter()), declare_(declare) { } @@ -43,6 +44,7 @@ public: decorators_(allocator->Adapter()), id_(id), type_params_(nullptr), + type_param_types_(allocator->Adapter()), declare_(false) { } @@ -57,7 +59,7 @@ public: return id_; } - const TSTypeParameterDeclaration *TypeParams() const + TSTypeParameterDeclaration *TypeParams() const { return type_params_; } @@ -77,7 +79,7 @@ public: return &Decorators(); } - void AddTypeParameters(ir::TSTypeParameterDeclaration *type_params) + void SetTypeParameters(ir::TSTypeParameterDeclaration *type_params) { type_params_ = type_params; } @@ -92,6 +94,16 @@ public: return !in_ts; } + void SetTypeParameterTypes(ArenaVector &&type_param_types) + { + type_param_types_ = std::move(type_param_types); + } + + ArenaVector const &TypeParameterTypes() const + { + return type_param_types_; + } + void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; @@ -110,6 +122,7 @@ private: ArenaVector decorators_; Identifier *id_; TSTypeParameterDeclaration *type_params_; + ArenaVector type_param_types_; bool declare_; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index a150b7a125..ce756aebcc 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1826,7 +1826,7 @@ ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration() auto options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; ir::TSTypeParameterDeclaration *params = ParseTypeParameterDeclaration(&options); - type_alias_decl->AddTypeParameters(params); + type_alias_decl->SetTypeParameters(params); params->SetParent(type_alias_decl); } diff --git a/ets2panda/test/runtime/ets/NoConstraint.ets b/ets2panda/test/runtime/ets/NoConstraint.ets new file mode 100644 index 0000000000..7c54f31ebb --- /dev/null +++ b/ets2panda/test/runtime/ets/NoConstraint.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 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. + */ + +type NullishFoo = Object | null | undefined; + +function foo(x: T): NullishFoo { + return x; +} + +function bar(x: T): NullishFoo { + return x; +} + +function main() { + foo(new Object()); + bar(new Object()); +} diff --git a/ets2panda/test/test-lists/parser/parser-js-ignored.txt b/ets2panda/test/test-lists/parser/parser-js-ignored.txt index 49f4f01669..a0cac35d0e 100644 --- a/ets2panda/test/test-lists/parser/parser-js-ignored.txt +++ b/ets2panda/test/test-lists/parser/parser-js-ignored.txt @@ -69,3 +69,12 @@ parser/ets/trailing_lambda_tests/trailing_lambda_define_lambda_in_body_capture_v # Bad test shadows Object with type parameter name #14913 compiler/ets/override13.ets + +# 15095 +compiler/ets/methodOverrideCovariantReturnType.ets +compiler/ets/override16.ets +compiler/ets/override17.ets +parser/ets/static_function_hide_2.ets + +# 14595 +compiler/ets/n_assignGenericWithNullableTypeParamToNonNullable.ets -- Gitee From 6469e0bcf5d4b640190f3df1b3f3c943a345d81f Mon Sep 17 00:00:00 2001 From: zhao-xinyuan8 Date: Tue, 2 Jan 2024 01:52:02 +0000 Subject: [PATCH 17/24] Fix optional parameters with generic return types The proxy method of the method with optional parameters and generic return type generated incorrectly. Add generic return type to the proxy method. issue:I8SS9H Signed-off-by: zhao-xinyuan8 --- ets2panda/parser/ETSparser.cpp | 15 +- ...ametersWithGenericReturnTypes-expected.txt | 2377 +++++++++++++++++ ...tionalParametersWithGenericReturnTypes.ets | 27 + 3 files changed, 2418 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes-expected.txt create mode 100644 ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes.ets diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index ce756aebcc..1cd76e3ab3 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2344,7 +2344,20 @@ std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *type_annotation, b } if (type_annotation->IsETSTypeReference()) { - return adjust_nullish(type_annotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8()); + std::string type_param_names; + auto type_param = type_annotation->AsETSTypeReference()->Part()->TypeParams(); + if (type_param != nullptr && type_param->IsTSTypeParameterInstantiation()) { + type_param_names = "<"; + auto param_list = type_param->Params(); + for (auto param : param_list) { + std::string type_param_name = GetNameForTypeNode(param); + type_param_names += type_param_name + ","; + } + type_param_names.pop_back(); + type_param_names += ">"; + } + return adjust_nullish(type_annotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8() + + type_param_names); } if (type_annotation->IsETSFunctionType()) { diff --git a/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes-expected.txt b/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes-expected.txt new file mode 100644 index 0000000000..e93759c224 --- /dev/null +++ b/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes-expected.txt @@ -0,0 +1,2377 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 8 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 9 + }, + "end": { + "line": 16, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "param", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Number", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "initializer": { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 24 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 28 + }, + "end": { + "line": 17, + "column": 30 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 27 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 32 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 18, + "column": 16 + }, + "end": { + "line": 18, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 20 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 31 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "overloads": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo_proxy", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo_proxy", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "param", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Number", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "$proxy_mask$", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "$proxy_mask$", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "param", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "property": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "param", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 19, + "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": 20, + "column": 2 + }, + "end": { + "line": 20, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "B", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 7 + }, + "end": { + "line": 22, + "column": 8 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 11 + } + } + }, + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "U", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 11 + }, + "end": { + "line": 22, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 11 + }, + "end": { + "line": 22, + "column": 13 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 8 + }, + "end": { + "line": 22, + "column": 13 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 8 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 8 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "param", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Number", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 17 + }, + "end": { + "line": 23, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 17 + }, + "end": { + "line": 23, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 17 + }, + "end": { + "line": 23, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 24 + } + } + }, + "initializer": { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 24 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "B", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 26 + }, + "end": { + "line": 23, + "column": 27 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 28 + }, + "end": { + "line": 23, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 28 + }, + "end": { + "line": 23, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 28 + }, + "end": { + "line": 23, + "column": 30 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "U", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 30 + }, + "end": { + "line": 23, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 30 + }, + "end": { + "line": 23, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 30 + }, + "end": { + "line": 23, + "column": 32 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 27 + }, + "end": { + "line": 23, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 26 + }, + "end": { + "line": 23, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 26 + }, + "end": { + "line": 23, + "column": 34 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 24, + "column": 16 + }, + "end": { + "line": 24, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 20 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 33 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 8 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 8 + }, + "end": { + "line": 25, + "column": 6 + } + } + }, + "overloads": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo_proxy", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo_proxy", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "param", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Number", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "$proxy_mask$", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "B", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "U", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "$proxy_mask$", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "param", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression", + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "property": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "param", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + } + ], + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 25, + "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": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 14 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 26, + "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": 28, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes.ets b/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes.ets new file mode 100644 index 0000000000..8eabddf519 --- /dev/null +++ b/ets2panda/test/parser/ets/OptionalParametersWithGenericReturnTypes.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 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 { + foo(param?: Number): A { + return this + } +} + +class B { + foo(param?: Number): B { + return this + } +} + -- Gitee From 96425216e7d82b237269ab0ca5ae6cc2475db9ed Mon Sep 17 00:00:00 2001 From: x30053363 Date: Wed, 3 Jan 2024 15:20:17 +0800 Subject: [PATCH 18/24] fix codestyle problems #15069 #15053 #15070 Signed-off-by: x30053363 --- ets2panda/parser/ETSparser.cpp | 260 +++++++++++++++++++-------------- ets2panda/parser/ETSparser.h | 20 ++- 2 files changed, 168 insertions(+), 112 deletions(-) diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 1cd76e3ab3..1713410b68 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -676,22 +676,6 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVector global_properties(Allocator()->Adapter()); field_map_.clear(); export_name_map_.clear(); - bool default_export = false; - - using ParserFunctionPtr = std::function; - auto const parse_type = [this, &statements, &default_export](std::size_t const current_pos, - ParserFunctionPtr const &parser_function) -> void { - ir::Statement *node = nullptr; - - node = parser_function(this); - if (node != nullptr) { - if (current_pos != std::numeric_limits::max()) { - MarkNodeAsExported(node, node->Start(), default_export); - default_export = false; - } - statements.push_back(node); - } - }; // Add special '_$init$_' method that will hold all the top-level variable initializations (as assignments) and // statements. By default it will be called in the global class static constructor but also it can be called @@ -702,6 +686,43 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVector &statements, bool &default_export, + std::size_t const current_pos, + std::function const &parser_function) +{ + ir::Statement *node = nullptr; + + node = parser_function(this); + if (node != nullptr) { + if (current_pos != std::numeric_limits::max()) { + MarkNodeAsExported(node, node->Start(), default_export); + default_export = false; + } + statements.push_back(node); + } +} + +void ETSParser::ParseTopLevelNextToken(ArenaVector &statements, + ArenaVector &global_properties, ir::ScriptFunction *init_function) +{ + bool default_export = false; + while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { Lexer()->NextToken(); @@ -742,42 +763,16 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorNextToken(); auto *member_name = ExpectIdentifier(); - ParseClassFieldDefiniton(member_name, member_modifiers, &global_properties, init_function, &start_loc); + ParseClassFieldDefinition(member_name, member_modifiers, &global_properties, init_function, &start_loc); break; } case lexer::TokenType::KEYW_ASYNC: case lexer::TokenType::KEYW_NATIVE: { - bool is_async = token_type == lexer::TokenType::KEYW_ASYNC; - - if (is_async) { - member_modifiers |= ir::ModifierFlags::ASYNC; - } else { - member_modifiers |= ir::ModifierFlags::NATIVE; - } - - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { - ThrowSyntaxError( - {is_async ? "'async'" : "'native'", " flags must be used for functions at top-level."}); - } + ParseTokenOfNative(token_type, member_modifiers); [[fallthrough]]; } case lexer::TokenType::KEYW_FUNCTION: { - Lexer()->NextToken(); - // check whether it is an extension function - ir::Identifier *class_name = nullptr; - if (Lexer()->Lookahead() == lexer::LEX_CHAR_DOT) { - class_name = ExpectIdentifier(); - Lexer()->NextToken(); - } - - auto *member_name = ExpectIdentifier(); - auto *class_method = ParseClassMethodDefinition(member_name, member_modifiers, class_name); - class_method->SetStart(start_loc); - if (!class_method->Function()->IsOverload()) { - global_properties.push_back(class_method); - } + ParseTokenOfFunction(member_modifiers, start_loc, global_properties); break; } case lexer::TokenType::KEYW_NAMESPACE: @@ -793,18 +788,21 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorParseTypeDeclaration(false); }); + ParseTopLevelType(statements, default_export, current_pos, + [](ETSParser *obj) { return obj->ParseTypeDeclaration(false); }); break; } @@ -829,18 +827,42 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorNextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { + ThrowSyntaxError({is_async ? "'async'" : "'native'", " flags must be used for functions at top-level."}); + } +} + +void ETSParser::ParseTokenOfFunction(ir::ModifierFlags member_modifiers, lexer::SourcePosition start_loc, + ArenaVector &global_properties) +{ + Lexer()->NextToken(); + // check whether it is an extension function + ir::Identifier *class_name = nullptr; + if (Lexer()->Lookahead() == lexer::LEX_CHAR_DOT) { + class_name = ExpectIdentifier(); + Lexer()->NextToken(); + } + + auto *member_name = ExpectIdentifier(); + auto *class_method = ParseClassMethodDefinition(member_name, member_modifiers, class_name); + class_method->SetStart(start_loc); + if (!class_method->Function()->IsOverload()) { + global_properties.push_back(class_method); } - return global_properties; } // NOLINTNEXTLINE(google-default-arguments) @@ -1266,9 +1288,9 @@ ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seen_static) } // NOLINTNEXTLINE(google-default-arguments) -void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::ModifierFlags modifiers, - ArenaVector *declarations, ir::ScriptFunction *init_function, - lexer::SourcePosition *let_loc) +void ETSParser::ParseClassFieldDefinition(ir::Identifier *field_name, ir::ModifierFlags modifiers, + ArenaVector *declarations, ir::ScriptFunction *init_function, + lexer::SourcePosition *let_loc) { lexer::SourcePosition start_loc = let_loc != nullptr ? *let_loc : Lexer()->GetToken().Start(); lexer::SourcePosition end_loc = start_loc; @@ -1292,28 +1314,7 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::Modifie // performed multiple times. if (init_function != nullptr && (modifiers & ir::ModifierFlags::CONST) == 0U && initializer != nullptr && !initializer->IsArrowFunctionExpression()) { - if (auto *const func_body = init_function->Body(); func_body != nullptr && func_body->IsBlockStatement()) { - auto *ident = AllocNode(field_name->Name(), Allocator()); - ident->SetReference(); - ident->SetRange(field_name->Range()); - - auto *assignment_expression = - AllocNode(ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - end_loc = initializer->End(); - assignment_expression->SetRange({field_name->Start(), end_loc}); - assignment_expression->SetParent(func_body); - - auto expression_statement = AllocNode(assignment_expression); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { - end_loc = Lexer()->GetToken().End(); - } - expression_statement->SetRange({start_loc, end_loc}); - func_body->AsBlockStatement()->Statements().emplace_back(expression_statement); - - if (type_annotation != nullptr && !type_annotation->IsETSFunctionType()) { - initializer = nullptr; - } - } + end_loc = InitializeGlobalVariable(field_name, initializer, init_function, start_loc, type_annotation); } bool is_declare = (modifiers & ir::ModifierFlags::DECLARE) != 0; @@ -1336,8 +1337,40 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::Modifie if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { Lexer()->NextToken(); ir::Identifier *next_name = ExpectIdentifier(false, true); - ParseClassFieldDefiniton(next_name, modifiers, declarations); + ParseClassFieldDefinition(next_name, modifiers, declarations); + } +} + +lexer::SourcePosition ETSParser::InitializeGlobalVariable(ir::Identifier *field_name, ir::Expression *&initializer, + ir::ScriptFunction *init_function, + lexer::SourcePosition &start_loc, + ir::TypeNode *type_annotation) +{ + lexer::SourcePosition end_loc = start_loc; + + if (auto *const func_body = init_function->Body(); func_body != nullptr && func_body->IsBlockStatement()) { + auto *ident = AllocNode(field_name->Name(), Allocator()); + ident->SetReference(); + ident->SetRange(field_name->Range()); + + auto *assignment_expression = + AllocNode(ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + end_loc = initializer->End(); + assignment_expression->SetRange({field_name->Start(), end_loc}); + assignment_expression->SetParent(func_body); + + auto expression_statement = AllocNode(assignment_expression); + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { + end_loc = Lexer()->GetToken().End(); + } + expression_statement->SetRange({start_loc, end_loc}); + func_body->AsBlockStatement()->Statements().emplace_back(expression_statement); + + if (type_annotation != nullptr && !type_annotation->IsETSFunctionType()) { + initializer = nullptr; + } } + return end_loc; } ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *method_name, ir::ModifierFlags modifiers, @@ -1637,7 +1670,7 @@ ir::AstNode *ETSParser::ParseClassElement([[maybe_unused]] const ArenaVector field_declarations(Allocator()->Adapter()); auto *placeholder = AllocNode(std::move(field_declarations)); - ParseClassFieldDefiniton(member_name, memberModifiers, placeholder->BodyPtr()); + ParseClassFieldDefinition(member_name, memberModifiers, placeholder->BodyPtr()); return placeholder; } @@ -2781,17 +2814,7 @@ std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnota switch (Lexer()->GetToken().Type()) { case lexer::TokenType::LITERAL_IDENT: { - if (const auto keyword = Lexer()->GetToken().KeywordType(); - keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) { - type_annotation = ParseWildcardType(options); - } else { - if (Lexer()->GetToken().IsDefinableTypeName()) { - type_annotation = GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options); - } else { - type_annotation = ParseTypeReference(options); - } - } - + type_annotation = ParseLiteralIdent(options); if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 && (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) { return std::make_pair(type_annotation, false); @@ -2850,17 +2873,7 @@ std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnota type_annotation = ParseUnionType(type_annotation); } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { - ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); - } - - Lexer()->Rewind(saved_pos); - type_annotation = nullptr; - } else { - Lexer()->NextToken(); // eat ')' - } - + ParseRightParenthesis(options, type_annotation, saved_pos); break; } case lexer::TokenType::PUNCTUATOR_FORMAT: { @@ -2883,6 +2896,35 @@ std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnota return std::make_pair(type_annotation, true); } +ir::TypeNode *ETSParser::ParseLiteralIdent(TypeAnnotationParsingOptions *options) +{ + if (const auto keyword = Lexer()->GetToken().KeywordType(); + keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) { + return ParseWildcardType(options); + } + + if (Lexer()->GetToken().IsDefinableTypeName()) { + return GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options); + } + + return ParseTypeReference(options); +} + +void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&type_annotation, + lexer::LexerPosition saved_pos) +{ + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { + ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); + } + + Lexer()->Rewind(saved_pos); + type_annotation = nullptr; + } else { + Lexer()->NextToken(); // eat ')' + } +} + ir::TypeNode *ETSParser::ParseThisType(TypeAnnotationParsingOptions *options) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index ffbbf5b088..a98d95e965 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -106,6 +106,13 @@ private: [[nodiscard]] std::unique_ptr InitLexer(const SourceFile &source_file) override; void ParsePackageDeclaration(ArenaVector &statements); ArenaVector ParseTopLevelStatements(ArenaVector &statements); + void ParseTopLevelType(ArenaVector &statements, bool &default_export, std::size_t current_pos, + std::function const &parser_function); + void ParseTopLevelNextToken(ArenaVector &statements, ArenaVector &global_properties, + ir::ScriptFunction *init_function); + void ParseTokenOfNative(panda::es2panda::lexer::TokenType token_type, ir::ModifierFlags &member_modifiers); + void ParseTokenOfFunction(ir::ModifierFlags member_modifiers, lexer::SourcePosition start_loc, + ArenaVector &global_properties); #ifdef USE_FTW static int NFTWCallBack(const char *fpath, const struct stat * /*unused*/, int tflag, struct FTW * /*unused*/); #endif @@ -160,9 +167,13 @@ private: ir::Expression *CreateParameterThis(util::StringView class_name) override; // NOLINTNEXTLINE(google-default-arguments) - void ParseClassFieldDefiniton(ir::Identifier *field_name, ir::ModifierFlags modifiers, - ArenaVector *declarations, ir::ScriptFunction *init_function = nullptr, - lexer::SourcePosition *let_loc = nullptr); + void ParseClassFieldDefinition(ir::Identifier *field_name, ir::ModifierFlags modifiers, + ArenaVector *declarations, + ir::ScriptFunction *init_function = nullptr, + lexer::SourcePosition *let_loc = nullptr); + lexer::SourcePosition InitializeGlobalVariable(ir::Identifier *field_name, ir::Expression *&initializer, + ir::ScriptFunction *init_function, lexer::SourcePosition &start_loc, + ir::TypeNode *type_annotation); std::tuple ParseTypeReferencePart( TypeAnnotationParsingOptions *options); ir::TypeNode *ParseTypeReference(TypeAnnotationParsingOptions *options); @@ -188,6 +199,9 @@ private: void ThrowIfVarDeclaration(VariableParsingFlags flags) override; std::pair GetTypeAnnotationFromToken(TypeAnnotationParsingOptions *options); + ir::TypeNode *ParseLiteralIdent(TypeAnnotationParsingOptions *options); + void ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&type_annotation, + lexer::LexerPosition saved_pos); ir::TypeNode *ParseTypeAnnotation(TypeAnnotationParsingOptions *options) override; ir::TSTypeAliasDeclaration *ParseTypeAliasDeclaration() override; -- Gitee From afe2f6c3f595c03f457dbcbf3d25d425212ec369 Mon Sep 17 00:00:00 2001 From: x30053363 Date: Fri, 5 Jan 2024 09:51:35 +0800 Subject: [PATCH 19/24] fix codestyle problem #15075 Signed-off-by: x30053363 --- ets2panda/public/es2panda_lib.cpp | 59 ------------------------------- ets2panda/public/es2panda_lib.h | 59 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 84ab4a84a6..1945b19eec 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -129,34 +129,6 @@ static char const *ArenaStrdup(ArenaAllocator *allocator, char const *src) return res; } -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define FOR_ALL_MODIFIER_FLAGS(_) \ - _(STATIC) \ - _(ASYNC) \ - _(PUBLIC) \ - _(PROTECTED) \ - _(PRIVATE) \ - _(DECLARE) \ - _(READONLY) \ - _(OPTIONAL) \ - _(DEFINITE) \ - _(ABSTRACT) \ - _(CONST) \ - _(FINAL) \ - _(NATIVE) \ - _(OVERRIDE) \ - _(CONSTRUCTOR) \ - _(SYNCHRONIZED) \ - _(FUNCTIONAL) \ - _(IN) \ - _(OUT) \ - _(INTERNAL) \ - _(NULL_ASSIGNABLE) \ - _(UNDEFINED_ASSIGNABLE) \ - _(EXPORT) \ - _(SETTER) \ - _(DEFAULT_EXPORT) - static ir::ModifierFlags E2pToIrModifierFlags(es2panda_ModifierFlags e2p_flags) { ir::ModifierFlags ir_flags {ir::ModifierFlags::NONE}; @@ -191,30 +163,6 @@ static es2panda_ModifierFlags IrToE2pModifierFlags(ir::ModifierFlags ir_flags) return e2p_flags; } -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define FOR_ALL_SCRIPT_FUNCTION_FLAGS(_) \ - _(GENERATOR) \ - _(ASYNC) \ - _(ARROW) \ - _(EXPRESSION) \ - _(OVERLOAD) \ - _(CONSTRUCTOR) \ - _(METHOD) \ - _(STATIC_BLOCK) \ - _(HIDDEN) \ - _(IMPLICIT_SUPER_CALL_NEEDED) \ - _(ENUM) \ - _(EXTERNAL) \ - _(PROXY) \ - _(THROWS) \ - _(RETHROWS) \ - _(GETTER) \ - _(SETTER) \ - _(DEFAULT_PARAM_PROXY) \ - _(ENTRY_POINT) \ - _(INSTANCE_EXTENSION_METHOD) \ - _(HAS_RETURN) - static ir::ScriptFunctionFlags E2pToIrScriptFunctionFlags(es2panda_ScriptFunctionFlags e2p_flags) { ir::ScriptFunctionFlags ir_flags {ir::ScriptFunctionFlags::NONE}; @@ -1467,13 +1415,6 @@ extern "C" es2panda_AstNode *ImportSpecifierLocal(es2panda_AstNode *ast) return reinterpret_cast(node->Local()); } -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define FOR_ALL_MEMBER_EXPRESSION_KINDS(_) \ - _(ELEMENT_ACCESS) \ - _(PROPERTY_ACCESS) \ - _(GETTER) \ - _(SETTER) - static ir::MemberExpressionKind E2pToIrMemberExpressionKind(es2panda_MemberExpressionKind e2p_kind) { ir::MemberExpressionKind ir_kind = ir::MemberExpressionKind::NONE; diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index c28f1e708b..fcbd4db52b 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -28,6 +28,65 @@ extern "C" { #define ES2PANDA_LIB_VERSION 1 +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_MODIFIER_FLAGS(_) \ + _(STATIC) \ + _(ASYNC) \ + _(PUBLIC) \ + _(PROTECTED) \ + _(PRIVATE) \ + _(DECLARE) \ + _(READONLY) \ + _(OPTIONAL) \ + _(DEFINITE) \ + _(ABSTRACT) \ + _(CONST) \ + _(FINAL) \ + _(NATIVE) \ + _(OVERRIDE) \ + _(CONSTRUCTOR) \ + _(SYNCHRONIZED) \ + _(FUNCTIONAL) \ + _(IN) \ + _(OUT) \ + _(INTERNAL) \ + _(NULL_ASSIGNABLE) \ + _(UNDEFINED_ASSIGNABLE) \ + _(EXPORT) \ + _(SETTER) \ + _(DEFAULT_EXPORT) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_SCRIPT_FUNCTION_FLAGS(_) \ + _(GENERATOR) \ + _(ASYNC) \ + _(ARROW) \ + _(EXPRESSION) \ + _(OVERLOAD) \ + _(CONSTRUCTOR) \ + _(METHOD) \ + _(STATIC_BLOCK) \ + _(HIDDEN) \ + _(IMPLICIT_SUPER_CALL_NEEDED) \ + _(ENUM) \ + _(EXTERNAL) \ + _(PROXY) \ + _(THROWS) \ + _(RETHROWS) \ + _(GETTER) \ + _(SETTER) \ + _(DEFAULT_PARAM_PROXY) \ + _(ENTRY_POINT) \ + _(INSTANCE_EXTENSION_METHOD) \ + _(HAS_RETURN) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_MEMBER_EXPRESSION_KINDS(_) \ + _(ELEMENT_ACCESS) \ + _(PROPERTY_ACCESS) \ + _(GETTER) \ + _(SETTER) + typedef struct es2panda_Config es2panda_Config; typedef struct es2panda_Context es2panda_Context; -- Gitee From 59f4d1de91f8c3a8bc8a950edd4ca1e0f55314e4 Mon Sep 17 00:00:00 2001 From: Martin Sajti Date: Thu, 4 Jan 2024 12:59:10 +0100 Subject: [PATCH 20/24] Fix tuple LUB type for undefined and null types Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8TP97 Internal issue: #15032 Test: build, new checker test Signed-off-by: Martin Sajti --- ets2panda/checker/types/ets/etsObjectType.cpp | 2 +- ets2panda/ir/ets/etsTuple.cpp | 39 +- ets2panda/ir/ets/etsTuple.h | 1 + .../compiler/ets/tuple_types_17-expected.txt | 543 ++++++++++++++++ .../test/compiler/ets/tuple_types_17.ets | 19 + .../compiler/ets/tuple_types_18-expected.txt | 585 ++++++++++++++++++ .../test/compiler/ets/tuple_types_18.ets | 22 + 7 files changed, 1204 insertions(+), 7 deletions(-) create mode 100644 ets2panda/test/compiler/ets/tuple_types_17-expected.txt create mode 100644 ets2panda/test/compiler/ets/tuple_types_17.ets create mode 100644 ets2panda/test/compiler/ets/tuple_types_18-expected.txt create mode 100644 ets2panda/test/compiler/ets/tuple_types_18.ets diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 45d0171b19..78964c18b0 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -570,7 +570,7 @@ void ETSObjectType::Cast(TypeRelation *const relation, Type *const target) } if (this->IsETSNullLike()) { - if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) { + if (target->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT)) { relation->GetNode()->SetTsType(target); relation->Result(true); return; diff --git a/ets2panda/ir/ets/etsTuple.cpp b/ets2panda/ir/ets/etsTuple.cpp index 13c879a2bf..fd230df186 100644 --- a/ets2panda/ir/ets/etsTuple.cpp +++ b/ets2panda/ir/ets/etsTuple.cpp @@ -53,9 +53,9 @@ void ETSTuple::Dump(ir::AstDumper *const dumper) const void ETSTuple::Dump(ir::SrcDumper *const dumper) const { dumper->Add("["); - for (auto type_annot : type_annotation_list_) { + for (const auto *const type_annot : type_annotation_list_) { type_annot->Dump(dumper); - if (type_annot != type_annotation_list_.back() || spread_type_ != nullptr) { + if ((type_annot != type_annotation_list_.back()) || (spread_type_ != nullptr)) { dumper->Add(", "); } } @@ -63,7 +63,7 @@ void ETSTuple::Dump(ir::SrcDumper *const dumper) const dumper->Add("..."); spread_type_->Dump(dumper); } - dumper->Add(("]")); + dumper->Add("]"); } void ETSTuple::Compile([[maybe_unused]] compiler::PandaGen *const pg) const {} @@ -79,6 +79,17 @@ checker::Type *ETSTuple::Check([[maybe_unused]] checker::ETSChecker *const check return GetType(checker); } +void ETSTuple::SetNullUndefinedFlags(std::pair &contains_null_or_undefined, const checker::Type *const type) +{ + if (type->HasTypeFlag(checker::TypeFlag::NULLISH)) { + contains_null_or_undefined.first = true; + } + + if (type->HasTypeFlag(checker::TypeFlag::UNDEFINED)) { + contains_null_or_undefined.second = true; + } +} + checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker, ArenaVector &type_list, checker::Type *const spread_type) { @@ -86,11 +97,17 @@ checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker return spread_type == nullptr ? checker->GlobalETSObjectType() : spread_type; } - bool all_elements_are_same = std::all_of(type_list.begin(), type_list.end(), [&checker, &type_list](auto *element) { - return checker->Relation()->IsIdenticalTo(type_list[0], element); - }); + std::pair contains_null_or_undefined = {false, false}; + + bool all_elements_are_same = + std::all_of(type_list.begin(), type_list.end(), + [this, &checker, &type_list, &contains_null_or_undefined](checker::Type *const element) { + SetNullUndefinedFlags(contains_null_or_undefined, element); + return checker->Relation()->IsIdenticalTo(type_list[0], element); + }); if (spread_type != nullptr) { + SetNullUndefinedFlags(contains_null_or_undefined, spread_type); all_elements_are_same = all_elements_are_same && checker->Relation()->IsIdenticalTo(type_list[0], spread_type); } @@ -121,6 +138,16 @@ checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker lub_type = checker->FindLeastUpperBound(lub_type, get_boxed_type_or_type(spread_type)); } + const auto nullish_undefined_flags = + (contains_null_or_undefined.first ? checker::TypeFlag::NULLISH | checker::TypeFlag::NULL_TYPE + : checker::TypeFlag::NONE) | + (contains_null_or_undefined.second ? checker::TypeFlag::UNDEFINED : checker::TypeFlag::NONE); + + if (nullish_undefined_flags != checker::TypeFlag::NONE) { + lub_type = checker->CreateNullishType(lub_type, nullish_undefined_flags, checker->Allocator(), + checker->Relation(), checker->GetGlobalTypesHolder()); + } + checker->Relation()->SetNode(saved_relation_node); return lub_type; diff --git a/ets2panda/ir/ets/etsTuple.h b/ets2panda/ir/ets/etsTuple.h index ce5af95a3a..d9572b2b57 100644 --- a/ets2panda/ir/ets/etsTuple.h +++ b/ets2panda/ir/ets/etsTuple.h @@ -75,6 +75,7 @@ public: checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; + void SetNullUndefinedFlags(std::pair &contains_null_or_undefined, const checker::Type *type); checker::Type *CalculateLUBForTuple(checker::ETSChecker *checker, ArenaVector &type_list, checker::Type *spread_type); diff --git a/ets2panda/test/compiler/ets/tuple_types_17-expected.txt b/ets2panda/test/compiler/ets/tuple_types_17-expected.txt new file mode 100644 index 0000000000..9ed30ce235 --- /dev/null +++ b/ets2panda/test/compiler/ets/tuple_types_17-expected.txt @@ -0,0 +1,543 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Two", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 6 + }, + "end": { + "line": 16, + "column": 9 + } + } + }, + "typeAnnotation": { + "type": "ETSTuple", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 16, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 16, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 16, + "column": 17 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 16, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 16, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 16, + "column": 35 + } + } + } + ], + "spreadType": null, + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + { + "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": 17, + "column": 10 + }, + "end": { + "line": 17, + "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": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "t", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Two", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + "init": { + "type": "ArrayExpression", + "elements": [ + { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 18, + "column": 28 + } + } + }, + { + "type": "StringLiteral", + "value": "Test", + "loc": { + "start": { + "line": 18, + "column": 30 + }, + "end": { + "line": 18, + "column": 36 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 37 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 38 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 23 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 19, + "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": 20, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/tuple_types_17.ets b/ets2panda/test/compiler/ets/tuple_types_17.ets new file mode 100644 index 0000000000..b7924a6f10 --- /dev/null +++ b/ets2panda/test/compiler/ets/tuple_types_17.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 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. + */ + +type Two = [Int|undefined, string] +function main(): void { + let t: Two = [undefined, "Test"]; +} diff --git a/ets2panda/test/compiler/ets/tuple_types_18-expected.txt b/ets2panda/test/compiler/ets/tuple_types_18-expected.txt new file mode 100644 index 0000000000..ebe6fc8aab --- /dev/null +++ b/ets2panda/test/compiler/ets/tuple_types_18-expected.txt @@ -0,0 +1,585 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "One", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 6 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + "typeAnnotation": { + "type": "ETSTuple", + "spreadType": null, + "loc": { + "start": { + "line": 17, + "column": 12 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 18, + "column": 5 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "Two", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 6 + }, + "end": { + "line": 18, + "column": 9 + } + } + }, + "typeAnnotation": { + "type": "ETSTuple", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "One", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 18, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 28 + }, + "end": { + "line": 18, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 28 + }, + "end": { + "line": 18, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 28 + }, + "end": { + "line": 18, + "column": 35 + } + } + } + ], + "spreadType": null, + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 20, + "column": 9 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 20, + "column": 9 + } + } + }, + { + "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": 20, + "column": 10 + }, + "end": { + "line": 20, + "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": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "t", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Two", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 17 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 10 + } + } + }, + "init": { + "type": "ArrayExpression", + "elements": [ + { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 21, + "column": 19 + }, + "end": { + "line": 21, + "column": 28 + } + } + }, + { + "type": "StringLiteral", + "value": "Test", + "loc": { + "start": { + "line": 21, + "column": 30 + }, + "end": { + "line": 21, + "column": 36 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 37 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 38 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 23 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 22, + "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/tuple_types_18.ets b/ets2panda/test/compiler/ets/tuple_types_18.ets new file mode 100644 index 0000000000..b0cfb9a33d --- /dev/null +++ b/ets2panda/test/compiler/ets/tuple_types_18.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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. + */ + + +type One = [] +type Two = [One|undefined, string] + +function main(): void { + let t: Two = [undefined, "Test"]; +} -- Gitee From 452a9cbab2c64c4900ac57383cc8bb8aa70b004a Mon Sep 17 00:00:00 2001 From: Anton Soldatov Date: Tue, 9 Jan 2024 15:19:49 +0800 Subject: [PATCH 21/24] Fix balance of NOLINTBEGIN/END in ETSParser.h Signed-off-by: Anton Soldatov --- ets2panda/parser/ETSparser.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index a98d95e965..e95f4dbdb4 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -338,6 +338,7 @@ private: ir::Statement *CreateStatement(std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view source_code, std::vector &inserting_nodes, std::string_view file_name = DEFAULT_SOURCE_FILE); + // NOLINTEND(google-default-arguments) template ir::Statement *CreateFormattedStatement(std::string_view const source_code, std::string_view const file_name, @@ -355,6 +356,8 @@ private: std::string_view file_name = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); + // NOLINTEND(google-default-arguments) + friend class ExternalSourceParser; friend class InnerSourceParser; -- Gitee From aaf845797a671bebdb90234395f156ab493ff7cf Mon Sep 17 00:00:00 2001 From: Orlovsky Maxim Date: Mon, 18 Dec 2023 18:05:03 +0300 Subject: [PATCH 22/24] Title: ASTVerifier integration Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8QPLB Description: Integrating verifier into phase/lowerings framework. Adding related checks into phases/lowerings. Testing: Unit tests (astverifier_gtests), stdlib generation (all checks enabled) Signed-off-by: Orlovsky Maxim --- ets2panda/checker/ets/helpers.cpp | 2 +- ets2panda/checker/ets/typeCreation.cpp | 5 +- ets2panda/compiler/core/ASTVerifier.cpp | 1087 ++++++++--------- ets2panda/compiler/core/ASTVerifier.h | 186 ++- ets2panda/compiler/core/compilerImpl.cpp | 31 + ets2panda/compiler/lowering/checkerPhase.cpp | 1 + ets2panda/compiler/lowering/checkerPhase.h | 6 +- .../compiler/lowering/ets/expandBrackets.cpp | 2 +- .../compiler/lowering/ets/expandBrackets.h | 5 +- .../lowering/ets/generateDeclarations.cpp | 2 + .../lowering/ets/generateDeclarations.h | 5 +- .../ets/interfacePropertyDeclarations.cpp | 7 +- .../ets/interfacePropertyDeclarations.h | 2 +- .../compiler/lowering/ets/lambdaLowering.cpp | 11 +- .../compiler/lowering/ets/lambdaLowering.h | 4 +- .../lowering/ets/objectIndexAccess.cpp | 8 +- .../compiler/lowering/ets/objectIndexAccess.h | 2 +- .../compiler/lowering/ets/opAssignment.cpp | 7 +- .../compiler/lowering/ets/opAssignment.h | 2 +- .../compiler/lowering/ets/promiseVoid.cpp | 21 +- ets2panda/compiler/lowering/ets/promiseVoid.h | 4 +- .../compiler/lowering/ets/structLowering.cpp | 6 - .../compiler/lowering/ets/structLowering.h | 2 +- .../compiler/lowering/ets/tupleLowering.cpp | 7 +- .../compiler/lowering/ets/tupleLowering.h | 2 +- .../compiler/lowering/ets/unionLowering.cpp | 7 +- .../compiler/lowering/ets/unionLowering.h | 2 +- ets2panda/compiler/lowering/phase.cpp | 48 +- ets2panda/compiler/lowering/phase.h | 6 + ets2panda/compiler/lowering/plugin_phase.h | 1 + .../lowering/scopesInit/scopesInitPhase.cpp | 80 +- .../lowering/scopesInit/scopesInitPhase.h | 39 +- ets2panda/ir/ets/etsScript.h | 1 + ets2panda/public/es2panda_lib.cpp | 2 +- .../unit/lowerings/scopes_initialization.cpp | 6 +- .../test/unit/public/ast_verifier_test.cpp | 235 ++-- 36 files changed, 919 insertions(+), 925 deletions(-) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 8b5b137960..ef38c31e6e 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2687,7 +2687,7 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons es2panda::CompilerOptions options; auto parser = parser::ETSParser(&program, options, parser::ParserStatus::NO_OPTS); auto *arg_expr = parser.CreateExpression(implicit_instantiate_argument); - compiler::ScopesInitPhaseETS::RunExternalNode(arg_expr, &program); + compiler::InitScopesPhaseETS::RunExternalNode(arg_expr, &program); arg_expr->SetParent(call_expr); arg_expr->SetRange(ident->Range()); diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index f673d9c562..63977bde5d 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -484,8 +484,9 @@ ETSObjectType *ETSChecker::CreateNewETSObjectType(util::StringView name, ir::Ast if (containing_obj_type != nullptr) { prefix = containing_obj_type->AssemblerName(); - } else if (decl_node->GetTopStatement()->Type() != - ir::AstNodeType::BLOCK_STATEMENT) { // NOTE: should not occur, fix for TS_INTERFACE_DECLARATION + } else if (const auto *top_statement = decl_node->GetTopStatement(); + top_statement->Type() != + ir::AstNodeType::ETS_SCRIPT) { // NOTE: should not occur, fix for TS_INTERFACE_DECLARATION ASSERT(decl_node->IsTSInterfaceDeclaration()); assembler_name = decl_node->AsTSInterfaceDeclaration()->InternalName(); } else { diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 17265d2995..82e0dce5e1 100644 --- a/ets2panda/compiler/core/ASTVerifier.cpp +++ b/ets2panda/compiler/core/ASTVerifier.cpp @@ -23,13 +23,16 @@ #include "ir/base/classStaticBlock.h" #include "ir/base/methodDefinition.h" #include "ir/base/scriptFunction.h" +#include "ir/ets/etsClassLiteral.h" #include "ir/ets/etsFunctionType.h" #include "ir/ets/etsNewClassInstanceExpression.h" #include "ir/ets/etsParameterExpression.h" +#include "ir/ets/etsScript.h" #include "ir/ets/etsTypeReference.h" #include "ir/ets/etsTypeReferencePart.h" #include "ir/ets/etsImportDeclaration.h" #include "ir/ets/etsScript.h" +#include "ir/expressions/sequenceExpression.h" #include "ir/module/importSpecifier.h" #include "ir/module/importNamespaceSpecifier.h" #include "ir/module/importDefaultSpecifier.h" @@ -62,17 +65,45 @@ #include #include +#define RECURSIVE_SUFFIX "ForAll" + namespace panda::es2panda::compiler { -template -ASTVerifier::CheckFunction RecursiveCheck(const Func &func) -{ - return [func](const ir::AstNode *ast) -> bool { - bool has_parent = func(ast); - ast->IterateRecursively([func, &has_parent](ir::AstNode *child) { has_parent &= func(child); }); - return has_parent; - }; -} +struct ASTVerifier::ErrorContext { + explicit ErrorContext() : named_errors_ {}, encountered_errors_ {} {} + + void ProcessEncounteredErrors(util::StringView name) + { + for (const auto &error : encountered_errors_) { + named_errors_.emplace_back(CheckError {name, error}); + } + encountered_errors_.clear(); + } + + void AddError(const std::string &message) + { + named_errors_.emplace_back(CheckError {"Unnamed", ASTVerifier::InvariantError {message, "", 0}}); + } + + void AddInvariantError(const std::string &cause, const ir::AstNode &node, const lexer::SourcePosition &from) + { + const auto loc = from.line; + const auto &&dump = node.DumpJSON(); + static const std::regex r {R"(\s+)"}; // removing all identation + auto ss = std::stringstream {}; + std::regex_replace(std::ostream_iterator(ss), dump.begin(), dump.end(), r, ""); + encountered_errors_.emplace_back(ASTVerifier::InvariantError {cause, ss.str(), loc}); + } + + ASTVerifier::Errors GetErrors() + { + return named_errors_; + } + +private: + ASTVerifier::Errors named_errors_; + std::vector encountered_errors_; +}; static bool IsNumericType(const ir::AstNode *ast) { @@ -115,7 +146,7 @@ static bool IsStringType(const ir::AstNode *ast) } template -bool IsContainedIn(const T *child, const T *parent) +static bool IsContainedIn(const T *child, const T *parent) { if (child == nullptr || parent == nullptr) { return false; @@ -148,7 +179,8 @@ bool IsVisibleInternalNode(const ir::AstNode *ast, const ir::AstNode *obj_type_d return current_top_statement == object_top_statement || (package_name_current == package_name_object && !package_name_current.Empty()); } -bool ValidateVariableAccess(const varbinder::LocalVariable *prop_var, const ir::MemberExpression *ast) + +static bool ValidateVariableAccess(const varbinder::LocalVariable *prop_var, const ir::MemberExpression *ast) { const auto *prop_var_decl = prop_var->Declaration(); if (prop_var_decl == nullptr) { @@ -189,7 +221,7 @@ bool ValidateVariableAccess(const varbinder::LocalVariable *prop_var, const ir:: return false; } -bool ValidateMethodAccess(const ir::MemberExpression *member_expression, const ir::CallExpression *ast) +static bool ValidateMethodAccess(const ir::MemberExpression *member_expression, const ir::CallExpression *ast) { auto *member_obj_type = member_expression->ObjType(); if (member_obj_type == nullptr) { @@ -236,693 +268,574 @@ bool ValidateMethodAccess(const ir::MemberExpression *member_expression, const i return false; } -bool ValidateExport(const varbinder::Variable *var) -{ - const auto *decl = var->Declaration(); - if (decl == nullptr) { - return false; - } - const auto *node = decl->Node(); - if (node == nullptr) { - return false; - } - return node->IsExported(); -} +class NodeHasParent { +public: + explicit NodeHasParent([[maybe_unused]] ArenaAllocator &allocator) {} -std::string ToStringHelper(const varbinder::ScopeType type) -{ - switch (type) { - case varbinder::ScopeType::CATCH: { - return "CATCH"; - } - case varbinder::ScopeType::CATCH_PARAM: { - return "CATCH_PARAM"; - } - case varbinder::ScopeType::CLASS: { - return "CLASS"; - } - case varbinder::ScopeType::FUNCTION: { - return "FUNCTION"; - } - case varbinder::ScopeType::FUNCTION_PARAM: { - return "FUNCTION_PARAM"; - } - case varbinder::ScopeType::GLOBAL: { - return "GLOBAL"; - } - case varbinder::ScopeType::LOCAL: { - return "LOCAL"; - } - case varbinder::ScopeType::LOOP: { - return "LOOP"; - } - case varbinder::ScopeType::LOOP_DECL: { - return "LOOP_DECL"; - } - case varbinder::ScopeType::MODULE: { - return "MODULE"; + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + const auto is_ets_script = ast->IsETSScript(); + const auto has_parent = ast->Parent() != nullptr; + if (!is_ets_script && !has_parent) { + ctx.AddInvariantError("NULL_PARENT", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; } - case varbinder::ScopeType::PARAM: { - return "PARAM"; - } - default: { - return "MUST BE UNREACHABLE"; + if (ast->IsProgram()) { + return ASTVerifier::CheckResult::Success; } + return ASTVerifier::CheckResult::Success; } -} - -std::string ToStringHelper(const util::StringView &name) -{ - return name == nullptr ? "" : name.Mutf8(); -} +}; -std::string ToStringHelper(const varbinder::Scope *scope) -{ - if (scope == nullptr) { - return ""; - } +class IdentifierHasVariable { +public: + explicit IdentifierHasVariable([[maybe_unused]] ArenaAllocator &allocator) {} - switch (scope->Type()) { - case varbinder::ScopeType::FUNCTION: { - return "FUNC_SCOPE " + ToStringHelper(scope->AsFunctionScope()->Name()); - } - case varbinder::ScopeType::LOCAL: { - return "LOCAL_SCOPE "; + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (!ast->IsIdentifier()) { + return ASTVerifier::CheckResult::Success; } - case varbinder::ScopeType::CATCH: { - return "CATCH_SCOPE "; + if (ast->AsIdentifier()->Variable() != nullptr) { + return ASTVerifier::CheckResult::Success; } - default: { - return "MUST BE UNREACHABLE"; - } - } -} -std::string ToStringHelper(const varbinder::Variable *var) -{ - if (var == nullptr) { - return ""; + const auto *id = ast->AsIdentifier(); + ctx.AddInvariantError("NULL_VARIABLE", *id, id->Start()); + return ASTVerifier::CheckResult::Failed; } - switch (var->Type()) { - case varbinder::VariableType::LOCAL: { - return "LOCAL_VAR " + ToStringHelper(var->Name()); - } - case varbinder::VariableType::MODULE: { - return "MODULE_VAR " + ToStringHelper(var->Name()); - } - case varbinder::VariableType::GLOBAL: { - return "GLOBAL_VAR " + ToStringHelper(var->Name()); - } - case varbinder::VariableType::ENUM: { - return "ENUM_VAR " + ToStringHelper(var->Name()); - } - default: { - return "MUST BE UNREACHABLE"; - } - } -} +private: +}; -template -std::string ToStringParamsHelper(const ir::AstNode *parent, const ArenaVector ¶ms) -{ - std::string name; - if (parent != nullptr) { - name = ToStringHelper(parent) + " "; - } +class NodeHasType { +public: + explicit NodeHasType([[maybe_unused]] ArenaAllocator &allocator) {} - name += "("; - for (auto const *param : params) { - name += ToStringHelper(param); + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (ast->IsTyped()) { + if (ast->IsClassDefinition() && ast->AsClassDefinition()->Ident()->Name() == "ETSGLOBAL") { + return ASTVerifier::CheckResult::SkipSubtree; + } + const auto *typed = static_cast(ast); + if (typed->TsType() == nullptr) { + ctx.AddInvariantError("NULL_TS_TYPE", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + } + return ASTVerifier::CheckResult::Success; } - return name + ")"; -} - -template -std::string ToStringParamsHelper(const ArenaVector ¶ms) -{ - std::string name = "("; +private: +}; - for (auto const *param : params) { - name += ToStringHelper(param); - } +class VariableHasScope { +public: + explicit VariableHasScope(ArenaAllocator &allocator) : allocator_ {allocator} {} - return name + ")"; -} + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (!ast->IsIdentifier()) { + return ASTVerifier::CheckResult::Success; // we will check invariant of Identifier only + } -std::string ToStringHelper(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return ""; + // we will check invariant for only local variables of identifiers + if (const auto maybe_var = GetLocalScopeVariable(allocator_, ctx, ast); maybe_var.has_value()) { + const auto var = *maybe_var; + const auto scope = var->GetScope(); + if (scope == nullptr) { + ctx.AddInvariantError("NULL_SCOPE_LOCAL_VAR", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + return ScopeEncloseVariable(ctx, var) == true ? ASTVerifier::CheckResult::Success + : ASTVerifier::CheckResult::Failed; + } + return ASTVerifier::CheckResult::Success; } - switch (ast->Type()) { - case ir::AstNodeType::IDENTIFIER: { - return "ID " + ToStringHelper(ast->AsIdentifier()->Name()); - } - case ir::AstNodeType::CLASS_DEFINITION: { - return "CLS_DEF " + ToStringHelper(ast->AsClassDefinition()->Ident()); - } - case ir::AstNodeType::CLASS_DECLARATION: { - return "CLS_DECL " + ToStringHelper(ast->AsClassDeclaration()->Definition()); - } - case ir::AstNodeType::BLOCK_STATEMENT: { - return "BLOCK " + ToStringHelper(ast->AsBlockStatement()->Scope()); - } - case ir::AstNodeType::SCRIPT_FUNCTION: { - auto const *sf = ast->AsScriptFunction(); - return "SCRIPT_FUN " + ToStringHelper(sf->Scope()) + "::" + ToStringHelper(sf->Id()); + static std::optional GetLocalScopeVariable(ArenaAllocator &allocator, + ASTVerifier::ErrorContext &ctx, + const ir::AstNode *ast) + { + if (!ast->IsIdentifier()) { + return std::nullopt; } - case ir::AstNodeType::FUNCTION_EXPRESSION: { - return "FUN_EXPR " + ToStringHelper(ast->AsFunctionExpression()->Function()); - } - case ir::AstNodeType::METHOD_DEFINITION: { - return "METHOD_DEF " + ToStringHelper(ast->AsMethodDefinition()->Value()); - } - case ir::AstNodeType::ETS_TYPE_REFERENCE_PART: { - return "TYPE_REF_PART " + ToStringHelper(ast->AsETSTypeReferencePart()->Name()); - } - case ir::AstNodeType::ETS_TYPE_REFERENCE: { - return "TYPE_REF " + ToStringHelper(ast->AsETSTypeReference()->Part()); - } - case ir::AstNodeType::VARIABLE_DECLARATOR: { - return "VAR_DECLARATOR " + ToStringHelper(ast->AsVariableDeclarator()->Id()); - } - case ir::AstNodeType::VARIABLE_DECLARATION: { - if (ast->AsVariableDeclaration()->Declarators().empty()) { - return "VAR_DECLARATION "; + + auto invariant_has_variable = IdentifierHasVariable {allocator}; + const auto variable = ast->AsIdentifier()->Variable(); + if ((invariant_has_variable(ctx, ast) == ASTVerifier::CheckResult::Success) && variable->IsLocalVariable()) { + const auto local_var = variable->AsLocalVariable(); + if (local_var->HasFlag(varbinder::VariableFlags::LOCAL)) { + return local_var; } - return "VAR_DECLARATION " + ToStringHelper(ast->AsVariableDeclaration()->Declarators().at(0)); - } - case ir::AstNodeType::CALL_EXPRESSION: { - return "CALL_EXPR " + ToStringHelper(ast->AsCallExpression()->Callee()) + "(...)"; - } - case ir::AstNodeType::EXPRESSION_STATEMENT: { - return "EXPR_STMT " + ToStringHelper(ast->AsExpressionStatement()->GetExpression()); } - case ir::AstNodeType::MEMBER_EXPRESSION: { - auto const *me = ast->AsMemberExpression(); - return "MEMBER_EXPR " + ToStringHelper(me->Object()) + "." + ToStringHelper(me->Property()); - } - case ir::AstNodeType::CLASS_STATIC_BLOCK: { - return "CLS_STATIC_BLOCK " + ToStringHelper(ast->AsClassStaticBlock()->Function()); - } - case ir::AstNodeType::ETS_PACKAGE_DECLARATION: { - return "PKG_DECL "; - } - case ir::AstNodeType::TS_TYPE_PARAMETER_DECLARATION: { - auto params = ast->AsTSTypeParameterDeclaration()->Params(); - return "PARAM_DECL " + ToStringParamsHelper(ast->Parent(), params); - } - case ir::AstNodeType::TS_TYPE_PARAMETER: { - return "TYPE_PARAM " + ToStringHelper(ast->AsTSTypeParameter()->Name()); - } - case ir::AstNodeType::TS_TYPE_PARAMETER_INSTANTIATION: { - return "PARAM_INSTANTIATION " + - ToStringParamsHelper(ast->Parent(), ast->AsTSTypeParameterInstantiation()->Params()); - } - case ir::AstNodeType::THROW_STATEMENT: { - return "THROW_STMT " + ToStringHelper(ast->AsThrowStatement()->Argument()); - } - case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { - return "NEW_CLS_INSTANCE " + ToStringHelper(ast->AsETSNewClassInstanceExpression()->GetTypeRef()); - } - case ir::AstNodeType::STRING_LITERAL: { - return "STR_LITERAL " + ToStringHelper(ast->AsStringLiteral()->Str()); - } - case ir::AstNodeType::TRY_STATEMENT: { - return "TRY_STMT " + ToStringHelper(ast->AsTryStatement()->Block()); - } - case ir::AstNodeType::CATCH_CLAUSE: { - return "CATCH_CLAUSE "; - } - case ir::AstNodeType::NUMBER_LITERAL: { - return "NUMBER_LITERAL " + ToStringHelper(ast->AsNumberLiteral()->Str()); - } - case ir::AstNodeType::ETS_PARAMETER_EXPRESSION: { - return "ETS_PARAM_EXPR " + ToStringHelper(ast->AsETSParameterExpression()->Ident()); - } - case ir::AstNodeType::TS_INTERFACE_DECLARATION: { - return "TS_INTERFACE_DECL " + ToStringHelper(ast->AsTSInterfaceDeclaration()->Id()); + return std::nullopt; + } + + bool ScopeEncloseVariable(ASTVerifier::ErrorContext &ctx, const varbinder::LocalVariable *var) + { + ASSERT(var); + + const auto scope = var->GetScope(); + if (scope == nullptr || var->Declaration() == nullptr) { + return true; } - case ir::AstNodeType::TS_INTERFACE_BODY: { - return "TS_INTERFACE_BODY "; + const auto node = var->Declaration()->Node(); + if (node == nullptr) { + return true; } - case ir::AstNodeType::ETS_FUNCTION_TYPE: { - return "ETS_FUNC_TYPE " + ToStringParamsHelper(ast->AsETSFunctionType()->Params()); + const auto var_start = node->Start(); + bool is_ok = true; + if (scope->Bindings().count(var->Name()) == 0) { + ctx.AddInvariantError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node, var_start); + is_ok = false; } - case ir::AstNodeType::TS_CLASS_IMPLEMENTS: { - return "TS_CLASS_IMPL " + ToStringHelper(ast->AsTSClassImplements()->Expr()); + const auto scope_node = scope->Node(); + auto var_node = node; + if (!IsContainedIn(var_node, scope_node) || scope_node == nullptr) { + ctx.AddInvariantError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node, var_start); + is_ok = false; } - default: { - return "MUST BE UNREACHABLE"; + const auto &decls = scope->Decls(); + const auto decl_dominate = std::count(decls.begin(), decls.end(), var->Declaration()); + if (decl_dominate == 0) { + ctx.AddInvariantError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node, var_start); + is_ok = false; } - } -} - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) -#define ADD_CHECK(Name) \ - { \ - const auto check = [this](const ir::AstNode *ast) -> bool { return this->Name(ast); }; \ - checks_.emplace_back(NamedCheck {#Name, check}); \ - all_checks_.insert(#Name); \ - checks_.emplace_back(NamedCheck {#Name "Recursive", RecursiveCheck(check)}); \ - all_checks_.insert(#Name "Recursive"); \ - } -// NOLINTEND(cppcoreguidelines-macro-usage) - -bool ASTVerifier::HasParent(const ir::AstNode *ast) -{ - if (ast != nullptr && !ast->IsETSScript() && ast->Parent() == nullptr) { - AddError("NULL_PARENT: " + ToStringHelper(ast), ast->Start()); - return false; + return is_ok; } - return true; -} +private: + ArenaAllocator &allocator_; +}; -bool ASTVerifier::HasType(const ir::AstNode *ast) -{ - if (ast->IsTyped() && static_cast(ast)->TsType() == nullptr) { - AddError("NULL_TS_TYPE: " + ToStringHelper(ast), ast->Start()); - return false; - } - return true; -} +class EveryChildHasValidParent { +public: + explicit EveryChildHasValidParent([[maybe_unused]] ArenaAllocator &allocator) {} -bool ASTVerifier::HasVariable(const ir::AstNode *ast) -{ - if (!ast->IsIdentifier() || ast->AsIdentifier()->Variable() != nullptr) { - return true; + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + auto result = ASTVerifier::CheckResult::Success; + if (ast->IsETSScript()) { + return result; + } + ast->Iterate([&](const ir::AstNode *node) { + if (ast != node->Parent()) { + ctx.AddInvariantError("INCORRECT_PARENT_REF", *node, node->Start()); + result = ASTVerifier::CheckResult::Failed; + } + }); + return result; } - const auto *id = ast->AsIdentifier(); - AddError("NULL_VARIABLE: " + ToStringHelper(id), id->Start()); - return false; -} +private: +}; -bool ASTVerifier::HasScope(const ir::AstNode *ast) -{ - if (!ast->IsIdentifier()) { - return true; // we will check only Identifier - } +class VariableHasEnclosingScope { +public: + explicit VariableHasEnclosingScope(ArenaAllocator &allocator) : allocator_ {allocator} {} - // we will check only local variables of identifiers - if (const auto maybe_var = GetLocalScopeVariable(ast)) { + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + const auto maybe_var = VariableHasScope::GetLocalScopeVariable(allocator_, ctx, ast); + if (!maybe_var) { + return ASTVerifier::CheckResult::Success; + } const auto var = *maybe_var; const auto scope = var->GetScope(); if (scope == nullptr) { - AddError("NULL_SCOPE_LOCAL_VAR: " + ToStringHelper(ast), ast->Start()); - return false; + // already checked + return ASTVerifier::CheckResult::Success; } - return ScopeEncloseVariable(var); + const auto enclose_scope = scope->EnclosingVariableScope(); + if (enclose_scope == nullptr) { + ctx.AddInvariantError("NO_ENCLOSING_VAR_SCOPE", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + const auto node = scope->Node(); + auto result = ASTVerifier::CheckResult::Success; + if (!IsContainedIn(ast, node)) { + result = ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); + } + if (!IsContainedIn(scope, enclose_scope)) { + result = ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); + } + return result; } - return true; -} -std::optional ASTVerifier::GetLocalScopeVariable(const ir::AstNode *ast) -{ - if (!ast->IsIdentifier()) { - return std::nullopt; - } +private: + ArenaAllocator &allocator_; +}; - const auto variable = ast->AsIdentifier()->Variable(); - if (HasVariable(ast) && variable->IsLocalVariable()) { - const auto local_var = variable->AsLocalVariable(); - if (local_var->HasFlag(varbinder::VariableFlags::LOCAL)) { - return local_var; +class SequenceExpressionHasLastType { +public: + explicit SequenceExpressionHasLastType([[maybe_unused]] ArenaAllocator &allocator) {} + + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (!ast->IsSequenceExpression()) { + return ASTVerifier::CheckResult::Success; + } + const auto *expr = ast->AsSequenceExpression(); + const auto *last = expr->Sequence().back(); + if (expr->TsType() == nullptr) { + ctx.AddInvariantError("Sequence expression type is null", *expr, expr->Start()); + return ASTVerifier::CheckResult::Failed; } + if (last->TsType() == nullptr) { + ctx.AddInvariantError("Sequence expression last type is null", *last, last->Start()); + return ASTVerifier::CheckResult::Failed; + } + if (expr->TsType() != last->TsType()) { + ctx.AddInvariantError("Sequence expression type and last expression type are not the same", *expr, + expr->Start()); + return ASTVerifier::CheckResult::Failed; + } + return ASTVerifier::CheckResult::Success; } - return std::nullopt; -} -bool ASTVerifier::VerifyChildNode(const ir::AstNode *ast) -{ - ASSERT(ast); - bool is_ok = true; - ast->Iterate([&](const auto node) { - if (ast != node->Parent()) { - AddError("INCORRECT_PARENT_REF: " + ToStringHelper(node), node->Start()); - is_ok = false; - } - }); - return is_ok; -} +private: +}; -bool ASTVerifier::VerifyScopeNode(const ir::AstNode *ast) -{ - ASSERT(ast); - const auto maybe_var = GetLocalScopeVariable(ast); - if (!maybe_var) { - return true; - } - const auto var = *maybe_var; - const auto scope = var->GetScope(); - if (scope == nullptr) { - // already checked - return false; - } - const auto enclose_scope = scope->EnclosingVariableScope(); - if (enclose_scope == nullptr) { - AddError("NO_ENCLOSING_VAR_SCOPE: " + ToStringHelper(ast), ast->Start()); - return false; - } - const auto node = scope->Node(); - bool is_ok = true; - if (!IsContainedIn(ast, node)) { - is_ok = false; - AddError("VARIABLE_NOT_ENCLOSE_SCOPE: " + ToStringHelper(ast), ast->Start()); - } - if (!IsContainedIn(scope, enclose_scope)) { - is_ok = false; - AddError("VARIABLE_NOT_ENCLOSE_SCOPE: " + ToStringHelper(ast), ast->Start()); - } - return is_ok; -} +class ForLoopCorrectlyInitialized { +public: + explicit ForLoopCorrectlyInitialized([[maybe_unused]] ArenaAllocator &allocator) {} -bool ASTVerifier::ScopeEncloseVariable(const varbinder::LocalVariable *var) -{ - ASSERT(var); + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (ast->IsForInStatement()) { + auto const *left = ast->AsForInStatement()->Left(); + if (left == nullptr) { + ctx.AddInvariantError("NULL FOR-IN-LEFT", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } - const auto scope = var->GetScope(); - if (scope == nullptr || var->Declaration() == nullptr) { - return true; - } - const auto node = var->Declaration()->Node(); - if (node == nullptr) { - return true; - } - const auto var_start = node->Start(); - bool is_ok = true; - if (scope->Bindings().count(var->Name()) == 0) { - AddError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR: " + ToStringHelper(node), var_start); - is_ok = false; - } - const auto scope_node = scope->Node(); - auto var_node = node; - if (!IsContainedIn(var_node, scope_node) || scope_node == nullptr) { - AddError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE: " + ToStringHelper(node), var_start); - is_ok = false; - } - const auto &decls = scope->Decls(); - const auto decl_dominate = std::count(decls.begin(), decls.end(), var->Declaration()); - if (decl_dominate == 0) { - AddError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL: " + ToStringHelper(node), var_start); - is_ok = false; - } - return is_ok; -} + if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { + ctx.AddInvariantError("INCORRECT FOR-IN-LEFT", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + } -bool ASTVerifier::CheckArithmeticExpression(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; - } + if (ast->IsForOfStatement()) { + auto const *left = ast->AsForOfStatement()->Left(); + if (left == nullptr) { + ctx.AddInvariantError("NULL FOR-OF-LEFT", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } - if (ast->IsBinaryExpression() && ast->AsBinaryExpression()->IsArithmetic()) { - if (ast->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS && - IsStringType(ast->AsBinaryExpression()->Left()) && IsStringType(ast->AsBinaryExpression()->Right())) { - return true; + if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { + ctx.AddInvariantError("INCORRECT FOR-OF-LEFT", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } } - bool is_correct = true; - ast->Iterate([&is_correct](ir::AstNode *child) { is_correct &= (IsNumericType(child)); }); - return is_correct; - } - return true; -} + if (ast->IsForUpdateStatement()) { + // The most important part of for-loop is the test. + // But it also can be null. Then there must be break;(return) in the body. + auto const *test = ast->AsForUpdateStatement()->Test(); + if (test == nullptr) { + auto const *body = ast->AsForUpdateStatement()->Body(); + if (body == nullptr) { + ctx.AddInvariantError("NULL FOR-TEST AND FOR-BODY", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + bool has_exit = body->IsBreakStatement() || body->IsReturnStatement(); + body->IterateRecursively([&has_exit](ir::AstNode *child) { + has_exit |= child->IsBreakStatement() || child->IsReturnStatement(); + }); + if (!has_exit) { + // an infinite loop + ctx.AddInvariantError("WARNING: NULL FOR-TEST AND FOR-BODY doesn't exit", *ast, ast->Start()); + } + return ASTVerifier::CheckResult::Success; + } -bool ASTVerifier::IsForLoopCorrectInitialized(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; + if (!test->IsExpression()) { + ctx.AddInvariantError("NULL FOR VAR", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + } + return ASTVerifier::CheckResult::Success; } - if (ast->IsForInStatement()) { - auto const *left = ast->AsForInStatement()->Left(); - if (left == nullptr) { - AddError("NULL FOR-IN-LEFT: " + ToStringHelper(ast), ast->Start()); - return false; - } +private: +}; - if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { - AddError("INCORRECT FOR-IN-LEFT: " + ToStringHelper(ast), ast->Start()); - return false; +class ModifierAccessValid { +public: + explicit ModifierAccessValid([[maybe_unused]] ArenaAllocator &allocator) {} + + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (ast->IsMemberExpression()) { + const auto *prop_var = ast->AsMemberExpression()->PropVar(); + if (prop_var != nullptr && prop_var->HasFlag(varbinder::VariableFlags::PROPERTY) && + !ValidateVariableAccess(prop_var, ast->AsMemberExpression())) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + } + if (ast->IsCallExpression()) { + const auto *call_expr = ast->AsCallExpression(); + const auto *callee = call_expr->Callee(); + if (callee != nullptr && callee->IsMemberExpression()) { + const auto *callee_member = callee->AsMemberExpression(); + const auto *prop_var_callee = callee_member->PropVar(); + if (prop_var_callee != nullptr && prop_var_callee->HasFlag(varbinder::VariableFlags::METHOD) && + !ValidateMethodAccess(callee_member, ast->AsCallExpression())) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *callee, callee->Start()); + return ASTVerifier::CheckResult::Failed; + } + } } + return ASTVerifier::CheckResult::Success; + } + +private: +}; + +class ImportExportAccessValid { +public: + explicit ImportExportAccessValid([[maybe_unused]] ArenaAllocator &allocator) {} + + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + ASTVerifier::InvariantSet imported_variables {}; + if (ast->IsETSImportDeclaration()) { + const auto import_decl = ast->AsETSImportDeclaration()->Specifiers(); + const auto name = [](ir::AstNode *const specifier) { + if (specifier->IsImportNamespaceSpecifier()) { + return specifier->AsImportNamespaceSpecifier()->Local()->Name(); + } + if (specifier->IsImportSpecifier()) { + return specifier->AsImportSpecifier()->Local()->Name(); + } + return specifier->AsImportDefaultSpecifier()->Local()->Name(); + }; + for (const auto import : import_decl) { + imported_variables.emplace(name(import)); + } + } + if (ast->IsCallExpression()) { + const auto *call_expr = ast->AsCallExpression(); + const auto *callee = call_expr->Callee(); + if (callee != nullptr && callee->IsIdentifier() && + !HandleImportExportIdentifier(imported_variables, callee->AsIdentifier(), call_expr)) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee, callee->Start()); + return ASTVerifier::CheckResult::Failed; + } + } + if (ast->IsIdentifier() && !HandleImportExportIdentifier(imported_variables, ast->AsIdentifier(), nullptr)) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast, ast->Start()); + return ASTVerifier::CheckResult::Failed; + } + return ASTVerifier::CheckResult::Success; } - if (ast->IsForOfStatement()) { - auto const *left = ast->AsForOfStatement()->Left(); - if (left == nullptr) { - AddError("NULL FOR-OF-LEFT: " + ToStringHelper(ast), ast->Start()); +private: + bool ValidateExport(const varbinder::Variable *var) + { + const auto *decl = var->Declaration(); + if (decl == nullptr) { return false; } - - if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { - AddError("INCORRECT FOR-OF-LEFT: " + ToStringHelper(ast), ast->Start()); + const auto *node = decl->Node(); + if (node == nullptr) { return false; } + return node->IsExported(); } - if (ast->IsForUpdateStatement()) { - // The most important part of for-loop is the test. - // But it also can be null. Then there must be break;(return) in the body. - auto const *test = ast->AsForUpdateStatement()->Test(); - if (test == nullptr) { - auto const *body = ast->AsForUpdateStatement()->Body(); - if (body == nullptr) { - AddError("NULL FOR-TEST AND FOR-BODY: " + ToStringHelper(ast), ast->Start()); - return false; - } - bool has_exit = body->IsBreakStatement() || body->IsReturnStatement(); - body->IterateRecursively([&has_exit](ir::AstNode *child) { - has_exit |= child->IsBreakStatement() || child->IsReturnStatement(); - }); - if (!has_exit) { - // an infinite loop - AddError("WARNING: NULL FOR-TEST AND FOR-BODY doesn't exit: " + ToStringHelper(ast), ast->Start()); - } + bool InvariantImportExportMethod(const ASTVerifier::InvariantSet &imported_variables, + const varbinder::Variable *var_callee, const ir::AstNode *call_expr, + util::StringView name) + { + auto *signature = call_expr->AsCallExpression()->Signature(); + if (signature->Owner() == nullptr) { + // NOTE(vpukhov): Add a synthetic owner for dynamic signatures + ASSERT(call_expr->AsCallExpression()->Callee()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)); return true; } - if (test->IsExpression()) { - AddError("NULL FOR VAR: " + ToStringHelper(ast), ast->Start()); + if (signature != nullptr && var_callee->Declaration() != nullptr && + var_callee->Declaration()->Node() != nullptr && + !IsContainedIn(var_callee->Declaration()->Node(), signature->Owner()->GetDeclNode()) && + var_callee->Declaration()->Node() != signature->Owner()->GetDeclNode()) { + if (imported_variables.find(name.Mutf8()) != imported_variables.end() || + imported_variables.find("") != imported_variables.end()) { + return ValidateExport(var_callee); + } return false; } + return true; } - return true; -} - -bool ASTVerifier::AreForLoopsCorrectInitialized(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; - } - - bool is_for_initialized = IsForLoopCorrectInitialized(ast); - ast->IterateRecursively( - [this, &is_for_initialized](ir::AstNode *child) { is_for_initialized &= IsForLoopCorrectInitialized(child); }); - return is_for_initialized; -} -bool ASTVerifier::VerifyModifierAccess(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; - } - if (ast->IsMemberExpression()) { - const auto *prop_var = ast->AsMemberExpression()->PropVar(); - if (prop_var == nullptr || (prop_var->HasFlag(varbinder::VariableFlags::PROPERTY) && - !ValidateVariableAccess(prop_var, ast->AsMemberExpression()))) { - AddError("PROPERTY_NOT_VISIBLE_HERE: " + ToStringHelper(ast), ast->Start()); - return false; - } - } - if (ast->IsCallExpression()) { - const auto *call_expr = ast->AsCallExpression(); - const auto *callee = call_expr->Callee(); - if (callee == nullptr) { - return false; - } - if (callee->IsMemberExpression()) { - const auto *callee_member = callee->AsMemberExpression(); - const auto *prop_var_callee = callee_member->PropVar(); - if (prop_var_callee == nullptr || (prop_var_callee->HasFlag(varbinder::VariableFlags::METHOD) && - !ValidateMethodAccess(callee_member, ast->AsCallExpression()))) { - AddError("PROPERTY_NOT_VISIBLE_HERE: " + ToStringHelper(callee), callee->Start()); + bool InvariantImportExportVariable(const ASTVerifier::InvariantSet &imported_variables, + const varbinder::Variable *var, const ir::Identifier *ident, + util::StringView name) + { + if (!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::VAR) && + var->HasFlag(varbinder::VariableFlags::INITIALIZED) && var->Declaration() != nullptr && + var->Declaration()->Node() != nullptr && !var->Declaration()->Node()->IsMethodDefinition() && + !var->Declaration()->Node()->IsClassProperty()) { + auto var_parent = var->Declaration()->Node()->Parent(); + if (var_parent != nullptr && !IsContainedIn(ident->Parent(), var_parent) && ident->Parent() != var_parent) { + if (var->GetScope() != nullptr && var->GetScope()->Parent() != nullptr && + var->GetScope()->Parent()->IsGlobalScope() && + ident->GetTopStatement() == var_parent->GetTopStatement()) { + return true; + } + if (imported_variables.find(name.Mutf8()) != imported_variables.end() || + imported_variables.find("") != imported_variables.end()) { + return ValidateExport(var); + } return false; } } + return true; } - return true; -} -bool ASTVerifier::VerifyExportAccess(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; - } - if (ast->IsETSImportDeclaration()) { - const auto import_decl = ast->AsETSImportDeclaration()->Specifiers(); - const auto name = [](ir::AstNode *const specifier) { - if (specifier->IsImportNamespaceSpecifier()) { - return specifier->AsImportNamespaceSpecifier()->Local()->Name(); + bool HandleImportExportIdentifier(ASTVerifier::InvariantSet &imported_variables, const ir::Identifier *ident, + const ir::AstNode *call_expr) + { + if (ident->IsReference()) { + const auto *var = ident->Variable(); + if (var != nullptr) { + if (var->HasFlag(varbinder::VariableFlags::METHOD) && call_expr != nullptr) { + return InvariantImportExportMethod(imported_variables, var, call_expr, ident->Name()); + } + return InvariantImportExportVariable(imported_variables, var, ident, ident->Name()); } - if (specifier->IsImportSpecifier()) { - return specifier->AsImportSpecifier()->Local()->Name(); - } - return specifier->AsImportDefaultSpecifier()->Local()->Name(); - }; - for (const auto import : import_decl) { - imported_variables_.emplace(name(import)); - } - } - if (ast->IsCallExpression()) { - const auto *call_expr = ast->AsCallExpression(); - const auto *callee = call_expr->Callee(); - if (callee != nullptr && callee->IsIdentifier() && - !HandleImportExportIdentifier(callee->AsIdentifier(), call_expr)) { - AddError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED): " + ToStringHelper(callee), callee->Start()); - return false; } - } - if (ast->IsIdentifier() && !HandleImportExportIdentifier(ast->AsIdentifier())) { - AddError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED): " + ToStringHelper(ast), ast->Start()); - return false; - } - return true; -} - -bool ASTVerifier::CheckImportExportMethod(const varbinder::Variable *var_callee, const ir::AstNode *call_expr, - util::StringView name) -{ - auto *signature = call_expr->AsCallExpression()->Signature(); - if (signature->Owner() == nullptr) { - // NOTE(vpukhov): Add a synthetic owner for dynamic signatures - ASSERT(call_expr->AsCallExpression()->Callee()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)); return true; } +}; + +class ArithmeticOperationValid { +public: + explicit ArithmeticOperationValid([[maybe_unused]] ArenaAllocator &allocator) {} - if (signature != nullptr && var_callee->Declaration() != nullptr && var_callee->Declaration()->Node() != nullptr && - !IsContainedIn(var_callee->Declaration()->Node(), signature->Owner()->GetDeclNode()) && - var_callee->Declaration()->Node() != signature->Owner()->GetDeclNode()) { - if (imported_variables_.find(name) != imported_variables_.end() || - imported_variables_.find(util::StringView("")) != imported_variables_.end()) { - return ValidateExport(var_callee); + ASTVerifier::CheckResult operator()([[maybe_unused]] ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (ast->IsBinaryExpression() && ast->AsBinaryExpression()->IsArithmetic()) { + if (ast->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS && + IsStringType(ast->AsBinaryExpression()->Left()) && IsStringType(ast->AsBinaryExpression()->Right())) { + return ASTVerifier::CheckResult::Success; + } + auto result = ASTVerifier::CheckResult::Success; + ast->Iterate([&result](ir::AstNode *child) { + if (!IsNumericType(child)) { + result = ASTVerifier::CheckResult::Failed; + } + }); + return result; } - return false; + + return ASTVerifier::CheckResult::Success; } - return true; -} -bool ASTVerifier::CheckImportExportVariable(const varbinder::Variable *var, const ir::Identifier *ident, - util::StringView name) -{ - if (!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::VAR) && - var->HasFlag(varbinder::VariableFlags::INITIALIZED) && var->Declaration() != nullptr && - var->Declaration()->Node() != nullptr && !var->Declaration()->Node()->IsMethodDefinition() && - !var->Declaration()->Node()->IsClassProperty()) { - auto var_parent = var->Declaration()->Node()->Parent(); - if (var_parent != nullptr && !IsContainedIn(ident->Parent(), var_parent) && ident->Parent() != var_parent) { - if (var->GetScope() != nullptr && var->GetScope()->Parent() != nullptr && - var->GetScope()->Parent()->IsGlobalScope() && - ident->GetTopStatement() == var_parent->GetTopStatement()) { - return true; +private: +}; + +template +static ASTVerifier::InvariantCheck RecursiveInvariant(Func &func) +{ + return [&func](ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) -> ASTVerifier::CheckResult { + std::function aux; + auto result = ASTVerifier::CheckResult::Success; + aux = [&ctx, &func, &aux, &result](const ir::AstNode *child) -> void { + if (result == ASTVerifier::CheckResult::Failed) { + return; } - if (imported_variables_.find(name) != imported_variables_.end() || - imported_variables_.find(util::StringView("")) != imported_variables_.end()) { - return ValidateExport(var); + const auto new_result = func(ctx, child); + if (new_result == ASTVerifier::CheckResult::SkipSubtree) { + return; } - return false; - } - } - return true; + result = new_result; + child->Iterate(aux); + }; + aux(ast); + return result; + }; } -bool ASTVerifier::HandleImportExportIdentifier(const ir::Identifier *ident, const ir::AstNode *call_expr) -{ - if (ident->IsReference()) { - const auto *var = ident->Variable(); - if (var != nullptr) { - if (var->HasFlag(varbinder::VariableFlags::METHOD) && call_expr != nullptr) { - return CheckImportExportMethod(var, call_expr, ident->Name()); - } - return CheckImportExportVariable(var, ident, ident->Name()); - } +// NOLINTBEGIN(cppcoreguidelines-macro-usage) +#define ADD_INVARIANT(Name) \ + { \ + auto *invariant = allocator->New(*allocator); \ + invariants_checks_.emplace_back(Invariant {#Name, *invariant}); \ + invariants_names_.insert(#Name); \ + invariants_checks_.emplace_back(Invariant {#Name RECURSIVE_SUFFIX, RecursiveInvariant(*invariant)}); \ + invariants_names_.insert(#Name RECURSIVE_SUFFIX); \ } - return true; -} +// NOLINTEND(cppcoreguidelines-macro-usage) -ASTVerifier::ASTVerifier(ArenaAllocator *allocator, bool save_errors, util::StringView source_code) - : save_errors_(save_errors), - allocator_ {allocator}, - named_errors_ {allocator_->Adapter()}, - encountered_errors_ {allocator_->Adapter()}, - checks_ {allocator_->Adapter()}, - all_checks_(allocator_->Adapter()) +ASTVerifier::ASTVerifier(ArenaAllocator *allocator) : invariants_checks_ {}, invariants_names_ {} { - if (!source_code.Empty()) { - index_.emplace(source_code); - } - - ADD_CHECK(HasParent); - ADD_CHECK(HasType); - ADD_CHECK(HasVariable); - ADD_CHECK(HasScope); - ADD_CHECK(VerifyChildNode); - ADD_CHECK(VerifyScopeNode); - ADD_CHECK(IsForLoopCorrectInitialized); - ADD_CHECK(AreForLoopsCorrectInitialized); - ADD_CHECK(VerifyModifierAccess); - ADD_CHECK(VerifyExportAccess); - ADD_CHECK(CheckArithmeticExpression); + ADD_INVARIANT(NodeHasParent); + ADD_INVARIANT(NodeHasType); + ADD_INVARIANT(IdentifierHasVariable); + ADD_INVARIANT(VariableHasScope); + ADD_INVARIANT(EveryChildHasValidParent); + ADD_INVARIANT(VariableHasEnclosingScope); + ADD_INVARIANT(ForLoopCorrectlyInitialized); + ADD_INVARIANT(ModifierAccessValid); + ADD_INVARIANT(ImportExportAccessValid); + ADD_INVARIANT(ArithmeticOperationValid); + ADD_INVARIANT(SequenceExpressionHasLastType); } -bool ASTVerifier::VerifyFull(const ir::AstNode *ast) +ASTVerifier::Errors ASTVerifier::VerifyFull(const ir::AstNode *ast) { - return Verify(ast, all_checks_); + auto recursive_checks = InvariantSet {}; + std::copy_if(invariants_names_.begin(), invariants_names_.end(), + std::inserter(recursive_checks, recursive_checks.end()), + [](const std::string &s) { return s.find(RECURSIVE_SUFFIX) != s.npos; }); + return Verify(ast, recursive_checks); } -bool ASTVerifier::Verify(const ir::AstNode *ast, const CheckSet &check_set) +ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantSet &invariant_set) { - bool is_correct = true; - auto check_and_report = [&is_correct, this](util::StringView name, const CheckFunction &check, - const ir::AstNode *node) { + ErrorContext ctx {}; + auto check_and_report = [&ctx](util::StringView name, const InvariantCheck &invariant, const ir::AstNode *node) { if (node == nullptr) { return; } - is_correct &= check(node); - if (!is_correct) { - for (const auto &error : encountered_errors_) { - named_errors_.emplace_back(NamedError {name, error}); - } - encountered_errors_.clear(); - } + invariant(ctx, node); + // if (result == CheckResult::Failed || result == CheckResult::SkipSubtree) { + ctx.ProcessEncounteredErrors(name); + // } }; - const auto contains_checks = - std::includes(all_checks_.begin(), all_checks_.end(), check_set.begin(), check_set.end()); - if (!contains_checks) { - auto invalid_checks = CheckSet {allocator_->Adapter()}; - for (const auto &check : check_set) { - if (all_checks_.find(check) == all_checks_.end()) { - invalid_checks.insert(check); + const auto contains_invariants = + std::includes(invariants_names_.begin(), invariants_names_.end(), invariant_set.begin(), invariant_set.end()); + + if (!contains_invariants) { + auto invalid_invariants = InvariantSet {}; + for (const auto &invariant : invariant_set) { + if (invariants_names_.find(invariant.data()) == invariants_names_.end()) { + invalid_invariants.insert(invariant.data()); } } - for (const auto &check : invalid_checks) { - const auto &message = check.Mutf8() + " check is not found"; - named_errors_.emplace_back(NamedError {"Check", Error {message, lexer::SourceLocation {}}}); + for (const auto &invariant : invalid_invariants) { + ctx.AddError(std::string {"invariant was not found: "} + invariant.data()); } } - for (const auto &[name, check] : checks_) { - if (check_set.find(name) != check_set.end()) { - check_and_report(name, check, ast); + for (const auto &invariant_name : invariant_set) { + for (const auto &[name, invariant] : invariants_checks_) { + if (std::string_view {invariant_name} == name.Utf8()) { + check_and_report(name, invariant, ast); + break; + } } } - return is_correct; + + return ctx.GetErrors(); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ASTVerifier.h b/ets2panda/compiler/core/ASTVerifier.h index 906c97c3cf..36454b0465 100644 --- a/ets2panda/compiler/core/ASTVerifier.h +++ b/ets2panda/compiler/core/ASTVerifier.h @@ -16,106 +16,172 @@ #ifndef ES2PANDA_COMPILER_CORE_ASTVERIFIER_H #define ES2PANDA_COMPILER_CORE_ASTVERIFIER_H +#include #include "ir/astNode.h" #include "lexer/token/sourceLocation.h" +#include "parser/program/program.h" #include "util/ustring.h" #include "utils/arena_containers.h" #include "varbinder/variable.h" +#include "utils/json_builder.h" +#include "ir/statements/blockStatement.h" +#include "compiler/lowering/phase.h" namespace panda::es2panda::compiler { +/* + * ASTVerifier used for checking various invariants that should hold during AST transformation in lowerings + * For all available checks lookup the constructor + */ class ASTVerifier final { public: - struct Error { + struct InvariantError { + std::string cause; std::string message; - lexer::SourceLocation location; + size_t line; }; - struct NamedError { - util::StringView check_name; - Error error; + struct CheckError { + util::StringView invariant_name; + InvariantError error; + + std::function DumpJSON() const + { + return [&](JsonObjectBuilder &body) { + body.AddProperty("invariant", invariant_name.Utf8()); + body.AddProperty("cause", error.cause); + body.AddProperty("message", error.message); + body.AddProperty("line", error.line + 1); + }; + } }; - using Errors = ArenaVector; - - using CheckFunction = std::function; - struct NamedCheck { - util::StringView check_name; - CheckFunction check; + using Errors = std::vector; + + enum class CheckResult { Failed, Success, SkipSubtree }; + struct ErrorContext; + using InvariantCheck = std::function; + struct Invariant { + util::StringView invariant_name; + InvariantCheck invariant; }; - using Checks = ArenaVector; + using Invariants = std::vector; NO_COPY_SEMANTIC(ASTVerifier); NO_MOVE_SEMANTIC(ASTVerifier); - explicit ASTVerifier(ArenaAllocator *allocator, bool save_errors = true, util::StringView source_code = ""); + explicit ASTVerifier(ArenaAllocator *allocator); ~ASTVerifier() = default; - using CheckSet = ArenaSet; + using InvariantSet = std::set; /** - * @brief Run all existing checks on some ast node (and consequently it's children) + * @brief Run all existing invariants on some ast node (and consequently it's children) * @param ast AstNode which will be analyzed - * @return bool Result of analysis + * @return Errors report of analysis */ - bool VerifyFull(const ir::AstNode *ast); + Errors VerifyFull(const ir::AstNode *ast); /** - * @brief Run some particular checks on some ast node - * @note Checks must be supplied as strings to check_set, additionally check - * name can be suffixed by `Recursive` string to include recursive analysis of provided node + * @brief Run some particular invariants on some ast node + * @note invariants must be supplied as strings to invariant_set, additionally invariant + * name can be suffixed by `ForAll` string to include recursive analysis of provided node + * I.e. 'HasParent' invariant can be named 'HasParentRecursive' to traverse all child nodes as well * @param ast AstNode which will be analyzed - * @param check_set Set of strings which will be used as check names - * @return bool Result of analysis + * @param invariant_set Set of strings which will be used as invariant names + * @return Errors report of analysis */ - bool Verify(const ir::AstNode *ast, const CheckSet &check_set); + Errors Verify(const ir::AstNode *ast, const InvariantSet &invariant_set); + +private: + Invariants invariants_checks_; + InvariantSet invariants_names_; +}; - Errors GetErrors() const +class ASTVerifierContext final { +public: + ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} + + void IntroduceNewInvariants(util::StringView phase_name) { - return named_errors_; + auto invariant_set = [phase_name]() -> std::optional { + (void)phase_name; + if (phase_name == "ScopesInitPhase") { + return {{ + "NodeHasParentForAll", + "IdentifierHasVariableForAll", + "ModifierAccessValidForAll", + "ImportExportAccessValid", + }}; + } else if (phase_name == "PromiseVoidInferencePhase") { + return {{}}; + } else if (phase_name == "StructLowering") { + return {{}}; + } else if (phase_name == "CheckerPhase") { + return {{ + "NodeHasTypeForAll", + "ArithmeticOperationValidForAll", + "SequenceExpressionHasLastTypeForAll", + "EveryChildHasValidParentForAll", + "ForLoopCorrectlyInitializedForAll", + "VariableHasScopeForAll", + "VariableHasEnclosingScopeForAll", + }}; + } else if (phase_name == "GenerateTsDeclarationsPhase") { + return {{}}; + } else if (phase_name == "InterfacePropertyDeclarationsPhase") { + return {{}}; + } else if (phase_name == "LambdaConstructionPhase") { + return {{}}; + } else if (phase_name == "ObjectIndexLowering") { + return {{}}; + } else if (phase_name == "OpAssignmentLowering") { + return {{}}; + } else if (phase_name == "PromiseVoidInferencePhase") { + return {{}}; + } else if (phase_name == "TupleLowering") { + return {{}}; + } else if (phase_name == "UnionLowering") { + return {{}}; + } else if (phase_name == "ExpandBracketsPhase") { + return {{}}; + } else if (phase_name.Utf8().find("plugins") != std::string_view::npos) { + return {{}}; + } + return std::nullopt; + }(); + + ASSERT_PRINT(invariant_set.has_value(), + std::string {"Invariant set does not contain value for "} + phase_name.Mutf8()); + const auto &s = *invariant_set; + accumulated_checks_.insert(s.begin(), s.end()); } -private: - bool HasParent(const ir::AstNode *ast); - bool HasType(const ir::AstNode *ast); - bool HasVariable(const ir::AstNode *ast); - bool HasScope(const ir::AstNode *ast); - bool VerifyChildNode(const ir::AstNode *ast); - bool VerifyScopeNode(const ir::AstNode *ast); - bool CheckArithmeticExpression(const ir::AstNode *ast); - bool IsForLoopCorrectInitialized(const ir::AstNode *ast); - bool AreForLoopsCorrectInitialized(const ir::AstNode *ast); - bool VerifyModifierAccess(const ir::AstNode *ast); - bool VerifyExportAccess(const ir::AstNode *ast); - - bool HandleImportExportIdentifier(const ir::Identifier *ident, const ir::AstNode *call_expr = nullptr); - bool CheckImportExportVariable(const varbinder::Variable *var, const ir::Identifier *ident, util::StringView name); - bool CheckImportExportMethod(const varbinder::Variable *var_callee, const ir::AstNode *call_expr, - util::StringView name); - - void AddError(const std::string &message, const lexer::SourcePosition &from) + bool Verify(const ir::AstNode *ast, util::StringView phase_name, util::StringView source_name) { - if (save_errors_) { - const auto loc = index_.has_value() ? index_->GetLocation(from) : lexer::SourceLocation {}; - encountered_errors_.emplace_back(Error {message, loc}); + errors_ = verifier_.Verify(ast, accumulated_checks_); + for (const auto &e : errors_) { + error_array_.Add([e, source_name, phase_name](JsonObjectBuilder &err) { + err.AddProperty("from", source_name.Utf8()); + err.AddProperty("phase", phase_name.Utf8()); + err.AddProperty("error", e.DumpJSON()); + }); } + auto result = errors_.empty(); + errors_.clear(); + return result; } - bool ScopeEncloseVariable(const varbinder::LocalVariable *var); - std::optional GetLocalScopeVariable(const ir::AstNode *ast); + std::string DumpErrorsJSON() + { + return std::move(error_array_).Build(); + } private: - std::optional index_; - - bool save_errors_; - ArenaAllocator *allocator_; - Errors named_errors_; - ArenaVector encountered_errors_; - Checks checks_; - CheckSet all_checks_; - std::unordered_set imported_variables_; + ASTVerifier &verifier_; + ASTVerifier::Errors errors_; + JsonArrayBuilder error_array_; + ASTVerifier::InvariantSet accumulated_checks_ {}; }; -std::string ToStringHelper(const ir::AstNode *ast); - } // namespace panda::es2panda::compiler #endif // ES2PANDA_COMPILER_CORE_ASTVERIFIER_H diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index c9847b33cb..ba41b75581 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -15,6 +15,7 @@ #include "compilerImpl.h" +#include "compiler/core/ASTVerifier.h" #include "es2panda.h" #include "checker/ETSAnalyzer.h" #include "checker/TSAnalyzer.h" @@ -129,6 +130,9 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase context.SetEmitter(&emitter); context.SetParser(&parser); + auto verifier = ASTVerifier {&allocator}; + auto verification_ctx = ASTVerifierContext {verifier}; + public_lib::Context public_context; SetupPublicContext(&public_context, &unit.input, &allocator, compiler_impl->Queue(), &compiler_impl->Plugins(), &parser, &context); @@ -142,7 +146,34 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase if (!phase->Apply(&public_context, &program)) { return nullptr; } +#ifndef NDEBUG + using NamedProgram = std::tuple; + ArenaVector to_check {program.Allocator()->Adapter()}; + to_check.push_back(std::make_tuple(program.SourceFilePath(), &program)); + for (const auto &external_source : program.ExternalSources()) { + for (const auto *external : external_source.second) { + to_check.push_back(std::make_tuple(external->SourceFilePath(), external)); + } + } + for (const auto &it : to_check) { + const auto &source_name = std::get<0>(it); + const auto &linked_program = std::get<1>(it); + verification_ctx.Verify(linked_program->Ast(), phase->Name(), source_name); + verification_ctx.IntroduceNewInvariants(phase->Name()); + } +#endif + } + +#ifndef NDEBUG + + if (auto errors = verification_ctx.DumpErrorsJSON(); errors != "[]") { +#ifdef ES2PANDA_AST_VERIFIER_ERROR + ASSERT_PRINT(false, errors); +#else + LOG(ERROR, ES2PANDA) << errors; +#endif } +#endif emitter.GenAnnotation(); diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index 9d9c741087..88fc8ebf4a 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -15,6 +15,7 @@ #include "checkerPhase.h" #include "checker/checker.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" namespace panda::es2panda::compiler { diff --git a/ets2panda/compiler/lowering/checkerPhase.h b/ets2panda/compiler/lowering/checkerPhase.h index ef42e7004b..c1f3de095c 100644 --- a/ets2panda/compiler/lowering/checkerPhase.h +++ b/ets2panda/compiler/lowering/checkerPhase.h @@ -20,11 +20,7 @@ namespace panda::es2panda::compiler { class CheckerPhase : public Phase { - std::string_view Name() override - { - return "checker"; - } - + DECLARE_PHASE_NAME(CheckerPhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/expandBrackets.cpp b/ets2panda/compiler/lowering/ets/expandBrackets.cpp index fdda661afc..715afb9ba5 100644 --- a/ets2panda/compiler/lowering/ets/expandBrackets.cpp +++ b/ets2panda/compiler/lowering/ets/expandBrackets.cpp @@ -63,7 +63,7 @@ bool ExpandBracketsPhase::Perform(public_lib::Context *ctx, parser::Program *pro "(@@E5);", parser::DEFAULT_SOURCE_FILE, ident, dimension, expr_type, ident->Clone(allocator), new_expression); sequence_expr->SetParent(new_expression->Parent()); - ScopesInitPhaseETS::RunExternalNode(sequence_expr, ctx->compiler_context->VarBinder()); + InitScopesPhaseETS::RunExternalNode(sequence_expr, ctx->compiler_context->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(sequence_expr, scope); sequence_expr->Check(checker); diff --git a/ets2panda/compiler/lowering/ets/expandBrackets.h b/ets2panda/compiler/lowering/ets/expandBrackets.h index 7a771f0789..731f04cc18 100644 --- a/ets2panda/compiler/lowering/ets/expandBrackets.h +++ b/ets2panda/compiler/lowering/ets/expandBrackets.h @@ -22,10 +22,7 @@ namespace panda::es2panda::compiler { class ExpandBracketsPhase : public Phase { public: - std::string_view Name() override - { - return "expand-brackets"; - } + DECLARE_PHASE_NAME(ExpandBracketsPhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/generateDeclarations.cpp b/ets2panda/compiler/lowering/ets/generateDeclarations.cpp index 96472eae50..a2ca924836 100644 --- a/ets2panda/compiler/lowering/ets/generateDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/generateDeclarations.cpp @@ -15,10 +15,12 @@ #include "generateDeclarations.h" #include "checker/checker.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "util/declgenEts2Ts.h" namespace panda::es2panda::compiler { + bool GenerateTsDeclarationsPhase::Perform(public_lib::Context *ctx, parser::Program *program) { auto *checker = ctx->checker; diff --git a/ets2panda/compiler/lowering/ets/generateDeclarations.h b/ets2panda/compiler/lowering/ets/generateDeclarations.h index 15ab3c61ef..7e805b86e5 100644 --- a/ets2panda/compiler/lowering/ets/generateDeclarations.h +++ b/ets2panda/compiler/lowering/ets/generateDeclarations.h @@ -22,10 +22,7 @@ namespace panda::es2panda::compiler { class GenerateTsDeclarationsPhase : public Phase { public: - std::string_view Name() override - { - return "generate-ts-declarations"; - } + DECLARE_PHASE_NAME(GenerateTsDeclarationsPhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index 720bfc456e..cc9fe7f293 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -17,6 +17,7 @@ #include "checker/ETSchecker.h" #include "checker/types/type.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "compiler/lowering/util.h" #include "ir/astNode.h" @@ -28,12 +29,6 @@ #include "ir/base/classProperty.h" namespace panda::es2panda::compiler { - -std::string_view InterfacePropertyDeclarationsPhase::Name() -{ - return "interface-prop-decl"; -} - static ir::MethodDefinition *GenerateGetterOrSetter(checker::ETSChecker *const checker, ir::ClassProperty *const field, bool is_setter) { diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h index 866fc16b56..5b4cf6646c 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h @@ -22,7 +22,7 @@ namespace panda::es2panda::compiler { class InterfacePropertyDeclarationsPhase : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(InterfacePropertyDeclarationsPhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 936fe080fe..dbf75f069b 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -15,16 +15,11 @@ #include "lambdaLowering.h" #include "checker/checker.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "util/declgenEts2Ts.h" namespace panda::es2panda::compiler { - -std::string_view LambdaLowering::Name() -{ - return "lambda-lowering"; -} - static ir::AstNode *ConvertExpression(checker::ETSChecker *const checker, ir::ArrowFunctionExpression *const arrow) { auto *const function = arrow->Function(); @@ -43,7 +38,7 @@ static ir::AstNode *ConvertExpression(checker::ETSChecker *const checker, ir::Ar return arrow; } -bool LambdaLowering::Perform(public_lib::Context *ctx, parser::Program *program) +bool LambdaConstructionPhase::Perform(public_lib::Context *ctx, parser::Program *program) { for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; @@ -66,7 +61,7 @@ bool LambdaLowering::Perform(public_lib::Context *ctx, parser::Program *program) return true; } -bool LambdaLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) +bool LambdaConstructionPhase::Postcondition(public_lib::Context *ctx, const parser::Program *program) { for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.h b/ets2panda/compiler/lowering/ets/lambdaLowering.h index c06a4cd3fa..5aba22e52f 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.h +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.h @@ -20,9 +20,9 @@ namespace panda::es2panda::compiler { -class LambdaLowering : public Phase { +class LambdaConstructionPhase : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(LambdaConstructionPhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp index 277f9026ff..70c48c5f80 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp @@ -24,16 +24,10 @@ #include "objectIndexAccess.h" #include "checker/ETSchecker.h" +#include "compiler/core/ASTVerifier.h" #include "parser/ETSparser.h" namespace panda::es2panda::compiler { - -std::string_view ObjectIndexLowering::Name() -{ - static std::string const NAME = "object-index-access"; - return NAME; -} - ir::Expression *ObjectIndexLowering::ProcessIndexSetAccess(parser::ETSParser *parser, checker::ETSChecker *checker, ir::AssignmentExpression *assignment_expression) const { diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.h b/ets2panda/compiler/lowering/ets/objectIndexAccess.h index 5150cd18a2..529f5354f1 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.h +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.h @@ -27,7 +27,7 @@ namespace panda::es2panda::compiler { class ObjectIndexLowering : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(ObjectIndexLowering) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; diff --git a/ets2panda/compiler/lowering/ets/opAssignment.cpp b/ets2panda/compiler/lowering/ets/opAssignment.cpp index c47f0e8c6a..354127150b 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.cpp +++ b/ets2panda/compiler/lowering/ets/opAssignment.cpp @@ -38,11 +38,6 @@ namespace panda::es2panda::compiler { -std::string_view OpAssignmentLowering::Name() -{ - return "op-assignment"; -} - struct Conversion { lexer::TokenType from; lexer::TokenType to; @@ -176,7 +171,7 @@ ir::Expression *HandleOpAssignment(public_lib::Context *ctx, checker::ETSChecker ident1->Clone(allocator), ident2 != nullptr ? ident2->Clone(allocator) : nullptr, ident1->Clone(allocator), ident2 != nullptr ? ident2->Clone(allocator) : nullptr, right, expr_type); lowering_result->SetParent(assignment->Parent()); - ScopesInitPhaseETS::RunExternalNode(lowering_result, ctx->compiler_context->VarBinder()); + InitScopesPhaseETS::RunExternalNode(lowering_result, ctx->compiler_context->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(lowering_result, scope); lowering_result->Check(checker); diff --git a/ets2panda/compiler/lowering/ets/opAssignment.h b/ets2panda/compiler/lowering/ets/opAssignment.h index 407d558a2e..8a4d2ea225 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.h +++ b/ets2panda/compiler/lowering/ets/opAssignment.h @@ -22,7 +22,7 @@ namespace panda::es2panda::compiler { class OpAssignmentLowering : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(OpAssignmentLowering) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/promiseVoid.cpp b/ets2panda/compiler/lowering/ets/promiseVoid.cpp index 06d0bacff8..d098846e99 100644 --- a/ets2panda/compiler/lowering/ets/promiseVoid.cpp +++ b/ets2panda/compiler/lowering/ets/promiseVoid.cpp @@ -16,6 +16,7 @@ #include "promiseVoid.h" #include "checker/ETSchecker.h" #include "checker/checker.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "generated/signatures.h" #include "ir/base/scriptFunction.h" @@ -31,13 +32,6 @@ #include "util/ustring.h" namespace panda::es2panda::compiler { - -std::string_view PromiseVoidLowering::Name() -{ - static std::string const NAME = "promise-void"; - return NAME; -} - static ir::BlockStatement *HandleAsyncScriptFunctionBody(checker::ETSChecker *checker, ir::BlockStatement *body) { (void)checker; @@ -129,7 +123,16 @@ static bool CheckForPromiseVoid(const ir::TypeNode *type) return is_type_promise && is_param_void; } -bool PromiseVoidLowering::Perform(public_lib::Context *ctx, parser::Program *program) +/* + * Transformation is basically syntactical: it adds relevant return type and return statements to methods and function + * NOTE: but not for lambdas, at least for now + * So, the code + * async function f() {} + * transforms to + * async function f(): Promise { return Void; } + * */ + +bool PromiseVoidInferencePhase::Perform(public_lib::Context *ctx, parser::Program *program) { auto *checker = ctx->checker->AsETSChecker(); @@ -182,7 +185,7 @@ bool PromiseVoidLowering::Perform(public_lib::Context *ctx, parser::Program *pro return true; } -bool PromiseVoidLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) +bool PromiseVoidInferencePhase::Postcondition(public_lib::Context *ctx, const parser::Program *program) { (void)ctx; diff --git a/ets2panda/compiler/lowering/ets/promiseVoid.h b/ets2panda/compiler/lowering/ets/promiseVoid.h index b09200838d..2c38eb3577 100644 --- a/ets2panda/compiler/lowering/ets/promiseVoid.h +++ b/ets2panda/compiler/lowering/ets/promiseVoid.h @@ -20,9 +20,9 @@ namespace panda::es2panda::compiler { -class PromiseVoidLowering : public Phase { +class PromiseVoidInferencePhase : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(PromiseVoidInferencePhase) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; diff --git a/ets2panda/compiler/lowering/ets/structLowering.cpp b/ets2panda/compiler/lowering/ets/structLowering.cpp index e1100319b4..67a3db3e00 100644 --- a/ets2panda/compiler/lowering/ets/structLowering.cpp +++ b/ets2panda/compiler/lowering/ets/structLowering.cpp @@ -30,12 +30,6 @@ namespace panda::es2panda::compiler { const char *const STRUCT_CLASS_NAME = "CommonStruct0"; -std::string_view StructLowering::Name() -{ - static std::string const NAME = "struct-class-extention"; - return NAME; -} - ir::ETSTypeReference *CreateStructTypeReference(checker::ETSChecker *checker, ir::ETSStructDeclaration *ets_struc_declaration) { diff --git a/ets2panda/compiler/lowering/ets/structLowering.h b/ets2panda/compiler/lowering/ets/structLowering.h index 3513322a03..8d73628d9a 100644 --- a/ets2panda/compiler/lowering/ets/structLowering.h +++ b/ets2panda/compiler/lowering/ets/structLowering.h @@ -22,7 +22,7 @@ namespace panda::es2panda::compiler { class StructLowering : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(StructLowering) bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/tupleLowering.cpp b/ets2panda/compiler/lowering/ets/tupleLowering.cpp index 34ed65ad7d..c8a9c7f2f9 100644 --- a/ets2panda/compiler/lowering/ets/tupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/tupleLowering.cpp @@ -18,6 +18,7 @@ #include "checker/ETSchecker.h" #include "checker/checker.h" #include "checker/types/type.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "compiler/lowering/util.h" #include "ir/astNode.h" @@ -32,12 +33,6 @@ #include "ir/ts/tsAsExpression.h" namespace panda::es2panda::compiler { - -std::string_view TupleLowering::Name() -{ - return "tuple-lowering"; -} - static ir::Expression *ConvertTupleUpdate(checker::ETSChecker *const checker, ir::UpdateExpression *const update) { // Converts `tuple[n]++` to diff --git a/ets2panda/compiler/lowering/ets/tupleLowering.h b/ets2panda/compiler/lowering/ets/tupleLowering.h index 1c5fce5b97..63aedf3c07 100644 --- a/ets2panda/compiler/lowering/ets/tupleLowering.h +++ b/ets2panda/compiler/lowering/ets/tupleLowering.h @@ -22,7 +22,7 @@ namespace panda::es2panda::compiler { class TupleLowering : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(TupleLowering) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index 603c42b6f7..e5b6a9f9a3 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -14,6 +14,7 @@ */ #include "unionLowering.h" +#include "compiler/core/ASTVerifier.h" #include "varbinder/variableFlags.h" #include "varbinder/ETSBinder.h" #include "checker/ETSchecker.h" @@ -38,12 +39,6 @@ #include "type_helper.h" namespace panda::es2panda::compiler { - -std::string_view UnionLowering::Name() -{ - return "union-property-access"; -} - ir::ClassDefinition *GetUnionFieldClass(checker::ETSChecker *checker, varbinder::VarBinder *varbinder) { // Create the name for the synthetic class node diff --git a/ets2panda/compiler/lowering/ets/unionLowering.h b/ets2panda/compiler/lowering/ets/unionLowering.h index efc0bf6bff..b77c88a380 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.h +++ b/ets2panda/compiler/lowering/ets/unionLowering.h @@ -22,7 +22,7 @@ namespace panda::es2panda::compiler { class UnionLowering : public Phase { public: - std::string_view Name() override; + DECLARE_PHASE_NAME(UnionLowering) bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 6231339684..10bf9f13b7 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -32,6 +32,7 @@ #include "compiler/lowering/ets/structLowering.h" #include "public/es2panda_lib.h" #include "compiler/lowering/ets/promiseVoid.h" +#include "utils/json_builder.h" namespace panda::es2panda::compiler { @@ -46,29 +47,31 @@ std::vector GetTrivialPhaseList() static InterfacePropertyDeclarationsPhase INTERFACE_PROP_DECL_PHASE; static GenerateTsDeclarationsPhase GENERATE_TS_DECLARATIONS_PHASE; -static LambdaLowering LAMBDA_LOWERING; +static LambdaConstructionPhase LAMBDA_CONSTRUCTION_PHASE; static OpAssignmentLowering OP_ASSIGNMENT_LOWERING; static ObjectIndexLowering OBJECT_INDEX_LOWERING; static TupleLowering TUPLE_LOWERING; // Can be only applied after checking phase, and OP_ASSIGNMENT_LOWERING phase static UnionLowering UNION_LOWERING; static ExpandBracketsPhase EXPAND_BRACKETS_PHASE; -static PromiseVoidLowering PROMISE_VOID_LOWERING; +static PromiseVoidInferencePhase PROMISE_VOID_INFERENCE_PHASE; static StructLowering STRUCT_LOWERING; static PluginPhase PLUGINS_AFTER_PARSE {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; static PluginPhase PLUGINS_AFTER_CHECK {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase PLUGINS_AFTER_LOWERINGS {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; +static InitScopesPhaseETS INIT_SCOPES_PHASE_ETS; +static InitScopesPhaseAS INIT_SCOPES_PHASE_AS; +static InitScopesPhaseTs INIT_SCOPES_PHASE_TS; +static InitScopesPhaseJs INIT_SCOPES_PHASE_JS; -// clang-format off std::vector GetETSPhaseList() { - static ScopesInitPhaseETS scopes_phase_ets; return { - &scopes_phase_ets, &PLUGINS_AFTER_PARSE, - &PROMISE_VOID_LOWERING, + &INIT_SCOPES_PHASE_ETS, + &PROMISE_VOID_INFERENCE_PHASE, &STRUCT_LOWERING, - &LAMBDA_LOWERING, + &LAMBDA_CONSTRUCTION_PHASE, &INTERFACE_PROP_DECL_PHASE, &CHECKER_PHASE, &PLUGINS_AFTER_CHECK, @@ -81,31 +84,27 @@ std::vector GetETSPhaseList() &PLUGINS_AFTER_LOWERINGS, }; } -// clang-format on std::vector GetASPhaseList() { - static ScopesInitPhaseAS scopes_phase_as; return { - &scopes_phase_as, + &INIT_SCOPES_PHASE_AS, &CHECKER_PHASE, }; } std::vector GetTSPhaseList() { - static ScopesInitPhaseTs scopes_phase_ts; return { - &scopes_phase_ts, + &INIT_SCOPES_PHASE_TS, &CHECKER_PHASE, }; } std::vector GetJSPhaseList() { - static ScopesInitPhaseJs scopes_phase_js; return { - &scopes_phase_js, + &INIT_SCOPES_PHASE_JS, &CHECKER_PHASE, }; } @@ -128,25 +127,6 @@ std::vector GetPhaseList(ScriptExtension ext) bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) { -#ifndef NDEBUG - const auto check_program = [](const parser::Program *p) { - ASTVerifier verifier {p->Allocator(), false, p->SourceCode()}; - ArenaVector to_check {p->Allocator()->Adapter()}; - to_check.push_back(p->Ast()); - for (const auto &external_source : p->ExternalSources()) { - for (const auto external : external_source.second) { - to_check.push_back(external->Ast()); - } - } - for (const auto *ast : to_check) { - if (!verifier.VerifyFull(ast)) { - return false; - } - } - return true; - }; -#endif - const auto *options = ctx->compiler_context->Options(); const auto name = std::string {Name()}; if (options->skip_phases.count(name) > 0) { @@ -169,8 +149,6 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) CheckOptionsAfterPhase(options, program, name); #ifndef NDEBUG - check_program(program); - if (!Postcondition(ctx, program)) { ctx->checker->ThrowTypeError({"Postcondition check failed for ", util::StringView {Name()}}, lexer::SourcePosition {}); diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index 9e2a381c14..2d369b4239 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -19,6 +19,12 @@ #include "parser/program/program.h" #include "public/public.h" +#define DECLARE_PHASE_NAME(Phase) \ + std::string_view Name() override \ + { \ + return #Phase; \ + } + namespace panda::es2panda::compiler { class Phase { diff --git a/ets2panda/compiler/lowering/plugin_phase.h b/ets2panda/compiler/lowering/plugin_phase.h index 4cff33ec06..dacdf6c84b 100644 --- a/ets2panda/compiler/lowering/plugin_phase.h +++ b/ets2panda/compiler/lowering/plugin_phase.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_COMPILER_PLUGIN_PHASE_H #define ES2PANDA_COMPILER_PLUGIN_PHASE_H +#include "compiler/core/ASTVerifier.h" #include "compiler/lowering/phase.h" #include "util/plugin.h" diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 96be103dbb..4165c0c057 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -563,31 +563,31 @@ void ScopeInitTyped::VisitClassDefinition(ir::ClassDefinition *class_def) IterateNoTParams(class_def); } -void ScopesInitPhaseTs::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *export_decl) +void InitScopesPhaseTs::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *export_decl) { ExportDeclarationContext export_decl_ctx(VarBinder()); Iterate(export_decl); } -void ScopesInitPhaseTs::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *export_decl) +void InitScopesPhaseTs::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *export_decl) { ExportDeclarationContext export_decl_ctx(VarBinder()); Iterate(export_decl); } -void ScopesInitPhaseTs::VisitImportDeclaration(ir::ImportDeclaration *import_declaration) +void InitScopesPhaseTs::VisitImportDeclaration(ir::ImportDeclaration *import_declaration) { ImportDeclarationContext import_ctx(VarBinder()); Iterate(import_declaration); } -void ScopesInitPhaseTs::VisitTSFunctionType(ir::TSFunctionType *constr_type) +void InitScopesPhaseTs::VisitTSFunctionType(ir::TSFunctionType *constr_type) { auto lexical_scope = HandleFunctionSig(constr_type->TypeParams(), constr_type->Params(), constr_type->ReturnType()); BindScopeNode(lexical_scope, constr_type); } -void ScopesInitPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) +void InitScopesPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) { const auto ident_node = func->Id(); const auto start_loc = ident_node->Start(); @@ -610,46 +610,46 @@ void ScopesInitPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) decl->Add(func); } -void ScopesInitPhaseTs::VisitTSConstructorType(ir::TSConstructorType *constr_t) +void InitScopesPhaseTs::VisitTSConstructorType(ir::TSConstructorType *constr_t) { auto func_param_scope = HandleFunctionSig(constr_t->TypeParams(), constr_t->Params(), constr_t->ReturnType()); BindScopeNode(func_param_scope, constr_t); } -void ScopesInitPhaseTs::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrow_f_expr) +void InitScopesPhaseTs::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrow_f_expr) { auto type_params_ctx = varbinder::LexicalScope(VarBinder()); Iterate(arrow_f_expr); } -void ScopesInitPhaseTs::VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *sign_decl) +void InitScopesPhaseTs::VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *sign_decl) { auto func_param_scope = HandleFunctionSig(sign_decl->TypeParams(), sign_decl->Params(), sign_decl->ReturnTypeAnnotation()); BindScopeNode(func_param_scope, sign_decl); } -void ScopesInitPhaseTs::VisitTSMethodSignature(ir::TSMethodSignature *method_sign) +void InitScopesPhaseTs::VisitTSMethodSignature(ir::TSMethodSignature *method_sign) { auto func_param_scope = HandleFunctionSig(method_sign->TypeParams(), method_sign->Params(), method_sign->ReturnTypeAnnotation()); BindScopeNode(func_param_scope, method_sign); } -void ScopesInitPhaseETS::RunExternalNode(ir::AstNode *node, varbinder::VarBinder *varbinder) +void InitScopesPhaseETS::RunExternalNode(ir::AstNode *node, varbinder::VarBinder *varbinder) { auto program = parser::Program(varbinder->Allocator(), varbinder); RunExternalNode(node, &program); } -void ScopesInitPhaseETS::RunExternalNode(ir::AstNode *node, parser::Program *ctx) +void InitScopesPhaseETS::RunExternalNode(ir::AstNode *node, parser::Program *ctx) { - auto scopes_phase = ScopesInitPhaseETS(); + auto scopes_phase = InitScopesPhaseETS(); scopes_phase.SetProgram(ctx); scopes_phase.CallNode(node); } -bool ScopesInitPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) +bool InitScopesPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) { Prepare(ctx, program); @@ -663,7 +663,7 @@ bool ScopesInitPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) return true; } -void ScopesInitPhaseETS::HandleProgram(parser::Program *program) +void InitScopesPhaseETS::HandleProgram(parser::Program *program) { for (auto &[_, prog_list] : program->ExternalSources()) { (void)_; @@ -679,7 +679,7 @@ void ScopesInitPhaseETS::HandleProgram(parser::Program *program) BindScopeNode(prog->VarBinder()->GetScope(), prog->Ast()); prog->VarBinder()->ResetTopScope(global_scope); if (main_prog->Ast() != nullptr) { - ScopesInitPhaseETS().Perform(Context(), prog); + InitScopesPhaseETS().Perform(Context(), prog); } } program->VarBinder()->ResetTopScope(saved_top_scope); @@ -689,7 +689,7 @@ void ScopesInitPhaseETS::HandleProgram(parser::Program *program) HandleETSScript(program->Ast()); } -void ScopesInitPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl, +void InitScopesPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl, varbinder::Variable *var) { binding->SetVariable(var); @@ -698,7 +698,7 @@ void ScopesInitPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *in decl->BindNode(init); } -void ScopesInitPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *static_block) +void InitScopesPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *static_block) { const auto func = static_block->Function(); @@ -725,7 +725,7 @@ void ScopesInitPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *static_bloc func->Id()->SetVariable(var); } -void ScopesInitPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *import_spec) +void InitScopesPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *import_spec) { if (import_spec->Local()->Name().Empty()) { return; @@ -735,7 +735,7 @@ void ScopesInitPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecif Iterate(import_spec); } -void ScopesInitPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) +void InitScopesPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) { const auto method_name = method->Id(); @@ -795,7 +795,7 @@ void ScopesInitPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) } } -void ScopesInitPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression *param_expr) +void InitScopesPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression *param_expr) { auto *const var = std::get<1>(VarBinder()->AddParamDecl(param_expr)); param_expr->Ident()->SetVariable(var); @@ -803,7 +803,7 @@ void ScopesInitPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression Iterate(param_expr); } -void ScopesInitPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *import_decl) +void InitScopesPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *import_decl) { ImportDeclarationContext import_ctx(VarBinder()); if (import_decl->Language().IsDynamic()) { @@ -812,7 +812,7 @@ void ScopesInitPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *imp Iterate(import_decl); } -void ScopesInitPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enum_member) +void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enum_member) { auto ident = enum_member->Key()->AsIdentifier(); auto [decl, var] = VarBinder()->NewVarDecl(ident->Start(), ident->Name()); @@ -823,7 +823,7 @@ void ScopesInitPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enum_member) Iterate(enum_member); } -void ScopesInitPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) +void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) { auto *cur_scope = VarBinder()->GetScope(); const auto method_name = method->Id(); @@ -835,7 +835,7 @@ void ScopesInitPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) DeclareClassMethod(method); } -void ScopesInitPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *func_type) +void InitScopesPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *func_type) { auto type_params_ctx = varbinder::LexicalScope(VarBinder()); varbinder::LexicalScope lexical_scope(VarBinder()); @@ -844,7 +844,7 @@ void ScopesInitPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *func_type) Iterate(func_type); } -void ScopesInitPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *new_class_expr) +void InitScopesPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *new_class_expr) { CallNode(new_class_expr->GetArguments()); CallNode(new_class_expr->GetTypeRef()); @@ -866,7 +866,7 @@ void ScopesInitPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInsta } } -void ScopesInitPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *type_param) +void InitScopesPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *type_param) { auto [decl, var] = VarBinder()->NewVarDecl(type_param->Name()->Start(), type_param->Name()->Name()); @@ -876,7 +876,7 @@ void ScopesInitPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *type_param) decl->BindNode(type_param); } -void ScopesInitPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interface_decl) +void InitScopesPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interface_decl) { { auto type_params_ctx = varbinder::LexicalScope(VarBinder()); @@ -892,7 +892,7 @@ void ScopesInitPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration decl->AsInterfaceDecl()->Add(interface_decl); } -void ScopesInitPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enum_decl) +void InitScopesPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enum_decl) { { const auto enum_ctx = varbinder::LexicalScope(VarBinder()); @@ -905,14 +905,14 @@ void ScopesInitPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enum_decl decl->BindScope(enum_decl->Scope()); } -void ScopesInitPhaseETS::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *type_alias) +void InitScopesPhaseETS::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *type_alias) { VarBinder()->AddDecl(type_alias->Id()->Start(), type_alias->Id()->Name(), type_alias); auto type_params_ctx = varbinder::LexicalScope(VarBinder()); Iterate(type_alias); } -void ScopesInitPhaseETS::AddGlobalToBinder(parser::Program *program) +void InitScopesPhaseETS::AddGlobalToBinder(parser::Program *program) { auto global_id = program->GlobalClass()->Ident(); @@ -927,7 +927,7 @@ void ScopesInitPhaseETS::AddGlobalToBinder(parser::Program *program) global_id->SetVariable(var); } -void ScopesInitPhaseETS::HandleETSScript(ir::BlockStatement *script) +void InitScopesPhaseETS::HandleETSScript(ir::BlockStatement *script) { for (auto decl : script->Statements()) { if (decl->IsETSImportDeclaration()) { @@ -945,7 +945,7 @@ void ScopesInitPhaseETS::HandleETSScript(ir::BlockStatement *script) } } -void ScopesInitPhaseETS::VisitClassDefinition(ir::ClassDefinition *class_def) +void InitScopesPhaseETS::VisitClassDefinition(ir::ClassDefinition *class_def) { if (class_def->IsGlobal()) { ParseGlobalClass(class_def); @@ -961,13 +961,13 @@ void ScopesInitPhaseETS::VisitClassDefinition(ir::ClassDefinition *class_def) BindScopeNode(class_scope, class_def); } -void ScopesInitPhaseETS::VisitTSInterfaceBody(ir::TSInterfaceBody *interf_body) +void InitScopesPhaseETS::VisitTSInterfaceBody(ir::TSInterfaceBody *interf_body) { Iterate(interf_body); FilterInterfaceOverloads(interf_body->Body()); } -void ScopesInitPhaseETS::FilterInterfaceOverloads(ArenaVector &props) +void InitScopesPhaseETS::FilterInterfaceOverloads(ArenaVector &props) { auto condition = [](ir::AstNode *prop) { if (prop->IsMethodDefinition()) { @@ -979,7 +979,7 @@ void ScopesInitPhaseETS::FilterInterfaceOverloads(ArenaVector &props) +void InitScopesPhaseETS::FilterOverloads(ArenaVector &props) { auto condition = [](ir::AstNode *prop) { if (prop->IsMethodDefinition()) { @@ -991,7 +991,7 @@ void ScopesInitPhaseETS::FilterOverloads(ArenaVector &prop props.erase(std::remove_if(props.begin(), props.end(), condition), props.end()); } -void ScopesInitPhaseETS::VisitClassProperty(ir::ClassProperty *class_prop) +void InitScopesPhaseETS::VisitClassProperty(ir::ClassProperty *class_prop) { auto cur_scope = VarBinder()->GetScope(); if (class_prop->IsClassStaticBlock()) { @@ -1023,7 +1023,7 @@ void ScopesInitPhaseETS::VisitClassProperty(ir::ClassProperty *class_prop) Iterate(class_prop); } -void ScopesInitPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) +void InitScopesPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) { for (auto decl : global->Body()) { if (decl->IsDefaultExported()) { @@ -1037,7 +1037,7 @@ void ScopesInitPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) FilterOverloads(global->Body()); } -void ScopesInitPhaseETS::AddGlobalDeclaration(ir::AstNode *node) +void InitScopesPhaseETS::AddGlobalDeclaration(ir::AstNode *node) { ir::Identifier *ident = nullptr; bool is_builtin = false; @@ -1081,12 +1081,12 @@ void ScopesInitPhaseETS::AddGlobalDeclaration(ir::AstNode *node) } } -void ScopesInitPhaseAS::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrow_expr) +void InitScopesPhaseAS::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrow_expr) { Iterate(arrow_expr); } -void ScopesInitPhaseAS::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *export_decl) +void InitScopesPhaseAS::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *export_decl) { ExportDeclarationContext export_decl_ctx(VarBinder()); Iterate(export_decl); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h index b3f3f4de2f..4257f60980 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h @@ -16,11 +16,11 @@ #ifndef ES2PANDA_COMPILER_CORE_SCOPES_INIT_PHASE_H #define ES2PANDA_COMPILER_CORE_SCOPES_INIT_PHASE_H +#include "compiler/lowering/phase.h" #include "util/helpers.h" #include "parser/parserFlags.h" #include "varbinder/tsBinding.h" #include "varbinder/ETSBinder.h" -#include "compiler/lowering/phase.h" #include "compiler/lowering/scopesInit/savedBindingsCtx.h" #include "checker/checker.h" #include "compiler/core/compilerContext.h" @@ -40,10 +40,7 @@ class ScopesInitPhase : public Phase, public ir::visitor::IterateAstVisitor { public: using PhaseContext = public_lib::Context; - std::string_view Name() override - { - return "scopes"; - } + DECLARE_PHASE_NAME(ScopesInitPhase) bool Perform(PhaseContext *ctx, parser::Program *program) override; @@ -220,16 +217,16 @@ public: void VisitClassDefinition(ir::ClassDefinition *class_def) override; }; -class ScopesInitPhaseJs : public ScopesInitPhase { +class InitScopesPhaseJs : public ScopesInitPhase { public: - ScopesInitPhaseJs() = default; - NO_COPY_SEMANTIC(ScopesInitPhaseJs); - NO_MOVE_SEMANTIC(ScopesInitPhaseJs); + InitScopesPhaseJs() = default; + NO_COPY_SEMANTIC(InitScopesPhaseJs); + NO_MOVE_SEMANTIC(InitScopesPhaseJs); - ~ScopesInitPhaseJs() override = default; + ~InitScopesPhaseJs() override = default; }; -class ScopesInitPhaseTs : public ScopeInitTyped { +class InitScopesPhaseTs : public ScopeInitTyped { protected: bool AllowInterfaceRedeclaration() override { @@ -250,11 +247,11 @@ protected: void CreateFuncDecl(ir::ScriptFunction *func) override; }; -class ScopesInitPhaseETS : public ScopeInitTyped { +class InitScopesPhaseETS : public ScopeInitTyped { public: - ScopesInitPhaseETS() = default; - NO_COPY_SEMANTIC(ScopesInitPhaseETS); - NO_MOVE_SEMANTIC(ScopesInitPhaseETS); + InitScopesPhaseETS() = default; + NO_COPY_SEMANTIC(InitScopesPhaseETS); + NO_MOVE_SEMANTIC(InitScopesPhaseETS); /** * Set scopes for ast-subtree @@ -307,7 +304,7 @@ public: */ bool Perform(PhaseContext *ctx, parser::Program *program) override; - ~ScopesInitPhaseETS() override = default; + ~InitScopesPhaseETS() override = default; private: void HandleProgram(parser::Program *program); @@ -361,12 +358,12 @@ private: void FilterOverloads(ArenaVector &props); }; -class ScopesInitPhaseAS : public ScopesInitPhase { +class InitScopesPhaseAS : public ScopesInitPhase { public: - NO_COPY_SEMANTIC(ScopesInitPhaseAS); - NO_MOVE_SEMANTIC(ScopesInitPhaseAS); - ScopesInitPhaseAS() = default; - ~ScopesInitPhaseAS() override = default; + NO_COPY_SEMANTIC(InitScopesPhaseAS); + NO_MOVE_SEMANTIC(InitScopesPhaseAS); + InitScopesPhaseAS() = default; + ~InitScopesPhaseAS() override = default; private: void VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrow_expr) override; diff --git a/ets2panda/ir/ets/etsScript.h b/ets2panda/ir/ets/etsScript.h index 52ce8c729c..f0bb73c1d4 100644 --- a/ets2panda/ir/ets/etsScript.h +++ b/ets2panda/ir/ets/etsScript.h @@ -29,6 +29,7 @@ public: explicit ETSScript(ArenaAllocator *allocator, ArenaVector &&statement_list, parser::Program *program) : BlockStatement(allocator, std::move(statement_list)), program_(program) { + type_ = AstNodeType::ETS_SCRIPT; } parser::Program *Program() diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 1945b19eec..2d48fdcc04 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -346,7 +346,7 @@ static Context *InitScopes(Context *ctx) ASSERT(ctx->state == ES2PANDA_STATE_PARSED); try { - compiler::ScopesInitPhaseETS scopes_init; + compiler::InitScopesPhaseETS scopes_init; scopes_init.Perform(ctx, ctx->parser_program); do { if (ctx->current_phase >= ctx->phases.size()) { diff --git a/ets2panda/test/unit/lowerings/scopes_initialization.cpp b/ets2panda/test/unit/lowerings/scopes_initialization.cpp index a55b4e18de..55aeb0dec9 100644 --- a/ets2panda/test/unit/lowerings/scopes_initialization.cpp +++ b/ets2panda/test/unit/lowerings/scopes_initialization.cpp @@ -81,7 +81,7 @@ TEST_F(ScopesInitPhaseTest, TestForUpdateLoop) */ auto varbinder = varbinder::VarBinder(Allocator()); auto for_node = NodeGen().CreateForUpdate(); - compiler::ScopesInitPhaseETS::RunExternalNode(for_node, &varbinder); + compiler::InitScopesPhaseETS::RunExternalNode(for_node, &varbinder); auto block_scope = for_node->Body()->AsBlockStatement()->Scope(); auto loop_scope = for_node->Scope(); @@ -111,7 +111,7 @@ TEST_F(ScopesInitPhaseTest, CreateWhile) auto varbinder = varbinder::VarBinder(Allocator()); auto while_node = NodeGen().CreateWhile(); - compiler::ScopesInitPhaseETS::RunExternalNode(while_node, &varbinder); + compiler::InitScopesPhaseETS::RunExternalNode(while_node, &varbinder); auto while_scope = while_node->Scope(); auto body_scope = while_node->Body()->AsBlockStatement()->Scope(); @@ -124,4 +124,4 @@ TEST_F(ScopesInitPhaseTest, CreateWhile) ASSERT_EQ(body_bindings.begin()->second, name->Variable()); } -} // namespace panda::es2panda \ No newline at end of file +} // namespace panda::es2panda diff --git a/ets2panda/test/unit/public/ast_verifier_test.cpp b/ets2panda/test/unit/public/ast_verifier_test.cpp index dc3414ba7c..20592966ce 100644 --- a/ets2panda/test/unit/public/ast_verifier_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_test.cpp @@ -14,7 +14,6 @@ */ #include "checker/ETSchecker.h" -#include "compiler/core/ASTVerifier.h" #include "ir/expressions/literals/stringLiteral.h" #include "ir/expressions/identifier.h" #include "ir/expressions/literals/numberLiteral.h" @@ -22,7 +21,9 @@ #include "macros.h" #include "parser/ETSparser.h" #include "varbinder/ETSBinder.h" -#include "public/es2panda_lib.h" +#include "utils/json_builder.h" +#include +#include "compiler/core/ASTVerifier.h" #include #include @@ -75,21 +76,35 @@ protected: // NOLINTEND(misc-non-private-member-variables-in-classes) }; +static void compare_minified(std::string_view actual_json, std::string_view expected_json) +{ + std::string message {actual_json}; + static const std::regex r {R"(\s+)"}; + auto ss = std::stringstream {}; + + std::regex_replace(std::ostream_iterator(ss), message.begin(), message.end(), r, ""); + ASSERT_EQ(ss.str(), expected_json); +} + TEST_F(ASTVerifierTest, NullParent) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + compiler::ASTVerifier verifier {Allocator()}; panda::es2panda::ir::StringLiteral empty_node; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasParent"); - bool has_parent = verifier.Verify(&empty_node, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; - + const auto check = "NodeHasParent"; + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert(check); + const auto &errors = verifier.Verify(&empty_node, checks); + bool has_parent = errors.size() == 0; ASSERT_EQ(has_parent, false); ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(name, "HasParent"); - ASSERT_EQ(error.message, "NULL_PARENT: STR_LITERAL "); + + const auto [name, error] = errors[0]; + ASSERT_EQ(name, check); + auto message_expected = JsonObjectBuilder {}; + message_expected.AddProperty("type", "StringLiteral"); + message_expected.AddProperty("value", ""); + compare_minified(error.message, std::move(message_expected).Build()); } TEST_F(ASTVerifierTest, NullType) @@ -97,16 +112,21 @@ TEST_F(ASTVerifierTest, NullType) panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; panda::es2panda::ir::StringLiteral empty_node; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasType"); - bool has_type = verifier.Verify(&empty_node, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; - + auto check = "NodeHasType"; + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert(check); + const auto &errors = verifier.Verify(&empty_node, checks); + bool has_type = errors.size() == 0; ASSERT_EQ(has_type, false); ASSERT_NE(errors.size(), 0); - ASSERT_EQ(name, "HasType"); - ASSERT_EQ(error.message, "NULL_TS_TYPE: STR_LITERAL "); + + const auto [name, error] = errors[0]; + ASSERT_EQ(name, check); + + auto message_expected = JsonObjectBuilder {}; + message_expected.AddProperty("type", "StringLiteral"); + message_expected.AddProperty("value", ""); + compare_minified(error.message, std::move(message_expected).Build()); } TEST_F(ASTVerifierTest, WithoutScope) @@ -114,155 +134,176 @@ TEST_F(ASTVerifierTest, WithoutScope) panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; panda::es2panda::ir::StringLiteral empty_node; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasScope"); - bool has_scope = verifier.Verify(&empty_node, checks); - const auto &errors = verifier.GetErrors(); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasScope"); + const auto &errors = verifier.Verify(&empty_node, checks); - ASSERT_EQ(has_scope, true); ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ScopeTest) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::Identifier ident(panda::es2panda::util::StringView("var_decl"), Allocator()); - panda::es2panda::varbinder::LetDecl decl("test", &ident); - panda::es2panda::varbinder::LocalVariable local(&decl, panda::es2panda::varbinder::VariableFlags::LOCAL); + compiler::ASTVerifier verifier {Allocator()}; + ir::Identifier ident(util::StringView("var_decl"), Allocator()); + varbinder::LetDecl decl("test", &ident); + varbinder::LocalVariable local(&decl, varbinder::VariableFlags::LOCAL); ident.SetVariable(&local); - panda::es2panda::varbinder::LocalScope scope(Allocator(), nullptr); - panda::es2panda::varbinder::FunctionScope parent_scope(Allocator(), nullptr); + varbinder::LocalScope scope(Allocator(), nullptr); + varbinder::FunctionScope parent_scope(Allocator(), nullptr); scope.SetParent(&parent_scope); - scope.AddDecl(Allocator(), &decl, panda::es2panda::ScriptExtension::ETS); + scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); local.SetScope(&scope); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasScope"); - bool is_ok = verifier.Verify(&ident, checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasScope"); + const auto &errors = verifier.Verify(&ident, checks); - ASSERT_EQ(is_ok, true); + ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ScopeNodeTest) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::Identifier ident(panda::es2panda::util::StringView("var_decl"), Allocator()); - panda::es2panda::varbinder::LetDecl decl("test", &ident); - panda::es2panda::varbinder::LocalVariable local(&decl, panda::es2panda::varbinder::VariableFlags::LOCAL); + compiler::ASTVerifier verifier {Allocator()}; + ir::Identifier ident(util::StringView("var_decl"), Allocator()); + varbinder::LetDecl decl("test", &ident); + varbinder::LocalVariable local(&decl, varbinder::VariableFlags::LOCAL); ident.SetVariable(&local); - panda::es2panda::varbinder::LocalScope scope(Allocator(), nullptr); - panda::es2panda::varbinder::FunctionScope parent_scope(Allocator(), nullptr); + varbinder::LocalScope scope(Allocator(), nullptr); + varbinder::FunctionScope parent_scope(Allocator(), nullptr); scope.SetParent(&parent_scope); - scope.AddDecl(Allocator(), &decl, panda::es2panda::ScriptExtension::ETS); + scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); parent_scope.BindNode(&ident); local.SetScope(&scope); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyScopeNode"); - bool is_ok = verifier.Verify(&ident, checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasEnclosingScope"); + const auto &errors = verifier.Verify(&ident, checks); - ASSERT_EQ(is_ok, true); + ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect1) { - panda::es2panda::checker::ETSChecker etschecker {}; - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - auto program = panda::es2panda::parser::Program::NewProgram(Allocator()); - auto parser = panda::es2panda::parser::ETSParser(&program, panda::es2panda::CompilerOptions {}); + checker::ETSChecker etschecker {}; + compiler::ASTVerifier verifier {Allocator()}; + auto program = parser::Program::NewProgram(Allocator()); + auto parser = parser::ETSParser(&program, CompilerOptions {}); - auto left = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {1}); - auto right = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {6}); - auto arithmetic_expression = - panda::es2panda::ir::BinaryExpression(&left, &right, panda::es2panda::lexer::TokenType::PUNCTUATOR_PLUS); + auto left = ir::NumberLiteral(lexer::Number {1}); + auto right = ir::NumberLiteral(lexer::Number {6}); + auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_PLUS); left.SetTsType(etschecker.GlobalIntType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("CheckArithmeticExpression"); - bool is_correct = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(is_correct, true); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect2) { - panda::es2panda::checker::ETSChecker etschecker {}; - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - auto program = panda::es2panda::parser::Program::NewProgram(Allocator()); - auto parser = panda::es2panda::parser::ETSParser(&program, panda::es2panda::CompilerOptions {}); + checker::ETSChecker etschecker {}; + compiler::ASTVerifier verifier {Allocator()}; + auto program = parser::Program::NewProgram(Allocator()); + auto parser = parser::ETSParser(&program, CompilerOptions {}); constexpr uint32_t LEFT1_PARAM = 1; constexpr uint32_t LEFT2_PARAM = 12; constexpr uint32_t RIGHT2_PARAM = 6; - auto left1 = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {LEFT1_PARAM}); - auto left2 = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {LEFT2_PARAM}); - auto right2 = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {RIGHT2_PARAM}); - auto right1 = - panda::es2panda::ir::BinaryExpression(&left2, &right2, panda::es2panda::lexer::TokenType::PUNCTUATOR_MULTIPLY); - auto arithmetic_expression = - panda::es2panda::ir::BinaryExpression(&left1, &right1, panda::es2panda::lexer::TokenType::PUNCTUATOR_PLUS); + auto left1 = ir::NumberLiteral(lexer::Number {LEFT1_PARAM}); + auto left2 = ir::NumberLiteral(lexer::Number {LEFT2_PARAM}); + auto right2 = ir::NumberLiteral(lexer::Number {RIGHT2_PARAM}); + auto right1 = ir::BinaryExpression(&left2, &right2, lexer::TokenType::PUNCTUATOR_MULTIPLY); + auto arithmetic_expression = ir::BinaryExpression(&left1, &right1, lexer::TokenType::PUNCTUATOR_PLUS); left1.SetTsType(etschecker.GlobalIntType()); right1.SetTsType(etschecker.GlobalIntType()); left2.SetTsType(etschecker.GlobalIntType()); right2.SetTsType(etschecker.GlobalIntType()); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("CheckArithmeticExpression"); - bool is_correct = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(is_correct, true); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionNegative1) { - panda::es2panda::checker::ETSChecker etschecker {}; - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - auto program = panda::es2panda::parser::Program::NewProgram(Allocator()); - auto parser = panda::es2panda::parser::ETSParser(&program, panda::es2panda::CompilerOptions {}); + checker::ETSChecker etschecker {}; + compiler::ASTVerifier verifier {Allocator()}; + auto program = parser::Program::NewProgram(Allocator()); + auto parser = parser::ETSParser(&program, CompilerOptions {}); const panda::es2panda::util::StringView left_param("1"); constexpr uint32_t RIGHT_PARAM = 1; - auto left = panda::es2panda::ir::StringLiteral(left_param); - auto right = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {RIGHT_PARAM}); - auto arithmetic_expression = - panda::es2panda::ir::BinaryExpression(&left, &right, panda::es2panda::lexer::TokenType::PUNCTUATOR_DIVIDE); + auto left = ir::StringLiteral(left_param); + auto right = ir::NumberLiteral(lexer::Number {RIGHT_PARAM}); + auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_DIVIDE); left.SetTsType(etschecker.GlobalETSStringLiteralType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("CheckArithmeticExpression"); - bool is_correct = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(is_correct, false); + ASSERT_EQ(errors.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionNegative2) { - panda::es2panda::checker::ETSChecker etschecker {}; - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - auto program = panda::es2panda::parser::Program::NewProgram(Allocator()); - auto parser = panda::es2panda::parser::ETSParser(&program, panda::es2panda::CompilerOptions {}); - auto left = panda::es2panda::ir::BooleanLiteral(true); - auto right = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {1}); - auto arithmetic_expression = - panda::es2panda::ir::BinaryExpression(&left, &right, panda::es2panda::lexer::TokenType::PUNCTUATOR_DIVIDE); + checker::ETSChecker etschecker {}; + compiler::ASTVerifier verifier {Allocator()}; + auto program = parser::Program::NewProgram(Allocator()); + auto parser = parser::ETSParser(&program, CompilerOptions {}); + auto left = ir::BooleanLiteral(true); + auto right = ir::NumberLiteral(lexer::Number {1}); + auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_DIVIDE); left.SetTsType(etschecker.GlobalETSStringLiteralType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("CheckArithmeticExpression"); - bool is_correct = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(is_correct, false); + ASSERT_EQ(errors.size(), 0); +} + +TEST_F(ASTVerifierTest, SequenceExpressionType) +{ + compiler::ASTVerifier verifier {Allocator()}; + auto *allocator = Allocator(); + + auto checker = checker::ETSChecker(); + + auto *last = TREE(NODE(NumberLiteral, lexer::Number {3})); + // clang-format off + auto *sequence_expression = + TREE(NODE(SequenceExpression, + NODES(Expression, + NODE(NumberLiteral, lexer::Number {1}), + NODE(NumberLiteral, lexer::Number {2}), + last, + ))); + // clang-format on + + last->SetTsType(checker.GlobalIntType()); + sequence_expression->SetTsType(checker.GlobalIntType()); + + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("SequenceExpressionHasLastType"); + const auto &errors = verifier.Verify(sequence_expression, checks); + + ASSERT_EQ(errors.size(), 0); } constexpr char const *PRIVATE_PROTECTED_PUBLIC_TEST = -- Gitee From b67ece5ff70c550b751c15912fc2902bb219b99c Mon Sep 17 00:00:00 2001 From: Tatiana Date: Sat, 30 Dec 2023 23:06:31 +0300 Subject: [PATCH 23/24] Title: Add options --verifier-warnings and --verifier-errors Issue: Add options --verifier-warnings and --verifier-errors Description: To be able run the ASTVerifier in the different modes: 'just warnings' and 'fail with errors' there were added two options Testing: full CI tests Signed-off-by: Tatiana --- ets2panda/compiler/core/ASTVerifier.cpp | 296 ++++---- ets2panda/compiler/core/ASTVerifier.h | 177 +++-- ets2panda/compiler/core/compilerImpl.cpp | 19 +- ets2panda/compiler/lowering/checkerPhase.h | 6 +- .../compiler/lowering/ets/expandBrackets.h | 6 +- .../lowering/ets/generateDeclarations.h | 6 +- .../ets/interfacePropertyDeclarations.h | 6 +- .../compiler/lowering/ets/lambdaLowering.h | 6 +- .../compiler/lowering/ets/objectIndexAccess.h | 6 +- .../compiler/lowering/ets/opAssignment.h | 6 +- ets2panda/compiler/lowering/ets/promiseVoid.h | 6 +- .../compiler/lowering/ets/structLowering.h | 6 +- .../compiler/lowering/ets/tupleLowering.h | 6 +- .../compiler/lowering/ets/unionLowering.h | 6 +- ets2panda/compiler/lowering/phase.cpp | 22 +- ets2panda/compiler/lowering/phase.h | 6 - .../lowering/scopesInit/scopesInitPhase.h | 5 +- ets2panda/es2panda.h | 2 + ets2panda/test/unit/ast_dumper_test.cpp | 1 - .../test/unit/public/ast_verifier_test.cpp | 630 +++++++++--------- ets2panda/util/options.cpp | 6 + 21 files changed, 624 insertions(+), 606 deletions(-) diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 82e0dce5e1..98695bdf7c 100644 --- a/ets2panda/compiler/core/ASTVerifier.cpp +++ b/ets2panda/compiler/core/ASTVerifier.cpp @@ -23,88 +23,33 @@ #include "ir/base/classStaticBlock.h" #include "ir/base/methodDefinition.h" #include "ir/base/scriptFunction.h" -#include "ir/ets/etsClassLiteral.h" -#include "ir/ets/etsFunctionType.h" #include "ir/ets/etsNewClassInstanceExpression.h" -#include "ir/ets/etsParameterExpression.h" #include "ir/ets/etsScript.h" -#include "ir/ets/etsTypeReference.h" -#include "ir/ets/etsTypeReferencePart.h" #include "ir/ets/etsImportDeclaration.h" -#include "ir/ets/etsScript.h" #include "ir/expressions/sequenceExpression.h" #include "ir/module/importSpecifier.h" #include "ir/module/importNamespaceSpecifier.h" #include "ir/module/importDefaultSpecifier.h" #include "ir/expressions/callExpression.h" #include "ir/expressions/binaryExpression.h" -#include "ir/expressions/functionExpression.h" #include "ir/expressions/identifier.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/expressions/literals/stringLiteral.h" #include "ir/expressions/memberExpression.h" -#include "ir/statements/blockStatement.h" #include "ir/statements/forInStatement.h" #include "ir/statements/forOfStatement.h" #include "ir/statements/forUpdateStatement.h" -#include "ir/statements/variableDeclaration.h" #include "ir/statements/variableDeclarator.h" -#include "ir/statements/classDeclaration.h" #include "ir/statements/expressionStatement.h" #include "ir/statements/throwStatement.h" -#include "ir/statements/tryStatement.h" -#include "ir/ts/tsClassImplements.h" #include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsTypeParameterDeclaration.h" -#include "ir/ts/tsTypeParameterInstantiation.h" #include "lexer/token/tokenType.h" #include "util/ustring.h" #include "utils/arena_containers.h" #include "varbinder/scope.h" -#include -#include - -#define RECURSIVE_SUFFIX "ForAll" +constexpr auto RECURSIVE_SUFFIX = "ForAll"; namespace panda::es2panda::compiler { -struct ASTVerifier::ErrorContext { - explicit ErrorContext() : named_errors_ {}, encountered_errors_ {} {} - - void ProcessEncounteredErrors(util::StringView name) - { - for (const auto &error : encountered_errors_) { - named_errors_.emplace_back(CheckError {name, error}); - } - encountered_errors_.clear(); - } - - void AddError(const std::string &message) - { - named_errors_.emplace_back(CheckError {"Unnamed", ASTVerifier::InvariantError {message, "", 0}}); - } - - void AddInvariantError(const std::string &cause, const ir::AstNode &node, const lexer::SourcePosition &from) - { - const auto loc = from.line; - const auto &&dump = node.DumpJSON(); - static const std::regex r {R"(\s+)"}; // removing all identation - auto ss = std::stringstream {}; - std::regex_replace(std::ostream_iterator(ss), dump.begin(), dump.end(), r, ""); - encountered_errors_.emplace_back(ASTVerifier::InvariantError {cause, ss.str(), loc}); - } - - ASTVerifier::Errors GetErrors() - { - return named_errors_; - } - -private: - ASTVerifier::Errors named_errors_; - std::vector encountered_errors_; -}; - static bool IsNumericType(const ir::AstNode *ast) { if (ast == nullptr) { @@ -277,13 +222,13 @@ public: const auto is_ets_script = ast->IsETSScript(); const auto has_parent = ast->Parent() != nullptr; if (!is_ets_script && !has_parent) { - ctx.AddInvariantError("NULL_PARENT", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("NodeHasParent", "NULL_PARENT", *ast); + return ASTVerifier::CheckResult::FAILED; } if (ast->IsProgram()) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } }; @@ -294,15 +239,15 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { if (!ast->IsIdentifier()) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } if (ast->AsIdentifier()->Variable() != nullptr) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } const auto *id = ast->AsIdentifier(); - ctx.AddInvariantError("NULL_VARIABLE", *id, id->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("IdentifierHasVariable", "NULL_VARIABLE", *id); + return ASTVerifier::CheckResult::FAILED; } private: @@ -316,15 +261,15 @@ public: { if (ast->IsTyped()) { if (ast->IsClassDefinition() && ast->AsClassDefinition()->Ident()->Name() == "ETSGLOBAL") { - return ASTVerifier::CheckResult::SkipSubtree; + return ASTVerifier::CheckResult::SKIP_SUBTREE; } const auto *typed = static_cast(ast); if (typed->TsType() == nullptr) { - ctx.AddInvariantError("NULL_TS_TYPE", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("NodeHasType", "NULL_TS_TYPE", *ast); + return ASTVerifier::CheckResult::FAILED; } } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: @@ -337,7 +282,7 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { if (!ast->IsIdentifier()) { - return ASTVerifier::CheckResult::Success; // we will check invariant of Identifier only + return ASTVerifier::CheckResult::SUCCESS; // we will check invariant of Identifier only } // we will check invariant for only local variables of identifiers @@ -345,13 +290,13 @@ public: const auto var = *maybe_var; const auto scope = var->GetScope(); if (scope == nullptr) { - ctx.AddInvariantError("NULL_SCOPE_LOCAL_VAR", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("VariableHasScope", "NULL_SCOPE_LOCAL_VAR", *ast); + return ASTVerifier::CheckResult::FAILED; } - return ScopeEncloseVariable(ctx, var) == true ? ASTVerifier::CheckResult::Success - : ASTVerifier::CheckResult::Failed; + return ScopeEncloseVariable(ctx, var) ? ASTVerifier::CheckResult::SUCCESS + : ASTVerifier::CheckResult::FAILED; } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } static std::optional GetLocalScopeVariable(ArenaAllocator &allocator, @@ -364,7 +309,7 @@ public: auto invariant_has_variable = IdentifierHasVariable {allocator}; const auto variable = ast->AsIdentifier()->Variable(); - if ((invariant_has_variable(ctx, ast) == ASTVerifier::CheckResult::Success) && variable->IsLocalVariable()) { + if ((invariant_has_variable(ctx, ast) == ASTVerifier::CheckResult::SUCCESS) && variable->IsLocalVariable()) { const auto local_var = variable->AsLocalVariable(); if (local_var->HasFlag(varbinder::VariableFlags::LOCAL)) { return local_var; @@ -385,22 +330,22 @@ public: if (node == nullptr) { return true; } - const auto var_start = node->Start(); + const auto name = "VariableHasScope"; bool is_ok = true; if (scope->Bindings().count(var->Name()) == 0) { - ctx.AddInvariantError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node, var_start); + ctx.AddInvariantError(name, "SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node); is_ok = false; } const auto scope_node = scope->Node(); auto var_node = node; if (!IsContainedIn(var_node, scope_node) || scope_node == nullptr) { - ctx.AddInvariantError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node, var_start); + ctx.AddInvariantError(name, "SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node); is_ok = false; } const auto &decls = scope->Decls(); const auto decl_dominate = std::count(decls.begin(), decls.end(), var->Declaration()); if (decl_dominate == 0) { - ctx.AddInvariantError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node, var_start); + ctx.AddInvariantError(name, "SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node); is_ok = false; } return is_ok; @@ -416,14 +361,14 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { - auto result = ASTVerifier::CheckResult::Success; + auto result = ASTVerifier::CheckResult::SUCCESS; if (ast->IsETSScript()) { return result; } ast->Iterate([&](const ir::AstNode *node) { if (ast != node->Parent()) { - ctx.AddInvariantError("INCORRECT_PARENT_REF", *node, node->Start()); - result = ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError("EveryChildHasValidParent", "INCORRECT_PARENT_REF", *node); + result = ASTVerifier::CheckResult::FAILED; } }); return result; @@ -440,28 +385,29 @@ public: { const auto maybe_var = VariableHasScope::GetLocalScopeVariable(allocator_, ctx, ast); if (!maybe_var) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } const auto var = *maybe_var; const auto scope = var->GetScope(); + const auto name = "VariableHasEnclosingScope"; if (scope == nullptr) { // already checked - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } const auto enclose_scope = scope->EnclosingVariableScope(); if (enclose_scope == nullptr) { - ctx.AddInvariantError("NO_ENCLOSING_VAR_SCOPE", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "NO_ENCLOSING_VAR_SCOPE", *ast); + return ASTVerifier::CheckResult::FAILED; } const auto node = scope->Node(); - auto result = ASTVerifier::CheckResult::Success; + auto result = ASTVerifier::CheckResult::SUCCESS; if (!IsContainedIn(ast, node)) { - result = ASTVerifier::CheckResult::Failed; - ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); + result = ASTVerifier::CheckResult::FAILED; + ctx.AddInvariantError(name, "VARIABLE_NOT_ENCLOSE_SCOPE", *ast); } if (!IsContainedIn(scope, enclose_scope)) { - result = ASTVerifier::CheckResult::Failed; - ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); + result = ASTVerifier::CheckResult::FAILED; + ctx.AddInvariantError(name, "VARIABLE_NOT_ENCLOSE_SCOPE", *ast); } return result; } @@ -477,24 +423,24 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { if (!ast->IsSequenceExpression()) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } const auto *expr = ast->AsSequenceExpression(); const auto *last = expr->Sequence().back(); + const auto name = "SequenceExpressionHasLastType"; if (expr->TsType() == nullptr) { - ctx.AddInvariantError("Sequence expression type is null", *expr, expr->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "Sequence expression type is null", *expr); + return ASTVerifier::CheckResult::FAILED; } if (last->TsType() == nullptr) { - ctx.AddInvariantError("Sequence expression last type is null", *last, last->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "Sequence expression last type is null", *last); + return ASTVerifier::CheckResult::FAILED; } if (expr->TsType() != last->TsType()) { - ctx.AddInvariantError("Sequence expression type and last expression type are not the same", *expr, - expr->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "Sequence expression type and last expression type are not the same", *expr); + return ASTVerifier::CheckResult::FAILED; } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: @@ -506,29 +452,30 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { + const auto name = "ForLoopCorrectlyInitialized"; if (ast->IsForInStatement()) { auto const *left = ast->AsForInStatement()->Left(); if (left == nullptr) { - ctx.AddInvariantError("NULL FOR-IN-LEFT", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "NULL FOR-IN-LEFT", *ast); + return ASTVerifier::CheckResult::FAILED; } if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { - ctx.AddInvariantError("INCORRECT FOR-IN-LEFT", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "INCORRECT FOR-IN-LEFT", *ast); + return ASTVerifier::CheckResult::FAILED; } } if (ast->IsForOfStatement()) { auto const *left = ast->AsForOfStatement()->Left(); if (left == nullptr) { - ctx.AddInvariantError("NULL FOR-OF-LEFT", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "NULL FOR-OF-LEFT", *ast); + return ASTVerifier::CheckResult::FAILED; } if (!left->IsIdentifier() && !left->IsVariableDeclaration()) { - ctx.AddInvariantError("INCORRECT FOR-OF-LEFT", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "INCORRECT FOR-OF-LEFT", *ast); + return ASTVerifier::CheckResult::FAILED; } } @@ -539,8 +486,8 @@ public: if (test == nullptr) { auto const *body = ast->AsForUpdateStatement()->Body(); if (body == nullptr) { - ctx.AddInvariantError("NULL FOR-TEST AND FOR-BODY", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "NULL FOR-TEST AND FOR-BODY", *ast); + return ASTVerifier::CheckResult::FAILED; } bool has_exit = body->IsBreakStatement() || body->IsReturnStatement(); body->IterateRecursively([&has_exit](ir::AstNode *child) { @@ -548,17 +495,17 @@ public: }); if (!has_exit) { // an infinite loop - ctx.AddInvariantError("WARNING: NULL FOR-TEST AND FOR-BODY doesn't exit", *ast, ast->Start()); + ctx.AddInvariantError(name, "WARNING: NULL FOR-TEST AND FOR-BODY doesn't exit", *ast); } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } if (!test->IsExpression()) { - ctx.AddInvariantError("NULL FOR VAR", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "NULL FOR VAR", *ast); + return ASTVerifier::CheckResult::FAILED; } } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: @@ -570,12 +517,13 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { + const auto name = "ModifierAccessValid"; if (ast->IsMemberExpression()) { const auto *prop_var = ast->AsMemberExpression()->PropVar(); if (prop_var != nullptr && prop_var->HasFlag(varbinder::VariableFlags::PROPERTY) && !ValidateVariableAccess(prop_var, ast->AsMemberExpression())) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE", *ast); + return ASTVerifier::CheckResult::FAILED; } } if (ast->IsCallExpression()) { @@ -586,12 +534,12 @@ public: const auto *prop_var_callee = callee_member->PropVar(); if (prop_var_callee != nullptr && prop_var_callee->HasFlag(varbinder::VariableFlags::METHOD) && !ValidateMethodAccess(callee_member, ast->AsCallExpression())) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *callee, callee->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE", *callee); + return ASTVerifier::CheckResult::FAILED; } } } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: @@ -619,20 +567,21 @@ public: imported_variables.emplace(name(import)); } } + const auto name = "ImportExportAccessValid"; if (ast->IsCallExpression()) { const auto *call_expr = ast->AsCallExpression(); const auto *callee = call_expr->Callee(); if (callee != nullptr && callee->IsIdentifier() && !HandleImportExportIdentifier(imported_variables, callee->AsIdentifier(), call_expr)) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee, callee->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee); + return ASTVerifier::CheckResult::FAILED; } } if (ast->IsIdentifier() && !HandleImportExportIdentifier(imported_variables, ast->AsIdentifier(), nullptr)) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast, ast->Start()); - return ASTVerifier::CheckResult::Failed; + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast); + return ASTVerifier::CheckResult::FAILED; } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: @@ -723,35 +672,35 @@ public: if (ast->IsBinaryExpression() && ast->AsBinaryExpression()->IsArithmetic()) { if (ast->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS && IsStringType(ast->AsBinaryExpression()->Left()) && IsStringType(ast->AsBinaryExpression()->Right())) { - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } - auto result = ASTVerifier::CheckResult::Success; + auto result = ASTVerifier::CheckResult::SUCCESS; ast->Iterate([&result](ir::AstNode *child) { if (!IsNumericType(child)) { - result = ASTVerifier::CheckResult::Failed; + result = ASTVerifier::CheckResult::FAILED; } }); return result; } - return ASTVerifier::CheckResult::Success; + return ASTVerifier::CheckResult::SUCCESS; } private: }; template -static ASTVerifier::InvariantCheck RecursiveInvariant(Func &func) +static ASTVerifier::InvariantCheck RecursiveInvariant(const Func &func) { - return [&func](ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) -> ASTVerifier::CheckResult { + return [func](ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) -> ASTVerifier::CheckResult { std::function aux; - auto result = ASTVerifier::CheckResult::Success; + auto result = ASTVerifier::CheckResult::SUCCESS; aux = [&ctx, &func, &aux, &result](const ir::AstNode *child) -> void { - if (result == ASTVerifier::CheckResult::Failed) { + if (result == ASTVerifier::CheckResult::FAILED) { return; } const auto new_result = func(ctx, child); - if (new_result == ASTVerifier::CheckResult::SkipSubtree) { + if (new_result == ASTVerifier::CheckResult::SKIP_SUBTREE) { return; } result = new_result; @@ -762,54 +711,46 @@ static ASTVerifier::InvariantCheck RecursiveInvariant(Func &func) }; } -// NOLINTBEGIN(cppcoreguidelines-macro-usage) -#define ADD_INVARIANT(Name) \ - { \ - auto *invariant = allocator->New(*allocator); \ - invariants_checks_.emplace_back(Invariant {#Name, *invariant}); \ - invariants_names_.insert(#Name); \ - invariants_checks_.emplace_back(Invariant {#Name RECURSIVE_SUFFIX, RecursiveInvariant(*invariant)}); \ - invariants_names_.insert(#Name RECURSIVE_SUFFIX); \ - } -// NOLINTEND(cppcoreguidelines-macro-usage) +void ASTVerifier::AddInvariant(const std::string &name, const InvariantCheck &invariant) +{ + invariants_checks_[name] = invariant; + invariants_names_.insert(name); + invariants_checks_[name + RECURSIVE_SUFFIX] = RecursiveInvariant(invariant); + invariants_names_.insert(name + RECURSIVE_SUFFIX); +} -ASTVerifier::ASTVerifier(ArenaAllocator *allocator) : invariants_checks_ {}, invariants_names_ {} +ASTVerifier::ASTVerifier(ArenaAllocator *allocator) { - ADD_INVARIANT(NodeHasParent); - ADD_INVARIANT(NodeHasType); - ADD_INVARIANT(IdentifierHasVariable); - ADD_INVARIANT(VariableHasScope); - ADD_INVARIANT(EveryChildHasValidParent); - ADD_INVARIANT(VariableHasEnclosingScope); - ADD_INVARIANT(ForLoopCorrectlyInitialized); - ADD_INVARIANT(ModifierAccessValid); - ADD_INVARIANT(ImportExportAccessValid); - ADD_INVARIANT(ArithmeticOperationValid); - ADD_INVARIANT(SequenceExpressionHasLastType); + AddInvariant("NodeHasParent", *allocator->New(*allocator)); + AddInvariant("NodeHasType", *allocator->New(*allocator)); + AddInvariant("IdentifierHasVariable", *allocator->New(*allocator)); + AddInvariant("VariableHasScope", *allocator->New(*allocator)); + AddInvariant("EveryChildHasValidParent", *allocator->New(*allocator)); + AddInvariant("VariableHasEnclosingScope", *allocator->New(*allocator)); + AddInvariant("ForLoopCorrectlyInitialized", *allocator->New(*allocator)); + AddInvariant("ModifierAccessValid", *allocator->New(*allocator)); + AddInvariant("ImportExportAccessValid", *allocator->New(*allocator)); + AddInvariant("ArithmeticOperationValid", *allocator->New(*allocator)); + AddInvariant("SequenceExpressionHasLastType", *allocator->New(*allocator)); } -ASTVerifier::Errors ASTVerifier::VerifyFull(const ir::AstNode *ast) +std::tuple ASTVerifier::VerifyFull( + const std::unordered_set &warnings, const std::unordered_set &asserts, + const ir::AstNode *ast) { auto recursive_checks = InvariantSet {}; std::copy_if(invariants_names_.begin(), invariants_names_.end(), std::inserter(recursive_checks, recursive_checks.end()), [](const std::string &s) { return s.find(RECURSIVE_SUFFIX) != s.npos; }); - return Verify(ast, recursive_checks); + return Verify(warnings, asserts, ast, recursive_checks); } -ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantSet &invariant_set) +std::tuple ASTVerifier::Verify( + const std::unordered_set &warnings, const std::unordered_set &asserts, + const ir::AstNode *ast, const InvariantSet &invariant_set) { - ErrorContext ctx {}; - auto check_and_report = [&ctx](util::StringView name, const InvariantCheck &invariant, const ir::AstNode *node) { - if (node == nullptr) { - return; - } - - invariant(ctx, node); - // if (result == CheckResult::Failed || result == CheckResult::SkipSubtree) { - ctx.ProcessEncounteredErrors(name); - // } - }; + ErrorContext warning_ctx {}; + AssertsContext assert_ctx {}; const auto contains_invariants = std::includes(invariants_names_.begin(), invariants_names_.end(), invariant_set.begin(), invariant_set.end()); @@ -817,25 +758,24 @@ ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantS if (!contains_invariants) { auto invalid_invariants = InvariantSet {}; for (const auto &invariant : invariant_set) { - if (invariants_names_.find(invariant.data()) == invariants_names_.end()) { + if (invariants_names_.find(invariant) == invariants_names_.end()) { invalid_invariants.insert(invariant.data()); } } for (const auto &invariant : invalid_invariants) { - ctx.AddError(std::string {"invariant was not found: "} + invariant.data()); + assert_ctx.AddError(std::string {"invariant was not found: "} + invariant); } } for (const auto &invariant_name : invariant_set) { - for (const auto &[name, invariant] : invariants_checks_) { - if (std::string_view {invariant_name} == name.Utf8()) { - check_and_report(name, invariant, ast); - break; - } + if (warnings.count(invariant_name) > 0) { + invariants_checks_[invariant_name](warning_ctx, ast); + } else if (asserts.count(invariant_name) > 0) { + invariants_checks_[invariant_name](assert_ctx, ast); } } - return ctx.GetErrors(); + return std::make_tuple(warning_ctx.GetErrors(), assert_ctx.GetErrors()); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ASTVerifier.h b/ets2panda/compiler/core/ASTVerifier.h index 36454b0465..007aa5ebf1 100644 --- a/ets2panda/compiler/core/ASTVerifier.h +++ b/ets2panda/compiler/core/ASTVerifier.h @@ -16,16 +16,20 @@ #ifndef ES2PANDA_COMPILER_CORE_ASTVERIFIER_H #define ES2PANDA_COMPILER_CORE_ASTVERIFIER_H +#include +#include #include +#include +#include + #include "ir/astNode.h" +#include "ir/statements/blockStatement.h" #include "lexer/token/sourceLocation.h" #include "parser/program/program.h" #include "util/ustring.h" #include "utils/arena_containers.h" -#include "varbinder/variable.h" #include "utils/json_builder.h" -#include "ir/statements/blockStatement.h" -#include "compiler/lowering/phase.h" +#include "varbinder/variable.h" namespace panda::es2panda::compiler { @@ -41,29 +45,77 @@ public: size_t line; }; struct CheckError { - util::StringView invariant_name; - InvariantError error; - + explicit CheckError(std::string name, InvariantError error) + : invariant_name_ {std::move(name)}, error_ {std::move(error)} + { + } std::function DumpJSON() const { return [&](JsonObjectBuilder &body) { - body.AddProperty("invariant", invariant_name.Utf8()); - body.AddProperty("cause", error.cause); - body.AddProperty("message", error.message); - body.AddProperty("line", error.line + 1); + body.AddProperty("invariant", invariant_name_); + body.AddProperty("cause", error_.cause); + body.AddProperty("message", error_.message); + body.AddProperty("line", error_.line + 1); }; } + const std::string &GetName() const + { + return invariant_name_; + } + + private: + std::string invariant_name_; + InvariantError error_; }; using Errors = std::vector; - enum class CheckResult { Failed, Success, SkipSubtree }; - struct ErrorContext; + enum class CheckResult { FAILED, SUCCESS, SKIP_SUBTREE }; + class ErrorContext { + public: + explicit ErrorContext() = default; + + void AddError(const std::string &message) + { + errors_.emplace_back(CheckError {"Unnamed", ASTVerifier::InvariantError {message, "", 0}}); + } + + virtual void AddInvariantError(const std::string &name, const std::string &cause, const ir::AstNode &node) + { + errors_.emplace_back( + CheckError {name, ASTVerifier::InvariantError {cause, node.DumpJSON(), node.Start().line}}); + } + + ASTVerifier::Errors GetErrors() + { + return errors_; + } + + private: + Errors errors_; + }; + + class AssertsContext : public ErrorContext { + public: + void AddInvariantError(const std::string &name, const std::string &cause, const ir::AstNode &node) override + { + ASTVerifier::ErrorContext::AddInvariantError(name, cause, node); + // NOTE(tatiana): add ASSERT here + } + }; + + class NoneContext : public ErrorContext { + public: + void AddInvariantError([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &cause, + [[maybe_unused]] const ir::AstNode &node) override + { + } + }; using InvariantCheck = std::function; struct Invariant { util::StringView invariant_name; InvariantCheck invariant; }; - using Invariants = std::vector; + using Invariants = std::map; NO_COPY_SEMANTIC(ASTVerifier); NO_MOVE_SEMANTIC(ASTVerifier); @@ -71,14 +123,16 @@ public: explicit ASTVerifier(ArenaAllocator *allocator); ~ASTVerifier() = default; - using InvariantSet = std::set; + using InvariantSet = std::unordered_set; /** * @brief Run all existing invariants on some ast node (and consequently it's children) * @param ast AstNode which will be analyzed * @return Errors report of analysis */ - Errors VerifyFull(const ir::AstNode *ast); + std::tuple VerifyFull(const std::unordered_set &warnings, + const std::unordered_set &asserts, + const ir::AstNode *ast); /** * @brief Run some particular invariants on some ast node @@ -89,16 +143,21 @@ public: * @param invariant_set Set of strings which will be used as invariant names * @return Errors report of analysis */ - Errors Verify(const ir::AstNode *ast, const InvariantSet &invariant_set); + std::tuple Verify(const std::unordered_set &warnings, + const std::unordered_set &asserts, + const ir::AstNode *ast, + const InvariantSet &invariant_set); private: + void AddInvariant(const std::string &name, const InvariantCheck &invariant); + Invariants invariants_checks_; InvariantSet invariants_names_; }; class ASTVerifierContext final { public: - ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} + explicit ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} void IntroduceNewInvariants(util::StringView phase_name) { @@ -107,43 +166,37 @@ public: if (phase_name == "ScopesInitPhase") { return {{ "NodeHasParentForAll", - "IdentifierHasVariableForAll", - "ModifierAccessValidForAll", - "ImportExportAccessValid", + "EveryChildHasValidParentForAll", + "VariableHasScopeForAll", }}; - } else if (phase_name == "PromiseVoidInferencePhase") { - return {{}}; - } else if (phase_name == "StructLowering") { - return {{}}; - } else if (phase_name == "CheckerPhase") { + } + if (phase_name == "CheckerPhase") { return {{ "NodeHasTypeForAll", + "IdentifierHasVariableForAll", "ArithmeticOperationValidForAll", "SequenceExpressionHasLastTypeForAll", - "EveryChildHasValidParentForAll", "ForLoopCorrectlyInitializedForAll", - "VariableHasScopeForAll", "VariableHasEnclosingScopeForAll", + "ModifierAccessValidForAll", + "ImportExportAccessValid", }}; - } else if (phase_name == "GenerateTsDeclarationsPhase") { - return {{}}; - } else if (phase_name == "InterfacePropertyDeclarationsPhase") { - return {{}}; - } else if (phase_name == "LambdaConstructionPhase") { - return {{}}; - } else if (phase_name == "ObjectIndexLowering") { - return {{}}; - } else if (phase_name == "OpAssignmentLowering") { - return {{}}; - } else if (phase_name == "PromiseVoidInferencePhase") { - return {{}}; - } else if (phase_name == "TupleLowering") { - return {{}}; - } else if (phase_name == "UnionLowering") { - return {{}}; - } else if (phase_name == "ExpandBracketsPhase") { + } + const std::set without_additional_checks = {"PromiseVoidInferencePhase", + "StructLowering", + "GenerateTsDeclarationsPhase", + "InterfacePropertyDeclarationsPhase", + "LambdaConstructionPhase", + "ObjectIndexLowering", + "OpAssignmentLowering", + "PromiseVoidInferencePhase", + "TupleLowering", + "UnionLowering", + "ExpandBracketsPhase"}; + if (without_additional_checks.count(phase_name.Mutf8()) > 0) { return {{}}; - } else if (phase_name.Utf8().find("plugins") != std::string_view::npos) { + } + if (phase_name.Utf8().find("plugins") != std::string_view::npos) { return {{}}; } return std::nullopt; @@ -155,30 +208,40 @@ public: accumulated_checks_.insert(s.begin(), s.end()); } - bool Verify(const ir::AstNode *ast, util::StringView phase_name, util::StringView source_name) + bool Verify(const std::unordered_set &warnings, const std::unordered_set &errors, + const ir::AstNode *ast, util::StringView phase_name, util::StringView source_name) { - errors_ = verifier_.Verify(ast, accumulated_checks_); - for (const auto &e : errors_) { - error_array_.Add([e, source_name, phase_name](JsonObjectBuilder &err) { + auto [warns, asserts] = verifier_.Verify(warnings, errors, ast, accumulated_checks_); + std::for_each(warns.begin(), warns.end(), [this, &source_name, &phase_name](ASTVerifier::CheckError &e) { + warnings_.Add([e, source_name, phase_name](JsonObjectBuilder &err) { err.AddProperty("from", source_name.Utf8()); err.AddProperty("phase", phase_name.Utf8()); err.AddProperty("error", e.DumpJSON()); }); - } - auto result = errors_.empty(); - errors_.clear(); - return result; + }); + std::for_each(asserts.begin(), asserts.end(), [this, &source_name, &phase_name](ASTVerifier::CheckError &e) { + asserts_.Add([e, source_name, phase_name](JsonObjectBuilder &err) { + err.AddProperty("from", source_name.Utf8()); + err.AddProperty("phase", phase_name.Utf8()); + err.AddProperty("error", e.DumpJSON()); + }); + }); + return warns.empty() && asserts.empty(); } - std::string DumpErrorsJSON() + std::string DumpWarningsJSON() + { + return std::move(warnings_).Build(); + } + std::string DumpAssertsJSON() { - return std::move(error_array_).Build(); + return std::move(asserts_).Build(); } private: ASTVerifier &verifier_; - ASTVerifier::Errors errors_; - JsonArrayBuilder error_array_; + JsonArrayBuilder warnings_; + JsonArrayBuilder asserts_; ASTVerifier::InvariantSet accumulated_checks_ {}; }; diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index ba41b75581..87850b5124 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -158,20 +158,23 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase for (const auto &it : to_check) { const auto &source_name = std::get<0>(it); const auto &linked_program = std::get<1>(it); - verification_ctx.Verify(linked_program->Ast(), phase->Name(), source_name); + verification_ctx.Verify(context.Options()->verifier_warnings, context.Options()->verifier_errors, + linked_program->Ast(), phase->Name(), source_name); verification_ctx.IntroduceNewInvariants(phase->Name()); } #endif } #ifndef NDEBUG - - if (auto errors = verification_ctx.DumpErrorsJSON(); errors != "[]") { -#ifdef ES2PANDA_AST_VERIFIER_ERROR - ASSERT_PRINT(false, errors); -#else - LOG(ERROR, ES2PANDA) << errors; -#endif + if (!context.Options()->verifier_warnings.empty()) { + if (auto errors = verification_ctx.DumpWarningsJSON(); errors != "[]") { + LOG(ERROR, ES2PANDA) << errors; + } + } + if (!context.Options()->verifier_errors.empty()) { + if (auto errors = verification_ctx.DumpAssertsJSON(); errors != "[]") { + ASSERT_PRINT(false, errors); + } } #endif diff --git a/ets2panda/compiler/lowering/checkerPhase.h b/ets2panda/compiler/lowering/checkerPhase.h index c1f3de095c..cc374cbfb4 100644 --- a/ets2panda/compiler/lowering/checkerPhase.h +++ b/ets2panda/compiler/lowering/checkerPhase.h @@ -20,7 +20,11 @@ namespace panda::es2panda::compiler { class CheckerPhase : public Phase { - DECLARE_PHASE_NAME(CheckerPhase) + std::string_view Name() override + { + return "CheckerPhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/expandBrackets.h b/ets2panda/compiler/lowering/ets/expandBrackets.h index 731f04cc18..30d664848f 100644 --- a/ets2panda/compiler/lowering/ets/expandBrackets.h +++ b/ets2panda/compiler/lowering/ets/expandBrackets.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class ExpandBracketsPhase : public Phase { public: - DECLARE_PHASE_NAME(ExpandBracketsPhase) + std::string_view Name() override + { + return "ExpandBracketsPhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/generateDeclarations.h b/ets2panda/compiler/lowering/ets/generateDeclarations.h index 7e805b86e5..ad6b23c600 100644 --- a/ets2panda/compiler/lowering/ets/generateDeclarations.h +++ b/ets2panda/compiler/lowering/ets/generateDeclarations.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class GenerateTsDeclarationsPhase : public Phase { public: - DECLARE_PHASE_NAME(GenerateTsDeclarationsPhase) + std::string_view Name() override + { + return "GenerateTsDeclarationsPhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h index 5b4cf6646c..ddfbce241a 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class InterfacePropertyDeclarationsPhase : public Phase { public: - DECLARE_PHASE_NAME(InterfacePropertyDeclarationsPhase) + std::string_view Name() override + { + return "InterfacePropertyDeclarationsPhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.h b/ets2panda/compiler/lowering/ets/lambdaLowering.h index 5aba22e52f..f30f8eb81a 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.h +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class LambdaConstructionPhase : public Phase { public: - DECLARE_PHASE_NAME(LambdaConstructionPhase) + std::string_view Name() override + { + return "LambdaConstructionPhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.h b/ets2panda/compiler/lowering/ets/objectIndexAccess.h index 529f5354f1..3e64caa9c5 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.h +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.h @@ -27,7 +27,11 @@ namespace panda::es2panda::compiler { class ObjectIndexLowering : public Phase { public: - DECLARE_PHASE_NAME(ObjectIndexLowering) + std::string_view Name() override + { + return "ObjectIndexLowering"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; diff --git a/ets2panda/compiler/lowering/ets/opAssignment.h b/ets2panda/compiler/lowering/ets/opAssignment.h index 8a4d2ea225..7a098a0544 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.h +++ b/ets2panda/compiler/lowering/ets/opAssignment.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class OpAssignmentLowering : public Phase { public: - DECLARE_PHASE_NAME(OpAssignmentLowering) + std::string_view Name() override + { + return "OpAssignmentLowering"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/promiseVoid.h b/ets2panda/compiler/lowering/ets/promiseVoid.h index 2c38eb3577..89bf01118b 100644 --- a/ets2panda/compiler/lowering/ets/promiseVoid.h +++ b/ets2panda/compiler/lowering/ets/promiseVoid.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class PromiseVoidInferencePhase : public Phase { public: - DECLARE_PHASE_NAME(PromiseVoidInferencePhase) + std::string_view Name() override + { + return "PromiseVoidInferencePhase"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; diff --git a/ets2panda/compiler/lowering/ets/structLowering.h b/ets2panda/compiler/lowering/ets/structLowering.h index 8d73628d9a..a311ab6929 100644 --- a/ets2panda/compiler/lowering/ets/structLowering.h +++ b/ets2panda/compiler/lowering/ets/structLowering.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class StructLowering : public Phase { public: - DECLARE_PHASE_NAME(StructLowering) + std::string_view Name() override + { + return "StructLowering"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/tupleLowering.h b/ets2panda/compiler/lowering/ets/tupleLowering.h index 63aedf3c07..65c6d8c81d 100644 --- a/ets2panda/compiler/lowering/ets/tupleLowering.h +++ b/ets2panda/compiler/lowering/ets/tupleLowering.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class TupleLowering : public Phase { public: - DECLARE_PHASE_NAME(TupleLowering) + std::string_view Name() override + { + return "TupleLowering"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/unionLowering.h b/ets2panda/compiler/lowering/ets/unionLowering.h index b77c88a380..5d2d707d59 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.h +++ b/ets2panda/compiler/lowering/ets/unionLowering.h @@ -22,7 +22,11 @@ namespace panda::es2panda::compiler { class UnionLowering : public Phase { public: - DECLARE_PHASE_NAME(UnionLowering) + std::string_view Name() override + { + return "UnionLowering"; + } + bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 10bf9f13b7..14286b3816 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -59,29 +59,21 @@ static PluginPhase PLUGINS_AFTER_PARSE {"plugins-after-parse", ES2PANDA_STATE_PA static PluginPhase PLUGINS_AFTER_CHECK {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase PLUGINS_AFTER_LOWERINGS {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; +// NOLINTBEGIN(fuchsia-statically-constructed-objects) static InitScopesPhaseETS INIT_SCOPES_PHASE_ETS; static InitScopesPhaseAS INIT_SCOPES_PHASE_AS; static InitScopesPhaseTs INIT_SCOPES_PHASE_TS; static InitScopesPhaseJs INIT_SCOPES_PHASE_JS; +// NOLINTEND(fuchsia-statically-constructed-objects) std::vector GetETSPhaseList() { return { - &PLUGINS_AFTER_PARSE, - &INIT_SCOPES_PHASE_ETS, - &PROMISE_VOID_INFERENCE_PHASE, - &STRUCT_LOWERING, - &LAMBDA_CONSTRUCTION_PHASE, - &INTERFACE_PROP_DECL_PHASE, - &CHECKER_PHASE, - &PLUGINS_AFTER_CHECK, - &GENERATE_TS_DECLARATIONS_PHASE, - &OP_ASSIGNMENT_LOWERING, - &OBJECT_INDEX_LOWERING, - &TUPLE_LOWERING, - &UNION_LOWERING, - &EXPAND_BRACKETS_PHASE, - &PLUGINS_AFTER_LOWERINGS, + &PLUGINS_AFTER_PARSE, &INIT_SCOPES_PHASE_ETS, &PROMISE_VOID_INFERENCE_PHASE, + &STRUCT_LOWERING, &LAMBDA_CONSTRUCTION_PHASE, &INTERFACE_PROP_DECL_PHASE, + &CHECKER_PHASE, &PLUGINS_AFTER_CHECK, &GENERATE_TS_DECLARATIONS_PHASE, + &OP_ASSIGNMENT_LOWERING, &OBJECT_INDEX_LOWERING, &TUPLE_LOWERING, + &UNION_LOWERING, &EXPAND_BRACKETS_PHASE, &PLUGINS_AFTER_LOWERINGS, }; } diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index 2d369b4239..9e2a381c14 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -19,12 +19,6 @@ #include "parser/program/program.h" #include "public/public.h" -#define DECLARE_PHASE_NAME(Phase) \ - std::string_view Name() override \ - { \ - return #Phase; \ - } - namespace panda::es2panda::compiler { class Phase { diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h index 4257f60980..99e824ccfd 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h @@ -40,7 +40,10 @@ class ScopesInitPhase : public Phase, public ir::visitor::IterateAstVisitor { public: using PhaseContext = public_lib::Context; - DECLARE_PHASE_NAME(ScopesInitPhase) + std::string_view Name() override + { + return "ScopesInitPhase"; + } bool Perform(PhaseContext *ctx, parser::Program *program) override; diff --git a/ets2panda/es2panda.h b/ets2panda/es2panda.h index 6cca648fb6..4c7e2210f3 100644 --- a/ets2panda/es2panda.h +++ b/ets2panda/es2panda.h @@ -103,6 +103,8 @@ struct CompilerOptions { std::string ts_decl_out {}; std::vector plugins {}; std::unordered_set skip_phases {}; + std::unordered_set verifier_warnings {}; + std::unordered_set verifier_errors {}; std::unordered_set dump_before_phases {}; std::unordered_set dump_ets_src_before_phases {}; std::unordered_set dump_after_phases {}; diff --git a/ets2panda/test/unit/ast_dumper_test.cpp b/ets2panda/test/unit/ast_dumper_test.cpp index 0ef51a441e..cb28d6709d 100644 --- a/ets2panda/test/unit/ast_dumper_test.cpp +++ b/ets2panda/test/unit/ast_dumper_test.cpp @@ -18,7 +18,6 @@ #include "macros.h" #include "assembler/assembly-program.h" -#include "compiler/core/ASTVerifier.h" #include "ir/astDump.h" #include "ir/expressions/literals/stringLiteral.h" diff --git a/ets2panda/test/unit/public/ast_verifier_test.cpp b/ets2panda/test/unit/public/ast_verifier_test.cpp index 20592966ce..fdfbb06cea 100644 --- a/ets2panda/test/unit/public/ast_verifier_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_test.cpp @@ -21,28 +21,34 @@ #include "macros.h" #include "parser/ETSparser.h" #include "varbinder/ETSBinder.h" -#include "utils/json_builder.h" -#include #include "compiler/core/ASTVerifier.h" -#include #include -// NOLINTBEGIN(cppcoreguidelines-macro-usage) -#define TREE(node) \ - ([&]() { \ - using namespace panda::es2panda::ir; \ - return node; \ - }()) - -#define NODE(Type, ...) allocator->New(__VA_ARGS__) -#define NODES(Type, ...) \ - ([&]() -> ArenaVector { \ - auto v = ArenaVector {allocator->Adapter()}; \ - v.insert(v.end(), {__VA_ARGS__}); \ - return v; \ - }()) -// NOLINTEND(cppcoreguidelines-macro-usage) +using panda::es2panda::CompilerOptions; +using panda::es2panda::ScriptExtension; +using panda::es2panda::checker::ETSChecker; +using panda::es2panda::compiler::ASTVerifier; +using panda::es2panda::ir::AstNode; +using panda::es2panda::ir::BinaryExpression; +using panda::es2panda::ir::BooleanLiteral; +using panda::es2panda::ir::ETSScript; +using panda::es2panda::ir::Expression; +using panda::es2panda::ir::Identifier; +using panda::es2panda::ir::NumberLiteral; +using panda::es2panda::ir::SequenceExpression; +using panda::es2panda::ir::StringLiteral; +using panda::es2panda::lexer::Number; +using panda::es2panda::lexer::TokenType; +using panda::es2panda::parser::ETSParser; +using panda::es2panda::parser::Program; +using panda::es2panda::util::StringView; +using panda::es2panda::varbinder::ETSBinder; +using panda::es2panda::varbinder::FunctionScope; +using panda::es2panda::varbinder::LetDecl; +using panda::es2panda::varbinder::LocalScope; +using panda::es2panda::varbinder::LocalVariable; +using panda::es2panda::varbinder::VariableFlags; class ASTVerifierTest : public testing::Test { public: @@ -69,6 +75,26 @@ public: NO_MOVE_SEMANTIC(ASTVerifierTest); protected: + template + Type *Tree(Type *node) + { + return node; + } + + template + Type *Node(Args &&...args) + { + return allocator_->New(std::forward(args)...); + } + + template + panda::ArenaVector Nodes(Args &&...args) + { + auto v = panda::ArenaVector {allocator_->Adapter()}; + v.insert(v.end(), {std::forward(args)...}); + return v; + } + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) es2panda_Impl const *impl_; es2panda_Config *cfg_; @@ -76,104 +102,83 @@ protected: // NOLINTEND(misc-non-private-member-variables-in-classes) }; -static void compare_minified(std::string_view actual_json, std::string_view expected_json) -{ - std::string message {actual_json}; - static const std::regex r {R"(\s+)"}; - auto ss = std::stringstream {}; - - std::regex_replace(std::ostream_iterator(ss), message.begin(), message.end(), r, ""); - ASSERT_EQ(ss.str(), expected_json); -} - TEST_F(ASTVerifierTest, NullParent) { - compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::StringLiteral empty_node; + ASTVerifier verifier {Allocator()}; + StringLiteral empty_node; const auto check = "NodeHasParent"; - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert(check); - const auto &errors = verifier.Verify(&empty_node, checks); - bool has_parent = errors.size() == 0; - ASSERT_EQ(has_parent, false); - ASSERT_EQ(errors.size(), 1); - - const auto [name, error] = errors[0]; - ASSERT_EQ(name, check); - auto message_expected = JsonObjectBuilder {}; - message_expected.AddProperty("type", "StringLiteral"); - message_expected.AddProperty("value", ""); - compare_minified(error.message, std::move(message_expected).Build()); + const auto [warnings, errors] = verifier.Verify({{"NodeHasParent"}}, {{}}, &empty_node, checks); + bool has_parent = warnings.empty(); + ASSERT_FALSE(has_parent); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_EQ(warnings[0].GetName(), check); } TEST_F(ASTVerifierTest, NullType) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::StringLiteral empty_node; + ASTVerifier verifier {Allocator()}; + StringLiteral empty_node; auto check = "NodeHasType"; - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert(check); - const auto &errors = verifier.Verify(&empty_node, checks); - bool has_type = errors.size() == 0; + const auto [warnings, errors] = verifier.Verify({{"NodeHasType"}}, {{}}, &empty_node, checks); + bool has_type = warnings.empty(); ASSERT_EQ(has_type, false); - ASSERT_NE(errors.size(), 0); - - const auto [name, error] = errors[0]; - ASSERT_EQ(name, check); + ASSERT_NE(warnings.size(), 0); - auto message_expected = JsonObjectBuilder {}; - message_expected.AddProperty("type", "StringLiteral"); - message_expected.AddProperty("value", ""); - compare_minified(error.message, std::move(message_expected).Build()); + ASSERT_EQ(warnings[0].GetName(), check); } TEST_F(ASTVerifierTest, WithoutScope) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::StringLiteral empty_node; + ASTVerifier verifier {Allocator()}; + StringLiteral empty_node; - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("VariableHasScope"); - const auto &errors = verifier.Verify(&empty_node, checks); + const auto [warnings, errors] = verifier.Verify({{"VariableHasScope"}}, {{}}, &empty_node, checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ScopeTest) { - compiler::ASTVerifier verifier {Allocator()}; - ir::Identifier ident(util::StringView("var_decl"), Allocator()); - varbinder::LetDecl decl("test", &ident); - varbinder::LocalVariable local(&decl, varbinder::VariableFlags::LOCAL); + ASTVerifier verifier {Allocator()}; + Identifier ident(StringView("var_decl"), Allocator()); + LetDecl decl("test", &ident); + LocalVariable local(&decl, VariableFlags::LOCAL); ident.SetVariable(&local); - varbinder::LocalScope scope(Allocator(), nullptr); - varbinder::FunctionScope parent_scope(Allocator(), nullptr); + LocalScope scope(Allocator(), nullptr); + FunctionScope parent_scope(Allocator(), nullptr); scope.SetParent(&parent_scope); scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); local.SetScope(&scope); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("VariableHasScope"); - const auto &errors = verifier.Verify(&ident, checks); + const auto [warnings, errors] = verifier.Verify({{"VariableHasScope"}}, {{}}, &ident, checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ScopeNodeTest) { - compiler::ASTVerifier verifier {Allocator()}; - ir::Identifier ident(util::StringView("var_decl"), Allocator()); - varbinder::LetDecl decl("test", &ident); - varbinder::LocalVariable local(&decl, varbinder::VariableFlags::LOCAL); + ASTVerifier verifier {Allocator()}; + Identifier ident(StringView("var_decl"), Allocator()); + LetDecl decl("test", &ident); + LocalVariable local(&decl, VariableFlags::LOCAL); ident.SetVariable(&local); - varbinder::LocalScope scope(Allocator(), nullptr); - varbinder::FunctionScope parent_scope(Allocator(), nullptr); + LocalScope scope(Allocator(), nullptr); + FunctionScope parent_scope(Allocator(), nullptr); scope.SetParent(&parent_scope); scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); @@ -181,133 +186,128 @@ TEST_F(ASTVerifierTest, ScopeNodeTest) local.SetScope(&scope); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("VariableHasEnclosingScope"); - const auto &errors = verifier.Verify(&ident, checks); + const auto [warnings, errors] = verifier.Verify({{"VariableHasEnclosingScope"}}, {{}}, &ident, checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect1) { - checker::ETSChecker etschecker {}; - compiler::ASTVerifier verifier {Allocator()}; - auto program = parser::Program::NewProgram(Allocator()); - auto parser = parser::ETSParser(&program, CompilerOptions {}); + ETSChecker etschecker {}; + ASTVerifier verifier {Allocator()}; + auto program = Program::NewProgram(Allocator()); + auto parser = ETSParser(&program, CompilerOptions {}); - auto left = ir::NumberLiteral(lexer::Number {1}); - auto right = ir::NumberLiteral(lexer::Number {6}); - auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_PLUS); + auto left = NumberLiteral(Number {1}); + auto right = NumberLiteral(Number {6}); + auto arithmetic_expression = BinaryExpression(&left, &right, TokenType::PUNCTUATOR_PLUS); left.SetTsType(etschecker.GlobalIntType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("ArithmeticOperationValid"); - const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(errors.size(), 0); + const auto [warnings, errors] = + verifier.Verify({{"ArithmeticOperationValid"}}, {{}}, arithmetic_expression.AsBinaryExpression(), checks); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect2) { - checker::ETSChecker etschecker {}; - compiler::ASTVerifier verifier {Allocator()}; - auto program = parser::Program::NewProgram(Allocator()); - auto parser = parser::ETSParser(&program, CompilerOptions {}); + ETSChecker etschecker {}; + ASTVerifier verifier {Allocator()}; + auto program = Program::NewProgram(Allocator()); + auto parser = ETSParser(&program, CompilerOptions {}); constexpr uint32_t LEFT1_PARAM = 1; constexpr uint32_t LEFT2_PARAM = 12; constexpr uint32_t RIGHT2_PARAM = 6; - auto left1 = ir::NumberLiteral(lexer::Number {LEFT1_PARAM}); - auto left2 = ir::NumberLiteral(lexer::Number {LEFT2_PARAM}); - auto right2 = ir::NumberLiteral(lexer::Number {RIGHT2_PARAM}); - auto right1 = ir::BinaryExpression(&left2, &right2, lexer::TokenType::PUNCTUATOR_MULTIPLY); - auto arithmetic_expression = ir::BinaryExpression(&left1, &right1, lexer::TokenType::PUNCTUATOR_PLUS); + auto left1 = NumberLiteral(Number {LEFT1_PARAM}); + auto left2 = NumberLiteral(Number {LEFT2_PARAM}); + auto right2 = NumberLiteral(Number {RIGHT2_PARAM}); + auto right1 = BinaryExpression(&left2, &right2, TokenType::PUNCTUATOR_MULTIPLY); + auto arithmetic_expression = BinaryExpression(&left1, &right1, TokenType::PUNCTUATOR_PLUS); left1.SetTsType(etschecker.GlobalIntType()); right1.SetTsType(etschecker.GlobalIntType()); left2.SetTsType(etschecker.GlobalIntType()); right2.SetTsType(etschecker.GlobalIntType()); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("ArithmeticOperationValid"); - const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(errors.size(), 0); + const auto [warnings, errors] = + verifier.Verify({{"ArithmeticOperationValid"}}, {{}}, arithmetic_expression.AsBinaryExpression(), checks); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionNegative1) { - checker::ETSChecker etschecker {}; - compiler::ASTVerifier verifier {Allocator()}; - auto program = parser::Program::NewProgram(Allocator()); - auto parser = parser::ETSParser(&program, CompilerOptions {}); + ETSChecker etschecker {}; + ASTVerifier verifier {Allocator()}; + auto program = Program::NewProgram(Allocator()); + auto parser = ETSParser(&program, CompilerOptions {}); - const panda::es2panda::util::StringView left_param("1"); + const StringView left_param("1"); constexpr uint32_t RIGHT_PARAM = 1; - auto left = ir::StringLiteral(left_param); - auto right = ir::NumberLiteral(lexer::Number {RIGHT_PARAM}); - auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_DIVIDE); + auto left = StringLiteral(left_param); + auto right = NumberLiteral(Number {RIGHT_PARAM}); + auto arithmetic_expression = BinaryExpression(&left, &right, TokenType::PUNCTUATOR_DIVIDE); left.SetTsType(etschecker.GlobalETSStringLiteralType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("ArithmeticOperationValid"); - const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + const auto [warnings, errors] = + verifier.Verify({{"ArithmeticOperationValid"}}, {{}}, arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, ArithmeticExpressionNegative2) { - checker::ETSChecker etschecker {}; - compiler::ASTVerifier verifier {Allocator()}; - auto program = parser::Program::NewProgram(Allocator()); - auto parser = parser::ETSParser(&program, CompilerOptions {}); - auto left = ir::BooleanLiteral(true); - auto right = ir::NumberLiteral(lexer::Number {1}); - auto arithmetic_expression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_DIVIDE); + ETSChecker etschecker {}; + ASTVerifier verifier {Allocator()}; + auto program = Program::NewProgram(Allocator()); + auto parser = ETSParser(&program, CompilerOptions {}); + auto left = BooleanLiteral(true); + auto right = NumberLiteral(Number {1}); + auto arithmetic_expression = BinaryExpression(&left, &right, TokenType::PUNCTUATOR_DIVIDE); left.SetTsType(etschecker.GlobalETSStringLiteralType()); right.SetTsType(etschecker.GlobalIntType()); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("ArithmeticOperationValid"); - const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); + const auto [warnings, errors] = + verifier.Verify({{"ArithmeticOperationValid"}}, {{}}, arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } TEST_F(ASTVerifierTest, SequenceExpressionType) { - compiler::ASTVerifier verifier {Allocator()}; - auto *allocator = Allocator(); - - auto checker = checker::ETSChecker(); - - auto *last = TREE(NODE(NumberLiteral, lexer::Number {3})); - // clang-format off - auto *sequence_expression = - TREE(NODE(SequenceExpression, - NODES(Expression, - NODE(NumberLiteral, lexer::Number {1}), - NODE(NumberLiteral, lexer::Number {2}), - last, - ))); - // clang-format on + ASTVerifier verifier {Allocator()}; + auto checker = ETSChecker(); + auto *last = Tree(Node(Number {3})); + auto *sequence_expression = Tree(Node( + Nodes(Node(Number {1}), Node(Number {2}), last))); last->SetTsType(checker.GlobalIntType()); sequence_expression->SetTsType(checker.GlobalIntType()); - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert("SequenceExpressionHasLastType"); - const auto &errors = verifier.Verify(sequence_expression, checks); + const auto [warnings, errors] = + verifier.Verify({{"SequenceExpressionHasLastType"}}, {{}}, sequence_expression, checks); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); } constexpr char const *PRIVATE_PROTECTED_PUBLIC_TEST = - R"XXX( + R"( class Base { public a: int = 1; protected b: int = 2; @@ -348,46 +348,44 @@ constexpr char const *PRIVATE_PROTECTED_PUBLIC_TEST = let c = derived2.a; derived2.publicMethod(); } - )XXX"; + )"; TEST_F(ASTVerifierTest, PrivateProtectedPublicAccessTestCorrect) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, PRIVATE_PROTECTED_PUBLIC_TEST, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); - ASSERT_EQ(is_correct, true); - ASSERT_EQ(errors.size(), 0); + ASSERT_EQ(warnings.size(), 0); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative1) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } class Derived extends Base { public b: int = this.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -396,23 +394,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative1) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR MUST BE UNREACHABLE.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative2) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -420,14 +416,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative2) let base: Base = new Base(); let a = base.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -436,23 +432,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative2) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID base.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative3) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -461,14 +455,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative3) let derived: Derived = new Derived(); let a = derived.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -477,23 +471,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative3) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative4) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -502,14 +494,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative4) let derived: Base = new Derived(); let a = derived.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -518,23 +510,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative4) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative5) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public privateMethod() { @@ -545,14 +535,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative5) let base: Base = new Base(); base.privateMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -572,23 +562,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative5) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID base.ID privateMethod"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative6) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public privateMethod() { @@ -600,14 +588,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative6) let derived: Derived = new Derived(); derived.privateMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -627,23 +615,21 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative6) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID privateMethod"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, PrivateAccessTestNegative7) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public privateMethod() { @@ -655,14 +641,14 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative7) let derived: Base = new Derived(); derived.privateMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -682,37 +668,35 @@ TEST_F(ASTVerifierTest, PrivateAccessTestNegative7) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PRIVATE); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID privateMethod"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestCorrect) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class A { public a: int = 1; } class B extends A { public b: int = this.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -721,21 +705,20 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestCorrect) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + + ASSERT_EQ(warnings.size(), 0); - ASSERT_EQ(is_correct, true); - ASSERT_EQ(errors.size(), 0); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative1) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -743,14 +726,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative1) let base: Base = new Base(); let a = base.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -759,23 +742,21 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative1) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID base.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative2) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -784,14 +765,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative2) let derived: Derived = new Derived(); let a = derived.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -800,23 +781,21 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative2) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative3) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; } @@ -825,14 +804,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative3) let derived: Base = new Derived(); let a = derived.a; } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[1] ->AsClassDeclaration() ->Definition() @@ -841,23 +820,21 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative3) ->AsClassProperty() ->AddModifier(panda::es2panda::ir::ModifierFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID a"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative4) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public protectedMethod() { @@ -868,14 +845,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative4) let base: Base = new Base(); base.protectedMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -895,23 +872,21 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative4) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID base.ID protectedMethod"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative5) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public protectedMethod() { @@ -923,14 +898,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative5) let derived: Derived = new Derived(); derived.protectedMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -950,23 +925,21 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative5) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID protectedMethod"); impl_->DestroyContext(ctx); } TEST_F(ASTVerifierTest, ProtectedAccessTestNegative6) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + ASTVerifier verifier {Allocator()}; - char const *text = R"XXX( + char const *text = R"( class Base { public a: int = 1; public protectedMethod() { @@ -978,14 +951,14 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative6) let derived: Base = new Derived(); derived.protectedMethod(); } - )XXX"; + )"; es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); - ast->AsBlockStatement() + ast->AsETSScript() ->Statements()[0] ->AsClassDeclaration() ->Definition() @@ -1005,14 +978,13 @@ TEST_F(ASTVerifierTest, ProtectedAccessTestNegative6) ->Signature() ->AddSignatureFlag(panda::es2panda::checker::SignatureFlags::PROTECTED); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyModifierAccessRecursive"); - bool is_correct = verifier.Verify(ast, checks); - const auto &errors = verifier.GetErrors(); - const auto [name, error] = errors[0]; + ASTVerifier::InvariantSet checks; + checks.insert("ModifierAccessValidForAll"); + + const auto [warnings, errors] = verifier.Verify({{"ModifierAccessValidForAll"}}, {{}}, ast, checks); + ASSERT_EQ(warnings.size(), 1); + + ASSERT_NE(checks.find(warnings[0].GetName() + "ForAll"), checks.end()); - ASSERT_EQ(is_correct, false); - ASSERT_EQ(errors.size(), 1); - ASSERT_EQ(error.message, "PROPERTY_NOT_VISIBLE_HERE: MEMBER_EXPR ID derived.ID protectedMethod"); impl_->DestroyContext(ctx); } diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index ef9399af14..81bf6ab527 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -181,6 +181,8 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg gen_std_lib("gen-stdlib", false, "Gen standard library"); panda::PandArg plugins("plugins", "", "Plugins"); panda::PandArg skip_phases("skip-phases", "", "Phases to skip"); + panda::PandArg verifier_warnings("verifier-warnings", "", "Show warnings form verifier"); + panda::PandArg verifier_errors("verifier-errors", "", "Show warnings form verifier"); panda::PandArg dump_before_phases("dump-before-phases", "", "Generate program dump before running phases in the list"); panda::PandArg dump_ets_src_before_phases( @@ -222,6 +224,8 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&gen_std_lib); argparser_->Add(&plugins); argparser_->Add(&skip_phases); + argparser_->Add(&verifier_warnings); + argparser_->Add(&verifier_errors); argparser_->Add(&dump_before_phases); argparser_->Add(&dump_ets_src_before_phases); argparser_->Add(&dump_after_phases); @@ -420,6 +424,8 @@ bool Options::Parse(int argc, const char **argv) compiler_options_.is_ets_module = op_ets_module.GetValue(); compiler_options_.plugins = SplitToStringVector(plugins.GetValue()); compiler_options_.skip_phases = SplitToStringSet(skip_phases.GetValue()); + compiler_options_.verifier_warnings = SplitToStringSet(verifier_warnings.GetValue()); + compiler_options_.verifier_errors = SplitToStringSet(verifier_errors.GetValue()); compiler_options_.dump_before_phases = SplitToStringSet(dump_before_phases.GetValue()); compiler_options_.dump_ets_src_before_phases = SplitToStringSet(dump_ets_src_before_phases.GetValue()); compiler_options_.dump_after_phases = SplitToStringSet(dump_after_phases.GetValue()); -- Gitee From 34427216bee1001feb22dc2b1ed4f61f89933038 Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Tue, 9 Jan 2024 15:47:43 +0300 Subject: [PATCH 24/24] Title: fix Array generic constructor with union Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8UVS7 Description: fix the assertion in the function that creates nullish type so that it works for Unions Test: ${ARK_SOURCE_DIR}/tests/tests-u-runner/runner.sh ${ARK_SOURCE_DIR} --ets-runtime --build-dir="${ARK_BUILD_DIR}" --heap-verifier="fail_on_verification:pre:into:before_g1_concurrent:post" --timeout=30 --force-generate --test-file generic_constructor_with_union.ets Signed-off-by: Anna Antipina --- .../checker/types/ets/etsTypeParameter.cpp | 3 +-- .../ets/generic_constructor_with_union.ets | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 ets2panda/test/runtime/ets/generic_constructor_with_union.ets diff --git a/ets2panda/checker/types/ets/etsTypeParameter.cpp b/ets2panda/checker/types/ets/etsTypeParameter.cpp index f3ea0c6799..abd24eecdb 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -142,8 +142,7 @@ Type *ETSTypeParameter::Substitute(TypeRelation *relation, const Substitution *s if (this != original && ((ContainsNull() && !repl_type->ContainsNull()) || (ContainsUndefined() && !repl_type->ContainsUndefined()))) { // this type is explicitly marked as nullish - ASSERT(repl_type->IsETSObjectType() || repl_type->IsETSArrayType() || repl_type->IsETSFunctionType() || - repl_type->IsETSTypeParameter()); + ASSERT(ETSChecker::IsReferenceType(repl_type)); auto nullish_flags = TypeFlag(TypeFlags() & TypeFlag::NULLISH); auto *new_repl_type = checker->CreateNullishType(repl_type, nullish_flags, checker->Allocator(), relation, checker->GetGlobalTypesHolder()); diff --git a/ets2panda/test/runtime/ets/generic_constructor_with_union.ets b/ets2panda/test/runtime/ets/generic_constructor_with_union.ets new file mode 100644 index 0000000000..4ec5964d82 --- /dev/null +++ b/ets2panda/test/runtime/ets/generic_constructor_with_union.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 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 main(): void { + let x = new Array<(Number|String)>(); +} \ No newline at end of file -- Gitee