From 3783d8db2900fb789ac9ab421486ded1dc318f15 Mon Sep 17 00:00:00 2001 From: liyue Date: Thu, 14 Dec 2023 06:47:08 +0000 Subject: [PATCH 01/27] 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 | 59 +- 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, 4749 insertions(+), 8 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 1099d4f2f0..d6cfff1fbf 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 @@ -968,9 +970,41 @@ checker::Type *ETSAnalyzer::Check(ir::BlockExpression *st) const UNREACHABLE(); } -ArenaVector &ChooseSignatures(checker::Type *calleeType, bool isConstructorCall, - bool isFunctionalInterface) +ArenaVector GetUnionTypeSignatures(ETSChecker *checker, checker::ETSUnionType *etsUnionType) { + ArenaVector callSignatures(checker->Allocator()->Adapter()); + + for (auto *constituentType : etsUnionType->ConstituentTypes()) { + if (constituentType->IsETSObjectType()) { + ArenaVector tmpCallSignatures(checker->Allocator()->Adapter()); + tmpCallSignatures = constituentType->AsETSObjectType() + ->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures(); + callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end()); + } + if (constituentType->IsETSFunctionType()) { + ArenaVector tmpCallSignatures(checker->Allocator()->Adapter()); + tmpCallSignatures = constituentType->AsETSFunctionType()->CallSignatures(); + callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end()); + } + if (constituentType->IsETSUnionType()) { + ArenaVector tmpCallSignatures(checker->Allocator()->Adapter()); + tmpCallSignatures = GetUnionTypeSignatures(checker, constituentType->AsETSUnionType()); + callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end()); + } + } + + return callSignatures; +} + +ArenaVector &ChooseSignatures(ETSChecker *checker, checker::Type *calleeType, + bool isConstructorCall, bool isFunctionalInterface, + bool isUnionTypeWithFunctionalInterface) +{ + static ArenaVector unionSignatures(checker->Allocator()->Adapter()); + unionSignatures.clear(); if (isConstructorCall) { return calleeType->AsETSObjectType()->ConstructSignatures(); } @@ -981,6 +1015,10 @@ ArenaVector &ChooseSignatures(checker::Type *calleeType, bool isCon ->AsETSFunctionType() ->CallSignatures(); } + if (isUnionTypeWithFunctionalInterface) { + unionSignatures = GetUnionTypeSignatures(checker, calleeType->AsETSUnionType()); + return unionSignatures; + } return calleeType->AsETSFunctionType()->CallSignatures(); } @@ -998,7 +1036,8 @@ checker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression } checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType, - bool isConstructorCall, bool isFunctionalInterface) + bool isConstructorCall, bool isFunctionalInterface, + bool isUnionTypeWithFunctionalInterface) { bool extensionFunctionType = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(calleeType); @@ -1008,7 +1047,8 @@ checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *ex if (extensionFunctionType) { return ResolveCallExtensionFunction(calleeType->AsETSFunctionType(), checker, expr); } - auto &signatures = ChooseSignatures(calleeType, isConstructorCall, isFunctionalInterface); + auto &signatures = ChooseSignatures(checker, calleeType, isConstructorCall, isFunctionalInterface, + isUnionTypeWithFunctionalInterface); checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start()); if (signature->Function()->IsExtensionMethod()) { checker->ThrowTypeError({"No matching call signature"}, expr->Start()); @@ -1020,8 +1060,11 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ { ETSChecker *checker = GetETSChecker(); bool isConstructorCall = expr->IsETSConstructorCall(); + bool isUnionTypeWithFunctionalInterface = + calleeType->IsETSUnionType() && + calleeType->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool isFunctionalInterface = calleeType->IsETSObjectType() && calleeType->AsETSObjectType()->HasObjectFlag( - checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); + checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool etsExtensionFuncHelperType = calleeType->IsETSExtensionFuncHelperType(); if (expr->Callee()->IsArrowFunctionExpression()) { @@ -1030,12 +1073,12 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ } if (!isFunctionalInterface && !calleeType->IsETSFunctionType() && !isConstructorCall && - !etsExtensionFuncHelperType) { + !etsExtensionFuncHelperType && !isUnionTypeWithFunctionalInterface) { checker->ThrowTypeError("This expression is not callable.", expr->Start()); } - checker::Signature *signature = - ResolveSignature(checker, expr, calleeType, isConstructorCall, isFunctionalInterface); + checker::Signature *signature = ResolveSignature(checker, expr, calleeType, isConstructorCall, + isFunctionalInterface, isUnionTypeWithFunctionalInterface); checker->CheckObjectLiteralArguments(signature, expr->Arguments()); checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 39e3852175..bea5bdbf88 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 *typeAnnotation); // Type creation ByteType *CreateByteType(int8_t value); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 22debb2259..34d5cb6d10 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 (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) { type->AddProperty(it->AsLocalVariable()); it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } else if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSTypeReference()) { + bool hasFunctionType = HasETSFunctionType(classProp->TypeAnnotation()); + if (hasFunctionType) { + type->AddProperty(it->AsLocalVariable()); + it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } } } @@ -418,6 +425,12 @@ void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) { type->AddProperty(it->AsLocalVariable()); it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE); + } else if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSTypeReference()) { + bool hasFunctionType = HasETSFunctionType(classProp->TypeAnnotation()); + if (hasFunctionType) { + 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 *typeAnnotation) +{ + if (typeAnnotation->IsETSFunctionType()) { + return true; + } + std::unordered_set childrenSet; + + if (typeAnnotation->IsETSTypeReference()) { + auto *typeDecl = + typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration(); + if (typeDecl != nullptr && typeDecl->IsTypeAliasDecl()) { + typeAnnotation = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation(); + if (typeAnnotation->IsETSUnionType()) { + for (auto *type : typeAnnotation->AsETSUnionType()->Types()) { + if (type->IsETSTypeReference()) { + childrenSet.insert(type); + } + } + } else { + childrenSet.insert(typeAnnotation); + } + } + + for (auto *child : childrenSet) { + if (HasETSFunctionType(child)) { + return true; + } + } + } + + return false; +} + std::vector ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *objType) { 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 ed200b6d88cc618a8f2a06e906a6f844988f99bc Mon Sep 17 00:00:00 2001 From: Zhelyapov Aleksey Date: Thu, 30 Nov 2023 21:00:38 +0300 Subject: [PATCH 02/27] 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 371f3a7aec..38bb21e67b 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -774,6 +774,10 @@ std::tuple ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Ty return {GlobalLongType(), bothConst}; } + if (unboxedL->IsCharType() && unboxedR->IsCharType()) { + return {GlobalCharType(), bothConst}; + } + return {GlobalIntType(), bothConst}; } diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index bc9fc3dc79..ec89b81fc1 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -837,6 +837,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, ifFalse); break; -- Gitee From ed794615b83133b581205ac2c68760b7fe94ce5b Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Mon, 13 Nov 2023 12:16:40 +0100 Subject: [PATCH 03/27] [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 0281394b50..ff6382c7ed 100644 --- a/ets2panda/varbinder/scope.cpp +++ b/ets2panda/varbinder/scope.cpp @@ -741,8 +741,18 @@ Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Var SetBindingProps(newDecl, &props, isStatic); - if (FindLocal(newDecl->Name(), ResolveBindingOptions::ALL) != nullptr) { - return nullptr; + const auto *foundVar = FindLocal(newDecl->Name(), ResolveBindingOptions::ALL); + if (foundVar != nullptr) { + if (!newDecl->IsLetOrConstDecl()) { + return nullptr; + } + + foundVar = FindLocal(newDecl->Name(), + ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES + : ResolveBindingOptions::STATIC_VARIABLES)); + if (foundVar != nullptr) { + return nullptr; + } } auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension); -- Gitee From ef823111b1cd646ab606fed277f93e558c973c3b Mon Sep 17 00:00:00 2001 From: Kira Prokopenko Date: Mon, 11 Dec 2023 18:15:45 +0300 Subject: [PATCH 04/27] 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 e22568ebc9251eec83791b576b27cf009049a7ec Mon Sep 17 00:00:00 2001 From: Molokanov Yaroslav Date: Tue, 19 Dec 2023 15:43:24 +0300 Subject: [PATCH 05/27] 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 6b8c568fe5..3cd89c8f79 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, substitutedSig->Function()->Params()[index], flags); + } + auto *const argumentType = argument->Check(this); if (auto const invocationCtx = checker::InvocationContext( diff --git a/ets2panda/checker/ets/typeRelationContext.h b/ets2panda/checker/ets/typeRelationContext.h index d990099248..92b8a8a602 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 b77ee5d33b..7c477a45d8 100644 --- a/ets2panda/ir/expressions/arrayExpression.cpp +++ b/ets2panda/ir/expressions/arrayExpression.cpp @@ -377,4 +377,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 (preferredType_ != nullptr) { + return; + } + auto paramType = param->Check(checker); + if (paramType->IsETSArrayType()) { + paramType = paramType->AsETSArrayType()->ElementType(); + } + bool isAssignable = true; + for (auto elem : elements_) { + auto assignCtx = checker::AssignmentContext(checker->Relation(), elem, elem->Check(checker), paramType, + elem->Start(), {""}, checker::TypeRelationFlag::NO_THROW | flags); + isAssignable &= assignCtx.IsAssignable(); + } + if (isAssignable) { + preferredType_ = param->Check(checker); + } +} + } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h index 8e3e1f0547..66efed5421 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 4a72a3561d1470b7d07a7c7755db70662716ab66 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Tue, 12 Dec 2023 13:53:17 +0300 Subject: [PATCH 06/27] 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 38bb21e67b..3c713a2f37 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1562,7 +1562,7 @@ bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *funcType, Signatur void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature) { for (auto *it : funcType->CallSignatures()) { - SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + SavedTypeRelationFlagsContext strfCtx(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 76a75d5c559512f3c8fc2a118f10ae8f9919ed91 Mon Sep 17 00:00:00 2001 From: aakmaev Date: Mon, 25 Dec 2023 03:31:25 +0300 Subject: [PATCH 07/27] 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 | 23 +++++++-- ets2panda/compiler/core/ETSCompiler.cpp | 6 ++- .../compiler/lowering/ets/unionLowering.cpp | 41 +++++++++++----- .../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, 179 insertions(+), 25 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 d6cfff1fbf..5ddaaaab4c 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1222,7 +1222,7 @@ checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const builtinAlternateType = alternateType; } - expr->SetTsType(checker->FindLeastUpperBound(builtinConseqType, builtinAlternateType)); + expr->SetTsType(checker->CreateETSUnionType(builtinConseqType, builtinAlternateType)); } } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index bea5bdbf88..8a2ca30980 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -194,6 +194,13 @@ public: ETSStringType *CreateETSStringLiteralType(util::StringView value); ETSArrayType *CreateETSArrayType(Type *elementType); Type *CreateETSUnionType(ArenaVector &&constituentTypes); + template + Type *CreateETSUnionType(Types &&...types) + { + ArenaVector constituentTypes(Allocator()->Adapter()); + (constituentTypes.push_back(types), ...); + return CreateETSUnionType(std::move(constituentTypes)); + } 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 bbac84f8f6..dc7912878e 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 etsChecker = 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 == etsChecker->GlobalETSObjectType() && source->IsETSArrayType()) { diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 6ff849b9bf..dddd05e512 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 } } constituentTypes = copiedConstituents; + // Removing subtypes should be in the next iteration, especially needed for proper literals removal + auto checkSubtyping = [relation](Type *lhs, Type *rhs) { + if (lhs == rhs) { + return false; + } + relation->Result(false); + lhs->IsSupertypeOf(relation, rhs); + bool inheritanceRelation = relation->IsTrue(); + rhs->IsSupertypeOf(relation, lhs); + inheritanceRelation = inheritanceRelation || relation->IsTrue(); + return inheritanceRelation; + }; // Secondly, remove identical types auto cmpIt = constituentTypes.begin(); while (cmpIt != constituentTypes.end()) { auto it = std::next(cmpIt); while (it != constituentTypes.end()) { - if (relation->IsIdenticalTo(*it, *cmpIt)) { + if (relation->IsIdenticalTo(*it, *cmpIt) && !checkSubtyping(*it, *cmpIt)) { it = constituentTypes.erase(it); } else { ++it; @@ -196,13 +208,14 @@ void ETSUnionType::NormalizeTypes(TypeRelation *relation, ArenaVector &c while (cmpIt != constituentTypes.end()) { auto newEnd = std::remove_if( constituentTypes.begin(), constituentTypes.end(), [relation, checker, cmpIt, numberFound](Type *ct) { + bool bothConstants = (*cmpIt)->HasTypeFlag(TypeFlag::CONSTANT) && ct->HasTypeFlag(TypeFlag::CONSTANT); relation->Result(false); (*cmpIt)->IsSupertypeOf(relation, ct); - bool removeSubtype = ct != *cmpIt && relation->IsTrue(); + bool removeSubtype = ct != *cmpIt && !bothConstants && relation->IsTrue(); bool removeNumeric = numberFound && ct->IsETSObjectType() && - ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && - !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) && - !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN); + ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && + !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) && + !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN); bool removeNever = ct == checker->GetGlobalTypesHolder()->GlobalBuiltinNeverType(); return removeSubtype || removeNumeric || removeNever; }); diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 2efcab39a7..f3e12197b2 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, endLabel); - 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 930c61a3a9..c05f6f1a70 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" @@ -153,9 +155,9 @@ ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *checker, ir: } if (sourceType != nullptr && expr->Expr()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) { if (expr->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { - auto *const boxedExprType = checker::BoxingConverter::ETSTypeFromSource(checker, expr->TsType()); - auto *const asExpr = GenAsExpression(checker, boxedExprType, expr->Expr(), expr); - asExpr->SetBoxingUnboxingFlags(expr->Expr()->GetBoxingUnboxingFlags()); + auto *const asExpr = GenAsExpression(checker, sourceType, expr->Expr(), expr); + asExpr->SetBoxingUnboxingFlags( + checker->GetUnboxingFlag(checker->ETSBuiltinTypeAsPrimitiveType(sourceType))); expr->Expr()->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::NONE); expr->SetExpr(asExpr); } @@ -179,15 +181,24 @@ ir::BinaryExpression *GenInstanceofExpr(checker::ETSChecker *checker, ir::Expres rhsType = checker::conversion::Boxing(checker->Relation(), constituentType); checker->Relation()->SetNode(nullptr); } - auto *const rhsExpr = - checker->Allocator()->New(rhsType->AsETSObjectType()->Name(), checker->Allocator()); + if (constituentType->IsETSStringType()) { + rhsType = checker->GlobalBuiltinETSStringType(); + } + ir::Expression *rhsExpr; + if (rhsType->IsETSUndefinedType()) { + rhsExpr = checker->Allocator()->New(); + } else if (rhsType->IsETSNullType()) { + rhsExpr = checker->Allocator()->New(); + } else { + rhsExpr = checker->Allocator()->New(rhsType->AsETSObjectType()->Name(), checker->Allocator()); + auto rhsVar = NearestScope(unionNode)->Find(rhsExpr->AsIdentifier()->Name()); + rhsExpr->AsIdentifier()->SetVariable(rhsVar.variable); + } auto *const instanceofExpr = - checker->Allocator()->New(lhsExpr, rhsExpr, lexer::TokenType::KEYW_INSTANCEOF); - lhsExpr->SetParent(instanceofExpr); + checker->Allocator()->New(rhsExpr, rhsExpr, lexer::TokenType::KEYW_INSTANCEOF); + rhsExpr->SetParent(instanceofExpr); rhsExpr->SetParent(instanceofExpr); - auto rhsVar = NearestScope(unionNode)->Find(rhsExpr->Name()); - rhsExpr->SetVariable(rhsVar.variable); - rhsExpr->SetTsType(rhsVar.variable->TsType()); + rhsExpr->SetTsType(rhsType); instanceofExpr->SetOperationType(checker->GlobalETSObjectType()); instanceofExpr->SetTsType(checker->GlobalETSBooleanType()); return instanceofExpr; @@ -266,9 +277,13 @@ ir::Expression *ProcessOperandsInBinaryExpr(checker::ETSChecker *checker, ir::Bi { ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL || expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL); - bool isLhsUnion = expr->Left()->TsType()->IsETSUnionType(); - ir::Expression *unionNode = isLhsUnion ? expr->Left() : expr->Right(); - auto *const asExpression = GenAsExpression(checker, constituentType, unionNode, expr); + bool isLhsUnion; + ir::Expression *unionNode = + (isLhsUnion = expr->Left()->TsType()->IsETSUnionType()) ? expr->Left() : expr->Right(); + checker::Type *typeToCast = constituentType->IsETSNullLike() + ? unionNode->TsType()->AsETSUnionType()->GetLeastUpperBoundType() + : constituentType; + auto *const asExpression = GenAsExpression(checker, typeToCast, unionNode, expr); if (isLhsUnion) { expr->SetLeft(asExpression); expr->SetRight(SetBoxFlagOrGenAsExpression(checker, constituentType, 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 a77e9ae81c..ce42d051e2 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 unionConstituents1(checker.Allocator()->Adapter()); + unionConstituents1.emplace_back(checker.GlobalBuiltinETSStringType()); + unionConstituents1.emplace_back(checker.CreateETSStringLiteralType("abc")); + + // Create union type, which will be normalized inside creation function + auto *const normalizedType1 = checker.CreateETSUnionType(std::move(unionConstituents1)); + ASSERT_NE(normalizedType1, nullptr); + ASSERT_TRUE(normalizedType1->IsETSObjectType()); + ASSERT_EQ(normalizedType1, checker.GlobalBuiltinETSStringType()); + + // Test normalization: "abc" | string | string ==> string + ArenaVector unionConstituents2(checker.Allocator()->Adapter()); + unionConstituents2.emplace_back(checker.CreateETSStringLiteralType("abc")); + unionConstituents2.emplace_back(checker.GlobalBuiltinETSStringType()); + unionConstituents2.emplace_back(checker.GlobalBuiltinETSStringType()); + + // Create union type, which will be normalized inside creation function + auto *const normalizedType2 = checker.CreateETSUnionType(std::move(unionConstituents2)); + ASSERT_NE(normalizedType2, nullptr); + ASSERT_TRUE(normalizedType2->IsETSObjectType()); + ASSERT_EQ(normalizedType2, checker.GlobalBuiltinETSStringType()); + + // Test normalization: number | "abc" | string | "xy" ==> number | string + ArenaVector unionConstituents3(checker.Allocator()->Adapter()); + unionConstituents3.emplace_back(checker.GlobalDoubleType()); + unionConstituents3.emplace_back(checker.CreateETSStringLiteralType("abc")); + unionConstituents3.emplace_back(checker.GlobalBuiltinETSStringType()); + unionConstituents3.emplace_back(checker.CreateETSStringLiteralType("xy")); + + // Create union type, which will be normalized inside creation function + auto *const normalizedType3 = checker.CreateETSUnionType(std::move(unionConstituents3)); + ASSERT_NE(normalizedType3, nullptr); + ASSERT_TRUE(normalizedType3->IsETSUnionType()); + auto *const unionType = normalizedType3->AsETSUnionType(); + ASSERT_EQ(unionType->ConstituentTypes().size(), SIZE2); + ASSERT_EQ(unionType->ConstituentTypes().at(IDX0), checker.GetGlobalTypesHolder()->GlobalDoubleBuiltinType()); + ASSERT_EQ(unionType->ConstituentTypes().at(IDX1), checker.GlobalBuiltinETSStringType()); +} + TEST_F(UnionNormalizationTest, UnionWithNever) { // Test normalization: int | never | number ==> number -- Gitee From 4416d894ecfbb211a7b7d17885591edbbe672f72 Mon Sep 17 00:00:00 2001 From: Maxim Logaev Date: Wed, 13 Dec 2023 17:47:18 +0300 Subject: [PATCH 08/27] 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 5ddaaaab4c..04020591f8 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1553,17 +1553,17 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const break; } case lexer::TokenType::PUNCTUATOR_TILDE: { - if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { - checker->ThrowTypeError("Bad operand type, the type of the operand must be integral type.", + if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", expr->Argument()->Start()); } if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { - expr->SetTsType(checker->BitwiseNegateIntegralType(operandType, expr)); + expr->SetTsType(checker->BitwiseNegateNumericType(operandType, expr)); break; } - expr->SetTsType(operandType); + expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType)); break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index b1815ac6b0..4230394c69 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -344,4 +344,19 @@ void ETSChecker::HandleUpdatedCallExpressionNode(ir::CallExpression *callExpr) VarBinder()->AsETSBinder()->HandleCustomNodes(callExpr); } +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 8a2ca30980..dda76984b0 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 operationType, lexer::SourcePosition pos, bool forcePromotion = false); @@ -261,6 +263,7 @@ public: checker::Type *CheckBinaryOperatorNullishCoalescing(ir::Expression *right, lexer::SourcePosition pos, checker::Type *leftType, checker::Type *rightType); Type *HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + Type *HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); void FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression); template Type *PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); @@ -529,6 +532,7 @@ public: bool ExtensionETSFunctionType(checker::Type *type); void ValidateTupleMinElementSize(ir::ArrayExpression *arrayExpr, ETSTupleType *tuple); void ModifyPreferredType(ir::ArrayExpression *arrayExpr, Type *newPreferredType); + Type *SelectGlobalIntegerTypeForNumeric(Type *type); // Exception ETSObjectType *CheckExceptionOrErrorType(checker::Type *type, lexer::SourcePosition pos); @@ -657,8 +661,8 @@ private: template UType HandleModulo(UType leftValue, UType rightValue); - template - UType HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType); + template + Type *HandleBitWiseArithmetic(Type *leftValue, Type *rightValue, lexer::TokenType operationType); template typename TargetType::UType GetOperand(Type *type); diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index e65660e159..c44bd63e7e 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(); } @@ -199,13 +209,13 @@ checker::Type *ETSChecker::CheckBinaryOperatorShift(ir::Expression *left, ir::Ex FlagExpressionWithUnboxing(leftType, unboxedL, left); FlagExpressionWithUnboxing(rightType, unboxedR, right); - if (promotedLeftType == nullptr || !promotedLeftType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL) || - promotedRightType == nullptr || !promotedRightType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { - ThrowTypeError("Bad operand type, the types of the operands must be integral type.", pos); + if (promotedLeftType == nullptr || !promotedLeftType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) || + promotedRightType == nullptr || !promotedRightType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); } if (promotedLeftType->HasTypeFlag(TypeFlag::CONSTANT) && promotedRightType->HasTypeFlag(TypeFlag::CONSTANT)) { - return HandleArithmeticOperationOnTypes(promotedLeftType, promotedRightType, operationType); + return HandleBitwiseOperationOnTypes(promotedLeftType, promotedRightType, operationType); } switch (ETSType(promotedLeftType)) { @@ -218,10 +228,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: { @@ -248,20 +260,20 @@ checker::Type *ETSChecker::CheckBinaryOperatorBitwise(ir::Expression *left, ir:: } auto [promotedType, bothConst] = - ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_INTEGRAL, !isEqualOp); + ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_NUMERIC, !isEqualOp); FlagExpressionWithUnboxing(leftType, unboxedL, left); FlagExpressionWithUnboxing(rightType, unboxedR, 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(leftType, rightType, operationType); + return HandleBitwiseOperationOnTypes(leftType, rightType, operationType); } - return promotedType; + return SelectGlobalIntegerTypeForNumeric(promotedType); } checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir::Expression *right, ir::Expression *expr, @@ -601,6 +613,26 @@ Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexe return PerformArithmeticOperationOnTypes(left, right, operationType); } +Type *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return HandleBitWiseArithmetic(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return HandleBitWiseArithmetic(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return HandleBitWiseArithmetic(left, right, operationType); + } + + return HandleBitWiseArithmetic(left, right, operationType); +} + void ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression) { if (type->IsETSObjectType() && (unboxedType != nullptr)) { diff --git a/ets2panda/checker/ets/arithmetic.h b/ets2panda/checker/ets/arithmetic.h index 928e9b6daf..258d93134b 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(leftValue, rightValue, operationType); + UNREACHABLE(); } } @@ -174,63 +173,69 @@ inline DoubleType::UType panda::es2panda::checker::ETSChecker::HandleModulo -UType ETSChecker::HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType) +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 operationType) { - using UnsignedType = std::make_unsigned_t; - auto unsignedLeftValue = static_cast(leftValue); - auto unsignedRightValue = static_cast(rightValue); - size_t mask = std::numeric_limits::digits - 1U; - size_t shift = static_cast(unsignedRightValue) & mask; + using IntegerUType = typename IntegerType::UType; + using UnsignedUType = std::make_unsigned_t; + + UnsignedUType result = 0; + UnsignedUType unsignedLeftValue = CastIfFloat(GetOperand(left)); + UnsignedUType unsignedRightValue = CastIfFloat(GetOperand(right)); + + auto mask = std::numeric_limits::digits - 1U; + auto shift = unsignedRightValue & mask; switch (operationType) { case lexer::TokenType::PUNCTUATOR_BITWISE_AND: case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { - return unsignedLeftValue & unsignedRightValue; + result = unsignedLeftValue & unsignedRightValue; + break; } case lexer::TokenType::PUNCTUATOR_BITWISE_OR: case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { - return unsignedLeftValue | unsignedRightValue; + result = unsignedLeftValue | unsignedRightValue; + break; } case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { - return unsignedLeftValue ^ unsignedRightValue; + result = unsignedLeftValue ^ unsignedRightValue; + break; } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { - static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); - return unsignedLeftValue << shift; + static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); + result = unsignedLeftValue << shift; + break; } case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { - static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); - return leftValue >> shift; // NOLINT(hicpp-signed-bitwise) + static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8); + result = static_cast(unsignedLeftValue) >> 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 unsignedLeftValue >> shift; + static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); + result = unsignedLeftValue >> shift; + break; } default: { UNREACHABLE(); } } -} - -template <> -inline FloatType::UType ETSChecker::HandleBitWiseArithmetic( - [[maybe_unused]] FloatType::UType leftValue, [[maybe_unused]] FloatType::UType rightValue, - [[maybe_unused]] lexer::TokenType operationType) -{ - return 0.0; -} -template <> -inline DoubleType::UType ETSChecker::HandleBitWiseArithmetic( - [[maybe_unused]] DoubleType::UType leftValue, [[maybe_unused]] DoubleType::UType rightValue, - [[maybe_unused]] lexer::TokenType operationType) -{ - 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 f3e12197b2..050909bea5 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()); } @@ -1068,7 +1067,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 6b0d773c5f539df09a15bfa3d5b8afe7bb626e89 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Mon, 25 Dec 2023 10:42:16 +0300 Subject: [PATCH 09/27] 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 6b88eb17c2..d1cc21302d 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 6d1348f51c..9f1858b5e0 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 { @@ -72,7 +73,9 @@ private: const ArenaVector ¶ms, ParserStatus newStatus, ParserStatus contextStatus) 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 5db2c3fd05..0120458bc8 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -3805,7 +3805,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(); @@ -3906,7 +3906,8 @@ ir::ArrowFunctionExpression *ETSParser::ParseArrowFunctionExpression() return arrowFuncNode; } -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()) { @@ -3916,7 +3917,12 @@ ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterLis lexer::SourcePosition start = Lexer()->GetToken().Start(); Lexer()->NextToken(); - ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); + ExpressionParseFlags newFlags = ExpressionParseFlags::ACCEPT_COMMA; + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + newFlags |= ExpressionParseFlags::INSTANCEOF; + }; + + ir::Expression *expr = ParseExpression(newFlags); if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { ThrowSyntaxError("Unexpected token, expected ')'"); @@ -4594,6 +4600,24 @@ bool ETSParser::IsStructKeyword() const Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT); } +void ETSParser::ValidateInstanceOfExpression(ir::Expression *expr) +{ + ValidateGroupedExpression(expr); + lexer::TokenType tokenType = Lexer()->GetToken().Type(); + if (tokenType == 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) { @@ -4605,6 +4629,10 @@ ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags) } ir::Expression *unaryExpressionNode = ParseUnaryOrPrefixUpdateExpression(flags); + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + ValidateInstanceOfExpression(unaryExpressionNode); + } + ir::Expression *assignmentExpression = ParseAssignmentExpression(unaryExpressionNode, flags); if (Lexer()->GetToken().NewLine()) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 8fb369d0c2..55ae82e016 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 startLoc); @@ -264,6 +267,7 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseEnumDeclaration(bool isConst = false, bool isStatic = 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; @@ -319,7 +323,6 @@ private: ir::Statement *CreateStatement(std::string_view sourceCode, std::string_view fileName = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view sourceCode, std::vector &insertingNodes, std::string_view fileName = DEFAULT_SOURCE_FILE); - // NOLINTEND(google-default-arguments) template ir::Statement *CreateFormattedStatement(std::string_view const sourceCode, std::string_view const fileName, @@ -337,7 +340,6 @@ private: std::string_view fileName = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view sourceCode, std::string_view fileName = 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 fc337a581f..3f299c36d6 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" @@ -2598,7 +2599,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 916abde624..81b2df7164 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; @@ -121,7 +122,9 @@ private: const ArenaVector ¶ms, ParserStatus newStatus, ParserStatus contextStatus) 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 56bd5ec91c..51c3d7c837 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 *lhsExpression) +{ + lexer::TokenType tokenType = lexer_->GetToken().Type(); + if (lhsExpression->IsGrouped() && tokenType != lexer::TokenType::PUNCTUATOR_ARROW) { + if (lhsExpression->IsSequenceExpression()) { + for (auto *seq : lhsExpression->AsSequenceExpression()->Sequence()) { + ValidateParenthesizedExpression(seq); + } + } else { + ValidateParenthesizedExpression(lhsExpression); + } + } +} + void ParserImpl::ValidateParenthesizedExpression(ir::Expression *lhsExpression) { switch (lhsExpression->Type()) { @@ -542,17 +558,9 @@ ir::Expression *ParserImpl::ParsePrefixAssertionExpression() ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpression, ExpressionParseFlags flags) { - lexer::TokenType tokenType = lexer_->GetToken().Type(); - if (lhsExpression->IsGrouped() && tokenType != lexer::TokenType::PUNCTUATOR_ARROW) { - if (lhsExpression->IsSequenceExpression()) { - for (auto *seq : lhsExpression->AsSequenceExpression()->Sequence()) { - ValidateParenthesizedExpression(seq); - } - } else { - ValidateParenthesizedExpression(lhsExpression); - } - } + ValidateGroupedExpression(lhsExpression); + lexer::TokenType tokenType = lexer_->GetToken().Type(); switch (tokenType) { case lexer::TokenType::PUNCTUATOR_QUESTION_MARK: { lexer_->NextToken(); @@ -1191,7 +1199,7 @@ void ParserImpl::CreateAmendedBinaryExpression(ir::Expression *const left, ir::E SetAmendedChildExpression(right, binaryExpr); } -ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) +ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left, ExpressionParseFlags flags) { lexer::TokenType operatorType = lexer_->GetToken().Type(); ASSERT(lexer::Token::IsBinaryToken(operatorType)); @@ -1206,7 +1214,12 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) lexer_->NextToken(); - ir::Expression *rightExpr = ParseExpression(ExpressionParseFlags::DISALLOW_YIELD); + ExpressionParseFlags newFlags = ExpressionParseFlags::DISALLOW_YIELD; + if ((operatorType == lexer::TokenType::KEYW_INSTANCEOF) || ((flags & ExpressionParseFlags::INSTANCEOF) != 0)) { + newFlags |= ExpressionParseFlags::INSTANCEOF; + } + + ir::Expression *rightExpr = ParseExpression(newFlags); ir::ConditionalExpression *conditionalExpr = nullptr; if (rightExpr->IsConditionalExpression() && !rightExpr->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 1965b6dcd5..b73e0aa8fa 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -227,13 +227,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 *returnExpression, bool isChainExpression); ir::Expression *ParseMemberExpression(bool ignoreCallExpression = false, ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); ir::MetaProperty *ParsePotentialNewTarget(); void CheckInvalidDestructuring(const ir::AstNode *object) const; void ValidateParenthesizedExpression(ir::Expression *lhsExpression); + void ValidateGroupedExpression(ir::Expression *lhsExpression); ir::Expression *ParseImportExpression(); ir::Expression *ParseOptionalChain(ir::Expression *leftSideExpr); ir::Expression *ParsePropertyKey(ExpressionParseFlags flags); @@ -480,7 +482,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 **propName); // NOLINTNEXTLINE(google-default-arguments) -- Gitee From 7fbf809198b71e8852bd2de5c40662a09381177e Mon Sep 17 00:00:00 2001 From: Redkin Mikhail Date: Tue, 12 Dec 2023 17:10:43 +0300 Subject: [PATCH 10/27] 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 ac4af44d68..a61f4137c8 100644 --- a/ets2panda/checker/ets/enum.cpp +++ b/ets2panda/checker/ets/enum.cpp @@ -139,7 +139,7 @@ template varbinder::FunctionParamScope *const paramScope, ArenaVector &¶ms, ArenaVector &&body, - ir::TypeNode *const returnTypeAnnotation) + ir::TypeNode *const returnTypeAnnotation, bool isDeclare) { auto *const functionScope = varbinder->Allocator()->New(checker->Allocator(), paramScope); functionScope->BindParamScope(paramScope); @@ -148,9 +148,15 @@ template auto *const bodyBlock = checker->Allocator()->New(checker->Allocator(), std::move(body)); bodyBlock->SetScope(functionScope); + auto flags = ir::ModifierFlags::PUBLIC; + + if (isDeclare) { + flags |= ir::ModifierFlags::DECLARE; + } + auto *const function = checker->Allocator()->New( ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), bodyBlock, - ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC, false, Language(Language::Id::ETS)); + ir::ScriptFunctionFlags::METHOD, flags, isDeclare, Language(Language::Id::ETS)); function->SetScope(functionScope); varbinder->AsETSBinder()->BuildInternalName(function); @@ -335,7 +341,7 @@ ETSEnumType::Method ETSChecker::CreateEnumFromIntMethod(ir::Identifier *const na auto *const enumTypeAnnotation = MakeTypeReference(Allocator(), enumType->GetName()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), enumTypeAnnotation); + std::move(body), enumTypeAnnotation, enumType->GetDecl()->IsDeclare()); function->AddFlag(ir::ScriptFunctionFlags::THROWS); auto *const ident = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::FROM_INT_METHOD_NAME); @@ -371,7 +377,7 @@ ETSEnumType::Method ETSChecker::CreateEnumToStringMethod(ir::Identifier *const s auto *const stringTypeAnnotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), stringTypeAnnotation); + std::move(body), stringTypeAnnotation, enumType->GetDecl()->IsDeclare()); auto *const functionIdent = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::TO_STRING_METHOD_NAME); @@ -409,7 +415,7 @@ ETSEnumType::Method ETSChecker::CreateEnumGetValueMethod(ir::Identifier *const v auto *const intTypeAnnotation = Allocator()->New(ir::PrimitiveType::INT); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), intTypeAnnotation); + std::move(body), intTypeAnnotation, enumType->GetDecl()->IsDeclare()); auto *const functionIdent = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::GET_VALUE_METHOD_NAME); @@ -447,7 +453,7 @@ ETSEnumType::Method ETSChecker::CreateEnumGetNameMethod(ir::Identifier *const na auto *const stringTypeAnnotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), stringTypeAnnotation); + std::move(body), stringTypeAnnotation, enumType->GetDecl()->IsDeclare()); auto *const functionIdent = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::GET_NAME_METHOD_NAME); @@ -571,7 +577,7 @@ ETSEnumType::Method ETSChecker::CreateEnumValueOfMethod(ir::Identifier *const na auto *const enumTypeAnnotation = MakeTypeReference(Allocator(), enumType->GetName()); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), enumTypeAnnotation); + std::move(body), enumTypeAnnotation, enumType->GetDecl()->IsDeclare()); function->AddFlag(ir::ScriptFunctionFlags::THROWS); auto *const functionIdent = @@ -603,7 +609,7 @@ ETSEnumType::Method ETSChecker::CreateEnumValuesMethod(ir::Identifier *const ite Allocator()->New(MakeTypeReference(Allocator(), enumType->GetName())); auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params), - std::move(body), enumArrayTypeAnnotation); + std::move(body), enumArrayTypeAnnotation, enumType->GetDecl()->IsDeclare()); auto *const functionIdent = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::VALUES_METHOD_NAME); diff --git a/ets2panda/compiler/core/ETSfunction.cpp b/ets2panda/compiler/core/ETSfunction.cpp index 485a647a7e..4ec98c2858 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 1ef96909ac..07da87553a 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 isConst, bool isStatic = false) + bool isConst, bool isStatic = false, bool isDeclare = false) : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), decorators_(allocator->Adapter()), key_(key), members_(std::move(members)), - isConst_(isConst) + isConst_(isConst), + isDeclare_(isDeclare) { if (isStatic) { AddModifier(ModifierFlags::STATIC); } + if (isDeclare) { + AddModifier(ModifierFlags::DECLARE); + } } bool IsScopeBearer() const override @@ -88,6 +92,11 @@ public: return isConst_; } + bool IsDeclare() const + { + return isDeclare_; + } + const ArenaVector &Decorators() const { return decorators_; @@ -131,6 +140,7 @@ private: ArenaVector members_; util::StringView internalName_; bool isConst_; + bool isDeclare_; }; } // 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 0120458bc8..0c77d72807 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -780,6 +780,8 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorRewind(savedPos); @@ -1578,6 +1582,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 *memberName = ExpectIdentifier(); if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { @@ -1728,6 +1743,15 @@ ir::Statement *ETSParser::ParseTypeDeclaration(bool allowStatic) 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); } @@ -4294,7 +4318,7 @@ ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, co } auto *const enumDeclaration = - AllocNode(Allocator(), key, std::move(members), isConst, isStatic); + AllocNode(Allocator(), key, std::move(members), isConst, isStatic, InAmbientContext()); enumDeclaration->SetRange({enumStart, Lexer()->GetToken().End()}); Lexer()->NextToken(); // eat '}' @@ -4690,6 +4714,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 3176b9f922..bf8f42719c 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 006777e1dfbbf52f90ab50741546c6b0aa1183f5 Mon Sep 17 00:00:00 2001 From: Redkin_Mikhail Date: Mon, 25 Dec 2023 06:17:20 +0300 Subject: [PATCH 11/27] 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 050909bea5..e966b231e4 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, objReg, qnameReg, signature, arguments); } +static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::ETSNewClassInstanceExpression *expr) +{ + if (expr->GetSignature()->RestVar() != nullptr) { + std::size_t const argumentCount = expr->GetArguments().size(); + std::size_t const parameterCount = expr->GetSignature()->MinArgCount(); + ASSERT(argumentCount >= parameterCount); + + auto &arguments = const_cast &>(expr->GetArguments()); + std::size_t i = parameterCount; + + if (i < argumentCount && expr->GetArguments()[i]->IsSpreadElement()) { + arguments[i] = expr->GetArguments()[i]->AsSpreadElement()->Argument(); + } else { + ArenaVector elements(checker->Allocator()->Adapter()); + for (; i < argumentCount; ++i) { + elements.emplace_back(expr->GetArguments()[i]); + } + auto *arrayExpression = checker->AllocNode(std::move(elements), checker->Allocator()); + arrayExpression->SetParent(const_cast(expr)); + arrayExpression->SetTsType(expr->GetSignature()->RestVar()->TsType()); + arguments.erase(expr->GetArguments().begin() + parameterCount, expr->GetArguments().end()); + arguments.emplace_back(arrayExpression); + } + } +} + 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, objReg, 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 371a904f9e..e93e44518a 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.h @@ -70,11 +70,16 @@ public: return typeReference_; } - [[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 a05242bdd2da7959465d5a3637120e5c20a8a27e Mon Sep 17 00:00:00 2001 From: Vadim Lomovtsev Date: Tue, 7 Nov 2023 17:52:24 +0300 Subject: [PATCH 12/27] 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 | 76 +- .../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(+), 27 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..26f51c28e7 --- /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 *etsStrucDeclaration) +{ + auto *allocator = checker->Allocator(); + + ArenaVector params(allocator->Adapter()); + + ir::TSTypeParameterInstantiation *typeParamSelfInst = nullptr; + + if (etsStrucDeclaration->Definition()->TypeParams() != nullptr && + !etsStrucDeclaration->Definition()->TypeParams()->Params().empty()) { + ArenaVector selfParams(allocator->Adapter()); + ir::ETSTypeReferencePart *referencePart = nullptr; + + for (const auto ¶m : etsStrucDeclaration->Definition()->TypeParams()->Params()) { + auto *identRef = checker->AllocNode(param->AsTSTypeParameter()->Name()->Name(), allocator); + identRef->AsIdentifier()->SetReference(); + + referencePart = checker->AllocNode(identRef, nullptr, nullptr); + + auto *typeReference = checker->AllocNode(referencePart); + + selfParams.push_back(typeReference); + } + + typeParamSelfInst = checker->AllocNode(std::move(selfParams)); + } + + auto *identSelfRef = + checker->AllocNode(etsStrucDeclaration->Definition()->Ident()->Name(), allocator); + identSelfRef->AsIdentifier()->SetReference(); + + auto *referenceSelfPart = + checker->AllocNode(identSelfRef, typeParamSelfInst, nullptr); + + auto *selfTypeReference = checker->AllocNode(referenceSelfPart); + + params.push_back(selfTypeReference); + + auto *typeParamInst = checker->AllocNode(std::move(params)); + + auto *identRef = checker->AllocNode(util::StringView(STRUCT_CLASS_NAME), allocator); + identRef->AsIdentifier()->SetReference(); + auto *referencePart = checker->AllocNode(identRef, typeParamInst, nullptr); + + auto *typeReference = checker->AllocNode(referencePart); + + return typeReference; +} + +bool StructLowering::Perform(public_lib::Context *ctx, parser::Program *program) +{ + for (auto &[_, ext_programs] : program->ExternalSources()) { + (void)_; + for (auto *extProg : ext_programs) { + Perform(ctx, extProg); + } + } + + checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + + program->Ast()->TransformChildrenRecursively([checker](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsETSStructDeclaration()) { + auto *typeRef = CreateStructTypeReference(checker, ast->AsETSStructDeclaration()); + ast->AsETSStructDeclaration()->Definition()->SetSuper(typeRef); + 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 312b3dd8dc..873dfdcb92 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,45 +53,74 @@ static TupleLowering g_tupleLowering; // Can be only applied after checking pha static UnionLowering g_unionLowering; static ExpandBracketsPhase g_expandBracketsPhase; static PromiseVoidLowering g_promiseVoidLowering; +static StructLowering g_structLowering; static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; -std::vector GetPhaseList(ScriptExtension ext) +// clang-format off +std::vector GetETSPhaseList() { static ScopesInitPhaseETS scopesPhaseEts; + return { + &scopesPhaseEts, + &g_pluginsAfterParse, + &g_promiseVoidLowering, + &g_structLowering, + &g_lambdaLowering, + &g_interfacePropDeclPhase, + &g_checkerPhase, + &g_pluginsAfterCheck, + &g_generateTsDeclarationsPhase, + &g_opAssignmentLowering, + &g_objectIndexLowering, + &g_tupleLowering, + &g_unionLowering, + &g_expandBracketsPhase, + &g_pluginsAfterLowerings, + }; +} +// clang-format on + +std::vector GetASPhaseList() +{ static ScopesInitPhaseAS scopesPhaseAs; + return { + &scopesPhaseAs, + &g_checkerPhase, + }; +} + +std::vector GetTSPhaseList() +{ static ScopesInitPhaseTs scopesPhaseTs; + return { + &scopesPhaseTs, + &g_checkerPhase, + }; +} + +std::vector GetJSPhaseList() +{ static ScopesInitPhaseJs scopesPhaseJs; + return { + &scopesPhaseJs, + &g_checkerPhase, + }; +} +std::vector GetPhaseList(ScriptExtension ext) +{ switch (ext) { case ScriptExtension::ETS: - return { - &scopesPhaseEts, &g_pluginsAfterParse, - &g_promiseVoidLowering, &g_lambdaLowering, - &g_interfacePropDeclPhase, &g_checkerPhase, - &g_pluginsAfterCheck, &g_generateTsDeclarationsPhase, - &g_opAssignmentLowering, &g_objectIndexLowering, - &g_tupleLowering, &g_unionLowering, - &g_expandBracketsPhase, &g_pluginsAfterLowerings, - }; - + return GetETSPhaseList(); case ScriptExtension::AS: - return std::vector { - &scopesPhaseAs, - &g_checkerPhase, - }; + return GetASPhaseList(); case ScriptExtension::TS: - return std::vector { - &scopesPhaseTs, - &g_checkerPhase, - }; + return GetTSPhaseList(); case ScriptExtension::JS: - return std::vector { - &scopesPhaseJs, - &g_checkerPhase, - }; + 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 76a59015ff11a1676d159b73d138da0558b1563e Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Tue, 26 Dec 2023 17:55:14 +0300 Subject: [PATCH 13/27] 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 3c713a2f37..21e1ad55c3 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2613,6 +2613,19 @@ void ETSChecker::ModifyPreferredType(ir::ArrayExpression *const arrayExpr, Type } } +std::string GenerateImplicitInstantiateArg(varbinder::LocalVariable *instantiateMethod, const std::string &className) +{ + auto callSignatures = instantiateMethod->TsType()->AsETSFunctionType()->CallSignatures(); + ASSERT(!callSignatures.empty()); + auto methodOwner = std::string(callSignatures[0]->Owner()->Name()); + std::string implicitInstantiateArgument = "()=>{return new " + className + "()"; + if (methodOwner != className) { + implicitInstantiateArgument.append(" as " + methodOwner); + } + implicitInstantiateArgument.append("}"); + return implicitInstantiateArgument; +} + bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolvedType) { ASSERT(ident->Parent()->IsCallExpression()); @@ -2658,7 +2671,8 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons callExpr->SetCallee(transformedCallee); if (instantiateMethod != nullptr) { - std::string implicitInstantiateArgument = "()=>{return new " + std::string(className) + "()}"; + std::string implicitInstantiateArgument = + GenerateImplicitInstantiateArg(instantiateMethod, std::string(className)); 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 a4bac944f6876ac868f3a34b19a49a2238764f51 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Fri, 13 Oct 2023 16:46:47 +0300 Subject: [PATCH 14/27] 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 | 10 +- 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 | 14 +- 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, 1526 insertions(+), 170 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 04020591f8..117456dd03 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1535,6 +1535,38 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType) : checker->ETSBuiltinTypeAsPrimitiveType(argType); + if (argType != nullptr && argType->IsETSBigIntType() && + argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: { + checker::Type *type = checker->CreateETSBigIntLiteralType(argType->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 (argType != nullptr && argType->IsETSBigIntType()) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_TILDE: { + expr->SetTsType(argType); + return expr->TsType(); + } + default: + break; + } + } + switch (expr->OperatorType()) { case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_PLUS: { @@ -1600,7 +1632,7 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const } } - if (argType->IsETSObjectType() && (unboxedOperandType != nullptr) && + if ((argType != nullptr) && argType->IsETSObjectType() && (unboxedOperandType != nullptr) && unboxedOperandType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedOperandType)); } @@ -1630,6 +1662,11 @@ checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const } } + if (operandType->IsETSBigIntType()) { + expr->SetTsType(operandType); + return expr->TsType(); + } + auto unboxedType = checker->ETSBuiltinTypeAsPrimitiveType(operandType); if (unboxedType == nullptr || !unboxedType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", @@ -1652,7 +1689,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 4230394c69..f5422c70ab 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 dda76984b0..a8de220725 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 *elementType); Type *CreateETSUnionType(ArenaVector &&constituentTypes); @@ -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 operationType, lexer::SourcePosition pos, bool forcePromotion = false); @@ -655,7 +660,10 @@ private: void CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends); void SetUpTypeParameterConstraint(ir::TSTypeParameter *param); - ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + ETSObjectType *UpdateGlobalType(ETSObjectType *objType, util::StringView name); + ETSObjectType *UpdateBoxedGlobalType(ETSObjectType *objType, util::StringView name); + ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, + ETSObjectFlags flags); void CheckProgram(parser::Program *program, bool runAnalysis = false); template diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index c44bd63e7e..564f35b581 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, operationType); } +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 operationType, lexer::SourcePosition pos, bool isEqualOp, checker::Type *const leftType, @@ -174,6 +212,11 @@ checker::Type *ETSChecker::CheckBinaryOperatorPlus(ir::Expression *left, ir::Exp } if (leftType->IsETSStringType() || rightType->IsETSStringType()) { + if (operationType == lexer::TokenType::PUNCTUATOR_MINUS || + operationType == lexer::TokenType::PUNCTUATOR_MINUS_EQUAL) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + return HandleStringConcatenation(leftType, rightType); } @@ -487,83 +530,87 @@ Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *right, le return FindLeastUpperBound(nonNullishLeftType, rightType); } -// NOLINTNEXTLINE(readability-function-size) -std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, - ir::Expression *expr, lexer::TokenType operationType, - lexer::SourcePosition pos, bool forcePromotion) +using CheckBinaryFunction = std::function; + +std::map &GetCheckMap() { - checker::Type *const leftType = left->Check(this); - checker::Type *const rightType = right->Check(this); - const bool isLogicalExtendedOperator = (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || - (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); - Type *unboxedL = - isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType); - Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType) - : ETSBuiltinTypeAsPrimitiveType(rightType); + static std::map checkMap = { + {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 checkMap; +} +struct BinaryOperatorParams { + ir::Expression *left; + ir::Expression *right; + ir::Expression *expr; + lexer::TokenType operationType; + lexer::SourcePosition pos; + bool isEqualOp; +}; + +struct TypeParams { + checker::Type *leftType; + checker::Type *rightType; + Type *unboxedL; + Type *unboxedR; +}; + +static std::tuple CheckBinaryOperatorHelper(ETSChecker *checker, + const BinaryOperatorParams &binaryParams, + const TypeParams &typeParams) +{ + ir::Expression *left = binaryParams.left; + ir::Expression *right = binaryParams.right; + lexer::SourcePosition pos = binaryParams.pos; + checker::Type *const leftType = typeParams.leftType; + checker::Type *const rightType = typeParams.rightType; + Type *unboxedL = typeParams.unboxedL; + Type *unboxedR = typeParams.unboxedR; checker::Type *tsType {}; - bool isEqualOp = (operationType > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && - operationType < lexer::TokenType::PUNCTUATOR_ARROW) && - !forcePromotion; - - switch (operationType) { - 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: { - tsType = CheckBinaryOperatorMulDivMod(left, right, operationType, pos, isEqualOp, leftType, rightType, - unboxedL, unboxedR); - break; - } - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { - if (leftType->IsETSStringType() || rightType->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: { - tsType = CheckBinaryOperatorPlus(left, right, operationType, pos, isEqualOp, leftType, rightType, unboxedL, - unboxedR); - 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: { - tsType = CheckBinaryOperatorShift(left, right, operationType, pos, isEqualOp, leftType, rightType, unboxedL, - unboxedR); - 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: { - tsType = CheckBinaryOperatorBitwise(left, right, operationType, pos, isEqualOp, leftType, rightType, - unboxedL, unboxedR); - break; - } + switch (binaryParams.operationType) { case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { - tsType = CheckBinaryOperatorLogical(left, right, expr, pos, leftType, rightType, unboxedL, unboxedR); + tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType, + unboxedL, unboxedR); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - return CheckBinaryOperatorStrictEqual(left, pos, leftType, rightType); + return checker->CheckBinaryOperatorStrictEqual(left, pos, leftType, rightType); } case lexer::TokenType::PUNCTUATOR_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { - std::tuple res = - CheckBinaryOperatorEqual(left, right, operationType, pos, leftType, rightType, unboxedL, unboxedR); + std::tuple res = checker->CheckBinaryOperatorEqual( + left, right, binaryParams.operationType, pos, leftType, rightType, unboxedL, unboxedR); if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) { return res; } @@ -573,18 +620,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, operationType, pos, isEqualOp, leftType, rightType, - unboxedL, unboxedR); + return checker->CheckBinaryOperatorLessGreater(left, right, binaryParams.operationType, pos, + binaryParams.isEqualOp, leftType, rightType, unboxedL, + unboxedR); } case lexer::TokenType::KEYW_INSTANCEOF: { - return CheckBinaryOperatorInstanceOf(pos, leftType, rightType); + return checker->CheckBinaryOperatorInstanceOf(pos, leftType, rightType); } case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { - tsType = CheckBinaryOperatorNullishCoalescing(right, pos, leftType, rightType); + tsType = checker->CheckBinaryOperatorNullishCoalescing(right, pos, leftType, rightType); break; } default: { - // NOTE UNREACHABLE(); break; } @@ -593,6 +640,51 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, return {tsType, tsType}; } +std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + ir::Expression *expr, lexer::TokenType op, + lexer::SourcePosition pos, bool forcePromotion) +{ + checker::Type *const leftType = left->Check(this); + checker::Type *const rightType = right->Check(this); + if ((leftType == nullptr) || (rightType == nullptr)) { + ThrowTypeError("Unexpected type error in binary expression", pos); + } + + const bool isLogicalExtendedOperator = + (op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || (op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); + Type *unboxedL = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) + : ETSBuiltinTypeAsPrimitiveType(leftType); + Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType) + : ETSBuiltinTypeAsPrimitiveType(rightType); + + checker::Type *tsType {}; + bool isEqualOp = + (op > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && op < lexer::TokenType::PUNCTUATOR_ARROW) && !forcePromotion; + + if (CheckBinaryOperatorForBigInt(leftType, rightType, 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 {leftType, rightType}; + } + }; + + auto checkMap = GetCheckMap(); + if (checkMap.find(op) != checkMap.end()) { + auto check = checkMap[op]; + tsType = check(this, left, right, op, pos, isEqualOp, leftType, rightType, unboxedL, unboxedR); + return {tsType, tsType}; + } + + BinaryOperatorParams binaryParams {left, right, expr, op, pos, isEqualOp}; + TypeParams typeParams {leftType, rightType, unboxedL, unboxedR}; + return CheckBinaryOperatorHelper(this, binaryParams, typeParams); +} + Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) { ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 21e1ad55c3..d7c7871659 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1666,7 +1666,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 nodeType, const ir::AstNode *node, diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index bf8867a24d..9446c7c8a9 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(classMethodType, extensionFunctionType); } +std::map &GetNameToTypeIdMap() +{ + static std::map nameToTypeId = { + {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 nameToTypeId; +} + +std::map> &GetNameToGlobalTypeMap() +{ + static std::map> nameToGlobalType = { + {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 nameToGlobalType; +} + +std::map> &GetNameToGlobalBoxTypeMap() +{ + static std::map> nameToGlobalBoxType = { + {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 nameToGlobalBoxType; +} + +ETSObjectType *ETSChecker::UpdateBoxedGlobalType(ETSObjectType *objType, util::StringView name) +{ + auto nameToGlobalBoxType = GetNameToGlobalBoxTypeMap(); + auto nameToTypeId = GetNameToTypeIdMap(); + + if (nameToGlobalBoxType.find(name) != nameToGlobalBoxType.end()) { + std::function globalType = nameToGlobalBoxType[name]; + if (GlobalBuiltinBoxType(globalType(this)) != nullptr) { + return GlobalBuiltinBoxType(globalType(this)); + } + + auto id = nameToTypeId.find(name); + if (id != nameToTypeId.end()) { + GetGlobalTypesHolder()->GlobalTypes()[static_cast(id->second)] = objType; + } + } + + return objType; +} + +ETSObjectType *ETSChecker::UpdateGlobalType(ETSObjectType *objType, util::StringView name) +{ + auto nameToGlobalType = GetNameToGlobalTypeMap(); + auto nameToTypeId = GetNameToTypeIdMap(); + + if (nameToGlobalType.find(name) != nameToGlobalType.end()) { + std::function globalType = nameToGlobalType[name]; + if (globalType(this) != nullptr) { + return globalType(this); + } + + auto id = nameToTypeId.find(name); + if (id != nameToTypeId.end()) { + GetGlobalTypesHolder()->GlobalTypes()[static_cast(id->second)] = objType; + } + + if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { + auto *nullish = CreateNullishType(objType, checker::TypeFlag::NULLISH, Allocator(), Relation(), + GetGlobalTypesHolder()); + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_NULLISH_OBJECT)] = nullish; + } + } + + return objType; +} + ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, 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, declNode, 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 *objType = CreateNewETSObjectType(name, declNode, flags); - - if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { - if (GlobalETSObjectType() != nullptr) { - return GlobalETSObjectType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_OBJECT_BUILTIN)] = objType; - auto *nullish = - CreateNullishType(objType, 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)] = objType; - } else if (name == compiler::Signatures::BUILTIN_ERROR_CLASS) { - if (GlobalBuiltinErrorType() != nullptr) { - return GlobalBuiltinErrorType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_ERROR_BUILTIN)] = objType; - } else if (name == compiler::Signatures::BUILTIN_TYPE_CLASS) { - if (GlobalBuiltinTypeType() != nullptr) { - return GlobalBuiltinTypeType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_TYPE_BUILTIN)] = objType; - } else if (name == compiler::Signatures::BUILTIN_PROMISE_CLASS) { - if (GlobalBuiltinPromiseType() != nullptr) { - return GlobalBuiltinPromiseType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_PROMISE_BUILTIN)] = objType; - } else if (name == compiler::Signatures::BUILTIN_BOX_CLASS) { - if (GlobalBuiltinBoxType(GlobalETSObjectType()) != nullptr) { - return GlobalBuiltinBoxType(GlobalETSObjectType()); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BOX_BUILTIN)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } 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)] = objType; - } else if (name == compiler::Signatures::BUILTIN_VOID_CLASS) { - if (GlobalBuiltinVoidType() != nullptr) { - return GlobalBuiltinVoidType(); - } - GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_VOID_BUILTIN)] = objType; + auto nameToGlobalBoxType = GetNameToGlobalBoxTypeMap(); + if (nameToGlobalBoxType.find(name) != nameToGlobalBoxType.end()) { + return UpdateBoxedGlobalType(objType, name); } - return objType; + return UpdateGlobalType(objType, name); } ETSObjectType *ETSChecker::CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags) diff --git a/ets2panda/checker/types/ets/etsBigIntType.cpp b/ets2panda/checker/types/ets/etsBigIntType.cpp new file mode 100644 index 0000000000..1c617a86e9 --- /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 *globalTypes) +{ + 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..22e196e98b --- /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 *globalTypes) 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 f84bd93eec..99fb0e6db0 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 4b3071f855..456c2b1887 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" @@ -121,11 +122,12 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) : builtinNameMap builtinNameMappings_.emplace("StackTrace", GlobalTypeId::ETS_STACK_TRACE_BUILTIN); builtinNameMappings_.emplace("NullPointerException", GlobalTypeId::ETS_NULL_POINTER_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ArrayIndexOutOfBoundsException", - GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN); + GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ArithmeticException", GlobalTypeId::ETS_ARITHMETIC_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ClassNotFoundException", GlobalTypeId::ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ClassCastException", GlobalTypeId::ETS_CLASS_CAST_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("String", GlobalTypeId::ETS_STRING_BUILTIN); + builtinNameMappings_.emplace("BigInt", GlobalTypeId::ETS_BIG_INT_BUILTIN); builtinNameMappings_.emplace("StringBuilder", GlobalTypeId::ETS_STRING_BUILDER_BUILTIN); builtinNameMappings_.emplace("Type", GlobalTypeId::ETS_TYPE_BUILTIN); builtinNameMappings_.emplace("Types", GlobalTypeId::ETS_TYPES_BUILTIN); @@ -511,6 +513,16 @@ Type *GlobalTypesHolder::GlobalETSStringBuiltinType() return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING_BUILTIN)); } +Type *GlobalTypesHolder::GlobalETSBigIntBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BIG_INT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalETSBigIntLiteralType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BIG_INT)); +} + Type *GlobalTypesHolder::GlobalStringBuilderBuiltinType() { return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING_BUILDER_BUILTIN)); diff --git a/ets2panda/checker/types/globalTypesHolder.h b/ets2panda/checker/types/globalTypesHolder.h index 32813e9a26..22c188dbf0 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 0e3b315c12..554df9ce6b 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 047346f00b..b02fd84afa 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 a3d5504886..718d8eca3b 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(binExpr, returnRightTrueLabel); } +bool Condition::CompileBinaryExprForBigInt(ETSGen *etsg, const ir::BinaryExpression *expr, Label *falseLabel) +{ + 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, falseLabel); + + return true; +} + bool Condition::CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel) { + if (CompileBinaryExprForBigInt(etsg, binExpr, falseLabel)) { + return true; + } + switch (binExpr->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 25387bc99d..48e26d2b44 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 *binExpr, Label *falseLabel); static void CompileLogicalAndExpr(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel); static void CompileLogicalOrExpr(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel); + static bool CompileBinaryExprForBigInt(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel); }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index e966b231e4..23eba24fc1 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 bigintSignatures = { + {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 bigintSignatures; +} + +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 *operationType = expr->OperationType(); + auto ttctx = compiler::TargetTypeContext(etsg, operationType); + compiler::RegScope rs(etsg); + compiler::VReg lhs = etsg->AllocReg(); + expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, operationType); + expr->Right()->Compile(etsg); + etsg->ApplyConversion(expr->Right(), operationType); + 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; } @@ -1119,7 +1193,16 @@ void ETSCompiler::Compile(const ir::UpdateExpression *expr) const lref.GetValue(); expr->Argument()->SetBoxingUnboxingFlags(argumentUnboxingFlags); etsg->ApplyConversion(expr->Argument(), nullptr); - etsg->Update(expr, expr->OperatorType()); + + if (expr->Argument()->TsType()->IsETSBigIntType()) { + compiler::RegScope rs(etsg); + compiler::VReg valueReg = etsg->AllocReg(); + etsg->StoreAccumulator(expr->Argument(), valueReg); + etsg->UpdateBigInt(expr, valueReg, expr->OperatorType()); + } else { + etsg->Update(expr, expr->OperatorType()); + } + expr->Argument()->SetBoxingUnboxingFlags(argumentBoxingFlags); etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); lref.SetValue(); @@ -1136,7 +1219,12 @@ void ETSCompiler::Compile(const ir::UpdateExpression *expr) const expr->Argument()->SetBoxingUnboxingFlags(argumentUnboxingFlags); etsg->ApplyConversion(expr->Argument(), nullptr); - etsg->Update(expr, expr->OperatorType()); + + if (expr->Argument()->TsType()->IsETSBigIntType()) { + etsg->UpdateBigInt(expr, originalValueReg, expr->OperatorType()); + } else { + etsg->Update(expr, expr->OperatorType()); + } expr->Argument()->SetBoxingUnboxingFlags(argumentBoxingFlags); etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); @@ -1152,7 +1240,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 9603461920..a00aab084c 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, dummyReg_); +} + void ETSGen::CreateLambdaObjectFromIdentReference(const ir::AstNode *node, ir::ClassDefinition *lambdaObj) { auto *ctor = lambdaObj->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 testEqual, VReg lhs 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 ec89b81fc1..248607444e 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -96,6 +96,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 *ifFalse); @@ -385,6 +386,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); @@ -548,6 +555,9 @@ public: void NewArray(const ir::AstNode *node, VReg arr, VReg dim, const checker::Type *arrType); 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) @@ -632,6 +642,7 @@ public: } #endif // PANDA_WITH_ETS + void CreateBigIntObject(const ir::AstNode *node, VReg arg0); void CreateLambdaObjectFromIdentReference(const ir::AstNode *node, ir::ClassDefinition *lambdaObj); void CreateLambdaObjectFromMemberReference(const ir::AstNode *node, ir::Expression *obj, ir::ClassDefinition *lambdaObj); @@ -658,6 +669,7 @@ private: void EmitUnboxedCall(const ir::AstNode *node, std::string_view signatureFlag, const checker::Type *targetType, const checker::Type *boxedType); + void LoadConstantObject(const ir::Expression *node, const checker::Type *type); void StringBuilderAppend(const ir::AstNode *node, VReg builder); void AppendString(const ir::Expression *binExpr, 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 1387f703be..1029fa2d80 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 savedLexerPosition = 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(savedLexerPosition); 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 7b892ff39b5c5cca05a00390cf4f9a8d7face5d7 Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Thu, 28 Dec 2023 14:01:23 +0300 Subject: [PATCH 15/27] 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/lexer/ETSLexer.h | 6 +- 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 + 8 files changed, 2083 insertions(+), 4 deletions(-) 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/lexer/ETSLexer.h b/ets2panda/lexer/ETSLexer.h index 1029fa2d80..ad4557def1 100644 --- a/ets2panda/lexer/ETSLexer.h +++ b/ets2panda/lexer/ETSLexer.h @@ -42,10 +42,10 @@ public: { const auto savedLexerPosition = Save(); - bool allow_bigint = false; + bool allowBigint = false; if (Iterator().Peek() == LEX_CHAR_LOWERCASE_N) { // 0n is the only allowed bigint literal with leading 0 - allow_bigint = true; + allowBigint = true; } try { @@ -56,7 +56,7 @@ public: } if ((GetToken().flags_ & TokenFlags::NUMBER_BIGINT) != 0) { - if (!allow_bigint) { + if (!allowBigint) { ThrowError("Invalid BigInt number"); } } diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 0c77d72807..2eb6b05d43 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -188,7 +188,9 @@ void ETSParser::ParseETSGlobalScript(lexer::SourcePosition startLoc, ArenaVector end(items)); for (const auto &item : items) { - parsedSources_.push_back(ResolveImportPath(item)); + auto resolved = ResolveImportPath(item); + resolvedParsedSources_.emplace(item, resolved); + parsedSources_.push_back(resolved); } }; // clang-format on 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 b512d990525c148b3024b8b4bd5b32d35af9aae6 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Tue, 26 Dec 2023 19:58:28 +0300 Subject: [PATCH 16/27] 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 117456dd03..4ab978b5d5 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1150,7 +1150,7 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const // NOTE(vpukhov): #14902 substituted signature is not updated } expr->SetOptionalType(returnType); - if (expr->IsOptional() && calleeType->IsNullishOrNullLike()) { + if (expr->IsOptional() && checker->MayHaveNulllikeValue(expr->Callee()->Check(checker))) { checker->Relation()->SetNode(expr); returnType = checker->CreateOptionalResultType(returnType); checker->Relation()->SetNode(nullptr); @@ -2742,6 +2742,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()) { @@ -2756,8 +2757,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 a8de220725..6989b06807 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); @@ -298,6 +299,7 @@ public: { return Allocator()->New>(Allocator()->Adapter()); } + ArenaVector CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const *typeParams); [[nodiscard]] bool EnhanceSubstitutionForType(const ArenaVector &typeParams, Type *paramType, Type *argumentType, Substitution *substitution, ArenaUnorderedSet *instantiatedTypeParams); @@ -654,8 +656,6 @@ private: return isConstruct ? &dynamicNewIntrinsics_ : &dynamicCallIntrinsics_; } - ArenaVector CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *typeParams); - 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 53122119d8..8016022e51 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -134,6 +134,11 @@ public: return uncheckedCastableResults_; } + RelationHolder &SupertypeResults() + { + return supertypeResults_; + } + std::unordered_set &TypeStack() { return typeStack_; @@ -209,6 +214,7 @@ private: RelationHolder assignableResults_; RelationHolder comparableResults_; RelationHolder uncheckedCastableResults_; + RelationHolder supertypeResults_; std::unordered_set typeStack_; }; diff --git a/ets2panda/checker/ets/conversion.cpp b/ets2panda/checker/ets/conversion.cpp index a37d8ca39c..e1ff98642e 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 3cd89c8f79..8f578c9eac 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 *typeParam, Type *typeArgument, const Substitution *substitution) { @@ -76,21 +77,8 @@ bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typ if (!typeArgument->IsETSTypeParameter() && !IsReferenceType(typeArgument)) { return false; } - if (typeArgument->IsETSUnionType()) { - auto const &constitutent = typeArgument->AsETSUnionType()->ConstituentTypes(); - return std::all_of(constitutent.begin(), constitutent.end(), [this, typeParam, substitution](Type *typeArg) { - return IsCompatibleTypeArgument(typeParam->AsETSTypeParameter(), typeArg, substitution); - }); - } - - if (auto *constraint = typeParam->GetConstraintType(); constraint != nullptr) { - constraint = constraint->Substitute(Relation(), substitution); - constraint->IsSupertypeOf(Relation(), typeArgument); - if (!Relation()->IsTrue()) { - return false; - } - } - return true; + auto *constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution); + return Relation()->IsSupertypeOf(constraint, typeArgument); } /* A very rough and imprecise partial type inference */ @@ -1052,9 +1040,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); @@ -1076,7 +1064,6 @@ bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source) if (Relation()->IsTrue()) { CheckThrowMarkers(source, target); - CheckStaticHide(target, source); if (source->HasSignatureFlag(SignatureFlags::STATIC)) { return false; } @@ -1194,7 +1181,8 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) (itSubst->Function()->IsGetter() && !signature->Function()->IsGetter())) { continue; } - } else if (!IsMethodOverridesOther(itSubst, signature)) { + } + if (!IsMethodOverridesOther(itSubst, signature)) { continue; } @@ -2595,8 +2583,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 d7c7871659..a33cc29407 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 34d5cb6d10..c82c2961cb 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 *typeParams) +ArenaVector ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const *typeParams) { ArenaVector result {Allocator()->Adapter()}; checker::ScopeContext scopeCtx(this, typeParams->Scope()); @@ -248,12 +249,14 @@ void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param) ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start()); } paramType->SetConstraintType(constraint); + } else { + paramType->SetConstraintType(GlobalETSNullishObjectType()); } + if (param->DefaultType() != nullptr) { traverseReferenced(param->DefaultType()); - auto *const dflt = param->DefaultType()->GetType(this); // NOTE: #14993 ensure default matches constraint - paramType->SetDefaultType(dflt); + paramType->SetDefaultType(MaybePromotedBuiltinType(param->DefaultType()->GetType(this))); } } @@ -264,6 +267,8 @@ ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const para paramType->AddTypeFlag(TypeFlag::GENERIC); paramType->SetDeclNode(param); paramType->SetVariable(param->Variable()); + // NOTE: #15026 recursive type parameter workaround + paramType->SetConstraintType(GlobalETSNullishObjectType()); param->Name()->Variable()->SetTsType(paramType); return paramType; @@ -1523,22 +1528,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 checkerCtx(this->Relation(), TypeRelationFlag::IGNORE_TYPE_PARAMETERS); @@ -1547,13 +1555,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; } @@ -1586,8 +1592,7 @@ ETSObjectType *ETSChecker::GetClosestCommonAncestor(ETSObjectType *source, ETSOb auto *sourceBase = GetOriginalBaseType(source); auto *sourceType = sourceBase == nullptr ? source : sourceBase; - targetType->IsSupertypeOf(Relation(), sourceType); - if (Relation()->IsTrue()) { + if (Relation()->IsSupertypeOf(targetType, sourceType)) { // NOTE: TorokG. Extending the search to find intersection types return targetType; } diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index 22f1a5f1f8..e741e69f63 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" @@ -60,12 +61,15 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType extends "Comparable", we will get an error here. */ - auto const getTypes = [this, &typeArgs, type](size_t idx) -> std::pair { + auto const isDefaulted = [typeArgs](size_t idx) { + return typeArgs == nullptr || idx >= typeArgs->Params().size(); + }; + + auto const getTypes = [this, &typeArgs, type, isDefaulted](size_t idx) -> std::pair { auto *typeParam = type->TypeArguments().at(idx)->AsETSTypeParameter(); - if (typeArgs != nullptr && idx < typeArgs->Params().size()) { - return {typeParam, typeArgs->Params().at(idx)->GetType(checker_)}; - } - return {typeParam, typeParam->GetDefaultType()}; + return {typeParam, isDefaulted(idx) + ? typeParam->GetDefaultType() + : checker_->MaybePromotedBuiltinType(typeArgs->Params().at(idx)->GetType(checker_))}; }; auto *const substitution = checker_->NewSubstitution(); @@ -87,7 +91,7 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType if (!ValidateTypeArg(constraint, typeArg) && typeArgs != nullptr && !checker_->Relation()->NoThrowGenericTypeAlias()) { checker_->ThrowTypeError({"Type '", typeArg, "' is not assignable to constraint type '", constraint, "'."}, - typeArgs->Params().at(idx)->Start()); + isDefaulted(idx) ? pos : typeArgs->Params().at(idx)->Start()); } } @@ -96,16 +100,10 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType bool InstantiationContext::ValidateTypeArg(Type *constraintType, Type *typeArg) { - if (!ETSChecker::IsReferenceType(typeArg)) { - return false; - } - - if (typeArg->IsETSUnionType()) { - auto const &constituentTypes = typeArg->AsETSUnionType()->ConstituentTypes(); - return std::all_of(constituentTypes.begin(), constituentTypes.end(), - [this, constraintType](Type *cType) { return ValidateTypeArg(constraintType, cType); }); + // NOTE: #14993 enforce ETSChecker::IsReferenceType + if (typeArg->IsWildcardType()) { + return true; } - return checker_->Relation()->IsAssignableTo(typeArg, constraintType); } diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index dc7912878e..aee6a52a3e 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 unboxFlags, @@ -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 == etsChecker->GlobalETSObjectType()) { + if (base == etsChecker->GlobalETSObjectType() || base == etsChecker->GlobalETSNullishObjectType()) { relation->Result(true); return; } @@ -654,16 +649,14 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) ETSObjectType *sourceObj = source->AsETSObjectType(); if (auto *sourceSuper = sourceObj->SuperType(); sourceSuper != nullptr) { - IsSupertypeOf(relation, sourceSuper); - if (relation->IsTrue()) { + if (relation->IsSupertypeOf(this, sourceSuper)) { return; } } if (HasObjectFlag(ETSObjectFlags::INTERFACE)) { for (auto *itf : sourceObj->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 8f5631304a..be2fca309c 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 842e4a69c2..c47ece8b30 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 *globalTypes) 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 dddd05e512..8eb91a1065 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 newEnd = std::remove_if( constituentTypes.begin(), constituentTypes.end(), [relation, checker, cmpIt, numberFound](Type *ct) { bool bothConstants = (*cmpIt)->HasTypeFlag(TypeFlag::CONSTANT) && ct->HasTypeFlag(TypeFlag::CONSTANT); - relation->Result(false); - (*cmpIt)->IsSupertypeOf(relation, ct); + relation->IsSupertypeOf((*cmpIt), ct); bool removeSubtype = ct != *cmpIt && !bothConstants && relation->IsTrue(); bool removeNumeric = numberFound && 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 &sourceCtype : source->AsETSUnionType()->ConstituentTypes()) { - if (IsSupertypeOf(relation, sourceCtype), !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 6fc427aa9c..6d5be98143 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 554df9ce6b..38f37ea0e4 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 *sourceVar) { return nullptr; diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index b02fd84afa..288ec03b9e 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 *sourceVar); virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index f3eaa9fdbd..437a22ff3c 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 &errMsg, const lexer::SourcePosition &loc) const { checker_->ThrowTypeError(errMsg, loc); diff --git a/ets2panda/checker/types/typeRelation.h b/ets2panda/checker/types/typeRelation.h index 0da58eadc0..53f1642d1b 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 &errMsg, 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 a00aab084c..f4718ce80b 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 (targetType->IsETSTypeParameter() && targetType->AsETSTypeParameter()->HasConstraint()) { + if (targetType->IsETSTypeParameter()) { CheckedReferenceNarrowing(node, targetType->AsETSTypeParameter()->GetConstraintType()); } else if (targetType->IsETSObjectType()) { CheckedReferenceNarrowing(node, targetType->AsETSObjectType()->GetConstOriginalBaseType()); diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index f307892936..f3f3e761a2 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) { uncheckedType_ = 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 e82a3a9d21..275026d757 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -34,6 +34,7 @@ public: decorators_(allocator->Adapter()), id_(id), typeParams_(typeParams), + typeParamTypes_(allocator->Adapter()), declare_(declare) { } @@ -43,6 +44,7 @@ public: decorators_(allocator->Adapter()), id_(id), typeParams_(nullptr), + typeParamTypes_(allocator->Adapter()), declare_(false) { } @@ -57,7 +59,7 @@ public: return id_; } - const TSTypeParameterDeclaration *TypeParams() const + TSTypeParameterDeclaration *TypeParams() const { return typeParams_; } @@ -77,7 +79,7 @@ public: return &Decorators(); } - void AddTypeParameters(ir::TSTypeParameterDeclaration *typeParams) + void SetTypeParameters(ir::TSTypeParameterDeclaration *typeParams) { typeParams_ = typeParams; } @@ -92,6 +94,16 @@ public: return !inTs; } + void SetTypeParameterTypes(ArenaVector &&typeParamTypes) + { + typeParamTypes_ = std::move(typeParamTypes); + } + + ArenaVector const &TypeParameterTypes() const + { + return typeParamTypes_; + } + 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 *typeParams_; + ArenaVector typeParamTypes_; bool declare_; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 2eb6b05d43..8238240ecc 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1828,7 +1828,7 @@ ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration() auto options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; ir::TSTypeParameterDeclaration *params = ParseTypeParameterDeclaration(&options); - typeAliasDecl->AddTypeParameters(params); + typeAliasDecl->SetTypeParameters(params); params->SetParent(typeAliasDecl); } 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 08ba2ba93e72c2a704b908c965e91ff1ad9940f3 Mon Sep 17 00:00:00 2001 From: zhao-xinyuan8 Date: Tue, 2 Jan 2024 01:52:02 +0000 Subject: [PATCH 17/27] 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 8238240ecc..6671014c70 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2344,7 +2344,20 @@ std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *typeAnnotation, bo } if (typeAnnotation->IsETSTypeReference()) { - return adjustNullish(typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8()); + std::string typeParamNames; + auto typeParam = typeAnnotation->AsETSTypeReference()->Part()->TypeParams(); + if (typeParam != nullptr && typeParam->IsTSTypeParameterInstantiation()) { + typeParamNames = "<"; + auto paramList = typeParam->Params(); + for (auto param : paramList) { + std::string typeParamName = GetNameForTypeNode(param); + typeParamNames += typeParamName + ","; + } + typeParamNames.pop_back(); + typeParamNames += ">"; + } + return adjustNullish(typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8() + + typeParamNames); } if (typeAnnotation->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 729436a43af089795bc53ca7b7c3edc9c1ad2d15 Mon Sep 17 00:00:00 2001 From: x30053363 Date: Wed, 3 Jan 2024 15:20:17 +0800 Subject: [PATCH 18/27] 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 6671014c70..7b2404b0b3 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -678,22 +678,6 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVector globalProperties(Allocator()->Adapter()); fieldMap_.clear(); exportNameMap_.clear(); - bool defaultExport = false; - - using ParserFunctionPtr = std::function; - auto const parseType = [this, &statements, &defaultExport](std::size_t const currentPos, - ParserFunctionPtr const &parserFunction) -> void { - ir::Statement *node = nullptr; - - node = parserFunction(this); - if (node != nullptr) { - if (currentPos != std::numeric_limits::max()) { - MarkNodeAsExported(node, node->Start(), defaultExport); - defaultExport = 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 @@ -704,6 +688,43 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVector &statements, bool &defaultExport, + std::size_t const currentPos, + std::function const &parserFunction) +{ + ir::Statement *node = nullptr; + + node = parserFunction(this); + if (node != nullptr) { + if (currentPos != std::numeric_limits::max()) { + MarkNodeAsExported(node, node->Start(), defaultExport); + defaultExport = false; + } + statements.push_back(node); + } +} + +void ETSParser::ParseTopLevelNextToken(ArenaVector &statements, + ArenaVector &globalProperties, ir::ScriptFunction *initFunction) +{ + bool defaultExport = false; + while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { Lexer()->NextToken(); @@ -744,42 +765,16 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorNextToken(); auto *memberName = ExpectIdentifier(); - ParseClassFieldDefiniton(memberName, memberModifiers, &globalProperties, initFunction, &startLoc); + ParseClassFieldDefinition(memberName, memberModifiers, &globalProperties, initFunction, &startLoc); break; } case lexer::TokenType::KEYW_ASYNC: case lexer::TokenType::KEYW_NATIVE: { - bool isAsync = tokenType == lexer::TokenType::KEYW_ASYNC; - - if (isAsync) { - memberModifiers |= ir::ModifierFlags::ASYNC; - } else { - memberModifiers |= ir::ModifierFlags::NATIVE; - } - - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { - ThrowSyntaxError( - {isAsync ? "'async'" : "'native'", " flags must be used for functions at top-level."}); - } + ParseTokenOfNative(tokenType, memberModifiers); [[fallthrough]]; } case lexer::TokenType::KEYW_FUNCTION: { - Lexer()->NextToken(); - // check whether it is an extension function - ir::Identifier *className = nullptr; - if (Lexer()->Lookahead() == lexer::LEX_CHAR_DOT) { - className = ExpectIdentifier(); - Lexer()->NextToken(); - } - - auto *memberName = ExpectIdentifier(); - auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers, className); - classMethod->SetStart(startLoc); - if (!classMethod->Function()->IsOverload()) { - globalProperties.push_back(classMethod); - } + ParseTokenOfFunction(memberModifiers, startLoc, globalProperties); break; } case lexer::TokenType::KEYW_NAMESPACE: @@ -795,18 +790,21 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorParseTypeDeclaration(false); }); + ParseTopLevelType(statements, defaultExport, currentPos, + [](ETSParser *obj) { return obj->ParseTypeDeclaration(false); }); break; } @@ -831,18 +829,42 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorNextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { + ThrowSyntaxError({isAsync ? "'async'" : "'native'", " flags must be used for functions at top-level."}); + } +} + +void ETSParser::ParseTokenOfFunction(ir::ModifierFlags memberModifiers, lexer::SourcePosition startLoc, + ArenaVector &globalProperties) +{ + Lexer()->NextToken(); + // check whether it is an extension function + ir::Identifier *className = nullptr; + if (Lexer()->Lookahead() == lexer::LEX_CHAR_DOT) { + className = ExpectIdentifier(); + Lexer()->NextToken(); + } + + auto *memberName = ExpectIdentifier(); + auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers, className); + classMethod->SetStart(startLoc); + if (!classMethod->Function()->IsOverload()) { + globalProperties.push_back(classMethod); } - return globalProperties; } // NOLINTNEXTLINE(google-default-arguments) @@ -1268,9 +1290,9 @@ ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic) } // NOLINTNEXTLINE(google-default-arguments) -void ETSParser::ParseClassFieldDefiniton(ir::Identifier *fieldName, ir::ModifierFlags modifiers, - ArenaVector *declarations, ir::ScriptFunction *initFunction, - lexer::SourcePosition *letLoc) +void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, + ArenaVector *declarations, ir::ScriptFunction *initFunction, + lexer::SourcePosition *letLoc) { lexer::SourcePosition startLoc = letLoc != nullptr ? *letLoc : Lexer()->GetToken().Start(); lexer::SourcePosition endLoc = startLoc; @@ -1294,28 +1316,7 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *fieldName, ir::Modifier // performed multiple times. if (initFunction != nullptr && (modifiers & ir::ModifierFlags::CONST) == 0U && initializer != nullptr && !initializer->IsArrowFunctionExpression()) { - if (auto *const funcBody = initFunction->Body(); funcBody != nullptr && funcBody->IsBlockStatement()) { - auto *ident = AllocNode(fieldName->Name(), Allocator()); - ident->SetReference(); - ident->SetRange(fieldName->Range()); - - auto *assignmentExpression = - AllocNode(ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - endLoc = initializer->End(); - assignmentExpression->SetRange({fieldName->Start(), endLoc}); - assignmentExpression->SetParent(funcBody); - - auto expressionStatement = AllocNode(assignmentExpression); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { - endLoc = Lexer()->GetToken().End(); - } - expressionStatement->SetRange({startLoc, endLoc}); - funcBody->AsBlockStatement()->Statements().emplace_back(expressionStatement); - - if (typeAnnotation != nullptr && !typeAnnotation->IsETSFunctionType()) { - initializer = nullptr; - } - } + endLoc = InitializeGlobalVariable(fieldName, initializer, initFunction, startLoc, typeAnnotation); } bool isDeclare = (modifiers & ir::ModifierFlags::DECLARE) != 0; @@ -1338,8 +1339,40 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *fieldName, ir::Modifier if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { Lexer()->NextToken(); ir::Identifier *nextName = ExpectIdentifier(false, true); - ParseClassFieldDefiniton(nextName, modifiers, declarations); + ParseClassFieldDefinition(nextName, modifiers, declarations); + } +} + +lexer::SourcePosition ETSParser::InitializeGlobalVariable(ir::Identifier *fieldName, ir::Expression *&initializer, + ir::ScriptFunction *initFunction, + lexer::SourcePosition &startLoc, + ir::TypeNode *typeAnnotation) +{ + lexer::SourcePosition endLoc = startLoc; + + if (auto *const funcBody = initFunction->Body(); funcBody != nullptr && funcBody->IsBlockStatement()) { + auto *ident = AllocNode(fieldName->Name(), Allocator()); + ident->SetReference(); + ident->SetRange(fieldName->Range()); + + auto *assignmentExpression = + AllocNode(ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + endLoc = initializer->End(); + assignmentExpression->SetRange({fieldName->Start(), endLoc}); + assignmentExpression->SetParent(funcBody); + + auto expressionStatement = AllocNode(assignmentExpression); + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { + endLoc = Lexer()->GetToken().End(); + } + expressionStatement->SetRange({startLoc, endLoc}); + funcBody->AsBlockStatement()->Statements().emplace_back(expressionStatement); + + if (typeAnnotation != nullptr && !typeAnnotation->IsETSFunctionType()) { + initializer = nullptr; + } } + return endLoc; } ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, @@ -1639,7 +1672,7 @@ ir::AstNode *ETSParser::ParseClassElement([[maybe_unused]] const ArenaVector fieldDeclarations(Allocator()->Adapter()); auto *placeholder = AllocNode(std::move(fieldDeclarations)); - ParseClassFieldDefiniton(memberName, memberModifiers, placeholder->BodyPtr()); + ParseClassFieldDefinition(memberName, 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) { - typeAnnotation = ParseWildcardType(options); - } else { - if (Lexer()->GetToken().IsDefinableTypeName()) { - typeAnnotation = GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options); - } else { - typeAnnotation = ParseTypeReference(options); - } - } - + typeAnnotation = ParseLiteralIdent(options); if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 && (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) { return std::make_pair(typeAnnotation, false); @@ -2850,17 +2873,7 @@ std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnota typeAnnotation = ParseUnionType(typeAnnotation); } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { - ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); - } - - Lexer()->Rewind(savedPos); - typeAnnotation = nullptr; - } else { - Lexer()->NextToken(); // eat ')' - } - + ParseRightParenthesis(options, typeAnnotation, savedPos); break; } case lexer::TokenType::PUNCTUATOR_FORMAT: { @@ -2883,6 +2896,35 @@ std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnota return std::make_pair(typeAnnotation, 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 *&typeAnnotation, + lexer::LexerPosition savedPos) +{ + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { + ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); + } + + Lexer()->Rewind(savedPos); + typeAnnotation = 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 55ae82e016..b5dfd2f02a 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -106,6 +106,13 @@ private: [[nodiscard]] std::unique_ptr InitLexer(const SourceFile &sourceFile) override; void ParsePackageDeclaration(ArenaVector &statements); ArenaVector ParseTopLevelStatements(ArenaVector &statements); + void ParseTopLevelType(ArenaVector &statements, bool &defaultExport, std::size_t currentPos, + std::function const &parserFunction); + void ParseTopLevelNextToken(ArenaVector &statements, ArenaVector &globalProperties, + ir::ScriptFunction *initFunction); + void ParseTokenOfNative(panda::es2panda::lexer::TokenType tokenType, ir::ModifierFlags &memberModifiers); + void ParseTokenOfFunction(ir::ModifierFlags memberModifiers, lexer::SourcePosition startLoc, + ArenaVector &globalProperties); #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 className) override; // NOLINTNEXTLINE(google-default-arguments) - void ParseClassFieldDefiniton(ir::Identifier *fieldName, ir::ModifierFlags modifiers, - ArenaVector *declarations, ir::ScriptFunction *initFunction = nullptr, - lexer::SourcePosition *letLoc = nullptr); + void ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, + ArenaVector *declarations, + ir::ScriptFunction *initFunction = nullptr, + lexer::SourcePosition *letLoc = nullptr); + lexer::SourcePosition InitializeGlobalVariable(ir::Identifier *fieldName, ir::Expression *&initializer, + ir::ScriptFunction *initFunction, lexer::SourcePosition &startLoc, + ir::TypeNode *typeAnnotation); 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 *&typeAnnotation, + lexer::LexerPosition savedPos); ir::TypeNode *ParseTypeAnnotation(TypeAnnotationParsingOptions *options) override; ir::TSTypeAliasDeclaration *ParseTypeAliasDeclaration() override; -- Gitee From 51d182f2d02634f23b3c8fbb72b9679d8731866d Mon Sep 17 00:00:00 2001 From: x30053363 Date: Fri, 5 Jan 2024 09:51:35 +0800 Subject: [PATCH 19/27] 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 61605f9160..7a7133a559 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 6c49d9e4e795c44d7bc7104515d0bb8915add7a0 Mon Sep 17 00:00:00 2001 From: Martin Sajti Date: Thu, 4 Jan 2024 12:59:10 +0100 Subject: [PATCH 20/27] 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 aee6a52a3e..a62da9a70c 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 1be5a6ad56..097a44fa22 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 typeAnnot : typeAnnotationList_) { + for (const auto *const typeAnnot : typeAnnotationList_) { typeAnnot->Dump(dumper); - if (typeAnnot != typeAnnotationList_.back() || spreadType_ != nullptr) { + if ((typeAnnot != typeAnnotationList_.back()) || (spreadType_ != nullptr)) { dumper->Add(", "); } } @@ -63,7 +63,7 @@ void ETSTuple::Dump(ir::SrcDumper *const dumper) const dumper->Add("..."); spreadType_->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 &containsNullOrUndefined, const checker::Type *const type) +{ + if (type->HasTypeFlag(checker::TypeFlag::NULLISH)) { + containsNullOrUndefined.first = true; + } + + if (type->HasTypeFlag(checker::TypeFlag::UNDEFINED)) { + containsNullOrUndefined.second = true; + } +} + checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker, ArenaVector &typeList, checker::Type *const spreadType) { @@ -86,11 +97,17 @@ checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker return spreadType == nullptr ? checker->GlobalETSObjectType() : spreadType; } - bool allElementsAreSame = std::all_of(typeList.begin(), typeList.end(), [&checker, &typeList](auto *element) { - return checker->Relation()->IsIdenticalTo(typeList[0], element); - }); + std::pair containsNullOrUndefined = {false, false}; + + bool allElementsAreSame = + std::all_of(typeList.begin(), typeList.end(), + [this, &checker, &typeList, &containsNullOrUndefined](checker::Type *const element) { + SetNullUndefinedFlags(containsNullOrUndefined, element); + return checker->Relation()->IsIdenticalTo(typeList[0], element); + }); if (spreadType != nullptr) { + SetNullUndefinedFlags(containsNullOrUndefined, spreadType); allElementsAreSame = allElementsAreSame && checker->Relation()->IsIdenticalTo(typeList[0], spreadType); } @@ -121,6 +138,16 @@ checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker lubType = checker->FindLeastUpperBound(lubType, getBoxedTypeOrType(spreadType)); } + const auto nullishUndefinedFlags = + (containsNullOrUndefined.first ? checker::TypeFlag::NULLISH | checker::TypeFlag::NULL_TYPE + : checker::TypeFlag::NONE) | + (containsNullOrUndefined.second ? checker::TypeFlag::UNDEFINED : checker::TypeFlag::NONE); + + if (nullishUndefinedFlags != checker::TypeFlag::NONE) { + lubType = checker->CreateNullishType(lubType, nullishUndefinedFlags, checker->Allocator(), + checker->Relation(), checker->GetGlobalTypesHolder()); + } + checker->Relation()->SetNode(savedRelationNode); return lubType; diff --git a/ets2panda/ir/ets/etsTuple.h b/ets2panda/ir/ets/etsTuple.h index 9d03e58faa..6cb0e0353d 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 &containsNullOrUndefined, const checker::Type *type); checker::Type *CalculateLUBForTuple(checker::ETSChecker *checker, ArenaVector &typeList, checker::Type *spreadType); 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 eaa3b18745396eba46cdb406a75743985224365e Mon Sep 17 00:00:00 2001 From: Anton Soldatov Date: Tue, 9 Jan 2024 15:19:49 +0800 Subject: [PATCH 21/27] 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 b5dfd2f02a..ef6979e34c 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -337,6 +337,7 @@ private: ir::Statement *CreateStatement(std::string_view sourceCode, std::string_view fileName = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view sourceCode, std::vector &insertingNodes, std::string_view fileName = DEFAULT_SOURCE_FILE); + // NOLINTEND(google-default-arguments) template ir::Statement *CreateFormattedStatement(std::string_view const sourceCode, std::string_view const fileName, @@ -354,6 +355,8 @@ private: std::string_view fileName = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view sourceCode, std::string_view fileName = DEFAULT_SOURCE_FILE); + // NOLINTEND(google-default-arguments) + friend class ExternalSourceParser; friend class InnerSourceParser; -- Gitee From c572162ebf631fd8eccbec9c21c9f279e7ced140 Mon Sep 17 00:00:00 2001 From: Orlovsky Maxim Date: Mon, 18 Dec 2023 18:05:03 +0300 Subject: [PATCH 22/27] 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 | 1085 ++++++++--------- 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 | 239 ++-- 36 files changed, 921 insertions(+), 925 deletions(-) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a33cc29407..cb5032a530 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2684,7 +2684,7 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons es2panda::CompilerOptions options; auto parser = parser::ETSParser(&program, options, parser::ParserStatus::NO_OPTS); auto *argExpr = parser.CreateExpression(implicitInstantiateArgument); - compiler::ScopesInitPhaseETS::RunExternalNode(argExpr, &program); + compiler::InitScopesPhaseETS::RunExternalNode(argExpr, &program); argExpr->SetParent(callExpr); argExpr->SetRange(ident->Range()); diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 9446c7c8a9..b3e251deee 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 (containingObjType != nullptr) { prefix = containingObjType->AssemblerName(); - } else if (declNode->GetTopStatement()->Type() != - ir::AstNodeType::BLOCK_STATEMENT) { // NOTE: should not occur, fix for TS_INTERFACE_DECLARATION + } else if (const auto *topStatement = declNode->GetTopStatement(); + topStatement->Type() != + ir::AstNodeType::ETS_SCRIPT) { // NOTE: should not occur, fix for TS_INTERFACE_DECLARATION ASSERT(declNode->IsTSInterfaceDeclaration()); assemblerName = declNode->AsTSInterfaceDeclaration()->InternalName(); } else { diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 7af3d4e186..6b7ac08848 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 hasParent = func(ast); - ast->IterateRecursively([func, &hasParent](ir::AstNode *child) { hasParent &= func(child); }); - return hasParent; - }; -} +struct ASTVerifier::ErrorContext { + explicit ErrorContext() : namedErrors_ {}, encounteredErrors_ {} {} + + void ProcessEncounteredErrors(util::StringView name) + { + for (const auto &error : encounteredErrors_) { + namedErrors_.emplace_back(CheckError {name, error}); + } + encounteredErrors_.clear(); + } + + void AddError(const std::string &message) + { + namedErrors_.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, ""); + encounteredErrors_.emplace_back(ASTVerifier::InvariantError {cause, ss.str(), loc}); + } + + ASTVerifier::Errors GetErrors() + { + return namedErrors_; + } + +private: + ASTVerifier::Errors namedErrors_; + std::vector encounteredErrors_; +}; 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 *objTypeDec return currentTopStatement == objectTopStatement || (packageNameCurrent == packageNameObject && !packageNameCurrent.Empty()); } -bool ValidateVariableAccess(const varbinder::LocalVariable *propVar, const ir::MemberExpression *ast) + +static bool ValidateVariableAccess(const varbinder::LocalVariable *propVar, const ir::MemberExpression *ast) { const auto *propVarDecl = propVar->Declaration(); if (propVarDecl == nullptr) { @@ -189,7 +221,7 @@ bool ValidateVariableAccess(const varbinder::LocalVariable *propVar, const ir::M return false; } -bool ValidateMethodAccess(const ir::MemberExpression *memberExpression, const ir::CallExpression *ast) +static bool ValidateMethodAccess(const ir::MemberExpression *memberExpression, const ir::CallExpression *ast) { auto *memberObjType = memberExpression->ObjType(); if (memberObjType == nullptr) { @@ -236,691 +268,574 @@ bool ValidateMethodAccess(const ir::MemberExpression *memberExpression, const ir 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"; + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + const auto isEtsScript = ast->IsETSScript(); + const auto hasParent = ast->Parent() != nullptr; + if (!isEtsScript && !hasParent) { + ctx.AddInvariantError("NULL_PARENT", *ast, ast->Start()); + return ASTVerifier::CheckResult::FAILED; } - case varbinder::ScopeType::MODULE: { - return "MODULE"; - } - 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()); + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + if (!ast->IsIdentifier()) { + return ASTVerifier::CheckResult::SUCCESS; } - case varbinder::ScopeType::LOCAL: { - return "LOCAL_SCOPE "; + if (ast->AsIdentifier()->Variable() != nullptr) { + return ASTVerifier::CheckResult::SUCCESS; } - case varbinder::ScopeType::CATCH: { - return "CATCH_SCOPE "; - } - 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::SKIP_SUBTREE; + } + 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 maybeVar = GetLocalScopeVariable(allocator_, ctx, ast); maybeVar.has_value()) { + const auto var = *maybeVar; + 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()); + static std::optional GetLocalScopeVariable(ArenaAllocator &allocator, + ASTVerifier::ErrorContext &ctx, + const ir::AstNode *ast) + { + if (!ast->IsIdentifier()) { + return std::nullopt; } - case ir::AstNodeType::SCRIPT_FUNCTION: { - auto const *sf = ast->AsScriptFunction(); - return "SCRIPT_FUN " + ToStringHelper(sf->Scope()) + "::" + ToStringHelper(sf->Id()); - } - 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 invariantHasVariable = IdentifierHasVariable {allocator}; + const auto variable = ast->AsIdentifier()->Variable(); + if ((invariantHasVariable(ctx, ast) == ASTVerifier::CheckResult::SUCCESS) && variable->IsLocalVariable()) { + const auto localVar = variable->AsLocalVariable(); + if (localVar->HasFlag(varbinder::VariableFlags::LOCAL)) { + return localVar; } - 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 varStart = node->Start(); + bool isOk = true; + if (scope->Bindings().count(var->Name()) == 0) { + ctx.AddInvariantError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node, varStart); + isOk = false; } - case ir::AstNodeType::TS_CLASS_IMPLEMENTS: { - return "TS_CLASS_IMPL " + ToStringHelper(ast->AsTSClassImplements()->Expr()); + const auto scopeNode = scope->Node(); + auto varNode = node; + if (!IsContainedIn(varNode, scopeNode) || scopeNode == nullptr) { + ctx.AddInvariantError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node, varStart); + isOk = false; } - default: { - return "MUST BE UNREACHABLE"; + const auto &decls = scope->Decls(); + const auto declDominate = std::count(decls.begin(), decls.end(), var->Declaration()); + if (declDominate == 0) { + ctx.AddInvariantError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node, varStart); + isOk = 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}); \ - allChecks_.insert(#Name); \ - checks_.emplace_back(NamedCheck {#Name "Recursive", RecursiveCheck(check)}); \ - allChecks_.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 isOk; } - 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 maybeVar = GetLocalScopeVariable(ast)) { + ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) + { + const auto maybeVar = VariableHasScope::GetLocalScopeVariable(allocator_, ctx, ast); + if (!maybeVar) { + return ASTVerifier::CheckResult::SUCCESS; + } const auto var = *maybeVar; 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; + } + const auto encloseScope = scope->EnclosingVariableScope(); + if (encloseScope == 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, encloseScope)) { + result = ASTVerifier::CheckResult::FAILED; + ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); } - return ScopeEncloseVariable(var); + 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 localVar = variable->AsLocalVariable(); - if (localVar->HasFlag(varbinder::VariableFlags::LOCAL)) { - return localVar; +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 isOk = true; - ast->Iterate([&](const auto node) { - if (ast != node->Parent()) { - AddError("INCORRECT_PARENT_REF: " + ToStringHelper(node), node->Start()); - isOk = false; - } - }); - return isOk; -} +private: +}; -bool ASTVerifier::VerifyScopeNode(const ir::AstNode *ast) -{ - ASSERT(ast); - const auto maybeVar = GetLocalScopeVariable(ast); - if (!maybeVar) { - return true; - } - const auto var = *maybeVar; - const auto scope = var->GetScope(); - if (scope == nullptr) { - // already checked - return false; - } - const auto encloseScope = scope->EnclosingVariableScope(); - if (encloseScope == nullptr) { - AddError("NO_ENCLOSING_VAR_SCOPE: " + ToStringHelper(ast), ast->Start()); - return false; - } - const auto node = scope->Node(); - bool isOk = true; - if (!IsContainedIn(ast, node)) { - isOk = false; - AddError("VARIABLE_NOT_ENCLOSE_SCOPE: " + ToStringHelper(ast), ast->Start()); - } - if (!IsContainedIn(scope, encloseScope)) { - isOk = false; - AddError("VARIABLE_NOT_ENCLOSE_SCOPE: " + ToStringHelper(ast), ast->Start()); - } - return isOk; -} +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 varStart = node->Start(); - bool isOk = true; - if (scope->Bindings().count(var->Name()) == 0) { - AddError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR: " + ToStringHelper(node), varStart); - isOk = false; - } - const auto scopeNode = scope->Node(); - auto varNode = node; - if (!IsContainedIn(varNode, scopeNode) || scopeNode == nullptr) { - AddError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE: " + ToStringHelper(node), varStart); - isOk = false; - } - const auto &decls = scope->Decls(); - const auto declDominate = std::count(decls.begin(), decls.end(), var->Declaration()); - if (declDominate == 0) { - AddError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL: " + ToStringHelper(node), varStart); - isOk = false; - } - return isOk; -} + 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 isCorrect = true; - ast->Iterate([&isCorrect](ir::AstNode *child) { isCorrect &= (IsNumericType(child)); }); - return isCorrect; - } - 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 hasExit = body->IsBreakStatement() || body->IsReturnStatement(); + body->IterateRecursively([&hasExit](ir::AstNode *child) { + hasExit |= child->IsBreakStatement() || child->IsReturnStatement(); + }); + if (!hasExit) { + // 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 *propVar = ast->AsMemberExpression()->PropVar(); + if (propVar != nullptr && propVar->HasFlag(varbinder::VariableFlags::PROPERTY) && + !ValidateVariableAccess(propVar, ast->AsMemberExpression())) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *ast, ast->Start()); + return ASTVerifier::CheckResult::FAILED; + } } + if (ast->IsCallExpression()) { + const auto *callExpr = ast->AsCallExpression(); + const auto *callee = callExpr->Callee(); + if (callee != nullptr && callee->IsMemberExpression()) { + const auto *calleeMember = callee->AsMemberExpression(); + const auto *propVarCallee = calleeMember->PropVar(); + if (propVarCallee != nullptr && propVarCallee->HasFlag(varbinder::VariableFlags::METHOD) && + !ValidateMethodAccess(calleeMember, 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 importedVariables {}; + if (ast->IsETSImportDeclaration()) { + const auto importDecl = 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 : importDecl) { + importedVariables.emplace(name(import)); + } + } + if (ast->IsCallExpression()) { + const auto *callExpr = ast->AsCallExpression(); + const auto *callee = callExpr->Callee(); + if (callee != nullptr && callee->IsIdentifier() && + !HandleImportExportIdentifier(importedVariables, callee->AsIdentifier(), callExpr)) { + ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee, callee->Start()); + return ASTVerifier::CheckResult::FAILED; + } + } + if (ast->IsIdentifier() && !HandleImportExportIdentifier(importedVariables, 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 hasExit = body->IsBreakStatement() || body->IsReturnStatement(); - body->IterateRecursively( - [&hasExit](ir::AstNode *child) { hasExit |= child->IsBreakStatement() || child->IsReturnStatement(); }); - if (!hasExit) { - // an infinite loop - AddError("WARNING: NULL FOR-TEST AND FOR-BODY doesn't exit: " + ToStringHelper(ast), ast->Start()); - } + bool InvariantImportExportMethod(const ASTVerifier::InvariantSet &importedVariables, + const varbinder::Variable *varCallee, const ir::AstNode *callExpr, + util::StringView name) + { + auto *signature = callExpr->AsCallExpression()->Signature(); + if (signature->Owner() == nullptr) { + // NOTE(vpukhov): Add a synthetic owner for dynamic signatures + ASSERT(callExpr->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 && varCallee->Declaration() != nullptr && + varCallee->Declaration()->Node() != nullptr && + !IsContainedIn(varCallee->Declaration()->Node(), signature->Owner()->GetDeclNode()) && + varCallee->Declaration()->Node() != signature->Owner()->GetDeclNode()) { + if (importedVariables.find(name.Mutf8()) != importedVariables.end() || + importedVariables.find("") != importedVariables.end()) { + return ValidateExport(varCallee); + } return false; } - } - return true; -} - -bool ASTVerifier::AreForLoopsCorrectInitialized(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; + return true; } - bool isForInitialized = IsForLoopCorrectInitialized(ast); - ast->IterateRecursively( - [this, &isForInitialized](ir::AstNode *child) { isForInitialized &= IsForLoopCorrectInitialized(child); }); - return isForInitialized; -} - -bool ASTVerifier::VerifyModifierAccess(const ir::AstNode *ast) -{ - if (ast == nullptr) { - return false; - } - if (ast->IsMemberExpression()) { - const auto *propVar = ast->AsMemberExpression()->PropVar(); - if (propVar == nullptr || (propVar->HasFlag(varbinder::VariableFlags::PROPERTY) && - !ValidateVariableAccess(propVar, ast->AsMemberExpression()))) { - AddError("PROPERTY_NOT_VISIBLE_HERE: " + ToStringHelper(ast), ast->Start()); - return false; - } - } - if (ast->IsCallExpression()) { - const auto *callExpr = ast->AsCallExpression(); - const auto *callee = callExpr->Callee(); - if (callee == nullptr) { - return false; - } - if (callee->IsMemberExpression()) { - const auto *calleeMember = callee->AsMemberExpression(); - const auto *propVarCallee = calleeMember->PropVar(); - if (propVarCallee == nullptr || (propVarCallee->HasFlag(varbinder::VariableFlags::METHOD) && - !ValidateMethodAccess(calleeMember, ast->AsCallExpression()))) { - AddError("PROPERTY_NOT_VISIBLE_HERE: " + ToStringHelper(callee), callee->Start()); + bool InvariantImportExportVariable(const ASTVerifier::InvariantSet &importedVariables, + 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 varParent = var->Declaration()->Node()->Parent(); + if (varParent != nullptr && !IsContainedIn(ident->Parent(), varParent) && ident->Parent() != varParent) { + if (var->GetScope() != nullptr && var->GetScope()->Parent() != nullptr && + var->GetScope()->Parent()->IsGlobalScope() && + ident->GetTopStatement() == varParent->GetTopStatement()) { + return true; + } + if (importedVariables.find(name.Mutf8()) != importedVariables.end() || + importedVariables.find("") != importedVariables.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 importDecl = 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(); + bool HandleImportExportIdentifier(ASTVerifier::InvariantSet &importedVariables, const ir::Identifier *ident, + const ir::AstNode *callExpr) + { + if (ident->IsReference()) { + const auto *var = ident->Variable(); + if (var != nullptr) { + if (var->HasFlag(varbinder::VariableFlags::METHOD) && callExpr != nullptr) { + return InvariantImportExportMethod(importedVariables, var, callExpr, ident->Name()); + } + return InvariantImportExportVariable(importedVariables, var, ident, ident->Name()); } - return specifier->AsImportDefaultSpecifier()->Local()->Name(); - }; - for (const auto import : importDecl) { - importedVariables_.emplace(name(import)); - } - } - if (ast->IsCallExpression()) { - const auto *callExpr = ast->AsCallExpression(); - const auto *callee = callExpr->Callee(); - if (callee != nullptr && callee->IsIdentifier() && - !HandleImportExportIdentifier(callee->AsIdentifier(), callExpr)) { - 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 *varCallee, const ir::AstNode *callExpr, - util::StringView name) -{ - auto *signature = callExpr->AsCallExpression()->Signature(); - if (signature->Owner() == nullptr) { - // NOTE(vpukhov): Add a synthetic owner for dynamic signatures - ASSERT(callExpr->AsCallExpression()->Callee()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)); return true; } +}; - if (signature != nullptr && varCallee->Declaration() != nullptr && varCallee->Declaration()->Node() != nullptr && - !IsContainedIn(varCallee->Declaration()->Node(), signature->Owner()->GetDeclNode()) && - varCallee->Declaration()->Node() != signature->Owner()->GetDeclNode()) { - if (importedVariables_.find(name) != importedVariables_.end() || - importedVariables_.find(util::StringView("")) != importedVariables_.end()) { - return ValidateExport(varCallee); +class ArithmeticOperationValid { +public: + explicit ArithmeticOperationValid([[maybe_unused]] ArenaAllocator &allocator) {} + + 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 varParent = var->Declaration()->Node()->Parent(); - if (varParent != nullptr && !IsContainedIn(ident->Parent(), varParent) && ident->Parent() != varParent) { - if (var->GetScope() != nullptr && var->GetScope()->Parent() != nullptr && - var->GetScope()->Parent()->IsGlobalScope() && - ident->GetTopStatement() == varParent->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 (importedVariables_.find(name) != importedVariables_.end() || - importedVariables_.find(util::StringView("")) != importedVariables_.end()) { - return ValidateExport(var); + const auto newResult = func(ctx, child); + if (newResult == ASTVerifier::CheckResult::SKIP_SUBTREE) { + return; } - return false; - } - } - return true; + result = newResult; + child->Iterate(aux); + }; + aux(ast); + return result; + }; } -bool ASTVerifier::HandleImportExportIdentifier(const ir::Identifier *ident, const ir::AstNode *callExpr) -{ - if (ident->IsReference()) { - const auto *var = ident->Variable(); - if (var != nullptr) { - if (var->HasFlag(varbinder::VariableFlags::METHOD) && callExpr != nullptr) { - return CheckImportExportMethod(var, callExpr, ident->Name()); - } - return CheckImportExportVariable(var, ident, ident->Name()); - } +// NOLINTBEGIN(cppcoreguidelines-macro-usage) +#define ADD_INVARIANT(Name) \ + { \ + auto *invariant = allocator->New(*allocator); \ + invariantsChecks_.emplace_back(Invariant {#Name, *invariant}); \ + invariantsNames_.insert(#Name); \ + invariantsChecks_.emplace_back(Invariant {#Name RECURSIVE_SUFFIX, RecursiveInvariant(*invariant)}); \ + invariantsNames_.insert(#Name RECURSIVE_SUFFIX); \ } - return true; -} +// NOLINTEND(cppcoreguidelines-macro-usage) -ASTVerifier::ASTVerifier(ArenaAllocator *allocator, bool saveErrors, util::StringView sourceCode) - : saveErrors_(saveErrors), - allocator_ {allocator}, - namedErrors_ {allocator_->Adapter()}, - encounteredErrors_ {allocator_->Adapter()}, - checks_ {allocator_->Adapter()}, - allChecks_(allocator_->Adapter()) +ASTVerifier::ASTVerifier(ArenaAllocator *allocator) : invariantsChecks_ {}, invariantsNames_ {} { - if (!sourceCode.Empty()) { - index_.emplace(sourceCode); - } - - 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, allChecks_); + auto recursiveChecks = InvariantSet {}; + std::copy_if(invariantsNames_.begin(), invariantsNames_.end(), + std::inserter(recursiveChecks, recursiveChecks.end()), + [](const std::string &s) { return s.find(RECURSIVE_SUFFIX) != s.npos; }); + return Verify(ast, recursiveChecks); } -bool ASTVerifier::Verify(const ir::AstNode *ast, const CheckSet &checkSet) +ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantSet &invariantSet) { - bool isCorrect = true; - auto checkAndReport = [&isCorrect, this](util::StringView name, const CheckFunction &check, - const ir::AstNode *node) { + ErrorContext ctx {}; + auto checkAndReport = [&ctx](util::StringView name, const InvariantCheck &invariant, const ir::AstNode *node) { if (node == nullptr) { return; } - isCorrect &= check(node); - if (!isCorrect) { - for (const auto &error : encounteredErrors_) { - namedErrors_.emplace_back(NamedError {name, error}); - } - encounteredErrors_.clear(); - } + invariant(ctx, node); + // if (result == CheckResult::Failed || result == CheckResult::SkipSubtree) { + ctx.ProcessEncounteredErrors(name); + // } }; - const auto containsChecks = std::includes(allChecks_.begin(), allChecks_.end(), checkSet.begin(), checkSet.end()); - if (!containsChecks) { - auto invalidChecks = CheckSet {allocator_->Adapter()}; - for (const auto &check : checkSet) { - if (allChecks_.find(check) == allChecks_.end()) { - invalidChecks.insert(check); + const auto containsInvariants = + std::includes(invariantsNames_.begin(), invariantsNames_.end(), invariantSet.begin(), invariantSet.end()); + + if (!containsInvariants) { + auto invalidInvariants = InvariantSet {}; + for (const auto &invariant : invariantSet) { + if (invariantsNames_.find(invariant.data()) == invariantsNames_.end()) { + invalidInvariants.insert(invariant.data()); } } - for (const auto &check : invalidChecks) { - const auto &message = check.Mutf8() + " check is not found"; - namedErrors_.emplace_back(NamedError {"Check", Error {message, lexer::SourceLocation {}}}); + for (const auto &invariant : invalidInvariants) { + ctx.AddError(std::string {"invariant was not found: "} + invariant.data()); } } - for (const auto &[name, check] : checks_) { - if (checkSet.find(name) != checkSet.end()) { - checkAndReport(name, check, ast); + for (const auto &invariantName : invariantSet) { + for (const auto &[name, invariant] : invariantsChecks_) { + if (std::string_view {invariantName} == name.Utf8()) { + checkAndReport(name, invariant, ast); + break; + } } } - return isCorrect; + + return ctx.GetErrors(); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ASTVerifier.h b/ets2panda/compiler/core/ASTVerifier.h index b92a55c897..24dc314aed 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 checkName; - Error error; + struct CheckError { + util::StringView invariantName; + InvariantError error; + + std::function DumpJSON() const + { + return [&](JsonObjectBuilder &body) { + body.AddProperty("invariant", invariantName.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 checkName; - CheckFunction check; + using Errors = std::vector; + + enum class CheckResult { FAILED, SUCCESS, SKIP_SUBTREE }; + struct ErrorContext; + using InvariantCheck = std::function; + struct Invariant { + util::StringView invariantName; + InvariantCheck invariant; }; - using Checks = ArenaVector; + using Invariants = std::vector; NO_COPY_SEMANTIC(ASTVerifier); NO_MOVE_SEMANTIC(ASTVerifier); - explicit ASTVerifier(ArenaAllocator *allocator, bool saveErrors = true, util::StringView sourceCode = ""); + 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 &checkSet); + Errors Verify(const ir::AstNode *ast, const InvariantSet &invariantSet); + +private: + Invariants invariantsChecks_; + InvariantSet invariantsNames_; +}; - Errors GetErrors() const +class ASTVerifierContext final { +public: + ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} + + void IntroduceNewInvariants(util::StringView phaseName) { - return namedErrors_; + auto invariantSet = [phaseName]() -> std::optional { + (void)phaseName; + if (phaseName == "ScopesInitPhase") { + return {{ + "NodeHasParentForAll", + "IdentifierHasVariableForAll", + "ModifierAccessValidForAll", + "ImportExportAccessValid", + }}; + } else if (phaseName == "PromiseVoidInferencePhase") { + return {{}}; + } else if (phaseName == "StructLowering") { + return {{}}; + } else if (phaseName == "CheckerPhase") { + return {{ + "NodeHasTypeForAll", + "ArithmeticOperationValidForAll", + "SequenceExpressionHasLastTypeForAll", + "EveryChildHasValidParentForAll", + "ForLoopCorrectlyInitializedForAll", + "VariableHasScopeForAll", + "VariableHasEnclosingScopeForAll", + }}; + } else if (phaseName == "GenerateTsDeclarationsPhase") { + return {{}}; + } else if (phaseName == "InterfacePropertyDeclarationsPhase") { + return {{}}; + } else if (phaseName == "LambdaConstructionPhase") { + return {{}}; + } else if (phaseName == "ObjectIndexLowering") { + return {{}}; + } else if (phaseName == "OpAssignmentLowering") { + return {{}}; + } else if (phaseName == "PromiseVoidInferencePhase") { + return {{}}; + } else if (phaseName == "TupleLowering") { + return {{}}; + } else if (phaseName == "UnionLowering") { + return {{}}; + } else if (phaseName == "ExpandBracketsPhase") { + return {{}}; + } else if (phaseName.Utf8().find("plugins") != std::string_view::npos) { + return {{}}; + } + return std::nullopt; + }(); + + ASSERT_PRINT(invariantSet.has_value(), + std::string {"Invariant set does not contain value for "} + phaseName.Mutf8()); + const auto &s = *invariantSet; + accumulatedChecks_.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 *callExpr = nullptr); - bool CheckImportExportVariable(const varbinder::Variable *var, const ir::Identifier *ident, util::StringView name); - bool CheckImportExportMethod(const varbinder::Variable *varCallee, const ir::AstNode *callExpr, - util::StringView name); - - void AddError(const std::string &message, const lexer::SourcePosition &from) + bool Verify(const ir::AstNode *ast, util::StringView phaseName, util::StringView sourceName) { - if (saveErrors_) { - const auto loc = index_.has_value() ? index_->GetLocation(from) : lexer::SourceLocation {}; - encounteredErrors_.emplace_back(Error {message, loc}); + errors_ = verifier_.Verify(ast, accumulatedChecks_); + for (const auto &e : errors_) { + errorArray_.Add([e, sourceName, phaseName](JsonObjectBuilder &err) { + err.AddProperty("from", sourceName.Utf8()); + err.AddProperty("phase", phaseName.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(errorArray_).Build(); + } private: - std::optional index_; - - bool saveErrors_; - ArenaAllocator *allocator_; - Errors namedErrors_; - ArenaVector encounteredErrors_; - Checks checks_; - CheckSet allChecks_; - std::unordered_set importedVariables_; + ASTVerifier &verifier_; + ASTVerifier::Errors errors_; + JsonArrayBuilder errorArray_; + ASTVerifier::InvariantSet accumulatedChecks_ {}; }; -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 3ecab6a0b2..6e17ccc7ca 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 verificationCtx = ASTVerifierContext {verifier}; + public_lib::Context publicContext; SetupPublicContext(&publicContext, &unit.input, &allocator, compilerImpl->Queue(), &compilerImpl->Plugins(), &parser, &context); @@ -142,7 +146,34 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase if (!phase->Apply(&publicContext, &program)) { return nullptr; } +#ifndef NDEBUG + using NamedProgram = std::tuple; + ArenaVector toCheck {program.Allocator()->Adapter()}; + toCheck.push_back(std::make_tuple(program.SourceFilePath(), &program)); + for (const auto &externalSource : program.ExternalSources()) { + for (const auto *external : externalSource.second) { + toCheck.push_back(std::make_tuple(external->SourceFilePath(), external)); + } + } + for (const auto &it : toCheck) { + const auto &sourceName = std::get<0>(it); + const auto &linkedProgram = std::get<1>(it); + verificationCtx.Verify(linkedProgram->Ast(), phase->Name(), sourceName); + verificationCtx.IntroduceNewInvariants(phase->Name()); + } +#endif + } + +#ifndef NDEBUG + + if (auto errors = verificationCtx.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 d807337a65..4b0fdd14d3 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 f36e6ea376..d4991c1646 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, exprType, ident->Clone(allocator), newExpression); sequenceExpr->SetParent(newExpression->Parent()); - ScopesInitPhaseETS::RunExternalNode(sequenceExpr, ctx->compilerContext->VarBinder()); + InitScopesPhaseETS::RunExternalNode(sequenceExpr, ctx->compilerContext->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(sequenceExpr, scope); sequenceExpr->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 ef7fb21ec2..9bf8336ea6 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 e84d17cd12..9c7779af86 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 isSetter) { 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 dc9ed7d0ac..f573c8d678 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 085150e5c4..95fbc98ad5 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 *assignmentExpression) const { diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.h b/ets2panda/compiler/lowering/ets/objectIndexAccess.h index 13513caa7c..8ea0758349 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 e15cc8fda6..b3c20d4855 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, exprType); loweringResult->SetParent(assignment->Parent()); - ScopesInitPhaseETS::RunExternalNode(loweringResult, ctx->compilerContext->VarBinder()); + InitScopesPhaseETS::RunExternalNode(loweringResult, ctx->compilerContext->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, scope); loweringResult->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 53aec6ca70..aed5157435 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; @@ -128,7 +122,16 @@ static bool CheckForPromiseVoid(const ir::TypeNode *type) return isTypePromise && isParamVoid; } -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(); @@ -181,7 +184,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 26f51c28e7..6569eb607a 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 *etsStrucDeclaration) { 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 a5f3987e52..b0be6f7632 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 c05f6f1a70..da18c59eb7 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 873dfdcb92..3d293a22a8 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 g_interfacePropDeclPhase; static GenerateTsDeclarationsPhase g_generateTsDeclarationsPhase; -static LambdaLowering g_lambdaLowering; +static LambdaConstructionPhase g_lambdaConstructionPhase; static OpAssignmentLowering g_opAssignmentLowering; static ObjectIndexLowering g_objectIndexLowering; static TupleLowering g_tupleLowering; // Can be only applied after checking phase, and OP_ASSIGNMENT_LOWERING phase static UnionLowering g_unionLowering; static ExpandBracketsPhase g_expandBracketsPhase; -static PromiseVoidLowering g_promiseVoidLowering; +static PromiseVoidInferencePhase g_promiseVoidInferencePhase; static StructLowering g_structLowering; static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; +static InitScopesPhaseETS g_initScopesPhaseEts; +static InitScopesPhaseAS g_initScopesPhaseAs; +static InitScopesPhaseTs g_initScopesPhaseTs; +static InitScopesPhaseJs g_initScopesPhaseJs; -// clang-format off std::vector GetETSPhaseList() { - static ScopesInitPhaseETS scopesPhaseEts; return { - &scopesPhaseEts, &g_pluginsAfterParse, - &g_promiseVoidLowering, + &g_initScopesPhaseEts, + &g_promiseVoidInferencePhase, &g_structLowering, - &g_lambdaLowering, + &g_lambdaConstructionPhase, &g_interfacePropDeclPhase, &g_checkerPhase, &g_pluginsAfterCheck, @@ -81,31 +84,27 @@ std::vector GetETSPhaseList() &g_pluginsAfterLowerings, }; } -// clang-format on std::vector GetASPhaseList() { - static ScopesInitPhaseAS scopesPhaseAs; return { - &scopesPhaseAs, + &g_initScopesPhaseAs, &g_checkerPhase, }; } std::vector GetTSPhaseList() { - static ScopesInitPhaseTs scopesPhaseTs; return { - &scopesPhaseTs, + &g_initScopesPhaseTs, &g_checkerPhase, }; } std::vector GetJSPhaseList() { - static ScopesInitPhaseJs scopesPhaseJs; return { - &scopesPhaseJs, + &g_initScopesPhaseJs, &g_checkerPhase, }; } @@ -128,25 +127,6 @@ std::vector GetPhaseList(ScriptExtension ext) bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) { -#ifndef NDEBUG - const auto checkProgram = [](const parser::Program *p) { - ASTVerifier verifier {p->Allocator(), false, p->SourceCode()}; - ArenaVector toCheck {p->Allocator()->Adapter()}; - toCheck.push_back(p->Ast()); - for (const auto &externalSource : p->ExternalSources()) { - for (const auto external : externalSource.second) { - toCheck.push_back(external->Ast()); - } - } - for (const auto *ast : toCheck) { - if (!verifier.VerifyFull(ast)) { - return false; - } - } - return true; - }; -#endif - const auto *options = ctx->compilerContext->Options(); const auto name = std::string {Name()}; if (options->skipPhases.count(name) > 0) { @@ -169,8 +149,6 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) CheckOptionsAfterPhase(options, program, name); #ifndef NDEBUG - checkProgram(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 58c56a2d70..042c291181 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 83e5b72381..d7d43bcd67 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -562,31 +562,31 @@ void ScopeInitTyped::VisitClassDefinition(ir::ClassDefinition *classDef) IterateNoTParams(classDef); } -void ScopesInitPhaseTs::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl) +void InitScopesPhaseTs::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl) { ExportDeclarationContext exportDeclCtx(VarBinder()); Iterate(exportDecl); } -void ScopesInitPhaseTs::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) +void InitScopesPhaseTs::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) { ExportDeclarationContext exportDeclCtx(VarBinder()); Iterate(exportDecl); } -void ScopesInitPhaseTs::VisitImportDeclaration(ir::ImportDeclaration *importDeclaration) +void InitScopesPhaseTs::VisitImportDeclaration(ir::ImportDeclaration *importDeclaration) { ImportDeclarationContext importCtx(VarBinder()); Iterate(importDeclaration); } -void ScopesInitPhaseTs::VisitTSFunctionType(ir::TSFunctionType *constrType) +void InitScopesPhaseTs::VisitTSFunctionType(ir::TSFunctionType *constrType) { auto lexicalScope = HandleFunctionSig(constrType->TypeParams(), constrType->Params(), constrType->ReturnType()); BindScopeNode(lexicalScope, constrType); } -void ScopesInitPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) +void InitScopesPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) { const auto identNode = func->Id(); const auto startLoc = identNode->Start(); @@ -609,46 +609,46 @@ void ScopesInitPhaseTs::CreateFuncDecl(ir::ScriptFunction *func) decl->Add(func); } -void ScopesInitPhaseTs::VisitTSConstructorType(ir::TSConstructorType *constrT) +void InitScopesPhaseTs::VisitTSConstructorType(ir::TSConstructorType *constrT) { auto funcParamScope = HandleFunctionSig(constrT->TypeParams(), constrT->Params(), constrT->ReturnType()); BindScopeNode(funcParamScope, constrT); } -void ScopesInitPhaseTs::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowFExpr) +void InitScopesPhaseTs::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowFExpr) { auto typeParamsCtx = varbinder::LexicalScope(VarBinder()); Iterate(arrowFExpr); } -void ScopesInitPhaseTs::VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *signDecl) +void InitScopesPhaseTs::VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *signDecl) { auto funcParamScope = HandleFunctionSig(signDecl->TypeParams(), signDecl->Params(), signDecl->ReturnTypeAnnotation()); BindScopeNode(funcParamScope, signDecl); } -void ScopesInitPhaseTs::VisitTSMethodSignature(ir::TSMethodSignature *methodSign) +void InitScopesPhaseTs::VisitTSMethodSignature(ir::TSMethodSignature *methodSign) { auto funcParamScope = HandleFunctionSig(methodSign->TypeParams(), methodSign->Params(), methodSign->ReturnTypeAnnotation()); BindScopeNode(funcParamScope, methodSign); } -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 scopesPhase = ScopesInitPhaseETS(); + auto scopesPhase = InitScopesPhaseETS(); scopesPhase.SetProgram(ctx); scopesPhase.CallNode(node); } -bool ScopesInitPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) +bool InitScopesPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) { Prepare(ctx, program); @@ -662,7 +662,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)_; @@ -678,7 +678,7 @@ void ScopesInitPhaseETS::HandleProgram(parser::Program *program) BindScopeNode(prog->VarBinder()->GetScope(), prog->Ast()); prog->VarBinder()->ResetTopScope(globalScope); if (mainProg->Ast() != nullptr) { - ScopesInitPhaseETS().Perform(Context(), prog); + InitScopesPhaseETS().Perform(Context(), prog); } } program->VarBinder()->ResetTopScope(savedTopScope); @@ -688,7 +688,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); @@ -697,7 +697,7 @@ void ScopesInitPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *in decl->BindNode(init); } -void ScopesInitPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) +void InitScopesPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) { const auto func = staticBlock->Function(); @@ -724,7 +724,7 @@ void ScopesInitPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock func->Id()->SetVariable(var); } -void ScopesInitPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec) +void InitScopesPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec) { if (importSpec->Local()->Name().Empty()) { return; @@ -734,7 +734,7 @@ void ScopesInitPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecif Iterate(importSpec); } -void ScopesInitPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) +void InitScopesPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) { const auto methodName = method->Id(); @@ -794,7 +794,7 @@ void ScopesInitPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) } } -void ScopesInitPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression *paramExpr) +void InitScopesPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression *paramExpr) { auto *const var = std::get<1>(VarBinder()->AddParamDecl(paramExpr)); paramExpr->Ident()->SetVariable(var); @@ -802,7 +802,7 @@ void ScopesInitPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression Iterate(paramExpr); } -void ScopesInitPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl) +void InitScopesPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl) { ImportDeclarationContext importCtx(VarBinder()); if (importDecl->Language().IsDynamic()) { @@ -811,7 +811,7 @@ void ScopesInitPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *imp Iterate(importDecl); } -void ScopesInitPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) +void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) { auto ident = enumMember->Key()->AsIdentifier(); auto [decl, var] = VarBinder()->NewVarDecl(ident->Start(), ident->Name()); @@ -822,7 +822,7 @@ void ScopesInitPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) Iterate(enumMember); } -void ScopesInitPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) +void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) { auto *curScope = VarBinder()->GetScope(); const auto methodName = method->Id(); @@ -834,7 +834,7 @@ void ScopesInitPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) DeclareClassMethod(method); } -void ScopesInitPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *funcType) +void InitScopesPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *funcType) { auto typeParamsCtx = varbinder::LexicalScope(VarBinder()); varbinder::LexicalScope lexicalScope(VarBinder()); @@ -843,7 +843,7 @@ void ScopesInitPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *funcType) Iterate(funcType); } -void ScopesInitPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr) +void InitScopesPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr) { CallNode(newClassExpr->GetArguments()); CallNode(newClassExpr->GetTypeRef()); @@ -865,7 +865,7 @@ void ScopesInitPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInsta } } -void ScopesInitPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *typeParam) +void InitScopesPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *typeParam) { auto [decl, var] = VarBinder()->NewVarDecl(typeParam->Name()->Start(), typeParam->Name()->Name()); @@ -875,7 +875,7 @@ void ScopesInitPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *typeParam) decl->BindNode(typeParam); } -void ScopesInitPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl) +void InitScopesPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl) { { auto typeParamsCtx = varbinder::LexicalScope(VarBinder()); @@ -891,7 +891,7 @@ void ScopesInitPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration decl->AsInterfaceDecl()->Add(interfaceDecl); } -void ScopesInitPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl) +void InitScopesPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl) { { const auto enumCtx = varbinder::LexicalScope(VarBinder()); @@ -904,14 +904,14 @@ void ScopesInitPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl) decl->BindScope(enumDecl->Scope()); } -void ScopesInitPhaseETS::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAlias) +void InitScopesPhaseETS::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAlias) { VarBinder()->AddDecl(typeAlias->Id()->Start(), typeAlias->Id()->Name(), typeAlias); auto typeParamsCtx = varbinder::LexicalScope(VarBinder()); Iterate(typeAlias); } -void ScopesInitPhaseETS::AddGlobalToBinder(parser::Program *program) +void InitScopesPhaseETS::AddGlobalToBinder(parser::Program *program) { auto globalId = program->GlobalClass()->Ident(); @@ -926,7 +926,7 @@ void ScopesInitPhaseETS::AddGlobalToBinder(parser::Program *program) globalId->SetVariable(var); } -void ScopesInitPhaseETS::HandleETSScript(ir::BlockStatement *script) +void InitScopesPhaseETS::HandleETSScript(ir::BlockStatement *script) { for (auto decl : script->Statements()) { if (decl->IsETSImportDeclaration()) { @@ -944,7 +944,7 @@ void ScopesInitPhaseETS::HandleETSScript(ir::BlockStatement *script) } } -void ScopesInitPhaseETS::VisitClassDefinition(ir::ClassDefinition *classDef) +void InitScopesPhaseETS::VisitClassDefinition(ir::ClassDefinition *classDef) { if (classDef->IsGlobal()) { ParseGlobalClass(classDef); @@ -960,13 +960,13 @@ void ScopesInitPhaseETS::VisitClassDefinition(ir::ClassDefinition *classDef) BindScopeNode(classScope, classDef); } -void ScopesInitPhaseETS::VisitTSInterfaceBody(ir::TSInterfaceBody *interfBody) +void InitScopesPhaseETS::VisitTSInterfaceBody(ir::TSInterfaceBody *interfBody) { Iterate(interfBody); FilterInterfaceOverloads(interfBody->Body()); } -void ScopesInitPhaseETS::FilterInterfaceOverloads(ArenaVector &props) +void InitScopesPhaseETS::FilterInterfaceOverloads(ArenaVector &props) { auto condition = [](ir::AstNode *prop) { if (prop->IsMethodDefinition()) { @@ -978,7 +978,7 @@ void ScopesInitPhaseETS::FilterInterfaceOverloads(ArenaVector &props) +void InitScopesPhaseETS::FilterOverloads(ArenaVector &props) { auto condition = [](ir::AstNode *prop) { if (prop->IsMethodDefinition()) { @@ -990,7 +990,7 @@ void ScopesInitPhaseETS::FilterOverloads(ArenaVector &prop props.erase(std::remove_if(props.begin(), props.end(), condition), props.end()); } -void ScopesInitPhaseETS::VisitClassProperty(ir::ClassProperty *classProp) +void InitScopesPhaseETS::VisitClassProperty(ir::ClassProperty *classProp) { auto curScope = VarBinder()->GetScope(); if (classProp->IsClassStaticBlock()) { @@ -1022,7 +1022,7 @@ void ScopesInitPhaseETS::VisitClassProperty(ir::ClassProperty *classProp) Iterate(classProp); } -void ScopesInitPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) +void InitScopesPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) { for (auto decl : global->Body()) { if (decl->IsDefaultExported()) { @@ -1036,7 +1036,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 isBuiltin = false; @@ -1080,12 +1080,12 @@ void ScopesInitPhaseETS::AddGlobalDeclaration(ir::AstNode *node) } } -void ScopesInitPhaseAS::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr) +void InitScopesPhaseAS::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr) { Iterate(arrowExpr); } -void ScopesInitPhaseAS::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) +void InitScopesPhaseAS::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) { ExportDeclarationContext exportDeclCtx(VarBinder()); Iterate(exportDecl); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h index 2338b5d7c9..a3edef3a2d 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 *classDef) 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 *arrowExpr) override; diff --git a/ets2panda/ir/ets/etsScript.h b/ets2panda/ir/ets/etsScript.h index 60505c6d5c..652d2e9d27 100644 --- a/ets2panda/ir/ets/etsScript.h +++ b/ets2panda/ir/ets/etsScript.h @@ -29,6 +29,7 @@ public: explicit ETSScript(ArenaAllocator *allocator, ArenaVector &&statementList, parser::Program *program) : BlockStatement(allocator, std::move(statementList)), program_(program) { + type_ = AstNodeType::ETS_SCRIPT; } parser::Program *Program() diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 7a7133a559..048c7cd93f 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 scopesInit; + compiler::InitScopesPhaseETS scopesInit; scopesInit.Perform(ctx, ctx->parserProgram); do { if (ctx->currentPhase >= ctx->phases.size()) { diff --git a/ets2panda/test/unit/lowerings/scopes_initialization.cpp b/ets2panda/test/unit/lowerings/scopes_initialization.cpp index acdd11dc9f..dc0849d9c2 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 forNode = NodeGen().CreateForUpdate(); - compiler::ScopesInitPhaseETS::RunExternalNode(forNode, &varbinder); + compiler::InitScopesPhaseETS::RunExternalNode(forNode, &varbinder); auto blockScope = forNode->Body()->AsBlockStatement()->Scope(); auto loopScope = forNode->Scope(); @@ -111,7 +111,7 @@ TEST_F(ScopesInitPhaseTest, CreateWhile) auto varbinder = varbinder::VarBinder(Allocator()); auto whileNode = NodeGen().CreateWhile(); - compiler::ScopesInitPhaseETS::RunExternalNode(whileNode, &varbinder); + compiler::InitScopesPhaseETS::RunExternalNode(whileNode, &varbinder); auto whileScope = whileNode->Scope(); auto bodyScope = whileNode->Body()->AsBlockStatement()->Scope(); @@ -124,4 +124,4 @@ TEST_F(ScopesInitPhaseTest, CreateWhile) ASSERT_EQ(bodyBindings.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 add3b8abdf..25c649cfaf 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 CompareMinified(std::string_view actualJson, std::string_view expectedJson) +{ + std::string message {actualJson}; + 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(), expectedJson); +} + TEST_F(ASTVerifierTest, NullParent) { - panda::es2panda::compiler::ASTVerifier verifier {Allocator()}; + compiler::ASTVerifier verifier {Allocator()}; panda::es2panda::ir::StringLiteral emptyNode; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasParent"); - bool hasParent = verifier.Verify(&emptyNode, 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 hasParent = errors.size() == 0; ASSERT_EQ(hasParent, 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 messageExpected = 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 emptyNode; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasType"); - bool hasType = verifier.Verify(&emptyNode, 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 hasType = errors.size() == 0; ASSERT_EQ(hasType, 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 messageExpected = 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 emptyNode; - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("HasScope"); - bool hasScope = verifier.Verify(&emptyNode, checks); - const auto &errors = verifier.GetErrors(); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasScope"); + const auto &errors = verifier.Verify(&empty_node, checks); - ASSERT_EQ(hasScope, 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 parentScope(Allocator(), nullptr); - scope.SetParent(&parentScope); - scope.AddDecl(Allocator(), &decl, panda::es2panda::ScriptExtension::ETS); + varbinder::LocalScope scope(Allocator(), nullptr); + varbinder::FunctionScope parent_scope(Allocator(), nullptr); + scope.SetParent(&parent_scope); + 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 isOk = verifier.Verify(&ident, checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasScope"); + const auto &errors = verifier.Verify(&ident, checks); - ASSERT_EQ(isOk, 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 parentScope(Allocator(), nullptr); - scope.SetParent(&parentScope); - scope.AddDecl(Allocator(), &decl, panda::es2panda::ScriptExtension::ETS); + varbinder::LocalScope scope(Allocator(), nullptr); + varbinder::FunctionScope parent_scope(Allocator(), nullptr); + scope.SetParent(&parent_scope); + scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); parentScope.BindNode(&ident); local.SetScope(&scope); - auto checks = panda::es2panda::compiler::ASTVerifier::CheckSet {Allocator()->Adapter()}; - checks.insert("VerifyScopeNode"); - bool isOk = verifier.Verify(&ident, checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("VariableHasEnclosingScope"); + const auto &errors = verifier.Verify(&ident, checks); - ASSERT_EQ(isOk, 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 arithmeticExpression = - 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 arithmeticExpression = 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 isCorrect = verifier.Verify(arithmeticExpression.AsBinaryExpression(), checks); - ASSERT_EQ(isCorrect, 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 arithmeticExpression = - 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 arithmeticExpression = 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 isCorrect = verifier.Verify(arithmeticExpression.AsBinaryExpression(), checks); - ASSERT_EQ(isCorrect, 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 leftParam("1"); constexpr uint32_t RIGHT_PARAM = 1; - auto left = panda::es2panda::ir::StringLiteral(leftParam); - auto right = panda::es2panda::ir::NumberLiteral(panda::es2panda::lexer::Number {RIGHT_PARAM}); - auto arithmeticExpression = - 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 arithmeticExpression = 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 isCorrect = verifier.Verify(arithmeticExpression.AsBinaryExpression(), checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(isCorrect, 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 arithmeticExpression = - 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 arithmeticExpression = 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 isCorrect = verifier.Verify(arithmeticExpression.AsBinaryExpression(), checks); + auto checks = compiler::ASTVerifier::InvariantSet {}; + checks.insert("ArithmeticOperationValid"); + const auto &errors = verifier.Verify(arithmetic_expression.AsBinaryExpression(), checks); - ASSERT_EQ(isCorrect, 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 *sequenceExpression = + 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 3a34bf69e7c818e2276807c7e3b4a051ec6065ec Mon Sep 17 00:00:00 2001 From: Tatiana Date: Sat, 30 Dec 2023 23:06:31 +0300 Subject: [PATCH 23/27] 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 | 202 ++---- ets2panda/compiler/core/ASTVerifier.h | 175 +++-- 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 | 636 +++++++++--------- ets2panda/util/options.cpp | 14 +- 21 files changed, 583 insertions(+), 565 deletions(-) diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 6b7ac08848..5c526ff323 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() : namedErrors_ {}, encounteredErrors_ {} {} - - void ProcessEncounteredErrors(util::StringView name) - { - for (const auto &error : encounteredErrors_) { - namedErrors_.emplace_back(CheckError {name, error}); - } - encounteredErrors_.clear(); - } - - void AddError(const std::string &message) - { - namedErrors_.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, ""); - encounteredErrors_.emplace_back(ASTVerifier::InvariantError {cause, ss.str(), loc}); - } - - ASTVerifier::Errors GetErrors() - { - return namedErrors_; - } - -private: - ASTVerifier::Errors namedErrors_; - std::vector encounteredErrors_; -}; - static bool IsNumericType(const ir::AstNode *ast) { if (ast == nullptr) { @@ -277,7 +222,7 @@ public: const auto isEtsScript = ast->IsETSScript(); const auto hasParent = ast->Parent() != nullptr; if (!isEtsScript && !hasParent) { - ctx.AddInvariantError("NULL_PARENT", *ast, ast->Start()); + ctx.AddInvariantError("NodeHasParent", "NULL_PARENT", *ast); return ASTVerifier::CheckResult::FAILED; } if (ast->IsProgram()) { @@ -301,7 +246,7 @@ public: } const auto *id = ast->AsIdentifier(); - ctx.AddInvariantError("NULL_VARIABLE", *id, id->Start()); + ctx.AddInvariantError("IdentifierHasVariable", "NULL_VARIABLE", *id); return ASTVerifier::CheckResult::FAILED; } @@ -320,7 +265,7 @@ public: } const auto *typed = static_cast(ast); if (typed->TsType() == nullptr) { - ctx.AddInvariantError("NULL_TS_TYPE", *ast, ast->Start()); + ctx.AddInvariantError("NodeHasType", "NULL_TS_TYPE", *ast); return ASTVerifier::CheckResult::FAILED; } } @@ -345,11 +290,11 @@ public: const auto var = *maybeVar; const auto scope = var->GetScope(); if (scope == nullptr) { - ctx.AddInvariantError("NULL_SCOPE_LOCAL_VAR", *ast, ast->Start()); + 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; } @@ -385,22 +330,22 @@ public: if (node == nullptr) { return true; } - const auto varStart = node->Start(); + const auto name = "VariableHasScope"; bool isOk = true; if (scope->Bindings().count(var->Name()) == 0) { - ctx.AddInvariantError("SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node, varStart); + ctx.AddInvariantError(name, "SCOPE_DO_NOT_ENCLOSE_LOCAL_VAR", *node); isOk = false; } const auto scopeNode = scope->Node(); auto varNode = node; if (!IsContainedIn(varNode, scopeNode) || scopeNode == nullptr) { - ctx.AddInvariantError("SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node, varStart); + ctx.AddInvariantError(name, "SCOPE_NODE_DONT_DOMINATE_VAR_NODE", *node); isOk = false; } const auto &decls = scope->Decls(); const auto declDominate = std::count(decls.begin(), decls.end(), var->Declaration()); if (declDominate == 0) { - ctx.AddInvariantError("SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node, varStart); + ctx.AddInvariantError(name, "SCOPE_DECL_DONT_DOMINATE_VAR_DECL", *node); isOk = false; } return isOk; @@ -422,7 +367,7 @@ public: } ast->Iterate([&](const ir::AstNode *node) { if (ast != node->Parent()) { - ctx.AddInvariantError("INCORRECT_PARENT_REF", *node, node->Start()); + ctx.AddInvariantError("EveryChildHasValidParent", "INCORRECT_PARENT_REF", *node); result = ASTVerifier::CheckResult::FAILED; } }); @@ -444,24 +389,25 @@ public: } const auto var = *maybeVar; const auto scope = var->GetScope(); + const auto name = "VariableHasEnclosingScope"; if (scope == nullptr) { // already checked return ASTVerifier::CheckResult::SUCCESS; } const auto encloseScope = scope->EnclosingVariableScope(); if (encloseScope == nullptr) { - ctx.AddInvariantError("NO_ENCLOSING_VAR_SCOPE", *ast, ast->Start()); + ctx.AddInvariantError(name, "NO_ENCLOSING_VAR_SCOPE", *ast); 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()); + ctx.AddInvariantError(name, "VARIABLE_NOT_ENCLOSE_SCOPE", *ast); } if (!IsContainedIn(scope, encloseScope)) { result = ASTVerifier::CheckResult::FAILED; - ctx.AddInvariantError("VARIABLE_NOT_ENCLOSE_SCOPE", *ast, ast->Start()); + ctx.AddInvariantError(name, "VARIABLE_NOT_ENCLOSE_SCOPE", *ast); } return result; } @@ -481,17 +427,17 @@ public: } 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()); + 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()); + 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()); + ctx.AddInvariantError(name, "Sequence expression type and last expression type are not the same", *expr); return ASTVerifier::CheckResult::FAILED; } return ASTVerifier::CheckResult::SUCCESS; @@ -506,15 +452,16 @@ 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()); + 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()); + ctx.AddInvariantError(name, "INCORRECT FOR-IN-LEFT", *ast); return ASTVerifier::CheckResult::FAILED; } } @@ -522,12 +469,12 @@ public: if (ast->IsForOfStatement()) { auto const *left = ast->AsForOfStatement()->Left(); if (left == nullptr) { - ctx.AddInvariantError("NULL FOR-OF-LEFT", *ast, ast->Start()); + 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()); + ctx.AddInvariantError(name, "INCORRECT FOR-OF-LEFT", *ast); return ASTVerifier::CheckResult::FAILED; } } @@ -539,7 +486,7 @@ public: if (test == nullptr) { auto const *body = ast->AsForUpdateStatement()->Body(); if (body == nullptr) { - ctx.AddInvariantError("NULL FOR-TEST AND FOR-BODY", *ast, ast->Start()); + ctx.AddInvariantError(name, "NULL FOR-TEST AND FOR-BODY", *ast); return ASTVerifier::CheckResult::FAILED; } bool hasExit = body->IsBreakStatement() || body->IsReturnStatement(); @@ -548,13 +495,13 @@ public: }); if (!hasExit) { // 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; } if (!test->IsExpression()) { - ctx.AddInvariantError("NULL FOR VAR", *ast, ast->Start()); + ctx.AddInvariantError(name, "NULL FOR VAR", *ast); return ASTVerifier::CheckResult::FAILED; } } @@ -570,11 +517,12 @@ public: ASTVerifier::CheckResult operator()(ASTVerifier::ErrorContext &ctx, const ir::AstNode *ast) { + const auto name = "ModifierAccessValid"; if (ast->IsMemberExpression()) { const auto *propVar = ast->AsMemberExpression()->PropVar(); if (propVar != nullptr && propVar->HasFlag(varbinder::VariableFlags::PROPERTY) && !ValidateVariableAccess(propVar, ast->AsMemberExpression())) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *ast, ast->Start()); + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE", *ast); return ASTVerifier::CheckResult::FAILED; } } @@ -586,7 +534,7 @@ public: const auto *propVarCallee = calleeMember->PropVar(); if (propVarCallee != nullptr && propVarCallee->HasFlag(varbinder::VariableFlags::METHOD) && !ValidateMethodAccess(calleeMember, ast->AsCallExpression())) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE", *callee, callee->Start()); + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE", *callee); return ASTVerifier::CheckResult::FAILED; } } @@ -619,17 +567,18 @@ public: importedVariables.emplace(name(import)); } } + const auto name = "ImportExportAccessValid"; if (ast->IsCallExpression()) { const auto *callExpr = ast->AsCallExpression(); const auto *callee = callExpr->Callee(); if (callee != nullptr && callee->IsIdentifier() && !HandleImportExportIdentifier(importedVariables, callee->AsIdentifier(), callExpr)) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee, callee->Start()); + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee); return ASTVerifier::CheckResult::FAILED; } } if (ast->IsIdentifier() && !HandleImportExportIdentifier(importedVariables, ast->AsIdentifier(), nullptr)) { - ctx.AddInvariantError("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast, ast->Start()); + ctx.AddInvariantError(name, "PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast); return ASTVerifier::CheckResult::FAILED; } return ASTVerifier::CheckResult::SUCCESS; @@ -741,9 +690,9 @@ 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; aux = [&ctx, &func, &aux, &result](const ir::AstNode *child) -> void { @@ -762,54 +711,46 @@ static ASTVerifier::InvariantCheck RecursiveInvariant(Func &func) }; } -// NOLINTBEGIN(cppcoreguidelines-macro-usage) -#define ADD_INVARIANT(Name) \ - { \ - auto *invariant = allocator->New(*allocator); \ - invariantsChecks_.emplace_back(Invariant {#Name, *invariant}); \ - invariantsNames_.insert(#Name); \ - invariantsChecks_.emplace_back(Invariant {#Name RECURSIVE_SUFFIX, RecursiveInvariant(*invariant)}); \ - invariantsNames_.insert(#Name RECURSIVE_SUFFIX); \ - } -// NOLINTEND(cppcoreguidelines-macro-usage) +void ASTVerifier::AddInvariant(const std::string &name, const InvariantCheck &invariant) +{ + invariantsChecks_[name] = invariant; + invariantsNames_.insert(name); + invariantsChecks_[name + RECURSIVE_SUFFIX] = RecursiveInvariant(invariant); + invariantsNames_.insert(name + RECURSIVE_SUFFIX); +} -ASTVerifier::ASTVerifier(ArenaAllocator *allocator) : invariantsChecks_ {}, invariantsNames_ {} +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 recursiveChecks = InvariantSet {}; std::copy_if(invariantsNames_.begin(), invariantsNames_.end(), std::inserter(recursiveChecks, recursiveChecks.end()), [](const std::string &s) { return s.find(RECURSIVE_SUFFIX) != s.npos; }); - return Verify(ast, recursiveChecks); + return Verify(warnings, asserts, ast, recursiveChecks); } -ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantSet &invariantSet) +std::tuple ASTVerifier::Verify( + const std::unordered_set &warnings, const std::unordered_set &asserts, + const ir::AstNode *ast, const InvariantSet &invariantSet) { - ErrorContext ctx {}; - auto checkAndReport = [&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 warningCtx {}; + AssertsContext assertCtx {}; const auto containsInvariants = std::includes(invariantsNames_.begin(), invariantsNames_.end(), invariantSet.begin(), invariantSet.end()); @@ -817,25 +758,24 @@ ASTVerifier::Errors ASTVerifier::Verify(const ir::AstNode *ast, const InvariantS if (!containsInvariants) { auto invalidInvariants = InvariantSet {}; for (const auto &invariant : invariantSet) { - if (invariantsNames_.find(invariant.data()) == invariantsNames_.end()) { + if (invariantsNames_.find(invariant) == invariantsNames_.end()) { invalidInvariants.insert(invariant.data()); } } for (const auto &invariant : invalidInvariants) { - ctx.AddError(std::string {"invariant was not found: "} + invariant.data()); + assertCtx.AddError(std::string {"invariant was not found: "} + invariant); } } for (const auto &invariantName : invariantSet) { - for (const auto &[name, invariant] : invariantsChecks_) { - if (std::string_view {invariantName} == name.Utf8()) { - checkAndReport(name, invariant, ast); - break; - } + if (warnings.count(invariantName) > 0) { + invariantsChecks_[invariantName](warningCtx, ast); + } else if (asserts.count(invariantName) > 0) { + invariantsChecks_[invariantName](assertCtx, ast); } } - return ctx.GetErrors(); + return std::make_tuple(warningCtx.GetErrors(), assertCtx.GetErrors()); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ASTVerifier.h b/ets2panda/compiler/core/ASTVerifier.h index 24dc314aed..de605c9189 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 invariantName; - InvariantError error; - + explicit CheckError(std::string name, InvariantError error) + : invariantName_ {std::move(name)}, error_ {std::move(error)} + { + } std::function DumpJSON() const { return [&](JsonObjectBuilder &body) { - body.AddProperty("invariant", invariantName.Utf8()); - body.AddProperty("cause", error.cause); - body.AddProperty("message", error.message); - body.AddProperty("line", error.line + 1); + body.AddProperty("invariant", invariantName_); + body.AddProperty("cause", error_.cause); + body.AddProperty("message", error_.message); + body.AddProperty("line", error_.line + 1); }; } + const std::string &GetName() const + { + return invariantName_; + } + + private: + std::string invariantName_; + InvariantError error_; }; using Errors = std::vector; enum class CheckResult { FAILED, SUCCESS, SKIP_SUBTREE }; - struct ErrorContext; + 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 invariantName; 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 &invariantSet); + std::tuple Verify(const std::unordered_set &warnings, + const std::unordered_set &asserts, + const ir::AstNode *ast, + const InvariantSet &invariantSet); private: + void AddInvariant(const std::string &name, const InvariantCheck &invariant); + Invariants invariantsChecks_; InvariantSet invariantsNames_; }; class ASTVerifierContext final { public: - ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} + explicit ASTVerifierContext(ASTVerifier &verifier) : verifier_ {verifier} {} void IntroduceNewInvariants(util::StringView phaseName) { @@ -107,43 +166,37 @@ public: if (phaseName == "ScopesInitPhase") { return {{ "NodeHasParentForAll", - "IdentifierHasVariableForAll", - "ModifierAccessValidForAll", - "ImportExportAccessValid", + "EveryChildHasValidParentForAll", + "VariableHasScopeForAll", }}; - } else if (phaseName == "PromiseVoidInferencePhase") { - return {{}}; - } else if (phaseName == "StructLowering") { - return {{}}; - } else if (phaseName == "CheckerPhase") { + } + if (phaseName == "CheckerPhase") { return {{ "NodeHasTypeForAll", + "IdentifierHasVariableForAll", "ArithmeticOperationValidForAll", "SequenceExpressionHasLastTypeForAll", - "EveryChildHasValidParentForAll", "ForLoopCorrectlyInitializedForAll", - "VariableHasScopeForAll", "VariableHasEnclosingScopeForAll", + "ModifierAccessValidForAll", + "ImportExportAccessValid", }}; - } else if (phaseName == "GenerateTsDeclarationsPhase") { - return {{}}; - } else if (phaseName == "InterfacePropertyDeclarationsPhase") { - return {{}}; - } else if (phaseName == "LambdaConstructionPhase") { - return {{}}; - } else if (phaseName == "ObjectIndexLowering") { - return {{}}; - } else if (phaseName == "OpAssignmentLowering") { - return {{}}; - } else if (phaseName == "PromiseVoidInferencePhase") { - return {{}}; - } else if (phaseName == "TupleLowering") { - return {{}}; - } else if (phaseName == "UnionLowering") { - return {{}}; - } else if (phaseName == "ExpandBracketsPhase") { + } + const std::set withoutAdditionalChecks = {"PromiseVoidInferencePhase", + "StructLowering", + "GenerateTsDeclarationsPhase", + "InterfacePropertyDeclarationsPhase", + "LambdaConstructionPhase", + "ObjectIndexLowering", + "OpAssignmentLowering", + "PromiseVoidInferencePhase", + "TupleLowering", + "UnionLowering", + "ExpandBracketsPhase"}; + if (withoutAdditionalChecks.count(phaseName.Mutf8()) > 0) { return {{}}; - } else if (phaseName.Utf8().find("plugins") != std::string_view::npos) { + } + if (phaseName.Utf8().find("plugins") != std::string_view::npos) { return {{}}; } return std::nullopt; @@ -155,30 +208,40 @@ public: accumulatedChecks_.insert(s.begin(), s.end()); } - bool Verify(const ir::AstNode *ast, util::StringView phaseName, util::StringView sourceName) + bool Verify(const std::unordered_set &warnings, const std::unordered_set &errors, + const ir::AstNode *ast, util::StringView phaseName, util::StringView sourceName) { - errors_ = verifier_.Verify(ast, accumulatedChecks_); - for (const auto &e : errors_) { - errorArray_.Add([e, sourceName, phaseName](JsonObjectBuilder &err) { + auto [warns, asserts] = verifier_.Verify(warnings, errors, ast, accumulatedChecks_); + std::for_each(warns.begin(), warns.end(), [this, &sourceName, &phaseName](ASTVerifier::CheckError &e) { + warnings_.Add([e, sourceName, phaseName](JsonObjectBuilder &err) { err.AddProperty("from", sourceName.Utf8()); err.AddProperty("phase", phaseName.Utf8()); err.AddProperty("error", e.DumpJSON()); }); - } - auto result = errors_.empty(); - errors_.clear(); - return result; + }); + std::for_each(asserts.begin(), asserts.end(), [this, &sourceName, &phaseName](ASTVerifier::CheckError &e) { + asserts_.Add([e, sourceName, phaseName](JsonObjectBuilder &err) { + err.AddProperty("from", sourceName.Utf8()); + err.AddProperty("phase", phaseName.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(errorArray_).Build(); + return std::move(asserts_).Build(); } private: ASTVerifier &verifier_; - ASTVerifier::Errors errors_; - JsonArrayBuilder errorArray_; + JsonArrayBuilder warnings_; + JsonArrayBuilder asserts_; ASTVerifier::InvariantSet accumulatedChecks_ {}; }; diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 6e17ccc7ca..28948051b6 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 : toCheck) { const auto &sourceName = std::get<0>(it); const auto &linkedProgram = std::get<1>(it); - verificationCtx.Verify(linkedProgram->Ast(), phase->Name(), sourceName); + verificationCtx.Verify(context.Options()->verifierWarnings, context.Options()->verifierErrors, + linkedProgram->Ast(), phase->Name(), sourceName); verificationCtx.IntroduceNewInvariants(phase->Name()); } #endif } #ifndef NDEBUG - - if (auto errors = verificationCtx.DumpErrorsJSON(); errors != "[]") { -#ifdef ES2PANDA_AST_VERIFIER_ERROR - ASSERT_PRINT(false, errors); -#else - LOG(ERROR, ES2PANDA) << errors; -#endif + if (!context.Options()->verifierWarnings.empty()) { + if (auto errors = verificationCtx.DumpWarningsJSON(); errors != "[]") { + LOG(ERROR, ES2PANDA) << errors; + } + } + if (!context.Options()->verifierErrors.empty()) { + if (auto errors = verificationCtx.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 8ea0758349..63f88b1846 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 3d293a22a8..c34d62ccb2 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -59,29 +59,21 @@ static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PA static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}; +// NOLINTBEGIN(fuchsia-statically-constructed-objects) static InitScopesPhaseETS g_initScopesPhaseEts; static InitScopesPhaseAS g_initScopesPhaseAs; static InitScopesPhaseTs g_initScopesPhaseTs; static InitScopesPhaseJs g_initScopesPhaseJs; +// NOLINTEND(fuchsia-statically-constructed-objects) std::vector GetETSPhaseList() { return { - &g_pluginsAfterParse, - &g_initScopesPhaseEts, - &g_promiseVoidInferencePhase, - &g_structLowering, - &g_lambdaConstructionPhase, - &g_interfacePropDeclPhase, - &g_checkerPhase, - &g_pluginsAfterCheck, - &g_generateTsDeclarationsPhase, - &g_opAssignmentLowering, - &g_objectIndexLowering, - &g_tupleLowering, - &g_unionLowering, - &g_expandBracketsPhase, - &g_pluginsAfterLowerings, + &g_pluginsAfterParse, &g_initScopesPhaseEts, &g_promiseVoidInferencePhase, + &g_structLowering, &g_lambdaConstructionPhase, &g_interfacePropDeclPhase, + &g_checkerPhase, &g_pluginsAfterCheck, &g_generateTsDeclarationsPhase, + &g_opAssignmentLowering, &g_objectIndexLowering, &g_tupleLowering, + &g_unionLowering, &g_expandBracketsPhase, &g_pluginsAfterLowerings, }; } 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 a3edef3a2d..8a7135cc41 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 38269eeb79..7f11b3340c 100644 --- a/ets2panda/es2panda.h +++ b/ets2panda/es2panda.h @@ -103,6 +103,8 @@ struct CompilerOptions { std::string tsDeclOut {}; std::vector plugins {}; std::unordered_set skipPhases {}; + std::unordered_set verifierWarnings {}; + std::unordered_set verifierErrors {}; std::unordered_set dumpBeforePhases {}; std::unordered_set dumpEtsSrcBeforePhases {}; std::unordered_set dumpAfterPhases {}; diff --git a/ets2panda/test/unit/ast_dumper_test.cpp b/ets2panda/test/unit/ast_dumper_test.cpp index 4f3b1c5196..047ce9a9fa 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 25c649cfaf..2968017c40 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,238 +102,212 @@ protected: // NOLINTEND(misc-non-private-member-variables-in-classes) }; -static void CompareMinified(std::string_view actualJson, std::string_view expectedJson) -{ - std::string message {actualJson}; - 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(), expectedJson); -} - TEST_F(ASTVerifierTest, NullParent) { - compiler::ASTVerifier verifier {Allocator()}; - panda::es2panda::ir::StringLiteral emptyNode; + ASTVerifier verifier {Allocator()}; + StringLiteral emptyNode; 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 hasParent = errors.size() == 0; - ASSERT_EQ(hasParent, false); - ASSERT_EQ(errors.size(), 1); - - const auto [name, error] = errors[0]; - ASSERT_EQ(name, check); - auto messageExpected = 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"}}, {{}}, &emptyNode, checks); + bool hasParent = warnings.empty(); + ASSERT_FALSE(hasParent); + 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 emptyNode; + ASTVerifier verifier {Allocator()}; + StringLiteral emptyNode; auto check = "NodeHasType"; - auto checks = compiler::ASTVerifier::InvariantSet {}; + auto checks = ASTVerifier::InvariantSet {}; checks.insert(check); - const auto &errors = verifier.Verify(&empty_node, checks); - bool hasType = errors.size() == 0; + const auto [warnings, errors] = verifier.Verify({{"NodeHasType"}}, {{}}, &emptyNode, checks); + bool hasType = warnings.empty(); ASSERT_EQ(hasType, false); - ASSERT_NE(errors.size(), 0); - - const auto [name, error] = errors[0]; - ASSERT_EQ(name, check); + ASSERT_NE(warnings.size(), 0); - auto messageExpected = 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 emptyNode; + ASTVerifier verifier {Allocator()}; + StringLiteral emptyNode; - 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"}}, {{}}, &emptyNode, 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); - scope.SetParent(&parent_scope); + LocalScope scope(Allocator(), nullptr); + FunctionScope parentScope(Allocator(), nullptr); + scope.SetParent(&parentScope); 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); - scope.SetParent(&parent_scope); + LocalScope scope(Allocator(), nullptr); + FunctionScope parentScope(Allocator(), nullptr); + scope.SetParent(&parentScope); scope.AddDecl(Allocator(), &decl, ScriptExtension::ETS); scope.BindNode(&ident); parentScope.BindNode(&ident); 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 arithmeticExpression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_PLUS); + auto left = NumberLiteral(Number {1}); + auto right = NumberLiteral(Number {6}); + auto arithmeticExpression = 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"}}, {{}}, arithmeticExpression.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 arithmeticExpression = 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 arithmeticExpression = 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"}}, {{}}, arithmeticExpression.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 leftParam("1"); + const StringView leftParam("1"); constexpr uint32_t RIGHT_PARAM = 1; - auto left = ir::StringLiteral(left_param); - auto right = ir::NumberLiteral(lexer::Number {RIGHT_PARAM}); - auto arithmeticExpression = ir::BinaryExpression(&left, &right, lexer::TokenType::PUNCTUATOR_DIVIDE); + auto left = StringLiteral(leftParam); + auto right = NumberLiteral(Number {RIGHT_PARAM}); + auto arithmeticExpression = 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"}}, {{}}, arithmeticExpression.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 arithmeticExpression = 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 arithmeticExpression = 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"}}, {{}}, arithmeticExpression.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 *sequenceExpression = - 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 *sequenceExpression = Tree(Node( + Nodes(Node(Number {1}), Node(Number {2}), last))); last->SetTsType(checker.GlobalIntType()); - sequence_expression->SetTsType(checker.GlobalIntType()); + sequenceExpression->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"}}, {{}}, sequenceExpression, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 isCorrect = 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(isCorrect, 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 f49a3d8d91..3761f18d40 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -181,8 +181,10 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg genStdLib("gen-stdlib", false, "Gen standard library"); panda::PandArg plugins("plugins", "", "Plugins"); panda::PandArg skipPhases("skip-phases", "", "Phases to skip"); + panda::PandArg verifierWarnings("verifier-warnings", "", "Show warnings form verifier"); + panda::PandArg verifierErrors("verifier-errors", "", "Show warnings form verifier"); panda::PandArg dumpBeforePhases("dump-before-phases", "", - "Generate program dump before running phases in the list"); + "Generate program dump before running phases in the list"); panda::PandArg dumpEtsSrcBeforePhases( "dump-ets-src-before-phases", "", "Generate program dump as ets source code before running phases in the list"); panda::PandArg dumpEtsSrcAfterPhases( @@ -222,10 +224,12 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&genStdLib); argparser_->Add(&plugins); argparser_->Add(&skipPhases); + argparser_->Add(&verifierWarnings); + argparser_->Add(&verifierErrors); argparser_->Add(&dumpBeforePhases); argparser_->Add(&dumpEtsSrcBeforePhases); argparser_->Add(&dumpAfterPhases); - argparser_->Add(&dumpEtsSrcAfterPhases); + argparser_->Add(&dumpEtsSrcBeforePhases); argparser_->Add(&arktsConfig); argparser_->Add(&opTsDeclOut); @@ -401,7 +405,7 @@ bool Options::Parse(int argc, const char **argv) } } - if ((dumpEtsSrcBeforePhases.GetValue().size() + dumpEtsSrcAfterPhases.GetValue().size() > 0) && + if ((dumpEtsSrcAfterPhases.GetValue().size() + dumpEtsSrcAfterPhases.GetValue().size() > 0) && extension_ != es2panda::ScriptExtension::ETS) { errorMsg_ = "--dump-ets-src-* option is valid only with ETS extension"; return false; @@ -420,9 +424,11 @@ bool Options::Parse(int argc, const char **argv) compilerOptions_.isEtsModule = opEtsModule.GetValue(); compilerOptions_.plugins = SplitToStringVector(plugins.GetValue()); compilerOptions_.skipPhases = SplitToStringSet(skipPhases.GetValue()); + compilerOptions_.verifierWarnings = SplitToStringSet(verifierWarnings.GetValue()); + compilerOptions_.verifierErrors = SplitToStringSet(verifierErrors.GetValue()); compilerOptions_.dumpBeforePhases = SplitToStringSet(dumpBeforePhases.GetValue()); compilerOptions_.dumpEtsSrcBeforePhases = SplitToStringSet(dumpEtsSrcBeforePhases.GetValue()); - compilerOptions_.dumpAfterPhases = SplitToStringSet(dumpAfterPhases.GetValue()); + compilerOptions_.dumpAfterPhases = SplitToStringSet(dumpBeforePhases.GetValue()); compilerOptions_.dumpEtsSrcAfterPhases = SplitToStringSet(dumpEtsSrcAfterPhases.GetValue()); return true; -- Gitee From ecd4cad58a9d5d6cafe5978c70622878d85d8a73 Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Tue, 9 Jan 2024 15:47:43 +0300 Subject: [PATCH 24/27] 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 | 5 ++--- .../ets/generic_constructor_with_union.ets | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 3 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 be2fca309c..7f1d44a882 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -142,11 +142,10 @@ Type *ETSTypeParameter::Substitute(TypeRelation *relation, const Substitution *s if (this != original && ((ContainsNull() && !replType->ContainsNull()) || (ContainsUndefined() && !replType->ContainsUndefined()))) { // this type is explicitly marked as nullish - ASSERT(replType->IsETSObjectType() || replType->IsETSArrayType() || replType->IsETSFunctionType() || - replType->IsETSTypeParameter()); + ASSERT(ETSChecker::IsReferenceType(replType)); auto nullishFlags = TypeFlag(TypeFlags() & TypeFlag::NULLISH); auto *newReplType = checker->CreateNullishType(replType, nullishFlags, checker->Allocator(), relation, - checker->GetGlobalTypesHolder()); + checker->GetGlobalTypesHolder()); replType = newReplType; } return replType; 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 From a432f9f9295504fd79f3220ae2098df00559951f Mon Sep 17 00:00:00 2001 From: Tatiana Date: Tue, 16 Jan 2024 15:28:10 +0300 Subject: [PATCH 25/27] Fix code-style warnings Signed-off-by: Tatiana --- ets2panda/checker/ETSAnalyzer.cpp | 13 ++++++------ ets2panda/checker/ETSchecker.h | 3 +-- ets2panda/checker/ets/arithmetic.cpp | 8 ++++---- ets2panda/checker/ets/typeCreation.cpp | 4 ++-- ets2panda/checker/ets/typeRelationContext.cpp | 8 +++----- .../checker/types/ets/etsTypeParameter.cpp | 2 +- ets2panda/checker/types/ets/etsUnionType.cpp | 6 +++--- ets2panda/checker/types/globalTypesHolder.cpp | 2 +- ets2panda/checker/types/typeRelation.cpp | 1 - ets2panda/compiler/core/ASTVerifier.cpp | 1 - ets2panda/compiler/core/ASTVerifier.h | 20 +++++++++---------- ets2panda/compiler/core/compilerImpl.cpp | 2 +- .../compiler/lowering/ets/structLowering.cpp | 3 +-- .../compiler/lowering/ets/unionLowering.cpp | 9 ++++----- ets2panda/compiler/lowering/phase.cpp | 8 ++++---- ets2panda/ir/ets/etsTuple.cpp | 6 +++--- ets2panda/ir/expressions/arrayExpression.cpp | 2 +- ets2panda/parser/ETSparser.cpp | 9 ++++----- ets2panda/parser/ETSparser.h | 3 +-- ets2panda/test/runtime/ets/array_inf.ets | 15 ++++++++++++++ ets2panda/util/options.cpp | 2 +- ets2panda/varbinder/scope.cpp | 4 ++-- 22 files changed, 68 insertions(+), 63 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 4ab978b5d5..5b7ac5a9ed 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -978,10 +978,10 @@ ArenaVector GetUnionTypeSignatures(ETSChecker *checker, ch if (constituentType->IsETSObjectType()) { ArenaVector tmpCallSignatures(checker->Allocator()->Adapter()); tmpCallSignatures = constituentType->AsETSObjectType() - ->GetOwnProperty("invoke") - ->TsType() - ->AsETSFunctionType() - ->CallSignatures(); + ->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures(); callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end()); } if (constituentType->IsETSFunctionType()) { @@ -1064,7 +1064,7 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ calleeType->IsETSUnionType() && calleeType->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool isFunctionalInterface = calleeType->IsETSObjectType() && calleeType->AsETSObjectType()->HasObjectFlag( - checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); + checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); bool etsExtensionFuncHelperType = calleeType->IsETSExtensionFuncHelperType(); if (expr->Callee()->IsArrowFunctionExpression()) { @@ -1535,8 +1535,7 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType) : checker->ETSBuiltinTypeAsPrimitiveType(argType); - if (argType != nullptr && argType->IsETSBigIntType() && - argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { + if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { switch (expr->OperatorType()) { case lexer::TokenType::PUNCTUATOR_MINUS: { checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue()); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 6989b06807..a856f80512 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -662,8 +662,7 @@ private: void SetUpTypeParameterConstraint(ir::TSTypeParameter *param); ETSObjectType *UpdateGlobalType(ETSObjectType *objType, util::StringView name); ETSObjectType *UpdateBoxedGlobalType(ETSObjectType *objType, util::StringView name); - ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, - ETSObjectFlags flags); + ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); void CheckProgram(parser::Program *program, bool runAnalysis = false); template diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 564f35b581..7e7da4307d 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -600,7 +600,7 @@ static std::tuple CheckBinaryOperatorHelper(ETSChecker *checker, case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType, - unboxedL, unboxedR); + unboxedL, unboxedR); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: @@ -652,10 +652,10 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, const bool isLogicalExtendedOperator = (op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || (op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); - Type *unboxedL = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) - : ETSBuiltinTypeAsPrimitiveType(leftType); + Type *unboxedL = + isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType); Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType) - : ETSBuiltinTypeAsPrimitiveType(rightType); + : ETSBuiltinTypeAsPrimitiveType(rightType); checker::Type *tsType {}; bool isEqualOp = diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index b3e251deee..4551e1169a 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -308,8 +308,8 @@ ETSObjectType *ETSChecker::UpdateGlobalType(ETSObjectType *objType, util::String } if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { - auto *nullish = CreateNullishType(objType, checker::TypeFlag::NULLISH, Allocator(), Relation(), - GetGlobalTypesHolder()); + auto *nullish = + CreateNullishType(objType, checker::TypeFlag::NULLISH, Allocator(), Relation(), GetGlobalTypesHolder()); GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_NULLISH_OBJECT)] = nullish; } } diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index e741e69f63..1cad83ce42 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -61,15 +61,13 @@ bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSType extends "Comparable", we will get an error here. */ - auto const isDefaulted = [typeArgs](size_t idx) { - return typeArgs == nullptr || idx >= typeArgs->Params().size(); - }; + auto const isDefaulted = [typeArgs](size_t idx) { return typeArgs == nullptr || idx >= typeArgs->Params().size(); }; auto const getTypes = [this, &typeArgs, type, isDefaulted](size_t idx) -> std::pair { auto *typeParam = type->TypeArguments().at(idx)->AsETSTypeParameter(); return {typeParam, isDefaulted(idx) - ? typeParam->GetDefaultType() - : checker_->MaybePromotedBuiltinType(typeArgs->Params().at(idx)->GetType(checker_))}; + ? typeParam->GetDefaultType() + : checker_->MaybePromotedBuiltinType(typeArgs->Params().at(idx)->GetType(checker_))}; }; auto *const substitution = checker_->NewSubstitution(); diff --git a/ets2panda/checker/types/ets/etsTypeParameter.cpp b/ets2panda/checker/types/ets/etsTypeParameter.cpp index 7f1d44a882..5f00ef4a3c 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -145,7 +145,7 @@ Type *ETSTypeParameter::Substitute(TypeRelation *relation, const Substitution *s ASSERT(ETSChecker::IsReferenceType(replType)); auto nullishFlags = TypeFlag(TypeFlags() & TypeFlag::NULLISH); auto *newReplType = checker->CreateNullishType(replType, nullishFlags, checker->Allocator(), relation, - checker->GetGlobalTypesHolder()); + checker->GetGlobalTypesHolder()); replType = newReplType; } return replType; diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 8eb91a1065..9967c7d936 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -212,9 +212,9 @@ void ETSUnionType::NormalizeTypes(TypeRelation *relation, ArenaVector &c relation->IsSupertypeOf((*cmpIt), ct); bool removeSubtype = ct != *cmpIt && !bothConstants && relation->IsTrue(); bool removeNumeric = numberFound && ct->IsETSObjectType() && - ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && - !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) && - !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN); + ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && + !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) && + !ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN); bool removeNever = ct == checker->GetGlobalTypesHolder()->GlobalBuiltinNeverType(); return removeSubtype || removeNumeric || removeNever; }); diff --git a/ets2panda/checker/types/globalTypesHolder.cpp b/ets2panda/checker/types/globalTypesHolder.cpp index 456c2b1887..c91292f512 100644 --- a/ets2panda/checker/types/globalTypesHolder.cpp +++ b/ets2panda/checker/types/globalTypesHolder.cpp @@ -122,7 +122,7 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) : builtinNameMap builtinNameMappings_.emplace("StackTrace", GlobalTypeId::ETS_STACK_TRACE_BUILTIN); builtinNameMappings_.emplace("NullPointerException", GlobalTypeId::ETS_NULL_POINTER_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ArrayIndexOutOfBoundsException", - GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN); + GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ArithmeticException", GlobalTypeId::ETS_ARITHMETIC_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ClassNotFoundException", GlobalTypeId::ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN); builtinNameMappings_.emplace("ClassCastException", GlobalTypeId::ETS_CLASS_CAST_EXCEPTION_BUILTIN); diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index 437a22ff3c..a0582ab359 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -176,7 +176,6 @@ bool TypeRelation::IsCastableTo(Type *const source, Type *const target) 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; diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 5c526ff323..e0e1eab167 100644 --- a/ets2panda/compiler/core/ASTVerifier.cpp +++ b/ets2panda/compiler/core/ASTVerifier.cpp @@ -754,7 +754,6 @@ std::tuple ASTVerifier::Verify( const auto containsInvariants = std::includes(invariantsNames_.begin(), invariantsNames_.end(), invariantSet.begin(), invariantSet.end()); - if (!containsInvariants) { auto invalidInvariants = InvariantSet {}; for (const auto &invariant : invariantSet) { diff --git a/ets2panda/compiler/core/ASTVerifier.h b/ets2panda/compiler/core/ASTVerifier.h index de605c9189..ba03e4fc8d 100644 --- a/ets2panda/compiler/core/ASTVerifier.h +++ b/ets2panda/compiler/core/ASTVerifier.h @@ -183,16 +183,16 @@ public: }}; } const std::set withoutAdditionalChecks = {"PromiseVoidInferencePhase", - "StructLowering", - "GenerateTsDeclarationsPhase", - "InterfacePropertyDeclarationsPhase", - "LambdaConstructionPhase", - "ObjectIndexLowering", - "OpAssignmentLowering", - "PromiseVoidInferencePhase", - "TupleLowering", - "UnionLowering", - "ExpandBracketsPhase"}; + "StructLowering", + "GenerateTsDeclarationsPhase", + "InterfacePropertyDeclarationsPhase", + "LambdaConstructionPhase", + "ObjectIndexLowering", + "OpAssignmentLowering", + "PromiseVoidInferencePhase", + "TupleLowering", + "UnionLowering", + "ExpandBracketsPhase"}; if (withoutAdditionalChecks.count(phaseName.Mutf8()) > 0) { return {{}}; } diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 28948051b6..2223692296 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -159,7 +159,7 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase const auto &sourceName = std::get<0>(it); const auto &linkedProgram = std::get<1>(it); verificationCtx.Verify(context.Options()->verifierWarnings, context.Options()->verifierErrors, - linkedProgram->Ast(), phase->Name(), sourceName); + linkedProgram->Ast(), phase->Name(), sourceName); verificationCtx.IntroduceNewInvariants(phase->Name()); } #endif diff --git a/ets2panda/compiler/lowering/ets/structLowering.cpp b/ets2panda/compiler/lowering/ets/structLowering.cpp index 6569eb607a..09da124b2f 100644 --- a/ets2panda/compiler/lowering/ets/structLowering.cpp +++ b/ets2panda/compiler/lowering/ets/structLowering.cpp @@ -62,8 +62,7 @@ ir::ETSTypeReference *CreateStructTypeReference(checker::ETSChecker *checker, checker->AllocNode(etsStrucDeclaration->Definition()->Ident()->Name(), allocator); identSelfRef->AsIdentifier()->SetReference(); - auto *referenceSelfPart = - checker->AllocNode(identSelfRef, typeParamSelfInst, nullptr); + auto *referenceSelfPart = checker->AllocNode(identSelfRef, typeParamSelfInst, nullptr); auto *selfTypeReference = checker->AllocNode(referenceSelfPart); diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index da18c59eb7..98f789177b 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -272,12 +272,11 @@ ir::Expression *ProcessOperandsInBinaryExpr(checker::ETSChecker *checker, ir::Bi { ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL || expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL); - bool isLhsUnion; - ir::Expression *unionNode = - (isLhsUnion = expr->Left()->TsType()->IsETSUnionType()) ? expr->Left() : expr->Right(); + bool isLhsUnion = false; + ir::Expression *unionNode = (isLhsUnion = expr->Left()->TsType()->IsETSUnionType()) ? expr->Left() : expr->Right(); checker::Type *typeToCast = constituentType->IsETSNullLike() - ? unionNode->TsType()->AsETSUnionType()->GetLeastUpperBoundType() - : constituentType; + ? unionNode->TsType()->AsETSUnionType()->GetLeastUpperBoundType() + : constituentType; auto *const asExpression = GenAsExpression(checker, typeToCast, unionNode, expr); if (isLhsUnion) { expr->SetLeft(asExpression); diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index c34d62ccb2..a7ee5fbe4e 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -69,11 +69,11 @@ static InitScopesPhaseJs g_initScopesPhaseJs; std::vector GetETSPhaseList() { return { - &g_pluginsAfterParse, &g_initScopesPhaseEts, &g_promiseVoidInferencePhase, - &g_structLowering, &g_lambdaConstructionPhase, &g_interfacePropDeclPhase, - &g_checkerPhase, &g_pluginsAfterCheck, &g_generateTsDeclarationsPhase, + &g_pluginsAfterParse, &g_initScopesPhaseEts, &g_promiseVoidInferencePhase, + &g_structLowering, &g_lambdaConstructionPhase, &g_interfacePropDeclPhase, + &g_checkerPhase, &g_pluginsAfterCheck, &g_generateTsDeclarationsPhase, &g_opAssignmentLowering, &g_objectIndexLowering, &g_tupleLowering, - &g_unionLowering, &g_expandBracketsPhase, &g_pluginsAfterLowerings, + &g_unionLowering, &g_expandBracketsPhase, &g_pluginsAfterLowerings, }; } diff --git a/ets2panda/ir/ets/etsTuple.cpp b/ets2panda/ir/ets/etsTuple.cpp index 097a44fa22..3e40d189db 100644 --- a/ets2panda/ir/ets/etsTuple.cpp +++ b/ets2panda/ir/ets/etsTuple.cpp @@ -140,12 +140,12 @@ checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker const auto nullishUndefinedFlags = (containsNullOrUndefined.first ? checker::TypeFlag::NULLISH | checker::TypeFlag::NULL_TYPE - : checker::TypeFlag::NONE) | + : checker::TypeFlag::NONE) | (containsNullOrUndefined.second ? checker::TypeFlag::UNDEFINED : checker::TypeFlag::NONE); if (nullishUndefinedFlags != checker::TypeFlag::NONE) { - lubType = checker->CreateNullishType(lubType, nullishUndefinedFlags, checker->Allocator(), - checker->Relation(), checker->GetGlobalTypesHolder()); + lubType = checker->CreateNullishType(lubType, nullishUndefinedFlags, checker->Allocator(), checker->Relation(), + checker->GetGlobalTypesHolder()); } checker->Relation()->SetNode(savedRelationNode); diff --git a/ets2panda/ir/expressions/arrayExpression.cpp b/ets2panda/ir/expressions/arrayExpression.cpp index 7c477a45d8..00cc5f9965 100644 --- a/ets2panda/ir/expressions/arrayExpression.cpp +++ b/ets2panda/ir/expressions/arrayExpression.cpp @@ -391,7 +391,7 @@ void ArrayExpression::GetPrefferedTypeFromFuncParam(checker::ETSChecker *checker bool isAssignable = true; for (auto elem : elements_) { auto assignCtx = checker::AssignmentContext(checker->Relation(), elem, elem->Check(checker), paramType, - elem->Start(), {""}, checker::TypeRelationFlag::NO_THROW | flags); + elem->Start(), {""}, checker::TypeRelationFlag::NO_THROW | flags); isAssignable &= assignCtx.IsAssignable(); } if (isAssignable) { diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 7b2404b0b3..0d5eff251f 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1345,8 +1345,7 @@ void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::Modifie lexer::SourcePosition ETSParser::InitializeGlobalVariable(ir::Identifier *fieldName, ir::Expression *&initializer, ir::ScriptFunction *initFunction, - lexer::SourcePosition &startLoc, - ir::TypeNode *typeAnnotation) + lexer::SourcePosition &startLoc, ir::TypeNode *typeAnnotation) { lexer::SourcePosition endLoc = startLoc; @@ -2390,7 +2389,7 @@ std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *typeAnnotation, bo typeParamNames += ">"; } return adjustNullish(typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8() + - typeParamNames); + typeParamNames); } if (typeAnnotation->IsETSFunctionType()) { @@ -4690,11 +4689,11 @@ void ETSParser::ValidateInstanceOfExpression(ir::Expression *expr) // Run checks to validate type declarations // Should provide helpful messages with incorrect declarations like the following: - // instanceof A; + // `instanceof A;` ThrowSyntaxError("Invalid right-hand side in 'instanceof' expression"); } } diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index ef6979e34c..c271015998 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -168,8 +168,7 @@ private: // NOLINTNEXTLINE(google-default-arguments) void ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, - ArenaVector *declarations, - ir::ScriptFunction *initFunction = nullptr, + ArenaVector *declarations, ir::ScriptFunction *initFunction = nullptr, lexer::SourcePosition *letLoc = nullptr); lexer::SourcePosition InitializeGlobalVariable(ir::Identifier *fieldName, ir::Expression *&initializer, ir::ScriptFunction *initFunction, lexer::SourcePosition &startLoc, diff --git a/ets2panda/test/runtime/ets/array_inf.ets b/ets2panda/test/runtime/ets/array_inf.ets index 5c09324c73..eb4ed7c67b 100644 --- a/ets2panda/test/runtime/ets/array_inf.ets +++ b/ets2panda/test/runtime/ets/array_inf.ets @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + class A { foo(p: Object[]): int { let s = 0 diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index 3761f18d40..eea4000cc3 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -184,7 +184,7 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg verifierWarnings("verifier-warnings", "", "Show warnings form verifier"); panda::PandArg verifierErrors("verifier-errors", "", "Show warnings form verifier"); panda::PandArg dumpBeforePhases("dump-before-phases", "", - "Generate program dump before running phases in the list"); + "Generate program dump before running phases in the list"); panda::PandArg dumpEtsSrcBeforePhases( "dump-ets-src-before-phases", "", "Generate program dump as ets source code before running phases in the list"); panda::PandArg dumpEtsSrcAfterPhases( diff --git a/ets2panda/varbinder/scope.cpp b/ets2panda/varbinder/scope.cpp index ff6382c7ed..a1f13194b8 100644 --- a/ets2panda/varbinder/scope.cpp +++ b/ets2panda/varbinder/scope.cpp @@ -748,8 +748,8 @@ Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Var } foundVar = FindLocal(newDecl->Name(), - ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES - : ResolveBindingOptions::STATIC_VARIABLES)); + ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES + : ResolveBindingOptions::STATIC_VARIABLES)); if (foundVar != nullptr) { return nullptr; } -- Gitee From 683aea97cd8abcb85f071824a231989d037b45db Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Thu, 18 Jan 2024 16:31:46 +0300 Subject: [PATCH 26/27] Fix code checker warnings Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8XASF Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8XASJ Signed-off-by: Konstantin Kuznetsov --- ets2panda/parser/ASparser.cpp | 84 ++++++++++++++++++++--------------- ets2panda/parser/ASparser.h | 2 + ets2panda/parser/TSparser.cpp | 84 ++++++++++++++++++++--------------- ets2panda/parser/TSparser.h | 2 + 4 files changed, 100 insertions(+), 72 deletions(-) diff --git a/ets2panda/parser/ASparser.cpp b/ets2panda/parser/ASparser.cpp index d1cc21302d..657d56be4d 100644 --- a/ets2panda/parser/ASparser.cpp +++ b/ets2panda/parser/ASparser.cpp @@ -1351,60 +1351,72 @@ ir::AstNode *ASParser::ParseImportDefaultSpecifier(ArenaVector *s return nullptr; } -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ASParser::ParseCoverParenthesizedExpressionAndArrowParameterList( - [[maybe_unused]] ExpressionParseFlags flags) +ir::Expression *ASParser::ParseArrowFunctionRestParameter(lexer::SourcePosition start) { - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { - ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); + restElement->SetGrouped(); + restElement->SetStart(start); - restElement->SetGrouped(); - restElement->SetStart(start); + ValidateArrowFunctionRestParameter(restElement); - ValidateArrowFunctionRestParameter(restElement); + Lexer()->NextToken(); - Lexer()->NextToken(); + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { + ThrowSyntaxError(":' expected"); + } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { - ThrowSyntaxError(":' expected"); - } + Lexer()->NextToken(); // eat ':' - Lexer()->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); - ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("'=>' expected"); + } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("'=>' expected"); - } + return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); +} + +ir::Expression *ASParser::ParseArrowFunctionNoParameter(lexer::SourcePosition start) +{ + Lexer()->NextToken(); - return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { + ThrowSyntaxError(":' expected"); } - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - Lexer()->NextToken(); + Lexer()->NextToken(); // eat ':' - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { - ThrowSyntaxError(":' expected"); - } + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); - Lexer()->NextToken(); // eat ':' + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("'=>' expected"); + } - ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); + auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); + arrowExpr->SetStart(start); + arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("'=>' expected"); - } + return arrowExpr; +} + +// 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(); + Lexer()->NextToken(); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); - arrowExpr->SetStart(start); - arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { + return ParseArrowFunctionRestParameter(start); + } - return arrowExpr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + return ParseArrowFunctionNoParameter(start); } ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST | diff --git a/ets2panda/parser/ASparser.h b/ets2panda/parser/ASparser.h index 9f1858b5e0..4a69e8214c 100644 --- a/ets2panda/parser/ASparser.h +++ b/ets2panda/parser/ASparser.h @@ -76,6 +76,8 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; + ir::Expression *ParseArrowFunctionRestParameter(lexer::SourcePosition start); + ir::Expression *ParseArrowFunctionNoParameter(lexer::SourcePosition start); ir::Expression *ParsePrefixAssertionExpression() override; ir::Statement *ParseConstStatement(StatementParsingFlags flags) override; ir::AnnotatedExpression *ParseVariableDeclaratorKey(VariableParsingFlags flags) override; diff --git a/ets2panda/parser/TSparser.cpp b/ets2panda/parser/TSparser.cpp index 3f299c36d6..fc0ffe75e3 100644 --- a/ets2panda/parser/TSparser.cpp +++ b/ets2panda/parser/TSparser.cpp @@ -2599,56 +2599,68 @@ ir::Statement *TSParser::ParseExportDeclaration(StatementParsingFlags flags) } } -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *TSParser::ParseCoverParenthesizedExpressionAndArrowParameterList( - [[maybe_unused]] ExpressionParseFlags flags) +ir::Expression *TSParser::ParseArrowFunctionRestParameter(lexer::SourcePosition start) { - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { - ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); + restElement->SetGrouped(); + restElement->SetStart(start); - restElement->SetGrouped(); - restElement->SetStart(start); + ValidateArrowFunctionRestParameter(restElement); - ValidateArrowFunctionRestParameter(restElement); + Lexer()->NextToken(); - Lexer()->NextToken(); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + returnTypeAnnotation = ParseTypeAnnotation(&options); + } - ir::TypeNode *returnTypeAnnotation = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - returnTypeAnnotation = ParseTypeAnnotation(&options); - } + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("Unexpected token"); + } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("Unexpected token"); - } + return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); +} + +ir::Expression *TSParser::ParseArrowFunctionNoParameter(lexer::SourcePosition start) +{ + Lexer()->NextToken(); - return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + returnTypeAnnotation = ParseTypeAnnotation(&options); } - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - Lexer()->NextToken(); + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("Unexpected token"); + } - ir::TypeNode *returnTypeAnnotation = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - returnTypeAnnotation = ParseTypeAnnotation(&options); - } + auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); + arrowExpr->SetStart(start); + arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("Unexpected token"); - } + return arrowExpr; +} - auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); - arrowExpr->SetStart(start); - arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); +// 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(); + Lexer()->NextToken(); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { + return ParseArrowFunctionRestParameter(start); + } - return arrowExpr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + return ParseArrowFunctionNoParameter(start); } ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST | diff --git a/ets2panda/parser/TSparser.h b/ets2panda/parser/TSparser.h index 81b2df7164..76a2dd47cf 100644 --- a/ets2panda/parser/TSparser.h +++ b/ets2panda/parser/TSparser.h @@ -125,6 +125,8 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList( ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; + ir::Expression *ParseArrowFunctionRestParameter(lexer::SourcePosition start); + ir::Expression *ParseArrowFunctionNoParameter(lexer::SourcePosition start); ir::Statement *ParseConstStatement(StatementParsingFlags flags) override; ir::Statement *ParsePotentialConstEnum(VariableParsingFlags flags) override; void ParseCatchParamTypeAnnotation(ir::AnnotatedExpression *param) override; -- Gitee From 2ea27613c27dac3dc7aea0c8fde997de47f07714 Mon Sep 17 00:00:00 2001 From: Molokanov Yaroslav Date: Thu, 18 Jan 2024 18:01:56 +0300 Subject: [PATCH 27/27] Fix codecheck warning in CheckOverride Signed-off-by: Molokanov Yaroslav --- ets2panda/checker/ETSchecker.h | 1 + ets2panda/checker/ets/function.cpp | 60 ++++++++++++++++-------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index a856f80512..abca67d822 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -348,6 +348,7 @@ public: void CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, const ir::MethodDefinition *currentFunc); Signature *AdjustForTypeParameters(Signature *source, Signature *target); + void ThrowOverrideError(Signature *signature, Signature *overriddenSignature, const OverrideErrorCode &errorCode); void CheckOverride(Signature *signature); bool CheckOverride(Signature *signature, ETSObjectType *site); std::tuple CheckOverride(Signature *signature, Signature *other); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 8f578c9eac..8bb6da708b 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1150,6 +1150,38 @@ Signature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *tar return target->Substitute(Relation(), substitution); } +void ETSChecker::ThrowOverrideError(Signature *signature, Signature *overriddenSignature, + const OverrideErrorCode &errorCode) +{ + const char *reason {}; + switch (errorCode) { + case OverrideErrorCode::OVERRIDDEN_STATIC: { + reason = "overridden method is static."; + break; + } + case OverrideErrorCode::OVERRIDDEN_FINAL: { + reason = "overridden method is final."; + break; + } + case OverrideErrorCode::INCOMPATIBLE_RETURN: { + reason = "overriding return type is not compatible with the other return type."; + break; + } + case OverrideErrorCode::OVERRIDDEN_WEAKER: { + reason = "overridden method has weaker access privilege."; + break; + } + default: { + UNREACHABLE(); + } + } + + ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), " cannot override ", + overriddenSignature->Function()->Id()->Name(), overriddenSignature, " in ", + overriddenSignature->Owner(), " because ", reason}, + signature->Function()->Start()); +} + bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) { auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD); @@ -1189,33 +1221,7 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) auto [success, errorCode] = CheckOverride(signature, itSubst); if (!success) { - const char *reason {}; - switch (errorCode) { - case OverrideErrorCode::OVERRIDDEN_STATIC: { - reason = "overridden method is static."; - break; - } - case OverrideErrorCode::OVERRIDDEN_FINAL: { - reason = "overridden method is final."; - break; - } - case OverrideErrorCode::INCOMPATIBLE_RETURN: { - reason = "overriding return type is not compatible with the other return type."; - break; - } - case OverrideErrorCode::OVERRIDDEN_WEAKER: { - reason = "overridden method has weaker access privilege."; - break; - } - default: { - UNREACHABLE(); - } - } - - ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), - " cannot override ", it->Function()->Id()->Name(), it, " in ", it->Owner(), " because ", - reason}, - signature->Function()->Start()); + ThrowOverrideError(signature, it, errorCode); } isOverridingAnySignature = true; -- Gitee