checker: check struct casting (#5864)
							parent
							
								
									6016f28171
								
							
						
					
					
						commit
						b2fee21ef3
					
				|  | @ -2328,6 +2328,13 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { | |||
| 				to_type_sym.kind == .byte { | ||||
| 				type_name := c.table.type_to_str(node.expr_type) | ||||
| 				c.error('cannot cast type `$type_name` to `byte`', node.pos) | ||||
| 			} else if to_type_sym.kind == .struct_ && !node.typ.is_ptr() && !(to_type_sym.info as table.Struct).is_typedef { | ||||
| 				from_type_info := from_type_sym.info as table.Struct | ||||
| 				to_type_info := to_type_sym.info as table.Struct | ||||
| 				if !c.check_struct_signature(from_type_info, to_type_info) { | ||||
| 					c.error('cannot convert struct `$from_type_sym.name` to struct `$to_type_sym.name`', | ||||
| 						node.pos) | ||||
| 				} | ||||
| 			} | ||||
| 			if node.has_arg { | ||||
| 				c.expr(node.arg) | ||||
|  | @ -3257,6 +3264,34 @@ pub fn (mut c Checker) error(message string, pos token.Position) { | |||
| 	c.warn_or_error(msg, pos, false) | ||||
| } | ||||
| 
 | ||||
| // check_struct_signature checks if both structs has the same signature / fields for casting
 | ||||
| fn (c Checker) check_struct_signature(from, to table.Struct) bool { | ||||
| 	if from.fields.len != to.fields.len { | ||||
| 		return false | ||||
| 	} | ||||
| 	for _, field in from.fields { | ||||
| 		filtered := to.fields.filter(it.name == field.name) | ||||
| 		if filtered.len != 1 { | ||||
| 			// field doesn't exist
 | ||||
| 			return false | ||||
| 		} | ||||
| 		counterpart := filtered[0] | ||||
| 		if field.typ != counterpart.typ { | ||||
| 			// field has different tye
 | ||||
| 			return false | ||||
| 		} | ||||
| 		if field.is_pub != counterpart.is_pub { | ||||
| 			// field is not public while the other one is
 | ||||
| 			return false | ||||
| 		} | ||||
| 		if field.is_mut != counterpart.is_mut { | ||||
| 			// field is not mutable while the other one is
 | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) { | ||||
| 	// add backtrace to issue struct, how?
 | ||||
| 	// if c.pref.is_verbose {
 | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/struct_cast_to_struct_generic_err.v:11:11: error: cannot convert struct `Abc<int>` to struct `Xyz` | ||||
|     9 | fn main() { | ||||
|    10 |     abc := Abc<int>{} | ||||
|    11 |     _ := Xyz(abc) | ||||
|       |              ~~~ | ||||
|    12 | } | ||||
|  | @ -0,0 +1,12 @@ | |||
| struct Abc<T> { | ||||
| 	name T | ||||
| } | ||||
| 
 | ||||
| struct Xyz { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	abc := Abc<int>{} | ||||
| 	_ := Xyz(abc) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/struct_cast_to_struct_mut_err_a.v:12:11: error: cannot convert struct `Abc` to struct `Xyz` | ||||
|    10 | fn main() { | ||||
|    11 |     abc := Abc{} | ||||
|    12 |     _ := Xyz(abc) | ||||
|       |              ~~~ | ||||
|    13 | } | ||||
|  | @ -0,0 +1,13 @@ | |||
| struct Abc { | ||||
| mut: | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| struct Xyz { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	abc := Abc{} | ||||
| 	_ := Xyz(abc) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/struct_cast_to_struct_mut_err_b.v:12:11: error: cannot convert struct `Abc` to struct `Xyz` | ||||
|    10 | fn main() { | ||||
|    11 |     abc := Abc{} | ||||
|    12 |     _ := Xyz(abc) | ||||
|       |              ~~~ | ||||
|    13 | } | ||||
|  | @ -0,0 +1,13 @@ | |||
| struct Abc { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| struct Xyz { | ||||
| mut: | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	abc := Abc{} | ||||
| 	_ := Xyz(abc) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/struct_cast_to_struct_pub_err_a.v:12:11: error: cannot convert struct `Abc` to struct `Xyz` | ||||
|    10 | fn main() { | ||||
|    11 |     abc := Abc{} | ||||
|    12 |     _ := Xyz(abc) | ||||
|       |              ~~~ | ||||
|    13 | } | ||||
|  | @ -0,0 +1,13 @@ | |||
| struct Abc { | ||||
| pub: | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| struct Xyz { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	abc := Abc{} | ||||
| 	_ := Xyz(abc) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/struct_cast_to_struct_pub_err_b.v:12:11: error: cannot convert struct `Abc` to struct `Xyz` | ||||
|    10 | fn main() { | ||||
|    11 |     abc := Abc{} | ||||
|    12 |     _ := Xyz(abc) | ||||
|       |              ~~~ | ||||
|    13 | } | ||||
|  | @ -0,0 +1,13 @@ | |||
| struct Abc { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| struct Xyz { | ||||
| pub: | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	abc := Abc{} | ||||
| 	_ := Xyz(abc) | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ struct Foo { | |||
| 
 | ||||
| struct Bar { | ||||
| 	f &Foo = &Foo(0) | ||||
| 	d Foo = Foo(0) | ||||
| 	d Foo = Foo{0} | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue