From e4d71ea3522a3cf603051fefa501d800dc8130d5 Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Thu, 25 Jul 2024 11:15:14 +0300 Subject: [PATCH 1/2] Move identifier resolving to lowering Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IAFDDS?from=project-issue Tests: Test-u-runner and CI Signed-off-by: Zelentsov Dmitry --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ETSchecker.cpp | 14 +----- ets2panda/compiler/lowering/phase.cpp | 12 ++--- .../compiler/lowering/resolveIdentifiers.cpp | 45 +++++++++++++++++++ .../compiler/lowering/resolveIdentifiers.h | 33 ++++++++++++++ 6 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 ets2panda/compiler/lowering/resolveIdentifiers.cpp create mode 100644 ets2panda/compiler/lowering/resolveIdentifiers.h diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 14a3b74899..7a4e8f8028 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -199,6 +199,7 @@ libes2panda_sources = [ "compiler/lowering/ets/unionLowering.cpp", "compiler/lowering/phase.cpp", "compiler/lowering/plugin_phase.cpp", + "compiler/lowering/resolveIdentifiers.cpp", "compiler/lowering/scopesInit/savedBindingsCtx.cpp", "compiler/lowering/scopesInit/scopesInitPhase.cpp", "compiler/lowering/util.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 270899a6b5..875d72c8b0 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -165,6 +165,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/scopesInit/scopesInitPhase.cpp compiler/lowering/phase.cpp compiler/lowering/plugin_phase.cpp + compiler/lowering/resolveIdentifiers.cpp compiler/lowering/util.cpp compiler/lowering/ets/topLevelStmts/importExportDecls.cpp compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 8556428fab..df65144b1d 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -138,26 +138,14 @@ void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringV GetGlobalTypesHolder()->InitializeBuiltin(name, type); } -bool ETSChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const CompilerOptions &options) +bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const CompilerOptions &options) { Initialize(varbinder); - if (options.dumpAst) { - std::cout << Program()->Dump() << std::endl; - } - - if (options.opDumpAstOnlySilent) { - Program()->DumpSilent(); - return false; - } - if (options.parseOnly) { return false; } - varbinder->SetGenStdLib(options.compilationMode == CompilationMode::GEN_STD_LIB); - varbinder->IdentifierAnalysis(); - auto *etsBinder = varbinder->AsETSBinder(); InitializeBuiltins(etsBinder); diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 99fb42aae5..2767fef520 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -15,10 +15,10 @@ #include "phase.h" #include "checker/checker.h" -#include "compiler/core/ASTVerifier.h" #include "ets/ambientLowering.h" #include "ets/defaultParameterLowering.h" #include "lexer/token/sourceLocation.h" +#include "compiler/lowering/resolveIdentifiers.h" #include "compiler/lowering/checkerPhase.h" #include "compiler/lowering/ets/constStringToCharLowering.h" #include "compiler/lowering/ets/defaultParameterLowering.h" @@ -52,14 +52,7 @@ namespace ark::es2panda::compiler { static CheckerPhase g_checkerPhase; - -std::vector GetTrivialPhaseList() -{ - return std::vector { - &g_checkerPhase, - }; -} - +static ResolveIdentifiers g_resolveIdentifiers {}; static AmbientLowering g_ambientLowering; static BigIntLowering g_bigintLowering; static StringConstructorLowering g_stringConstructorLowering; @@ -117,6 +110,7 @@ std::vector GetETSPhaseList() &g_expressionLambdaConstructionPhase, &g_interfacePropDeclPhase, &g_enumLoweringPhase, + &g_resolveIdentifiers, &g_checkerPhase, &g_spreadConstructionPhase, &g_pluginsAfterCheck, diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.cpp b/ets2panda/compiler/lowering/resolveIdentifiers.cpp new file mode 100644 index 0000000000..944c828acb --- /dev/null +++ b/ets2panda/compiler/lowering/resolveIdentifiers.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "resolveIdentifiers.h" + +#include "varbinder/ETSBinder.h" + +namespace ark::es2panda::compiler { +bool ResolveIdentifiers::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) +{ + auto const &options = ctx->config->options->CompilerOptions(); + auto *varbinder = ctx->parserProgram->VarBinder()->AsETSBinder(); + + if (options.dumpAst) { + std::cout << varbinder->Program()->Dump() << std::endl; + } + + if (options.opDumpAstOnlySilent) { + varbinder->Program()->DumpSilent(); + return false; + } + + if (options.parseOnly) { + return false; + } + + varbinder->SetGenStdLib(options.compilationMode == CompilationMode::GEN_STD_LIB); + varbinder->IdentifierAnalysis(); + + return true; +} + +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.h b/ets2panda/compiler/lowering/resolveIdentifiers.h new file mode 100644 index 0000000000..d7f97078bf --- /dev/null +++ b/ets2panda/compiler/lowering/resolveIdentifiers.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_RESOLVE_IDENT_H +#define ES2PANDA_COMPILER_LOWERING_RESOLVE_IDENT_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { +class ResolveIdentifiers : public Phase { +public: + std::string_view Name() const override + { + return "ResolveIdentifiers"; + } + + bool Perform(public_lib::Context *ctx, parser::Program *program) override; +}; +} // namespace ark::es2panda::compiler + +#endif -- Gitee From 5e2be8414e07b14bd32009c64ad2a694b18ed04d Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Wed, 24 Jul 2024 17:40:26 +0300 Subject: [PATCH 2/2] Exclude modifying captured variables from smart casts Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IAFDEW?from=project-issue Tests: U-runner and CI Signed-off-by: Zelentsov Dmitry --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/checkerContext.cpp | 8 + ets2panda/checker/checkerContext.h | 5 +- .../lowering/ets/capturedVariables.cpp | 137 +++ .../compiler/lowering/ets/capturedVariables.h | 35 + ets2panda/compiler/lowering/phase.cpp | 3 + .../parser/ets/SmartCast_n01-expected.txt | 888 ++++++++++++++++++ ets2panda/test/parser/ets/SmartCast_n01.ets | 24 + .../parser/ets/SmartCast_n02-expected.txt | 789 ++++++++++++++++ ets2panda/test/parser/ets/SmartCast_n02.ets | 26 + ets2panda/test/runtime/ets/SmartCast_12.ets | 52 + ets2panda/varbinder/variableFlags.h | 1 + 13 files changed, 1966 insertions(+), 4 deletions(-) create mode 100644 ets2panda/compiler/lowering/ets/capturedVariables.cpp create mode 100644 ets2panda/compiler/lowering/ets/capturedVariables.h create mode 100644 ets2panda/test/parser/ets/SmartCast_n01-expected.txt create mode 100644 ets2panda/test/parser/ets/SmartCast_n01.ets create mode 100644 ets2panda/test/parser/ets/SmartCast_n02-expected.txt create mode 100644 ets2panda/test/parser/ets/SmartCast_n02.ets create mode 100644 ets2panda/test/runtime/ets/SmartCast_12.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 7a4e8f8028..95926a4a73 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -171,6 +171,7 @@ libes2panda_sources = [ "compiler/lowering/ets/ambientLowering.cpp", "compiler/lowering/ets/bigintLowering.cpp", "compiler/lowering/ets/boxingForLocals.cpp", + "compiler/lowering/ets/capturedVariables.cpp", "compiler/lowering/ets/constStringToCharLowering.cpp", "compiler/lowering/ets/defaultParameterLowering.cpp", "compiler/lowering/ets/enumLowering.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 875d72c8b0..e4cf1ea055 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -173,6 +173,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp compiler/lowering/ets/expressionLambdaLowering.cpp compiler/lowering/ets/boxingForLocals.cpp + compiler/lowering/ets/capturedVariables.cpp compiler/lowering/ets/lambdaLowering.cpp compiler/lowering/ets/spreadLowering.cpp compiler/lowering/ets/localClassLowering.cpp diff --git a/ets2panda/checker/checkerContext.cpp b/ets2panda/checker/checkerContext.cpp index d69b16dcf0..2d4efb5686 100644 --- a/ets2panda/checker/checkerContext.cpp +++ b/ets2panda/checker/checkerContext.cpp @@ -30,6 +30,14 @@ CheckerContext::CheckerContext(Checker *checker, CheckerStatus newStatus, ETSObj { } +void CheckerContext::SetSmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept +{ + // Just block captured and modified variables here instead of finding all their usage occurrences. + if (!variable->HasFlag(varbinder::VariableFlags::CAPTURED_MODIFIED)) { + smartCasts_.insert_or_assign(variable, smartType); + } +} + SmartCastTypes CheckerContext::CloneTestSmartCasts(bool const clearData) noexcept { if (testSmartCasts_.empty()) { diff --git a/ets2panda/checker/checkerContext.h b/ets2panda/checker/checkerContext.h index f50d37811a..b97876e1fe 100644 --- a/ets2panda/checker/checkerContext.h +++ b/ets2panda/checker/checkerContext.h @@ -171,10 +171,7 @@ public: smartCasts_.erase(variable); } - void SetSmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept - { - smartCasts_.insert_or_assign(variable, smartType); - } + void SetSmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept; [[nodiscard]] checker::Type *GetSmartCast(varbinder::Variable const *const variable) const noexcept; [[nodiscard]] SmartCastArray CloneSmartCasts(bool clearData = false) noexcept; diff --git a/ets2panda/compiler/lowering/ets/capturedVariables.cpp b/ets2panda/compiler/lowering/ets/capturedVariables.cpp new file mode 100644 index 0000000000..3f61d20684 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/capturedVariables.cpp @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include "capturedVariables.h" + +namespace ark::es2panda::compiler { + +static bool OnLeftSideOfAssignment(ir::Identifier const *const ident) noexcept +{ + return ident->Parent()->IsAssignmentExpression() && ident->Parent()->AsAssignmentExpression()->Left() == ident; +} + +static void AddScopes(ir::AstNode *node, std::set &scopes) noexcept +{ + if (node->Scope()->IsFunctionScope()) { + scopes.emplace(node->Scope()->AsFunctionScope()->ParamScope()); + } + if (node->Scope()->IsCatchScope()) { + scopes.emplace(node->Scope()->AsCatchScope()->ParamScope()); + } + if (node->Scope()->IsLoopScope()) { + scopes.emplace(node->Scope()->AsLoopScope()->DeclScope()); + } + scopes.emplace(node->Scope()); +} + +static varbinder::Variable *FindVariable(ir::Identifier *ident, std::set const &scopes) noexcept +{ + auto *var = ident->Variable(); + // NOTE! For some unknown reasons :) variables exist in scope collections but are not set to identifiers after + // 'varbinder->IdentifierAnalysis()' pass. Probably need to be investigated and fixed sometimes... + if (var == nullptr) { + // We start from the innermost scope! + for (auto it = scopes.crbegin(); it != scopes.crend(); ++it) { + auto res = (*it)->Find(ident->Name(), varbinder::ResolveBindingOptions::VARIABLES); + if (res.variable != nullptr) { + var = res.variable; + break; + } + } + } + + if (var != nullptr) { + auto *scope = var->GetScope(); + ASSERT(scope != nullptr); + // We are not interested in variables defined inside arrow function! + if (scopes.find(scope) != scopes.cend()) { + return nullptr; + } + } + + return var; +} + +static void FindModifiedCaptured(ir::ScriptFunction const *const scriptFunction, + std::set &variables) noexcept +{ + auto scopes = std::set {}; + bool inLambda = false; + + std::function walker = [&](ir::AstNode *node) -> void { + if (node->IsArrowFunctionExpression() || node->IsClassDeclaration()) { + auto savedWL = inLambda; + auto savedScopes = std::set {}; + std::swap(scopes, savedScopes); + + inLambda = true; + node->Iterate(walker); + + inLambda = savedWL; + std::swap(scopes, savedScopes); + savedScopes.clear(); + + return; + } + + if (inLambda && node->IsScopeBearer()) { + AddScopes(node, scopes); + } else if (inLambda && node->IsIdentifier() && OnLeftSideOfAssignment(node->AsIdentifier())) { + if (auto *var = FindVariable(node->AsIdentifier(), scopes); var != nullptr) { + variables.insert(var); + } + } + + node->Iterate(walker); + }; + + scriptFunction->Iterate(walker); +} + +static void HandleScriptFunction(ir::ScriptFunction const *const scriptFunction) noexcept +{ + auto variables = std::set {}; + FindModifiedCaptured(scriptFunction, variables); + + for (auto *variable : variables) { + variable->AddFlag(varbinder::VariableFlags::CAPTURED_MODIFIED); + } + + variables.clear(); +} + +bool CapturedVariables::Perform(public_lib::Context *ctx, parser::Program *program) +{ + if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) { + for (auto &[_, ext_programs] : program->ExternalSources()) { + (void)_; + for (auto *extProg : ext_programs) { + Perform(ctx, extProg); + } + } + } + + std::function searchForFunctions = [&](ir::AstNode *ast) { + if (ast->IsScriptFunction()) { + HandleScriptFunction(ast->AsScriptFunction()); // no recursion + } else { + ast->Iterate(searchForFunctions); + } + }; + + program->Ast()->Iterate(searchForFunctions); + return true; +} +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/capturedVariables.h b/ets2panda/compiler/lowering/ets/capturedVariables.h new file mode 100644 index 0000000000..539d472625 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/capturedVariables.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_CAPTURED_VARIABLES_H +#define ES2PANDA_COMPILER_LOWERING_CAPTURED_VARIABLES_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +class CapturedVariables : public Phase { +public: + std::string_view Name() const override + { + return "CapturedVariables"; + } + + bool Perform(public_lib::Context *ctx, parser::Program *program) override; +}; + +} // namespace ark::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 2767fef520..f0cb2a8ec2 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -27,6 +27,7 @@ #include "compiler/lowering/ets/topLevelStmts/topLevelStmts.h" #include "compiler/lowering/ets/expressionLambdaLowering.h" #include "compiler/lowering/ets/boxingForLocals.h" +#include "compiler/lowering/ets/capturedVariables.h" #include "compiler/lowering/ets/lambdaLowering.h" #include "compiler/lowering/ets/spreadLowering.h" #include "compiler/lowering/ets/interfacePropertyDeclarations.h" @@ -63,6 +64,7 @@ static SpreadConstructionPhase g_spreadConstructionPhase; static ExpressionLambdaConstructionPhase g_expressionLambdaConstructionPhase; static OpAssignmentLowering g_opAssignmentLowering; static BoxingForLocals g_boxingForLocals; +static CapturedVariables g_capturedVariables {}; static LambdaConversionPhase g_lambdaConversionPhase; static ObjectIndexLowering g_objectIndexLowering; static ObjectIteratorLowering g_objectIteratorLowering; @@ -111,6 +113,7 @@ std::vector GetETSPhaseList() &g_interfacePropDeclPhase, &g_enumLoweringPhase, &g_resolveIdentifiers, + &g_capturedVariables, &g_checkerPhase, &g_spreadConstructionPhase, &g_pluginsAfterCheck, diff --git a/ets2panda/test/parser/ets/SmartCast_n01-expected.txt b/ets2panda/test/parser/ets/SmartCast_n01-expected.txt new file mode 100644 index 0000000000..3a2505b99a --- /dev/null +++ b/ets2panda/test/parser/ets/SmartCast_n01-expected.txt @@ -0,0 +1,888 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "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": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "resolve", + "typeAnnotation": { + "type": "ETSUnionType", + "types": [ + { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "value", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 25 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 25 + }, + "end": { + "line": 17, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 25 + }, + "end": { + "line": 17, + "column": 32 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 32 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 17, + "column": 36 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + { + "type": "ETSNullType", + "loc": { + "start": { + "line": 17, + "column": 44 + }, + "end": { + "line": 17, + "column": 48 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 48 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "init": { + "type": "NullLiteral", + "value": null, + "loc": { + "start": { + "line": 17, + "column": 51 + }, + "end": { + "line": 17, + "column": 55 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 55 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 56 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "p", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 19, + "column": 8 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Promise", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 19, + "column": 22 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 23 + }, + "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 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 22 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 19, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 19, + "column": 31 + } + } + }, + "arguments": [ + { + "type": "ArrowFunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "_resolve", + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "value", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 50 + }, + "end": { + "line": 19, + "column": 56 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 50 + }, + "end": { + "line": 19, + "column": 57 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 50 + }, + "end": { + "line": 19, + "column": 57 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 43 + }, + "end": { + "line": 19, + "column": 57 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 43 + }, + "end": { + "line": 19, + "column": 57 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 19, + "column": 60 + }, + "end": { + "line": 19, + "column": 64 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 42 + }, + "end": { + "line": 19, + "column": 64 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 32 + }, + "end": { + "line": 19, + "column": 64 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 32 + }, + "end": { + "line": 19, + "column": 64 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 19, + "column": 67 + }, + "end": { + "line": 19, + "column": 71 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "resolve", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 12 + } + } + }, + "right": { + "type": "Identifier", + "name": "_resolve", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 15 + }, + "end": { + "line": 20, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 75 + }, + "end": { + "line": 21, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 21, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 21, + "column": 4 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 11 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 21, + "column": 6 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 19, + "column": 3 + }, + "end": { + "line": 21, + "column": 6 + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "resolve", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 3 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + "arguments": [ + { + "type": "StringLiteral", + "value": "abc", + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 23, + "column": 16 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 23, + "column": 3 + }, + "end": { + "line": 23, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 3 + }, + "end": { + "line": 23, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 24, + "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": 25, + "column": 1 + } + } +} +TypeError: This expression is not callable. [SmartCast_n01.ets:23:3] diff --git a/ets2panda/test/parser/ets/SmartCast_n01.ets b/ets2panda/test/parser/ets/SmartCast_n01.ets new file mode 100644 index 0000000000..0dbdfb6780 --- /dev/null +++ b/ets2panda/test/parser/ets/SmartCast_n01.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main() { + let resolve: ((value: string) => void) | null = null; + + let p = new Promise((_resolve: (value: string)=> void): void => { + resolve = _resolve; + }); + + resolve("abc"); // no smart cast! +} diff --git a/ets2panda/test/parser/ets/SmartCast_n02-expected.txt b/ets2panda/test/parser/ets/SmartCast_n02-expected.txt new file mode 100644 index 0000000000..1f238339ed --- /dev/null +++ b/ets2panda/test/parser/ets/SmartCast_n02-expected.txt @@ -0,0 +1,789 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "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": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "x", + "typeAnnotation": { + "type": "ETSUnionType", + "types": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Number", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 17 + } + } + }, + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "String", + "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 + } + } + }, + { + "type": "ETSUndefinedType", + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 33 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 33 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "init": { + "type": "StringLiteral", + "value": "test1", + "loc": { + "start": { + "line": 17, + "column": 36 + }, + "end": { + "line": 17, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 43 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 44 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "lam", + "typeAnnotation": { + "type": "ETSFunctionType", + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 19, + "column": 18 + }, + "end": { + "line": 19, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 12 + }, + "end": { + "line": 19, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 19, + "column": 10 + } + } + }, + "init": { + "type": "ArrowFunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 6 + }, + "end": { + "line": 20, + "column": 7 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 7, + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 6 + }, + "end": { + "line": 20, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 6 + }, + "end": { + "line": 20, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 21, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 25 + }, + "end": { + "line": 21, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 25 + }, + "end": { + "line": 21, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 7 + }, + "end": { + "line": 21, + "column": 4 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 19, + "column": 3 + }, + "end": { + "line": 21, + "column": 5 + } + } + }, + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "instanceof", + "left": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 7 + }, + "end": { + "line": 23, + "column": 8 + } + } + }, + "right": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 20 + }, + "end": { + "line": 23, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 20 + }, + "end": { + "line": 23, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 20 + }, + "end": { + "line": 23, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 7 + }, + "end": { + "line": 23, + "column": 27 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "tmp", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 24, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 12 + } + } + }, + "init": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 23 + }, + "end": { + "line": 24, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 9 + }, + "end": { + "line": 24, + "column": 24 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 24, + "column": 5 + }, + "end": { + "line": 24, + "column": 25 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 28 + }, + "end": { + "line": 25, + "column": 4 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 23, + "column": 3 + }, + "end": { + "line": 25, + "column": 4 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 26, + "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": 27, + "column": 1 + } + } +} +TypeError: Type 'Double|String|undefined' cannot be assigned to type 'String' [SmartCast_n02.ets:24:23] diff --git a/ets2panda/test/parser/ets/SmartCast_n02.ets b/ets2panda/test/parser/ets/SmartCast_n02.ets new file mode 100644 index 0000000000..0fc05483c0 --- /dev/null +++ b/ets2panda/test/parser/ets/SmartCast_n02.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ + +function main() { + let x: Number|String|undefined = "test1"; + + let lam: () => void = () => { + x = 7; + }; + + if (x instanceof string) { + let tmp: string = x; // no smart cast! + } +} diff --git a/ets2panda/test/runtime/ets/SmartCast_12.ets b/ets2panda/test/runtime/ets/SmartCast_12.ets new file mode 100644 index 0000000000..70e68b6b3f --- /dev/null +++ b/ets2panda/test/runtime/ets/SmartCast_12.ets @@ -0,0 +1,52 @@ +/* + * 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. + */ + +function main() { + let resolve: ((value: string) => void) | null = null; + + let p = new Promise((_resolve: (value: string)=> void): void => { + resolve = _resolve; + }); + + resolve!("abc"); // no smart cast! + + let x: Number|String|undefined = "test1"; + let y: Number|String|undefined = "test2" + let z: Number|String|undefined = 7 + + let lam: () => void = () => { + let y: Number|String|undefined = 2; // hides outer declaration! + x = z; + let tmp: number = y; // smart cast is used + assert(tmp == 2); + }; + + if (x instanceof string) { + let tmp: string = x as string; // no smart cast! + assert(tmp == "test1"); + } + + lam(); + + assert(x == 7); + + if (y instanceof string) { + let tmp: string = y; // smart cast is used + assert(tmp == "test2"); + } + + let w: number = z; // smart cast is used + assert(w == 7) +} diff --git a/ets2panda/varbinder/variableFlags.h b/ets2panda/varbinder/variableFlags.h index b4dabdd82e..9ec50fa1fe 100644 --- a/ets2panda/varbinder/variableFlags.h +++ b/ets2panda/varbinder/variableFlags.h @@ -155,6 +155,7 @@ enum class VariableFlags : uint64_t { LEXICAL_BOUND = 1U << 30U, BUILTIN_TYPE = 1ULL << 31ULL, + CAPTURED_MODIFIED = 1ULL << 32ULL, HOIST_VAR = HOIST | VAR, CLASS_OR_INTERFACE = CLASS | INTERFACE, -- Gitee