diff --git a/bundle.json b/bundle.json index 80c4a610936616f4779d73a67ee5f3dd567a8fd9..3ea4b67716580490c83ee24a95b068b98b2402fd 100644 --- a/bundle.json +++ b/bundle.json @@ -47,7 +47,8 @@ } ], "test": [ - "//arkcompiler/ets_frontend/es2panda:es2abc_tests" + "//arkcompiler/ets_frontend/es2panda:es2abc_tests", + "//arkcompiler/ets_frontend/ets2panda/bindings/test:bindings_test" ] } } diff --git a/codecheck_ignore.json b/codecheck_ignore.json index e51d43f3b4a770ab232e4d3e74cebc1b0a09daa4..a30bb19d2b134825596abb32890795d7089fd638 100755 --- a/codecheck_ignore.json +++ b/codecheck_ignore.json @@ -14,7 +14,9 @@ "ets2panda/linter/arkanalyzer": "*", "ets2panda/linter/homecheck": "*", "ets2panda/linter/build_linter.py": "*", + "ets2panda/linter/src/cli/CommandLineParser.ts": "*", "ets2panda/linter/src/lib/TypeScriptLinter.ts": "*", + "ets2panda/linter/src/lib/autofixes/Autofixer.ts": "*", "ets2panda/linter/src/lib/autofixes/QuasiEditor.ts": "*", "ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsCommonFunction.ts": "*", "ets2panda/linter/src/lib/utils/functions/ConfiguredRulesProcess.ts": "*", diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 58a6dd05fc6fd494d530b6dd8eec0e963cd18d5a..60c32ea888d672fd753514e638086c66492cc36b 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -245,7 +245,6 @@ libes2panda_sources = [ "compiler/lowering/ets/interfacePropertyDeclarations.cpp", "compiler/lowering/ets/lambdaLowering.cpp", "compiler/lowering/ets/lateInitialization.cpp", - "compiler/lowering/ets/localClassLowering.cpp", "compiler/lowering/ets/objectIndexAccess.cpp", "compiler/lowering/ets/objectIterator.cpp", "compiler/lowering/ets/objectLiteralLowering.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 6f31c4e658670b25e7daf7f3ea257361f15b433c..73d465ae3641b94bb806b297268f3b89e79e5884 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -293,7 +293,6 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/dynamicImport.cpp compiler/lowering/ets/restTupleLowering.cpp compiler/lowering/ets/spreadLowering.cpp - compiler/lowering/ets/localClassLowering.cpp compiler/lowering/ets/objectIndexAccess.cpp compiler/lowering/ets/objectIterator.cpp compiler/lowering/ets/insertOptionalParametersAnnotation.cpp diff --git a/ets2panda/REVIEWERS b/ets2panda/REVIEWERS index 20cd974d164d3590f1662d4536bd3053816e61ed..9305160b98b4c953fad028c5484fbb8bdcb85cb0 100644 --- a/ets2panda/REVIEWERS +++ b/ets2panda/REVIEWERS @@ -87,12 +87,8 @@ /ets2panda/checker/types/ets/etsTypeParameter.* ^vpukhov @gogabr ^igelhaus ^Prof1983 /ets2panda/checker/types/ets/etsUnionType.* @akmaevaleksey ^vpukhov ^igelhaus ^Prof1983 /ets2panda/checker/types/ets/wildcardType.* ^vpukhov @gogabr ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/ @gogabr ^igelhaus ^Prof1983 ^zelentsovdmitry -/ets2panda/compiler/lowering/ets/const* @ziziziiziziz @lirismankarina ^akmaevaleksey ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/enum* @ziziziiziziz @dkofanov ^akmaevaleksey ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @Ekkoruse @gogabr ^vpukhov ^akmaevaleksey ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/localClassLowering.cpp @gogabr ^akmaevaleksey ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/optionalLowering.cpp @akmaevaleksey ^vpukhov ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/spread* @ziziziiziziz @dkofanov ^akmaevaleksey ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/unionLowering.cpp @Ekkoruse @akmaevaleksey ^vpukhov ^igelhaus ^Prof1983 -/ets2panda/compiler/lowering/ets/topLevelStmts/.* @lirismankarina @xuxjeeee ^akmaevaleksey ^vpukhov ^igelhaus ^Prof1983 +/ets2panda/compiler/lowering/ets/ @akmaevaleksey ^igelhaus ^Prof1983 ^zelentsovdmitry +/ets2panda/compiler/lowering/ets/lambdaLowering.cpp ^vpukhov @akmaevaleksey @gogabr ^igelhaus ^Prof1983 +/ets2panda/compiler/lowering/ets/optionalLowering.cpp ^vpukhov @akmaevaleksey ^igelhaus ^Prof1983 +/ets2panda/compiler/lowering/ets/unionLowering.cpp ^vpukhov @akmaevaleksey ^igelhaus ^Prof1983 +/ets2panda/compiler/lowering/ets/topLevelStmts/.* ^vpukhov @akmaevaleksey ^igelhaus ^Prof1983 diff --git a/ets2panda/ast_verifier/ASTVerifier.h b/ets2panda/ast_verifier/ASTVerifier.h index 9aaa1aecc3e55d08feea243f73b2f6329e0b46f7..1bd190ef7657372f5f3b05fa905c94602a9fbac7 100644 --- a/ets2panda/ast_verifier/ASTVerifier.h +++ b/ets2panda/ast_verifier/ASTVerifier.h @@ -129,7 +129,8 @@ public: i <= VerifierInvariants::AFTER_CHECKER_PHASE_LAST; i++) { allowed_[i] = true; } - // NOTE(dkofanov): This should be called after "NumberLowering" phase: + } + if (occurredPhaseName == "Unbox") { Get()->SetNumberLoweringOccured(); } if (occurredPhaseName == "UnionLowering") { diff --git a/ets2panda/ast_verifier/invariants/nodeHasType.h b/ets2panda/ast_verifier/invariants/nodeHasType.h index 12e7eaf4e6b12063468326eba03f866100c717ab..c48d97ce8095479c72c9335c9ee02d918353aac1 100644 --- a/ets2panda/ast_verifier/invariants/nodeHasType.h +++ b/ets2panda/ast_verifier/invariants/nodeHasType.h @@ -49,7 +49,8 @@ public: if (type == nullptr) { return {CheckDecision::CORRECT, CheckAction::CONTINUE}; } - if (!numberLoweringOccurred_ && type->IsETSPrimitiveType()) { + // NOTE(dkofanov): Broken extension functions. + if (!numberLoweringOccurred_ && !type->IsETSExtensionFuncHelperType() && type->IsETSPrimitiveType()) { AddCheckMessage("PRIMITIVE_BEFORE_LOWERING", *ast); return {CheckDecision::INCORRECT, CheckAction::CONTINUE}; } diff --git a/ets2panda/bindings/src/common/preDefine.ts b/ets2panda/bindings/src/common/preDefine.ts index 0de1510a8f34aa704a76e10152b60582694c7459..79f470bd73f3d0e57f550c3dbafd4d309fe08aba 100644 --- a/ets2panda/bindings/src/common/preDefine.ts +++ b/ets2panda/bindings/src/common/preDefine.ts @@ -26,3 +26,5 @@ export const PANDA_SDK_PATH_FROM_SDK: string = './build-tools/ets2panda'; export const SYSTEM_SDK_PATH_FROM_SDK: string = './'; export const EXTERNAL_API_PATH_FROM_SDK: string = '../../../hms/ets/ets1.2'; export const DEFAULT_CACHE_DIR: string = './.idea/.deveco'; +export const ETS_SUFFIX: string = '.ets'; +export const TS_SUFFIX: string = '.ts'; diff --git a/ets2panda/bindings/src/common/utils.ts b/ets2panda/bindings/src/common/utils.ts index 7c900df5ad61e1de643d0922e47a31e0c1bdf364..800f92b064490f638bf0e71299ed0809ab6bcf76 100644 --- a/ets2panda/bindings/src/common/utils.ts +++ b/ets2panda/bindings/src/common/utils.ts @@ -16,6 +16,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; +import { DECL_ETS_SUFFIX } from './preDefine'; export function throwError(error: string): never { throw new Error(error); @@ -48,3 +49,21 @@ export function ensurePathExists(filePath: string): void { export function isMac(): boolean { return os.type() === 'Darwin'; } + +export function changeDeclgenFileExtension(file: string, targetExt: string): string { + if (file.endsWith(DECL_ETS_SUFFIX)) { + return changeFileExtension(file, targetExt, DECL_ETS_SUFFIX); + } + return changeFileExtension(file, targetExt); +} + +export function getModuleNameAndPath(filePath: string, projectPath: string): [string, string] { + let moduleName: string = ''; + let moduleRootPath: string = ''; + if (filePath.indexOf(projectPath) >= 0) { + const relativePath = path.relative(projectPath, filePath); + moduleName = relativePath.split(path.sep)[0]; + moduleRootPath = path.join(projectPath, moduleName); + } + return [moduleName, moduleRootPath]; +} diff --git a/ets2panda/bindings/src/lsp/lsp_helper.ts b/ets2panda/bindings/src/lsp/lsp_helper.ts index 8500c1a2012e78608b849c1827e77a182a02de88..4e2fc5e6f049f49a9fa30feaa0a9aa32d500e90f 100644 --- a/ets2panda/bindings/src/lsp/lsp_helper.ts +++ b/ets2panda/bindings/src/lsp/lsp_helper.ts @@ -74,9 +74,13 @@ import { NativePtrDecoder } from '../common/Platform'; import { Worker as ThreadWorker } from 'worker_threads'; import { ensurePathExists } from '../common/utils'; import * as child_process from 'child_process'; -import { DECL_ETS_SUFFIX, DEFAULT_CACHE_DIR } from '../common/preDefine'; +import { DECL_ETS_SUFFIX, DEFAULT_CACHE_DIR, TS_SUFFIX } from '../common/preDefine'; import * as crypto from 'crypto'; import * as os from 'os'; +import { + changeDeclgenFileExtension, + getModuleNameAndPath +} from '../common/utils'; const ets2pandaCmdPrefix = ['-', '--extension', 'ets', '--arktsconfig']; @@ -121,6 +125,7 @@ export class Lsp { this.moduleInfos = generateArkTsConfigs(this.buildConfigs); this.pathConfig = pathConfig; PluginDriver.getInstance().initPlugins(Object.values(this.buildConfigs)[0]); + this.generateDeclFile(); } // Partially update for new file @@ -146,13 +151,165 @@ export class Lsp { } private getFileSource(filePath: string): string { - const getSource = this.filesMap.get(filePath) || this.getFileContent(filePath); - if (!getSource) { + const getSource = this.filesMap.get(filePath) || this.getFileContent(filePath) || fs.readFileSync(filePath, 'utf8'); + if (getSource === undefined) { throw new Error(`File content not found for path: ${filePath}`); } return getSource.replace(/\r\n/g, '\n'); } + generateDeclFile(): void { + let lspDriverHelper = new LspDriverHelper(); + for (const [moduleName, buildConfig] of Object.entries(this.buildConfigs)) { + if (!buildConfig.enableDeclgenEts2Ts) { + continue; + } + if (!buildConfig.declgenOutDir || buildConfig.declgenOutDir === '') { + return; + } + buildConfig.compileFiles.forEach((compilefilePath: string) => { + if (!this.moduleInfos.hasOwnProperty(compilefilePath)) { + return; + } + let sourceFilePath = path.resolve(compilefilePath); + const moduleInfo = this.moduleInfos[compilefilePath]; + let arktsconfig = moduleInfo.arktsConfigFile; + let ets2pandaCmd = ets2pandaCmdPrefix.concat(arktsconfig); + let localCfg = lspDriverHelper.createCfg(ets2pandaCmd, sourceFilePath, this.pandaLibPath); + const source = this.getFileSource(compilefilePath); + let localCtx = lspDriverHelper.createCtx(source, compilefilePath, localCfg); + PluginDriver.getInstance().getPluginContext().setContextPtr(localCtx); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_CHECKED); + // declgen file + let modulePath: string = path.relative(buildConfig.moduleRootPath, compilefilePath); + let declOut: string = ''; + let declBridgeOut: string = ''; + if (!moduleInfo.declgenV1OutPath) { + declOut = path.join(buildConfig.declgenOutDir, moduleName); + } + if (!moduleInfo.declgenBridgeCodePath) { + declBridgeOut = path.join(buildConfig.declgenOutDir, moduleName); + } + let declEtsOutputPath: string = changeDeclgenFileExtension( + path.join(moduleInfo.declgenV1OutPath ?? declOut, modulePath), + DECL_ETS_SUFFIX + ); + let etsOutputPath: string = changeDeclgenFileExtension( + path.join(moduleInfo.declgenBridgeCodePath ?? declBridgeOut, modulePath), + TS_SUFFIX + ); + ensurePathExists(declEtsOutputPath); + ensurePathExists(etsOutputPath); + global.es2pandaPublic._GenerateTsDeclarationsFromContext( + localCtx, + declEtsOutputPath, + etsOutputPath, + 1, + 0 + ); + let declfilePath = path.resolve(declEtsOutputPath); + let declgLocalCfg = lspDriverHelper.createCfg(ets2pandaCmd, declfilePath, this.pandaLibPath); + const declgSource = this.getFileSource(declfilePath); + let declgLocalCtx = lspDriverHelper.createCtx(declgSource, declfilePath, declgLocalCfg); + PluginDriver.getInstance().getPluginContext().setContextPtr(declgLocalCtx); + lspDriverHelper.proceedToState(declgLocalCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + lspDriverHelper.proceedToState(declgLocalCtx, Es2pandaContextState.ES2PANDA_STATE_CHECKED); + // clean and destroy + PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + lspDriverHelper.destroyContext(localCtx); + lspDriverHelper.destroyContext(declgLocalCtx); + }); + } + } + + modifyDeclFile(modifyFilePath: string, arktsConfigFile?: string): void { + // source file + let lspDriverHelper = new LspDriverHelper(); + let sourceFilePath = path.resolve(modifyFilePath.valueOf()); + let moduleInfo: ModuleInfo; + if (this.moduleInfos.hasOwnProperty(sourceFilePath)) { + moduleInfo = this.moduleInfos[sourceFilePath]; + } else { + const [newModuleName, newModuleRootPath] = getModuleNameAndPath(modifyFilePath, this.pathConfig.projectPath); + if (newModuleName && newModuleName !== '' && newModuleRootPath && newModuleRootPath !== '') { + moduleInfo = { + packageName: newModuleName, + moduleRootPath: newModuleRootPath, + moduleType: '', + entryFile: '', + arktsConfigFile: arktsConfigFile ?? '', + compileFiles: [], + declgenV1OutPath: '', + declgenBridgeCodePath: '', + staticDepModuleInfos: [], + dynamicDepModuleInfos: [], + language: '' + }; + } else { + return; + } + } + const moduleName = moduleInfo.packageName; + const moduleRootPath = moduleInfo.moduleRootPath; + if (!this.buildConfigs.hasOwnProperty(moduleName)) { + return; + } + const buildConfig = this.buildConfigs[moduleName]; + if (!buildConfig.enableDeclgenEts2Ts) { + return; + } + let arktsconfig = moduleInfo.arktsConfigFile; + let ets2pandaCmd = ets2pandaCmdPrefix.concat(arktsconfig); + let localCfg = lspDriverHelper.createCfg(ets2pandaCmd, sourceFilePath, this.pandaLibPath); + const source = this.getFileSource(sourceFilePath); + let localCtx = lspDriverHelper.createCtx(source, sourceFilePath, localCfg); + PluginDriver.getInstance().getPluginContext().setContextPtr(localCtx); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_CHECKED); + // declgen file + let declOut: string = ''; + let declBridgeOut: string = ''; + if (!moduleInfo.declgenV1OutPath) { + declOut = path.join(buildConfig.declgenOutDir, moduleName); + } + if (!moduleInfo.declgenBridgeCodePath) { + declBridgeOut = path.join(buildConfig.declgenOutDir, moduleName); + } + let filePathFromModuleRoot: string = path.relative(moduleRootPath, modifyFilePath); + let declEtsOutputPath: string = changeDeclgenFileExtension( + path.join(moduleInfo.declgenV1OutPath ?? declOut, filePathFromModuleRoot), + DECL_ETS_SUFFIX + ); + let etsOutputPath: string = changeDeclgenFileExtension( + path.join(moduleInfo.declgenBridgeCodePath ?? declBridgeOut, filePathFromModuleRoot), + TS_SUFFIX + ); + ensurePathExists(declEtsOutputPath); + ensurePathExists(etsOutputPath); + global.es2pandaPublic._GenerateTsDeclarationsFromContext( + localCtx, + declEtsOutputPath, + etsOutputPath, + 1, + 0 + ); + let filePath = path.resolve(declEtsOutputPath); + let declgLocalCfg = lspDriverHelper.createCfg(ets2pandaCmd, filePath, this.pandaLibPath); + const declgSource = this.getFileSource(filePath); + let declgLocalCtx = lspDriverHelper.createCtx(declgSource, filePath, declgLocalCfg); + PluginDriver.getInstance().getPluginContext().setContextPtr(declgLocalCtx); + lspDriverHelper.proceedToState(declgLocalCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + lspDriverHelper.proceedToState(declgLocalCtx, Es2pandaContextState.ES2PANDA_STATE_CHECKED); + lspDriverHelper.destroyContext(declgLocalCtx); + PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + lspDriverHelper.destroyContext(localCtx); + } + getDefinitionAtPosition(filename: String, offset: number): LspDefinitionData { let lspDriverHelper = new LspDriverHelper(); let filePath = path.resolve(filename.valueOf()); diff --git a/ets2panda/bindings/test/BUILD.gn b/ets2panda/bindings/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..83a299be121b1c897c8351347ee6ac00f76f1524 --- /dev/null +++ b/ets2panda/bindings/test/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright (c) 2025 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("//build/version.gni") + +action("bindings_test") { + script = "run_bindings.sh" + args = [ + rebase_path("./"), + rebase_path( + "//prebuilts/build-tools/common/nodejs/node-v16.20.2-linux-x64/bin"), + rebase_path("//prebuilts/ohos-sdk/linux/${api_version}/ets"), + ] + outputs = [ "$target_out_dir/$target_name.timestamp" ] +} diff --git a/ets2panda/bindings/test/cases.ts b/ets2panda/bindings/test/cases.ts index f353848c71171c8daa1a077116a00d32cde1724e..316424244ca6f00288d8b4d375fe66440e5fced6 100644 --- a/ets2panda/bindings/test/cases.ts +++ b/ets2panda/bindings/test/cases.ts @@ -63,6 +63,10 @@ export const testCases: TestCases = { expectedFilePath: resolveTestPath('test/expected/getFileReferences.json'), '1': [resolveTestPath('test/testcases/getFileReferences/getFileReferences1_export.ets')] }, + getFileSource: { + expectedFilePath: resolveTestPath('test/expected/getFileSource.json'), + '1': [resolveTestPath('test/testcases/getFileSource/getFileSource1.ets')] + }, getReferencesAtPosition: { expectedFilePath: resolveTestPath('test/expected/getReferencesAtPosition.json'), '1': [resolveTestPath('test/testcases/getReferencesAtPosition/getReferencesAtPosition1.ets'), 613], @@ -145,6 +149,21 @@ export const testCases: TestCases = { getRenameInfo: { expectedFilePath: resolveTestPath('test/expected/getRenameInfo.json'), '1': [resolveTestPath('test/testcases/getRenameInfo/getRenameInfo1.ets'), 615] + }, + entry: { + expectedFilePath: '', + '1': [resolveTestPath('test/testcases/entry/Index.ets'), 615] + } +}; + +export const testSingleModuleCases: TestCases = { + generateDeclFile: { + expectedFilePath: resolveTestPath('test/expected/generateDeclFile.json'), + '1': [] + }, + modifyDeclFile: { + expectedFilePath: resolveTestPath('test/expected/modifyDeclFile.json'), + '1': [resolveTestPath('test/testcases/modifyDeclFile/entry/index.ets')] } }; diff --git a/ets2panda/bindings/test/expected/generateDeclFile.json b/ets2panda/bindings/test/expected/generateDeclFile.json new file mode 100644 index 0000000000000000000000000000000000000000..adaa8c41ba026024e8124327c13034438725b998 --- /dev/null +++ b/ets2panda/bindings/test/expected/generateDeclFile.json @@ -0,0 +1,13 @@ +{ + "1": [ + "generateDeclFile1.d.ets", + "generateDeclFile2.d.ets", + "generateDeclFile3.d.ets", + "generateDeclFile4.d.ets", + "generateDeclFile5.d.ets", + "generateDeclFile6.d.ets", + "generateDeclFile7.d.ets", + "generateDeclFile8.d.ets", + "generateDeclFile9.d.ets" + ] +} \ No newline at end of file diff --git a/ets2panda/bindings/test/expected/getFileSource.json b/ets2panda/bindings/test/expected/getFileSource.json new file mode 100644 index 0000000000000000000000000000000000000000..e893655add4e990ee5dee52a66bfe7be02fb141d --- /dev/null +++ b/ets2panda/bindings/test/expected/getFileSource.json @@ -0,0 +1,3 @@ +{ + "1": "/*\n * Copyright (c) 2025 Huawei Device Co., Ltd.\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nlet a = 1;" +} \ No newline at end of file diff --git a/ets2panda/bindings/test/expected/getSemanticDiagnostics.json b/ets2panda/bindings/test/expected/getSemanticDiagnostics.json index 8c5983e344c9d934e82d615714ffba32e6034f6d..96a6551b8dfa9c62b550d290056103419fae7360 100644 --- a/ets2panda/bindings/test/expected/getSemanticDiagnostics.json +++ b/ets2panda/bindings/test/expected/getSemanticDiagnostics.json @@ -19,7 +19,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 2046, "data": 0, "severity": 1, "codeDescription": { @@ -41,7 +41,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 2127, "data": 0, "severity": 1, "codeDescription": { @@ -63,7 +63,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 2318, "data": 0, "severity": 1, "codeDescription": { diff --git a/ets2panda/bindings/test/expected/getSyntacticDiagnostics.json b/ets2panda/bindings/test/expected/getSyntacticDiagnostics.json index baa3c0c3ad58cc3a339fcb4b84e70d6fc018dd53..37ff72da0fa39654a354aa2434f21d8f43e66507 100644 --- a/ets2panda/bindings/test/expected/getSyntacticDiagnostics.json +++ b/ets2panda/bindings/test/expected/getSyntacticDiagnostics.json @@ -19,7 +19,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -41,7 +41,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1229, "data": 0, "severity": 1, "codeDescription": { @@ -63,7 +63,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -85,7 +85,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -107,7 +107,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -129,7 +129,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -151,7 +151,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -160,20 +160,20 @@ }, { "message": "Unexpected token 'b'.", - "source": "", + "source": "functon;\nadd(a);\n*ERROR_LITERAL*;\nnumber;\n*ERROR_LITERAL*;\n\nnumber;\n*ERROR_LITERAL*;\n{\n return ((a) + (b));\n}\nn = 333;\nres = add(n, n);", "range": { "start": { "line": 16, - "character": 24 + "character": 1 }, "end": { - "line": 16, - "character": 24 + "line": 20, + "character": 20 } }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -195,7 +195,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1038, "data": 0, "severity": 1, "codeDescription": { @@ -217,7 +217,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -239,7 +239,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -261,7 +261,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1227, "data": 0, "severity": 1, "codeDescription": { @@ -283,7 +283,7 @@ }, "tags": [], "relatedInfo": [], - "code": 1, + "code": 1163, "data": 0, "severity": 1, "codeDescription": { diff --git a/ets2panda/bindings/test/expected/modifyDeclFile.json b/ets2panda/bindings/test/expected/modifyDeclFile.json new file mode 100644 index 0000000000000000000000000000000000000000..7fdd0ca29e096b806eabf4df9e425542065d18be --- /dev/null +++ b/ets2panda/bindings/test/expected/modifyDeclFile.json @@ -0,0 +1,7 @@ +{ + "1": [ + "modifyDeclFile1.d.ets", + "modifyDeclFile2.d.ets", + "modifyDeclFile3.d.ets" + ] +} \ No newline at end of file diff --git a/ets2panda/bindings/test/monitor_node.js b/ets2panda/bindings/test/monitor_node.js new file mode 100644 index 0000000000000000000000000000000000000000..aade7588cfa828f60cbb067cb4f692eaf18b54e8 --- /dev/null +++ b/ets2panda/bindings/test/monitor_node.js @@ -0,0 +1,48 @@ +#!/usr/bin/env node +/* + * Copyright (c) 2025 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. + */ + +const { spawn } = require('child_process'); + +const child = spawn(process.argv[2], process.argv.slice(3), { + stdio: 'inherit', + detached: true, + windowsHide: true +}); + +const timeout = setTimeout(() => { + console.error('process timeout'); + child.kill('SIGKILL'); + process.exit(124); +}, 900000); + +child.on('exit', (code, signal) => { + clearTimeout(timeout); + + if (signal === 'SIGSEGV' || signal === 'SIGABRT') { + console.error(`process crashe: ${signal}`); + process.exit(128 + signal); + } else { + process.exit(code ?? 0); + } +}); + +child.on('error', (err) => { + clearTimeout(timeout); + console.error(`Promoter process failure: ${err.message}`); + process.exit(127); +}); + +child.unref(); \ No newline at end of file diff --git a/ets2panda/bindings/test/run_bindings.sh b/ets2panda/bindings/test/run_bindings.sh new file mode 100755 index 0000000000000000000000000000000000000000..7fef1f2f16c23a3fbecf887dbaab90835f1141e3 --- /dev/null +++ b/ets2panda/bindings/test/run_bindings.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright (c) 2025 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. + +set -e + +readonly TEST_DIR="$1" +readonly NODE_DIR="$2" +readonly SDK_DIR="$3" +readonly CWD="${TEST_DIR}/../" +readonly CURRENT_NPM="${NODE_DIR}/npm" +readonly CURRENT_NODE="${NODE_DIR}/node" + +cp -rfp -- "$SDK_DIR" "$TEST_DIR" +cd "$CWD" && "$CURRENT_NPM" run test:build +if [ $? -eq 0 ]; then + echo "bindings test build successfully" +else + echo "bindings test build failed" + exit 1 +fi + +"$CURRENT_NODE" test/monitor_node.js "$CURRENT_NODE" --unhandled-rejections=strict dist-test/test/run_tests.js ./test +exit_code=$? +if [ $exit_code -eq 0 ]; then + echo "test execution successfully" +else + echo "test execution failed" + exit $exit_code +fi diff --git a/ets2panda/bindings/test/run_tests.ts b/ets2panda/bindings/test/run_tests.ts index 9220c53c917f33f75723dd47b730ec8a668ce23d..9e7ae34818e84998d3016c9f7b9d30f82a1b702f 100644 --- a/ets2panda/bindings/test/run_tests.ts +++ b/ets2panda/bindings/test/run_tests.ts @@ -16,7 +16,7 @@ import path from 'path'; import fs from 'fs'; import { Lsp, LspDefinitionData, LspCompletionInfo, LspDiagsNode, ModuleDescriptor, PathConfig } from '../src/index'; -import { testCases } from './cases'; +import { testCases, testSingleModuleCases } from './cases'; import { LspCompletionEntry } from '../src/lsp/lspNode'; interface ComparisonOptions { @@ -53,6 +53,19 @@ function getExpectedResult(filePath: string): any { } } +// CC-OFFNXT(no_explicit_any) project code style +function getFilesByDir(dirPath: string): string[] { + try { + return fs.readdirSync(dirPath) + .filter(file => + fs.statSync(path.join(dirPath, file)).isFile() + ); + } catch (err) { + console.error(`Failed to load files from ${dirPath}: ${err}`); + return []; + } +} + function sortCompletions(completionResult: LspCompletionInfo): LspCompletionInfo { if (!completionResult || !completionResult.entries || !Array.isArray(completionResult.entries)) { return completionResult; @@ -220,6 +233,15 @@ function compareGetCompletionResult(testName: string, actual: unknown, expected: } as ComparisonOptions); } +function compareDeclFileResult(testName: string, declgenOutDir: string, expected: unknown): boolean { + let fileList: string[] = getFilesByDir(declgenOutDir); + const actualEntries = fileList.filter(file => file.endsWith('.d.ets')); + const expectedEntries = expected as string[]; + return compareResultsHelper(testName, normalizeData(actualEntries), expectedEntries, { + subMatch: true + } as ComparisonOptions); +} + function findTextDefinitionPosition(sourceCode: string): number { const textDefinitionPattern = /export\s+declare\s+function\s+Text\(/; const match = textDefinitionPattern.exec(sourceCode); @@ -280,7 +302,7 @@ function compareGetDefinitionResult(testName: string, actual: any, expected: Rec } // CC-OFFNXT(no_explicit_any) project code style -function compareResults(testName: string, index: string, actual: unknown, expected: unknown): boolean { +function compareResults(testName: string, index: string, actual: unknown, expected: unknown, declgenOutDir: string = ''): boolean { const name = `${testName}:${index}`; if (testName === 'getDefinitionAtPosition') { return compareGetDefinitionResult(name, actual, expected as Record); @@ -288,15 +310,17 @@ function compareResults(testName: string, index: string, actual: unknown, expect if (testName === 'getCompletionAtPosition') { return compareGetCompletionResult(name, actual, expected); } - + if (testName === 'generateDeclFile' || testName === 'modifyDeclFile') { + const declOutPath = path.join(declgenOutDir, 'dynamic', 'dep', 'declgenV1'); + return compareDeclFileResult(name, declOutPath, expected); + } return compareResultsHelper(name, normalizeData(actual), expected); } -function runTests(testDir: string, lsp: Lsp) { +function runTests(lsp: Lsp): string[] { console.log('Running tests...'); if (!testCases) { - console.error('Failed to load test cases'); - return; + return []; } let failedList: string[] = []; @@ -338,13 +362,133 @@ function runTests(testDir: string, lsp: Lsp) { console.log(`Finished test: ${testName}`); console.log('-----------------------------------'); } + return failedList; +} + +function runSingleTests(testDir: string, failedList: string[]): string[] { + console.log('Running single tests...'); + if (!testSingleModuleCases) { + return []; + } + const testSrcPath = path.join(testDir, 'testcases'); + for (const [testName, testConfig] of Object.entries(testSingleModuleCases)) { + const testBuildPath = path.join(testSrcPath, '.idea', '.deveco', testName); + let pathConfig: PathConfig = { + buildSdkPath: path.join(testDir, 'ets', 'ets1.2'), + projectPath: testBuildPath, + declgenOutDir: testBuildPath + }; + const moduleList: ModuleDescriptor[] = [ + { + arktsversion: '1.1', + name: 'entry', + moduleType: 'har', + srcPath: path.join(testSrcPath, testName, 'entry') + }, + { + arktsversion: '1.2', + name: 'dep', + moduleType: 'har', + srcPath: path.join(testSrcPath, testName, 'dep') + } + ] as ModuleDescriptor[]; + const lsp = new Lsp(pathConfig, undefined, moduleList); + const { expectedFilePath, ...testCaseVariants } = testConfig; + const expectedResult = getExpectedResult(expectedFilePath); + if (expectedResult === null) { + console.error(`[${testName}] Skipped (expected result not found)`); + continue; + } + // CC-OFFNXT(no_explicit_any) project code style + if (typeof (lsp as any)[testName] !== 'function') { + console.error(`[${testName}] ❌ Error: Method "${testName}" not found on Lsp object`); + continue; + } + + for (const [index, params] of Object.entries(testCaseVariants)) { + let pass = false; + let actualResult = null; + try { + // CC-OFFNXT(no_explicit_any) project code style + actualResult = (lsp as any)[testName](...params); + actualResult = sortActualResult(testName, actualResult); + pass = compareResults(testName, index, actualResult, expectedResult[index], pathConfig.declgenOutDir); + } catch (error) { + console.error(`[${testName}:${index}] ❌ Error: ${error}`); + } + if (!pass) { + failedList.push(`${testName}:${index}`); + } + if (!pass && updateMode) { + console.log(`Updating expected result for ${testName}:${index}`); + expectedResult[index] = normalizeData(actualResult); + } + } + if (updateMode) { + fs.writeFileSync(expectedFilePath, JSON.stringify(expectedResult, null, 2)); + } + console.log(`Finished test: ${testName}`); + console.log('-----------------------------------'); + } + return failedList; +} + +function run(lsp: Lsp, testDir: string): void { + let failedList = runTests(lsp); + failedList = runSingleTests(testDir, failedList); + console.log('Tests completed.'); if (failedList.length > 0) { console.log('❌ Failed tests:'); - failedList.forEach((failedCase) => { + failedList.forEach((failedCase: string) => { console.log(`- ${failedCase}`); }); + + console.error('Tests failed without AST cache'); + process.exit(1); + } else { + if (!testCases) { + console.error('Failed to load test cases'); + } + if (!testSingleModuleCases) { + console.error('Failed to load single module test cases'); + } + if (!testCases && !testSingleModuleCases) { + console.error('Tests failed without AST cache'); + process.exit(1); + } } + console.log('Finished test without ast cache'); +} + +async function runWithAstCache(lsp: Lsp, modules: ModuleDescriptor[], testDir: string): Promise { + await lsp.initAstCache(); + lsp.update(modules); + let failedList = runTests(lsp); + failedList = runSingleTests(testDir, failedList); + + console.log('Tests completed.'); + if (failedList.length > 0) { + console.log('❌ Failed tests:'); + failedList.forEach((failedCase: string) => { + console.log(`- ${failedCase}`); + }); + + console.error('Tests failed with AST cache'); + process.exit(1); + } else { + if (!testCases) { + console.error('Failed to load test cases'); + } + if (!testSingleModuleCases) { + console.error('Failed to load single module test cases'); + } + if (!testCases && !testSingleModuleCases) { + console.error('Tests failed without AST cache'); + process.exit(1); + } + } + console.log('Finished test with ast cache'); } if (require.main === module) { @@ -357,16 +501,27 @@ if (require.main === module) { updateMode = true; } const testDir = path.resolve(process.argv[2]); - const pathConfig: PathConfig = { + let pathConfig: PathConfig = { buildSdkPath: path.join(testDir, 'ets', 'ets1.2'), projectPath: path.join(testDir, 'testcases'), declgenOutDir: '' }; const modules = getModules(pathConfig.projectPath); - - const lsp = new Lsp(pathConfig, undefined, modules); - process.env.BINDINGS_PATH = path.join(pathConfig.buildSdkPath, 'build-tools', 'bindings'); - runTests(testDir, lsp); + process.env.PANDA_LIB_PATH = path.join(pathConfig.buildSdkPath, 'build-tools', 'ets2panda', 'lib'); + process.env.PANDA_BIN_PATH = path.join(pathConfig.buildSdkPath, 'build-tools', 'ets2panda', 'bin'); + const lsp = new Lsp(pathConfig, undefined, modules); + run(lsp, testDir); + // for generate ast cache + const entry_module = [ + { + arktsversion: '1.2', + name: 'entry', + moduleType: 'har', + srcPath: path.join(pathConfig.projectPath, 'entry') + } + ]; + const lsp_1 = new Lsp(pathConfig, undefined, entry_module); + runWithAstCache(lsp_1, modules, testDir).then(() => {}); } diff --git a/ets2panda/bindings/test/testcases/entry/Index.ets b/ets2panda/bindings/test/testcases/entry/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a665975076ca05f9e8111b218136fdbff21f123c --- /dev/null +++ b/ets2panda/bindings/test/testcases/entry/Index.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2025 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 { Text, Column, Component, Entry, Button, ClickEvent } from "@ohos.arkui.component" +import { State, Link, Prop } from "@ohos.arkui.stateManagement" +import hilog from '@ohos.hilog' + +@Entry +@Component +struct MyStateSample { + @State stateVar: string = "state var"; + message: string = `click to change state variable, add **`; + changeValue() { + this.stateVar+="**" + } + build() { + Column() { + Button("clean variable").onClick((e: ClickEvent) => { this.stateVar = "state var" }) + Text("Hello World").fontSize(20) + Button(this.message).backgroundColor("#FFFF00FF") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + this.changeValue() + }) + Text(this.stateVar).fontSize(20) + Child({linkVar: this.stateVar, propVar: this.stateVar}) + }.margin(10) + } +} + +@Component +struct Child { + @Link linkVar: string = ""; // TODO: remove this + @Prop propVar: string = "Prop"; + + changeValue1() { + this.linkVar+="!!" + } + + changeValue2() { + this.propVar+="~~" + } + + build() { + Column() { + Button(`click to change Link variable, add symbol !!`) + .backgroundColor("#4169E1") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + this.changeValue1() + }) + Button(`click to change Prop variable, add symbol ~~`) + .backgroundColor("#3CB371") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + this.changeValue2() + }) + Text(`Link variable in child: ${this.linkVar}`).fontSize(30) + Text(`Prop variable in child: ${this.propVar}`).fontSize(30) + } + } +} \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile1.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7f033b2c0310beab1cecebeb2efb412fd53521a1 --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile1.ets @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2025 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. + */ + +let currentValue: string = 'currentValue'; + +let resultValue: number = -1; + +let mathRandom: number = 14; + +function getCurrentValue(): number { + let firstValue = getFirstValue(); + let secondValue = getSecondValue(); + let thridValue = getThridValue(); + resultValue = currentValue.length; + return currentValue.length; +} + +function getFirstValue(): number { + let c = 15; + let value = c * mathRandom; + mathRandom++; + EtsStepArkTest() + return value; +} + +function getSecondValue(): number { + let d = 11; + let value1 = getFirstValue(); + return value1 * d; +} + +function getThridValue(): number { + let value1 = getFirstValue(); + let value2 = getSecondValue(); + return value1 * value2; +} + +function getValue(): string { + return getCurrentValue() + currentValue; +} + +getValue(); \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile2.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile2.ets new file mode 100644 index 0000000000000000000000000000000000000000..d86e832dddad78e9c7c27228d4c1c1635ffe34fa --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile2.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 Foo { + Foo(a:number, b:number): number { + return a + b; + } +} diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile3.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile3.ets new file mode 100644 index 0000000000000000000000000000000000000000..74e5fc562609d051b80763d02a9004b538ef7c5d --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile3.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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 A(a:number, b:number): number { + return a + b; +} +A(1, 2); +function A(a:number): number { + return a; +} +A(1); diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile4.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile4.ets new file mode 100644 index 0000000000000000000000000000000000000000..7b762ba46101e5106cf2329ceb9fb4250b9e4439 --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile4.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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 A { + Foo(a:number, b:number): number { + return a + b; + } + readTest1(c:number, d:number): number { + return a - b; + } + + readTest2(e:number, f:number): number { + return a * b; + } + + readTest3(e:number, f:number): number { + return a / b; + } +}; \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile5.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile5.ets new file mode 100644 index 0000000000000000000000000000000000000000..50e29bb12fe3e8702274b4d541f47003f79e7de9 --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile5.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 A { + Foo(a:number, b:number): number { + return a + b; + } +} diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile6.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile6.ets new file mode 100644 index 0000000000000000000000000000000000000000..c54a0d1535beb24b839528d630e01201cd4010fa --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile6.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement"; +import { Text, Column, Component, Button, ClickEvent } from "@ohos.arkui.component"; + +import hilog from '@ohos.hilog'; + +@Component +export struct MyStateSample { + message: string = "Click"; + + build() { + Column(undefined) { + Text("Hello World") + .fontSize(20) + Button(this.message) + .backgroundColor("#FFFF00FF") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + }) + Child() + } + } +} + +@Component +export struct Child { + stateVar: string = "Child"; + + build() { + Text(this.stateVar) + .fontSize(50) + } +} diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile7.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile7.ets new file mode 100644 index 0000000000000000000000000000000000000000..3f8d64d3fa9e7cc595245dbc303453427804d928 --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile7.ets @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface DataValue { + a: number; + b: string; + c: string; + d: number; +} + +let currentValue: DataValue = { + a: 12, + b: 'da', + c: 'vk', + d: 1111 +}; + +let result: number = 0; + +let resultStr: number = 0; + +let resultValue: number = -1; + +let mathRandom: number = 14; + +function getPath(c: number, d: number): number { + return c * d; +} + +function getPathDate(c: number): number { + return c * 2 + 6; +} + +function getCurrentValue(): DataValue { + let currentValue: DataValue = { + a: 12, + b: 'da', + c: 'vk', + d: 1111 + }; + currentValue.a = getFirstValue(); + currentValue.d = getSecondValue(); + currentValue.c = getThridValue() + getSecondValue() + getFirstValue(); + currentValue.b = getThridValue() + getSecondValue() + getFirstValue() + resultValue; + EtsStepArkTest() + while(currentValue.a < 12) { + if (resultValue % 2 === 0) { + currentValue.a = currentValue.a++; + } else { + currentValue.d = currentValue.d--; + } + } + return currentValue; +} + +function getFirstValue(): number { + let currentFirstValue: DataValue = { + a: 23, + b: '124f', + c: 'gfr', + d: 767 + }; + EtsStepArkTest() + return getPath(currentFirstValue.a, currentFirstValue.d); +} + +function getSecondValue(): number { + for(let index = 0; index < 2; index++) { + result = getPathDate(index); + } + return result; +} + +function getThridValue(): string { + let dd: string = ''; + for(let index = 0; index< 2; index++) { + dd = resultStr + getPathDate(index) + 'abc'; + } + EtsStepArkTest() + return dd; +} + +function getValueStr(): string { + return getCurrentValue().b + currentValue; +} + +getValueStr(); diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile8.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile8.ets new file mode 100644 index 0000000000000000000000000000000000000000..10859e929cf149305acef118db4e74f319c4d69c --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile8.ets @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2025 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 func06(): void { + EtsStepArkTest(); +} + +function func05(): void { + func06(); + EtsStepArkTest(); +} + +function func04(): void { + func05(); + EtsStepArkTest(); +} + +function func03(): void { + let id = 0; + for (let i = 0; i < 10; ++i) { + id++ + } + func04(); + EtsStepArkTest(); +} + +function func02(): void { + func03(); + EtsStepArkTest(); +} + +function func01(): void { + func02(); + EtsStepArkTest(); +} + +function main(argc:string[]): void { + func01(); +} diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile9.ets b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile9.ets new file mode 100644 index 0000000000000000000000000000000000000000..a38038cd9c441a688778cffb05f72e5692d9ac9f --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/dep/generateDeclFile9.ets @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface FileDataValue { + fileName: string; + filePath: string; + data: DataValue; +} + +interface DataValue { + dataLength: number; + dataOffset: number; + dataStr: string; +} + +class OperationFactory { + private currentType: string = 'add'; + + createOperation(type: 'add' | 'subtract' | 'multiply' | 'divide', a: number, b: number): number { + this.currentType = type; + switch (type) { + case 'add': + return a + b; + case 'subtract': + return a - b; + case 'multiply': + return a * b; + case 'divide': + if (b === 0) { + throw new Error("Division by zero is not allowed."); + } + return a / b; + default: + throw new Error("Unknown operation type"); + } + } +} + +function getFileDate(): FileDataValue[] { + let FileDataValues: FileDataValue[] = [{ + fileName: 'OperationFactoryFile', + filePath: 'source/url/OperationFactoryFile', + data: { + dataLength: 10, + dataOffset: 2, + dataStr: 'This is a test data!' + } + }]; + EtsStepArkTest(); + return FileDataValues; +} + +function getOperationFactory(): void { + getFileDate(); + const factory = new OperationFactory(); + factory.createOperation('add', 2, 3); + factory.createOperation('subtract', 5, 5); + factory.createOperation('multiply', 3, 6); + factory.createOperation('divide', 2, 2); +} + +getOperationFactory(); diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/entry/index.ets b/ets2panda/bindings/test/testcases/generateDeclFile/entry/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..6fc34b5b10bc306f7613a62e1b441e9669e4b02e --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/entry/index.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + + let indexStr: string = "generateDeclFile"; \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/generateDeclFile/entry/oh-package.json5 b/ets2panda/bindings/test/testcases/generateDeclFile/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8ee2596efddc104b26b6ec83ed6fac9ac144acf8 --- /dev/null +++ b/ets2panda/bindings/test/testcases/generateDeclFile/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025 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. + */ + +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + "myDep": "file:../dep" + }, + "devDependencies": { + } +} diff --git a/ets2panda/bindings/test/testcases/getFileSource/getFileSource1.ets b/ets2panda/bindings/test/testcases/getFileSource/getFileSource1.ets new file mode 100644 index 0000000000000000000000000000000000000000..119751e901726748feeeb271b61fd5633db5b46b --- /dev/null +++ b/ets2panda/bindings/test/testcases/getFileSource/getFileSource1.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +let a = 1; \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile1.ets b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6056b864f5a8aabc2d32242444578acb24417502 --- /dev/null +++ b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile1.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Employee { + name: string; + salary: number; + hasBonus: boolean; +} + +function calculateTotalSalary(employees: Employee[]): number { + const bonusAmount = 500; + + let totalSalary = 0; + EtsStepArkTest(); + + for (const employee of employees) { + let adjustedSalary = employee.salary; + if (employee.hasBonus) { + adjustedSalary += bonusAmount; + } + totalSalary += adjustedSalary; + } + return totalSalary; +} + +const employees: Employee[] = [ + { name: "Alice", salary: 3000, hasBonus: true }, + { name: "Bob", salary: 2800, hasBonus: false }, + { name: "Charlie", salary: 3200, hasBonus: true }, + { name: "David", salary: 2900, hasBonus: false } +]; + +const totalSalary = calculateTotalSalary(employees); diff --git a/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile2.ets b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile2.ets new file mode 100644 index 0000000000000000000000000000000000000000..fd7b2efb5ffc195a9655e062398f0124caa5c5b7 --- /dev/null +++ b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile2.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class ChainCalculator { + private result: number; + + constructor(initialValue: number) { + this.result = initialValue; + } + + add(value: number): ChainCalculator { + this.result += value; + return this; + } + + subtract(value: number): ChainCalculator { + this.result -= value; + return this; + } + + multiply(value: number): ChainCalculator { + this.result *= value; + return this; + } + + divide(value: number): ChainCalculator { + EtsStepArkTest(); + if (value === 0) { + throw new Error("Division by zero is not allowed."); + } + this.result /= value; + return this; + } + + getResult(): number { + return this.result; + } + + geFinalResult(addValue: number, subtractValue: number, multiplyValue: number, divideValue: number): number { + return chainCalc.add(addValue).subtract(subtractValue).multiply(multiplyValue).divide(divideValue).getResult(); + } +} + +const chainCalc = new ChainCalculator(10); +chainCalc.geFinalResult(2, 4, 6, 3); diff --git a/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile3.ets b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile3.ets new file mode 100644 index 0000000000000000000000000000000000000000..901ff0e5a05e58b5e6f4bce30d02198555876b88 --- /dev/null +++ b/ets2panda/bindings/test/testcases/modifyDeclFile/dep/modifyDeclFile3.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 getC(a:number, b:number): number { + return a + b; +} + +getC(1, 120); diff --git a/ets2panda/bindings/test/testcases/modifyDeclFile/entry/index.ets b/ets2panda/bindings/test/testcases/modifyDeclFile/entry/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b342f515ec93e1b84cf24499e987b66f03f7c43b --- /dev/null +++ b/ets2panda/bindings/test/testcases/modifyDeclFile/entry/index.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + + let indexStr: string = "modifyDeclFile"; \ No newline at end of file diff --git a/ets2panda/bindings/test/testcases/modifyDeclFile/entry/oh-package.json5 b/ets2panda/bindings/test/testcases/modifyDeclFile/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8ee2596efddc104b26b6ec83ed6fac9ac144acf8 --- /dev/null +++ b/ets2panda/bindings/test/testcases/modifyDeclFile/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025 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. + */ + +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + "myDep": "file:../dep" + }, + "devDependencies": { + } +} diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index c4d2946155463dcfde7a2ba8e4219d59b333469d..4748735b14712406ac39fcfd00a2bbfc502f3660 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -167,6 +167,7 @@ checker::Type *ETSAnalyzer::Check(ir::ClassStaticBlock *st) const static void HandleNativeAndAsyncMethods(ETSChecker *checker, ir::MethodDefinition *node) { auto *scriptFunc = node->Function(); + ES2PANDA_ASSERT(scriptFunc != nullptr); if (node->IsNative() && !node->IsConstructor() && !scriptFunc->IsSetter()) { if (scriptFunc->ReturnTypeAnnotation() == nullptr) { checker->LogError(diagnostic::NATIVE_WITHOUT_RETURN, {}, scriptFunc->Start()); @@ -361,7 +362,9 @@ checker::Type *ETSAnalyzer::Check(ir::OverloadDeclaration *node) const } if (node->IsFunctionOverloadDeclaration()) { - ES2PANDA_ASSERT(node->Parent()->IsClassDefinition() && compiler::HasGlobalClassParent(node)); + ES2PANDA_ASSERT( + node->Parent()->IsClassDefinition() && + (compiler::HasGlobalClassParent(node) || node->Parent()->AsClassDefinition()->IsNamespaceTransformed())); checker->CheckFunctionOverloadDeclaration(checker, node); return nullptr; } @@ -459,7 +462,10 @@ checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const checker->CheckFunctionSignatureAnnotations(node->Params(), node->TypeParams(), node->ReturnType()); auto *signatureInfo = checker->ComposeSignatureInfo(node->TypeParams(), node->Params()); - auto *returnType = checker->ComposeReturnType(node->ReturnType(), node->IsAsync()); + auto *returnType = node->IsExtensionFunction() && node->ReturnType()->IsTSThisType() + ? signatureInfo->params.front()->TsType() + : checker->ComposeReturnType(node->ReturnType(), node->IsAsync()); + auto *const signature = checker->CreateSignature(signatureInfo, returnType, node->Flags(), node->IsExtensionFunction()); if (signature == nullptr) { // #23134 @@ -479,6 +485,7 @@ static bool CheckArrayElementType(ETSChecker *checker, T *newArrayInstanceExpr) ES2PANDA_ASSERT(newArrayInstanceExpr != nullptr); checker::Type *elementType = newArrayInstanceExpr->TypeReference()->GetType(checker)->MaybeBaseTypeOfGradualType(); + ES2PANDA_ASSERT(elementType != nullptr); if (elementType->IsETSPrimitiveType()) { return true; } @@ -1665,6 +1672,7 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const checker::TypeStackElement tse(checker, expr, {{diagnostic::CYCLIC_CALLEE, {}}}, expr->Start()); if (tse.HasTypeError()) { + expr->SetTsType(checker->GlobalTypeError()); return checker->GlobalTypeError(); } @@ -1770,7 +1778,7 @@ checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const checker->Context().CombineSmartCasts(consequentSmartCasts); if (checker->IsTypeIdenticalTo(consequentType, alternateType)) { - expr->SetTsType(checker->GetNonConstantType(consequentType)); + expr->SetTsType(consequentType); } else if (IsNumericType(GetETSChecker(), consequentType) && IsNumericType(GetETSChecker(), alternateType)) { expr->SetTsType(BiggerNumericType(GetETSChecker(), consequentType, alternateType)); } else { @@ -2015,7 +2023,7 @@ checker::Type *ETSAnalyzer::CheckDynamic(ir::ObjectExpression *expr) const static bool ValidatePreferredType(ETSChecker *checker, ir::ObjectExpression *expr) { - auto preferredType = expr->PreferredType(); + auto preferredType = expr->PreferredType()->MaybeBaseTypeOfGradualType(); if (preferredType == nullptr) { checker->LogError(diagnostic::CLASS_COMPOSITE_UNKNOWN_TYPE, {}, expr->Start()); return false; @@ -2374,7 +2382,7 @@ checker::ETSObjectType *ResolveUnionObjectTypeForObjectLiteral(ETSChecker *check static checker::ETSObjectType *ResolveObjectTypeFromPreferredType(ETSChecker *checker, ir::ObjectExpression *expr) { // Assume not null, checked by caller in Check() - checker::Type *preferredType = expr->PreferredType(); + checker::Type *preferredType = expr->PreferredType()->MaybeBaseTypeOfGradualType(); if (preferredType->IsETSAsyncFuncReturnType()) { preferredType = preferredType->AsETSAsyncFuncReturnType()->GetPromiseTypeArg(); @@ -3114,7 +3122,7 @@ checker::Type *ETSAnalyzer::Check(ir::AnnotationUsage *st) const return ReturnTypeForStatement(st); } - if (st->Properties().size() == 1 && + if (st->Properties().size() == 1 && st->Properties().at(0)->AsClassProperty()->Id() != nullptr && st->Properties().at(0)->AsClassProperty()->Id()->Name() == compiler::Signatures::ANNOTATION_KEY_VALUE) { checker->CheckSinglePropertyAnnotation(st, annoDecl); fieldMap.clear(); @@ -3376,6 +3384,7 @@ bool ETSAnalyzer::CheckInferredFunctionReturnType(ir::ReturnStatement *st, ir::S // Case when function's return type is defined explicitly: if (st->argument_ == nullptr) { + ES2PANDA_ASSERT(funcReturnType != nullptr); if (!funcReturnType->MaybeBaseTypeOfGradualType()->IsETSVoidType() && funcReturnType != checker->GlobalVoidType() && !funcReturnType->MaybeBaseTypeOfGradualType()->IsETSAsyncFuncReturnType()) { diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index 021f906c1a022736ccdeeb8eacc88c1cdd89a774..295eaa49b553b6c13d76c64661dd37e793643b17 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -57,6 +57,7 @@ void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *chec const auto *const funcType = methodVariable->TsType()->AsETSFunctionType(); for (auto *funcSignature : funcType->CallSignatures()) { + ES2PANDA_ASSERT(signature != nullptr); signature->SetReturnType(funcSignature->ReturnType()); if (!checker->Relation()->SignatureIsSupertypeOf(signature, funcSignature) && !checker->HasSameAssemblySignature(signature, funcSignature)) { @@ -149,6 +150,7 @@ void CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *exte checker::SignatureInfo *originalExtensionSigInfo = checker->ProgramAllocator()->New( extensionFunc->Signature()->GetSignatureInfo(), checker->ProgramAllocator()); + ES2PANDA_ASSERT(originalExtensionSigInfo != nullptr); originalExtensionSigInfo->minArgCount -= 1U; originalExtensionSigInfo->params.erase(originalExtensionSigInfo->params.begin()); checker::Signature *originalExtensionSignature = @@ -220,6 +222,7 @@ void DoBodyTypeChecking(ETSChecker *checker, ir::MethodDefinition *node, ir::Scr if (scriptFunc->ReturnTypeAnnotation() == nullptr) { if (scriptFunc->IsAsyncFunc()) { auto returnType = checker->CreateETSAsyncFuncReturnTypeFromBaseType(scriptFunc->Signature()->ReturnType()); + ES2PANDA_ASSERT(returnType != nullptr); scriptFunc->Signature()->SetReturnType(returnType->PromiseType()); for (auto &returnStatement : scriptFunc->ReturnStatements()) { returnStatement->SetReturnType(checker, returnType); @@ -248,6 +251,7 @@ void ComposeAsyncImplFuncReturnType(ETSChecker *checker, ir::ScriptFunction *scr auto *returnType = checker->ProgramAllocNode( checker->ProgramAllocNode(objectId, nullptr, nullptr, checker->ProgramAllocator()), checker->ProgramAllocator()); + ES2PANDA_ASSERT(returnType != nullptr); objectId->SetParent(returnType->Part()); returnType->Part()->SetParent(returnType); returnType->SetTsType(checker->ProgramAllocator()->New(checker->ProgramAllocator(), @@ -317,6 +321,7 @@ void CheckIteratorMethodReturnType(ETSChecker *checker, ir::ScriptFunction *scri returnType = checker->GetApparentType(returnType->AsETSTypeParameter()->GetConstraintType()); } + ES2PANDA_ASSERT(returnType != nullptr); if (returnType->IsETSObjectType() && HasIteratorInterface(returnType->AsETSObjectType())) { return; } @@ -655,6 +660,7 @@ checker::Type *InferReturnType(ETSChecker *checker, ir::ScriptFunction *containi // First (or single) return statement in the function: auto *funcReturnType = stArgument == nullptr ? checker->GlobalVoidType() : checker->GetNonConstantType(stArgument->Check(checker)); + ES2PANDA_ASSERT(funcReturnType != nullptr); if (funcReturnType->IsTypeError()) { containingFunc->Signature()->RemoveSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE); return funcReturnType; @@ -672,6 +678,7 @@ checker::Type *InferReturnType(ETSChecker *checker, ir::ScriptFunction *containi auto typeAnnotation = arrowFunc->CreateTypeAnnotation(checker); auto *argumentType = arrowFunc->TsType(); + ES2PANDA_ASSERT(typeAnnotation != nullptr); funcReturnType = typeAnnotation->GetType(checker); if (!checker::AssignmentContext(checker->Relation(), arrowFunc, argumentType, funcReturnType, stArgument->Start(), std::nullopt, @@ -744,6 +751,7 @@ checker::Type *ProcessReturnStatements(ETSChecker *checker, ir::ScriptFunction * checker::Type *argumentType = checker->GetNonConstantType(stArgument->Check(checker)); // previous return statement(s) don't have any value + ES2PANDA_ASSERT(argumentType != nullptr); if (funcReturnType->IsETSVoidType() && !argumentType->IsETSVoidType()) { checker->LogError(diagnostic::MIXED_VOID_NONVOID, {}, stArgument->Start()); return funcReturnType; @@ -773,6 +781,7 @@ bool CheckReturnTypeNecessity(ir::MethodDefinition *node) auto *scriptFunc = node->Function(); needReturnType &= (node->IsNative() || node->IsDeclare()); needReturnType &= !node->IsConstructor(); + ES2PANDA_ASSERT(scriptFunc != nullptr); needReturnType &= !scriptFunc->IsSetter(); return needReturnType; } diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index abf418beae8b15f7a9979144cac3a715ede08fe4..d63dcd1f115ce06087e78d98a04ea7097d03f476 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -697,6 +697,7 @@ ETSObjectType *ETSChecker::GlobalBuiltinBoxType(Type *contents) default: { auto *base = AsETSObjectType(&GlobalTypesHolder::GlobalBoxBuiltinType); auto substitution = Substitution {}; + ES2PANDA_ASSERT(base != nullptr); substitution.emplace(base->TypeArguments()[0]->AsETSTypeParameter(), contents); return base->Substitute(Relation(), &substitution); } @@ -713,6 +714,16 @@ const GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() const return globalArraySignatures_; } +const ArenaSet &ETSChecker::UnionAssemblerTypes() const +{ + return unionAssemblerTypes_; +} + +ArenaSet &ETSChecker::UnionAssemblerTypes() +{ + return unionAssemblerTypes_; +} + Type *ETSChecker::GlobalTypeError() const { return GetGlobalTypesHolder()->GlobalTypeError(); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 62c5776c6b25bac3bda30ddbb34a35413a27a800..40549ea10234e95a65448bd2e1935cb0d0022004 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -93,6 +93,7 @@ public: invokeToArrowSignatures_(Allocator()->Adapter()), arrowToFuncInterfaces_(Allocator()->Adapter()), globalArraySignatures_(Allocator()->Adapter()), + unionAssemblerTypes_(Allocator()->Adapter()), dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), @@ -174,6 +175,9 @@ public: GlobalArraySignatureMap &GlobalArrayTypes(); const GlobalArraySignatureMap &GlobalArrayTypes() const; + const ArenaSet &UnionAssemblerTypes() const; + ArenaSet &UnionAssemblerTypes(); + Type *GlobalTypeError() const; [[nodiscard]] Type *InvalidateType(ir::Typed *node); [[nodiscard]] Type *TypeError(ir::Typed *node, const diagnostic::DiagnosticKind &diagKind, @@ -207,6 +211,7 @@ public: void CheckObjectLiteralKeys(const ArenaVector &properties); Type *BuildBasicClassProperties(ir::ClassDefinition *classDef); ETSObjectType *BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType); + Type *MaybeGradualType(ir::AstNode *node, ETSObjectType *type); Type *BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl); ETSObjectType *GetSuperType(ETSObjectType *type); ArenaVector GetInterfaces(ETSObjectType *type); @@ -468,7 +473,6 @@ public: bool ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument, std::size_t index, TypeRelationFlag flags); bool CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index); - bool ValidateArgumentAsIdentifier(const ir::Identifier *identifier); bool IsValidRestArgument(ir::Expression *argument, Signature *substitutedSig, TypeRelationFlag flags, std::size_t index); bool SetPreferredTypeForArrayArgument(ir::ArrayExpression *arrayExpr, Signature *substitutedSig); @@ -513,6 +517,8 @@ public: void SearchAmongMostSpecificTypes(Type *&mostSpecificType, Signature *&prevSig, std::tuple info, bool lookForClassType); + void CheckAmbiguousCall(Type *&mostSpecificType, Type *sigType, Signature *prevSig, Signature *sig, + const lexer::SourcePosition &pos); void CollectSuitableSignaturesForTypeInference(size_t paramIdx, ArenaVector &signatures, ArenaMultiMap &bestSignaturesForParameter, const ArenaVector &arguments); @@ -940,6 +946,7 @@ public: pendingConstraintCheckRecords_.clear(); constraintCheckScopesCount_ = 0; globalArraySignatures_.clear(); + unionAssemblerTypes_.clear(); GetCachedComputedAbstracts()->clear(); for (auto &dynamicCallIntrinsicsMap : dynamicIntrinsics_) { dynamicCallIntrinsicsMap.clear(); @@ -1099,6 +1106,7 @@ private: FunctionInterfaceMap arrowToFuncInterfaces_; size_t constraintCheckScopesCount_ {0}; GlobalArraySignatureMap globalArraySignatures_; + ArenaSet unionAssemblerTypes_; ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; // NOTE(aleksisch): Extract dynamic from checker to separate class std::array dynamicIntrinsics_; diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index cfaad3f534778bcc113cfa6f35b12ba77bdffdfb..44d5a3d824525e69a8147a6a8d9e201a9fc4ca03 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -74,6 +74,7 @@ checker::Type *TSAnalyzer::Check(ir::TSIndexSignature *node) const checker::ObjectDescriptor *desc = checker->Allocator()->New(checker->Allocator()); checker::ObjectType *placeholder = checker->Allocator()->New(desc); + ES2PANDA_ASSERT(placeholder != nullptr); if (node->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) { placeholder->Desc()->numberIndexInfo = info; } else { @@ -107,6 +108,7 @@ checker::Type *TSAnalyzer::Check(ir::TSMethodSignature *node) const } returnType->Check(checker); + ES2PANDA_ASSERT(callSignature != nullptr); callSignature->SetReturnType(returnType->GetType(checker)); return nullptr; @@ -280,12 +282,13 @@ checker::Type *TSAnalyzer::Check(ir::ArrayExpression *expr) const util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index); varbinder::LocalVariable *tupleMember = varbinder::Scope::CreateVar( checker->Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY, nullptr); - + ES2PANDA_ASSERT(tupleMember != nullptr); if (inConstContext) { tupleMember->AddFlag(varbinder::VariableFlags::READONLY); } tupleMember->SetTsType(*it); + ES2PANDA_ASSERT(desc != nullptr); desc->properties.push_back(tupleMember); } @@ -326,7 +329,7 @@ checker::Type *TSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const if (funcVar != nullptr && funcVar->TsType() == nullptr) { funcVar->SetTsType(funcType); } - + ES2PANDA_ASSERT(signature != nullptr); signature->SetReturnType(checker->HandleFunctionReturn(expr->Function())); if (!expr->Function()->Body()->IsExpression()) { @@ -569,7 +572,7 @@ checker::Type *TSAnalyzer::Check(ir::FunctionExpression *expr) const if (funcVar != nullptr && funcVar->TsType() == nullptr) { funcVar->SetTsType(funcType); } - + ES2PANDA_ASSERT(signature != nullptr); signature->SetReturnType(checker->HandleFunctionReturn(expr->Function())); expr->Function()->Body()->Check(checker); @@ -787,6 +790,7 @@ void TSAnalyzer::CheckNonComputed(checker::ObjectDescriptor *desc, ir::Expressio auto *memberVar = varbinder::Scope::CreateVar(checker->Allocator(), propName, flags, it); + ES2PANDA_ASSERT(memberVar != nullptr); if (inConstContext) { memberVar->AddFlag(varbinder::VariableFlags::READONLY); } else { @@ -876,6 +880,7 @@ checker::Type *TSAnalyzer::Check(ir::ObjectExpression *expr) const } checker::Type *returnType = checker->Allocator()->New(desc); + ES2PANDA_ASSERT(returnType != nullptr); returnType->AsObjectType()->AddObjectFlag(checker::ObjectFlags::RESOLVED_MEMBERS | checker::ObjectFlags::CHECK_EXCESS_PROPS); return returnType; @@ -1342,6 +1347,7 @@ static void CheckSimpleVariableDeclaration(checker::TSChecker *checker, ir::Vari initializerType = checker->GetBaseTypeOfLiteralType(initializerType); } + ES2PANDA_ASSERT(initializerType != nullptr); if (initializerType->IsNullType()) { checker->ThrowTypeError( {"Cannot infer type for variable '", declarator->Id()->AsIdentifier()->Name(), "'."}, @@ -1729,6 +1735,7 @@ static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, if (res == nullptr) { auto *decl = checker->Allocator()->New(memberStr); + ES2PANDA_ASSERT(decl != nullptr); decl->BindNode(variable->Declaration()->Node()); enumScope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS); res = enumScope->FindLocal(memberStr, varbinder::ResolveBindingOptions::BINDINGS); @@ -1846,6 +1853,7 @@ checker::Type *TSAnalyzer::Check(ir::TSEnumDeclaration *st) const if (enumVar->TsType() == nullptr) { checker::ScopeContext scopeCtx(checker, st->Scope()); checker::Type *enumType = InferType(checker, st->IsConst(), st); + ES2PANDA_ASSERT(enumType != nullptr); enumType->SetVariable(enumVar); enumVar->SetTsType(enumType); } @@ -1953,6 +1961,7 @@ checker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const checker->Allocator()->New(checker->Allocator()); resolvedType = checker->Allocator()->New(checker->Allocator(), st->Id()->Name(), desc); + ES2PANDA_ASSERT(resolvedType != nullptr); resolvedType->SetVariable(var); var->SetTsType(resolvedType); } diff --git a/ets2panda/checker/ets/aliveAnalyzer.cpp b/ets2panda/checker/ets/aliveAnalyzer.cpp index a4b3ed1b9b68916cd8ccec947c440e37a6c98b1e..13abe6b9ca76eb040ad9d23fb9dc050246f31104 100644 --- a/ets2panda/checker/ets/aliveAnalyzer.cpp +++ b/ets2panda/checker/ets/aliveAnalyzer.cpp @@ -235,6 +235,7 @@ void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) auto *func = methodDef->Function(); + ES2PANDA_ASSERT(func != nullptr); if (func->Body() == nullptr || func->IsProxy()) { return; } @@ -255,6 +256,7 @@ void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) } if (status_ == LivenessStatus::ALIVE && !isVoid && !isPromiseVoid) { + ES2PANDA_ASSERT(methodDef->Function() != nullptr); if (!methodDef->Function()->HasReturnStatement()) { if (!util::Helpers::IsAsyncMethod(methodDef)) { checker_->LogError(diagnostic::MISSING_RETURN_STMT, {}, func->Start()); diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index cbe2c38d4ec82f65b2addbc0f7694aed02f89501..b76c779b5ae596684a2d710a8dac3be1938a5747 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -224,16 +224,6 @@ bool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, lexer::To case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: case lexer::TokenType::PUNCTUATOR_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_MULTIPLY: - case lexer::TokenType::PUNCTUATOR_DIVIDE: - case lexer::TokenType::PUNCTUATOR_MOD: - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: - case lexer::TokenType::PUNCTUATOR_BITWISE_AND: - case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: return true; default: break; @@ -250,6 +240,7 @@ bool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, lexer::To case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: case lexer::TokenType::KEYW_INSTANCEOF: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: // This is handled in the main CheckBinaryOperator function return false; default: @@ -933,6 +924,7 @@ Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *left, ir: LogError(diagnostic::COALESCE_NOT_REF, {}, pos); } leftType = GetNonNullishType(leftType); + ES2PANDA_ASSERT(leftType != nullptr); if (leftType->IsTypeError()) { ES2PANDA_ASSERT(IsAnyError()); return GlobalTypeError(); diff --git a/ets2panda/checker/ets/assignAnalyzer.cpp b/ets2panda/checker/ets/assignAnalyzer.cpp index d5d379b49b766e6bd00725e16be30705bda186f4..8d32f667b6cfffe464c40ce49c5a59cb9511617d 100644 --- a/ets2panda/checker/ets/assignAnalyzer.cpp +++ b/ets2panda/checker/ets/assignAnalyzer.cpp @@ -532,11 +532,14 @@ static bool IsInitialConstructor(const ir::AstNode *node) } const auto methodDef = node->AsMethodDefinition(); + ES2PANDA_ASSERT(methodDef != nullptr); if (methodDef->Function()->Body() == nullptr || methodDef->Function()->IsExternal()) { return false; } - const auto funcBody = node->AsMethodDefinition()->Function()->Body()->AsBlockStatement(); + const auto *func = node->AsMethodDefinition()->Function(); + ES2PANDA_ASSERT(func != nullptr); + const auto funcBody = func->Body()->AsBlockStatement(); return !(!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() && funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() && @@ -551,7 +554,7 @@ static bool IsInitialConstructor(const ir::AstNode *node) void AssignAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) { auto *func = methodDef->Function(); - + ES2PANDA_ASSERT(func != nullptr); if (func->Body() == nullptr || func->IsProxy()) { return; } @@ -1204,8 +1207,11 @@ util::StringView AssignAnalyzer::GetVariableType(const ir::AstNode *node) const util::StringView AssignAnalyzer::GetVariableName(const ir::AstNode *node) const { switch (node->Type()) { - case ir::AstNodeType::CLASS_PROPERTY: - return node->AsClassProperty()->Id()->Name(); + case ir::AstNodeType::CLASS_PROPERTY: { + const ir::Identifier *identifier = node->AsClassProperty()->Id(); + ES2PANDA_ASSERT(identifier != nullptr); + return identifier->Name(); + } case ir::AstNodeType::VARIABLE_DECLARATOR: return node->AsVariableDeclarator()->Id()->AsIdentifier()->Name(); default: @@ -1277,7 +1283,9 @@ varbinder::Variable *AssignAnalyzer::GetBoundVariable(const ir::AstNode *node) varbinder::Variable *ret = nullptr; if (node->IsClassProperty()) { - ret = node->AsClassProperty()->Id()->Variable(); + const ir::Identifier *identifier = node->AsClassProperty()->Id(); + ES2PANDA_ASSERT(identifier != nullptr); + ret = identifier->Variable(); } else if (node->IsVariableDeclarator()) { ret = node->AsVariableDeclarator()->Id()->AsIdentifier()->Variable(); } else { diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index e5530fc8122ee9aa86ca28fe1d56038027ba148f..2a67acd88d5d2d5a73df5b16812ca6e63de7b950 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -48,6 +48,7 @@ namespace ark::es2panda::checker { void ProcessCheckerNode(ETSChecker *checker, ir::AstNode *node) { auto scope = compiler::NearestScope(node); + ES2PANDA_ASSERT(scope != nullptr); if (scope->IsGlobalScope()) { // NOTE(aleksisch): All classes are contained in ETSGlobal class scope (not just Global scope), // however it's parent is ETSModule. It should be fixed @@ -62,6 +63,7 @@ void ProcessCheckerNode(ETSChecker *checker, ir::AstNode *node) // however right now checker do it when called on ClassDefinition auto method = node->AsMethodDefinition(); auto func = method->Value()->AsFunctionExpression()->Function(); + ES2PANDA_ASSERT(method->Id() != nullptr); func->Id()->SetVariable(method->Id()->Variable()); } ScopeContext checkerScope(checker, scope); @@ -71,6 +73,7 @@ void ProcessCheckerNode(ETSChecker *checker, ir::AstNode *node) void ProcessScopesNode(ETSChecker *checker, ir::AstNode *node) { auto *scope = compiler::NearestScope(node); + ES2PANDA_ASSERT(scope != nullptr); if (scope->IsGlobalScope()) { // NOTE(aleksisch): All classes are contained in ETSGlobal scope, // however it's parent is ETSModule (not ETSGlobal). It should be fixed @@ -117,6 +120,7 @@ std::pair ETSChecker::CreateStaticScript ir::ModifierFlags::STATIC, }); // clang-format on + ES2PANDA_ASSERT(func != nullptr); func->SetIdent(id); return std::make_pair(func, id); @@ -143,6 +147,7 @@ std::pair ETSChecker::CreateScriptFuncti ir::ScriptFunctionFlags::CONSTRUCTOR | ir::ScriptFunctionFlags::EXPRESSION, ir::ModifierFlags::PUBLIC}); + ES2PANDA_ASSERT(func != nullptr); func->SetIdent(id); return std::make_pair(func, id); @@ -159,6 +164,7 @@ ir::ClassStaticBlock *ETSChecker::CreateClassStaticInitializer(const ClassInitia // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *staticBlock = ProgramAllocNode(funcExpr, ProgramAllocator()); + ES2PANDA_ASSERT(staticBlock != nullptr); staticBlock->AddModifier(ir::ModifierFlags::STATIC); return staticBlock; diff --git a/ets2panda/checker/ets/etsWarningAnalyzer.cpp b/ets2panda/checker/ets/etsWarningAnalyzer.cpp index fc451700cc4c347237694ae6ff636f7aef32e53d..f686ff057b060145f4a05ec2c80e36e202ad6338 100644 --- a/ets2panda/checker/ets/etsWarningAnalyzer.cpp +++ b/ets2panda/checker/ets/etsWarningAnalyzer.cpp @@ -101,10 +101,13 @@ void ETSWarningAnalyzer::AnalyzeClassMethodForFinalModifier(const ir::MethodDefi if (!potentialDescendant->IsDescendantOf(classAsETSObject)) { continue; } - const util::StringView bodyMethodName = - ETSChecker::GetSignatureFromMethodDefinition(bodyPart->AsMethodDefinition())->Function()->Id()->Name(); + auto signature = ETSChecker::GetSignatureFromMethodDefinition(bodyPart->AsMethodDefinition()); + ES2PANDA_ASSERT(signature != nullptr); + const util::StringView bodyMethodName = signature->Function()->Id()->Name(); + const auto *func = methodDef->Function(); + ES2PANDA_ASSERT(func != nullptr); if (bodyPart->IsOverride() && bodyMethodName != compiler::Signatures::CTOR && - bodyMethodName == methodDef->Function()->Id()->Name()) { + bodyMethodName == func->Id()->Name()) { suggestFinal = false; break; } @@ -208,13 +211,13 @@ void ETSWarningAnalyzer::ETSWarningsProhibitTopLevelStatements(const ir::AstNode } for (const auto *itBody : classDef->Body()) { - if (!itBody->IsMethodDefinition() || + if (!itBody->IsMethodDefinition() || itBody->AsMethodDefinition()->Id() == nullptr || itBody->AsMethodDefinition()->Id()->Name() != compiler::Signatures::INIT_METHOD) { continue; } - - for (const auto *statement : - itBody->AsMethodDefinition()->Function()->Body()->AsBlockStatement()->Statements()) { + const auto *func = itBody->AsMethodDefinition()->Function(); + ES2PANDA_ASSERT(func != nullptr); + for (const auto *statement : func->Body()->AsBlockStatement()->Statements()) { if (program_->NodeContainsETSNolint(statement, ETSWarnings::ETS_PROHIBIT_TOP_LEVEL_STATEMENTS)) { continue; } diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index c31ff6160718f78f24c67415339861681903e485..b10a5e7edbf30a99907595fac61122e3559db908 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -91,6 +91,7 @@ bool ETSChecker::EnhanceSubstitutionForReadonly(const ArenaVector &typeP bool ETSChecker::EnhanceSubstitutionForType(const ArenaVector &typeParams, Type *paramType, Type *argumentType, Substitution *substitution) { + ES2PANDA_ASSERT(argumentType != nullptr); if (argumentType->IsETSPrimitiveType()) { argumentType = MaybeBoxInRelation(argumentType); } @@ -385,10 +386,11 @@ bool ETSChecker::CheckOptionalLambdaFunction(ir::Expression *argument, Signature return false; } -bool ETSChecker::ValidateArgumentAsIdentifier(const ir::Identifier *identifier) +static bool IsInvalidArgumentAsIdentifier(varbinder::Scope *scope, const ir::Identifier *identifier) { - auto result = Scope()->Find(identifier->Name()); - return result.variable != nullptr && (result.variable->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)); + auto result = scope->Find(identifier->Name()); + return result.variable != nullptr && (result.variable->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE | + varbinder::VariableFlags::TYPE_ALIAS)); } static void ClearPreferredTypeForArray(checker::ETSChecker *checker, ir::Expression *argument, Type *paramType, @@ -442,6 +444,7 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, auto const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType())->MaybeBaseTypeOfGradualType(); if (argument->IsObjectExpression()) { + ES2PANDA_ASSERT(paramType != nullptr); if (!paramType->IsETSObjectType()) { return false; } @@ -476,7 +479,7 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, ClearPreferredTypeForArray(this, argument, paramType, flags, false); - if (argument->IsIdentifier() && ValidateArgumentAsIdentifier(argument->AsIdentifier())) { + if (argument->IsIdentifier() && IsInvalidArgumentAsIdentifier(Scope(), argument->AsIdentifier())) { LogError(diagnostic::ARG_IS_CLASS_ID, {}, argument->Start()); return false; } @@ -1009,6 +1012,23 @@ static void InitMostSpecificType(TypeRelation *relation, const ArenaVectorIsETSObjectType() && mostSpecificType->IsETSObjectType()) || + (sigType->IsETSUnionType() && mostSpecificType->IsETSUnionType() && + ((Relation()->IsSupertypeOf(sigType->AsETSUnionType(), GlobalETSNullType()) && + Relation()->IsSupertypeOf(mostSpecificType->AsETSUnionType(), GlobalETSNullType())) || + // CC-OFFNXT(G.FMT.02-CPP) project code style + (Relation()->IsSupertypeOf(sigType->AsETSUnionType(), GlobalETSUndefinedType()) && + Relation()->IsSupertypeOf(mostSpecificType->AsETSUnionType(), GlobalETSUndefinedType()))))) && + !Relation()->IsAssignableTo(mostSpecificType, sigType) && + !Relation()->IsLegalBoxedPrimitiveConversion(sigType, mostSpecificType)) { + auto funcName = sig->Function()->Id()->Name(); + LogError(diagnostic::AMBIGUOUS_CALL, {funcName, funcName, funcName, prevSig, funcName, sig}, pos); + } +} + void ETSChecker::SearchAmongMostSpecificTypes(Type *&mostSpecificType, Signature *&prevSig, std::tuple info, bool lookForClassType) @@ -1056,11 +1076,8 @@ void ETSChecker::SearchAmongMostSpecificTypes(Type *&mostSpecificType, Signature if (Relation()->IsAssignableTo(sigType, mostSpecificType)) { mostSpecificType = sigType; prevSig = sig; - } else if (sigType->IsETSObjectType() && mostSpecificType->IsETSObjectType() && - !Relation()->IsAssignableTo(mostSpecificType, sigType) && - !Relation()->IsLegalBoxedPrimitiveConversion(sigType, mostSpecificType)) { - auto funcName = sig->Function()->Id()->Name(); - LogError(diagnostic::AMBIGUOUS_CALL, {funcName, funcName, funcName, prevSig, funcName, sig}, pos); + } else { + CheckAmbiguousCall(mostSpecificType, sigType, prevSig, sig, pos); } } } @@ -1077,6 +1094,7 @@ void ETSChecker::CollectSuitableSignaturesForTypeInference( for (auto *sig : signatures) { auto *sigParamType = GetNonNullishType(sig->Params().at(paramIdx)->TsType()); + ES2PANDA_ASSERT(sigParamType != nullptr); if (!sigParamType->IsETSFunctionType()) { continue; } @@ -1089,6 +1107,7 @@ void ETSChecker::CollectSuitableSignaturesForTypeInference( for (auto *sig : signatures) { auto *sigParamType = GetNonNullishType(sig->Params().at(paramIdx)->TsType()); + ES2PANDA_ASSERT(sigParamType != nullptr); if (!sigParamType->IsETSFunctionType()) { continue; } @@ -1405,11 +1424,14 @@ static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition * for (ir::MethodDefinition *const currentFunc : method->Overloads()) { ldInfo.isDeclare &= currentFunc->IsDeclare(); - + ES2PANDA_ASSERT(currentFunc->Function() != nullptr); + ES2PANDA_ASSERT(currentFunc->Id() != nullptr); currentFunc->Function()->Id()->SetVariable(currentFunc->Id()->Variable()); checker->BuildFunctionSignature(currentFunc->Function(), method->IsConstructor()); if (currentFunc->Function()->Signature() == nullptr) { - method->Id()->Variable()->SetTsType(checker->GlobalTypeError()); + auto *methodId = method->Id(); + ES2PANDA_ASSERT(methodId != nullptr); + methodId->Variable()->SetTsType(checker->GlobalTypeError()); return false; } @@ -1454,11 +1476,13 @@ checker::Type *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) if (method->TsType() != nullptr) { return method->TsType()->AsETSFunctionType(); } - - method->Function()->Id()->SetVariable(method->Id()->Variable()); + auto *methodId = method->Id(); + ES2PANDA_ASSERT(methodId != nullptr); + ES2PANDA_ASSERT(method->Function() != nullptr); + method->Function()->Id()->SetVariable(methodId->Variable()); BuildFunctionSignature(method->Function(), method->IsConstructor()); if (method->Function()->Signature() == nullptr) { - return method->Id()->Variable()->SetTsType(GlobalTypeError()); + return methodId->Variable()->SetTsType(GlobalTypeError()); } auto *funcType = BuildMethodType(method->Function()); method->InitializeOverloadInfo(); @@ -1472,7 +1496,7 @@ checker::Type *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) LogDiagnostic(diagnostic::FUNCTION_ASM_SIG_COLLISION, {std::string(funcType->Name())}, method->Start()); } - return method->Id()->Variable()->SetTsType(funcType); + return methodId->Variable()->SetTsType(funcType); } bool ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, @@ -1597,6 +1621,7 @@ SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::TSTypeParameterDeclaration * if (typeParams != nullptr) { auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(typeParams); + ES2PANDA_ASSERT(signatureInfo != nullptr); signatureInfo->typeParams = std::move(typeParamTypes); if (ok) { AssignTypeParameterConstraints(typeParams); @@ -1658,6 +1683,7 @@ void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func) void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) { + ES2PANDA_ASSERT(func != nullptr); bool isArrow = func->IsArrow(); // note(Ekko): For extenal function overload, need to not change ast tree, for arrow type, need perferred type. if (func->Signature() != nullptr && !isArrow) { @@ -1708,6 +1734,7 @@ void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstru checker::ETSFunctionType *ETSChecker::BuildMethodType(ir::ScriptFunction *func) { ES2PANDA_ASSERT(!func->IsArrow()); + ES2PANDA_ASSERT(func != nullptr); auto *nameVar = func->Id()->Variable(); ETSFunctionType *funcType = CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}); @@ -1726,7 +1753,7 @@ Signature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType * for (auto sourceSig : source->CallSignatures()) { if ((*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name() && Relation()->SignatureIsSupertypeOf(*targetSig, sourceSig)) { - target->CallSignatures().erase(targetSig); + targetSig = target->CallSignatures().erase(targetSig); isOverridden = true; break; } @@ -1917,7 +1944,7 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) auto *target = site->GetProperty(signature->Function()->Id()->Name(), flags); bool isOverridingAnySignature = false; - if (target == nullptr) { + if (target == nullptr || target->TsType() == nullptr || !target->TsType()->IsETSFunctionType()) { return isOverridingAnySignature; } @@ -1962,7 +1989,9 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) void ETSChecker::CheckOverride(Signature *signature) { + ES2PANDA_ASSERT(signature != nullptr); auto *owner = signature->Owner(); + ES2PANDA_ASSERT(owner != nullptr); bool isOverriding = false; if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) { @@ -2177,7 +2206,9 @@ std::string ETSChecker::GetAsyncImplName(const util::StringView &name) std::string ETSChecker::GetAsyncImplName(ir::MethodDefinition *asyncMethod) { - ir::Identifier *asyncName = asyncMethod->Function()->Id(); + ir::ScriptFunction *scriptFunc = asyncMethod->Function(); + CHECK_NOT_NULL(scriptFunc); + ir::Identifier *asyncName = scriptFunc->Id(); ES2PANDA_ASSERT_POS(asyncName != nullptr, asyncMethod->Start()); return GetAsyncImplName(asyncName->Name()); } @@ -2208,11 +2239,13 @@ ir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir: // CC-OFFNXT(G.FMT.05-CPP) project codestyle clang format off body, ir::FunctionSignature(nullptr, std::move(params), returnType), flags, modifiers}); // clang-format on + ES2PANDA_ASSERT(func != nullptr); func->SetScope(scope); func->SetIdent(nameId); if (body != nullptr && body->IsBlockStatement()) { body->AsBlockStatement()->SetScope(scope); } + ES2PANDA_ASSERT(scope != nullptr); scope->BindNode(func); paramScope->BindNode(func); scope->BindParamScope(paramScope); @@ -2245,7 +2278,9 @@ varbinder::FunctionParamScope *ETSChecker::CopyParams( for (auto *const it : params) { auto *const paramOld = it->AsETSParameterExpression(); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *const paramNew = paramOld->Clone(ProgramAllocator(), paramOld->Parent())->AsETSParameterExpression(); + auto *typeOld = paramOld->Clone(ProgramAllocator(), paramOld->Parent()); + ES2PANDA_ASSERT(typeOld != nullptr); + auto *const paramNew = typeOld->AsETSParameterExpression(); varbinder::Variable *var = VarBinder()->AddParamDecl(paramNew); Type *paramType = paramOld->Variable()->TsType(); @@ -2390,6 +2425,7 @@ ArenaVector ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallE ArenaVector statements(ProgramAllocator()->Adapter()); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *body = ProgramAllocNode(ProgramAllocator(), std::move(statements)); + ES2PANDA_ASSERT(body != nullptr); body->SetScope(funcScope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) @@ -2397,10 +2433,12 @@ ArenaVector ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallE ProgramAllocator(), ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), ir::ScriptFunctionFlags::ARROW}); + ES2PANDA_ASSERT(funcNode != nullptr); funcNode->SetScope(funcScope); funcScope->BindNode(funcNode); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *arrowFuncNode = ProgramAllocNode(funcNode, ProgramAllocator()); + ES2PANDA_ASSERT(arrowFuncNode != nullptr); arrowFuncNode->SetParent(callExpr); ArenaVector fakeArguments = callExpr->Arguments(); @@ -2692,7 +2730,7 @@ bool ETSChecker::ValidateOrderSignatureRequiredParams(Signature *substitutedSig, return false; } - if (argument->IsIdentifier() && ValidateArgumentAsIdentifier(argument->AsIdentifier())) { + if (argument->IsIdentifier() && IsInvalidArgumentAsIdentifier(Scope(), argument->AsIdentifier())) { LogError(diagnostic::ARG_IS_CLASS_ID, {}, argument->Start()); return false; } diff --git a/ets2panda/checker/ets/function_helpers.h b/ets2panda/checker/ets/function_helpers.h index 7c22e2f83b690b8c753b021b516bb43c0a0e93d7..7730c65f761e4decde9ef61df925a6af35a41b56 100644 --- a/ets2panda/checker/ets/function_helpers.h +++ b/ets2panda/checker/ets/function_helpers.h @@ -54,6 +54,7 @@ namespace ark::es2panda::checker { static Type *MaybeBoxedType(ETSChecker *checker, Type *type, ir::Expression *expr) { + ES2PANDA_ASSERT(type != nullptr); if (!type->IsETSPrimitiveType()) { return type; } @@ -77,6 +78,7 @@ static void InferUntilFail(Signature const *const signature, const ArenaVectorAddStatus(checker::CheckerStatus::IN_TYPE_INFER); // some ets lib files require type infer from arg index 0,1,... , not fit to build graph + ES2PANDA_ASSERT(substitution != nullptr); while (anyChange && substitution->size() < sigParams.size()) { anyChange = false; for (size_t ix = 0; ix < arguments.size(); ++ix) { diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index f7a520764e69a21025157c8f529f447c5d0c7d66..095b9f0503e36efd4eabfe0252c84ded480c63d2 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -26,6 +26,7 @@ #include "evaluate/scopedDebugInfoPlugin.h" #include "compiler/lowering/scopesInit/scopesInitPhase.h" #include "compiler/lowering/util.h" +#include "util/helpers.h" namespace ark::es2panda::checker { @@ -43,7 +44,8 @@ std::pair ETSChecker::FindVariable return {nullptr, nullptr}; } const auto searchFlags = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE | - PropertySearchFlags::SEARCH_IN_INTERFACES; + PropertySearchFlags::SEARCH_IN_INTERFACES | + PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION; auto *resolved = classType->GetProperty(name, searchFlags); while (classType->EnclosingType() != nullptr && resolved == nullptr) { classType = classType->EnclosingType(); @@ -62,8 +64,10 @@ varbinder::Variable *ETSChecker::FindVariableInGlobal(const ir::Identifier *cons bool ETSChecker::IsVariableStatic(const varbinder::Variable *var) { + CHECK_NOT_NULL(var); if (var->HasFlag(varbinder::VariableFlags::METHOD)) { - return var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC); + return var->TsType()->IsETSFunctionType() && + var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC); } return var->HasFlag(varbinder::VariableFlags::STATIC); } @@ -781,6 +785,7 @@ static void CheckAssignForDeclare(ir::Identifier *ident, ir::TypeNode *typeAnnot return; } const bool isConst = (flags & ir::ModifierFlags::CONST) != 0; + ES2PANDA_ASSERT(init != nullptr); bool numberLiteralButNotBigInt = init->IsNumberLiteral() && !init->IsBigIntLiteral(); bool multilineLiteralWithNoEmbedding = init->IsTemplateLiteral() && init->AsTemplateLiteral()->Expressions().empty(); @@ -877,6 +882,7 @@ static void CheckRecordType(ir::Expression *init, checker::Type *annotationType, checker::Type *ETSChecker::CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation, ir::Expression *init, ir::ModifierFlags const flags) { + ES2PANDA_ASSERT(ident != nullptr); varbinder::Variable *const bindingVar = ident->Variable(); checker::Type *annotationType = nullptr; @@ -1784,6 +1790,7 @@ void ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjT parser::Program *program = SelectEntryOrExternalProgram(static_cast(VarBinder()), importPath); // Check imported properties before assigning them to module object + ES2PANDA_ASSERT(program != nullptr); if (!program->IsASTChecked()) { // NOTE: helps to avoid endless loop in case of recursive imports that uses all bindings program->SetASTChecked(); @@ -2109,6 +2116,7 @@ Type *ETSChecker::CheckSwitchDiscriminant(ir::Expression *discriminant) { Type *discriminantType = discriminant->Check(this); discriminantType = GetNonConstantType(MaybeUnboxType(discriminantType)); + ES2PANDA_ASSERT(discriminantType != nullptr); if (!discriminantType->HasTypeFlag(TypeFlag::VALID_SWITCH_TYPE)) { if (!(discriminantType->IsETSObjectType() && discriminantType->AsETSObjectType()->HasObjectFlag( @@ -2382,7 +2390,7 @@ ETSObjectType *ETSChecker::GetRelevantArgumentedTypeFromChild(ETSObjectType *con auto *relevantType = CreateETSObjectType(child->GetDeclNode(), child->ObjectFlags()); ArenaVector params = child->TypeArguments(); - + ES2PANDA_ASSERT(relevantType != nullptr); relevantType->SetTypeArguments(std::move(params)); relevantType->SetEnclosingType(child->EnclosingType()); relevantType->SetSuperType(child->SuperType()); @@ -2406,6 +2414,7 @@ void ETSChecker::EmplaceSubstituted(Substitution *substitution, ETSTypeParameter { // *only* reference type may be substituted, no exceptions ES2PANDA_ASSERT(typeArg->IsETSReferenceType()); + ES2PANDA_ASSERT(substitution != nullptr); substitution->emplace(tparam, typeArg); } @@ -2466,7 +2475,9 @@ util::StringView ETSChecker::GetHashFromFunctionType(ir::ETSFunctionType *type) std::stringstream ss; for (auto *p : type->Params()) { auto *const param = p->AsETSParameterExpression(); - param->TypeAnnotation()->GetType(this)->ToString(ss, true); + auto *paramType = param->TypeAnnotation()->GetType(this); + ES2PANDA_ASSERT(paramType != nullptr); + paramType->ToString(ss, true); ss << ";"; } @@ -2474,11 +2485,15 @@ util::StringView ETSChecker::GetHashFromFunctionType(ir::ETSFunctionType *type) if (type->ReturnType()->IsTSThisType()) { type->Params()[0]->AsETSParameterExpression()->TypeAnnotation()->TsType()->ToString(ss, true); } else { - type->ReturnType()->GetType(this)->ToString(ss, true); + auto *returnType = type->ReturnType()->GetType(this); + ES2PANDA_ASSERT(returnType != nullptr); + returnType->ToString(ss, true); } ss << "extensionFunction;"; } else { - type->ReturnType()->GetType(this)->ToString(ss, true); + auto *returnType = type->ReturnType()->GetType(this); + ES2PANDA_ASSERT(returnType != nullptr); + returnType->ToString(ss, true); } ss << ";"; @@ -2563,13 +2578,21 @@ std::vector ETSChecker::FindTypeInferenceArguments(const ArenaVectorAsETSUnionType()->Types()) { if (type->IsETSFunctionType()) { - return lambda->Params().size() == type->AsETSFunctionType()->Params().size(); + assignable |= lambda->Params().size() == type->AsETSFunctionType()->Params().size(); + continue; + } + + if (type->IsETSTypeReference()) { + auto aliasType = util::Helpers::DerefETSTypeReference(type); + assignable |= aliasType->IsETSFunctionType() && + lambda->Params().size() == aliasType->AsETSFunctionType()->Params().size(); } } - return false; + return assignable; } void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType, @@ -2699,6 +2722,7 @@ ir::ClassProperty *ETSChecker::ClassPropToImplementationProp(ir::ClassProperty * classProp->AddModifier(ir::ModifierFlags::PRIVATE); auto *fieldDecl = ProgramAllocator()->New(classProp->Key()->AsIdentifier()->Name()); + ES2PANDA_ASSERT(fieldDecl != nullptr); fieldDecl->BindNode(classProp); auto fieldVar = scope->InstanceFieldScope()->AddDecl(ProgramAllocator(), fieldDecl, ScriptExtension::ETS); @@ -2801,6 +2825,7 @@ static ir::BlockStatement *GenGetterSetterBodyHelper(ETSChecker *checker, ArenaV return nullptr; } auto *body = checker->ProgramAllocNode(checker->ProgramAllocator(), std::move(stmts)); + ES2PANDA_ASSERT(body != nullptr); body->SetScope(functionScope); return body; } @@ -2861,6 +2886,7 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty auto *methodIdent = property->Key()->AsIdentifier()->Clone(checker->ProgramAllocator(), nullptr); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *funcExpr = checker->ProgramAllocNode(func); + CHECK_NOT_NULL(funcExpr); funcExpr->SetRange(func->Range()); func->AddFlag(ir::ScriptFunctionFlags::METHOD); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) @@ -2870,15 +2896,20 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty auto *decl = checker->ProgramAllocator()->New( checker->ProgramAllocator(), property->Key()->AsIdentifier()->Name(), method); auto *var = checker->ProgramAllocator()->New(decl, varbinder::VariableFlags::VAR); + CHECK_NOT_NULL(var); var->AddFlag(varbinder::VariableFlags::METHOD); methodIdent->SetVariable(var); - method->Id()->SetMutator(); + auto *methodId = method->Id(); + CHECK_NOT_NULL(methodId); + methodId->SetMutator(); method->SetRange(field->Range()); + auto *methodFunc = method->Function(); + CHECK_NOT_NULL(methodFunc); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - method->Function()->SetIdent(method->Id()->Clone(checker->ProgramAllocator(), nullptr)); - method->Function()->AddModifier(method->Modifiers()); + methodFunc->SetIdent(methodId->Clone(checker->ProgramAllocator(), nullptr)); + methodFunc->AddModifier(method->Modifiers()); method->SetVariable(var); method->SetParent(field->Parent()); @@ -2935,19 +2966,21 @@ void ETSChecker::SetupGetterSetterFlags(ir::ClassProperty *originalProp, ETSObje method->TsType()->AddTypeFlag(tflag); method->Variable()->SetTsType(method->TsType()); + auto *func = method->Function(); + ES2PANDA_ASSERT(func != nullptr); if (((originalProp->Modifiers() & mflag) != 0U)) { - method->Function()->AddModifier(ir::ModifierFlags::OVERRIDE); + func->AddModifier(ir::ModifierFlags::OVERRIDE); } if (inExternal && !getProgram(originalProp)->IsGenAbcForExternal()) { - method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL); + func->AddFlag(ir::ScriptFunctionFlags::EXTERNAL); } if (originalProp->IsDeclare()) { method->AddModifier(ir::ModifierFlags::DECLARE); - method->Function()->AddModifier(ir::ModifierFlags::DECLARE); + func->AddModifier(ir::ModifierFlags::DECLARE); } - this->CheckOverride(method->Function()->Signature()); + this->CheckOverride(func->Signature()); method->SetParent(classDef); classType->AddProperty(method->Variable()->AsLocalVariable()); } @@ -3092,6 +3125,7 @@ void ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclarati if (reExportType->IsTypeError()) { continue; } + ES2PANDA_ASSERT(lastObjectType != nullptr); lastObjectType->AddReExports(reExportType->AsETSObjectType()); for (auto node : importDecl->Specifiers()) { if (node->IsImportSpecifier()) { @@ -3125,6 +3159,7 @@ Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importD auto *rootDecl = ProgramAllocator()->New(moduleName); varbinder::LocalVariable *rootVar = ProgramAllocator()->New(rootDecl, varbinder::VariableFlags::NONE); + ES2PANDA_ASSERT(rootVar != nullptr); rootVar->SetTsType(moduleObjectType); ImportNamespaceObjectTypeAddReExportType(importDecl, moduleObjectType, ident); @@ -3137,9 +3172,12 @@ Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importD ETSChecker::NamedAccessMeta ETSChecker::FormNamedAccessMetadata(varbinder::Variable const *prop) { + CHECK_NOT_NULL(prop); const auto *field = prop->Declaration()->Node()->AsClassProperty(); const auto *owner = field->Parent()->AsClassDefinition(); - return {owner->TsType()->AsETSObjectType(), field->TsType(), field->Id()->Name()}; + auto *fieldId = field->Id(); + CHECK_NOT_NULL(fieldId); + return {owner->TsType()->AsETSObjectType(), field->TsType(), fieldId->Name()}; } void ETSChecker::ETSObjectTypeDeclNode(ETSChecker *checker, ETSObjectType *const objectType) @@ -3168,6 +3206,7 @@ ir::CallExpression *ETSChecker::CreateExtensionAccessorCall(ETSChecker *checker, // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) callExpr = checker->ProgramAllocNode(expr, std::move(args), nullptr, false, false); } + ES2PANDA_ASSERT(callExpr != nullptr); callExpr->SetRange(expr->Range()); return callExpr->AsCallExpression(); } @@ -3178,7 +3217,7 @@ void ETSChecker::CheckTypeParameterVariance(ir::ClassDefinition *classDef) return; } - Context().SetContainingClass(classDef->TsType()->AsETSObjectType()); + Context().SetContainingClass(classDef->TsType()->MaybeBaseTypeOfGradualType()->AsETSObjectType()); auto checkVariance = [this](VarianceFlag varianceFlag, ir::Expression *expression, Type *type) { Relation()->Result(RelationResult::TRUE); Relation()->SetNode(expression); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 7cfe16d58eb609267a1f9c2a2877defcbd7daa76..d048894b2c4612f726fb4080c2ab5d61af1f5f67 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -112,7 +112,7 @@ static bool CheckFunctionDecl(varbinder::LocalVariable *child, varbinder::LocalV return false; } ES2PANDA_ASSERT(child->Declaration()->Type() == parent->Declaration()->Type()); - if (!child->TsType()->IsETSMethodType()) { + if (!child->TsType()->IsETSMethodType() || !parent->TsType()->IsETSMethodType()) { return true; } @@ -183,7 +183,7 @@ bool ETSChecker::ComputeSuperType(ETSObjectType *type) return false; } - auto *superType = classDef->Super()->AsTypeNode()->GetType(this); + auto *superType = classDef->Super()->AsTypeNode()->GetType(this)->MaybeBaseTypeOfGradualType(); if (superType == nullptr) { return true; } @@ -215,6 +215,8 @@ bool ETSChecker::ComputeSuperType(ETSObjectType *type) void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface, std::unordered_set *extendsSet, const lexer::SourcePosition &pos) { + ES2PANDA_ASSERT(interface != nullptr); + interface = interface->MaybeBaseTypeOfGradualType(); if (interface->IsETSObjectType() && interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { LogError(diagnostic::INTERFACE_EXTENDS_CLASS, {}, pos); return; @@ -427,7 +429,7 @@ ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const para } auto *const paramType = CreateTypeParameter(); - + ES2PANDA_ASSERT(paramType != nullptr); paramType->AddTypeFlag(TypeFlag::GENERIC); paramType->SetDeclNode(param); paramType->SetVariable(param->Variable()); @@ -455,6 +457,15 @@ void ETSChecker::CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType *type type->AddObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION); } +Type *ETSChecker::MaybeGradualType(ir::AstNode *node, ETSObjectType *type) +{ + ES2PANDA_ASSERT(node->IsClassDefinition() || node->IsTSInterfaceDeclaration()); + auto isDynamic = node->IsClassDefinition() ? node->AsClassDefinition()->Language().IsDynamic() + : node->AsTSInterfaceDeclaration()->Language().IsDynamic(); + // Temporary solution, the struct loses 'language' while being converted to a class through the plugin API. + return isDynamic || Program()->IsDeclForDynamicStaticInterop() ? CreateGradualType(type) : type; +} + Type *ETSChecker::BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl) { auto *var = interfaceDecl->Id()->Variable(); @@ -468,11 +479,14 @@ Type *ETSChecker::BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *inte if (var->TsType() == nullptr) { interfaceType = CreateETSObjectTypeOrBuiltin(interfaceDecl, checker::ETSObjectFlags::INTERFACE); interfaceType->SetVariable(var); - type = Program()->IsDeclForDynamicStaticInterop() ? CreateGradualType(interfaceType) : interfaceType; + type = MaybeGradualType(interfaceDecl, interfaceType); var->SetTsType(type); + } else if (var->TsType()->MaybeBaseTypeOfGradualType()->IsETSObjectType()) { + interfaceType = var->TsType()->MaybeBaseTypeOfGradualType()->AsETSObjectType(); + type = MaybeGradualType(interfaceDecl, interfaceType); } else { - interfaceType = var->TsType()->AsETSObjectType(); - type = Program()->IsDeclForDynamicStaticInterop() ? CreateGradualType(interfaceType) : interfaceType; + ES2PANDA_ASSERT(IsAnyError()); + return GlobalTypeError(); } // Save before we mess with savedContext. @@ -518,15 +532,15 @@ Type *ETSChecker::BuildBasicClassProperties(ir::ClassDefinition *classDef) checker::Type *type {}; if (var->TsType() == nullptr) { classType = CreateETSObjectTypeOrBuiltin(classDef, checker::ETSObjectFlags::CLASS); - type = Program()->IsDeclForDynamicStaticInterop() ? CreateGradualType(classType) : classType; + type = MaybeGradualType(classDef, classType); classType->SetVariable(var); var->SetTsType(type); if (classDef->IsAbstract()) { classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT); } - } else if (var->TsType()->IsETSObjectType()) { - classType = var->TsType()->AsETSObjectType(); - type = Program()->IsDeclForDynamicStaticInterop() ? CreateGradualType(classType) : classType; + } else if (var->TsType()->MaybeBaseTypeOfGradualType()->IsETSObjectType()) { + classType = var->TsType()->MaybeBaseTypeOfGradualType()->AsETSObjectType(); + type = MaybeGradualType(classDef, classType); } else { ES2PANDA_ASSERT(IsAnyError()); return GlobalTypeError(); @@ -563,6 +577,7 @@ ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *cl { auto classType = CreateETSObjectType(classDef, checker::ETSObjectFlags::CLASS); classDef->SetTsType(classType); + ES2PANDA_ASSERT(classType != nullptr); classType->SetSuperType(superType); classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER); @@ -588,6 +603,7 @@ static void ResolveDeclaredFieldsOfObject(ETSChecker *checker, const ETSObjectTy } } +// CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope) { for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) { @@ -595,6 +611,7 @@ static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectT if (it->Declaration()->Node()->IsMethodDefinition()) { auto *method = it->Declaration()->Node()->AsMethodDefinition(); auto *function = method->Function(); + ES2PANDA_ASSERT(function != nullptr); if (function->IsProxy()) { continue; } @@ -619,7 +636,7 @@ static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectT if (it->Declaration()->Node()->IsMethodDefinition()) { auto *method = it->Declaration()->Node()->AsMethodDefinition(); auto *function = method->Function(); - + ES2PANDA_ASSERT(function != nullptr); if (function->IsProxy()) { continue; } @@ -786,8 +803,10 @@ void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType) { - auto cached = GetCachedComputedAbstracts()->find(interfaceType); - if (cached != GetCachedComputedAbstracts()->end()) { + auto cachedComputedAbstracts = GetCachedComputedAbstracts(); + ES2PANDA_ASSERT(cachedComputedAbstracts != nullptr); + auto cached = cachedComputedAbstracts->find(interfaceType); + if (cached != cachedComputedAbstracts->end()) { return; } @@ -800,8 +819,8 @@ void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType) ArenaUnorderedSet abstractInheritanceTarget(ProgramAllocator()->Adapter()); for (auto *interface : interfaceType->Interfaces()) { - auto found = GetCachedComputedAbstracts()->find(interface); - ES2PANDA_ASSERT(found != GetCachedComputedAbstracts()->end()); + auto found = cachedComputedAbstracts->find(interface); + ES2PANDA_ASSERT(found != cachedComputedAbstracts->end()); if (!abstractInheritanceTarget.insert(found->first).second) { continue; @@ -814,7 +833,7 @@ void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType) } } - GetCachedComputedAbstracts()->insert({interfaceType, {merged, abstractInheritanceTarget}}); + cachedComputedAbstracts->insert({interfaceType, {merged, abstractInheritanceTarget}}); } ArenaVector &ETSChecker::GetAbstractsForClass(ETSObjectType *classType) @@ -918,6 +937,7 @@ void ETSChecker::CheckFunctionRedeclarationInInterface(ETSObjectType *classType, if (sig == sigFunc) { return; } + ES2PANDA_ASSERT(sigFunc != nullptr); if (sigFunc->Function()->Id()->Name() == sig->Function()->Id()->Name()) { if (classType->IsSameBasedGeneric(Relation(), sig->Owner())) { return; @@ -937,6 +957,7 @@ static void CallRedeclarationCheckForCorrectSignature(ir::MethodDefinition *meth ETSObjectType *classType, ETSChecker *checker) { ir::ScriptFunction *func = method->Function(); + ES2PANDA_ASSERT(func != nullptr); if (!func->IsAbstract()) { auto *sigFunc = funcType->FindSignature(func); checker->CheckFunctionRedeclarationInInterface(classType, similarSignatures, sigFunc); @@ -1256,6 +1277,12 @@ void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) classType->SuperType()->GetDeclNode()->Check(this); } + if (classType->GetDeclNode() != classDef) { + ES2PANDA_ASSERT(IsAnyError()); + classDef->SetTsType(GlobalTypeError()); + return; + } + auto newStatus = checker::CheckerStatus::IN_CLASS; if (Context().ContainingClass() != classType) { classType->SetEnclosingType(Context().ContainingClass()); @@ -1706,7 +1733,10 @@ bool ETSChecker::ValidateTupleIndexFromEtsObject(const ETSTupleType *const tuple if (expr->Property() == nullptr || expr->Property()->Variable() == nullptr || expr->Property()->Variable()->Declaration() == nullptr || expr->Property()->Variable()->Declaration()->Node() == nullptr || - expr->Property()->Variable()->Declaration()->Node()->AsClassElement() == nullptr) { + !(expr->Property()->Variable()->Declaration()->Node()->IsMethodDefinition() || + expr->Property()->Variable()->Declaration()->Node()->IsClassProperty() || + expr->Property()->Variable()->Declaration()->Node()->IsClassStaticBlock() || + expr->Property()->Variable()->Declaration()->Node()->IsOverloadDeclaration())) { LogError(diagnostic::TUPLE_INDEX_NONCONST, {}, expr->Start()); return false; } @@ -1811,6 +1841,7 @@ void ETSChecker::CheckCyclicConstructorCall(Signature *signature) ETSObjectType *ETSChecker::CheckExceptionOrErrorType(checker::Type *type, const lexer::SourcePosition pos) { + ES2PANDA_ASSERT(type != nullptr); if (!type->IsETSObjectType() || (!Relation()->IsAssignableTo(type, GlobalBuiltinExceptionType()) && !Relation()->IsAssignableTo(type, GlobalBuiltinErrorType()))) { LogError(diagnostic::CATCH_OR_THROW_OF_INVALID_TYPE, @@ -2318,12 +2349,13 @@ void ETSChecker::WarnForEndlessLoopInGetterSetter(const ir::MemberExpression *co } auto ident = memberExpr->Property()->AsIdentifier(); auto parent = memberExpr->Parent(); - while (parent != nullptr && - (!parent->IsMethodDefinition() || (!parent->AsMethodDefinition()->Function()->IsGetter() && - !parent->AsMethodDefinition()->Function()->IsSetter()))) { + while (parent != nullptr && (!parent->IsMethodDefinition() || parent->AsMethodDefinition()->Function() == nullptr || + (!parent->AsMethodDefinition()->Function()->IsGetter() && + !parent->AsMethodDefinition()->Function()->IsSetter()))) { parent = parent->Parent(); } - if (parent != nullptr && ident->Name() == parent->AsMethodDefinition()->Function()->Id()->Name()) { + if (parent != nullptr && parent->AsMethodDefinition()->Function() != nullptr && + ident->Name() == parent->AsMethodDefinition()->Function()->Id()->Name()) { if (parent->AsMethodDefinition()->Function()->IsGetter()) { LogDiagnostic(diagnostic::GETTER_LOOP, memberExpr->Property()->AsIdentifier()->Start()); } else { @@ -2341,6 +2373,12 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefini const auto &allProps = classType->GetAllProperties(); for (auto *it : allProps) { + auto *node = it->Declaration()->Node(); + if (node->IsClassProperty() && node->AsClassProperty()->TsType() != nullptr && + node->AsClassProperty()->TsType()->IsTypeError()) { + continue; + } + const auto searchFlag = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION; @@ -2567,6 +2605,10 @@ Type *ETSChecker::GetApparentType(Type *type) apparentTypes.insert({res, res}); return res; }; + ES2PANDA_ASSERT(type != nullptr); + if (type->IsGradualType()) { + return cached(type->AsGradualType()->GetBaseType()); + } if (type->IsETSTypeParameter()) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index f2a5fd239c3e1880de04b922ddbd820ecd817e54..7605fae5d9446dcf1e0fc33614220f9e14e808c1 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -89,7 +89,8 @@ bool ETSChecker::CheckNonNullish(ir::Expression const *expr) Type *ETSChecker::GetNonNullishType(Type *type) { if (type->IsGradualType()) { - return GetNonNullishType(type->AsGradualType()->GetBaseType()); + return CreateGradualType(GetNonNullishType(type->AsGradualType()->GetBaseType()), + type->AsGradualType()->Language()); } if (type->DefinitelyNotETSNullish()) { return type; @@ -414,6 +415,7 @@ bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type) Type *ETSChecker::GetNonConstantType(Type *type) { + ES2PANDA_ASSERT(type != nullptr); if (type->IsETSStringType()) { return GlobalBuiltinETSStringType(); } @@ -471,7 +473,14 @@ Type *ETSChecker::GetTypeOfSetterGetter(varbinder::Variable *const var) { auto *propType = var->TsType()->AsETSFunctionType(); if (propType->HasTypeFlag(checker::TypeFlag::GETTER)) { - return propType->FindGetter()->ReturnType(); + auto *getter = propType->FindGetter(); + ES2PANDA_ASSERT(getter != nullptr); + return getter->ReturnType(); + } + + if (propType->FindSetter()->Params().empty()) { + var->SetTsType(GlobalTypeError()); + return GlobalTypeError(); } return propType->FindSetter()->Params()[0]->TsType(); @@ -511,7 +520,9 @@ void ETSChecker::IterateInVariableContext(varbinder::Variable *const var) if (iter->IsMethodDefinition()) { auto *methodDef = iter->AsMethodDefinition(); ES2PANDA_ASSERT(methodDef->TsType()); - Context().SetContainingSignature(methodDef->Function()->Signature()); + auto *func = methodDef->Function(); + ES2PANDA_ASSERT(func != nullptr); + Context().SetContainingSignature(func->Signature()); } else if (iter->IsClassDefinition()) { auto *classDef = iter->AsClassDefinition(); Type *containingClass {}; @@ -666,7 +677,9 @@ Type *ETSChecker::GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable * switch (auto node = prop->Declaration()->Node(); node->Type()) { case ir::AstNodeType::CLASS_PROPERTY: { - auto baseProp = node->AsClassProperty()->Id()->Variable(); + auto *id = node->AsClassProperty()->Id(); + ES2PANDA_ASSERT(id != nullptr); + auto baseProp = id->Variable(); if (baseProp == prop) { return nullptr; } @@ -686,6 +699,7 @@ Type *ETSChecker::GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable * // Determine if substituted method cast requires cast from erased type Type *ETSChecker::GuaranteedTypeForUncheckedCallReturn(Signature *sig) { + ES2PANDA_ASSERT(sig != nullptr); ES2PANDA_ASSERT(sig->HasFunction()); if (sig->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) { return sig->ReturnType(); @@ -704,9 +718,9 @@ Type *ETSChecker::ResolveUnionUncheckedType(ArenaVector &&appar return nullptr; } auto *unionType = CreateETSUnionType(std::move(apparentTypes)); + ES2PANDA_ASSERT(unionType != nullptr); if (unionType->IsETSUnionType()) { - checker::Type *typeLUB = unionType->AsETSUnionType()->GetAssemblerLUB(); - return typeLUB; + return unionType->AsETSUnionType(); } // Is case of single apparent type, just return itself return unionType; @@ -808,6 +822,7 @@ Type *ETSChecker::GetTypeFromTypeAliasReference(varbinder::Variable *var) typeAliasType = CreateETSTypeAliasType(aliasTypeNode->Id()->Name(), aliasTypeNode); if (aliasTypeNode->TypeParams() != nullptr) { auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(aliasTypeNode->TypeParams()); + ES2PANDA_ASSERT(typeAliasType != nullptr); typeAliasType->AsETSTypeAliasType()->SetTypeArguments(std::move(typeParamTypes)); if (ok) { AssignTypeParameterConstraints(aliasTypeNode->TypeParams()); @@ -957,12 +972,15 @@ void ETSChecker::CheckAmbientAnnotation(ir::AnnotationDeclaration *annoImpl, ir: for (auto *prop : annoDecl->Properties()) { auto *field = prop->AsClassProperty(); + ES2PANDA_ASSERT(field->Id() != nullptr); fieldMap[field->Id()->Name()] = field; } for (auto *prop : annoImpl->Properties()) { auto *field = prop->AsClassProperty(); - auto fieldName = field->Id()->Name(); + auto *id = field->Id(); + ES2PANDA_ASSERT(id != nullptr); + auto fieldName = id->Name(); auto fieldDeclIter = fieldMap.find(fieldName); if (fieldDeclIter == fieldMap.end()) { LogError(diagnostic::AMBIENT_ANNOT_IMPL_OF_UNDEFINED_FIELD, {fieldName, annoDecl->GetBaseName()->Name()}, @@ -1140,7 +1158,7 @@ void ETSChecker::HandleAnnotationRetention(ir::AnnotationUsage *anno, ir::Annota void ETSChecker::CheckStandardAnnotation(ir::AnnotationUsage *anno) { - if (anno->GetBaseName()->Variable() == nullptr) { + if (anno->GetBaseName()->Variable() == nullptr || IsTypeError(anno->GetBaseName()->TsType())) { return; } ES2PANDA_ASSERT(anno->GetBaseName()->Variable()->Declaration()->Node()->AsAnnotationDeclaration() != nullptr); @@ -1235,9 +1253,11 @@ void ETSChecker::CheckMultiplePropertiesAnnotation(ir::AnnotationUsage *st, util { for (auto *it : st->Properties()) { auto *param = it->AsClassProperty(); - auto result = fieldMap.find(param->Id()->Name()); + auto *id = param->Id(); + ES2PANDA_ASSERT(id != nullptr); + auto result = fieldMap.find(id->Name()); if (result == fieldMap.end()) { - LogError(diagnostic::ANNOT_PROP_UNDEFINED, {param->Id()->Name(), baseName}, param->Start()); + LogError(diagnostic::ANNOT_PROP_UNDEFINED, {id->Name(), baseName}, param->Start()); continue; } @@ -1312,11 +1332,13 @@ Type *ETSChecker::MaybeBoxInRelation(Type *objectType) Type *ETSChecker::MaybeBoxType(Type *type) const { + ES2PANDA_ASSERT(type != nullptr); return type->IsETSPrimitiveType() ? BoxingConverter::Convert(this, type) : type; } Type *ETSChecker::MaybeUnboxType(Type *type) const { + ES2PANDA_ASSERT(type != nullptr); return type->IsETSUnboxableObject() ? UnboxingConverter::Convert(this, type->AsETSObjectType()) : type; } @@ -1389,24 +1411,6 @@ void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *rela } } -static ir::AstNode *DerefETSTypeReference(ir::AstNode *node) -{ - ES2PANDA_ASSERT(node->IsETSTypeReference()); - do { - auto *name = node->AsETSTypeReference()->Part()->GetIdent(); - - ES2PANDA_ASSERT(name->IsIdentifier()); - auto *var = name->AsIdentifier()->Variable(); - ES2PANDA_ASSERT(var != nullptr); - auto *declNode = var->Declaration()->Node(); - if (!declNode->IsTSTypeAliasDeclaration()) { - return declNode; - } - node = declNode->AsTSTypeAliasDeclaration()->TypeAnnotation(); - } while (node->IsETSTypeReference()); - return node; -} - // #22952: optional arrow leftovers bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda) { @@ -1416,14 +1420,13 @@ bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction return false; } if (typeAnn->IsETSTypeReference() && !typeAnn->AsETSTypeReference()->TsType()->IsETSArrayType()) { - typeAnn = DerefETSTypeReference(typeAnn); + typeAnn = util::Helpers::DerefETSTypeReference(typeAnn); } if (!typeAnn->IsETSFunctionType()) { // the surrounding function is made so we can *bypass* the typecheck in the "inference" context, // however the body of the function has to be checked in any case if (typeAnn->IsETSUnionType()) { - lambda->Parent()->Check(this); return CheckLambdaAssignableUnion(typeAnn, lambda); } @@ -1443,7 +1446,7 @@ bool ETSChecker::CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunction Type *const subParameterType) { if (typeAnnotation->IsETSTypeReference()) { - typeAnnotation = DerefETSTypeReference(typeAnnotation); + typeAnnotation = util::Helpers::DerefETSTypeReference(typeAnnotation); } if (!typeAnnotation->IsETSFunctionType()) { @@ -1462,7 +1465,10 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, ir::ArrowFunctionExpression *const arrowFuncExpr, Type *const parameterType, TypeRelationFlag flags) { - auto *typeAnnotation = param->Ident()->TypeAnnotation(); + ir::AstNode *typeAnnotation = param->Ident()->TypeAnnotation(); + if (typeAnnotation->IsETSTypeReference()) { + typeAnnotation = util::Helpers::DerefETSTypeReference(typeAnnotation); + } auto checkInvocable = [&arrowFuncExpr, ¶meterType, this](TypeRelationFlag functionFlags) { Type *const argumentType = arrowFuncExpr->Check(this); functionFlags |= TypeRelationFlag::NO_THROW; @@ -1476,6 +1482,7 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, if (!typeAnnotation->IsETSUnionType()) { // #22952: infer optional parameter heuristics auto nonNullishParam = param->IsOptional() ? GetNonNullishType(parameterType) : parameterType; + ES2PANDA_ASSERT(nonNullishParam != nullptr); if (!nonNullishParam->IsETSFunctionType()) { arrowFuncExpr->Check(this); return true; @@ -1492,13 +1499,12 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, } auto *const lambdaReturnTypeAnnotation = lambda->ReturnTypeAnnotation(); - Type *const argumentType = arrowFuncExpr->Check(this); - if (Relation()->IsSupertypeOf(parameterType, argumentType)) { - return true; + if (!parameterType->IsETSUnionType() || parameterType->AsETSUnionType()->ConstituentTypes().size() != + typeAnnotation->AsETSUnionType()->Types().size()) { + Type *const argumentType = arrowFuncExpr->Check(this); + return Relation()->IsSupertypeOf(parameterType, argumentType); } - ES2PANDA_ASSERT(parameterType->AsETSUnionType()->ConstituentTypes().size() == - typeAnnotation->AsETSUnionType()->Types().size()); const auto typeAnnsOfUnion = typeAnnotation->AsETSUnionType()->Types(); const auto typeParamOfUnion = parameterType->AsETSUnionType()->ConstituentTypes(); for (size_t ix = 0; ix < typeAnnsOfUnion.size(); ++ix) { diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 725024a0bb166273d69a53172c882399ecd87aee..959fcad7731532ffdfb72a35ebfbf334621adbbd 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -79,7 +79,9 @@ ETSStringType *ETSChecker::CreateETSStringLiteralType(util::StringView value) ETSResizableArrayType *ETSChecker::CreateETSMultiDimResizableArrayType(Type *element, size_t dimSize) { - ETSResizableArrayType *const arrayType = GlobalBuiltinETSResizableArrayType()->AsETSResizableArrayType(); + ETSObjectType *type = GlobalBuiltinETSResizableArrayType(); + ES2PANDA_ASSERT(type != nullptr); + ETSResizableArrayType *const arrayType = type->AsETSResizableArrayType(); ES2PANDA_ASSERT(arrayType->TypeArguments().size() == 1U); Type *baseArrayType = element; @@ -95,7 +97,9 @@ ETSResizableArrayType *ETSChecker::CreateETSMultiDimResizableArrayType(Type *ele ETSResizableArrayType *ETSChecker::CreateETSResizableArrayType(Type *element) { - ETSResizableArrayType *arrayType = GlobalBuiltinETSResizableArrayType()->AsETSResizableArrayType(); + ETSObjectType *type = GlobalBuiltinETSResizableArrayType(); + ES2PANDA_ASSERT(type != nullptr); + ETSResizableArrayType *arrayType = type->AsETSResizableArrayType(); ES2PANDA_ASSERT(arrayType->TypeArguments().size() == 1U); auto substitution = Substitution {}; @@ -113,6 +117,7 @@ ETSArrayType *ETSChecker::CreateETSArrayType(Type *elementType, bool isCachePoll auto *arrayType = ProgramAllocator()->New(elementType); + ES2PANDA_ASSERT(arrayType != nullptr); std::stringstream ss; arrayType->ToAssemblerTypeWithRank(ss); // arrayType->SetAssemblerName(util::UString(ss.str(), ProgramAllocator()).View()); @@ -133,9 +138,6 @@ Type *ETSChecker::CreateGradualType(Type *type, Language const lang) if (type->IsGradualType()) { return type; } - if (!type->PossiblyInForeignDomain()) { - return type; - } if (type->IsETSAnyType()) { return type; } @@ -162,8 +164,12 @@ Type *ETSChecker::CreateETSUnionType(Span constituentTypes) if (newConstituentTypes.size() == 1) { return newConstituentTypes[0]; } - - return ProgramAllocator()->New(this, std::move(newConstituentTypes)); + auto *un = ProgramAllocator()->New(this, std::move(newConstituentTypes)); + auto ut = un->GetAssemblerType().Mutf8(); + if (std::count_if(ut.begin(), ut.end(), [](char c) { return c == ','; }) > 0) { + unionAssemblerTypes_.insert(un->GetAssemblerType()); + } + return un; } ETSTypeAliasType *ETSChecker::CreateETSTypeAliasType(util::StringView name, const ir::AstNode *declNode, @@ -221,6 +227,7 @@ Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir } auto signature = ProgramAllocator()->New(info, returnType, func); auto convertedFlag = ConvertToSignatureFlags(func->Modifiers(), func->Flags()); + ES2PANDA_ASSERT(signature != nullptr); func->HasReceiver() ? signature->AddSignatureFlag(SignatureFlags::EXTENSION_FUNCTION | convertedFlag) : signature->AddSignatureFlag(convertedFlag); return signature; @@ -234,6 +241,7 @@ Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir return nullptr; } auto signature = ProgramAllocator()->New(info, returnType, nullptr); + ES2PANDA_ASSERT(signature != nullptr); signature->AddSignatureFlag(ConvertToSignatureFlags(ir::ModifierFlags::NONE, sff)); // synthetic arrow type signature flags auto extraFlags = SignatureFlags::ABSTRACT | SignatureFlags::CALL | SignatureFlags::PUBLIC; @@ -384,12 +392,14 @@ std::tuple ETSChecker::CreateBuiltinArraySign arrayType->ToAssemblerTypeWithRank(ss); auto *info = CreateSignatureInfo(); + ES2PANDA_ASSERT(info != nullptr); info->minArgCount = dim; for (size_t i = 0; i < dim; i++) { util::UString param(std::to_string(i), ProgramAllocator()); auto *paramVar = varbinder::Scope::CreateVar(ProgramAllocator(), param.View(), varbinder::VariableFlags::NONE, nullptr); + ES2PANDA_ASSERT(paramVar != nullptr); paramVar->SetTsType(GlobalIntType()); info->params.push_back(paramVar); @@ -416,6 +426,7 @@ Signature *ETSChecker::CreateBuiltinArraySignature(const ETSArrayType *arrayType auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim); auto *signature = CreateSignature(info, GlobalVoidType(), ir::ScriptFunctionFlags::NONE, false); + ES2PANDA_ASSERT(signature != nullptr); signature->SetInternalName(internalName); globalArraySignatures.insert({arrayType, signature}); @@ -428,6 +439,7 @@ ETSObjectType *ETSChecker::CreatePromiseOf(Type *type) ES2PANDA_ASSERT(promiseType->TypeArguments().size() == 1U); auto substitution = Substitution {}; + ES2PANDA_ASSERT(promiseType != nullptr); EmplaceSubstituted(&substitution, promiseType->TypeArguments()[0]->AsETSTypeParameter()->GetOriginal(), type); return promiseType->Substitute(Relation(), &substitution); diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index 80bfff4d4ebc492025a92f10c9e7d15cba978d00..855ea818309eec24bf01bb68432e35ebd88e9010 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -73,6 +73,7 @@ void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParame if (typeArgs != nullptr) { for (auto *const it : typeArgs->Params()) { auto *paramType = it->GetType(checker_); + ES2PANDA_ASSERT(paramType != nullptr); if (paramType->IsTypeError()) { result_ = paramType; return; @@ -110,6 +111,7 @@ static void CheckInstantiationConstraints(ETSChecker *checker, ArenaVectorRelation(); for (auto type : typeParams) { + type = type->MaybeBaseTypeOfGradualType(); if (!type->IsETSTypeParameter()) { continue; } diff --git a/ets2panda/checker/ets/typeRelationContext.h b/ets2panda/checker/ets/typeRelationContext.h index eeb2ba008ddce15c0f48884f6998036577db8aa8..ae20ce5ad1ceddc5f13cc6f8e61af4269b365b04 100644 --- a/ets2panda/checker/ets/typeRelationContext.h +++ b/ets2panda/checker/ets/typeRelationContext.h @@ -34,6 +34,8 @@ public: auto *const etsChecker = relation->GetChecker()->AsETSChecker(); + ES2PANDA_ASSERT(target != nullptr); + ES2PANDA_ASSERT(node != nullptr); if (target->IsETSArrayType() && node->IsArrayExpression()) { assignable_ = ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsETSArrayType()); diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index 3206fddacec0bf8953a431d37cbd60f4126b4fa8..076bdb34bd08c8caf9ac3258f87e77f9533311fb 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -238,8 +238,11 @@ Type *ETSChecker::HandlePartialInterface(ir::TSInterfaceDeclaration *interfaceDe ir::ClassProperty *ETSChecker::CreateNullishPropertyFromAccessor(ir::MethodDefinition *const accessor, ir::ClassDefinition *const newClassDefinition) { + auto *id = accessor->Id(); + ES2PANDA_ASSERT(id != nullptr); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *ident = accessor->Id()->Clone(ProgramAllocator(), nullptr); + auto *ident = id->Clone(ProgramAllocator(), nullptr); + ES2PANDA_ASSERT(accessor->Function() != nullptr); auto modifierFlag = accessor->Function()->IsGetter() && accessor->Overloads().empty() ? ir::ModifierFlags::READONLY : ir::ModifierFlags::NONE; @@ -373,8 +376,10 @@ ir::TSTypeParameterDeclaration *ETSChecker::ProcessTypeParamAndGenSubstitution( CloneNodeIfNotNullptr(classOrInterfaceDefTypeParam->Constraint(), ProgramAllocator()), // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) CloneNodeIfNotNullptr(classOrInterfaceDefTypeParam->DefaultType(), ProgramAllocator()), ProgramAllocator()); + ES2PANDA_ASSERT(newTypeParam != nullptr); newTypeParams->AddParam(newTypeParam); newTypeParam->SetParent(newTypeParams); + ES2PANDA_ASSERT(likeSubstitution != nullptr); (*likeSubstitution)[classOrInterfaceDefTypeParam] = newTypeParam; } return newTypeParams; @@ -407,9 +412,11 @@ ir::TSTypeParameterInstantiation *ETSChecker::CreateNewSuperPartialRefTypeParams // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ProgramAllocNode(it->second->Name()->Clone(ProgramAllocator(), nullptr), ProgramAllocator()); + ES2PANDA_ASSERT(typeParamRefPart != nullptr); typeParamRefPart->Name()->SetParent(typeParamRefPart); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *typeParamRef = ProgramAllocNode(typeParamRefPart, ProgramAllocator()); + ES2PANDA_ASSERT(typeParamRef != nullptr); typeParamRefPart->SetParent(typeParamRef); typeParamRef->SetParent(superPartialRefTypeParams); @@ -435,6 +442,7 @@ ir::ETSTypeReference *ETSChecker::BuildSuperPartialTypeReference( // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ProgramAllocNode(clonedId, superPartialRefTypeParams, nullptr, ProgramAllocator()); + ES2PANDA_ASSERT(superPartialRefPart != nullptr); superPartialRefPart->Name()->SetParent(superPartialRefPart); if (superPartialRefTypeParams != nullptr) { superPartialRefTypeParams->SetParent(superPartialRefPart); @@ -468,7 +476,7 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ProgramAllocNode(std::move(typeParams), classDef->TypeParams()->RequiredParams()); - + ES2PANDA_ASSERT(newTypeParams != nullptr); newClassDefinition->SetTypeParams(newTypeParams); newTypeParams->SetParent(newClassDefinition); } @@ -480,7 +488,8 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla // Only handle class properties (members) // Method calls on partial classes will make the class not type safe, so we don't copy any methods if (prop->IsClassProperty()) { - if (prop->AsClassProperty()->Id()->Name().Mutf8().find(compiler::Signatures::PROPERTY, 0) == 0) { + if (prop->AsClassProperty()->Id() == nullptr || + prop->AsClassProperty()->Id()->Name().Mutf8().find(compiler::Signatures::PROPERTY, 0) == 0) { continue; } @@ -490,10 +499,11 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla // Put the new property into the class declaration newClassDefinition->EmplaceBody(newProp); } - - if (prop->IsMethodDefinition() && (prop->AsMethodDefinition()->Function()->IsGetter() || - prop->AsMethodDefinition()->Function()->IsSetter())) { + if (prop->IsMethodDefinition() && prop->AsMethodDefinition()->Function() != nullptr && + (prop->AsMethodDefinition()->Function()->IsGetter() || + prop->AsMethodDefinition()->Function()->IsSetter())) { auto *method = prop->AsMethodDefinition(); + ES2PANDA_ASSERT(method->Id() != nullptr); if (newClassDefinition->Scope()->FindLocal(method->Id()->Name(), varbinder::ResolveBindingOptions::VARIABLES) != nullptr) { continue; @@ -520,6 +530,7 @@ ir::MethodDefinition *ETSChecker::CreateNullishAccessor(ir::MethodDefinition *co const auto interfaceCtx = varbinder::LexicalScope::Enter(VarBinder(), interface->Scope()); auto *paramScope = ProgramAllocator()->New(ProgramAllocator(), interface->Scope()); auto *functionScope = ProgramAllocator()->New(ProgramAllocator(), paramScope); + ES2PANDA_ASSERT(functionScope != nullptr); functionScope->BindParamScope(paramScope); paramScope->BindFunctionScope(functionScope); @@ -598,6 +609,7 @@ ir::TSInterfaceDeclaration *ETSChecker::CreateInterfaceProto(util::StringView na auto *const interfaceId = ProgramAllocNode(name, ProgramAllocator()); const auto [decl, var] = VarBinder()->NewVarDecl(interfaceId->Start(), ProgramAllocator(), interfaceId->Name()); + ES2PANDA_ASSERT(interfaceId != nullptr); interfaceId->SetVariable(var); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) @@ -615,6 +627,7 @@ ir::TSInterfaceDeclaration *ETSChecker::CreateInterfaceProto(util::StringView na Language(Language::Id::ETS)}); const auto classCtx = varbinder::LexicalScope(VarBinder()); + ES2PANDA_ASSERT(partialInterface != nullptr); partialInterface->TypeParams()->SetParent(partialInterface); partialInterface->SetScope(classCtx.GetScope()); partialInterface->SetVariable(var); @@ -667,14 +680,17 @@ void ETSChecker::CreatePartialTypeInterfaceMethods(ir::TSInterfaceDeclaration *c } auto *const method = prop->AsMethodDefinition(); - ES2PANDA_ASSERT((method->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) == 0U); + auto *func = method->Function(); + ES2PANDA_ASSERT(func != nullptr); + ES2PANDA_ASSERT((func->Flags() & ir::ScriptFunctionFlags::OVERLOAD) == 0U); - if (method->Function()->IsGetter() || method->Function()->IsSetter()) { + if (func->IsGetter() || func->IsSetter()) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) addNullishAccessor(CreateNullishAccessor(method, partialInterface)); } for (auto *overload : method->Overloads()) { + ES2PANDA_ASSERT(overload->Function() != nullptr); if (overload->Function()->IsGetter() || overload->Function()->IsSetter()) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) addNullishAccessor(CreateNullishAccessor(overload, partialInterface)); @@ -705,7 +721,9 @@ Type *ETSChecker::CreatePartialTypeInterfaceDecl(ir::TSInterfaceDeclaration *con auto methodscope = partialInterface->Scope()->AsClassScope()->InstanceMethodScope(); // Add getter methods to instancemethodscope. for (auto *const prop : partialInterface->Body()->Body()) { - if (prop->IsMethodDefinition() && prop->AsMethodDefinition()->Function()->IsGetter()) { + auto *func = prop->AsMethodDefinition()->Function(); + ES2PANDA_ASSERT(func != nullptr); + if (prop->IsMethodDefinition() && func->IsGetter()) { auto *decl = ProgramAllocator()->New( ProgramAllocator(), prop->AsMethodDefinition()->Key()->AsIdentifier()->Name(), prop); methodscope->AddDecl(ProgramAllocator(), decl, ScriptExtension::ETS); @@ -775,6 +793,7 @@ ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, par // Create class name, and declaration variable // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *const classId = ProgramAllocNode(name, ProgramAllocator()); + ES2PANDA_ASSERT(classId != nullptr); const auto [decl, var] = VarBinder()->NewVarDecl(classId->Start(), classId->Name()); classId->SetVariable(var); @@ -784,12 +803,14 @@ ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, par // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ProgramAllocNode(ProgramAllocator(), classId, ir::ClassDefinitionModifiers::DECLARATION, ir::ModifierFlags::NONE, Language(Language::Id::ETS)); + ES2PANDA_ASSERT(classDef != nullptr); classDef->SetScope(classCtx.GetScope()); classDef->SetVariable(var); // Create class declaration node // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *const classDecl = ProgramAllocNode(classDef, ProgramAllocator()); + ES2PANDA_ASSERT(classDecl != nullptr); classDecl->SetParent(classDeclProgram->Ast()); // Class definition is scope bearer, not class declaration @@ -874,6 +895,9 @@ Type *ETSChecker::CreatePartialTypeClassDef(ir::ClassDefinition *const partialCl LogError(diagnostic::CYCLIC_CLASS_SUPER_TYPE, {}, classDef->Start()); return partialType; } + if (partialSuper->IsTypeError()) { + return partialType; + } partialType->SetSuperType(partialSuper->AsETSObjectType()); } @@ -891,6 +915,7 @@ std::pair ETSChecker::CreateScriptFuncti // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *const body = ProgramAllocNode(ProgramAllocator(), std::move(statements)); + ES2PANDA_ASSERT(body != nullptr); body->SetScope(scope); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) id = ProgramAllocNode(util::UString(std::string("constructor"), ProgramAllocator()).View(), @@ -902,7 +927,7 @@ std::pair ETSChecker::CreateScriptFuncti ir::ScriptFunctionFlags::CONSTRUCTOR | ir::ScriptFunctionFlags::EXPRESSION, ir::ModifierFlags::PUBLIC}); - + ES2PANDA_ASSERT(func != nullptr); func->SetScope(scope); scope->BindNode(func); func->SetIdent(id); @@ -959,10 +984,11 @@ Type *ETSChecker::GetReadonlyType(Type *type) } NamedTypeStackElement ntse(this, type); - + ES2PANDA_ASSERT(type != nullptr); if (type->IsETSArrayType()) { ETSArrayType *const clonedArrayType = ProgramAllocator()->New(type->AsETSArrayType()->ElementType()); + ES2PANDA_ASSERT(clonedArrayType != nullptr); clonedArrayType->AddTypeFlag(TypeFlag::READONLY); return clonedArrayType; } @@ -1025,6 +1051,7 @@ Type *ETSChecker::HandleRequiredType(Type *typeToBeRequired) for (auto *type : typeToBeRequired->AsETSUnionType()->ConstituentTypes()) { if (type->IsETSObjectType()) { type = type->Clone(this); + ES2PANDA_ASSERT(type != nullptr); MakePropertiesNonNullish(type->AsETSObjectType()); } @@ -1044,7 +1071,7 @@ Type *ETSChecker::HandleRequiredType(Type *typeToBeRequired) typeToBeRequired = typeToBeRequired->Clone(this); - MakePropertiesNonNullish(typeToBeRequired->AsETSObjectType()); + MakePropertiesNonNullish(typeToBeRequired->MaybeBaseTypeOfGradualType()->AsETSObjectType()); return typeToBeRequired; } @@ -1076,7 +1103,7 @@ void ETSChecker::MakePropertyNonNullish(ETSObjectType *const classType, varbinde auto *const nonNullishPropType = GetNonNullishType(propType); auto *const propCopy = prop->Copy(ProgramAllocator(), prop->Declaration()); - + ES2PANDA_ASSERT(propCopy != nullptr); propCopy->SetTsType(nonNullishPropType); classType->RemoveProperty(prop); classType->AddProperty(propCopy); @@ -1106,7 +1133,12 @@ void ETSChecker::ValidateObjectLiteralForRequiredType(const ETSObjectType *const if (requiredType->HasObjectFlag(ETSObjectFlags::INTERFACE)) { for (const auto *method : requiredType->GetDeclNode()->AsTSInterfaceDeclaration()->Body()->Body()) { - if (!method->IsMethodDefinition() || !method->AsMethodDefinition()->Function()->IsGetter()) { + if (!method->IsMethodDefinition()) { + continue; + } + auto *func = method->AsMethodDefinition()->Function(); + ES2PANDA_ASSERT(func != nullptr); + if (!func->IsGetter()) { continue; } diff --git a/ets2panda/checker/ts/destructuringContext.cpp b/ets2panda/checker/ts/destructuringContext.cpp index 95f65a54bb3774b404092e6be1cefd35534e21c7..62212a8fcac53a0723d372e7ae9608ebbcab3005 100644 --- a/ets2panda/checker/ts/destructuringContext.cpp +++ b/ets2panda/checker/ts/destructuringContext.cpp @@ -154,7 +154,7 @@ void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *ass if (!checker_->HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { defaultType = checker_->GetBaseTypeOfLiteralType(defaultType); } - + ES2PANDA_ASSERT(defaultType != nullptr); if (validateDefault && assignmentPattern->Right()->IsObjectExpression() && assignmentPattern->Left()->IsObjectPattern()) { ValidateObjectLiteralType(defaultType->AsObjectType(), assignmentPattern->Left()->AsObjectPattern()); @@ -201,6 +201,7 @@ void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *ass void ArrayDestructuringContext::ValidateInferredType() { + ES2PANDA_ASSERT(inferredType_ != nullptr); if (!inferredType_->IsArrayType() && !inferredType_->IsUnionType() && (!inferredType_->IsObjectType() || !inferredType_->AsObjectType()->IsTupleType())) { checker_->ThrowTypeError( @@ -328,6 +329,7 @@ Type *ArrayDestructuringContext::CreateTupleTypeForRest(TupleType *tuple) util::StringView memberIndex = util::Helpers::ToStringView(checker_->Allocator(), iterIndex); auto *memberVar = varbinder::Scope::CreateVar(checker_->Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY, nullptr); + ES2PANDA_ASSERT(memberVar != nullptr); memberVar->SetTsType(tupleElementType); elementFlags.push_back(memberFlag); desc->properties.push_back(memberVar); @@ -528,6 +530,7 @@ void ArrayDestructuringContext::Start() void ObjectDestructuringContext::ValidateInferredType() { + ES2PANDA_ASSERT(inferredType_ != nullptr); // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) if (!inferredType_->IsObjectType()) { return; @@ -557,13 +560,16 @@ Type *ObjectDestructuringContext::CreateObjectTypeForRest(ObjectType *objType) if (!it->HasFlag(varbinder::VariableFlags::INFERRED_IN_PATTERN)) { auto *memberVar = varbinder::Scope::CreateVar(checker_->Allocator(), it->Name(), varbinder::VariableFlags::NONE, nullptr); + ES2PANDA_ASSERT(memberVar != nullptr); memberVar->SetTsType(it->TsType()); memberVar->AddFlag(it->Flags()); + ES2PANDA_ASSERT(desc != nullptr); desc->properties.push_back(memberVar); } } Type *returnType = checker_->Allocator()->New(desc); + ES2PANDA_ASSERT(returnType != nullptr); returnType->AsObjectType()->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); return returnType; } diff --git a/ets2panda/checker/ts/function.cpp b/ets2panda/checker/ts/function.cpp index e4419c3f8c3e31d2890a36cf00d8249525e94ec9..7b0634260ae6807f7d3a0a5ed3871690ee83a8db 100644 --- a/ets2panda/checker/ts/function.cpp +++ b/ets2panda/checker/ts/function.cpp @@ -54,7 +54,7 @@ Type *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func) if (func->IsArrow() && func->Body()->IsExpression()) { ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start()); } - + ES2PANDA_ASSERT(returnType != nullptr); if (returnType->IsNeverType()) { ThrowTypeError("A function returning 'never' cannot have a reachable end point.", func->ReturnTypeAnnotation()->Start()); @@ -149,13 +149,15 @@ Type *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpressio return inferredType; } - TupleType *newTuple = - inferredTuple->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType()->AsTupleType(); + auto initTuple = inferredTuple->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder()); + ES2PANDA_ASSERT(initTuple != nullptr); + TupleType *newTuple = initTuple->AsObjectType()->AsTupleType(); for (uint32_t index = inferredTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) { util::StringView memberIndex = util::Helpers::ToStringView(Allocator(), index); varbinder::LocalVariable *newMember = varbinder::Scope::CreateVar( Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr); + ES2PANDA_ASSERT(newMember != nullptr); newMember->SetTsType(GlobalAnyType()); newTuple->AddProperty(newMember); } @@ -193,6 +195,7 @@ Type *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpress varbinder::LocalVariable *newProp = varbinder::Scope::CreateVar( Allocator(), prop->Key()->AsIdentifier()->Name(), varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr); + ES2PANDA_ASSERT(newProp != nullptr); newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right()))); newObject->AddProperty(newProp); } @@ -246,6 +249,7 @@ ReturnedVariable TSChecker::CheckFunctionAssignmentPatternParameter(ir::Assignme util::UString pn(ss.str(), Allocator()); varbinder::LocalVariable *patternVar = varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param); + ES2PANDA_ASSERT(patternVar != nullptr); patternVar->SetTsType(paramType); patternVar->AddFlag(varbinder::VariableFlags::OPTIONAL); return {patternVar->AsLocalVariable(), nullptr, true}; @@ -264,6 +268,7 @@ std::tuple TSCheck if (typeAnnotation != nullptr) { typeAnnotation->Check(this); restType = typeAnnotation->GetType(this); + ES2PANDA_ASSERT(restType != nullptr); if (!restType->IsArrayType()) { ThrowTypeError("A rest parameter must be of an array type", param->Start()); } @@ -315,6 +320,7 @@ std::tuple TSCheck auto destructuringContext = ArrayDestructuringContext({this, param->AsArrayPattern(), false, false, param->TypeAnnotation(), nullptr}); destructuringContext.Start(); + ES2PANDA_ASSERT(patternVar != nullptr); patternVar->SetTsType(destructuringContext.InferredType()); return {patternVar->AsLocalVariable(), nullptr, false}; } @@ -337,6 +343,7 @@ std::tuple TSCheck auto destructuringContext = ObjectDestructuringContext( {this, param->AsObjectPattern(), false, false, param->TypeAnnotation(), nullptr}); destructuringContext.Start(); + ES2PANDA_ASSERT(patternVar != nullptr); patternVar->SetTsType(destructuringContext.InferredType()); return {patternVar->AsLocalVariable(), nullptr, false}; } @@ -386,6 +393,7 @@ std::tuple TSCheck if (cache) { Type *placeholder = Allocator()->New(GlobalAnyType()); + ES2PANDA_ASSERT(placeholder != nullptr); placeholder->SetVariable(std::get<0>(result)); param->SetTsType(placeholder); } @@ -396,6 +404,7 @@ std::tuple TSCheck void TSChecker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, SignatureInfo *signatureInfo) { + ES2PANDA_ASSERT(signatureInfo != nullptr); signatureInfo->restVar = nullptr; signatureInfo->minArgCount = 0; @@ -590,6 +599,7 @@ void TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl } Signature *overloadSignature = Allocator()->New(overloadSignatureInfo, returnType, func); + ES2PANDA_ASSERT(descWithOverload != nullptr); descWithOverload->callSignatures.push_back(overloadSignature); } @@ -601,14 +611,16 @@ void TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl if (descWithOverload->callSignatures.empty()) { Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature); + ES2PANDA_ASSERT(funcType != nullptr); funcType->SetVariable(funcVar); funcVar->SetTsType(funcType); } - + ES2PANDA_ASSERT(bodyCallSignature != nullptr); bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration)); if (!descWithOverload->callSignatures.empty()) { Type *funcType = Allocator()->New(descWithOverload); + ES2PANDA_ASSERT(funcType != nullptr); funcType->SetVariable(funcVar); funcVar->SetTsType(funcType); diff --git a/ets2panda/checker/ts/helpers.cpp b/ets2panda/checker/ts/helpers.cpp index 9c2455f558c2cf064c93663fee5cd0ffa05bf9b4..9b5abf6d2902b1da9ca71b0877115008f6afa0ac 100644 --- a/ets2panda/checker/ts/helpers.cpp +++ b/ets2panda/checker/ts/helpers.cpp @@ -59,7 +59,7 @@ Type *TSChecker::GetBaseTypeOfLiteralType(Type *type) if (HasStatus(CheckerStatus::KEEP_LITERAL_TYPE)) { return type; } - + ES2PANDA_ASSERT(type != nullptr); if (type->IsStringLiteralType()) { return GlobalStringType(); } @@ -382,6 +382,7 @@ void TSChecker::GetTypeParam(varbinder::Variable *var, varbinder::Decl *decl) { ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); + ES2PANDA_ASSERT(declaration != nullptr); if (declaration->IsIdentifier()) { auto *ident = declaration->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { @@ -499,6 +500,7 @@ Type *TSChecker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] ir::TSTyp if (resolvedType == nullptr) { ObjectDescriptor *desc = Allocator()->New(Allocator()); resolvedType = Allocator()->New(Allocator(), var->Name(), desc); + ES2PANDA_ASSERT(resolvedType != nullptr); resolvedType->SetVariable(var); var->SetTsType(resolvedType); } diff --git a/ets2panda/checker/ts/object.cpp b/ets2panda/checker/ts/object.cpp index d0b36c61dc21745bb7fb0994b1f9c0f222731dd9..0c9e3c25c32a4186ee55c6746a6e212a05cedbc7 100644 --- a/ets2panda/checker/ts/object.cpp +++ b/ets2panda/checker/ts/object.cpp @@ -139,6 +139,7 @@ void TSChecker::ResolveUnionTypeMembers(UnionType *type) } } + ES2PANDA_ASSERT(desc != nullptr); desc->callSignatures = callSignatures; desc->constructSignatures = constructSignatures; @@ -151,6 +152,7 @@ void TSChecker::ResolveUnionTypeMembers(UnionType *type) } ObjectType *mergedType = Allocator()->New(desc); + ES2PANDA_ASSERT(mergedType != nullptr); mergedType->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); type->SetMergedObjectType(mergedType); } @@ -333,6 +335,7 @@ varbinder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const ut } varbinder::Variable *syntheticProp = varbinder::Scope::CreateVar(Allocator(), name, flags, nullptr); + ES2PANDA_ASSERT(syntheticProp != nullptr); syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes))); type->CachedSyntheticProperties().insert({name, syntheticProp}); return syntheticProp; @@ -386,10 +389,12 @@ IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType) Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType) { + ES2PANDA_ASSERT(type != nullptr); if (type->IsArrayType()) { return type->AsArrayType()->ElementType(); } + ES2PANDA_ASSERT(indexType != nullptr); if (indexType->HasTypeFlag(TypeFlag::STRING_LITERAL | TypeFlag::NUMBER_LITERAL)) { varbinder::Variable *prop = nullptr; @@ -453,6 +458,7 @@ ArenaVector TSChecker::GetBaseTypes(InterfaceType *type) for (auto *extends : declaration->Extends()) { Type *baseType = extends->Expr()->GetType(this); + ES2PANDA_ASSERT(baseType != nullptr); if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) { ThrowTypeError( "An interface can only extend an object type or intersection of object types with statically " diff --git a/ets2panda/checker/ts/typeCreation.cpp b/ets2panda/checker/ts/typeCreation.cpp index c40b8b1ed750ee4e21a47d61006ca2b9620b0bc2..08b9a7ae9bcba3a14be96f43d24ed6c717601b50 100644 --- a/ets2panda/checker/ts/typeCreation.cpp +++ b/ets2panda/checker/ts/typeCreation.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -125,6 +125,7 @@ Type *TSChecker::CreateUnionType(ArenaVector &&constituentTypes) Type *TSChecker::CreateObjectTypeWithCallSignature(Signature *callSignature) { auto *objType = Allocator()->New(Allocator()->New(Allocator())); + ES2PANDA_ASSERT(objType != nullptr); objType->AddCallSignature(callSignature); return objType; } @@ -132,6 +133,7 @@ Type *TSChecker::CreateObjectTypeWithCallSignature(Signature *callSignature) Type *TSChecker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) { auto *objType = Allocator()->New(Allocator()->New(Allocator())); + ES2PANDA_ASSERT(objType != nullptr); objType->AddConstructSignature(constructSignature); return objType; } @@ -139,6 +141,7 @@ Type *TSChecker::CreateObjectTypeWithConstructSignature(Signature *constructSign Type *TSChecker::CreateFunctionTypeWithSignature(Signature *callSignature) { auto *funcObjType = Allocator()->New(Allocator()->New(Allocator())); + ES2PANDA_ASSERT(funcObjType != nullptr); funcObjType->AddCallSignature(callSignature); return funcObjType; } @@ -146,6 +149,7 @@ Type *TSChecker::CreateFunctionTypeWithSignature(Signature *callSignature) Type *TSChecker::CreateConstructorTypeWithSignature(Signature *constructSignature) { auto *constructObjType = Allocator()->New(Allocator()->New(Allocator())); + ES2PANDA_ASSERT(constructObjType != nullptr); constructObjType->AddConstructSignature(constructSignature); return constructObjType; } diff --git a/ets2panda/checker/types/ets/etsAnyType.cpp b/ets2panda/checker/types/ets/etsAnyType.cpp index 52793689c9b76084dfc5ac556f7a9a53ef7d1319..8f36fb2b2123613809dc8f798044a89eebd61803 100644 --- a/ets2panda/checker/types/ets/etsAnyType.cpp +++ b/ets2panda/checker/types/ets/etsAnyType.cpp @@ -105,6 +105,6 @@ void ETSAnyType::ToDebugInfoType(std::stringstream &ss) const Type *ETSAnyType::Instantiate(ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, [[maybe_unused]] GlobalTypesHolder *globalTypes) { - return allocator->New(); + return isRelaxedAny_ ? allocator->New(true) : allocator->New(); } } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsEnumType.cpp b/ets2panda/checker/types/ets/etsEnumType.cpp index 2ff91ba0ca4a748b24dd7df25ed23dc97d4d1dab..233a403e0501e8a662fba2b7bd2ad9c056b0df62 100644 --- a/ets2panda/checker/types/ets/etsEnumType.cpp +++ b/ets2panda/checker/types/ets/etsEnumType.cpp @@ -61,6 +61,7 @@ void ETSStringEnumType::Cast(TypeRelation *const relation, Type *const target) return; } if (target->IsETSStringType()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {this, target}, relation->GetNode()->Start()); relation->Result(true); return; } @@ -70,6 +71,7 @@ void ETSStringEnumType::Cast(TypeRelation *const relation, Type *const target) void ETSStringEnumType::CastTarget(TypeRelation *relation, Type *source) { if (source->IsETSStringType()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {source, this}, relation->GetNode()->Start()); relation->Result(true); return; } @@ -115,6 +117,7 @@ void ETSIntEnumType::Cast(TypeRelation *const relation, Type *const target) return; } if (target->HasTypeFlag(TypeFlag::ETS_NUMERIC) || target->IsBuiltinNumeric()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {this, target}, relation->GetNode()->Start()); relation->Result(true); return; } @@ -123,11 +126,8 @@ void ETSIntEnumType::Cast(TypeRelation *const relation, Type *const target) void ETSIntEnumType::CastTarget(TypeRelation *relation, Type *source) { - if (source->IsIntType()) { - relation->Result(true); - return; - } - if (source->IsBuiltinNumeric()) { + if (source->IsIntType() || source->IsBuiltinNumeric()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {source, this}, relation->GetNode()->Start()); relation->Result(true); return; } diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 3c356758c81ed3429d8852efe51203f026010773..58c4ea3ceade56f550d26cb6b0c7efbf58fbbf10 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -46,9 +46,12 @@ ETSFunctionType::ETSFunctionType(ETSChecker *checker, Signature *signature) extensionFunctionSigs_(ArenaVector(checker->ProgramAllocator()->Adapter())), extensionAccessorSigs_(ArenaVector(checker->ProgramAllocator()->Adapter())), name_(""), - assemblerName_(checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter()) - ->AsETSObjectType() - ->AssemblerName()) + assemblerName_(checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter()) != + nullptr + ? checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter()) + ->AsETSObjectType() + ->AssemblerName() + : "") { } @@ -56,11 +59,12 @@ ETSFunctionType::ETSFunctionType(ETSChecker *checker, Signature *signature) static void HackThisParameterInExtensionFunctionInvoke(ETSObjectType *interface, size_t arity) { auto invokeName = FunctionalInterfaceInvokeName(arity, false); - auto &callSigsOfInvoke0 = interface->AsETSObjectType() - ->GetOwnProperty(util::StringView(invokeName)) - ->TsType() - ->AsETSFunctionType() - ->CallSignatures(); + auto *property = interface->AsETSObjectType()->GetOwnProperty( + util::StringView(invokeName)); + ES2PANDA_ASSERT(property != nullptr); + auto *tsType = property->TsType(); + ES2PANDA_ASSERT(tsType != nullptr); + auto &callSigsOfInvoke0 = tsType->AsETSFunctionType()->CallSignatures(); for (auto sig : callSigsOfInvoke0) { sig->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE); } @@ -72,8 +76,9 @@ static ETSObjectType *FunctionTypeToFunctionalInterfaceType(ETSChecker *checker, bool isExtensionHack = signature->HasSignatureFlag(SignatureFlags::EXTENSION_FUNCTION); if (signature->RestVar() != nullptr) { - auto nPosParams = signature->Params().size(); - auto *functionN = checker->GlobalBuiltinFunctionType(nPosParams, true)->AsETSObjectType(); + auto sigParamsSize = signature->Params().size(); + auto nPosParams = arity < sigParamsSize ? arity : sigParamsSize; + auto *functionN = checker->GlobalBuiltinFunctionType(nPosParams, true); auto substitution = Substitution {}; for (size_t i = 0; i < nPosParams; i++) { substitution.emplace(functionN->TypeArguments()[i]->AsETSTypeParameter(), @@ -98,7 +103,7 @@ static ETSObjectType *FunctionTypeToFunctionalInterfaceType(ETSChecker *checker, return nullptr; } - auto *funcIface = checker->GlobalBuiltinFunctionType(arity, false)->AsETSObjectType(); + auto *funcIface = checker->GlobalBuiltinFunctionType(arity, false); auto substitution = Substitution {}; for (size_t i = 0; i < arity; i++) { diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index e7d2fb4229839b42e0e1cd6d17c135906d3be3b4..9834924f2eac763cbd88ea9a3775de8f1a16d6eb 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -235,9 +235,11 @@ varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(co varbinder::LocalVariable *res = allocator_->New(varianceFlag); ETSFunctionType *funcType = CreateMethodTypeForProp(name); + ES2PANDA_ASSERT(funcType != nullptr); for (auto &s : signatures) { funcType->AddCallSignature(s); } + ES2PANDA_ASSERT(res != nullptr); res->SetTsType(funcType); funcType->SetVariable(res); @@ -1069,6 +1071,7 @@ varbinder::LocalVariable *ETSObjectType::CopyProperty(varbinder::LocalVariable * if (copiedPropType->Variable() == prop) { copiedPropType->SetVariable(copiedProp); } + ES2PANDA_ASSERT(copiedProp != nullptr); copiedProp->SetTsType(copiedPropType); return copiedProp; } @@ -1089,6 +1092,7 @@ Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation * auto *const copiedType = checker->CreateETSObjectType(declNode_, flags_); ES2PANDA_ASSERT(copiedType->internalName_ == internalName_); ES2PANDA_ASSERT(copiedType->name_ == name_); + ES2PANDA_ASSERT(copiedType != nullptr); copiedType->typeFlags_ = typeFlags_; copiedType->RemoveObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY); copiedType->SetVariable(variable_); @@ -1136,6 +1140,7 @@ static varbinder::LocalVariable *CopyPropertyWithTypeArguments(varbinder::LocalV if (copiedPropType->Variable() == prop || copiedPropType->Variable() == nullptr) { copiedPropType->SetVariable(copiedProp); } + ES2PANDA_ASSERT(copiedProp != nullptr); copiedProp->SetTsType(copiedPropType); return copiedProp; } @@ -1186,6 +1191,7 @@ static ArenaSubstitution *ComputeEffectiveSubstitution(TypeRelation *const relat void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObjectType *const copiedType, ArenaVector &&newTypeArgs, ETSObjectType *base) { + ES2PANDA_ASSERT(copiedType != nullptr); copiedType->typeFlags_ = typeFlags_; copiedType->RemoveObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY); copiedType->SetVariable(variable_); @@ -1568,8 +1574,29 @@ void ETSObjectType::CheckVarianceRecursively(TypeRelation *relation, VarianceFla return; } - auto *params = GetDeclNode()->IsClassDefinition() ? GetDeclNode()->AsClassDefinition()->TypeParams() - : GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + // according to the spec(GENERICS chapter), only class/interface/function/ + // method/lambda and type alias can have type parameters. since + // 1. the type of function and method is ETSFunctionType + // 2. lambda has been checked above + // here we just need check + // 1. class + // 2. interface + // 3. type alias(which will be redirected to its real type) + // And all of them should have declarations + if (declNode_ == nullptr) { + // If the type is not declared, then we do not need to check variance. + return; + } + ir::TSTypeParameterDeclaration *params; + if (GetDeclNode()->IsClassDefinition()) { + params = GetDeclNode()->AsClassDefinition()->TypeParams(); + } else if (GetDeclNode()->IsTSInterfaceDeclaration()) { + params = GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } else { + // If the type is not a class or interface or type alias, then we do not need to check variance. + return; + } + if (params == nullptr) { return; } diff --git a/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp b/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp index 14b55779761ae1d6d2230315da9696e72eaf0d35..fc451fd0707596091c2f81d0c8fb6beb8ce54b6b 100644 --- a/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp @@ -82,8 +82,13 @@ void ETSPartialTypeParameter::IsSubtypeOf(TypeRelation *relation, Type *target) ETSPartialTypeParameter *ETSPartialTypeParameter::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { - return allocator->New( - GetUnderlying()->Instantiate(allocator, relation, globalTypes)->AsETSTypeParameter(), checker_); + auto *underlying = GetUnderlying(); + ES2PANDA_ASSERT(underlying != nullptr); + auto *instantiated = underlying->Instantiate(allocator, relation, globalTypes); + ES2PANDA_ASSERT(instantiated != nullptr); + auto *typeParam = instantiated->AsETSTypeParameter(); + ES2PANDA_ASSERT(typeParam != nullptr); + return allocator->New(typeParam, checker_); } Type *ETSPartialTypeParameter::Substitute(TypeRelation *relation, const Substitution *substitution) diff --git a/ets2panda/checker/types/ets/etsTupleType.cpp b/ets2panda/checker/types/ets/etsTupleType.cpp index d0eb6e703455b8c83bb6cd488cbdcdc61b18f466..38930b20a3a519e024ff6bba7b36b785e0619191 100644 --- a/ets2panda/checker/types/ets/etsTupleType.cpp +++ b/ets2panda/checker/types/ets/etsTupleType.cpp @@ -198,6 +198,7 @@ Type *ETSTupleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[ma { auto *const checker = relation->GetChecker()->AsETSChecker(); auto *const tupleType = allocator->New(checker, GetTupleTypesList()); + ES2PANDA_ASSERT(tupleType != nullptr); tupleType->typeFlags_ = typeFlags_; return tupleType; } diff --git a/ets2panda/checker/types/ets/etsTupleType.h b/ets2panda/checker/types/ets/etsTupleType.h index 2a326dedf9288398ada9753743ee0f539b33b060..f6a76125a9f8d2032f1526238b5be2e100543fef 100644 --- a/ets2panda/checker/types/ets/etsTupleType.h +++ b/ets2panda/checker/types/ets/etsTupleType.h @@ -28,7 +28,10 @@ public: explicit ETSTupleType(ETSChecker *checker, const ArenaVector &typeList) : Type(checker::TypeFlag::ETS_TUPLE), typeList_(typeList), - wrapperType_(checker->GlobalBuiltinTupleType(typeList_.size())->AsETSObjectType()) + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + wrapperType_(checker->GlobalBuiltinTupleType(typeList_.size()) != nullptr + ? checker->GlobalBuiltinTupleType(typeList_.size())->AsETSObjectType() + : nullptr) { typeFlags_ |= TypeFlag::ETS_TUPLE; } diff --git a/ets2panda/checker/types/ets/etsTypeParameter.cpp b/ets2panda/checker/types/ets/etsTypeParameter.cpp index 518a42441bc1d0493b3a90a4a549052fdf48b3b9..ebb370321da70c44aa3855509d3387f22c3d2244 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -127,6 +127,7 @@ Type *ETSTypeParameter::Instantiate([[maybe_unused]] ArenaAllocator *allocator, auto *const checker = relation->GetChecker()->AsETSChecker(); auto *const copiedType = checker->CreateTypeParameter(); + ES2PANDA_ASSERT(copiedType != nullptr); copiedType->AddTypeFlag(TypeFlag::GENERIC); copiedType->SetDeclNode(GetDeclNode()); copiedType->SetDefaultType(GetDefaultType()); diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 34f539ad85602e085170611432a02f385a66d2e2..3bfeecc8cc9282d8c9d2cd9a936db99701553574 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -34,74 +34,125 @@ void ETSUnionType::ToString(std::stringstream &ss, bool precise) const void ETSUnionType::ToAssemblerType(std::stringstream &ss) const { - assemblerLub_->ToAssemblerTypeWithRank(ss); + ss << GetAssemblerType(); } void ETSUnionType::ToDebugInfoType(std::stringstream &ss) const { - assemblerLub_->ToDebugInfoType(ss); -} - -ETSUnionType::ETSUnionType(ETSChecker *checker, ArenaVector &&constituentTypes) - : Type(TypeFlag::ETS_UNION), constituentTypes_(std::move(constituentTypes)) -{ - ES2PANDA_ASSERT(constituentTypes_.size() > 1); - assemblerLub_ = ComputeAssemblerLUB(checker, this); + if (assemblerConstituentTypes_.size() == 1) { + assemblerConstituentTypes_[0]->ToDebugInfoType(ss); + return; + } + ss << "{U"; + // NOLINTNEXTLINE(modernize-loop-convert) + for (size_t idx = 0; idx < assemblerConstituentTypes_.size(); idx++) { + assemblerConstituentTypes_[idx]->ToDebugInfoType(ss); + if (idx != assemblerConstituentTypes_.size() - 1) { + ss << ","; + } + } + ss << "}"; } -bool ETSUnionType::EachTypeRelatedToSomeType(TypeRelation *relation, ETSUnionType *source, ETSUnionType *target) +static std::string GetAssemblerTypeString(Type *type) { - return std::all_of(source->constituentTypes_.begin(), source->constituentTypes_.end(), - [relation, target](auto *s) { return TypeRelatedToSomeType(relation, s, target); }); + std::stringstream ss; + type->ToAssemblerTypeWithRank(ss); + return ss.str(); } -bool ETSUnionType::TypeRelatedToSomeType(TypeRelation *relation, Type *source, ETSUnionType *target) +void ETSUnionType::InitAssemblerTypeCache(ETSChecker *checker) { - return std::any_of(target->constituentTypes_.begin(), target->constituentTypes_.end(), - [relation, source](auto *t) { return relation->IsIdenticalTo(source, t); }); + ES2PANDA_ASSERT(!assemblerConstituentTypes_.empty()); + std::stringstream ss; + if (assemblerConstituentTypes_.size() == 1) { + assemblerConstituentTypes_[0]->ToAssemblerTypeWithRank(ss); + } else { + ss << "{U"; + for (size_t idx = 0; idx < assemblerConstituentTypes_.size(); idx++) { + if (idx != 0) { + ss << ","; + } + if (assemblerConstituentTypes_[idx]->IsETSNullType()) { + ss << compiler::Signatures::NULL_ASSEMBLY_TYPE; + continue; + } + assemblerConstituentTypes_[idx]->ToAssemblerTypeWithRank(ss); + } + ss << "}"; + } + assemblerTypeCache_ = util::UString(ss.str(), checker->ProgramAllocator()).View(); } -// This function computes effective runtime representation of union type -Type *ETSUnionType::ComputeAssemblerLUB(ETSChecker *checker, ETSUnionType *un) +void ETSUnionType::CanonicalizedAssemblerType(ETSChecker *checker) { - auto *const apparent = checker->GetApparentType(un); + auto *const apparent = checker->GetApparentType(this); if (!apparent->IsETSUnionType()) { - return apparent; + assemblerConstituentTypes_.push_back(apparent); + return; } - if (apparent != un) { - return apparent->AsETSUnionType()->assemblerLub_; + if (apparent != this) { + const auto &types = apparent->AsETSUnionType()->GetAssemblerTypes(); + assemblerConstituentTypes_.insert(assemblerConstituentTypes_.begin(), types.begin(), types.end()); + return; } - un = apparent->AsETSUnionType(); - - Type *lub = nullptr; - for (auto *t : un->ConstituentTypes()) { - if (t->IsTypeError()) { - return checker->GlobalTypeError(); - } - // NOTE(vpukhov): #19701 void refactoring - ES2PANDA_ASSERT(t->IsETSReferenceType() || t->IsETSVoidType()); - t = t->IsETSVoidType() ? checker->GlobalETSUndefinedType() : t; - if (lub == nullptr || lub->IsETSUndefinedType()) { - lub = t; + ES2PANDA_ASSERT(constituentTypes_.size() > 1); + bool hasNull = false; + for (auto *type : constituentTypes_) { + ES2PANDA_ASSERT(!type->IsETSUnionType()); + if (type->IsETSUndefinedType() || type->IsETSVoidType()) { continue; } - if (lub == t || t->IsETSUndefinedType()) { + if (type->IsETSNullType() && !hasNull) { + hasNull = true; + assemblerConstituentTypes_.push_back(type); continue; } - if (t->IsETSNullType()) { - return checker->GetGlobalTypesHolder()->GlobalETSObjectType(); + if (type->IsTypeError()) { + assemblerConstituentTypes_.clear(); + assemblerConstituentTypes_.push_back(checker->GlobalTypeError()); + return; } - if (t->IsETSObjectType() && lub->IsETSObjectType()) { - lub = checker->GetClosestCommonAncestor(lub->AsETSObjectType(), t->AsETSObjectType()); - } else if (t->IsETSArrayType() && lub->IsETSArrayType()) { - // NOTE: can compute "common(lub, t)[]" - return checker->GetGlobalTypesHolder()->GlobalETSObjectType(); - } else { - return checker->GetGlobalTypesHolder()->GlobalETSObjectType(); + auto found = + std::find_if(assemblerConstituentTypes_.begin(), assemblerConstituentTypes_.end(), + [&type](Type *t) { return GetAssemblerTypeString(type) == GetAssemblerTypeString(t); }); + if (found == assemblerConstituentTypes_.end()) { + assemblerConstituentTypes_.push_back(type); } } - return checker->GetNonConstantType(lub); + if (assemblerConstituentTypes_.empty()) { + assemblerConstituentTypes_.push_back(checker->GlobalETSObjectType()); + return; + } + if (assemblerConstituentTypes_.size() == 1) { + return; + } + + std::sort(assemblerConstituentTypes_.begin(), assemblerConstituentTypes_.end(), + [](Type *a, Type *b) { return GetAssemblerTypeString(a) < GetAssemblerTypeString(b); }); +} + +ETSUnionType::ETSUnionType(ETSChecker *checker, ArenaVector &&constituentTypes) + : Type(TypeFlag::ETS_UNION), + constituentTypes_(std::move(constituentTypes)), + assemblerConstituentTypes_(checker->ProgramAllocator()->Adapter()) +{ + ES2PANDA_ASSERT(constituentTypes_.size() > 1); + CanonicalizedAssemblerType(checker); + InitAssemblerTypeCache(checker); +} + +bool ETSUnionType::EachTypeRelatedToSomeType(TypeRelation *relation, ETSUnionType *source, ETSUnionType *target) +{ + return std::all_of(source->constituentTypes_.begin(), source->constituentTypes_.end(), + [relation, target](auto *s) { return TypeRelatedToSomeType(relation, s, target); }); +} + +bool ETSUnionType::TypeRelatedToSomeType(TypeRelation *relation, Type *source, ETSUnionType *target) +{ + return std::any_of(target->constituentTypes_.begin(), target->constituentTypes_.end(), + [relation, source](auto *t) { return relation->IsIdenticalTo(source, t); }); } void ETSUnionType::Identical(TypeRelation *relation, Type *other) @@ -368,6 +419,7 @@ bool ETSUnionType::ExtractType(checker::ETSChecker *checker, checker::Type *sour constituentType = constituentType->AsETSTypeParameter()->GetConstraintType(); } else if (constituentType->HasTypeFlag(checker::TypeFlag::GENERIC)) { constituentType = constituentType->Clone(checker); + ES2PANDA_ASSERT(constituentType != nullptr); constituentType->RemoveTypeFlag(checker::TypeFlag::GENERIC); } diff --git a/ets2panda/checker/types/ets/etsUnionType.h b/ets2panda/checker/types/ets/etsUnionType.h index 54c15370d85c9d453a8183ea0844b4a576856743..71c9ac8601f4de50b818fac6c149ee28950068cb 100644 --- a/ets2panda/checker/types/ets/etsUnionType.h +++ b/ets2panda/checker/types/ets/etsUnionType.h @@ -54,10 +54,9 @@ public: [[nodiscard]] ArenaVector GetNonConstantTypes(ETSChecker *checker) const noexcept; - // Do not use it anywhere except codegen - Type *GetAssemblerLUB() const noexcept + const util::StringView &GetAssemblerType() const { - return assemblerLub_; + return assemblerTypeCache_; } template @@ -105,10 +104,17 @@ private: checker::ETSChecker *checker, checker::ETSObjectType *sourceType, std::map &numericTypes) const noexcept; - static Type *ComputeAssemblerLUB(ETSChecker *checker, ETSUnionType *un); + void CanonicalizedAssemblerType(ETSChecker *checker); + void InitAssemblerTypeCache(ETSChecker *checker); + + const ArenaVector &GetAssemblerTypes() const + { + return assemblerConstituentTypes_; + } ArenaVector const constituentTypes_; - Type *assemblerLub_ {nullptr}; + ArenaVector assemblerConstituentTypes_; + util::StringView assemblerTypeCache_; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/gradualType.cpp b/ets2panda/checker/types/gradualType.cpp index cdb568ab47c0aa5a9947f45ba4b76f2c15c0c50e..ccf3f35b6c558b42ac42bcc1b1b6d1710b55c86f 100644 --- a/ets2panda/checker/types/gradualType.cpp +++ b/ets2panda/checker/types/gradualType.cpp @@ -21,37 +21,64 @@ namespace ark::es2panda::checker { void GradualType::Identical(TypeRelation *relation, Type *other) { - baseType_->Identical(relation, other); + if (other->IsGradualType()) { + baseType_->Identical(relation, other->AsGradualType()->GetBaseType()); + } else { + baseType_->Identical(relation, other); + } } void GradualType::AssignmentTarget(TypeRelation *relation, Type *source) { - baseType_->AssignmentTarget(relation, source); + if (source->IsGradualType()) { + baseType_->AssignmentTarget(relation, source->AsGradualType()->GetBaseType()); + } else { + baseType_->AssignmentTarget(relation, source); + } } bool GradualType::AssignmentSource(TypeRelation *relation, Type *target) { + if (target->IsGradualType()) { + return baseType_->AssignmentSource(relation, target->AsGradualType()->GetBaseType()); + } return baseType_->AssignmentSource(relation, target); } void GradualType::Compare(TypeRelation *relation, Type *other) { - return baseType_->Compare(relation, other); + if (other->IsGradualType()) { + baseType_->Compare(relation, other->AsGradualType()->GetBaseType()); + } else { + baseType_->Compare(relation, other); + } } void GradualType::Cast(TypeRelation *relation, Type *target) { - return baseType_->Cast(relation, target); + if (target->IsGradualType()) { + baseType_->Cast(relation, target->AsGradualType()->GetBaseType()); + } else { + baseType_->Cast(relation, target); + } } void GradualType::CastTarget(TypeRelation *relation, Type *source) { - return baseType_->CastTarget(relation, source); + if (source->IsGradualType()) { + baseType_->CastTarget(relation, source->AsGradualType()->GetBaseType()); + } else { + baseType_->CastTarget(relation, source); + } } void GradualType::IsSubtypeOf(TypeRelation *relation, Type *target) { - return baseType_->IsSubtypeOf(relation, target); + if (target->IsGradualType()) { + baseType_->IsSubtypeOf(relation, target->AsGradualType()->GetBaseType()); + } else { + baseType_->IsSubtypeOf(relation, target); + } } void GradualType::IsSupertypeOf(TypeRelation *relation, Type *source) @@ -70,7 +97,8 @@ void GradualType::ToString(std::stringstream &ss, [[maybe_unused]] bool precise) Type *GradualType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { - return baseType_->Instantiate(allocator, relation, globalTypes); + auto baseType = baseType_->Instantiate(allocator, relation, globalTypes); + return relation->GetChecker()->AsETSChecker()->CreateGradualType(baseType); } Type *GradualType::Substitute(TypeRelation *relation, const Substitution *substitution) diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index cac1b14a0ab7eb4859f09290a1fb79c208b37243..0aaeab306651b74f0c87a99d36bc33cd095b239f 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -35,7 +35,7 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub auto *allocator = checker->ProgramAllocator(); bool anyChange = false; SignatureInfo *newSigInfo = allocator->New(allocator); - + ES2PANDA_ASSERT(newSigInfo != nullptr); if (!signatureInfo_->typeParams.empty()) { for (auto *tparam : signatureInfo_->typeParams) { auto *newTparam = tparam->Substitute(relation, substitution); @@ -51,6 +51,10 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub if (newParamType != param->TsType()) { anyChange = true; newParam = param->Copy(allocator, param->Declaration()); + if (newParamType->IsETSVoidType()) { + // since `void` is not allowed to be used as param type + newParamType = checker->GlobalETSUndefinedType(); + } newParam->SetTsType(newParamType); } newSigInfo->params.push_back(newParam); @@ -82,6 +86,7 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub Signature *Signature::CreateSignatureForSubstitute(ArenaAllocator *allocator, SignatureInfo *sigInfo, Type *returnType) { auto *result = allocator->New(sigInfo, returnType, func_); + ES2PANDA_ASSERT(result != nullptr); result->flags_ = flags_; result->internalName_ = internalName_; result->ownerObj_ = ownerObj_; @@ -110,7 +115,7 @@ void Signature::ToAssemblerType(std::stringstream &ss) const Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); - + ES2PANDA_ASSERT(copiedInfo != nullptr); for (size_t idx = 0U; idx < signatureInfo_->params.size(); ++idx) { auto *const paramType = signatureInfo_->params[idx]->TsType()->MaybeBaseTypeOfGradualType(); if (paramType->HasTypeFlag(TypeFlag::GENERIC) && paramType->IsETSObjectType()) { @@ -124,6 +129,7 @@ Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, Gl } auto *const copiedSignature = allocator->New(copiedInfo, returnType_, func_); + ES2PANDA_ASSERT(copiedSignature != nullptr); copiedSignature->flags_ = flags_; copiedSignature->internalName_ = internalName_; copiedSignature->ownerObj_ = ownerObj_; @@ -283,12 +289,14 @@ Signature *Signature::ToArrowSignature(ETSChecker *checker) { auto *allocator = checker->ProgramAllocator(); auto *sigInfo = allocator->New(signatureInfo_, allocator); + ES2PANDA_ASSERT(sigInfo != nullptr); for (auto param : sigInfo->params) { param->SetTsType(checker->MaybeBoxType(param->TsType())); } auto *retType = checker->MaybeBoxType(returnType_); auto *resultSig = allocator->New(sigInfo, retType); + ES2PANDA_ASSERT(resultSig != nullptr); resultSig->flags_ = flags_; resultSig->SetOwner(Owner()); resultSig->SetOwnerVar(OwnerVar()); diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index 8515f6b0ca5eb8ee717b40fc2b80770db1fc5c31..4051395469791c11047011856c61c70fa52f8dca 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -49,6 +49,7 @@ public: if (other->restVar != nullptr) { restVar = other->restVar->Copy(allocator, other->restVar->Declaration()); + ES2PANDA_ASSERT(restVar != nullptr); restVar->SetTsType(other->restVar->TsType()); } } diff --git a/ets2panda/checker/types/ts/interfaceType.cpp b/ets2panda/checker/types/ts/interfaceType.cpp index 724bee9caa8d13e7521140aece70a67359c3dacd..ff846e5d8ee23a37b1567938cd0789559647da71 100644 --- a/ets2panda/checker/types/ts/interfaceType.cpp +++ b/ets2panda/checker/types/ts/interfaceType.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -148,6 +148,7 @@ Type *InterfaceType::Instantiate(ArenaAllocator *allocator, TypeRelation *relati Type *newInterfaceType = allocator->New(allocator, name_, copiedDesc); + ES2PANDA_ASSERT(newInterfaceType != nullptr); for (auto *it : bases_) { newInterfaceType->AsObjectType()->AsInterfaceType()->AddBase( it->Instantiate(allocator, relation, globalTypes)->AsObjectType()); diff --git a/ets2panda/checker/types/ts/objectDescriptor.cpp b/ets2panda/checker/types/ts/objectDescriptor.cpp index a418e6815ba44d59aa5f44e684de97144d9447bd..ccd7d48a60bb566487fd5bd2f727025ea334ead7 100644 --- a/ets2panda/checker/types/ts/objectDescriptor.cpp +++ b/ets2panda/checker/types/ts/objectDescriptor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -34,9 +34,11 @@ varbinder::LocalVariable *ObjectDescriptor::FindProperty(const util::StringView void ObjectDescriptor::Copy(ArenaAllocator *allocator, ObjectDescriptor *copiedDesc, TypeRelation *relation, GlobalTypesHolder *globalTypes) { + ES2PANDA_ASSERT(copiedDesc != nullptr); // copy by hand for (auto *it : properties) { auto *copiedProp = it->Copy(allocator, it->Declaration()); + ES2PANDA_ASSERT(copiedProp != nullptr); copiedProp->SetTsType(it->TsType()->Instantiate(allocator, relation, globalTypes)); copiedDesc->properties.push_back(copiedProp); } diff --git a/ets2panda/checker/types/ts/unionType.cpp b/ets2panda/checker/types/ts/unionType.cpp index 8ba291ba7b360e44ee5e333de3e3ae6fd3557059..fe540ce69eed998cb223d590e9c936cbe6536e8e 100644 --- a/ets2panda/checker/types/ts/unionType.cpp +++ b/ets2panda/checker/types/ts/unionType.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -111,6 +111,7 @@ void UnionType::RemoveDuplicatedTypes(TypeRelation *relation, ArenaVectorHasConstituentFlag(TypeFlag::ANY)) { return globalTypesHolder->GlobalAnyType(); } @@ -184,6 +185,7 @@ Type *UnionType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, Type *newUnionType = allocator->New(allocator, std::move(copiedConstituents)); + ES2PANDA_ASSERT(newUnionType != nullptr); return HandleUnionType(newUnionType->AsUnionType(), globalTypes); } } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index ac28d50150c38bf60b8c9efb23b5d01862540e1a..d6de75572207b5695a3c3cba510f209f23562674 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -121,6 +121,8 @@ bool TypeRelation::IsAssignableTo(Type *source, Type *target) if (result_ == RelationResult::CACHE_MISS) { // NOTE: we support assigning T to Readonly, but do not support assigning Readonly to T // more details in spec + ES2PANDA_ASSERT(source != nullptr); + ES2PANDA_ASSERT(target != nullptr); if (source->HasTypeFlag(TypeFlag::READONLY) && !target->HasTypeFlag(TypeFlag::READONLY)) { result_ = RelationResult::FALSE; } diff --git a/ets2panda/checker/types/typeRelation.h b/ets2panda/checker/types/typeRelation.h index ac87200fbce06c222e7618258bcee72f2aa1a2a8..33c32e789cfada5d83580cd839f5aacf80fa48e5 100644 --- a/ets2panda/checker/types/typeRelation.h +++ b/ets2panda/checker/types/typeRelation.h @@ -312,7 +312,6 @@ public: void RaiseError(const diagnostic::DiagnosticKind &kind, const lexer::SourcePosition &loc) const; void RaiseError(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &list, const lexer::SourcePosition &loc) const; - void LogError(const util::DiagnosticMessageParams &list, const lexer::SourcePosition &loc) const; bool Result(bool res) { diff --git a/ets2panda/compiler/base/lreference.cpp b/ets2panda/compiler/base/lreference.cpp index ca4f4e66523d3ef277fe98842c6260cdce2e7bfb..1ae778a945176e180d5322d98fa8776da71b1814 100644 --- a/ets2panda/compiler/base/lreference.cpp +++ b/ets2panda/compiler/base/lreference.cpp @@ -306,6 +306,7 @@ void ETSLReference::SetValueComputed(const ir::MemberExpression *memberExpr) con if (objectType->IsETSArrayType() || objectType->IsETSResizableArrayType()) { auto vRegtype = etsg_->GetVRegType(baseReg_); + ES2PANDA_ASSERT(vRegtype != nullptr); auto *elementType = vRegtype->IsETSArrayType() ? vRegtype->AsETSArrayType()->ElementType() : vRegtype->AsETSResizableArrayType()->ElementType(); etsg_->StoreArrayElement(Node(), baseReg_, propReg_, elementType); @@ -317,11 +318,12 @@ void ETSLReference::SetValueComputed(const ir::MemberExpression *memberExpr) con void ETSLReference::SetValueGetterSetter(const ir::MemberExpression *memberExpr) const { + ES2PANDA_ASSERT(memberExpr->PropVar() != nullptr); const auto *sig = memberExpr->PropVar()->TsType()->AsETSFunctionType()->FindSetter(); auto argReg = etsg_->AllocReg(); etsg_->StoreAccumulator(Node(), argReg); - + ES2PANDA_ASSERT(sig->Function() != nullptr); if (sig->Function()->IsStatic()) { etsg_->CallExact(Node(), sig->InternalName(), argReg); } else if (memberExpr->Object()->IsSuperExpression()) { @@ -356,6 +358,7 @@ void ETSLReference::SetValue() const return; } + ES2PANDA_ASSERT(memberExpr->PropVar() != nullptr); if (memberExpr->PropVar()->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { SetValueGetterSetter(memberExpr); return; diff --git a/ets2panda/compiler/core/CFG.cpp b/ets2panda/compiler/core/CFG.cpp index cfafe5d7922d24e1ebdbeb0be82e26b6c0d3d52a..d1e62215e0ce57411bba4c82e0486d888ec68346 100644 --- a/ets2panda/compiler/core/CFG.cpp +++ b/ets2panda/compiler/core/CFG.cpp @@ -32,6 +32,7 @@ size_t CFG::BasicBlock::AddNode(ir::AstNode *node) std::pair CFG::BasicBlock::AddSuccessor(BasicBlock *successor) { + ES2PANDA_ASSERT(successor != nullptr); succs_.push_back(successor); successor->preds_.push_back(this); return std::make_pair(succs_.size() - 1, successor->preds_.size() - 1); @@ -208,6 +209,7 @@ CFG::BasicBlock *CFG::Build(ir::ScriptFunction *scriptFunctionNode) } ES2PANDA_ASSERT(scriptFunctionNode->Body()->IsBlockStatement()); auto exitBB = Build(scriptFunctionNode->Body()->AsBlockStatement(), entryBB); + ES2PANDA_ASSERT(exitBB != nullptr); exitBB->SetFlag(BasicBlockFlags::EXIT); return entryBB; } @@ -231,6 +233,7 @@ CFG::BasicBlock *CFG::CreateNewBB(const std::vector &&preds, const std::vector &&labels) { auto bb = allocator_->New(allocator_, basicBlockIdx_++); + ES2PANDA_ASSERT(bb != nullptr); if (inLoop_ > 0) { bb->SetFlag(BasicBlockFlags::LOOP); } @@ -840,6 +843,7 @@ size_t CFG::AddNodeToBB(ir::AstNode *node, BasicBlock *bb) if (bb == nullptr) { bb = CreateNewBB({}); } + ES2PANDA_ASSERT(bb != nullptr); size_t index = bb->AddNode(node); nodeBBMap_[node] = std::make_pair(bb, index); return index; diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 8992e4463266032d54ade146aee52b4d6f28f6a7..75fd7d3de505e7bba5f6d34adae7e5d6b9110aeb 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -174,6 +174,7 @@ static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::E elements.emplace_back(expr->GetArguments()[i]); } auto *arrayExpression = checker->AllocNode(std::move(elements), checker->Allocator()); + ES2PANDA_ASSERT(arrayExpression != nullptr); arrayExpression->SetParent(const_cast(expr)); auto restType = expr->GetSignature()->RestVar()->TsType()->AsETSArrayType(); arrayExpression->SetTsType(restType); @@ -707,8 +708,7 @@ void ETSCompiler::CompileAny(const ir::CallExpression *expr, const ir::Expressio } else { etsg->CallAnyThis(expr, memberExpr->Property()->AsIdentifier(), expr->Arguments(), objReg); } - auto returnType = expr->Signature()->ReturnType(); - etsg->EmitAnyCheckCast(expr, returnType); + etsg->EmitAnyCheckCast(expr, expr->TsType()); } void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &calleeReg, @@ -735,6 +735,7 @@ void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &calle // NOTE: need to refactor: type of member expression object can be obtained via // me->ObjType() or me->Object()->TsType() and they may differ!!!! } else if (me->ObjType() == etsg->Checker()->GlobalETSObjectType() && + (etsg->Checker()->GetApparentType(me->Object()->TsType()) != nullptr) && (etsg->Checker()->GetApparentType(me->Object()->TsType())->IsETSUnionType())) { etsg->CallByName(expr, signature, calleeReg, expr->Arguments()); } else { @@ -939,6 +940,7 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); ES2PANDA_ASSERT(expr->PropVar()->TsType() != nullptr); const checker::Type *const variableType = expr->PropVar()->TsType(); + ES2PANDA_ASSERT(variableType != nullptr); if (variableType->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { if (expr->Object()->IsSuperExpression()) { etsg->CallExact(expr, variableType->AsETSFunctionType()->FindGetter()->InternalName(), objReg); @@ -959,6 +961,7 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const bool ETSCompiler::HandleArrayTypeLengthProperty(const ir::MemberExpression *expr, ETSGen *etsg) const { auto *const objectType = etsg->Checker()->GetApparentType(expr->Object()->TsType()); + ES2PANDA_ASSERT(objectType != nullptr); auto &propName = expr->Property()->AsIdentifier()->Name(); if (objectType->IsETSArrayType() && propName.Is("length")) { auto ottctx = compiler::TargetTypeContext(etsg, objectType); @@ -982,6 +985,7 @@ bool ETSCompiler::HandleStaticProperties(const ir::MemberExpression *expr, ETSGe if (auto const *const varType = variable->TsType(); varType->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { checker::Signature *sig = varType->AsETSFunctionType()->FindGetter(); + ES2PANDA_ASSERT(sig != nullptr); etsg->CallExact(expr, sig->InternalName()); etsg->SetAccumulatorType(expr->TsType()); } else { diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 4e62393a954b62facfe7f9675d6a93d5568f3c26..ff54d72f975078fcf116ca670ad2aae73e73232d 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -86,6 +86,7 @@ void ETSGen::CompileAndCheck(const ir::Expression *expr) return; } + ES2PANDA_ASSERT(accType != nullptr); if (accType->IsETSPrimitiveType() && ((accType->TypeFlags() ^ exprType->TypeFlags()) & ~checker::TypeFlag::CONSTANT) == 0) { return; @@ -216,6 +217,7 @@ checker::Type const *ETSGen::TypeForVar(varbinder::Variable const *var) const no void ETSGen::MoveVreg(const ir::AstNode *const node, const VReg vd, const VReg vs) { const auto *const sourceType = GetVRegType(vs); + ES2PANDA_ASSERT(sourceType != nullptr); if (sourceType->IsETSReferenceType()) { Ra().Emit(node, vd, vs); @@ -247,6 +249,7 @@ void ETSGen::LoadVar(const ir::Identifier *node, varbinder::Variable const *cons break; } case ReferenceKind::FIELD: { + ES2PANDA_ASSERT(GetVRegType(GetThisReg()) != nullptr); const auto fullName = FormClassPropReference(GetVRegType(GetThisReg())->AsETSObjectType(), var->Name()); LoadProperty(node, var->TsType(), GetThisReg(), fullName); break; @@ -298,6 +301,7 @@ void ETSGen::StoreVar(const ir::Identifier *node, const varbinder::ConstScopeFin util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name) { std::stringstream ss; + ES2PANDA_ASSERT(classType != nullptr); ss << classType->AssemblerName().Mutf8() << Signatures::METHOD_SEPARATOR << name; return util::StringView(*ProgElement()->Strings().emplace(ss.str()).first); } @@ -345,6 +349,7 @@ static bool StaticAccessRequiresReferenceSafetyCheck(const ir::AstNode *const no void ETSGen::LoadStaticProperty(const ir::AstNode *const node, const checker::Type *propType, const util::StringView &fullName) { + ES2PANDA_ASSERT(propType != nullptr); if (propType->IsETSReferenceType()) { Sa().Emit(node, fullName); if (StaticAccessRequiresReferenceSafetyCheck(node, propType)) { @@ -362,6 +367,7 @@ void ETSGen::LoadStaticProperty(const ir::AstNode *const node, const checker::Ty void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *propType, const VReg objReg, const util::StringView &name) { + ES2PANDA_ASSERT(Checker()->GetApparentType(GetVRegType(objReg)) != nullptr); auto *objType = Checker()->GetApparentType(GetVRegType(objReg))->AsETSObjectType(); const auto fullName = FormClassPropReference(objType, name); @@ -574,6 +580,7 @@ void ETSGen::EmitReturnVoid(const ir::AstNode *node) void ETSGen::ReturnAcc(const ir::AstNode *node) { const auto *const accType = GetAccumulatorType(); + ES2PANDA_ASSERT(accType != nullptr); if (accType->IsETSReferenceType()) { Sa().Emit(node); @@ -584,16 +591,19 @@ void ETSGen::ReturnAcc(const ir::AstNode *node) } } -static bool IsNullUnsafeObjectType(checker::Type const *type) +bool ETSGen::IsNullUnsafeObjectType(checker::Type const *type) const { - return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType(); + ES2PANDA_ASSERT(type != nullptr); + auto const checker = const_cast(Checker()); + return checker->Relation()->IsSupertypeOf(checker->GetApparentType(type), checker->GlobalETSObjectType()); } // Implemented on top of the runtime type system, do not relax checks, do not introduce new types -void ETSGen::TestIsInstanceConstituent(const ir::AstNode *const node, std::tuple