From 499230f9d79fc3faaca08a3211a16d0c97754f04 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Sat, 16 Aug 2025 18:22:40 +0300 Subject: [PATCH 1/5] Slightly change algorithm of call expressions resolving --- .../src/analysis/AnalysisVisitor.ts | 61 +----------- .../memo-plugin/src/analysis/PostAnalysis.ts | 97 +++++++++++++++++++ ui2abc/memo-plugin/src/common.ts | 9 +- .../src/diagnostics/DiagnosticVisitor.ts | 10 +- ui2abc/memo-plugin/src/entry.ts | 15 +-- ui2abc/memo-plugin/src/index.ts | 5 +- .../src/transform/FunctionTransformer.ts | 4 +- .../src/transform/MemoTransformer.ts | 4 + 8 files changed, 132 insertions(+), 73 deletions(-) create mode 100644 ui2abc/memo-plugin/src/analysis/PostAnalysis.ts diff --git a/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts b/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts index 24225e97c..95b2876c8 100644 --- a/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts +++ b/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts @@ -15,27 +15,18 @@ import * as arkts from "@koalaui/libarkts" import { - callsiteSupportsArgumentsRewrite, isMemoFreeSubtree, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, - MemoCallsiteKind, MemoFunctionKind, MemoPluginContext, TransformerOptions } from "../common" -import { - getDeclResolveGensym, +import { getMemoFunctionKind, - getMemoParameterKind, - getParams, - isMemo, isMemoAnnotatable, - isMemoizable, maskToKind, MemoAnnotatable, - shouldWrap, } from "../api-utils" -import { functionKindToCallsiteKind } from "./utils" function isSetter(node: arkts.ScriptFunction) { return node.flags & arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER @@ -114,61 +105,17 @@ class AnalysisVisitor extends arkts.AbstractVisitor { } } -export function checkedAnalysis( +export function checkedAnalysisVisitor( userPluginOptions?: TransformerOptions ) { return (program: arkts.Program, options: arkts.CompilationOptions, context: arkts.PluginContext) => { const memoPluginContext = context.parameter(MEMO_PLUGIN_CONTEXT_PARAMETER_NAME) if (!memoPluginContext) { - throw new Error("Memo analysis called without memo table") + throw new Error("Memo analysis visitor called without memo table") } const callExpressions = new Set() new AnalysisVisitor(memoPluginContext, callExpressions).visitor(program.ast) - - // We should extract binding information within analysis - callExpressions.forEach((node: arkts.CallExpression) => { - const callee = node.callee - const decl = getDeclResolveGensym(callee!) - if (!decl || !isMemoizable(decl)) { - return - } - - const params = getParams(decl) - // This is about memo inference for lambdas - node.arguments.forEach((arg, index) => { - if (!params[index] || !arkts.isArrowFunctionExpression(arg)) return - const kind = getMemoParameterKind(params[index]) - if (kind) { - memoPluginContext.ScriptFunctionKinds.set(arg.function!.original, getMemoParameterKind(params[index])) - } - }) - - // There is a difference on receiver meaning on ScriptFunction and CallExpression: - // For ScriptFunction it is related to __memo_parameter_this creation - // For CallExpression it is related to position of inserted __memo_context and __memo_id - // These things generally has nothing in common - - // Proper usage is node.isExtensionAccessorCall instead of this trick with parameter, - // but it doesn't work due to es2panda issue #29010 - const hasReceiver = !!(params[0]?.ident?.isReceiver) - const kind = functionKindToCallsiteKind(isMemo(decl), hasReceiver) - - if (callsiteSupportsArgumentsRewrite(kind)) { - // This is about wrapping in compute - node.arguments.forEach((arg, index) => { - if (!params[index]) return - // Improve: this is not quite correct. - // This code is too dependent on the availability of parameter declaration and its type - // Most of the decisions should be taken basing on the fact that this is a memo call - if (shouldWrap(params[index], index + 1 == params.length, !!userPluginOptions?.trackContentParam, arg)) { - memoPluginContext.ArgumentsToWrap.add(arg.original) - } - }) - } - if (kind != MemoCallsiteKind.NONE) { - memoPluginContext.CallExpressionKinds.set(node.original, kind) - } - }) + memoPluginContext.PerProgramCallExpessions.set(program.absoluteName, callExpressions) } } diff --git a/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts b/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts new file mode 100644 index 000000000..3fc7db19d --- /dev/null +++ b/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022-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 * as arkts from "@koalaui/libarkts" +import { + callsiteSupportsArgumentsRewrite, + MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, + MemoCallsiteKind, + MemoPluginContext, + TransformerOptions +} from "../common" +import { + getDeclResolveGensym, + getMemoParameterKind, + getParams, + isMemo, + isMemoizable, + shouldWrap +} from "../api-utils" +import { + functionKindToCallsiteKind +} from "./utils" + +export function checkedPostAnalysis( + userPluginOptions?: TransformerOptions +) { + return (program: arkts.Program, options: arkts.CompilationOptions, context: arkts.PluginContext) => { + const memoPluginContext = context.parameter(MEMO_PLUGIN_CONTEXT_PARAMETER_NAME) + if (!memoPluginContext) { + throw new Error("Memo post analysis called without memo table") + } + + const programName = program.absoluteName + + // We should extract binding information within analysis + const callExpressions = memoPluginContext.PerProgramCallExpessions.get(programName) + const markedCallExpressions = new Map() + callExpressions?.forEach((node: arkts.CallExpression) => { + const callee = node.callee + const decl = getDeclResolveGensym(callee!) + if (!decl || !isMemoizable(decl)) { + return + } + + const params = getParams(decl) + // This is about memo inference for lambdas + node.arguments.forEach((arg, index) => { + if (!params[index] || !arkts.isArrowFunctionExpression(arg)) return + const kind = getMemoParameterKind(params[index]) + if (kind) { + memoPluginContext.ScriptFunctionKinds.set(arg.function!.original, getMemoParameterKind(params[index])) + } + }) + + // There is a difference on receiver meaning on ScriptFunction and CallExpression: + // For ScriptFunction it is related to __memo_parameter_this creation + // For CallExpression it is related to position of inserted __memo_context and __memo_id + // These things generally has nothing in common + + // Proper usage is node.isExtensionAccessorCall instead of this trick with parameter, + // but it doesn't work due to es2panda issue #29010 + const hasReceiver = !!(params[0]?.ident?.isReceiver) + const kind = functionKindToCallsiteKind(isMemo(decl), hasReceiver) + + if (callsiteSupportsArgumentsRewrite(kind)) { + // This is about wrapping in compute + node.arguments.forEach((arg, index) => { + if (!params[index]) return + // Improve: this is not quite correct. + // This code is too dependent on the availability of parameter declaration and its type + // Most of the decisions should be taken basing on the fact that this is a memo call + if (shouldWrap(params[index], index + 1 == params.length, !!userPluginOptions?.trackContentParam, arg)) { + memoPluginContext.ArgumentsToWrap.add(arg.original) + } + }) + } + if (kind != MemoCallsiteKind.NONE) { + markedCallExpressions.set(node.original, kind) + } + }) + if (markedCallExpressions.size) { + memoPluginContext.PerProgramCallExpressionKinds.set(programName, markedCallExpressions) + } + } +} diff --git a/ui2abc/memo-plugin/src/common.ts b/ui2abc/memo-plugin/src/common.ts index 66ccd65c7..81102429e 100644 --- a/ui2abc/memo-plugin/src/common.ts +++ b/ui2abc/memo-plugin/src/common.ts @@ -140,20 +140,23 @@ export enum DebugNames { export interface MemoPluginContext { ScriptFunctionKinds: Map ETSFunctionTypeKinds: Map - CallExpressionKinds: Map + PerProgramCallExpessions: Map> + PerProgramCallExpressionKinds: Map> ArgumentsToWrap: Set } export class MemoPluginContextImpl implements MemoPluginContext { ScriptFunctionKinds: Map ETSFunctionTypeKinds: Map - CallExpressionKinds: Map + PerProgramCallExpessions: Map> + PerProgramCallExpressionKinds: Map> ArgumentsToWrap: Set constructor() { this.ScriptFunctionKinds = new Map() this.ETSFunctionTypeKinds = new Map() - this.CallExpressionKinds = new Map() + this.PerProgramCallExpessions = new Map() + this.PerProgramCallExpressionKinds = new Map() this.ArgumentsToWrap = new Set() } } diff --git a/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts b/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts index df35f4306..be9161413 100644 --- a/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts +++ b/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts @@ -14,7 +14,7 @@ */ import * as arkts from "@koalaui/libarkts" -import { callsiteIsEntry, isMemoFreeSubtree, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoPluginContext, RuntimeNames, TransformerOptions } from "../common" +import { callsiteIsEntry, isMemoFreeSubtree, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoCallsiteKind, MemoPluginContext, RuntimeNames, TransformerOptions } from "../common" import { getDeclResolveGensym, getName, isMemoizable } from "../api-utils" import { checkReturnTypeAnnotation } from "../inference-helpers" import { ScopedVisitor } from "./ScopedVisitor" @@ -24,6 +24,7 @@ import { toArray } from "./ToArrayVisitor" export class DiagnosticVisitor extends ScopedVisitor { constructor( memoPluginContext: MemoPluginContext, + private callExpressionKinds: Map | undefined, ) { super(memoPluginContext) } @@ -49,7 +50,7 @@ export class DiagnosticVisitor extends ScopedVisitor { private checkOutOfMemoContextMemoCall(node: arkts.AstNode): void { if (!arkts.isCallExpression(node)) return if (this.isCurrentScopeMemo()) return - const kind = this.memoPluginContext.CallExpressionKinds.get(node) + const kind = this.callExpressionKinds?.get(node) if (!kind || callsiteIsEntry(kind)) return // The logic below is done only in exceptional cases // Improve: move it to separate file not to have imported getDeclResolveGensym here @@ -70,7 +71,7 @@ export class DiagnosticVisitor extends ScopedVisitor { const isGensym = (it: arkts.AstNode) => arkts.isIdentifier(it) && it.name.includes(RuntimeNames.GENSYM) if (toArray(node.init.test).some(isGensym) && toArray(node.init.alternate).some((node) => - arkts.isCallExpression(node) && this.memoPluginContext.CallExpressionKinds.has(node) + arkts.isCallExpression(node) && this.callExpressionKinds?.has(node) )) { Reporter.reportDefaultValueMemoCall(node.id.name) } @@ -107,6 +108,7 @@ export function checkedDiagnostics( if (!memoPluginContext) { throw new Error("Memo diagnostic called without memo table") } - new DiagnosticVisitor(memoPluginContext).visitor(program.ast) + const programName = program.absoluteName + new DiagnosticVisitor(memoPluginContext, memoPluginContext.PerProgramCallExpressionKinds.get(programName)).visitor(program.ast) } } diff --git a/ui2abc/memo-plugin/src/entry.ts b/ui2abc/memo-plugin/src/entry.ts index e696d71ac..b7e4bebcb 100644 --- a/ui2abc/memo-plugin/src/entry.ts +++ b/ui2abc/memo-plugin/src/entry.ts @@ -15,8 +15,6 @@ import * as arkts from "@koalaui/libarkts" import * as memo from "./index" -import { MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoPluginContextImpl } from "./common" -import { isKoalaWorkspace } from "./transform/utils" export function init(parsedJson?: Object, checkedJson?: Object) { let pluginContext = new arkts.PluginContextImpl() @@ -43,19 +41,22 @@ export function init(parsedJson?: Object, checkedJson?: Object) { arkts.traceGlobal(() => "Run checked state plugin", true) const prog = arkts.arktsGlobal.compilerContext!.program const state = arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED - const memoPluginContextImpl = new MemoPluginContextImpl() - pluginContext.setParameter(MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, memoPluginContextImpl) + const memoPluginContextImpl = new memo.MemoPluginContextImpl() + pluginContext.setParameter(memo.MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, memoPluginContextImpl) - const analysis = memo.checkedAnalysis(checkedJson) + const analysisVisitor = memo.checkedAnalysisVisitor(checkedJson) + const postAnalysis = memo.checkedPostAnalysis(checkedJson) const diagnostics = memo.checkedDiagnostics(checkedJson) const rewriteTransformer = memo.checkedRewriteTransformer(checkedJson) try { - if (!isKoalaWorkspace()) { + if (!memo.isKoalaWorkspace()) { arkts.traceGlobal(() => "Run Recheck to stabilize changes from UI plugin", true) arkts.recheckContext() } arkts.traceGlobal(() => "Run Analysis", true) - arkts.runTransformer(prog, state, analysis, pluginContext, hooks) + arkts.runTransformer(prog, state, analysisVisitor, pluginContext, hooks) + arkts.traceGlobal(() => "Run Post Analysis", true) + arkts.runTransformer(prog, state, postAnalysis, pluginContext, hooks) arkts.traceGlobal(() => "Run Diagnostics", true) arkts.runTransformer(prog, state, diagnostics, pluginContext, hooks) arkts.traceGlobal(() => "Run Rewrite", true) diff --git a/ui2abc/memo-plugin/src/index.ts b/ui2abc/memo-plugin/src/index.ts index 630e5e199..9baa28ac5 100644 --- a/ui2abc/memo-plugin/src/index.ts +++ b/ui2abc/memo-plugin/src/index.ts @@ -14,6 +14,9 @@ */ export { parsedTransformer } from "./parsed/ParsedTransformer" -export { checkedAnalysis } from "./analysis/AnalysisVisitor" +export { checkedAnalysisVisitor } from "./analysis/AnalysisVisitor" +export { checkedPostAnalysis } from "./analysis/PostAnalysis" export { checkedDiagnostics } from "./diagnostics/DiagnosticVisitor" export { checkedRewriteTransformer } from "./transform/MemoTransformer" +export { MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoPluginContextImpl } from "./common" +export { isKoalaWorkspace } from "./transform/utils" diff --git a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts index 3bdf69178..83927ba36 100644 --- a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts @@ -34,6 +34,7 @@ import { functionHasFullBodyTransformation, functionHasReceiver, isMemoFreeSubtree, + MemoCallsiteKind, MemoPluginContext, RuntimeNames } from "../common" @@ -123,6 +124,7 @@ function updateFunctionBody( export class FunctionTransformer extends arkts.AbstractVisitor { constructor( private memoPluginContext: MemoPluginContext, + private callExpressionKinds: Map | undefined, private positionalIdTracker: PositionalIdTracker, private bodiesTransformer: BodiesTransformer, private addLogging: boolean, @@ -198,7 +200,7 @@ export class FunctionTransformer extends arkts.AbstractVisitor { } transformCallExpression(node: arkts.CallExpression): arkts.CallExpression { - const kind = this.memoPluginContext.CallExpressionKinds.get(node.original) + const kind = this.callExpressionKinds?.get(node.original) if (!callsiteSupportsArgumentsRewrite(kind)) { return node } diff --git a/ui2abc/memo-plugin/src/transform/MemoTransformer.ts b/ui2abc/memo-plugin/src/transform/MemoTransformer.ts index 0a0700184..7694a28f2 100644 --- a/ui2abc/memo-plugin/src/transform/MemoTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/MemoTransformer.ts @@ -31,10 +31,14 @@ export function checkedRewriteTransformer( const positionalIdTracker = new PositionalIdTracker(program.relativeFilePath, userPluginOptions?.stableForTests) const bodiesTransformer = new BodiesTransformer(positionalIdTracker) + const programName = program.absoluteName + const callExpressions = memoPluginContext.PerProgramCallExpressionKinds.get(programName) + const node = program.ast as arkts.ETSModule const functionTransformer = new FunctionTransformer( memoPluginContext, + callExpressions, positionalIdTracker, bodiesTransformer, userPluginOptions?.addLogging ?? false, -- Gitee From b9fa3df0e4e5db18e017770edb8ff937ae40ede1 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Sat, 16 Aug 2025 19:28:10 +0300 Subject: [PATCH 2/5] Markup callsites in another way --- .../memo-plugin/src/analysis/PostAnalysis.ts | 27 ++++++++++--------- ui2abc/memo-plugin/src/common.ts | 11 ++++---- .../src/diagnostics/DiagnosticVisitor.ts | 8 +++--- .../src/transform/FunctionTransformer.ts | 14 ++++++---- .../src/transform/MemoTransformer.ts | 2 +- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts b/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts index 3fc7db19d..5d29e3c63 100644 --- a/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts +++ b/ui2abc/memo-plugin/src/analysis/PostAnalysis.ts @@ -16,6 +16,7 @@ import * as arkts from "@koalaui/libarkts" import { callsiteSupportsArgumentsRewrite, + MarkedUpCallExpressionDescription, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoCallsiteKind, MemoPluginContext, @@ -46,7 +47,7 @@ export function checkedPostAnalysis( // We should extract binding information within analysis const callExpressions = memoPluginContext.PerProgramCallExpessions.get(programName) - const markedCallExpressions = new Map() + const markedUpCallExpressions = new Map() callExpressions?.forEach((node: arkts.CallExpression) => { const callee = node.callee const decl = getDeclResolveGensym(callee!) @@ -74,24 +75,24 @@ export function checkedPostAnalysis( const hasReceiver = !!(params[0]?.ident?.isReceiver) const kind = functionKindToCallsiteKind(isMemo(decl), hasReceiver) + const argumentsToWrap: number[] = [] if (callsiteSupportsArgumentsRewrite(kind)) { // This is about wrapping in compute - node.arguments.forEach((arg, index) => { - if (!params[index]) return - // Improve: this is not quite correct. - // This code is too dependent on the availability of parameter declaration and its type - // Most of the decisions should be taken basing on the fact that this is a memo call - if (shouldWrap(params[index], index + 1 == params.length, !!userPluginOptions?.trackContentParam, arg)) { - memoPluginContext.ArgumentsToWrap.add(arg.original) - } - }) + argumentsToWrap.push(...node.arguments.map((arg, index) => { + if (!params[index]) return 0 + // Improve: this is not quite correct. + // This code is too dependent on the availability of parameter declaration and its type + // Most of the decisions should be taken basing on the fact that this is a memo call + return +shouldWrap(params[index], index + 1 == params.length, !!userPluginOptions?.trackContentParam, arg) + }) + ) } if (kind != MemoCallsiteKind.NONE) { - markedCallExpressions.set(node.original, kind) + markedUpCallExpressions.set(node.original, [kind, argumentsToWrap]) } }) - if (markedCallExpressions.size) { - memoPluginContext.PerProgramCallExpressionKinds.set(programName, markedCallExpressions) + if (markedUpCallExpressions.size) { + memoPluginContext.PerProgramMarkedUpCallExpressionKinds.set(programName, markedUpCallExpressions) } } } diff --git a/ui2abc/memo-plugin/src/common.ts b/ui2abc/memo-plugin/src/common.ts index 81102429e..78a2525ba 100644 --- a/ui2abc/memo-plugin/src/common.ts +++ b/ui2abc/memo-plugin/src/common.ts @@ -137,27 +137,26 @@ export enum DebugNames { LOG = "log", } +export type MarkedUpCallExpressionDescription = [MemoCallsiteKind, number[]] + export interface MemoPluginContext { ScriptFunctionKinds: Map ETSFunctionTypeKinds: Map PerProgramCallExpessions: Map> - PerProgramCallExpressionKinds: Map> - ArgumentsToWrap: Set + PerProgramMarkedUpCallExpressionKinds: Map> } export class MemoPluginContextImpl implements MemoPluginContext { ScriptFunctionKinds: Map ETSFunctionTypeKinds: Map PerProgramCallExpessions: Map> - PerProgramCallExpressionKinds: Map> - ArgumentsToWrap: Set + PerProgramMarkedUpCallExpressionKinds: Map> constructor() { this.ScriptFunctionKinds = new Map() this.ETSFunctionTypeKinds = new Map() this.PerProgramCallExpessions = new Map() - this.PerProgramCallExpressionKinds = new Map() - this.ArgumentsToWrap = new Set() + this.PerProgramMarkedUpCallExpressionKinds = new Map() } } diff --git a/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts b/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts index be9161413..93ef3857e 100644 --- a/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts +++ b/ui2abc/memo-plugin/src/diagnostics/DiagnosticVisitor.ts @@ -14,7 +14,7 @@ */ import * as arkts from "@koalaui/libarkts" -import { callsiteIsEntry, isMemoFreeSubtree, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoCallsiteKind, MemoPluginContext, RuntimeNames, TransformerOptions } from "../common" +import { callsiteIsEntry, isMemoFreeSubtree, MarkedUpCallExpressionDescription, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoPluginContext, RuntimeNames, TransformerOptions } from "../common" import { getDeclResolveGensym, getName, isMemoizable } from "../api-utils" import { checkReturnTypeAnnotation } from "../inference-helpers" import { ScopedVisitor } from "./ScopedVisitor" @@ -24,7 +24,7 @@ import { toArray } from "./ToArrayVisitor" export class DiagnosticVisitor extends ScopedVisitor { constructor( memoPluginContext: MemoPluginContext, - private callExpressionKinds: Map | undefined, + private callExpressionKinds: Map | undefined, ) { super(memoPluginContext) } @@ -50,7 +50,7 @@ export class DiagnosticVisitor extends ScopedVisitor { private checkOutOfMemoContextMemoCall(node: arkts.AstNode): void { if (!arkts.isCallExpression(node)) return if (this.isCurrentScopeMemo()) return - const kind = this.callExpressionKinds?.get(node) + const kind = this.callExpressionKinds?.get(node)?.[0] if (!kind || callsiteIsEntry(kind)) return // The logic below is done only in exceptional cases // Improve: move it to separate file not to have imported getDeclResolveGensym here @@ -109,6 +109,6 @@ export function checkedDiagnostics( throw new Error("Memo diagnostic called without memo table") } const programName = program.absoluteName - new DiagnosticVisitor(memoPluginContext, memoPluginContext.PerProgramCallExpressionKinds.get(programName)).visitor(program.ast) + new DiagnosticVisitor(memoPluginContext, memoPluginContext.PerProgramMarkedUpCallExpressionKinds.get(programName)).visitor(program.ast) } } diff --git a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts index 83927ba36..8639747e1 100644 --- a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts @@ -34,7 +34,7 @@ import { functionHasFullBodyTransformation, functionHasReceiver, isMemoFreeSubtree, - MemoCallsiteKind, + MarkedUpCallExpressionDescription, MemoPluginContext, RuntimeNames } from "../common" @@ -124,7 +124,7 @@ function updateFunctionBody( export class FunctionTransformer extends arkts.AbstractVisitor { constructor( private memoPluginContext: MemoPluginContext, - private callExpressionKinds: Map | undefined, + private callExpressionKinds: Map | undefined, private positionalIdTracker: PositionalIdTracker, private bodiesTransformer: BodiesTransformer, private addLogging: boolean, @@ -200,13 +200,17 @@ export class FunctionTransformer extends arkts.AbstractVisitor { } transformCallExpression(node: arkts.CallExpression): arkts.CallExpression { - const kind = this.callExpressionKinds?.get(node.original) + const callsiteDecscription = this.callExpressionKinds?.get(node.original) + if (!callsiteDecscription) { + return node + } + const [kind, argumentsToWrap] = callsiteDecscription if (!callsiteSupportsArgumentsRewrite(kind)) { return node } - const updatedArguments = node.arguments.map((it) => { - if (this.memoPluginContext.ArgumentsToWrap.has(it.original)) { + const updatedArguments = node.arguments.map((it, index) => { + if (argumentsToWrap[index]) { return factory.createComputeExpression(this.positionalIdTracker.id(), it) } return it diff --git a/ui2abc/memo-plugin/src/transform/MemoTransformer.ts b/ui2abc/memo-plugin/src/transform/MemoTransformer.ts index 7694a28f2..10661b9c7 100644 --- a/ui2abc/memo-plugin/src/transform/MemoTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/MemoTransformer.ts @@ -32,7 +32,7 @@ export function checkedRewriteTransformer( const bodiesTransformer = new BodiesTransformer(positionalIdTracker) const programName = program.absoluteName - const callExpressions = memoPluginContext.PerProgramCallExpressionKinds.get(programName) + const callExpressions = memoPluginContext.PerProgramMarkedUpCallExpressionKinds.get(programName) const node = program.ast as arkts.ETSModule -- Gitee From 39993e8a9b14d9ef5aa9e66344b91971417e9797 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Sat, 16 Aug 2025 20:42:19 +0300 Subject: [PATCH 3/5] remove that thing about static --- ui2abc/memo-plugin/src/transform/FunctionTransformer.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts index 8639747e1..cc4431eca 100644 --- a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts @@ -41,8 +41,8 @@ import { import { rewriteSignature } from "./SignatureTransformer" import { BodiesTransformer, fullBodiesTransfomerOptions, ParamInfo, partBodiesTransfomerOptions } from "./BodiesTransformer" -function needThisRewrite(hasReceiver: boolean, isStatic: boolean, stableThis: boolean) { - return hasReceiver && !isStatic && !stableThis +function needThisRewrite(hasReceiver: boolean, stableThis: boolean) { + return hasReceiver && !stableThis } function mayAddLastReturn(node: arkts.BlockStatement): boolean { @@ -174,7 +174,6 @@ export class FunctionTransformer extends arkts.AbstractVisitor { return rewriteSignature(scriptFunction, kind) } const hasReceiver = functionHasReceiver(kind) - const isStatic = (scriptFunction.modifierFlags & arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC) != 0 const isStableThis = this.stable > 0 if (mayAddLastReturn(body)) { body.addStatement(arkts.factory.createReturnStatement(undefined)) @@ -183,7 +182,7 @@ export class FunctionTransformer extends arkts.AbstractVisitor { const parameterIdentifiers = getMemoParameterIdentifiers(parameters, this.trackContentParam) const gensymParamsCount = fixGensymParams(parameterIdentifiers, body) const afterBodiesTransformer = this.bodiesTransformer - .withThis(needThisRewrite(hasReceiver, isStatic, isStableThis)) + .withThis(needThisRewrite(hasReceiver, isStableThis)) .withParameters(parameterIdentifiers) .visitor(body, fullBodiesTransfomerOptions) updateFunctionBody( @@ -191,7 +190,7 @@ export class FunctionTransformer extends arkts.AbstractVisitor { parameterIdentifiers, gensymParamsCount, getReturnTypeAnnotation(scriptFunction), - needThisRewrite(hasReceiver, isStatic, isStableThis) && !parametersBlockHasReceiver(parameters), + needThisRewrite(hasReceiver, isStableThis) && !parametersBlockHasReceiver(parameters), isStableThis, this.positionalIdTracker.id(), this.addLogging, -- Gitee From 9124c124279c846f5bba5c59a76de76f6e2d5b17 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Sat, 16 Aug 2025 21:13:23 +0300 Subject: [PATCH 4/5] move logic about stable to analysis --- .../src/analysis/AnalysisVisitor.ts | 11 ++++- .../src/transform/FunctionTransformer.ts | 41 ++++--------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts b/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts index 95b2876c8..d66fbbb5d 100644 --- a/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts +++ b/ui2abc/memo-plugin/src/analysis/AnalysisVisitor.ts @@ -23,6 +23,7 @@ import { } from "../common" import { getMemoFunctionKind, + hasMemoStableAnnotation, isMemoAnnotatable, maskToKind, MemoAnnotatable, @@ -46,12 +47,14 @@ function pushMemoFunctionKind(node: MemoAnnotatable, kind?: MemoFunctionKind) { function updateOptions(options: AnalysisVisitorOptions | undefined, node: MemoAnnotatable): AnalysisVisitorOptions | undefined { return { applyMemo: pushMemoFunctionKind(node, options?.applyMemo), + stableContext: options?.stableContext, receiverContext: false, } } class AnalysisVisitorOptions { applyMemo?: MemoFunctionKind + stableContext?: boolean receiverContext?: boolean } @@ -74,7 +77,7 @@ class AnalysisVisitor extends arkts.AbstractVisitor { } const kind = pushMemoFunctionKind(node, options?.applyMemo) if (kind) { - this.memoPluginContext.ScriptFunctionKinds.set(node.original, kind << ((node.hasReceiver || options?.receiverContext) ? 1 : 0)) + this.memoPluginContext.ScriptFunctionKinds.set(node.original, kind << (((node.hasReceiver || options?.receiverContext) && !options?.stableContext) ? 1 : 0)) } return this.visitEachChild(node) } @@ -98,7 +101,11 @@ class AnalysisVisitor extends arkts.AbstractVisitor { } if (arkts.isMethodDefinition(node)) { - return this.visitEachChild(node, { receiverContext: !node.isStatic }) + return this.visitEachChild(node, { stableContext: options?.stableContext, receiverContext: !node.isStatic }) + } + + if (arkts.isClassDefinition(node)) { + return this.visitEachChild(node, { stableContext: hasMemoStableAnnotation(node) }) } return this.visitEachChild(node, options) diff --git a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts index cc4431eca..214b01d05 100644 --- a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts @@ -41,10 +41,6 @@ import { import { rewriteSignature } from "./SignatureTransformer" import { BodiesTransformer, fullBodiesTransfomerOptions, ParamInfo, partBodiesTransfomerOptions } from "./BodiesTransformer" -function needThisRewrite(hasReceiver: boolean, stableThis: boolean) { - return hasReceiver && !stableThis -} - function mayAddLastReturn(node: arkts.BlockStatement): boolean { return node.statements.length == 0 || ( !arkts.isReturnStatement(node.statements[node.statements.length - 1]) && @@ -90,12 +86,12 @@ function updateFunctionBody( parameterIdentifiers: ParamInfo[], gensymParamsCount: number, returnTypeAnnotation: arkts.TypeNode | undefined, - shouldCreateMemoThisParam: boolean, - stableThis: boolean, + parametersContainsReceiver: boolean, + hasReceiver: boolean, hash: arkts.Expression, addLogging: boolean, ): arkts.BlockStatement { - const parameterNames = [...(shouldCreateMemoThisParam ? [RuntimeNames.THIS.valueOf()] : []), ...parameterIdentifiers.map(it => it.ident.name)] + const parameterNames = [...(hasReceiver && !parametersContainsReceiver ? [RuntimeNames.THIS.valueOf()] : []), ...parameterIdentifiers.map(it => it.ident.name)] const scopeDeclaration = factory.createScopeDeclaration( arkts.isTSThisType(returnTypeAnnotation) ? undefined : returnTypeAnnotation, hash, parameterNames.length @@ -103,7 +99,7 @@ function updateFunctionBody( const memoParametersDeclaration = parameterNames.length ? factory.createMemoParameterDeclaration(parameterNames) : undefined const syntheticReturnStatement = factory.createSyntheticReturnStatement(returnTypeAnnotation) const unchangedCheck = [factory.createIfStatementWithSyntheticReturnStatement(syntheticReturnStatement)] - const thisParamSubscription = (arkts.isTSThisType(returnTypeAnnotation) && !stableThis) + const thisParamSubscription = (arkts.isTSThisType(returnTypeAnnotation) && hasReceiver) ? [arkts.factory.createExpressionStatement(factory.createMemoParameterAccess("=t"))] : [] node.setStatements( @@ -133,26 +129,6 @@ export class FunctionTransformer extends arkts.AbstractVisitor { super() } - private stable: number = 0 - - enter(node: arkts.AstNode) { - if (arkts.isClassDefinition(node)) { - if (hasMemoStableAnnotation(node)) { - this.stable++ - } - } - return this - } - - exit(node: arkts.AstNode) { - if (arkts.isClassDefinition(node)) { - if (hasMemoStableAnnotation(node)) { - this.stable-- - } - } - return this - } - transformScriptFunction( scriptFunction: arkts.ScriptFunction, ): arkts.ScriptFunction { @@ -174,7 +150,6 @@ export class FunctionTransformer extends arkts.AbstractVisitor { return rewriteSignature(scriptFunction, kind) } const hasReceiver = functionHasReceiver(kind) - const isStableThis = this.stable > 0 if (mayAddLastReturn(body)) { body.addStatement(arkts.factory.createReturnStatement(undefined)) } @@ -182,7 +157,7 @@ export class FunctionTransformer extends arkts.AbstractVisitor { const parameterIdentifiers = getMemoParameterIdentifiers(parameters, this.trackContentParam) const gensymParamsCount = fixGensymParams(parameterIdentifiers, body) const afterBodiesTransformer = this.bodiesTransformer - .withThis(needThisRewrite(hasReceiver, isStableThis)) + .withThis(hasReceiver) .withParameters(parameterIdentifiers) .visitor(body, fullBodiesTransfomerOptions) updateFunctionBody( @@ -190,8 +165,8 @@ export class FunctionTransformer extends arkts.AbstractVisitor { parameterIdentifiers, gensymParamsCount, getReturnTypeAnnotation(scriptFunction), - needThisRewrite(hasReceiver, isStableThis) && !parametersBlockHasReceiver(parameters), - isStableThis, + !!parametersBlockHasReceiver(parameters), + hasReceiver, this.positionalIdTracker.id(), this.addLogging, ) @@ -240,9 +215,7 @@ export class FunctionTransformer extends arkts.AbstractVisitor { return beforeChildren } - this.enter(beforeChildren) const node = this.visitEachChild(beforeChildren) - this.exit(beforeChildren) if (arkts.isScriptFunction(node)) { return this.transformScriptFunction(node) } -- Gitee From 927290332a08f842c3c597069bcf9f156db76320 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Sat, 16 Aug 2025 21:22:17 +0300 Subject: [PATCH 5/5] more joined logic --- ui2abc/memo-plugin/src/transform/FunctionTransformer.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts index 214b01d05..552613476 100644 --- a/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts +++ b/ui2abc/memo-plugin/src/transform/FunctionTransformer.ts @@ -18,11 +18,9 @@ import { factory } from "../MemoFactory" import { PositionalIdTracker, moveToFront, - parametersBlockHasReceiver, } from "./utils" import { castParameters, - hasMemoStableAnnotation, isTrackableParam, } from "../api-utils" import { @@ -86,12 +84,11 @@ function updateFunctionBody( parameterIdentifiers: ParamInfo[], gensymParamsCount: number, returnTypeAnnotation: arkts.TypeNode | undefined, - parametersContainsReceiver: boolean, hasReceiver: boolean, hash: arkts.Expression, addLogging: boolean, ): arkts.BlockStatement { - const parameterNames = [...(hasReceiver && !parametersContainsReceiver ? [RuntimeNames.THIS.valueOf()] : []), ...parameterIdentifiers.map(it => it.ident.name)] + const parameterNames = [...(hasReceiver && !parameterIdentifiers[0]?.ident?.isReceiver ? [RuntimeNames.THIS.valueOf()] : []), ...parameterIdentifiers.map(it => it.ident.name)] const scopeDeclaration = factory.createScopeDeclaration( arkts.isTSThisType(returnTypeAnnotation) ? undefined : returnTypeAnnotation, hash, parameterNames.length @@ -165,7 +162,6 @@ export class FunctionTransformer extends arkts.AbstractVisitor { parameterIdentifiers, gensymParamsCount, getReturnTypeAnnotation(scriptFunction), - !!parametersBlockHasReceiver(parameters), hasReceiver, this.positionalIdTracker.id(), this.addLogging, -- Gitee