@@ -151,6 +151,26 @@ fn lower_element_layout(
151151 layout_type
152152}
153153
154+ // to detect mixing auto and non-literal expressions in row/col values
155+ #[ derive( Debug , PartialEq , Eq ) ]
156+ enum RowColExpressionType {
157+ Auto , // not specified
158+ Literal ,
159+ RuntimeExpression ,
160+ }
161+ impl RowColExpressionType {
162+ fn from_option_expr (
163+ expr : & Option < Expression > ,
164+ is_number_literal : bool ,
165+ ) -> RowColExpressionType {
166+ match expr {
167+ None => RowColExpressionType :: Auto ,
168+ Some ( _) if is_number_literal => RowColExpressionType :: Literal ,
169+ Some ( _) => RowColExpressionType :: RuntimeExpression ,
170+ }
171+ }
172+ }
173+
154174fn lower_grid_layout (
155175 component : & Rc < Component > ,
156176 grid_layout_element : & ElementRc ,
@@ -192,6 +212,7 @@ fn lower_grid_layout(
192212 let layout_children = std:: mem:: take ( & mut grid_layout_element. borrow_mut ( ) . children ) ;
193213 let mut collected_children = Vec :: new ( ) ;
194214 let mut new_row = false ; // true until the first child of a Row, or the first item after an empty Row
215+ let mut numbering_type: Option < RowColExpressionType > = None ;
195216 for layout_child in layout_children {
196217 let is_row = if let ElementType :: Builtin ( be) = & layout_child. borrow ( ) . base_type {
197218 be. name == "Row"
@@ -214,6 +235,7 @@ fn lower_grid_layout(
214235 & layout_cache_prop_h,
215236 & layout_cache_prop_v,
216237 & layout_organized_data_prop,
238+ & mut numbering_type,
217239 diag,
218240 ) ;
219241 collected_children. push ( x) ;
@@ -234,6 +256,7 @@ fn lower_grid_layout(
234256 & layout_cache_prop_h,
235257 & layout_cache_prop_v,
236258 & layout_organized_data_prop,
259+ & mut numbering_type,
237260 diag,
238261 ) ;
239262 collected_children. push ( layout_child) ;
@@ -314,20 +337,24 @@ impl GridLayout {
314337 layout_cache_prop_h : & NamedReference ,
315338 layout_cache_prop_v : & NamedReference ,
316339 organized_data_prop : & NamedReference ,
340+ numbering_type : & mut Option < RowColExpressionType > ,
317341 diag : & mut BuildDiagnostics ,
318342 ) {
319343 let mut get_expr = |name : & str | {
320- item_element. borrow_mut ( ) . bindings . get ( name) . map ( |e| {
344+ let mut is_number_literal = false ;
345+ let expr = item_element. borrow_mut ( ) . bindings . get ( name) . map ( |e| {
321346 let expr = & e. borrow ( ) . expression ;
322- check_number_literal_is_positive_integer ( expr, name, & * e. borrow ( ) , diag) ;
347+ is_number_literal =
348+ check_number_literal_is_positive_integer ( expr, name, & * e. borrow ( ) , diag) ;
323349 expr. clone ( )
324- } )
350+ } ) ;
351+ ( expr, is_number_literal)
325352 } ;
326353
327- let row_expr = get_expr ( "row" ) ;
328- let col_expr = get_expr ( "col" ) ;
329- let rowspan_expr = get_expr ( "rowspan" ) ;
330- let colspan_expr = get_expr ( "colspan" ) ;
354+ let ( row_expr, row_is_number_literal ) = get_expr ( "row" ) ;
355+ let ( col_expr, col_is_number_literal ) = get_expr ( "col" ) ;
356+ let ( rowspan_expr, _ ) = get_expr ( "rowspan" ) ;
357+ let ( colspan_expr, _ ) = get_expr ( "colspan" ) ;
331358
332359 self . add_element_with_coord_as_expr (
333360 item_element,
@@ -339,6 +366,32 @@ impl GridLayout {
339366 organized_data_prop,
340367 diag,
341368 ) ;
369+
370+ let mut check_numbering_consistency = |expr_type : RowColExpressionType , prop_name : & str | {
371+ if !matches ! ( expr_type, RowColExpressionType :: Literal ) {
372+ if let Some ( current_numbering_type) = numbering_type {
373+ if * current_numbering_type != expr_type {
374+ item_element. borrow_mut ( ) . bindings . get ( prop_name) . map ( |binding| {
375+ diag. push_error (
376+ format ! ( "Cannot mix auto-numbering and runtime expressions for the '{prop_name}' property" ) ,
377+ & * binding. borrow ( ) ,
378+ ) ;
379+ } ) ;
380+ }
381+ } else {
382+ // Store the first auto or runtime expression case we see
383+ * numbering_type = Some ( expr_type) ;
384+ }
385+ }
386+ } ;
387+
388+ let row_expr_type =
389+ RowColExpressionType :: from_option_expr ( & row_expr, row_is_number_literal) ;
390+ check_numbering_consistency ( row_expr_type, "row" ) ;
391+
392+ let col_expr_type =
393+ RowColExpressionType :: from_option_expr ( & col_expr, col_is_number_literal) ;
394+ check_numbering_consistency ( col_expr_type, "col" ) ;
342395 }
343396
344397 fn add_element_with_coord (
@@ -910,27 +963,30 @@ fn set_prop_from_cache(
910963
911964// If it's a number literal, it must be a positive integer
912965// But also allow any other kind of expression
966+ // Returns true for literals, false for other kinds of expressions
913967fn check_number_literal_is_positive_integer (
914968 expression : & Expression ,
915969 name : & str ,
916970 span : & dyn crate :: diagnostics:: Spanned ,
917971 diag : & mut BuildDiagnostics ,
918- ) {
972+ ) -> bool {
919973 match super :: ignore_debug_hooks ( expression) {
920974 Expression :: NumberLiteral ( v, Unit :: None ) => {
921975 if * v > u16:: MAX as f64 || !v. trunc ( ) . approx_eq ( v) {
922976 diag. push_error ( format ! ( "'{name}' must be a positive integer" ) , span) ;
923977 }
978+ true
924979 }
925980 Expression :: UnaryOp { op : '-' , sub } => {
926981 if let Expression :: NumberLiteral ( _, Unit :: None ) = super :: ignore_debug_hooks ( sub) {
927982 diag. push_error ( format ! ( "'{name}' must be a positive integer" ) , span) ;
928983 }
984+ true
929985 }
930986 Expression :: Cast { from, .. } => {
931987 check_number_literal_is_positive_integer ( from, name, span, diag)
932988 }
933- _ => { }
989+ _ => false ,
934990 }
935991}
936992
0 commit comments