checker: improve errors with compile-time field access (#8373)
							parent
							
								
									4aee997689
								
							
						
					
					
						commit
						d012f2713b
					
				|  | @ -3377,13 +3377,19 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { | |||
| 					node.field_expr.position()) | ||||
| 			} | ||||
| 			if node.field_expr is ast.SelectorExpr { | ||||
| 				left_pos := node.field_expr.expr.position() | ||||
| 				if c.comptime_fields_type.len == 0 { | ||||
| 					c.error('compile time field access can only be used when iterating over `T.fields`', | ||||
| 						left_pos) | ||||
| 				} | ||||
| 				expr_name := node.field_expr.expr.str() | ||||
| 				if expr_name in c.comptime_fields_type { | ||||
| 					return c.comptime_fields_type[expr_name] | ||||
| 				} | ||||
| 				c.error('unknown `\$for` variable `$expr_name`', left_pos) | ||||
| 			} else { | ||||
| 				c.error('expected selector expression e.g. `$(field.name)`', node.field_expr.position()) | ||||
| 			} | ||||
| 			c.error('compile time field access can only be used when iterating over `T.fields`', | ||||
| 				node.field_expr.position()) | ||||
| 			return table.void_type | ||||
| 		} | ||||
| 		ast.ConcatExpr { | ||||
|  | @ -4458,12 +4464,14 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { | |||
| 		} | ||||
| 		if node.is_comptime { // Skip checking if needed
 | ||||
| 			// smartcast field type on comptime if
 | ||||
| 			mut comptime_field_name := '' | ||||
| 			if branch.cond is ast.InfixExpr { | ||||
| 				if branch.cond.op == .key_is { | ||||
| 					left := branch.cond.left | ||||
| 					got_type := (branch.cond.right as ast.Type).typ | ||||
| 					if left is ast.SelectorExpr { | ||||
| 						c.comptime_fields_type[left.expr.str()] = got_type | ||||
| 						comptime_field_name = left.expr.str() | ||||
| 						c.comptime_fields_type[comptime_field_name] = got_type | ||||
| 						is_comptime_type_is_expr = true | ||||
| 					} else if left is ast.Type { | ||||
| 						is_comptime_type_is_expr = true | ||||
|  | @ -4488,6 +4496,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { | |||
| 			} else if !is_comptime_type_is_expr { | ||||
| 				node.branches[i].stmts = [] | ||||
| 			} | ||||
| 			if comptime_field_name.len > 0 { | ||||
| 				c.comptime_fields_type.delete(comptime_field_name) | ||||
| 			} | ||||
| 			c.skip_flags = cur_skip_flags | ||||
| 		} else { | ||||
| 			c.stmts(branch.stmts) | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| vlib/v/checker/tests/comptime_field_selector_not_in_for_err.vv:9:5: error: compile time field access can only be used when iterating over `T.fields` | ||||
| vlib/v/checker/tests/comptime_field_selector_not_in_for_err.vv:9:5: error: expected selector expression e.g. `$(field.name)` | ||||
|     7 |     mut t := T{} | ||||
|     8 |     name := 'test' | ||||
|     9 |     t.$name = '3' | ||||
|       |        ~~~~ | ||||
|    10 | } | ||||
|    11 | | ||||
|    11 | | ||||
|  |  | |||
|  | @ -3,5 +3,19 @@ vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:10:7: error: expect | |||
|     9 |         $if f.typ is string { | ||||
|    10 |             t.$f = '3' | ||||
|       |                ^ | ||||
|    11 |         } | ||||
|    12 |     } | ||||
|    11 |             fv := Foo{} | ||||
|    12 |             _ = t.$fv.name | ||||
| vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:12:11: error: unknown `$for` variable `fv` | ||||
|    10 |             t.$f = '3' | ||||
|    11 |             fv := Foo{} | ||||
|    12 |             _ = t.$fv.name | ||||
|       |                    ~~ | ||||
|    13 |         } | ||||
|    14 |     } | ||||
| vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:15:9: error: compile time field access can only be used when iterating over `T.fields` | ||||
|    13 |         } | ||||
|    14 |     } | ||||
|    15 |     _ = t.$f.name | ||||
|       |            ^ | ||||
|    16 | } | ||||
|    17 | | ||||
|  |  | |||
|  | @ -8,8 +8,11 @@ fn test<T>() { | |||
| 	$for f in T.fields { | ||||
| 		$if f.typ is string { | ||||
| 			t.$f = '3' | ||||
| 			fv := Foo{} | ||||
| 			_ = t.$fv.name | ||||
| 		} | ||||
| 	} | ||||
| 	_ = t.$f.name | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue