From 7b3d8b91a067a0b5aa048bbd02b9f2254db4d5d8 Mon Sep 17 00:00:00 2001 From: Benjamin Thomas Date: Sat, 15 Aug 2026 14:03:16 -0700 Subject: [PATCH] fix: bare dictionary subscript on action output compiled to Property aggrandizement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit variableValue() only emitted a WFDictionaryValueVariableAggrandizement when the referenced variable's value type was Dict. A variable holding an action's output (e.g. `const d = getDictionary(x)`) has value type Action, so `@v = d['key']` fell through to WFPropertyVariableAggrandizement — which Shortcuts resolves to an empty value at runtime. The same subscript inside string interpolation was already handled correctly by makeAggrandizement(), which resolves Action references via the action definition's outputType. Apply the same resolution in variableValue(): when the reference is an Action, use its definition's outputType before the Dict check. Adds tests/dictionary-action-output.cherri covering bare and inline subscripts on an action-output dictionary (baseline compiled the bare case to 1 Property aggrandizement; now both compile to DictionaryKey). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PmFsHCZ4S5KAiUCu4uZAtH --- shortcutgen.go | 10 ++++++++++ tests/dictionary-action-output.cherri | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/dictionary-action-output.cherri diff --git a/shortcutgen.go b/shortcutgen.go index 10814686..80395166 100644 --- a/shortcutgen.go +++ b/shortcutgen.go @@ -383,6 +383,16 @@ func variableValue(variable varValue) map[string]any { if variable.valueType == Variable && variableReference.valueType != "" { refValueType = variableReference.valueType } + // A reference to an action's output has value type Action, not Dict, so + // resolve what the action actually returns. Without this a key access on + // a dictionary-returning action (e.g. getDictionary()) compiles to a + // property lookup, which Shortcuts resolves to an empty value at + // runtime. makeAggrandizement() already does this for inline references. + if refValueType == Action { + if variableAction, ok := variableReference.value.(action); ok && variableAction.def != nil { + refValueType = variableAction.def.outputType + } + } if refValueType == Dict { aggrandizements = append(aggrandizements, map[string]any{ "Type": "WFDictionaryValueVariableAggrandizement", diff --git a/tests/dictionary-action-output.cherri b/tests/dictionary-action-output.cherri new file mode 100644 index 00000000..0530c232 --- /dev/null +++ b/tests/dictionary-action-output.cherri @@ -0,0 +1,19 @@ +/* +Subscripting a dictionary that is the output of an action (e.g. getDictionary()) +must compile to a dictionary-value aggrandizement (Type: WFDictionaryValueVariableAggrandizement), +the same as subscripting a literal dictionary — not a property aggrandizement, +which resolves to nothing at runtime. +*/ + +#include 'actions/scripting' + +@response = "placeholder" +const responseDict = getDictionary(@response) + +// bare subscript on an action-output dictionary +@summary = responseDict['summary'] + +// subscript inside string interpolation (was already correct) +const inline = "{responseDict['summary']}" + +alert("bare: {summary} inline: {inline}", "Dictionary action output")