@@ -187,7 +187,19 @@ impl<A: 'static + Send> ScanBuilder<A> {
187187
188188 /// The [`DType`] returned by the scan, after applying the projection.
189189 pub fn dtype ( & self ) -> VortexResult < DType > {
190- self . projection . return_dtype ( self . layout_reader . dtype ( ) )
190+ // NOTE: `GetItem` may simplify into `GetItemList` for list-of-struct projections.
191+ // To avoid rejecting valid nested projections (like `items.a`) we must simplify before
192+ // validating the return dtype.
193+ //
194+ // Also, `row_idx` support is provided by `RowIdxLayoutReader`, so use the same reader
195+ // enrichment as `prepare`.
196+ let layout_reader = Arc :: new ( RowIdxLayoutReader :: new (
197+ self . row_offset ,
198+ self . layout_reader . clone ( ) ,
199+ self . session . clone ( ) ,
200+ ) ) ;
201+ let projection = self . projection . optimize_recursive ( layout_reader. dtype ( ) ) ?;
202+ projection. return_dtype ( layout_reader. dtype ( ) )
191203 }
192204
193205 /// The session used by the scan.
@@ -220,8 +232,6 @@ impl<A: 'static + Send> ScanBuilder<A> {
220232 }
221233
222234 pub fn prepare ( self ) -> VortexResult < RepeatedScan < A > > {
223- let dtype = self . dtype ( ) ?;
224-
225235 if self . filter . is_some ( ) && self . limit . is_some ( ) {
226236 vortex_bail ! ( "Vortex doesn't support scans with both a filter and a limit" )
227237 }
@@ -241,6 +251,7 @@ impl<A: 'static + Send> ScanBuilder<A> {
241251
242252 // Normalize and simplify the expressions.
243253 let projection = self . projection . optimize_recursive ( layout_reader. dtype ( ) ) ?;
254+ let dtype = projection. return_dtype ( layout_reader. dtype ( ) ) ?;
244255
245256 let filter = self
246257 . filter
0 commit comments