mrhhsg commented on code in PR #67713:
URL: https://github.com/apache/doris/pull/67713#discussion_r3966692614


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java:
##########
@@ -497,6 +502,36 @@ protected void couldNotFoundColumn(UnboundSlot 
unboundSlot, String tableName) {
         return lambdaAnalyzer.analyze(lambdaFunction, context);
     }
 
+    /**
+     * Build the scope of a lambda body. The lambda arguments shadow the 
same-named slots that are visible
+     * to the enclosing expression, and the enclosing scope becomes the outer 
scope. Slot binding only looks
+     * one level up, so when this analyzer itself analyzes a lambda body 
(nested high-order functions), the
+     * scope of this analyzer only holds the enclosing lambda arguments: merge 
them into the new scope and keep
+     * the plan scope as the outer scope, so that the columns captured by the 
nested lambda body stay bindable.
+     */
+    private Scope newLambdaScope(List<Slot> lambdaArgumentSlots) {
+        Scope enclosingScope = getScope();
+        if (!isLambdaBodyAnalyzer()) {
+            return new Scope(Optional.of(enclosingScope), lambdaArgumentSlots);
+        }
+        ImmutableList.Builder<Slot> slots = 
ImmutableList.builderWithExpectedSize(
+                lambdaArgumentSlots.size() + enclosingScope.getSlots().size());
+        slots.addAll(lambdaArgumentSlots);
+        for (Slot enclosingArgument : enclosingScope.getSlots()) {
+            boolean shadowed = lambdaArgumentSlots.stream()
+                    .anyMatch(argument -> 
argument.getName().equalsIgnoreCase(enclosingArgument.getName()));
+            if (!shadowed) {
+                slots.add(enclosingArgument);
+            }
+        }
+        return new Scope(enclosingScope.getOuterScope(), slots.build());

Review Comment:
   Thanks for tracing this. The observation is accurate, but the comparator 
limitation is independent of nesting and is not introduced by this PR, so I 
would keep it out of scope here.
   
   `array_sort` comparators cannot capture anything today, even at a single 
level. On the PR's table, this already fails on master before this change:
   
   ```sql
   SELECT array_sort((x, y) -> if(flag, if(x < y, -1, if(x > y, 1, 0)), 0), 
arr2) FROM t_arr;
   -- [NOT_IMPLEMENTED_ERROR]array_sort comparator only supports its own lambda 
arguments, but found captured slot ref 'flag'
   ```
   
   The same holds for a nested comparator capturing the enclosing lambda 
argument (`array_map(a -> array_sort((x, y) -> if(a = 'A', ...), arr2), 
arr1)`), which was already bindable in FE before this PR and is rejected by BE 
with `captured column ref 'a'`. `_set_comparator_argument_gap` documents this 
as a deliberate restriction of the comparator-local frame 
(`parent_bindings_visible = false`).
   
   So after this PR the nested comparator case fails with exactly the same 
error as the single-level case, instead of the misleading FE `Unknown lambda 
slot` error. No query that used to run is affected.
   
   I would rather not special-case `ARRAY_COMPARATOR` in `ExpressionAnalyzer`: 
it would move the error site for single-level `array_sort` as well and would 
replace the uniform rule "a nested lambda body sees the same names as a 
single-level one" with a per-function exception, while supporting comparator 
captures is a separate BE feature. I will add a regression case that pins the 
nested `array_sort` comparator capture to the current BE error, plus a nested 
`array_sort` without capture that executes, so the chosen behavior is covered 
end to end.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to