checker: require or block for sumtype map (#11089)
							parent
							
								
									af75789bbf
								
							
						
					
					
						commit
						be0c54caf9
					
				|  | @ -44,7 +44,7 @@ fn (s &Scope) dont_lookup_parent() bool { | |||
| pub fn (s &Scope) find(name string) ?ScopeObject { | ||||
| 	for sc := s; true; sc = sc.parent { | ||||
| 		if name in sc.objects { | ||||
| 			return sc.objects[name] | ||||
| 			return unsafe { sc.objects[name] } | ||||
| 		} | ||||
| 		if sc.dont_lookup_parent() { | ||||
| 			break | ||||
|  | @ -104,7 +104,7 @@ pub fn (s &Scope) known_var(name string) bool { | |||
| } | ||||
| 
 | ||||
| pub fn (mut s Scope) update_var_type(name string, typ Type) { | ||||
| 	mut obj := s.objects[name] | ||||
| 	mut obj := unsafe { s.objects[name] } | ||||
| 	if mut obj is Var { | ||||
| 		if obj.typ != typ { | ||||
| 			obj.typ = typ | ||||
|  |  | |||
|  | @ -5783,8 +5783,8 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { | |||
| 				i++ | ||||
| 				continue | ||||
| 			} | ||||
| 			if k in c.fn_scope.objects && c.fn_scope.objects[k] is ast.Var { | ||||
| 				mut vsc := c.fn_scope.objects[k] as ast.Var | ||||
| 			if k in c.fn_scope.objects && unsafe { c.fn_scope.objects[k] } is ast.Var { | ||||
| 				mut vsc := unsafe { c.fn_scope.objects[k] } as ast.Var | ||||
| 				vsc.is_used = true | ||||
| 				c.fn_scope.objects[k] = vsc | ||||
| 			} | ||||
|  | @ -7437,6 +7437,12 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type { | |||
| 				err := c.expected_msg(index_type, info.key_type) | ||||
| 				c.error('invalid key: $err', node.pos) | ||||
| 			} | ||||
| 			value_sym := c.table.get_type_symbol(info.value_type) | ||||
| 			if !node.is_setter && value_sym.kind == .sum_type && node.or_expr.kind == .absent | ||||
| 				&& !c.inside_unsafe { | ||||
| 				c.warn('`or {}` block required when indexing a map with sum type value', | ||||
| 					node.pos) | ||||
| 			} | ||||
| 		} else { | ||||
| 			index_type := c.expr(node.index) | ||||
| 			c.check_index(typ_sym, node.index, index_type, node.pos, false) | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/require_or_block_sumtype_map.err.vv:5:8: error: `or {}` block required when indexing a map with sum type value | ||||
|     3 | fn main() { | ||||
|     4 |     x := map[string]Abc{} | ||||
|     5 |     _ := x['nonexisting'] | ||||
|       |           ~~~~~~~~~~~~~~~ | ||||
|     6 | } | ||||
|  | @ -0,0 +1,6 @@ | |||
| type Abc = string | int | ||||
| 
 | ||||
| fn main() { | ||||
| 	x := map[string]Abc{} | ||||
| 	_ := x['nonexisting'] | ||||
| } | ||||
|  | @ -290,7 +290,7 @@ fn (mut task TaskDescription) execute() { | |||
| 	task.expected_out_path = expected_out_path | ||||
| 	task.cli_cmd = cli_cmd | ||||
| 	if should_autofix && !os.exists(expected_out_path) { | ||||
| 		os.write_file(expected_out_path, '') or { panic(err) } | ||||
| 		os.create(expected_out_path) or { panic(err) } | ||||
| 	} | ||||
| 	mut expected := os.read_file(expected_out_path) or { panic(err) } | ||||
| 	task.expected = clean_line_endings(expected) | ||||
|  |  | |||
|  | @ -1097,7 +1097,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { | |||
| fn (mut p Parser) reg_or_alias() ast.AsmArg { | ||||
| 	p.check(.name) | ||||
| 	if p.prev_tok.lit in p.scope.objects { | ||||
| 		x := p.scope.objects[p.prev_tok.lit] | ||||
| 		x := unsafe { p.scope.objects[p.prev_tok.lit] } | ||||
| 		if x is ast.AsmRegister { | ||||
| 			return ast.AsmArg(x as ast.AsmRegister) | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -25,106 +25,106 @@ fn is_null(f json2.Any) bool { | |||
| 
 | ||||
| fn test_f32() { | ||||
| 	// valid conversions
 | ||||
| 	assert sample_data['int'].f32() == 1.0 | ||||
| 	assert sample_data['i64'].f32() == 128.0 | ||||
| 	assert sample_data['f32'].f32() == 2.0 | ||||
| 	assert sample_data['f64'].f32() == 1.2829999923706055 | ||||
| 	assert sample_data['int'] or { 0 }.f32() == 1.0 | ||||
| 	assert sample_data['i64'] or { 0 }.f32() == 128.0 | ||||
| 	assert sample_data['f32'] or { 0 }.f32() == 2.0 | ||||
| 	assert sample_data['f64'] or { 0 }.f32() == 1.2829999923706055 | ||||
| 	// invalid conversions
 | ||||
| 	assert sample_data['bool'].f32() == 0.0 | ||||
| 	assert sample_data['str'].f32() == 0.0 | ||||
| 	assert sample_data['null'].f32() == 0.0 | ||||
| 	assert sample_data['arr'].f32() == 0.0 | ||||
| 	assert sample_data['obj'].f32() == 0.0 | ||||
| 	assert sample_data['bool'] or { 0 }.f32() == 0.0 | ||||
| 	assert sample_data['str'] or { 0 }.f32() == 0.0 | ||||
| 	assert sample_data['null'] or { 0 }.f32() == 0.0 | ||||
| 	assert sample_data['arr'] or { 0 }.f32() == 0.0 | ||||
| 	assert sample_data['obj'] or { 0 }.f32() == 0.0 | ||||
| } | ||||
| 
 | ||||
| fn test_f64() { | ||||
| 	// valid conversions
 | ||||
| 	assert sample_data['int'].f64() == 1.0 | ||||
| 	assert sample_data['i64'].f64() == 128.0 | ||||
| 	assert sample_data['f32'].f64() == 2.0 | ||||
| 	assert sample_data['f64'].f64() == 1.283 | ||||
| 	assert sample_data['int'] or { 0 }.f64() == 1.0 | ||||
| 	assert sample_data['i64'] or { 0 }.f64() == 128.0 | ||||
| 	assert sample_data['f32'] or { 0 }.f64() == 2.0 | ||||
| 	assert sample_data['f64'] or { 0 }.f64() == 1.283 | ||||
| 	// invalid conversions
 | ||||
| 	assert sample_data['bool'].f64() == 0.0 | ||||
| 	assert sample_data['str'].f64() == 0.0 | ||||
| 	assert sample_data['null'].f64() == 0.0 | ||||
| 	assert sample_data['arr'].f64() == 0.0 | ||||
| 	assert sample_data['obj'].f64() == 0.0 | ||||
| 	assert sample_data['bool'] or { 0 }.f64() == 0.0 | ||||
| 	assert sample_data['str'] or { 0 }.f64() == 0.0 | ||||
| 	assert sample_data['null'] or { 0 }.f64() == 0.0 | ||||
| 	assert sample_data['arr'] or { 0 }.f64() == 0.0 | ||||
| 	assert sample_data['obj'] or { 0 }.f64() == 0.0 | ||||
| } | ||||
| 
 | ||||
| fn test_int() { | ||||
| 	// valid conversions
 | ||||
| 	assert sample_data['int'].int() == 1 | ||||
| 	assert sample_data['i64'].int() == 128 | ||||
| 	assert sample_data['f32'].int() == 2 | ||||
| 	assert sample_data['f64'].int() == 1 | ||||
| 	assert sample_data['int'] or { 0 }.int() == 1 | ||||
| 	assert sample_data['i64'] or { 0 }.int() == 128 | ||||
| 	assert sample_data['f32'] or { 0 }.int() == 2 | ||||
| 	assert sample_data['f64'] or { 0 }.int() == 1 | ||||
| 	assert json2.Any(true).int() == 1 | ||||
| 	// invalid conversions
 | ||||
| 	assert json2.Any('123').int() == 0 | ||||
| 	assert sample_data['null'].int() == 0 | ||||
| 	assert sample_data['arr'].int() == 0 | ||||
| 	assert sample_data['obj'].int() == 0 | ||||
| 	assert sample_data['null'] or { 0 }.int() == 0 | ||||
| 	assert sample_data['arr'] or { 0 }.int() == 0 | ||||
| 	assert sample_data['obj'] or { 0 }.int() == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_i64() { | ||||
| 	// valid conversions
 | ||||
| 	assert sample_data['int'].i64() == 1 | ||||
| 	assert sample_data['i64'].i64() == 128 | ||||
| 	assert sample_data['f32'].i64() == 2 | ||||
| 	assert sample_data['f64'].i64() == 1 | ||||
| 	assert sample_data['int'] or { 0 }.i64() == 1 | ||||
| 	assert sample_data['i64'] or { 0 }.i64() == 128 | ||||
| 	assert sample_data['f32'] or { 0 }.i64() == 2 | ||||
| 	assert sample_data['f64'] or { 0 }.i64() == 1 | ||||
| 	assert json2.Any(true).i64() == 1 | ||||
| 	// invalid conversions
 | ||||
| 	assert json2.Any('123').i64() == 0 | ||||
| 	assert sample_data['null'].i64() == 0 | ||||
| 	assert sample_data['arr'].i64() == 0 | ||||
| 	assert sample_data['obj'].i64() == 0 | ||||
| 	assert sample_data['null'] or { 0 }.i64() == 0 | ||||
| 	assert sample_data['arr'] or { 0 }.i64() == 0 | ||||
| 	assert sample_data['obj'] or { 0 }.i64() == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_as_map() { | ||||
| 	assert sample_data['int'].as_map()['0'].int() == 1 | ||||
| 	assert sample_data['i64'].as_map()['0'].i64() == 128.0 | ||||
| 	assert sample_data['f32'].as_map()['0'].f32() == 2.0 | ||||
| 	assert sample_data['f64'].as_map()['0'].f64() == 1.283 | ||||
| 	assert sample_data['bool'].as_map()['0'].bool() == false | ||||
| 	assert sample_data['str'].as_map()['0'].str() == 'test' | ||||
| 	assert is_null(sample_data['null'].as_map()['0']) == true | ||||
| 	assert sample_data['arr'].as_map()['0'].str() == 'lol' | ||||
| 	assert sample_data['obj'].as_map()['foo'].int() == 10 | ||||
| 	assert sample_data['int'] or { 0 }.as_map()['0'] or { 0 }.int() == 1 | ||||
| 	assert sample_data['i64'] or { 0 }.as_map()['0'] or { 0 }.i64() == 128.0 | ||||
| 	assert sample_data['f32'] or { 0 }.as_map()['0'] or { 0 }.f32() == 2.0 | ||||
| 	assert sample_data['f64'] or { 0 }.as_map()['0'] or { 0 }.f64() == 1.283 | ||||
| 	assert sample_data['bool'] or { 0 }.as_map()['0'] or { 0 }.bool() == false | ||||
| 	assert sample_data['str'] or { 0 }.as_map()['0'] or { 0 }.str() == 'test' | ||||
| 	assert is_null(sample_data['null'] or { 0 }.as_map()['0'] or { 0 }) == true | ||||
| 	assert sample_data['arr'] or { 0 }.as_map()['0'] or { 0 }.str() == 'lol' | ||||
| 	assert sample_data['obj'] or { 0 }.as_map()['foo'] or { 0 }.int() == 10 | ||||
| } | ||||
| 
 | ||||
| fn test_arr() { | ||||
| 	assert sample_data['int'].arr()[0].int() == 1 | ||||
| 	assert sample_data['i64'].arr()[0].i64() == 128.0 | ||||
| 	assert sample_data['f32'].arr()[0].f32() == 2.0 | ||||
| 	assert sample_data['f64'].arr()[0].f64() == 1.283 | ||||
| 	assert sample_data['bool'].arr()[0].bool() == false | ||||
| 	assert sample_data['str'].arr()[0].str() == 'test' | ||||
| 	assert is_null(sample_data['null'].arr()[0]) == true | ||||
| 	assert sample_data['arr'].arr()[0].str() == 'lol' | ||||
| 	assert sample_data['obj'].arr()[0].int() == 10 | ||||
| 	assert sample_data['int'] or { 0 }.arr()[0].int() == 1 | ||||
| 	assert sample_data['i64'] or { 0 }.arr()[0].i64() == 128.0 | ||||
| 	assert sample_data['f32'] or { 0 }.arr()[0].f32() == 2.0 | ||||
| 	assert sample_data['f64'] or { 0 }.arr()[0].f64() == 1.283 | ||||
| 	assert sample_data['bool'] or { 0 }.arr()[0].bool() == false | ||||
| 	assert sample_data['str'] or { 0 }.arr()[0].str() == 'test' | ||||
| 	assert is_null(sample_data['null'] or { 0 }.arr()[0]) == true | ||||
| 	assert sample_data['arr'] or { 0 }.arr()[0].str() == 'lol' | ||||
| 	assert sample_data['obj'] or { 0 }.arr()[0].int() == 10 | ||||
| } | ||||
| 
 | ||||
| fn test_bool() { | ||||
| 	// valid conversions
 | ||||
| 	assert sample_data['bool'].bool() == false | ||||
| 	assert sample_data['bool'] or { 0 }.bool() == false | ||||
| 	assert json2.Any('true').bool() == true | ||||
| 	// invalid conversions
 | ||||
| 	assert sample_data['int'].bool() == false | ||||
| 	assert sample_data['i64'].bool() == false | ||||
| 	assert sample_data['f32'].bool() == false | ||||
| 	assert sample_data['f64'].bool() == false | ||||
| 	assert sample_data['null'].bool() == false | ||||
| 	assert sample_data['arr'].bool() == false | ||||
| 	assert sample_data['obj'].bool() == false | ||||
| 	assert sample_data['int'] or { 0 }.bool() == false | ||||
| 	assert sample_data['i64'] or { 0 }.bool() == false | ||||
| 	assert sample_data['f32'] or { 0 }.bool() == false | ||||
| 	assert sample_data['f64'] or { 0 }.bool() == false | ||||
| 	assert sample_data['null'] or { 0 }.bool() == false | ||||
| 	assert sample_data['arr'] or { 0 }.bool() == false | ||||
| 	assert sample_data['obj'] or { 0 }.bool() == false | ||||
| } | ||||
| 
 | ||||
| fn test_str() { | ||||
| 	assert sample_data['int'].str() == '1' | ||||
| 	assert sample_data['i64'].str() == '128' | ||||
| 	assert sample_data['f32'].str() == '2.0' | ||||
| 	assert sample_data['f64'].str() == '1.283' | ||||
| 	assert sample_data['bool'].str() == 'false' | ||||
| 	assert sample_data['str'].str() == 'test' | ||||
| 	assert sample_data['null'].str() == 'null' | ||||
| 	assert sample_data['arr'].str() == '["lol"]' | ||||
| 	assert sample_data['int'] or { 0 }.str() == '1' | ||||
| 	assert sample_data['i64'] or { 0 }.str() == '128' | ||||
| 	assert sample_data['f32'] or { 0 }.str() == '2.0' | ||||
| 	assert sample_data['f64'] or { 0 }.str() == '1.283' | ||||
| 	assert sample_data['bool'] or { 0 }.str() == 'false' | ||||
| 	assert sample_data['str'] or { 0 }.str() == 'test' | ||||
| 	assert sample_data['null'] or { 0 }.str() == 'null' | ||||
| 	assert sample_data['arr'] or { 0 }.str() == '["lol"]' | ||||
| 	assert sample_data.str() == '{"int":1,"i64":128,"f32":2.0,"f64":1.283,"bool":false,"str":"test","null":null,"arr":["lol"],"obj":{"foo":10}}' | ||||
| } | ||||
|  |  | |||
|  | @ -13,8 +13,8 @@ fn test_raw_decode_number() ? { | |||
| fn test_raw_decode_array() ? { | ||||
| 	raw_arr := raw_decode('["Foo", 1]') ? | ||||
| 	arr := raw_arr.arr() | ||||
| 	assert arr[0].str() == 'Foo' | ||||
| 	assert arr[1].int() == 1 | ||||
| 	assert arr[0] or { 0 }.str() == 'Foo' | ||||
| 	assert arr[1] or { 0 }.int() == 1 | ||||
| } | ||||
| 
 | ||||
| fn test_raw_decode_bool() ? { | ||||
|  | @ -25,8 +25,8 @@ fn test_raw_decode_bool() ? { | |||
| fn test_raw_decode_map() ? { | ||||
| 	raw_mp := raw_decode('{"name":"Bob","age":20}') ? | ||||
| 	mp := raw_mp.as_map() | ||||
| 	assert mp['name'].str() == 'Bob' | ||||
| 	assert mp['age'].int() == 20 | ||||
| 	assert mp['name'] or { 0 }.str() == 'Bob' | ||||
| 	assert mp['age'] or { 0 }.int() == 20 | ||||
| } | ||||
| 
 | ||||
| fn test_raw_decode_null() ? { | ||||
|  | @ -50,8 +50,8 @@ fn test_raw_decode_string_with_dollarsign() ? { | |||
| fn test_raw_decode_map_with_whitespaces() ? { | ||||
| 	raw_mp := raw_decode(' \n\t{"name":"Bob","age":20}\n\t') ? | ||||
| 	mp := raw_mp.as_map() | ||||
| 	assert mp['name'].str() == 'Bob' | ||||
| 	assert mp['age'].int() == 20 | ||||
| 	assert mp['name'] or { 0 }.str() == 'Bob' | ||||
| 	assert mp['age'] or { 0 }.int() == 20 | ||||
| } | ||||
| 
 | ||||
| fn test_nested_array_object() ? { | ||||
|  |  | |||
|  | @ -36,10 +36,10 @@ fn (e Employee) to_json() string { | |||
| 
 | ||||
| fn (mut e Employee) from_json(any json2.Any) { | ||||
| 	mp := any.as_map() | ||||
| 	e.name = mp['name'].str() | ||||
| 	e.age = mp['age'].int() | ||||
| 	e.salary = mp['salary'].f32() | ||||
| 	e.title = JobTitle(mp['title'].int()) | ||||
| 	e.name = mp['name'] or { 0 }.str() | ||||
| 	e.age = mp['age'] or { 0 }.int() | ||||
| 	e.salary = mp['salary'] or { 0 }.f32() | ||||
| 	e.title = JobTitle(mp['title'] or { 0 }.int()) | ||||
| } | ||||
| 
 | ||||
| fn test_simple() { | ||||
|  | @ -84,11 +84,11 @@ fn test_character_unescape() { | |||
| 	} | ||||
| 	lines := obj.as_map() | ||||
| 	eprintln('$lines') | ||||
| 	assert lines['newline'].str() == 'new\nline' | ||||
| 	assert lines['tab'].str() == '\ttab' | ||||
| 	assert lines['backslash'].str() == 'back\\slash' | ||||
| 	assert lines['quotes'].str() == '"quotes"' | ||||
| 	assert lines['slash'].str() == '/dev/null' | ||||
| 	assert lines['newline'] or { 0 }.str() == 'new\nline' | ||||
| 	assert lines['tab'] or { 0 }.str() == '\ttab' | ||||
| 	assert lines['backslash'] or { 0 }.str() == 'back\\slash' | ||||
| 	assert lines['quotes'] or { 0 }.str() == '"quotes"' | ||||
| 	assert lines['slash'] or { 0 }.str() == '/dev/null' | ||||
| } | ||||
| 
 | ||||
| struct User2 { | ||||
|  | @ -109,8 +109,8 @@ fn (mut u User2) from_json(an json2.Any) { | |||
| 			} | ||||
| 		} | ||||
| 		match field.name { | ||||
| 			'age' { u.age = mp[js_field_name].int() } | ||||
| 			'nums' { u.nums = mp[js_field_name].arr().map(it.int()) } | ||||
| 			'age' { u.age = mp[js_field_name] or { 0 }.int() } | ||||
| 			'nums' { u.nums = mp[js_field_name] or { 0 }.arr().map(it.int()) } | ||||
| 			else {} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -140,12 +140,12 @@ fn (mut u User) from_json(an json2.Any) { | |||
| 			} | ||||
| 		} | ||||
| 		match field.name { | ||||
| 			'age' { u.age = mp[js_field_name].int() } | ||||
| 			'nums' { u.nums = mp[js_field_name].arr().map(it.int()) } | ||||
| 			'last_name' { u.last_name = mp[js_field_name].str() } | ||||
| 			'is_registered' { u.is_registered = mp[js_field_name].bool() } | ||||
| 			'typ' { u.typ = mp[js_field_name].int() } | ||||
| 			'pets' { u.pets = mp[js_field_name].str() } | ||||
| 			'age' { u.age = mp[js_field_name] or { 0 }.int() } | ||||
| 			'nums' { u.nums = mp[js_field_name] or { 0 }.arr().map(it.int()) } | ||||
| 			'last_name' { u.last_name = mp[js_field_name] or { 0 }.str() } | ||||
| 			'is_registered' { u.is_registered = mp[js_field_name] or { 0 }.bool() } | ||||
| 			'typ' { u.typ = mp[js_field_name] or { 0 }.int() } | ||||
| 			'pets' { u.pets = mp[js_field_name] or { 0 }.str() } | ||||
| 			else {} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -212,8 +212,8 @@ fn (mut c Color) from_json(an json2.Any) { | |||
| 	mp := an.as_map() | ||||
| 	$for field in Color.fields { | ||||
| 		match field.name { | ||||
| 			'space' { c.space = mp[field.name].str() } | ||||
| 			'point' { c.point = mp[field.name].str() } | ||||
| 			'space' { c.space = mp[field.name] or { 0 }.str() } | ||||
| 			'point' { c.point = mp[field.name] or { 0 }.str() } | ||||
| 			else {} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue