Skip to content

Commit 5bb6e5e

Browse files
kyleconroyclaude
andcommitted
Recursively check nested arrays for non-literal expressions in EXPLAIN AST
When array literals contain nested arrays with non-literal expressions (like identifiers or binary operations), they should be output as nested Function array calls, not as a single Literal node. This adds a recursive check containsNonLiteralExpressionsRecursive that properly detects expressions like [[[number]],[[number + 1],...]] at any nesting depth. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent aed95c0 commit 5bb6e5e

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

internal/explain/expressions.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ func explainLiteral(sb *strings.Builder, n *ast.Literal, indent string, depth in
222222
if hasNestedArrays && containsTuplesRecursive(exprs) {
223223
shouldUseFunctionArray = true
224224
}
225+
// Also check for non-literal expressions at any depth within nested arrays
226+
if hasNestedArrays && containsNonLiteralExpressionsRecursive(exprs) {
227+
shouldUseFunctionArray = true
228+
}
225229

226230
if shouldUseFunctionArray {
227231
// Render as Function array instead of Literal
@@ -410,6 +414,36 @@ func containsTuplesRecursive(exprs []ast.Expression) bool {
410414
return false
411415
}
412416

417+
// containsNonLiteralExpressionsRecursive checks if any nested array contains non-literal expressions at any depth
418+
func containsNonLiteralExpressionsRecursive(exprs []ast.Expression) bool {
419+
for _, e := range exprs {
420+
if lit, ok := e.(*ast.Literal); ok {
421+
// Parenthesized literals need Function array format
422+
if lit.Parenthesized {
423+
return true
424+
}
425+
if lit.Type == ast.LiteralArray {
426+
if innerExprs, ok := lit.Value.([]ast.Expression); ok {
427+
// Recursively check nested arrays
428+
if containsNonLiteralExpressionsRecursive(innerExprs) {
429+
return true
430+
}
431+
}
432+
}
433+
continue
434+
}
435+
// Unary minus of a literal (negative number) is also acceptable
436+
if unary, ok := e.(*ast.UnaryExpr); ok && unary.Op == "-" {
437+
if _, ok := unary.Operand.(*ast.Literal); ok {
438+
continue
439+
}
440+
}
441+
// Any other expression type means we have non-literal expressions
442+
return true
443+
}
444+
return false
445+
}
446+
413447
func explainBinaryExpr(sb *strings.Builder, n *ast.BinaryExpr, indent string, depth int) {
414448
// Convert operator to function name
415449
fnName := OperatorToFunction(n.Op)
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt31": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt3": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"explain_todo":{"stmt11":true}}
1+
{}

0 commit comments

Comments
 (0)