@@ -76,6 +76,14 @@ def rewrite_slice(node: nodes.BigFrameNode):
76
76
return node
77
77
78
78
slice_def = (node .start , node .stop , node .step )
79
+
80
+ # Handle empty slice cases explicitly before any row count dependent logic
81
+ # This ensures empty slices always return empty results regardless of statistics
82
+ if _is_empty_slice (node .start , node .stop , node .step ):
83
+ # Create a filter that will always return empty results
84
+ # Use start=0, stop=0, step=1 to ensure empty result
85
+ return slice_as_filter (node .child , 0 , 0 , 1 )
86
+
79
87
# no-op (eg. df[::1])
80
88
if slices .is_noop (slice_def , node .child .row_count ):
81
89
return node .child
@@ -89,6 +97,26 @@ def rewrite_slice(node: nodes.BigFrameNode):
89
97
return slice_as_filter (node .child , * slice_def )
90
98
91
99
100
+ def _is_empty_slice (start , stop , step ):
101
+ """Check if a slice will always return empty results."""
102
+ if start is None or stop is None :
103
+ return False
104
+
105
+ # Normalize step
106
+ if step is None :
107
+ step = 1
108
+
109
+ # For positive step, empty if start >= stop
110
+ # For negative step, empty if start <= stop
111
+ if step > 0 :
112
+ return start >= stop
113
+ elif step < 0 :
114
+ return start <= stop
115
+ else :
116
+ # step == 0 is invalid, but handle gracefully
117
+ return True
118
+
119
+
92
120
def slice_as_filter (
93
121
node : nodes .BigFrameNode , start : Optional [int ], stop : Optional [int ], step : int
94
122
) -> nodes .BigFrameNode :
0 commit comments