From 584208ee7e768a3bf91b06c26e387bcfd87bd94c Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Thu, 9 Nov 2023 17:39:09 +0300 Subject: [PATCH 1/9] Title: Fix imported paths Description: Fixed different type signatures for same class imported with different paths Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8FAPJ Testing: ./tests/tests-u-runner/runner.sh $ARK_SOURCE_DIR --parser --build-dir=$ARK_BUILD_BIR --test-file parser/ets/import_tests/import_diff_paths.ets Signed-off-by: Anna Antipina --- ets2panda/checker/ets/helpers.cpp | 7 +- ets2panda/compiler/core/compilerImpl.cpp | 5 +- ets2panda/parser/ETSparser.cpp | 90 +++- ets2panda/parser/ETSparser.h | 14 +- .../import_diff_paths-expected.txt | 491 ++++++++++++++++++ .../ets/import_tests/import_diff_paths.ets | 21 + .../modules/test_lib1-expected.txt | 290 +++++++++++ .../ets/import_tests/modules/test_lib1.ets | 17 + .../modules/test_lib2-expected.txt | 389 ++++++++++++++ .../ets/import_tests/modules/test_lib2.ets | 18 + ets2panda/util/helpers.cpp | 35 ++ ets2panda/util/helpers.h | 2 + ets2panda/varbinder/ETSBinder.cpp | 45 +- ets2panda/varbinder/ETSBinder.h | 26 +- 14 files changed, 1406 insertions(+), 44 deletions(-) create mode 100644 ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/import_diff_paths.ets create mode 100644 ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets create mode 100644 ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt create mode 100644 ets2panda/test/parser/ets/import_tests/modules/test_lib2.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 7331139366..d1e74e0835 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1057,8 +1057,11 @@ void ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *module_obj { auto *ets_binder = static_cast(VarBinder()); - auto res = ets_binder->GetGlobalRecordTable()->Program()->ExternalSources().find(import_path); - + auto ext_records = ets_binder->GetGlobalRecordTable()->Program()->ExternalSources(); + auto res = [ets_binder, ext_records, import_path]() { + auto r = ext_records.find(import_path); + return r != ext_records.end() ? r : ext_records.find(ets_binder->GetResolvedImportPath(import_path)); + }(); for (auto [_, var] : res->second.front()->GlobalClassScope()->StaticFieldScope()->Bindings()) { (void)_; if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) { diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 0d33af9dd5..858ca20a05 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -115,7 +115,10 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase context.SetParser(&parser); parser.ParseScript(unit.input, unit.options.compilation_mode == CompilationMode::GEN_STD_LIB); - + if constexpr (std::is_same_v && std::is_same_v) { + reinterpret_cast(varbinder)->FillResolvedImportPathes(parser.ResolvedParsedSourcesMap(), + &allocator); + } for (auto *phase : get_phases()) { if (!phase->Apply(&context, &program)) { return nullptr; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 1100af3be5..0becad2529 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -173,11 +173,21 @@ void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVecto // remove external sources from paths because already parsed them paths.erase(remove_if(begin(paths), end(paths), [this](auto x) { - return find(begin(parsed_sources_), end(parsed_sources_), x) != end(parsed_sources_); + auto resolved = ResolveImportPath(x); + auto path_iter = + std::find_if(resolved_parsed_sources_.begin(), resolved_parsed_sources_.end(), + [resolved](const auto &p) { return p.second == resolved; }); + auto found = path_iter != resolved_parsed_sources_.end(); + if (found) { + resolved_parsed_sources_.emplace(x, resolved); + } + return found; }), end(paths)); - parsed_sources_.insert(parsed_sources_.end(), paths.begin(), paths.end()); + for (const auto &path : paths) { + parsed_sources_.push_back(ResolveImportPath(path)); + } ParseSources(paths, false); ParseTopLevelDeclaration(statements); @@ -231,9 +241,12 @@ ArenaVector ETSParser::PrepareExternalGlobalClass([[maybe_unuse if (!statements.empty()) { res = ext_sources.find(name); } else { - const util::UString source_file_path( - GetProgram()->SourceFilePath().Mutf8() + GetProgram()->GetPackageName().Mutf8(), Allocator()); - GetProgram()->SetSource(GetProgram()->SourceCode(), GetProgram()->SourceFile(), source_file_path.View()); + auto path = GetProgram()->SourceFilePath().Mutf8() + panda::os::file::File::GetPathDelim().at(0) + + GetProgram()->GetPackageName().Mutf8(); + auto resolved = ResolveImportPath(path); + resolved_parsed_sources_.emplace(path, resolved); + GetProgram()->SetSource(GetProgram()->SourceCode(), GetProgram()->SourceFile(), + util::UString(resolved, Allocator()).View()); } if (res == ext_sources.end()) { @@ -344,14 +357,30 @@ ETSParser::ImportData ETSParser::GetImportData(const std::string &path) return {ToLanguage(Extension()), path, true}; } +std::string ETSParser::ResolveFullPathFromRelative(const std::string &path) +{ + char path_delimiter = panda::os::file::File::GetPathDelim().at(0); + auto resolved_fp = GetProgram()->ResolvedFilePath().Mutf8(); + auto source_fp = GetProgram()->SourceFilePath().Mutf8(); + if (resolved_fp.empty()) { + auto fp = source_fp + path_delimiter + path; + return util::Helpers::IsRealPath(fp) ? fp : path; + } + auto fp = resolved_fp + path_delimiter + path; + if (util::Helpers::IsRealPath(fp)) { + return fp; + } + if (path.find(source_fp) == 0) { + return resolved_fp + path_delimiter + path.substr(source_fp.size()); + } + return path; +} + std::string ETSParser::ResolveImportPath(const std::string &path) { char path_delimiter = panda::os::file::File::GetPathDelim().at(0); if (util::Helpers::IsRelativePath(path)) { - if (GetProgram()->ResolvedFilePath().Mutf8().empty()) { - return GetProgram()->SourceFilePath().Mutf8() + path_delimiter + path; - } - return GetProgram()->ResolvedFilePath().Mutf8() + path_delimiter + path; + return util::Helpers::GetAbsPath(ResolveFullPathFromRelative(path)); } std::string base_url; @@ -395,11 +424,29 @@ std::string ETSParser::ResolveImportPath(const std::string &path) return base_url; } +std::tuple ETSParser::GetSourceRegularPath(const std::string &path, const std::string &resolved_path) +{ + if (!panda::os::file::File::IsRegularFile(resolved_path)) { + std::string import_extension = ".ets"; + + if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { + import_extension = ".ts"; + + if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { + ThrowSyntaxError("Incorrect path: " + resolved_path); + } + } + return {path + import_extension, true}; + } + return {path, false}; +} + std::tuple, bool> ETSParser::CollectUserSources(const std::string &path) { std::vector user_paths; const std::string resolved_path = ResolveImportPath(path); + resolved_parsed_sources_.emplace(path, resolved_path); const auto data = GetImportData(resolved_path); if (!data.has_decl) { @@ -407,23 +454,11 @@ std::tuple, bool> ETSParser::CollectUserSources(const s } if (!panda::os::file::File::IsDirectory(resolved_path)) { - if (!panda::os::file::File::IsRegularFile(resolved_path)) { - std::string import_extension = ".ets"; - - if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { - import_extension = ".ts"; - - if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { - ThrowSyntaxError("Incorrect path: " + resolved_path); - } - } - - user_paths.emplace_back(path + import_extension); - return {user_paths, true}; - } - - user_paths.emplace_back(path); - return {user_paths, false}; + std::string regular_path; + bool is_module = false; + std::tie(regular_path, is_module) = GetSourceRegularPath(path, resolved_path); + user_paths.emplace_back(regular_path); + return {user_paths, is_module}; } #ifdef USE_UNIX_SYSCALL @@ -479,6 +514,8 @@ void ETSParser::ParseSources(const std::vector &paths, bool is_exte const std::size_t path_count = paths.size(); for (std::size_t idx = 0; idx < path_count; idx++) { std::string resolved_path = ResolveImportPath(paths[idx]); + resolved_parsed_sources_.emplace(paths[idx], resolved_path); + const auto data = GetImportData(resolved_path); if (!data.has_decl) { @@ -2862,6 +2899,7 @@ std::tuple> ETSParser::ParseFromCla bool is_module = false; auto import_path = Lexer()->GetToken().Ident(); auto resolved_import_path = ResolveImportPath(import_path.Mutf8()); + resolved_parsed_sources_.emplace(import_path.Mutf8(), resolved_import_path); ir::StringLiteral *resolved_source; if (*import_path.Bytes() == '/') { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index d1eb419aa8..cf643c0d57 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -41,7 +41,10 @@ inline constexpr char const DEFAULT_SOURCE_FILE[] = ".ets"; class ETSParser final : public TypedParser { public: ETSParser(Program *program, const CompilerOptions &options, ParserStatus status = ParserStatus::NO_OPTS) - : TypedParser(program, options, status), global_program_(GetProgram()), parsed_sources_({}) + : TypedParser(program, options, status), + global_program_(GetProgram()), + parsed_sources_({}), + resolved_parsed_sources_({}) { } @@ -109,8 +112,10 @@ private: void ParseTopLevelDeclaration(ArenaVector &statements); void CollectDefaultSources(); std::string ResolveImportPath(const std::string &path); + std::string ResolveFullPathFromRelative(const std::string &path); ImportData GetImportData(const std::string &path); std::tuple, bool> CollectUserSources(const std::string &path); + std::tuple GetSourceRegularPath(const std::string &path, const std::string &resolved_path); void ParseSources(const std::vector &paths, bool is_external = true); std::tuple> ParseFromClause(bool require_from); void ParseNamedImportSpecifiers(ArenaVector *specifiers); @@ -328,10 +333,17 @@ private: friend class ExternalSourceParser; friend class InnerSourceParser; +public: + const std::unordered_map &ResolvedParsedSourcesMap() const + { + return resolved_parsed_sources_; + } + private: parser::Program *global_program_; std::vector parsed_sources_; std::vector inserting_nodes_ {}; + std::unordered_map resolved_parsed_sources_; }; class ExternalSourceParser { diff --git a/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt b/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt new file mode 100644 index 0000000000..36509b5515 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt @@ -0,0 +1,491 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./modules", + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 40 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 40 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./modules", + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + { + "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": 19, + "column": 10 + }, + "end": { + "line": 19, + "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": 19, + "column": 10 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 6 + } + } + }, + "arguments": [ + { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 15 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 16 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets b/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets new file mode 100644 index 0000000000..b768dbc1fc --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets @@ -0,0 +1,21 @@ +/* + * 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 { C } from "./modules/test_lib1" +import { f } from "./modules/test_lib2" + +function main() { + f(new C()); +} \ No newline at end of file diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt b/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt new file mode 100644 index 0000000000..8386d8940f --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt @@ -0,0 +1,290 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 15 + } + } + }, + "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": 18 + }, + "end": { + "line": 16, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 16 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + { + "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": 18, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets b/ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets new file mode 100644 index 0000000000..03521fe135 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib1.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. + */ + +export class C {} + diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt b/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt new file mode 100644 index 0000000000..51e505772f --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt @@ -0,0 +1,389 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./", + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + { + "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": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 24 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 17, + "column": 25 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 27 + } + } + } + ], + "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/modules/test_lib2.ets b/ets2panda/test/parser/ets/import_tests/modules/test_lib2.ets new file mode 100644 index 0000000000..858acdc0f8 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib2.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. + */ + +import { C } from "./test_lib1" +export function f(c: C) {} + diff --git a/ets2panda/util/helpers.cpp b/ets2panda/util/helpers.cpp index aafd8d43e7..b1f4abe0f9 100644 --- a/ets2panda/util/helpers.cpp +++ b/ets2panda/util/helpers.cpp @@ -43,6 +43,7 @@ #include "ir/module/importDeclaration.h" #include "lexer/token/letters.h" #include "libpandabase/utils/utf.h" +#include "libpandabase/os/filesystem.h" namespace panda::es2panda::util { // Helpers @@ -169,6 +170,40 @@ bool Helpers::IsRelativePath(const std::string &path) return ((path.find(current_dir_reference) == 0) || (path.find(parent_dir_reference) == 0)); } +std::string Helpers::GetAbsPath(const std::string &path) +{ + std::string full_file_path = path; + std::string import_extension; + if (!panda::os::file::File::IsRegularFile(path) && (panda::os::GetAbsolutePath(path).empty())) { + import_extension = ".ets"; + full_file_path = path + import_extension; + if (!panda::os::file::File::IsRegularFile(full_file_path)) { + import_extension = ".ts"; + full_file_path = path + import_extension; + if (!panda::os::file::File::IsRegularFile(full_file_path)) { + return path; + } + } + } + std::string abs_file_path = panda::os::GetAbsolutePath(full_file_path); + abs_file_path.erase(abs_file_path.find(import_extension), import_extension.size()); + return abs_file_path; +} + +bool Helpers::IsRealPath(const std::string &path) +{ + if (!panda::os::file::File::IsRegularFile(path) && (panda::os::GetAbsolutePath(path).empty())) { + auto import_extension = ".ets"; + if (!panda::os::file::File::IsRegularFile(path + import_extension)) { + import_extension = ".ts"; + if (!panda::os::file::File::IsRegularFile(path + import_extension)) { + return false; + } + } + } + return true; +} + const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::AstNode *node) { const ir::ScriptFunction *iter = GetContainingFunction(node); diff --git a/ets2panda/util/helpers.h b/ets2panda/util/helpers.h index 2611e79141..bd32ed03a5 100644 --- a/ets2panda/util/helpers.h +++ b/ets2panda/util/helpers.h @@ -79,6 +79,8 @@ public: static util::StringView ToStringView(ArenaAllocator *allocator, int32_t number); static util::StringView ToStringView(ArenaAllocator *allocator, uint32_t number); static bool IsRelativePath(const std::string &path); + static bool IsRealPath(const std::string &path); + static std::string GetAbsPath(const std::string &path); static const ir::ScriptFunction *GetContainingConstructor(const ir::AstNode *node); static const ir::ScriptFunction *GetContainingConstructor(const ir::ClassProperty *node); diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index d12f33d16e..61c93cd5b9 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -582,6 +582,23 @@ varbinder::Variable *ETSBinder::FindStaticBinding(const ArenaVectorsecond; } +ArenaVector ETSBinder::GetExternalProgram(const util::StringView &source_name, + const ir::StringLiteral *import_path) +{ + const auto &ext_records = global_record_table_.Program()->ExternalSources(); + auto record_res = [this, ext_records, source_name]() { + auto res = ext_records.find(source_name); + return (res != ext_records.end()) ? res : ext_records.find(GetResolvedImportPath(source_name)); + }(); + if (record_res == ext_records.end()) { + ThrowError(import_path->Start(), "Cannot find import: " + std::string(source_name)); + } + + ASSERT(!record_res->second.empty()); + + return record_res->second; +} + void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import) { const ir::StringLiteral *const import_path = import->Source(); @@ -591,18 +608,20 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i return; } - const auto &ext_records = global_record_table_.Program()->ExternalSources(); - const util::StringView source_name = - (import->Module() == nullptr) - ? import_path->Str() - : util::UString(import_path->Str().Mutf8() + import->Module()->Str().Mutf8(), Allocator()).View(); - const auto record_res = ext_records.find(source_name); - if (record_res == ext_records.end()) { - ThrowError(import_path->Start(), "Cannot find import: " + std::string(source_name)); - } + const util::StringView source_name = [import, import_path, this]() { + if (import->Module() == nullptr) { + return import_path->Str(); + } + char path_delimiter = panda::os::file::File::GetPathDelim().at(0); + auto str_import_path = import_path->Str().Mutf8(); + if (str_import_path.find(path_delimiter) == (str_import_path.size() - 1)) { + return util::UString(str_import_path + import->Module()->Str().Mutf8(), Allocator()).View(); + } + return util::UString(str_import_path + path_delimiter + import->Module()->Str().Mutf8(), Allocator()).View(); + }(); - ASSERT(!record_res->second.empty()); - const auto *const import_program = record_res->second.front(); + auto record = GetExternalProgram(source_name, import_path); + const auto *const import_program = record.front(); const auto *const import_global_scope = import_program->GlobalScope(); const auto &global_bindings = import_global_scope->Bindings(); @@ -618,7 +637,7 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i return; } - if (AddImportSpecifiersToTopBindings(specifier, global_bindings, import, record_res->second)) { + if (AddImportSpecifiersToTopBindings(specifier, global_bindings, import, record)) { return; } @@ -628,7 +647,7 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i auto item = std::find_if(global_bindings.begin(), global_bindings.end(), predicate_func); if (item == global_bindings.end()) { insert_foreign_binding(specifier->AsImportDefaultSpecifier()->Local()->Name(), - FindStaticBinding(record_res->second, import_path)); + FindStaticBinding(record, import_path)); return; } diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 82f49cd9ae..48d7cf964e 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -43,7 +43,8 @@ public: dynamic_imports_(Allocator()->Adapter()), lambda_objects_(Allocator()->Adapter()), dynamic_import_vars_(Allocator()->Adapter()), - import_specifiers_(Allocator()->Adapter()) + import_specifiers_(Allocator()->Adapter()), + resolved_import_pathes_map_(Allocator()->Adapter()) { InitImplicitThisParam(); } @@ -119,6 +120,8 @@ public: void BuildImportDeclaration(ir::ETSImportDeclaration *decl); void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *class_instance); void AddSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import); + ArenaVector GetExternalProgram(const util::StringView &source_name, + const ir::StringLiteral *import_path); bool AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *specifier, const varbinder::Scope::VariableMap &global_bindings, const parser::Program *import_program, @@ -184,6 +187,26 @@ public: default_export_ = default_export; } + const ArenaUnorderedMap &ResolvedImportPathesMap() const + { + return resolved_import_pathes_map_; + } + + const util::StringView &GetResolvedImportPath(const util::StringView &path) const + { + ASSERT(resolved_import_pathes_map_.find(path) != resolved_import_pathes_map_.end()); + + return resolved_import_pathes_map_.find(path)->second; + } + + void FillResolvedImportPathes(const std::unordered_map &map, ArenaAllocator *allocator) + { + for (const auto &path : map) { + resolved_import_pathes_map_.emplace(util::UString(path.first, allocator).View(), + util::UString(path.second, allocator).View()); + } + } + bool IsDynamicModuleVariable(const Variable *var) const; bool IsDynamicNamespaceVariable(const Variable *var) const; const DynamicImportData *DynamicImportDataForVar(const Variable *var) const; @@ -218,6 +241,7 @@ private: DynamicImportVariables dynamic_import_vars_; ir::Identifier *this_param_ {}; ArenaVector> import_specifiers_; + ArenaUnorderedMap resolved_import_pathes_map_; ir::AstNode *default_export_ {}; }; -- Gitee From 1b3c486779c04d738589ee3c51d2ca0a7b158cec Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Mon, 20 Nov 2023 14:04:41 +0300 Subject: [PATCH 2/9] Check constraint circular dependency for type parameters. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8HODT?from=project-issue Tests: .../05.generics/01.generic_declarations/generic_interfaces/generic_interface_self_dependency4,5.ets Signed-off-by: Zelentsov Dmitry --- ets2panda/checker/ETSchecker.h | 5 +++ ets2panda/checker/ets/object.cpp | 55 +++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 87fc469310..e6acf295cc 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -587,7 +587,12 @@ private: } ArenaVector CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *type_params); + Type *CreateTypeParameterType(ir::TSTypeParameter *param); + + using Type2TypeMap = std::unordered_map; + void CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends); + void SetUpTypeParameterConstraint(ir::TSTypeParameter *param); ETSObjectType *SetUpParameterType(ir::TSTypeParameter *param); ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *decl_node, diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 3de0b51247..5baa4a4ab0 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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 @@ -175,9 +175,20 @@ ArenaVector ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterD ArenaVector result {Allocator()->Adapter()}; checker::ScopeContext scope_ctx(this, type_params->Scope()); - for (auto *const param : type_params->Params()) { - result.push_back(CreateTypeParameterType(param)); + // Note: we have to run pure check loop first to avoid endless loop because of possible circular dependencies + Type2TypeMap extends {}; + for (auto *const type_param : type_params->Params()) { + if (auto *const constraint = type_param->Constraint(); + constraint != nullptr && constraint->IsETSTypeReference() && + constraint->AsETSTypeReference()->Part()->Name()->IsIdentifier()) { + CheckTypeParameterConstraint(type_param, extends); + } + } + + for (auto *const type_param : type_params->Params()) { + result.emplace_back(CreateTypeParameterType(type_param)); } + // The type parameter might be used in the constraint, like 'K extend Comparable', // so we need to create their type first, then set up the constraint for (auto *const param : type_params->Params()) { @@ -187,6 +198,35 @@ ArenaVector ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterD return result; } +void ETSChecker::CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends) +{ + const auto type_param_name = param->Name()->Name().Utf8(); + const auto constraint_name = + param->Constraint()->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Utf8(); + + if (type_param_name == constraint_name) { + ThrowTypeError({"Type parameter '", type_param_name, "' cannot extend/implement itself."}, + param->Constraint()->Start()); + } + + auto it = extends.find(type_param_name); + if (it != extends.cend()) { + ThrowTypeError({"Type parameter '", type_param_name, "' is duplicated in the list."}, + param->Constraint()->Start()); + } + + it = extends.find(constraint_name); + while (it != extends.cend()) { + if (it->second == type_param_name) { + ThrowTypeError({"Type parameter '", type_param_name, "' has circular constraint dependency."}, + param->Constraint()->Start()); + } + it = extends.find(it->second); + } + + extends.emplace(type_param_name, constraint_name); +} + Type *ETSChecker::CreateTypeParameterType(ir::TSTypeParameter *const param) { auto const instantiate_supertype = [this](TypeFlag nullish_flags) { @@ -217,19 +257,10 @@ void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param) param_type = param->Name()->Variable()->TsType()->AsETSObjectType(); } if (param->Constraint() != nullptr) { - if (param->Constraint()->IsETSTypeReference() && - param->Constraint()->AsETSTypeReference()->Part()->Name()->IsIdentifier() && - param->Name()->Name() == - param->Constraint()->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name()) { - ThrowTypeError({"Type variable '", param->Name()->Name(), "' cannot depend on itself"}, - param->Constraint()->Start()); - } - if (param->Constraint()->IsETSTypeReference()) { const auto constraint_name = param->Constraint()->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name(); const auto *const type_param_scope = param->Parent()->AsTSTypeParameterDeclaration()->Scope(); - if (auto *const found_param = type_param_scope->FindLocal(constraint_name, varbinder::ResolveBindingOptions::BINDINGS); found_param != nullptr) { -- Gitee From c0c30fe8bcb72e6e694f290804de18bb6dd597ba Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Thu, 9 Nov 2023 14:46:23 +0300 Subject: [PATCH 3/9] Implement constructors with default parameters. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8FJLJ?from=project-issue Test: build Signed-off-by: Zelentsov Dmitry --- ets2panda/checker/ets/function.cpp | 30 ++-- .../ir/ets/etsNewClassInstanceExpression.cpp | 2 + ets2panda/ir/ets/etsParameterExpression.cpp | 4 + ets2panda/ir/ets/etsParameterExpression.h | 15 ++ ets2panda/parser/ETSparser.cpp | 159 +++++++++++++----- ets2panda/parser/ETSparser.h | 24 ++- .../ets/optionalLambdaParameter-expected.txt | 4 +- .../ets/default_parameter1-expected.txt | 4 +- .../ets/default_parameter2-expected.txt | 4 +- .../ets/default_parameter4-expected.txt | 10 +- .../ets/default_parameter5-expected.txt | 4 +- ..._implicitly_typed_return_void-expected.txt | 6 +- .../parser/ets/rest_parameter_02-expected.txt | 4 +- .../test/runtime/ets/default_parameters.ets | 49 ++++++ 14 files changed, 240 insertions(+), 79 deletions(-) create mode 100644 ets2panda/test/runtime/ets/default_parameters.ets diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index ed412dc646..9594d01036 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -290,10 +290,12 @@ bool ETSChecker::ValidateProxySignature(Signature *const signature, return false; } - const auto num_non_default_params = - signature->Params().size() - signature->Function()->Body()->AsBlockStatement()->Statements().size(); + auto const *const proxy_param = signature->Function()->Params().back()->AsETSParameterExpression(); + if (!proxy_param->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) { + return false; + } - if (arguments.size() < num_non_default_params) { + if (arguments.size() < proxy_param->GetRequiredParams()) { return false; } @@ -366,17 +368,25 @@ Signature *ETSChecker::ValidateSignatures(ArenaVector &signatures, return nullptr; } + // Just to avoid extra nesting level + auto const check_ambiguous = [this, most_specific_signature, + &pos](Signature const *const proxy_signature) -> void { + auto const *const proxy_param = proxy_signature->Function()->Params().back()->AsETSParameterExpression(); + if (!proxy_param->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) { + ThrowTypeError({"Proxy parameter '", proxy_param->Ident()->Name(), "' has invalid name."}, pos); + } + + if (most_specific_signature->Params().size() == proxy_param->GetRequiredParams()) { + ThrowTypeError({"Reference to ", most_specific_signature->Function()->Id()->Name(), " is ambiguous"}, + pos); + } + }; + if (!proxy_signatures.empty()) { auto *const proxy_signature = ChooseMostSpecificProxySignature( proxy_signatures, arguments, arg_type_inference_required, pos, arguments.size()); if (proxy_signature != nullptr) { - const size_t num_non_default_params = - proxy_signature->Params().size() - - proxy_signature->Function()->Body()->AsBlockStatement()->Statements().size(); - if (most_specific_signature->Params().size() == num_non_default_params) { - ThrowTypeError( - {"Reference to ", most_specific_signature->Function()->Id()->Name(), " is ambiguous"}, pos); - } + check_ambiguous(proxy_signature); } } diff --git a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp index e0a0ce1b2d..f39597c1c6 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp @@ -164,6 +164,8 @@ checker::Type *ETSNewClassInstanceExpression::Check([[maybe_unused]] checker::ET auto *signature = checker->ResolveConstructExpression(callee_obj, arguments_, Start()); checker->CheckObjectLiteralArguments(signature, arguments_); + checker->AddUndefinedParamsForDefaultParams(signature, arguments_, checker); + checker->ValidateSignatureAccessibility(callee_obj, signature, Start()); ASSERT(signature->Function() != nullptr); diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp index 3d00268107..0445df4d22 100644 --- a/ets2panda/ir/ets/etsParameterExpression.cpp +++ b/ets2panda/ir/ets/etsParameterExpression.cpp @@ -171,12 +171,16 @@ ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allo if (auto *const clone = allocator->New(ident_or_spread, initializer); clone != nullptr) { ident_or_spread->SetParent(clone); + if (initializer != nullptr) { initializer->SetParent(clone); } + if (parent != nullptr) { clone->SetParent(parent); } + + clone->SetRequiredParams(extra_value_); return clone; } diff --git a/ets2panda/ir/ets/etsParameterExpression.h b/ets2panda/ir/ets/etsParameterExpression.h index 7786d77fc3..64af2b1778 100644 --- a/ets2panda/ir/ets/etsParameterExpression.h +++ b/ets2panda/ir/ets/etsParameterExpression.h @@ -23,6 +23,10 @@ class ETSAnalyzer; } // namespace panda::es2panda::checker namespace panda::es2panda::ir { +// NOLINTBEGIN(modernize-avoid-c-arrays) +inline constexpr char const PROXY_PARAMETER_NAME[] = "$proxy_mask$"; +// NOLINTEND(modernize-avoid-c-arrays) + class ETSParameterExpression final : public Expression { public: ETSParameterExpression() = delete; @@ -64,6 +68,16 @@ public: return spread_ != nullptr; } + [[nodiscard]] std::size_t GetRequiredParams() const noexcept + { + return extra_value_; + } + + void SetRequiredParams(std::size_t const value) noexcept + { + extra_value_ = value; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] ETSParameterExpression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; @@ -80,6 +94,7 @@ private: Expression *initializer_; SpreadElement *spread_ = nullptr; util::StringView saved_lexer_ = ""; + std::size_t extra_value_ = 0U; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 0becad2529..5d2da9eaaf 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2205,13 +2205,15 @@ void ETSParser::CreateClassFunctionDeclaration(ir::MethodDefinition *method) method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); } -bool ETSParser::HasDefaultParam(const ir::ScriptFunction *const function) +std::pair ETSParser::CheckDefaultParameters(const ir::ScriptFunction *const function) const { bool has_default_parameter = false; bool has_rest_parameter = false; + std::size_t required_parameters_number = 0U; for (auto *const it : function->Params()) { auto const *const param = it->AsETSParameterExpression(); + if (param->IsRestParameter()) { has_rest_parameter = true; continue; @@ -2229,23 +2231,58 @@ bool ETSParser::HasDefaultParam(const ir::ScriptFunction *const function) if (has_default_parameter) { ThrowSyntaxError("Required parameter follows default parameter(s).", param->Start()); } - } - if (!has_default_parameter) { - return false; + ++required_parameters_number; } - if (has_rest_parameter) { + if (has_default_parameter && has_rest_parameter) { ThrowSyntaxError("Both optional and rest parameters are not allowed in function's parameter list.", function->Start()); } - return true; + return std::make_pair(has_default_parameter, required_parameters_number); } -std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const function, ir::MethodDefinition *method, - ir::Identifier *ident_node, varbinder::ClassScope *const cls_scope) +ir::MethodDefinition *ETSParser::CreateProxyConstructorDefinition(ir::MethodDefinition const *const method) { + ASSERT(method->IsConstructor()); + + const auto *const function = method->Function(); + std::string proxy_method = function->Id()->Name().Mutf8() + '('; + + for (const auto *const it : function->Params()) { + auto const *const param = it->AsETSParameterExpression(); + proxy_method += param->Ident()->Name().Mutf8() + ": " + GetNameForTypeNode(param->TypeAnnotation()) + ", "; + } + + proxy_method += ir::PROXY_PARAMETER_NAME; + proxy_method += ": int) { this("; + + auto const parameters_number = function->Params().size(); + for (size_t i = 0U; i < parameters_number; ++i) { + if (auto const *const param = function->Params()[i]->AsETSParameterExpression(); param->IsDefault()) { + std::string proxy_if = "(((" + std::string {ir::PROXY_PARAMETER_NAME} + " >> " + std::to_string(i) + + ") & 0x1) == 0) ? " + param->Ident()->Name().Mutf8() + " : (" + + param->LexerSaved().Mutf8() + "), "; + proxy_method += proxy_if; + } else { + proxy_method += function->Params()[i]->AsETSParameterExpression()->Ident()->Name().Mutf8() + ", "; + } + } + + proxy_method.pop_back(); // Note: at least one parameter always should present! + proxy_method.pop_back(); + proxy_method += ") }"; + + return CreateConstructorDefinition(method->Modifiers(), proxy_method, DEFAULT_PROXY_FILE); +} + +ir::MethodDefinition *ETSParser::CreateProxyMethodDefinition(ir::MethodDefinition const *const method, + ir::Identifier const *const ident_node) +{ + ASSERT(!method->IsConstructor()); + + const auto *const function = method->Function(); std::string proxy_method = function->Id()->Name().Mutf8() + "_proxy("; for (const auto *const it : function->Params()) { @@ -2253,32 +2290,42 @@ std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const fun proxy_method += param->Ident()->Name().Mutf8() + ": " + GetNameForTypeNode(param->TypeAnnotation()) + ", "; } - const bool has_function_return_type = method->Function()->ReturnTypeAnnotation() != nullptr; + const bool has_function_return_type = function->ReturnTypeAnnotation() != nullptr; const std::string return_type = - has_function_return_type ? GetNameForTypeNode(method->Function()->ReturnTypeAnnotation()) : ""; + has_function_return_type ? GetNameForTypeNode(function->ReturnTypeAnnotation()) : ""; - proxy_method += has_function_return_type ? "proxy_int:int):" + return_type + "{" : "proxy_int:int) {"; + proxy_method += ir::PROXY_PARAMETER_NAME; + proxy_method += ": int)"; + if (has_function_return_type) { + proxy_method += ": " + return_type; + } + proxy_method += " { "; auto const parameters_number = function->Params().size(); - for (size_t i = 0U; i < parameters_number; i++) { + for (size_t i = 0U; i < parameters_number; ++i) { if (auto const *const param = function->Params()[i]->AsETSParameterExpression(); param->IsDefault()) { - std::string proxy_if = "if (((proxy_int >> " + std::to_string(i) + ") & 0x1) == 1) { " + - param->Ident()->Name().Mutf8() + " = " + param->LexerSaved().Mutf8() + " }"; + std::string proxy_if = "if (((" + std::string {ir::PROXY_PARAMETER_NAME} + " >> " + std::to_string(i) + + ") & 0x1) == 1) { " + param->Ident()->Name().Mutf8() + " = " + + param->LexerSaved().Mutf8() + " } "; proxy_method += proxy_if; } } + proxy_method += ' '; if (return_type != "void") { - if (cls_scope->Parent()->IsGlobalScope()) { + if (auto *const cls_scope = VarBinder()->GetScope()->AsClassScope(); cls_scope->Parent()->IsGlobalScope()) { proxy_method += "return "; } else if (method->IsStatic()) { + ASSERT(ident_node != nullptr); proxy_method += "return " + ident_node->Name().Mutf8() + "."; } else { proxy_method += "return this."; } } - proxy_method += function->Id()->Name().Mutf8() + "("; + proxy_method += function->Id()->Name().Mutf8(); + proxy_method += '('; + for (const auto *const it : function->Params()) { proxy_method += it->AsETSParameterExpression()->Ident()->Name().Mutf8() + ", "; } @@ -2286,39 +2333,34 @@ std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const fun proxy_method.pop_back(); proxy_method += ") }"; - return proxy_method; + return CreateMethodDefinition(method->Modifiers(), proxy_method, DEFAULT_PROXY_FILE); } void ETSParser::AddProxyOverloadToMethodWithDefaultParams(ir::MethodDefinition *method, ir::Identifier *ident_node) { - if (method->IsConstructor()) { - return; // NOTE(szd): Fix constructors not working with default params - } - - const auto *const function = method->Function(); + if (auto const [has_default_parameters, required_parameters] = CheckDefaultParameters(method->Function()); + has_default_parameters) { + if (ir::MethodDefinition *proxy_method_def = !method->IsConstructor() + ? CreateProxyMethodDefinition(method, ident_node) + : CreateProxyConstructorDefinition(method); + proxy_method_def != nullptr) { + auto *const proxy_param = proxy_method_def->Function()->Params().back()->AsETSParameterExpression(); + proxy_param->SetRequiredParams(required_parameters); - if (!HasDefaultParam(function)) { - return; - } + proxy_method_def->Function()->SetDefaultParamProxy(); + proxy_method_def->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); - auto *const cls_scope = VarBinder()->GetScope()->AsClassScope(); - varbinder::LocalScope *target_scope = - method->IsStatic() ? cls_scope->StaticMethodScope() : cls_scope->InstanceMethodScope(); - auto *const found = target_scope->FindLocal(method->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS); + auto *const var = method->Id()->Variable(); + auto *const current_node = var->Declaration()->Node(); - std::string proxy_method = CreateProxyMethodName(function, method, ident_node, cls_scope); + proxy_method_def->Id()->SetVariable(var); + proxy_method_def->SetParent(current_node); - auto class_ctx = - varbinder::LexicalScope::Enter(VarBinder(), GetProgram()->GlobalClassScope()); - - auto *const proxy_method_def = CreateMethodDefinition(method->Modifiers(), proxy_method, ".ets"); - proxy_method_def->Function()->SetDefaultParamProxy(); - - auto *const current_node = found->Declaration()->Node(); - current_node->AsMethodDefinition()->AddOverload(proxy_method_def); - proxy_method_def->Id()->SetVariable(found); - proxy_method_def->SetParent(current_node); - proxy_method_def->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + if (!method->IsConstructor()) { + current_node->AsMethodDefinition()->AddOverload(proxy_method_def); + } + } + } } std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) @@ -2347,7 +2389,7 @@ std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) } } -std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *type_annotation) +std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *type_annotation) const { if ((type_annotation->IsNullAssignable() || type_annotation->IsUndefinedAssignable()) && type_annotation->IsETSUnionType()) { @@ -4765,6 +4807,39 @@ ir::MethodDefinition *ETSParser::CreateMethodDefinition(ir::ModifierFlags modifi return method_definition; } +ir::MethodDefinition *ETSParser::CreateConstructorDefinition(ir::ModifierFlags modifiers, + std::string_view const source_code, + std::string_view const file_name) +{ + util::UString source {source_code, Allocator()}; + auto const isp = InnerSourceParser(this); + auto const lexer = InitLexer({file_name, source.View().Utf8()}); + + auto const start_loc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + if (IsClassMethodModifier(Lexer()->GetToken().Type())) { + modifiers |= ParseClassMethodModifiers(false); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_CONSTRUCTOR) { + ThrowSyntaxError({"Unexpected token. 'Constructor' keyword is expected."}); + } + + if ((modifiers & ir::ModifierFlags::ASYNC) != 0) { + ThrowSyntaxError({"Constructor should not be async."}); + } + + auto *member_name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + modifiers |= ir::ModifierFlags::CONSTRUCTOR; + Lexer()->NextToken(); + + auto *const method_definition = ParseClassMethodDefinition(member_name, modifiers); + method_definition->SetStart(start_loc); + + return method_definition; +} + ir::Expression *ETSParser::CreateExpression(std::string_view const source_code, ExpressionParseFlags const flags, std::string_view const file_name) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index cf643c0d57..a2716bef27 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -170,12 +170,13 @@ private: ir::TypeNode *ParseWildcardType(TypeAnnotationParsingOptions *options); ir::TypeNode *ParseFunctionType(); void CreateClassFunctionDeclaration(ir::MethodDefinition *method); - bool HasDefaultParam(const ir::ScriptFunction *function); - std::string CreateProxyMethodName(const ir::ScriptFunction *function, ir::MethodDefinition *method, - ir::Identifier *ident_node, varbinder::ClassScope *cls_scope); + std::pair CheckDefaultParameters(const ir::ScriptFunction *function) const; + ir::MethodDefinition *CreateProxyMethodDefinition(ir::MethodDefinition const *method, + ir::Identifier const *ident_node); + ir::MethodDefinition *CreateProxyConstructorDefinition(ir::MethodDefinition const *method); void AddProxyOverloadToMethodWithDefaultParams(ir::MethodDefinition *method, ir::Identifier *ident_node = nullptr); static std::string PrimitiveTypeToName(ir::PrimitiveType type); - std::string GetNameForTypeNode(const ir::TypeNode *type_annotation); + std::string GetNameForTypeNode(const ir::TypeNode *type_annotation) const; ir::TSInterfaceDeclaration *ParseInterfaceBody(ir::Identifier *name, bool is_static); bool IsArrowFunctionExpressionStart(); ir::ArrowFunctionExpression *ParseArrowFunctionExpression(); @@ -307,10 +308,14 @@ private: void CheckDeclare(); - // Methods to create AST node(s) from the specified string (part of valid ETS-code!) - // NOTE: the correct initial scope should be entered BEFORE calling any of these methods, - // and correct parent and, probably, variable set to the node(s) after obtaining - + // Methods to create AST node(s) from the specified string (part of valid ETS-code!) + // NOTE: the correct initial scope should be entered BEFORE calling any of these methods, + // and correct parent and, probably, variable set to the node(s) after obtaining + // NOLINTBEGIN(modernize-avoid-c-arrays) + inline static constexpr char const DEFAULT_SOURCE_FILE[] = ".ets"; + inline static constexpr char const DEFAULT_PROXY_FILE[] = ".ets"; + // NOLINTEND(modernize-avoid-c-arrays) + // NOLINTBEGIN(google-default-arguments) ir::Statement *CreateStatement(std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view source_code, std::vector &inserting_nodes, std::string_view file_name = DEFAULT_SOURCE_FILE); @@ -326,7 +331,8 @@ private: ir::MethodDefinition *CreateMethodDefinition(ir::ModifierFlags modifiers, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); - + ir::MethodDefinition *CreateConstructorDefinition(ir::ModifierFlags modifiers, std::string_view source_code, + std::string_view file_name = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); diff --git a/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt b/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt index ca7577b0c3..9924e957d6 100644 --- a/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt +++ b/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt @@ -513,7 +513,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -608,7 +608,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter1-expected.txt b/ets2panda/test/parser/ets/default_parameter1-expected.txt index 70a65a1979..edf5d5438e 100644 --- a/ets2panda/test/parser/ets/default_parameter1-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter1-expected.txt @@ -691,7 +691,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -758,7 +758,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter2-expected.txt b/ets2panda/test/parser/ets/default_parameter2-expected.txt index 0267fc1b3f..96e2d6dcdf 100644 --- a/ets2panda/test/parser/ets/default_parameter2-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter2-expected.txt @@ -676,7 +676,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -743,7 +743,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter4-expected.txt b/ets2panda/test/parser/ets/default_parameter4-expected.txt index 35457f1bc8..5c072e7bcd 100644 --- a/ets2panda/test/parser/ets/default_parameter4-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter4-expected.txt @@ -816,7 +816,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -883,7 +883,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1067,7 +1067,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1656,7 +1656,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -1723,7 +1723,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter5-expected.txt b/ets2panda/test/parser/ets/default_parameter5-expected.txt index c7eec11850..ab0a5a6760 100644 --- a/ets2panda/test/parser/ets/default_parameter5-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter5-expected.txt @@ -861,7 +861,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -928,7 +928,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt b/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt index fcf3644024..1e35125767 100644 --- a/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt @@ -690,7 +690,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -744,7 +744,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -928,7 +928,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt index 9dcbe17e90..87a53b8d5a 100644 --- a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt +++ b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt @@ -793,7 +793,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -860,7 +860,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/runtime/ets/default_parameters.ets b/ets2panda/test/runtime/ets/default_parameters.ets new file mode 100644 index 0000000000..a660a80c04 --- /dev/null +++ b/ets2panda/test/runtime/ets/default_parameters.ets @@ -0,0 +1,49 @@ +/* + * 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(a: int = 3, b: int = 5): int { + return a * 10 + b; +} + +class C { + x: int; + y: int; + + constructor (a: int = 3, b: int = 5) { + this.x = a; + this.y = b; + } +} + +function main(): void { + + let res = foo(5, 7); + assert (res == 57); + + res = foo(7); + assert (res == 75); + + res = foo(); + assert (res == 35); + + let c0 = new C(); + assert (c0.x == 3 && c0.y == 5); + + let c1 = new C(7); + assert (c1.x == 7 && c1.y == 5); + + let c2 = new C(5, 7); + assert (c2.x == 5 && c2.y == 7); +} -- Gitee From 2c90854caf98b4b2ce749d6d1e9797b3f8459d09 Mon Sep 17 00:00:00 2001 From: Maxim Logaev Date: Mon, 27 Nov 2023 13:52:47 +0300 Subject: [PATCH 4/9] Fixed bug #I8G6U5 Signed-off-by: Maxim Logaev --- ets2panda/checker/ets/helpers.cpp | 4 ++++ .../test/compiler/ets/voidTypeInBinaryOperation-expected.txt | 1 + 2 files changed, 5 insertions(+) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index d1e74e0835..c1d3dec4fc 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -75,6 +75,10 @@ void ETSChecker::CheckTruthinessOfType(ir::Expression *expr) checker::Type *type = expr->Check(this); auto *unboxed_type = ETSBuiltinTypeAsConditionalType(type); + if (unboxed_type == GlobalBuiltinVoidType() || unboxed_type->IsETSVoidType()) { + ThrowTypeError("An expression of type 'void' cannot be tested for truthiness", expr->Start()); + } + if (unboxed_type != nullptr && !unboxed_type->IsConditionalExprType()) { ThrowTypeError("Condition must be of possible condition type", expr->Start()); } diff --git a/ets2panda/test/compiler/ets/voidTypeInBinaryOperation-expected.txt b/ets2panda/test/compiler/ets/voidTypeInBinaryOperation-expected.txt index 9447d6cad0..b434ae012c 100644 --- a/ets2panda/test/compiler/ets/voidTypeInBinaryOperation-expected.txt +++ b/ets2panda/test/compiler/ets/voidTypeInBinaryOperation-expected.txt @@ -494,3 +494,4 @@ } } } +TypeError: An expression of type 'void' cannot be tested for truthiness [voidTypeInBinaryOperation.ets:20:19] -- Gitee From 0b868757c5dee62cfc8ce5b2d29b9a69fcd65e7e Mon Sep 17 00:00:00 2001 From: Molokanov Yaroslav Date: Mon, 23 Oct 2023 18:17:42 +0300 Subject: [PATCH 5/9] Implemented auto-boxing for primitive types in ets Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8D0AZ Test: .../test/runtime/ets/autoboxing.ets Signed-off-by: Molokanov Yaroslav --- ets2panda/checker/ets/helpers.cpp | 2 +- ets2panda/compiler/core/ETSCompiler.cpp | 4 ++- ets2panda/ir/expressions/memberExpression.cpp | 9 +++++ ets2panda/test/runtime/ets/autoboxing.ets | 35 +++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 ets2panda/test/runtime/ets/autoboxing.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index c1d3dec4fc..97b3b385f2 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -443,7 +443,7 @@ void ETSChecker::ValidateResolvedIdentifier(ir::Identifier *const ident, varbind if (!resolved_type->IsETSObjectType() && !resolved_type->IsETSArrayType() && !resolved_type->IsETSEnumType() && !resolved_type->IsETSStringEnumType() && - !resolved_type->IsETSUnionType()) { + !resolved_type->IsETSUnionType() && !resolved_type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { throw_error(); } diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 6ee70ad191..7df01ed603 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -524,7 +524,9 @@ void ETSCompiler::CompileDynamic(const ir::CallExpression *expr, compiler::VReg void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &callee_reg, bool is_static) const { ETSGen *etsg = GetETSGen(); - + if (expr->Callee()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) { + etsg->ApplyConversionAndStoreAccumulator(expr->Callee(), callee_reg, nullptr); + } if (is_static) { etsg->CallStatic(expr, expr->Signature(), expr->Arguments()); } else if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::PRIVATE) || expr->IsETSConstructorCall() || diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index eda32a4f54..a308acfd14 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -451,6 +451,15 @@ checker::Type *MemberExpression::Check(checker::ETSChecker *checker) return AdjustOptional(checker, CheckUnionMember(checker, base_type)); } + if (base_type->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + checker->Relation()->SetNode(this); + SetObjectType(checker->PrimitiveTypeAsETSBuiltinType(base_type)->AsETSObjectType()); + checker->AddBoxingUnboxingFlagToNode(this, obj_type_); + auto [res_type, res_var] = ResolveObjectMember(checker); + SetPropVar(res_var); + return AdjustOptional(checker, res_type); + } + checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, object_->Start()); } diff --git a/ets2panda/test/runtime/ets/autoboxing.ets b/ets2panda/test/runtime/ets/autoboxing.ets new file mode 100644 index 0000000000..f66dbbb41b --- /dev/null +++ b/ets2panda/test/runtime/ets/autoboxing.ets @@ -0,0 +1,35 @@ +/* + * 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 foo_i(value: int): string { + return value.toString(); +} + +function foo_d(value: double): string { + return value.toString(); +} + +function foo_n(value: number): string { + return value.toString(); +} + +function main(): void { + let str_i: string = foo_i(4); + assert str_i == "4"; + let str_d: string = foo_d(3.14); + assert str_d == "3.14"; + let str_n: string = foo_n(5); + assert str_n == "5"; +} \ No newline at end of file -- Gitee From 12fe62e039b48404610654435473d537d4527529 Mon Sep 17 00:00:00 2001 From: Robert Sipka Date: Mon, 13 Nov 2023 15:18:10 +0100 Subject: [PATCH 6/9] [ETS] Minor fix for es2panda path in coverage measurement Signed-off-by: Robert Sipka --- ets2panda/cmake/coverage.cmake | 6 +++++- ets2panda/scripts/es2panda_coverage.sh | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ets2panda/cmake/coverage.cmake b/ets2panda/cmake/coverage.cmake index 8464c0fed8..794bf7a6e7 100644 --- a/ets2panda/cmake/coverage.cmake +++ b/ets2panda/cmake/coverage.cmake @@ -17,9 +17,13 @@ include(${PANDA_ROOT}/cmake/toolchain/coverage/unit_tests_lcov.cmake) add_custom_target(es2panda_coverage DEPENDS etsstdlib es2panda verifier ark) +if (NOT DEFINED ES2PANDA_PATH) + set(ES2PANDA_PATH ${PANDA_ROOT}/tools/es2panda) +endif() + add_custom_command(TARGET es2panda_coverage POST_BUILD WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND bash ${PANDA_ROOT}/plugins/ecmascript/es2panda/scripts/es2panda_coverage.sh --binary-dir=${PANDA_BINARY_ROOT} --root-dir=${PANDA_ROOT} + COMMAND bash ${ES2PANDA_PATH}/scripts/es2panda_coverage.sh --binary-dir=${PANDA_BINARY_ROOT} --root-dir=${PANDA_ROOT} ) if(ENABLE_ES2PANDA_COVERAGE) diff --git a/ets2panda/scripts/es2panda_coverage.sh b/ets2panda/scripts/es2panda_coverage.sh index 9af403a22b..a299f1c515 100644 --- a/ets2panda/scripts/es2panda_coverage.sh +++ b/ets2panda/scripts/es2panda_coverage.sh @@ -26,16 +26,16 @@ case "$ARGUMENT" in esac done -python $PANDA_ROOT/plugins/ecmascript/es2panda/scripts/test_runner.py \ +python $PANDA_ROOT/tools/es2panda/scripts/test_runner.py \ --builddir $PANDA_BINARY_ROOT --arkdir $PANDA_ROOT --all -gcov $PANDA_BINARY_ROOT/plugins/ecmascript/es2panda/CMakeFiles/es2panda-lib.dir/*/* +gcov $PANDA_BINARY_ROOT/tools/es2panda/CMakeFiles/es2panda-lib.dir/*/* if [ -x "$(command -v gcovr)" ]; then echo "gcovr found" gcovr --version - gcovr -v -r $PANDA_ROOT/plugins/ecmascript/es2panda \ - -e $PANDA_ROOT/plugins/ecmascript/es2panda/test \ + gcovr -v -r $PANDA_ROOT/tools/es2panda/ \ + -e $PANDA_ROOT/tools/es2panda/test \ --object-directory=$PANDA_BINARY_ROOT --html-details --html -o report.html else -- Gitee From 80439b9c252e62122a01e37cc4033976ed03adff Mon Sep 17 00:00:00 2001 From: Anton Berezin Date: Thu, 16 Nov 2023 11:54:12 +0400 Subject: [PATCH 7/9] Fix bug of assigning primitive to Number. Allow widening for boxed source type. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8EZ44 Signed-off-by: Anton Berezin --- ets2panda/checker/ets/helpers.cpp | 4 ++-- .../runtime/ets/number-from-narrow-prim.ets | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 ets2panda/test/runtime/ets/number-from-narrow-prim.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 97b3b385f2..dd678cbfa3 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1793,7 +1793,7 @@ void ETSChecker::CheckUnboxedTypesAssignable(TypeRelation *relation, Type *sourc void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *source, Type *target) { checker::SavedTypeRelationFlagsContext saved_type_relation_flag_ctx( - relation, TypeRelationFlag::ONLY_CHECK_WIDENING | + relation, (relation->ApplyWidening() ? TypeRelationFlag::WIDENING : TypeRelationFlag::NONE) | (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE)); auto *boxed_source_type = relation->GetChecker()->AsETSChecker()->PrimitiveTypeAsETSBuiltinType(source); if (boxed_source_type == nullptr) { @@ -1811,7 +1811,7 @@ void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *so if (unboxed_target_type == nullptr) { return; } - NarrowingConverter(this, relation, unboxed_target_type, source); + NarrowingWideningConverter(this, relation, unboxed_target_type, source); if (relation->IsTrue()) { AddBoxingFlagToPrimitiveType(relation, target); } diff --git a/ets2panda/test/runtime/ets/number-from-narrow-prim.ets b/ets2panda/test/runtime/ets/number-from-narrow-prim.ets new file mode 100644 index 0000000000..0c4744297c --- /dev/null +++ b/ets2panda/test/runtime/ets/number-from-narrow-prim.ets @@ -0,0 +1,24 @@ +/* + * 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. + * + * + * Based on https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8EZ44 + */ + + +function main() { + let n: Number = 5 + + assert n == 5 +} -- Gitee From 9658417c675cb80d67d34f50d38bcc07d779a145 Mon Sep 17 00:00:00 2001 From: zhaoziming Date: Mon, 27 Nov 2023 16:23:54 +0800 Subject: [PATCH 8/9] Implement stricter function override validation Signed-off-by: zhaoziming --- ets2panda/checker/ETSchecker.h | 4 + ets2panda/checker/checker.h | 5 + ets2panda/checker/types/signature.cpp | 124 +- ets2panda/checker/types/signature.h | 1 + .../ets/default_parameter1-expected.txt | 2 +- .../ets/default_parameter2-expected.txt | 2 +- .../ets/default_parameter4-expected.txt | 2 +- .../ets/default_parameter6-expected.txt | 2637 +++++++++++++++++ .../test/parser/ets/default_parameter6.ets | 24 + .../ets/default_parameter7-expected.txt | 1655 +++++++++++ .../test/parser/ets/default_parameter7.ets | 24 + ets2panda/test/runtime/ets/DefaultParam_1.ets | 34 - ets2panda/test/runtime/ets/DefaultParam_2.ets | 33 - ets2panda/test/runtime/ets/DefaultParam_4.ets | 33 - 14 files changed, 4437 insertions(+), 143 deletions(-) create mode 100644 ets2panda/test/parser/ets/default_parameter6-expected.txt create mode 100644 ets2panda/test/parser/ets/default_parameter6.ets create mode 100644 ets2panda/test/parser/ets/default_parameter7-expected.txt create mode 100644 ets2panda/test/parser/ets/default_parameter7.ets diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index e6acf295cc..3dd9b2fe45 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -124,6 +124,10 @@ public: Type *CheckTypeCached(ir::Expression *expr) override; void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} Type *GetTypeOfVariable([[maybe_unused]] varbinder::Variable *var) override; + bool IsETSChecker() override + { + return true; + } // Object ETSObjectType *BuildClassProperties(ir::ClassDefinition *class_def); diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index 9927c78589..5113779226 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -139,6 +139,11 @@ public: return type_stack_; } + virtual bool IsETSChecker() + { + return false; + } + ETSChecker *AsETSChecker() { return reinterpret_cast(this); diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index ab2188c6c0..79019e3787 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -172,12 +172,44 @@ void Signature::ToString(std::stringstream &ss, const varbinder::Variable *varia return_type_->ToString(ss); } +namespace { +std::size_t GetToCheckParamCount(Signature *signature, bool is_ets) +{ + auto param_number = static_cast(signature->Params().size()); + if (!is_ets || signature->Function() == nullptr) { + return param_number; + } + for (auto i = param_number - 1; i >= 0; i--) { + if (!signature->Function()->Params()[i]->AsETSParameterExpression()->IsDefault()) { + return static_cast(i + 1); + } + } + return 0; +} +} // namespace + +bool Signature::IdenticalParameter(TypeRelation *relation, Type *type1, Type *type2) +{ + if (!CheckFunctionalInterfaces(relation, type1, type2)) { + relation->IsIdenticalTo(type1, type2); + } + return relation->IsTrue(); +} + void Signature::Identical(TypeRelation *relation, Signature *other) { - if ((this->MinArgCount() != other->MinArgCount() || this->Params().size() != other->Params().size()) && + bool is_ets = relation->GetChecker()->IsETSChecker(); + auto const this_to_check_parameters_number = GetToCheckParamCount(this, is_ets); + auto const other_to_check_parameters_number = GetToCheckParamCount(other, is_ets); + if ((this_to_check_parameters_number != other_to_check_parameters_number || + this->MinArgCount() != other->MinArgCount()) && this->RestVar() == nullptr && other->RestVar() == nullptr) { - relation->Result(false); - return; + // skip check for ets cases only when all parameters are mandatory + if (!is_ets || (this_to_check_parameters_number == this->Params().size() && + other_to_check_parameters_number == other->Params().size())) { + relation->Result(false); + return; + } } if (relation->NoReturnTypeCheck()) { @@ -187,51 +219,63 @@ void Signature::Identical(TypeRelation *relation, Signature *other) } if (relation->IsTrue()) { - // Lambda to check parameter types - auto const identical_parameters = [this, relation](checker::Type *const type1, - checker::Type *const type2) -> bool { - if (!CheckFunctionalInterfaces(relation, type1, type2)) { - relation->IsIdenticalTo(type1, type2); - } - return relation->IsTrue(); - }; - - auto const this_parameters_number = this->Params().size(); - auto const other_parameters_number = other->Params().size(); - auto const parameters_number = std::min(this_parameters_number, other_parameters_number); + /* In ETS, the functions "foo(a: int)" and "foo(a: int, b: int = 1)" should be considered as having an + equivalent signature. Hence, we only need to check if the mandatory parameters of the signature with + more mandatory parameters can match the parameters of the other signature (including the optional + parameter or rest parameters) here. + + XXX_to_check_parameters_number is calculated beforehand by counting mandatory parameters. + Signature::params() stores all parameters (mandatory and optional), excluding the rest parameter. + Signature::restVar() stores the rest parameters of the function. + + For example: + foo(a: int): params().size: 1, to_check_param_number: 1, restVar: nullptr + foo(a: int, b: int = 0): params().size: 2, to_check_param_number: 1, restVar: nullptr + foo(a: int, ...b: int[]): params().size: 1, to_check_param_number: 1, restVar: ...b: int[] + + Note that optional parameters always come after mandatory parameters, and signatures containing both + optional and rest parameters are not allowed. + + "to_check_parameters_number" is the number of parameters that need to be checked to ensure identical. + "parameters_number" is the number of parameters that can be checked in Signature::params(). + */ + auto const to_check_parameters_number = + std::max(this_to_check_parameters_number, other_to_check_parameters_number); + auto const parameters_number = + std::min({this->Params().size(), other->Params().size(), to_check_parameters_number}); std::size_t i = 0U; for (; i < parameters_number; ++i) { - auto *const this_sig_param_type = this->Params()[i]->TsType(); - auto *const other_sig_param_type = other->Params()[i]->TsType(); - if (!identical_parameters(this_sig_param_type, other_sig_param_type)) { + if (!IdenticalParameter(relation, this->Params()[i]->TsType(), other->Params()[i]->TsType())) { return; } } - // Lambda to check the rest parameters - auto const identical_rest_parameters = - [&i, &identical_parameters, relation](std::size_t const parameter_number, - ArenaVector const ¶meters, - varbinder::LocalVariable const *const rest_parameter) -> void { - if (rest_parameter != nullptr) { - auto *const other_sig_param_type = rest_parameter->TsType()->AsETSArrayType()->ElementType(); - - for (; i < parameter_number; ++i) { - auto *const this_sig_param_type = parameters[i]->TsType(); - if (!identical_parameters(this_sig_param_type, other_sig_param_type)) { - break; - } - } - } else { - relation->Result(false); + /* "i" could be one of the following three cases: + 1. == to_check_parameters_number, we have finished the checking and can directly return. + 2. == other->Params().size(), must be < this_to_check_parameters_number in this case since + xxx->Params().size() always >= xxx_to_check_parameters_number. We need to check the remaining + mandatory parameters of "this" against ths RestVar of "other". + 3. == this->Params().size(), must be < other_to_check_parameters_number as described in 2, and + we need to check the remaining mandatory parameters of "other" against the RestVar of "this". + */ + if (i == to_check_parameters_number) { + return; + } + bool is_other_mandatory_params_matched = i < this_to_check_parameters_number; + ArenaVector const ¶meters = + is_other_mandatory_params_matched ? this->Params() : other->Params(); + varbinder::LocalVariable const *rest_parameter = + is_other_mandatory_params_matched ? other->RestVar() : this->RestVar(); + if (rest_parameter == nullptr) { + relation->Result(false); + return; + } + auto *const rest_parameter_type = rest_parameter->TsType()->AsETSArrayType()->ElementType(); + for (; i < to_check_parameters_number; ++i) { + if (!IdenticalParameter(relation, parameters[i]->TsType(), rest_parameter_type)) { + return; } - }; - - if (i < this_parameters_number) { - identical_rest_parameters(this_parameters_number, this->Params(), other->RestVar()); - } else if (i < other_parameters_number) { - identical_rest_parameters(other_parameters_number, other->Params(), this->RestVar()); } } } diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index 2341dd5745..161325c6a0 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -250,6 +250,7 @@ public: void AssignmentTarget(TypeRelation *relation, Signature *source); private: + bool IdenticalParameter(TypeRelation *relation, Type *type1, Type *type2); checker::SignatureInfo *signature_info_; Type *return_type_; ir::ScriptFunction *func_ {}; diff --git a/ets2panda/test/parser/ets/default_parameter1-expected.txt b/ets2panda/test/parser/ets/default_parameter1-expected.txt index edf5d5438e..41c4146c87 100644 --- a/ets2panda/test/parser/ets/default_parameter1-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter1-expected.txt @@ -1276,4 +1276,4 @@ } } } -TypeError: Reference to foo is ambiguous [default_parameter1.ets:18:5] +TypeError: Function already declared. [default_parameter1.ets:26:1] diff --git a/ets2panda/test/parser/ets/default_parameter2-expected.txt b/ets2panda/test/parser/ets/default_parameter2-expected.txt index 96e2d6dcdf..1bc729dc18 100644 --- a/ets2panda/test/parser/ets/default_parameter2-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter2-expected.txt @@ -1261,4 +1261,4 @@ } } } -TypeError: No matching call signature [default_parameter2.ets:18:5] +TypeError: Function already declared. [default_parameter2.ets:26:1] diff --git a/ets2panda/test/parser/ets/default_parameter4-expected.txt b/ets2panda/test/parser/ets/default_parameter4-expected.txt index 5c072e7bcd..9ddd359583 100644 --- a/ets2panda/test/parser/ets/default_parameter4-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter4-expected.txt @@ -2048,4 +2048,4 @@ } } } -TypeError: Reference to foo is ambiguous [default_parameter4.ets:18:5] +TypeError: Function already declared. [default_parameter4.ets:26:1] diff --git a/ets2panda/test/parser/ets/default_parameter6-expected.txt b/ets2panda/test/parser/ets/default_parameter6-expected.txt new file mode 100644 index 0000000000..caaeb8826a --- /dev/null +++ b/ets2panda/test/parser/ets/default_parameter6-expected.txt @@ -0,0 +1,2637 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 27 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 27 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 27 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 23 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 20, + "loc": { + "start": { + "line": 16, + "column": 33 + }, + "end": { + "line": 16, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 23 + }, + "end": { + "line": 16, + "column": 35 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 41 + }, + "end": { + "line": 16, + "column": 44 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 41 + }, + "end": { + "line": 16, + "column": 46 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 41 + }, + "end": { + "line": 16, + "column": 46 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 37 + }, + "end": { + "line": 16, + "column": 46 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 30, + "loc": { + "start": { + "line": 16, + "column": 47 + }, + "end": { + "line": 16, + "column": 49 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 37 + }, + "end": { + "line": 16, + "column": 49 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 53 + }, + "end": { + "line": 16, + "column": 56 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 53 + }, + "end": { + "line": 17, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 53 + }, + "end": { + "line": 17, + "column": 2 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "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": true, + "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": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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_int", + "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": "Int", + "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 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "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 + } + } + }, + "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": "b", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 20, + "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": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 2, + "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": "c", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 30, + "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": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "c", + "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 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 10 + }, + "end": { + "line": 21, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 10 + }, + "end": { + "line": 21, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 27 + }, + "end": { + "line": 21, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 27 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 27 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 23 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "initializer": { + "type": "StringLiteral", + "value": "a", + "loc": { + "start": { + "line": 21, + "column": 36 + }, + "end": { + "line": 21, + "column": 39 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 23 + }, + "end": { + "line": 21, + "column": 39 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 45 + }, + "end": { + "line": 21, + "column": 48 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 45 + }, + "end": { + "line": 21, + "column": 50 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 45 + }, + "end": { + "line": 21, + "column": 50 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 41 + }, + "end": { + "line": 21, + "column": 50 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 30, + "loc": { + "start": { + "line": 21, + "column": 51 + }, + "end": { + "line": 21, + "column": 53 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 41 + }, + "end": { + "line": 21, + "column": 53 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 57 + }, + "end": { + "line": 21, + "column": 60 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 57 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 57 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 23, + "column": 12 + }, + "end": { + "line": 23, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 13 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 13 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + { + "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": true, + "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": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "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": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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_int", + "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": "Int", + "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 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "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 + } + } + }, + "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": "b", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "StringLiteral", + "value": "a", + "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": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 2, + "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": "c", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 30, + "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": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "c", + "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": 16, + "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": 25, + "column": 1 + } + } +} +TypeError: Function already declared. [default_parameter6.ets:21:1] diff --git a/ets2panda/test/parser/ets/default_parameter6.ets b/ets2panda/test/parser/ets/default_parameter6.ets new file mode 100644 index 0000000000..2cb74c5e65 --- /dev/null +++ b/ets2panda/test/parser/ets/default_parameter6.ets @@ -0,0 +1,24 @@ +/* + * 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 foo(a : Int, b : Int = 20, c : Int = 30) : Int +{ + return 1; +} + +function foo(a : Int, b : string = "a", c : Int = 30) : Int +{ + return 2; +} diff --git a/ets2panda/test/parser/ets/default_parameter7-expected.txt b/ets2panda/test/parser/ets/default_parameter7-expected.txt new file mode 100644 index 0000000000..ef5625ac46 --- /dev/null +++ b/ets2panda/test/parser/ets/default_parameter7-expected.txt @@ -0,0 +1,1655 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 21 + }, + "end": { + "line": 16, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 26 + }, + "end": { + "line": 16, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 27 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 30 + }, + "end": { + "line": 16, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 30 + }, + "end": { + "line": 17, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 30 + }, + "end": { + "line": 17, + "column": 2 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 18, + "column": 12 + }, + "end": { + "line": 18, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "overloads": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 10 + }, + "end": { + "line": 21, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 10 + }, + "end": { + "line": 21, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 21, + "column": 22 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "String", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 28 + }, + "end": { + "line": 21, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 28 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 28 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 23 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "initializer": { + "type": "UndefinedLiteral", + "value": undefined, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 23 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 40 + }, + "end": { + "line": 21, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 40 + }, + "end": { + "line": 21, + "column": 45 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 40 + }, + "end": { + "line": 21, + "column": 45 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 36 + }, + "end": { + "line": 21, + "column": 45 + } + } + }, + "initializer": { + "type": "NumberLiteral", + "value": 30, + "loc": { + "start": { + "line": 21, + "column": 46 + }, + "end": { + "line": 21, + "column": 48 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 36 + }, + "end": { + "line": 21, + "column": 48 + } + } + } + ], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 52 + }, + "end": { + "line": 21, + "column": 55 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 52 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 52 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 23, + "column": 12 + }, + "end": { + "line": 23, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 13 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 13 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + { + "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": true, + "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": "a", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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": "b", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "String", + "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": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "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_int", + "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": "Int", + "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 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "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 + } + } + }, + "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": "b", + "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": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "BinaryExpression", + "operator": "&", + "left": { + "type": "BinaryExpression", + "operator": ">>", + "left": { + "type": "Identifier", + "name": "proxy_int", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 2, + "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": "c", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 30, + "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": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Identifier", + "name": "c", + "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": 16, + "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": 25, + "column": 1 + } + } +} +TypeError: Function already declared. [default_parameter7.ets:21:1] diff --git a/ets2panda/test/parser/ets/default_parameter7.ets b/ets2panda/test/parser/ets/default_parameter7.ets new file mode 100644 index 0000000000..490da83dbf --- /dev/null +++ b/ets2panda/test/parser/ets/default_parameter7.ets @@ -0,0 +1,24 @@ +/* + * 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 foo(...a : Int[]) : Int +{ + return 1; +} + +function foo(a : Int, b? : String, c : Int = 30) : Int +{ + return 2; +} diff --git a/ets2panda/test/runtime/ets/DefaultParam_1.ets b/ets2panda/test/runtime/ets/DefaultParam_1.ets index af964ea382..72368a9610 100644 --- a/ets2panda/test/runtime/ets/DefaultParam_1.ets +++ b/ets2panda/test/runtime/ets/DefaultParam_1.ets @@ -35,16 +35,6 @@ function main():void{ assert foo15(10,5) == 20; assert foo16(10,5) == 30; - - - assert foo17(1,2) == 1; - assert foo17(1,9999999999) == 2; - - assert foo18(1,2) == 1; - assert foo18(1,false) == 2; - - assert foo19(1,2) == 1; - assert foo19(1,c'a') == 2; } function foo1(a : int = 10) : int { @@ -96,27 +86,3 @@ function foo15(a : int, b : int, c : int = 5) : int { function foo16(a : int, b : int, c : int = 10, d : int = 5) : int { return a + b + c + d; } - -function foo17(a : int, b : int = 20, c : int = 30) : int { - return 1; -} - -function foo17(a : int, b : long = 20, c : int = 30) : int { - return 2; -} - -function foo18(a : int, b : int = 20, c : int = 30) : int { - return 1; -} - -function foo18(a : int, b : boolean = true, c : int = 30) : int { - return 2; -} - -function foo19(a : int, b : int = 20, c : int = 30) : int { - return 1; -} - -function foo19(a : int, b : char = c'a', c : int = 30) : int { - return 2; -} diff --git a/ets2panda/test/runtime/ets/DefaultParam_2.ets b/ets2panda/test/runtime/ets/DefaultParam_2.ets index d00f90d198..c82f36b460 100644 --- a/ets2panda/test/runtime/ets/DefaultParam_2.ets +++ b/ets2panda/test/runtime/ets/DefaultParam_2.ets @@ -43,15 +43,6 @@ function main():void{ assert foo15(new Int(10),new Int(5)) == 20; assert foo16(new Int(10),new Int(5)) == 30; - - assert foo17(new Int(1),new Int(2)) == 1; - assert foo17(new Int(1),new Long(9999999999)) == 2; - - assert foo18(new Int(1),new Int(2)) == 1; - assert foo18(new Int(1),new Boolean(true)) == 2; - - assert foo19(new Int(1),new Int(1)) == 1; - assert foo19(new Int(1),"a") == 2; } function foo1(a : Int = 10) : Int { @@ -142,27 +133,3 @@ function foo15(a : Int, b : Int, c : Int = 5) : Int { function foo16(a : Int, b : Int, c : Int = 10, d : Int = 5) : Int { return a + b + c + d; } - -function foo17(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; -} - -function foo17(a : Int, b : Long = 9999999999, c : Int = 30) : Int { - return 2; -} - -function foo18(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; -} - -function foo18(a : Int, b : Boolean = true, c : Int = 30) : Int { - return 2; -} - -function foo19(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; -} - -function foo19(a : Int, b : string = "a", c : Int = 30) : Int { - return 2; -} diff --git a/ets2panda/test/runtime/ets/DefaultParam_4.ets b/ets2panda/test/runtime/ets/DefaultParam_4.ets index 696647a3b7..38a37046f5 100644 --- a/ets2panda/test/runtime/ets/DefaultParam_4.ets +++ b/ets2panda/test/runtime/ets/DefaultParam_4.ets @@ -45,15 +45,6 @@ function main():void{ assert boo.foo15(new Int(10),new Int(5)) == 20; assert boo.foo16(new Int(10),new Int(5)) == 30; - - assert boo.foo17(new Int(1),new Int(2)) == 1; - assert boo.foo17(new Int(1),new Long(9999999999)) == 2; - - assert boo.foo18(new Int(1),new Int(2)) == 1; - assert boo.foo18(new Int(1),new Boolean(true)) == 2; - - assert boo.foo19(new Int(1),new Int(1)) == 1; - assert boo.foo19(new Int(1),"a") == 2; } class bar { @@ -145,28 +136,4 @@ class bar { foo16(a : Int, b : Int, c : Int = 10, d : Int = 5) : Int { return a + b + c + d; } - - foo17(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; - } - - foo17(a : Int, b : Long = 9999999999, c : Int = 30) : Int { - return 2; - } - - foo18(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; - } - - foo18(a : Int, b : Boolean = true, c : Int = 30) : Int { - return 2; - } - - foo19(a : Int, b : Int = 20, c : Int = 30) : Int { - return 1; - } - - foo19(a : Int, b : string = "a", c : Int = 30) : Int { - return 2; - } } -- Gitee From 1c33f685afba9fef7f989b8f6b5037e6fccd9cb0 Mon Sep 17 00:00:00 2001 From: aakmaev Date: Mon, 13 Nov 2023 23:49:39 +0300 Subject: [PATCH 9/9] =?UTF-8?q?Support=20union=20types=20follow-up=20&=20b?= =?UTF-8?q?ug=20fixes=20Issue=EF=BC=9Ahttps://gitee.com/openharmony/arkcom?= =?UTF-8?q?piler=5Fets=5Ffrontend/issues/I8I1VZ=20Testing=20:=20All=20requ?= =?UTF-8?q?ired=20pre-merge=20tests=20passed.=20Results=20are=20availible?= =?UTF-8?q?=20in=20the=20ggwatcher.=20Signed-off-by:=20Akmaev=20Alexey=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ets2panda/checker/ets/arithmetic.cpp | 30 +- ets2panda/checker/ets/helpers.cpp | 2 +- ets2panda/checker/ets/typeCreation.cpp | 1 + ets2panda/checker/types/ets/etsObjectType.cpp | 1 - ets2panda/checker/types/ets/etsUnionType.cpp | 109 +++++-- ets2panda/checker/types/ets/etsUnionType.h | 18 +- ets2panda/compiler/core/ETSGen.cpp | 79 ++--- ets2panda/compiler/core/ETSGen.h | 1 + .../compiler/lowering/ets/unionLowering.cpp | 303 +++++++++++++++--- ets2panda/ir/astNode.cpp | 21 ++ ets2panda/ir/astNode.h | 1 + ets2panda/ir/expressions/binaryExpression.h | 6 + ets2panda/ir/expressions/memberExpression.cpp | 10 +- ets2panda/ir/statements/ifStatement.h | 5 + .../ets/default_parameter6-expected.txt | 12 +- .../ets/default_parameter7-expected.txt | 6 +- ets2panda/test/union_types_4-expected.txt | 0 17 files changed, 494 insertions(+), 111 deletions(-) delete mode 100644 ets2panda/test/union_types_4-expected.txt diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index c78ac64ba9..de5372293c 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -139,6 +139,10 @@ checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod(ir::Expression *left, ir FlagExpressionWithUnboxing(left_type, unboxed_l, left); FlagExpressionWithUnboxing(right_type, unboxed_r, right); + if (left_type->IsETSUnionType() || right_type->IsETSUnionType()) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + if (promotedType == nullptr && !bothConst) { ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); } @@ -156,6 +160,10 @@ checker::Type *ETSChecker::CheckBinaryOperatorPlus(ir::Expression *left, ir::Exp bool is_equal_op, checker::Type *const left_type, checker::Type *const right_type, Type *unboxed_l, Type *unboxed_r) { + if (left_type->IsETSUnionType() || right_type->IsETSUnionType()) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + if (left_type->IsETSStringType() || right_type->IsETSStringType()) { return HandleStringConcatenation(left_type, right_type); } @@ -182,6 +190,10 @@ checker::Type *ETSChecker::CheckBinaryOperatorShift(ir::Expression *left, ir::Ex bool is_equal_op, checker::Type *const left_type, checker::Type *const right_type, Type *unboxed_l, Type *unboxed_r) { + if (left_type->IsETSUnionType() || right_type->IsETSUnionType()) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + auto promoted_left_type = ApplyUnaryOperatorPromotion(unboxed_l, false, !is_equal_op); auto promoted_right_type = ApplyUnaryOperatorPromotion(unboxed_r, false, !is_equal_op); @@ -225,6 +237,10 @@ checker::Type *ETSChecker::CheckBinaryOperatorBitwise(ir::Expression *left, ir:: bool is_equal_op, checker::Type *const left_type, checker::Type *const right_type, Type *unboxed_l, Type *unboxed_r) { + if (left_type->IsETSUnionType() || right_type->IsETSUnionType()) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + if (unboxed_l != nullptr && unboxed_l->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxed_r != nullptr && unboxed_r->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { FlagExpressionWithUnboxing(left_type, unboxed_l, left); @@ -253,6 +269,10 @@ checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir:: lexer::SourcePosition pos, checker::Type *const left_type, checker::Type *const right_type, Type *unboxed_l, Type *unboxed_r) { + if (left_type->IsETSUnionType() || right_type->IsETSUnionType()) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + if (unboxed_l == nullptr || !unboxed_l->IsConditionalExprType() || unboxed_r == nullptr || !unboxed_r->IsConditionalExprType()) { ThrowTypeError("Bad operand type, the types of the operands must be of possible condition type.", pos); @@ -278,8 +298,8 @@ std::tuple ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expres checker::Type *const right_type) { checker::Type *ts_type {}; - if (!(left_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) || - !(right_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT))) { + if (!(left_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || left_type->IsETSUnionType()) || + !(right_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || right_type->IsETSUnionType())) { ThrowTypeError("Both operands have to be reference types", pos); } @@ -374,6 +394,12 @@ std::tuple ETSChecker::CheckBinaryOperatorLessGreater( ir::Expression *left, ir::Expression *right, lexer::TokenType operation_type, lexer::SourcePosition pos, bool is_equal_op, checker::Type *const left_type, checker::Type *const right_type, Type *unboxed_l, Type *unboxed_r) { + if ((left_type->IsETSUnionType() || right_type->IsETSUnionType()) && + operation_type != lexer::TokenType::PUNCTUATOR_EQUAL && + operation_type != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) { + ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); + } + checker::Type *ts_type {}; auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(unboxed_l, unboxed_r, TypeFlag::ETS_NUMERIC, !is_equal_op); diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index dd678cbfa3..3e61d31919 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2047,7 +2047,7 @@ Type *ETSChecker::GetTypeFromTypeAnnotation(ir::TypeNode *const type_annotation) return type; } - if (!type->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT)) { + if (!type->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT) && !type->HasTypeFlag(TypeFlag::ETS_UNION)) { ThrowTypeError("Non reference types cannot be nullish.", type_annotation->Start()); } diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 03be8f6bda..bd75518d92 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -143,6 +143,7 @@ Type *ETSChecker::CreateETSUnionType(ArenaVector &&constituent_types) } auto *new_union_type = Allocator()->New(std::move(new_constituent_types)); + new_union_type->SetLeastUpperBoundType(this); return ETSUnionType::HandleUnionType(new_union_type); } diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 7d060c93c5..6c6435e7ec 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -762,7 +762,6 @@ Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation * for (auto *const type_argument : TypeArguments()) { copied_type->TypeArguments().emplace_back(type_argument->Instantiate(allocator, relation, global_types)); } - copied_type->SetBaseType(this); copied_type->properties_instantiated_ = false; copied_type->relation_ = relation; diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index cca516221f..b3335689a1 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -19,6 +19,7 @@ #include "checker/ets/conversion.h" #include "checker/types/globalTypesHolder.h" #include "checker/ETSchecker.h" +#include "ir/astNode.h" namespace panda::es2panda::checker { void ETSUnionType::ToString(std::stringstream &ss) const @@ -26,11 +27,16 @@ void ETSUnionType::ToString(std::stringstream &ss) const for (auto it = constituent_types_.begin(); it != constituent_types_.end(); it++) { (*it)->ToString(ss); if (std::next(it) != constituent_types_.end()) { - ss << " | "; + ss << "|"; } } } +void ETSUnionType::ToAssemblerType(std::stringstream &ss) const +{ + ss << compiler::Signatures::BUILTIN_OBJECT; +} + bool ETSUnionType::EachTypeRelatedToSomeType(TypeRelation *relation, ETSUnionType *source, ETSUnionType *target) { return std::all_of(source->constituent_types_.begin(), source->constituent_types_.end(), @@ -43,7 +49,7 @@ bool ETSUnionType::TypeRelatedToSomeType(TypeRelation *relation, Type *source, E [relation, source](auto *t) { return relation->IsIdenticalTo(source, t); }); } -Type *ETSUnionType::GetLeastUpperBoundType(ETSChecker *checker) +void ETSUnionType::SetLeastUpperBoundType(ETSChecker *checker) { ASSERT(constituent_types_.size() > 1); if (lub_type_ == nullptr) { @@ -51,12 +57,11 @@ Type *ETSUnionType::GetLeastUpperBoundType(ETSChecker *checker) for (auto *t : constituent_types_) { if (!t->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT)) { lub_type_ = checker->GetGlobalTypesHolder()->GlobalETSObjectType(); - return lub_type_; + return; } lub_type_ = checker->FindLeastUpperBound(lub_type_, t); } } - return lub_type_; } void ETSUnionType::Identical(TypeRelation *relation, Type *other) @@ -86,10 +91,21 @@ bool ETSUnionType::AssignmentSource(TypeRelation *relation, Type *target) void ETSUnionType::AssignmentTarget(TypeRelation *relation, Type *source) { - auto *const ref_source = source->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) - ? relation->GetChecker()->AsETSChecker()->PrimitiveTypeAsETSBuiltinType(source) - : source; - + auto *const checker = relation->GetChecker()->AsETSChecker(); + auto *const ref_source = + source->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) ? checker->PrimitiveTypeAsETSBuiltinType(source) : source; + auto exact_type = std::find_if( + constituent_types_.begin(), constituent_types_.end(), [checker, relation, source, ref_source](Type *ct) { + if (ct == ref_source && source->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && ct->IsETSObjectType() && + ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) { + relation->GetNode()->SetBoxingUnboxingFlags(checker->GetBoxingFlag(ct)); + return relation->IsAssignableTo(ref_source, ct); + } + return false; + }); + if (exact_type != constituent_types_.end()) { + return; + } for (auto *it : constituent_types_) { if (relation->IsAssignableTo(ref_source, it)) { if (ref_source != source) { @@ -98,6 +114,18 @@ void ETSUnionType::AssignmentTarget(TypeRelation *relation, Type *source) } return; } + bool assign_primitive = it->IsETSObjectType() && + it->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && + source->HasTypeFlag(TypeFlag::ETS_PRIMITIVE); + if (assign_primitive && relation->IsAssignableTo(source, checker->ETSBuiltinTypeAsPrimitiveType(it))) { + Type *unboxed_it = checker->ETSBuiltinTypeAsPrimitiveType(it); + if (unboxed_it != source) { + relation->GetNode()->SetBoxingUnboxingFlags(checker->GetBoxingFlag(it)); + source->Cast(relation, unboxed_it); + ASSERT(relation->IsTrue()); + } + return; + } } } @@ -124,21 +152,32 @@ Type *ETSUnionType::Instantiate(ArenaAllocator *allocator, TypeRelation *relatio return copied_constituents[0]; } - Type *new_union_type = allocator->New(std::move(copied_constituents)); + auto *new_union_type = allocator->New(std::move(copied_constituents)); - lub_type_ = global_types->GlobalETSObjectType(); - return HandleUnionType(new_union_type->AsETSUnionType()); + new_union_type->SetLeastUpperBoundType(relation->GetChecker()->AsETSChecker()); + return HandleUnionType(new_union_type); } void ETSUnionType::Cast(TypeRelation *relation, Type *target) { - auto *const ref_target = target->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) - ? relation->GetChecker()->AsETSChecker()->PrimitiveTypeAsETSBuiltinType(target) - : target; - + auto *const checker = relation->GetChecker()->AsETSChecker(); + auto *const ref_target = + target->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) ? checker->PrimitiveTypeAsETSBuiltinType(target) : target; + auto exact_type = std::find_if(constituent_types_.begin(), constituent_types_.end(), + [this, checker, relation, ref_target](Type *src) { + if (src == ref_target && relation->IsCastableTo(src, ref_target)) { + GetLeastUpperBoundType(checker)->Cast(relation, ref_target); + ASSERT(relation->IsTrue()); + return true; + } + return false; + }); + if (exact_type != constituent_types_.end()) { + return; + } for (auto *source : constituent_types_) { if (relation->IsCastableTo(source, ref_target)) { - GetLeastUpperBoundType(relation->GetChecker()->AsETSChecker())->Cast(relation, ref_target); + GetLeastUpperBoundType(checker)->Cast(relation, ref_target); ASSERT(relation->IsTrue()); if (ref_target != target) { source->Cast(relation, target); @@ -147,6 +186,13 @@ void ETSUnionType::Cast(TypeRelation *relation, Type *target) } return; } + bool cast_primitive = source->IsETSObjectType() && + source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE) && + target->HasTypeFlag(TypeFlag::ETS_PRIMITIVE); + if (cast_primitive && relation->IsCastableTo(checker->ETSBuiltinTypeAsPrimitiveType(source), target)) { + ASSERT(relation->IsTrue()); + return; + } } conversion::Forbidden(relation); @@ -241,9 +287,36 @@ Type *ETSUnionType::FindTypeIsCastableToSomeType(ir::Expression *node, TypeRelat return nullptr; } -void ETSUnionType::ToAssemblerType(std::stringstream &ss) const +Type *ETSUnionType::FindUnboxableType() const { - ss << compiler::Signatures::BUILTIN_OBJECT; + auto it = std::find_if(constituent_types_.begin(), constituent_types_.end(), + [](Type *t) { return t->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE); }); + if (it != constituent_types_.end()) { + return *it; + } + return nullptr; +} + +bool ETSUnionType::HasObjectType(ETSObjectFlags flag) const +{ + auto it = std::find_if(constituent_types_.begin(), constituent_types_.end(), + [flag](Type *t) { return t->AsETSObjectType()->HasObjectFlag(flag); }); + return it != constituent_types_.end(); +} + +Type *ETSUnionType::FindExactOrBoxedType(ETSChecker *checker, Type *const type) const +{ + auto it = std::find_if(constituent_types_.begin(), constituent_types_.end(), [checker, type](Type *ct) { + if (ct->IsETSObjectType() && ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) { + auto *const unboxed_ct = checker->ETSBuiltinTypeAsPrimitiveType(ct); + return unboxed_ct == type; + } + return ct == type; + }); + if (it != constituent_types_.end()) { + return *it; + } + return nullptr; } } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsUnionType.h b/ets2panda/checker/types/ets/etsUnionType.h index 728c05665b..3d0e27f986 100644 --- a/ets2panda/checker/types/ets/etsUnionType.h +++ b/ets2panda/checker/types/ets/etsUnionType.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_UNION_TYPE_H #include "checker/types/type.h" +#include "checker/types/ets/etsObjectType.h" namespace panda::es2panda::checker { class GlobalTypesHolder; @@ -60,6 +61,7 @@ public: } void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; void Identical(TypeRelation *relation, Type *other) override; void AssignmentTarget(TypeRelation *relation, Type *source) override; bool AssignmentSource(TypeRelation *relation, Type *target) override; @@ -68,10 +70,18 @@ public: void CastToThis(TypeRelation *relation, Type *source); Type *FindTypeIsCastableToThis(ir::Expression *node, TypeRelation *relation, Type *source) const; Type *FindTypeIsCastableToSomeType(ir::Expression *node, TypeRelation *relation, Type *target) const; + Type *FindUnboxableType() const; - void ToAssemblerType(std::stringstream &ss) const override; + void SetLeastUpperBoundType(ETSChecker *checker); - Type *GetLeastUpperBoundType(ETSChecker *checker); + Type *GetLeastUpperBoundType(ETSChecker *checker) + { + if (lub_type_ == nullptr) { + SetLeastUpperBoundType(checker); + } + ASSERT(lub_type_ != nullptr); + return lub_type_; + } Type *GetLeastUpperBoundType() const { @@ -79,6 +89,10 @@ public: return lub_type_; } + bool HasObjectType(ETSObjectFlags flag) const; + + Type *FindExactOrBoxedType(ETSChecker *checker, Type *type) const; + static Type *HandleUnionType(ETSUnionType *union_type); private: diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 30b8519653..e540cdbf07 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -15,7 +15,6 @@ #include "ETSGen.h" -#include "checker/ets/boxingConverter.h" #include "ir/base/scriptFunction.h" #include "ir/base/classDefinition.h" #include "ir/statement.h" @@ -40,6 +39,7 @@ #include "checker/types/typeFlag.h" #include "checker/checker.h" #include "checker/ETSchecker.h" +#include "checker/ets/boxingConverter.h" #include "checker/types/ets/etsObjectType.h" #include "checker/types/ets/types.h" #include "parser/program/program.h" @@ -867,15 +867,35 @@ bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) return true; } -// NOTE: vpukhov. lower (union_value) as (primitive_type) to be two as-nodes -static void ApplyUnboxingUnionPrimitive(ETSGen *etsg, const ir::AstNode *node) +void ETSGen::ApplyConversionCast(const ir::AstNode *node, const checker::Type *target_type) { - if (node->IsExpression() && node->Parent()->IsTSAsExpression()) { - auto const *from_type = node->AsExpression()->TsType(); - auto const *to_type = node->Parent()->AsTSAsExpression()->TsType(); - if (from_type->IsETSUnionType() && to_type->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { - etsg->EmitCheckedNarrowingReferenceConversion( - node, checker::BoxingConverter::ETSTypeFromSource(etsg->Checker(), to_type)); + switch (checker::ETSChecker::TypeKind(target_type)) { + case checker::TypeFlag::DOUBLE: { + CastToDouble(node); + break; + } + case checker::TypeFlag::FLOAT: { + CastToFloat(node); + break; + } + case checker::TypeFlag::LONG: { + CastToLong(node); + break; + } + case checker::TypeFlag::ETS_ARRAY: + [[fallthrough]]; + case checker::TypeFlag::ETS_OBJECT: { + if (GetAccumulatorType() != nullptr && GetAccumulatorType()->IsETSDynamicType()) { + CastDynamicToObject(node, target_type); + } + break; + } + case checker::TypeFlag::ETS_DYNAMIC_TYPE: { + CastToDynamic(node, target_type->AsETSDynamicType()); + break; + } + default: { + break; } } } @@ -897,7 +917,6 @@ void ETSGen::ApplyConversion(const ir::AstNode *node, const checker::Type *targe if (GetAccumulatorType()->IsNullishOrNullLike()) { // NOTE: vpukhov. should be a CTE EmitNullishGuardian(node); } - ApplyUnboxingUnionPrimitive(this, node); EmitUnboxingConversion(node); const auto unboxing_flags = static_cast(node->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG); @@ -909,35 +928,12 @@ void ETSGen::ApplyConversion(const ir::AstNode *node, const checker::Type *targe return; } - switch (checker::ETSChecker::TypeKind(target_type)) { - case checker::TypeFlag::DOUBLE: { - CastToDouble(node); - break; - } - case checker::TypeFlag::FLOAT: { - CastToFloat(node); - break; - } - case checker::TypeFlag::LONG: { - CastToLong(node); - break; - } - case checker::TypeFlag::ETS_ARRAY: - [[fallthrough]]; - case checker::TypeFlag::ETS_OBJECT: { - if (GetAccumulatorType() != nullptr && GetAccumulatorType()->IsETSDynamicType()) { - CastDynamicToObject(node, target_type); - } - break; - } - case checker::TypeFlag::ETS_DYNAMIC_TYPE: { - CastToDynamic(node, target_type->AsETSDynamicType()); - break; - } - default: { - break; - } + if (target_type->IsETSUnionType()) { + SetAccumulatorType(target_type->AsETSUnionType()->GetLeastUpperBoundType()); + return; } + + ApplyConversionCast(node, target_type); } void ETSGen::ApplyCast(const ir::AstNode *node, const checker::Type *target_type) @@ -2422,6 +2418,10 @@ void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg object_reg) { auto *element_type = GetVRegType(object_reg)->AsETSArrayType()->ElementType(); + if (element_type->IsETSUnionType()) { + element_type = element_type->AsETSUnionType()->GetLeastUpperBoundType(); + } + switch (checker::ETSChecker::ETSType(element_type)) { case checker::TypeFlag::ETS_BOOLEAN: case checker::TypeFlag::BYTE: { @@ -2472,6 +2472,9 @@ void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg object_reg) void ETSGen::StoreArrayElement(const ir::AstNode *node, VReg object_reg, VReg index, const checker::Type *element_type) { + if (element_type->IsETSUnionType()) { + element_type = element_type->AsETSUnionType()->GetLeastUpperBoundType(); + } switch (checker::ETSChecker::ETSType(element_type)) { case checker::TypeFlag::ETS_BOOLEAN: case checker::TypeFlag::BYTE: { diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 7ee98c5619..ec33c5d788 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -407,6 +407,7 @@ public: ApplyConversion(node, target_type_); } } + void ApplyConversionCast(const ir::AstNode *node, const checker::Type *target_type); void ApplyConversion(const ir::AstNode *node, const checker::Type *target_type); void ApplyCast(const ir::AstNode *node, const checker::Type *target_type); void EmitUnboxingConversion(const ir::AstNode *node); diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index f036bdab81..fbe3ea2305 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -17,21 +17,21 @@ #include "varbinder/variableFlags.h" #include "varbinder/ETSBinder.h" #include "checker/ETSchecker.h" +#include "checker/ets/conversion.h" +#include "checker/ets/boxingConverter.h" #include "compiler/core/compilerContext.h" +#include "compiler/lowering/util.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/ets/etsParameterExpression.h" -#include "ir/expressions/assignmentExpression.h" #include "ir/expressions/binaryExpression.h" #include "ir/expressions/identifier.h" -#include "ir/expressions/functionExpression.h" #include "ir/expressions/memberExpression.h" -#include "ir/expressions/sequenceExpression.h" #include "ir/statements/blockStatement.h" #include "ir/statements/classDeclaration.h" +#include "ir/statements/variableDeclaration.h" #include "ir/ts/tsAsExpression.h" #include "type_helper.h" @@ -115,46 +115,261 @@ void HandleUnionPropertyAccess(checker::ETSChecker *checker, varbinder::VarBinde ASSERT(expr->PropVar() != nullptr); } -ir::Expression *HandleBinaryExpressionWithUnion(checker::ETSChecker *checker, ir::BinaryExpression *expr) +ir::TSAsExpression *GenAsExpression(checker::ETSChecker *checker, checker::Type *const opaque_type, + ir::Expression *const node, ir::AstNode *const parent) { - auto *union_type = expr->OperationType()->AsETSUnionType(); - ir::Expression *union_node; - ir::Expression *other_union_node = nullptr; - checker::Type *other_node_type; - if (expr->Left()->TsType()->IsETSUnionType()) { - union_node = expr->Left(); - other_node_type = expr->Right()->TsType(); - if (other_node_type->IsETSUnionType()) { - other_union_node = expr->Right(); + auto *const type_node = checker->AllocNode(opaque_type); + auto *const as_expression = checker->AllocNode(node, type_node, false); + as_expression->SetParent(parent); + node->SetParent(as_expression); + as_expression->Check(checker); + return as_expression; +} + +/* + * Function that generates conversion from (union) to (primitive) type as to `as` expressions: + * (union) as (prim) => ((union) as (ref)) as (prim), + * where (ref) is some unboxable type from union constituent types. + * Finally, `(union) as (prim)` expression replaces union_node that came above. + */ +ir::TSAsExpression *UnionCastToPrimitive(checker::ETSChecker *checker, checker::ETSObjectType *unboxable_ref, + checker::Type *unboxed_prim, ir::Expression *union_node) +{ + auto *const union_as_ref_expression = GenAsExpression(checker, unboxable_ref, union_node, nullptr); + union_as_ref_expression->SetBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxed_prim)); + union_node->SetParent(union_as_ref_expression); + + auto *const ref_as_prim_expression = + GenAsExpression(checker, unboxed_prim, union_as_ref_expression, union_node->Parent()); + union_as_ref_expression->SetParent(ref_as_prim_expression); + + return ref_as_prim_expression; +} + +ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *checker, ir::TSAsExpression *expr) +{ + auto *const union_type = expr->Expr()->TsType()->AsETSUnionType(); + auto *source_type = union_type->FindExactOrBoxedType(checker, expr->TsType()); + if (source_type == nullptr) { + source_type = union_type->AsETSUnionType()->FindTypeIsCastableToSomeType(expr->Expr(), checker->Relation(), + expr->TsType()); + } + if (source_type != nullptr && expr->Expr()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) { + if (expr->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + auto *const boxed_expr_type = checker::BoxingConverter::ETSTypeFromSource(checker, expr->TsType()); + auto *const as_expr = GenAsExpression(checker, boxed_expr_type, expr->Expr(), expr); + as_expr->SetBoxingUnboxingFlags(expr->Expr()->GetBoxingUnboxingFlags()); + expr->Expr()->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::NONE); + expr->SetExpr(as_expr); } - } else { - union_node = expr->Right(); - other_node_type = expr->Left()->TsType(); + return expr; } - auto *source_type = - union_type->AsETSUnionType()->FindTypeIsCastableToSomeType(union_node, checker->Relation(), other_node_type); - if (source_type == nullptr) { - checker->ThrowTypeError("Bad operand type, some type of the union must be the same type as other expression.", - expr->Start()); - } - if ((union_node->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::BOXING_FLAG) != 0U && - source_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { - union_node->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::NONE); - } - auto *union_type_node = checker->AllocNode(source_type); - auto *as_expression = checker->AllocNode(union_node, union_type_node, false); - as_expression->SetParent(expr); - expr->SetOperationType(source_type); - if (other_union_node != nullptr) { - auto *other_union_type_node = checker->AllocNode(other_node_type); - auto *other_as_expression = - checker->AllocNode(other_union_node, other_union_type_node, false); - other_as_expression->SetParent(expr); + auto *const unboxable_union_type = source_type != nullptr ? source_type : union_type->FindUnboxableType(); + auto *const unboxed_union_type = checker->ETSBuiltinTypeAsPrimitiveType(unboxable_union_type); + expr->SetExpr( + UnionCastToPrimitive(checker, unboxable_union_type->AsETSObjectType(), unboxed_union_type, expr->Expr())); + return expr; +} + +ir::BinaryExpression *GenInstanceofExpr(checker::ETSChecker *checker, ir::Expression *union_node, + checker::Type *constituent_type) +{ + auto *const lhs_expr = union_node->Clone(checker->Allocator())->AsExpression(); + lhs_expr->Check(checker); + lhs_expr->SetBoxingUnboxingFlags(union_node->GetBoxingUnboxingFlags()); + auto *rhs_type = constituent_type; + if (!constituent_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + checker->Relation()->SetNode(union_node); + rhs_type = checker::conversion::Boxing(checker->Relation(), constituent_type); + checker->Relation()->SetNode(nullptr); } + auto *const rhs_expr = + checker->Allocator()->New(rhs_type->AsETSObjectType()->Name(), checker->Allocator()); + auto *const instanceof_expr = + checker->Allocator()->New(lhs_expr, rhs_expr, lexer::TokenType::KEYW_INSTANCEOF); + lhs_expr->SetParent(instanceof_expr); + rhs_expr->SetParent(instanceof_expr); + auto rhs_var = NearestScope(union_node)->Find(rhs_expr->Name()); + rhs_expr->SetVariable(rhs_var.variable); + rhs_expr->SetTsType(rhs_var.variable->TsType()); + instanceof_expr->SetOperationType(checker->GlobalETSObjectType()); + instanceof_expr->SetTsType(checker->GlobalETSBooleanType()); + return instanceof_expr; +} + +ir::VariableDeclaration *GenVariableDeclForBinaryExpr(checker::ETSChecker *checker, varbinder::Scope *scope, + ir::BinaryExpression *expr) +{ + ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL || + expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL); + auto *var_id = Gensym(checker->Allocator()); + auto *var = scope->AddDecl(checker->Allocator(), var_id->Name(), + varbinder::VariableFlags::LOCAL); + var->SetTsType(checker->GlobalETSBooleanType()); + var_id->SetVariable(var); + var_id->SetTsType(var->TsType()); + + auto declarator = checker->AllocNode(var_id); + ArenaVector declarators(checker->Allocator()->Adapter()); + declarators.push_back(declarator); + + auto var_kind = ir::VariableDeclaration::VariableDeclarationKind::LET; + auto *binary_var_decl = + checker->AllocNode(var_kind, checker->Allocator(), std::move(declarators), false); + binary_var_decl->SetRange({expr->Start(), expr->End()}); + return binary_var_decl; +} + +ir::ExpressionStatement *GenExpressionStmtWithAssignment(checker::ETSChecker *checker, ir::Identifier *var_decl_id, + ir::Expression *expr) +{ + auto *assignment_for_binary = + checker->AllocNode(var_decl_id, expr, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + assignment_for_binary->SetTsType(expr->TsType()); + return checker->AllocNode(assignment_for_binary); +} + +ir::BlockStatement *GenBlockStmtForAssignmentBinary(checker::ETSChecker *checker, ir::Identifier *var_decl_id, + ir::Expression *expr) +{ + auto local_ctx = varbinder::LexicalScope(checker->VarBinder()); + ArenaVector stmts(checker->Allocator()->Adapter()); + auto *stmt = GenExpressionStmtWithAssignment(checker, var_decl_id, expr); + stmts.push_back(stmt); + auto *const local_block_stmt = + checker->AllocNode(checker->Allocator(), local_ctx.GetScope(), std::move(stmts)); + stmt->SetParent(local_block_stmt); + local_block_stmt->SetRange(stmt->Range()); + local_ctx.GetScope()->BindNode(local_block_stmt); + return local_block_stmt; +} + +ir::Expression *SetBoxFlagOrGenAsExpression(checker::ETSChecker *checker, checker::Type *constituent_type, + ir::Expression *other_node) +{ + if (constituent_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::UNBOXABLE_TYPE) && + !other_node->IsETSUnionType() && other_node->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + auto *unboxed_constituent_type = checker->ETSBuiltinTypeAsPrimitiveType(constituent_type); + if (unboxed_constituent_type != other_node->TsType()) { + auto *const prim_as_expression = + GenAsExpression(checker, unboxed_constituent_type, other_node, other_node->Parent()); + prim_as_expression->SetBoxingUnboxingFlags(checker->GetBoxingFlag(constituent_type)); + return prim_as_expression; + } + return other_node; + } + if (other_node->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + other_node->SetBoxingUnboxingFlags( + checker->GetBoxingFlag(checker::BoxingConverter::ETSTypeFromSource(checker, other_node->TsType()))); + } + return other_node; +} + +ir::Expression *ProcessOperandsInBinaryExpr(checker::ETSChecker *checker, ir::BinaryExpression *expr, + checker::Type *constituent_type) +{ + ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL || + expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL); + bool is_lhs_union; + ir::Expression *union_node = + (is_lhs_union = expr->Left()->TsType()->IsETSUnionType()) ? expr->Left() : expr->Right(); + auto *const as_expression = GenAsExpression(checker, constituent_type, union_node, expr); + if (is_lhs_union) { + expr->SetLeft(as_expression); + expr->SetRight(SetBoxFlagOrGenAsExpression(checker, constituent_type, expr->Right())); + } else { + expr->SetRight(as_expression); + expr->SetLeft(SetBoxFlagOrGenAsExpression(checker, constituent_type, expr->Left())); + } + expr->SetOperationType(checker->GlobalETSObjectType()); expr->SetTsType(checker->GlobalETSBooleanType()); return expr; } +ir::Statement *FindStatementFromNode(ir::Expression *expr) +{ + ir::AstNode *node = expr; + while (!node->IsStatement()) { + node = node->Parent(); + } + ASSERT(node->IsStatement()); + return node->AsStatement(); +} + +void InsertInstanceofTreeBeforeStmt(ir::Statement *stmt, ir::VariableDeclaration *binary_var_decl, + ir::Statement *instanceof_tree) +{ + if (stmt->IsVariableDeclarator()) { + ASSERT(stmt->Parent()->IsVariableDeclaration()); + stmt = stmt->Parent()->AsVariableDeclaration(); + } + ASSERT(stmt->Parent()->IsBlockStatement()); + auto *block = stmt->Parent()->AsBlockStatement(); + binary_var_decl->SetParent(block); + instanceof_tree->SetParent(block); + auto it_stmt = std::find(block->Statements().begin(), block->Statements().end(), stmt); + block->Statements().insert(it_stmt, {binary_var_decl, instanceof_tree}); +} + +ir::BlockStatement *ReplaceBinaryExprInStmt(checker::ETSChecker *checker, ir::Expression *union_node, + ir::BlockStatement *block, ir::BinaryExpression *expr) +{ + auto *stmt = FindStatementFromNode(expr); + ASSERT(stmt->IsVariableDeclarator() || block == stmt->Parent()); // statement with union + auto *const binary_var_decl = GenVariableDeclForBinaryExpr(checker, NearestScope(stmt), expr); + auto *const var_decl_id = binary_var_decl->Declarators().front()->Id(); // only one declarator was generated + ir::IfStatement *instanceof_tree = nullptr; + for (auto *u_type : union_node->TsType()->AsETSUnionType()->ConstituentTypes()) { + auto *const test = GenInstanceofExpr(checker, union_node, u_type); + auto *cloned_binary = expr->Clone(checker->Allocator(), expr->Parent())->AsBinaryExpression(); + cloned_binary->Check(checker); + auto *const consequent = GenBlockStmtForAssignmentBinary( + checker, var_decl_id->AsIdentifier(), ProcessOperandsInBinaryExpr(checker, cloned_binary, u_type)); + instanceof_tree = checker->Allocator()->New(test, consequent, instanceof_tree); + test->SetParent(instanceof_tree); + consequent->SetParent(instanceof_tree); + if (instanceof_tree->Alternate() != nullptr) { + instanceof_tree->Alternate()->SetParent(instanceof_tree); + } + } + ASSERT(instanceof_tree != nullptr); + // Replacing a binary expression with an identifier + // that was set in one of the branches of the `instanceof_tree` tree + stmt->TransformChildrenRecursively([var_decl_id](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsBinaryExpression() && ast->AsBinaryExpression()->OperationType() != nullptr && + ast->AsBinaryExpression()->OperationType()->IsETSUnionType()) { + return var_decl_id; + } + + return ast; + }); + InsertInstanceofTreeBeforeStmt(stmt, binary_var_decl, instanceof_tree); + return block; +} + +ir::BlockStatement *HandleBlockWithBinaryAndUnion(checker::ETSChecker *checker, ir::BlockStatement *block, + ir::BinaryExpression *bin_expr) +{ + if (bin_expr->OperatorType() != lexer::TokenType::PUNCTUATOR_EQUAL && + bin_expr->OperatorType() != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) { + checker->ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", + bin_expr->Start()); + } + ir::Expression *union_node = bin_expr->Left()->TsType()->IsETSUnionType() ? bin_expr->Left() : bin_expr->Right(); + return ReplaceBinaryExprInStmt(checker, union_node, block, bin_expr); +} + +ir::BlockStatement *HandleBlockWithBinaryAndUnions(checker::ETSChecker *checker, ir::BlockStatement *block, + const ir::NodePredicate &handle_binary) +{ + ir::BlockStatement *modified_ast_block = block; + while (modified_ast_block->IsAnyChild(handle_binary)) { + modified_ast_block = HandleBlockWithBinaryAndUnion( + checker, modified_ast_block, modified_ast_block->FindChild(handle_binary)->AsBinaryExpression()); + } + return modified_ast_block; +} + bool UnionLowering::Perform(CompilerContext *ctx, parser::Program *program) { for (auto &[_, ext_programs] : program->ExternalSources()) { @@ -173,9 +388,19 @@ bool UnionLowering::Perform(CompilerContext *ctx, parser::Program *program) return ast; } - if (ast->IsBinaryExpression() && ast->AsBinaryExpression()->OperationType() != nullptr && - ast->AsBinaryExpression()->OperationType()->IsETSUnionType()) { - return HandleBinaryExpressionWithUnion(checker, ast->AsBinaryExpression()); + if (ast->IsTSAsExpression() && ast->AsTSAsExpression()->Expr()->TsType() != nullptr && + ast->AsTSAsExpression()->Expr()->TsType()->IsETSUnionType() && + ast->AsTSAsExpression()->TsType() != nullptr && + ast->AsTSAsExpression()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + return HandleUnionCastToPrimitive(checker, ast->AsTSAsExpression()); + } + + auto handle_binary = [](const ir::AstNode *ast_node) { + return ast_node->IsBinaryExpression() && ast_node->AsBinaryExpression()->OperationType() != nullptr && + ast_node->AsBinaryExpression()->OperationType()->IsETSUnionType(); + }; + if (ast->IsBlockStatement() && ast->IsAnyChild(handle_binary)) { + return HandleBlockWithBinaryAndUnions(checker, ast->AsBlockStatement(), handle_binary); } return ast; diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 4db50cff07..3aee5eb547 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -89,6 +89,27 @@ bool AstNode::IsAnyChild(const NodePredicate &cb) const return found; } +void FindChildHelper(AstNode *&found, const NodePredicate &cb, AstNode *ast) +{ + if (found != nullptr) { + return; + } + + if (cb(ast)) { + found = ast; + return; + } + + ast->Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); }); +} + +AstNode *AstNode::FindChild(const NodePredicate &cb) const +{ + AstNode *found = nullptr; + Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); }); + return found; +} + void AnnotatedAstNode::CloneTypeAnnotation(ArenaAllocator *const allocator) { if (auto *annotation = const_cast(TypeAnnotation()); annotation != nullptr) { diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index f164f1660c..db3ab5e36e 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -460,6 +460,7 @@ public: void TransformChildrenRecursively(const NodeTransformer &cb); void IterateRecursively(const NodeTraverser &cb) const; bool IsAnyChild(const NodePredicate &cb) const; + AstNode *FindChild(const NodePredicate &cb) const; std::string DumpJSON() const; diff --git a/ets2panda/ir/expressions/binaryExpression.h b/ets2panda/ir/expressions/binaryExpression.h index 98416dc89f..69bdfa92f8 100644 --- a/ets2panda/ir/expressions/binaryExpression.h +++ b/ets2panda/ir/expressions/binaryExpression.h @@ -92,6 +92,12 @@ public: SetStart(left_->Start()); } + void SetRight(Expression *expr) noexcept + { + right_ = expr; + SetEnd(right_->End()); + } + void SetResult(Expression *expr) noexcept { left_ = expr; diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index a308acfd14..082e0be648 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -469,7 +469,15 @@ MemberExpression *MemberExpression::Clone(ArenaAllocator *const allocator, AstNo auto *const object = object_ != nullptr ? object_->Clone(allocator)->AsExpression() : nullptr; auto *const property = property_ != nullptr ? property_->Clone(allocator)->AsExpression() : nullptr; - if (auto *const clone = allocator->New(Tag {}, *this, object, property); clone != nullptr) { + if (auto *const clone = + allocator->New(object, property, kind_, computed_, MaybeOptionalExpression::IsOptional()); + clone != nullptr) { + if (object != nullptr) { + object->SetParent(clone); + } + if (property != nullptr) { + property->SetParent(clone); + } if (parent != nullptr) { clone->SetParent(parent); } diff --git a/ets2panda/ir/statements/ifStatement.h b/ets2panda/ir/statements/ifStatement.h index e124967507..57755853e4 100644 --- a/ets2panda/ir/statements/ifStatement.h +++ b/ets2panda/ir/statements/ifStatement.h @@ -47,6 +47,11 @@ public: return consequent_; } + Statement *Alternate() + { + return alternate_; + } + const Statement *Alternate() const { return alternate_; diff --git a/ets2panda/test/parser/ets/default_parameter6-expected.txt b/ets2panda/test/parser/ets/default_parameter6-expected.txt index caaeb8826a..ad8c1be4b1 100644 --- a/ets2panda/test/parser/ets/default_parameter6-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter6-expected.txt @@ -759,7 +759,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -854,7 +854,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1038,7 +1038,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -2000,7 +2000,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -2095,7 +2095,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -2279,7 +2279,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter7-expected.txt b/ets2panda/test/parser/ets/default_parameter7-expected.txt index ef5625ac46..c6d4b58f37 100644 --- a/ets2panda/test/parser/ets/default_parameter7-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter7-expected.txt @@ -1018,7 +1018,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -1113,7 +1113,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1297,7 +1297,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/union_types_4-expected.txt b/ets2panda/test/union_types_4-expected.txt deleted file mode 100644 index e69de29bb2..0000000000 -- Gitee