checker: minor cleanup of struct_init() (#10310)
							parent
							
								
									4089aa38c5
								
							
						
					
					
						commit
						86d70fade7
					
				|  | @ -670,43 +670,44 @@ fn (mut c Checker) unwrap_generic_struct(struct_type ast.Type, generic_names []s | ||||||
| 	return struct_type | 	return struct_type | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { | ||||||
| 	if struct_init.typ == ast.void_type { | 	if node.typ == ast.void_type { | ||||||
| 		// Short syntax `({foo: bar})`
 | 		// Short syntax `({foo: bar})`
 | ||||||
| 		if c.expected_type == ast.void_type { | 		if c.expected_type == ast.void_type { | ||||||
| 			c.error('unexpected short struct syntax', struct_init.pos) | 			c.error('unexpected short struct syntax', node.pos) | ||||||
| 			return ast.void_type | 			return ast.void_type | ||||||
| 		} | 		} | ||||||
| 		sym := c.table.get_type_symbol(c.expected_type) | 		sym := c.table.get_type_symbol(c.expected_type) | ||||||
| 		if sym.kind == .array { | 		if sym.kind == .array { | ||||||
| 			struct_init.typ = c.table.value_type(c.expected_type) | 			node.typ = c.table.value_type(c.expected_type) | ||||||
| 		} else { | 		} else { | ||||||
| 			struct_init.typ = c.expected_type | 			node.typ = c.expected_type | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	struct_sym := c.table.get_type_symbol(struct_init.typ) | 	struct_sym := c.table.get_type_symbol(node.typ) | ||||||
| 	if struct_sym.info is ast.Struct { | 	if struct_sym.info is ast.Struct { | ||||||
| 		if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 | 		if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 | ||||||
| 			&& c.table.cur_concrete_types.len == 0 { | 			&& c.table.cur_concrete_types.len == 0 { | ||||||
| 			c.error('generic struct init must specify type parameter, e.g. Foo<int>', | 			c.error('generic struct init must specify type parameter, e.g. Foo<int>', | ||||||
| 				struct_init.pos) | 				node.pos) | ||||||
| 		} | 		} | ||||||
| 	} else if struct_sym.info is ast.Alias { | 	} else if struct_sym.info is ast.Alias { | ||||||
| 		parent_sym := c.table.get_type_symbol(struct_sym.info.parent_type) | 		parent_sym := c.table.get_type_symbol(struct_sym.info.parent_type) | ||||||
| 		// e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´
 | 		// e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´
 | ||||||
| 		if parent_sym.kind == .map { | 		if parent_sym.kind == .map { | ||||||
| 			alias_str := c.table.type_to_str(struct_init.typ) | 			alias_str := c.table.type_to_str(node.typ) | ||||||
| 			map_str := c.table.type_to_str(struct_sym.info.parent_type) | 			map_str := c.table.type_to_str(struct_sym.info.parent_type) | ||||||
| 			c.error('direct map alias init is not possible, use `${alias_str}($map_str{})` instead', | 			c.error('direct map alias init is not possible, use `${alias_str}($map_str{})` instead', | ||||||
| 				struct_init.pos) | 				node.pos) | ||||||
| 			return ast.void_type | 			return ast.void_type | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	utyp := c.unwrap_generic_struct(struct_init.typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types) | 	unwrapped_struct_type := c.unwrap_generic_struct(node.typ, c.table.cur_fn.generic_names, | ||||||
| 	c.ensure_type_exists(utyp, struct_init.pos) or {} | 		c.table.cur_concrete_types) | ||||||
| 	type_sym := c.table.get_type_symbol(utyp) | 	c.ensure_type_exists(unwrapped_struct_type, node.pos) or {} | ||||||
|  | 	type_sym := c.table.get_type_symbol(unwrapped_struct_type) | ||||||
| 	if !c.inside_unsafe && type_sym.kind == .sum_type { | 	if !c.inside_unsafe && type_sym.kind == .sum_type { | ||||||
| 		c.note('direct sum type init (`x := SumType{}`) will be removed soon', struct_init.pos) | 		c.note('direct sum type init (`x := SumType{}`) will be removed soon', node.pos) | ||||||
| 	} | 	} | ||||||
| 	// Make sure the first letter is capital, do not allow e.g. `x := string{}`,
 | 	// Make sure the first letter is capital, do not allow e.g. `x := string{}`,
 | ||||||
| 	// but `x := T{}` is ok.
 | 	// but `x := T{}` is ok.
 | ||||||
|  | @ -715,43 +716,42 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 		pos := type_sym.name.last_index('.') or { -1 } | 		pos := type_sym.name.last_index('.') or { -1 } | ||||||
| 		first_letter := type_sym.name[pos + 1] | 		first_letter := type_sym.name[pos + 1] | ||||||
| 		if !first_letter.is_capital() { | 		if !first_letter.is_capital() { | ||||||
| 			c.error('cannot initialize builtin type `$type_sym.name`', struct_init.pos) | 			c.error('cannot initialize builtin type `$type_sym.name`', node.pos) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if type_sym.kind == .sum_type && struct_init.fields.len == 1 { | 	if type_sym.kind == .sum_type && node.fields.len == 1 { | ||||||
| 		sexpr := struct_init.fields[0].expr.str() | 		sexpr := node.fields[0].expr.str() | ||||||
| 		c.error('cast to sum type using `${type_sym.name}($sexpr)` not `$type_sym.name{$sexpr}`', | 		c.error('cast to sum type using `${type_sym.name}($sexpr)` not `$type_sym.name{$sexpr}`', | ||||||
| 			struct_init.pos) | 			node.pos) | ||||||
| 	} | 	} | ||||||
| 	if type_sym.kind == .interface_ { | 	if type_sym.kind == .interface_ { | ||||||
| 		c.error('cannot instantiate interface `$type_sym.name`', struct_init.pos) | 		c.error('cannot instantiate interface `$type_sym.name`', node.pos) | ||||||
| 	} | 	} | ||||||
| 	if type_sym.info is ast.Alias { | 	if type_sym.info is ast.Alias { | ||||||
| 		if type_sym.info.parent_type.is_number() { | 		if type_sym.info.parent_type.is_number() { | ||||||
| 			c.error('cannot instantiate number type alias `$type_sym.name`', struct_init.pos) | 			c.error('cannot instantiate number type alias `$type_sym.name`', node.pos) | ||||||
| 			return ast.void_type | 			return ast.void_type | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	// allow init structs from generic if they're private except the type is from builtin module
 | 	// allow init structs from generic if they're private except the type is from builtin module
 | ||||||
| 	if !type_sym.is_public && type_sym.kind != .placeholder && type_sym.language != .c | 	if !type_sym.is_public && type_sym.kind != .placeholder && type_sym.language != .c | ||||||
| 		&& (type_sym.mod != c.mod && !(struct_init.typ.has_flag(.generic) | 		&& (type_sym.mod != c.mod && !(node.typ.has_flag(.generic) && type_sym.mod != 'builtin')) { | ||||||
| 		&& type_sym.mod != 'builtin')) { | 		c.error('type `$type_sym.name` is private', node.pos) | ||||||
| 		c.error('type `$type_sym.name` is private', struct_init.pos) |  | ||||||
| 	} | 	} | ||||||
| 	if type_sym.kind == .struct_ { | 	if type_sym.kind == .struct_ { | ||||||
| 		info := type_sym.info as ast.Struct | 		info := type_sym.info as ast.Struct | ||||||
| 		if info.attrs.len > 0 && info.attrs[0].name == 'noinit' && type_sym.mod != c.mod { | 		if info.attrs.len > 0 && info.attrs[0].name == 'noinit' && type_sym.mod != c.mod { | ||||||
| 			c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' + | 			c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' + | ||||||
| 				'it cannot be initialized with `$type_sym.name{}`', struct_init.pos) | 				'it cannot be initialized with `$type_sym.name{}`', node.pos) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if type_sym.name.len == 1 && c.table.cur_fn.generic_names.len == 0 { | 	if type_sym.name.len == 1 && c.table.cur_fn.generic_names.len == 0 { | ||||||
| 		c.error('unknown struct `$type_sym.name`', struct_init.pos) | 		c.error('unknown struct `$type_sym.name`', node.pos) | ||||||
| 		return 0 | 		return 0 | ||||||
| 	} | 	} | ||||||
| 	match type_sym.kind { | 	match type_sym.kind { | ||||||
| 		.placeholder { | 		.placeholder { | ||||||
| 			c.error('unknown struct: $type_sym.name', struct_init.pos) | 			c.error('unknown struct: $type_sym.name', node.pos) | ||||||
| 			return ast.void_type | 			return ast.void_type | ||||||
| 		} | 		} | ||||||
| 		// string & array are also structs but .kind of string/array
 | 		// string & array are also structs but .kind of string/array
 | ||||||
|  | @ -761,33 +761,33 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 				info_t := type_sym.info as ast.Alias | 				info_t := type_sym.info as ast.Alias | ||||||
| 				sym := c.table.get_type_symbol(info_t.parent_type) | 				sym := c.table.get_type_symbol(info_t.parent_type) | ||||||
| 				if sym.kind == .placeholder { // pending import symbol did not resolve
 | 				if sym.kind == .placeholder { // pending import symbol did not resolve
 | ||||||
| 					c.error('unknown struct: $type_sym.name', struct_init.pos) | 					c.error('unknown struct: $type_sym.name', node.pos) | ||||||
| 					return ast.void_type | 					return ast.void_type | ||||||
| 				} | 				} | ||||||
| 				if sym.kind == .struct_ { | 				if sym.kind == .struct_ { | ||||||
| 					info = sym.info as ast.Struct | 					info = sym.info as ast.Struct | ||||||
| 				} else { | 				} else { | ||||||
| 					c.error('alias type name: $sym.name is not struct type', struct_init.pos) | 					c.error('alias type name: $sym.name is not struct type', node.pos) | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				info = type_sym.info as ast.Struct | 				info = type_sym.info as ast.Struct | ||||||
| 			} | 			} | ||||||
| 			if struct_init.is_short { | 			if node.is_short { | ||||||
| 				exp_len := info.fields.len | 				exp_len := info.fields.len | ||||||
| 				got_len := struct_init.fields.len | 				got_len := node.fields.len | ||||||
| 				if exp_len != got_len { | 				if exp_len != got_len { | ||||||
| 					amount := if exp_len < got_len { 'many' } else { 'few' } | 					amount := if exp_len < got_len { 'many' } else { 'few' } | ||||||
| 					c.error('too $amount fields in `$type_sym.name` literal (expecting $exp_len, got $got_len)', | 					c.error('too $amount fields in `$type_sym.name` literal (expecting $exp_len, got $got_len)', | ||||||
| 						struct_init.pos) | 						node.pos) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			mut inited_fields := []string{} | 			mut inited_fields := []string{} | ||||||
| 			for i, field in struct_init.fields { | 			for i, field in node.fields { | ||||||
| 				mut info_field := ast.StructField{} | 				mut info_field := ast.StructField{} | ||||||
| 				mut embed_type := ast.Type(0) | 				mut embed_type := ast.Type(0) | ||||||
| 				mut is_embed := false | 				mut is_embed := false | ||||||
| 				mut field_name := '' | 				mut field_name := '' | ||||||
| 				if struct_init.is_short { | 				if node.is_short { | ||||||
| 					if i >= info.fields.len { | 					if i >= info.fields.len { | ||||||
| 						// It doesn't make sense to check for fields that don't exist.
 | 						// It doesn't make sense to check for fields that don't exist.
 | ||||||
| 						// We should just stop here.
 | 						// We should just stop here.
 | ||||||
|  | @ -795,7 +795,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 					} | 					} | ||||||
| 					info_field = info.fields[i] | 					info_field = info.fields[i] | ||||||
| 					field_name = info_field.name | 					field_name = info_field.name | ||||||
| 					struct_init.fields[i].name = field_name | 					node.fields[i].name = field_name | ||||||
| 				} else { | 				} else { | ||||||
| 					field_name = field.name | 					field_name = field.name | ||||||
| 					mut exists := false | 					mut exists := false | ||||||
|  | @ -841,8 +841,8 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 								field.pos) | 								field.pos) | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 					struct_init.fields[i].typ = expr_type | 					node.fields[i].typ = expr_type | ||||||
| 					struct_init.fields[i].expected_type = embed_type | 					node.fields[i].expected_type = embed_type | ||||||
| 				} else { | 				} else { | ||||||
| 					inited_fields << field_name | 					inited_fields << field_name | ||||||
| 					field_type_sym := c.table.get_type_symbol(info_field.typ) | 					field_type_sym := c.table.get_type_symbol(info_field.typ) | ||||||
|  | @ -873,8 +873,8 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 								field.pos) | 								field.pos) | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 					struct_init.fields[i].typ = expr_type | 					node.fields[i].typ = expr_type | ||||||
| 					struct_init.fields[i].expected_type = info_field.typ | 					node.fields[i].expected_type = info_field.typ | ||||||
| 				} | 				} | ||||||
| 				if expr_type.is_ptr() && expected_type.is_ptr() { | 				if expr_type.is_ptr() && expected_type.is_ptr() { | ||||||
| 					if mut field.expr is ast.Ident { | 					if mut field.expr is ast.Ident { | ||||||
|  | @ -904,23 +904,23 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 				if field.has_default_expr || field.name in inited_fields { | 				if field.has_default_expr || field.name in inited_fields { | ||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
| 				if field.typ.is_ptr() && !field.typ.has_flag(.shared_f) | 				if field.typ.is_ptr() && !field.typ.has_flag(.shared_f) && !node.has_update_expr | ||||||
| 					&& !struct_init.has_update_expr && !c.pref.translated { | 					&& !c.pref.translated { | ||||||
| 					c.error('reference field `${type_sym.name}.$field.name` must be initialized', | 					c.error('reference field `${type_sym.name}.$field.name` must be initialized', | ||||||
| 						struct_init.pos) | 						node.pos) | ||||||
| 				} | 				} | ||||||
| 				// Do not allow empty uninitialized sum types
 | 				// Do not allow empty uninitialized sum types
 | ||||||
| 				/* | 				/* | ||||||
| 				sym := c.table.get_type_symbol(field.typ) | 				sym := c.table.get_type_symbol(field.typ) | ||||||
| 				if sym.kind == .sum_type { | 				if sym.kind == .sum_type { | ||||||
| 					c.warn('sum type field `${type_sym.name}.$field.name` must be initialized', | 					c.warn('sum type field `${type_sym.name}.$field.name` must be initialized', | ||||||
| 						struct_init.pos) | 						node.pos) | ||||||
| 				} | 				} | ||||||
| 				*/ | 				*/ | ||||||
| 				// Check for `[required]` struct attr
 | 				// Check for `[required]` struct attr
 | ||||||
| 				if field.attrs.contains('required') && !struct_init.is_short { | 				if field.attrs.contains('required') && !node.is_short { | ||||||
| 					mut found := false | 					mut found := false | ||||||
| 					for init_field in struct_init.fields { | 					for init_field in node.fields { | ||||||
| 						if field.name == init_field.name { | 						if field.name == init_field.name { | ||||||
| 							found = true | 							found = true | ||||||
| 							break | 							break | ||||||
|  | @ -928,37 +928,37 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 					} | 					} | ||||||
| 					if !found { | 					if !found { | ||||||
| 						c.error('field `${type_sym.name}.$field.name` must be initialized', | 						c.error('field `${type_sym.name}.$field.name` must be initialized', | ||||||
| 							struct_init.pos) | 							node.pos) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else {} | 		else {} | ||||||
| 	} | 	} | ||||||
| 	if struct_init.has_update_expr { | 	if node.has_update_expr { | ||||||
| 		update_type := c.expr(struct_init.update_expr) | 		update_type := c.expr(node.update_expr) | ||||||
| 		struct_init.update_expr_type = update_type | 		node.update_expr_type = update_type | ||||||
| 		if c.table.type_kind(update_type) != .struct_ { | 		if c.table.type_kind(update_type) != .struct_ { | ||||||
| 			s := c.table.type_to_str(update_type) | 			s := c.table.type_to_str(update_type) | ||||||
| 			c.error('expected struct, found `$s`', struct_init.update_expr.position()) | 			c.error('expected struct, found `$s`', node.update_expr.position()) | ||||||
| 		} else if update_type != struct_init.typ { | 		} else if update_type != node.typ { | ||||||
| 			from_sym := c.table.get_type_symbol(update_type) | 			from_sym := c.table.get_type_symbol(update_type) | ||||||
| 			to_sym := c.table.get_type_symbol(struct_init.typ) | 			to_sym := c.table.get_type_symbol(node.typ) | ||||||
| 			from_info := from_sym.info as ast.Struct | 			from_info := from_sym.info as ast.Struct | ||||||
| 			to_info := to_sym.info as ast.Struct | 			to_info := to_sym.info as ast.Struct | ||||||
| 			// TODO this check is too strict
 | 			// TODO this check is too strict
 | ||||||
| 			if !c.check_struct_signature(from_info, to_info) { | 			if !c.check_struct_signature(from_info, to_info) { | ||||||
| 				c.error('struct `$from_sym.name` is not compatible with struct `$to_sym.name`', | 				c.error('struct `$from_sym.name` is not compatible with struct `$to_sym.name`', | ||||||
| 					struct_init.update_expr.position()) | 					node.update_expr.position()) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if !struct_init.update_expr.is_lvalue() { | 		if !node.update_expr.is_lvalue() { | ||||||
| 			// cgen will repeat `update_expr` for each field
 | 			// cgen will repeat `update_expr` for each field
 | ||||||
| 			// so enforce an lvalue for efficiency
 | 			// so enforce an lvalue for efficiency
 | ||||||
| 			c.error('expression is not an lvalue', struct_init.update_expr.position()) | 			c.error('expression is not an lvalue', node.update_expr.position()) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return utyp | 	return unwrapped_struct_type | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (mut c Checker) check_div_mod_by_zero(expr ast.Expr, op_kind token.Kind) { | fn (mut c Checker) check_div_mod_by_zero(expr ast.Expr, op_kind token.Kind) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue