compiler: clean up multiple returns and verify number of returned values
							parent
							
								
									a44a03f9a5
								
							
						
					
					
						commit
						3317d7fd7c
					
				|  | @ -275,19 +275,17 @@ fn (p mut Parser) fn_decl() { | ||||||
| 		typ = p.get_type() | 		typ = p.get_type() | ||||||
| 	} | 	} | ||||||
| 	// multiple returns
 | 	// multiple returns
 | ||||||
| 	if typ.starts_with('MultiReturn_') { | 	if typ.starts_with('_V_MulRet_') && p.first_pass() && !p.table.known_type(typ) { | ||||||
| 		if !p.first_pass() && !p.table.known_type(typ) { |  | ||||||
| 		p.table.register_type2(Type{ | 		p.table.register_type2(Type{ | ||||||
| 			cat: TypeCategory.struct_, | 			cat: TypeCategory.struct_, | ||||||
| 			name: typ, | 			name: typ, | ||||||
| 			mod: p.mod | 			mod: p.mod | ||||||
| 		}) | 		}) | ||||||
| 			for i, t in typ.replace('MultiReturn_', '').replace('_ZptrZ_', '*').split('_Z_') { | 		for i, t in typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') { | ||||||
| 			p.table.add_field(typ, 'var_$i', t, false, '', .public) | 			p.table.add_field(typ, 'var_$i', t, false, '', .public) | ||||||
| 		} | 		} | ||||||
| 		p.cgen.typedefs << 'typedef struct $typ $typ;' | 		p.cgen.typedefs << 'typedef struct $typ $typ;' | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	// Translated C code can have empty functions (just definitions)
 | 	// Translated C code can have empty functions (just definitions)
 | ||||||
| 	is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) &&	p.tok != .lcbr | 	is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) &&	p.tok != .lcbr | ||||||
| 	if is_fn_header { | 	if is_fn_header { | ||||||
|  |  | ||||||
|  | @ -276,6 +276,8 @@ fn (p mut Parser) parse(pass Pass) { | ||||||
| 			p.cgen.consts << g | 			p.cgen.consts << g | ||||||
| 		case Token.eof: | 		case Token.eof: | ||||||
| 			//p.log('end of parse()')
 | 			//p.log('end of parse()')
 | ||||||
|  | 			// TODO: check why this was added? everything seems to work
 | ||||||
|  | 			// without it, and it's already happening in fn_decl
 | ||||||
| 			// if p.is_script && !p.pref.is_test {
 | 			// if p.is_script && !p.pref.is_test {
 | ||||||
| 			// 	p.set_current_fn( MainFn )
 | 			// 	p.set_current_fn( MainFn )
 | ||||||
| 			// 	p.check_unused_variables()
 | 			// 	p.check_unused_variables()
 | ||||||
|  | @ -863,7 +865,7 @@ fn (p mut Parser) get_type() string { | ||||||
| 		} | 		} | ||||||
| 		p.check(.rpar) | 		p.check(.rpar) | ||||||
| 		// p.inside_tuple = false
 | 		// p.inside_tuple = false
 | ||||||
| 		return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_') | 		return '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_') | ||||||
| 	} | 	} | ||||||
| 	// fn type
 | 	// fn type
 | ||||||
| 	if p.tok == .func { | 	if p.tok == .func { | ||||||
|  | @ -1366,16 +1368,19 @@ fn (p mut Parser) var_decl() { | ||||||
| 	// t := p.bool_expression()
 | 	// t := p.bool_expression()
 | ||||||
| 	p.var_decl_name = mr_var_name | 	p.var_decl_name = mr_var_name | ||||||
| 	t := p.gen_var_decl(mr_var_name, is_static) | 	t := p.gen_var_decl(mr_var_name, is_static) | ||||||
| 
 |  | ||||||
| 	mut types := [t] | 	mut types := [t] | ||||||
| 	// multiple returns
 | 	// multiple returns
 | ||||||
| 	if names.len > 1 { | 	if names.len > 1 { | ||||||
| 		// should we register __ret var?
 | 		// should we register __ret var?
 | ||||||
| 		types = t.replace('MultiReturn_', '').replace('_ZptrZ_', '*').split('_Z_') | 		types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') | ||||||
| 	} | 	} | ||||||
| 	for i, name in names { | 	for i, name in names { | ||||||
| 		typ := types[i] | 		typ := types[i] | ||||||
| 		if names.len > 1 { | 		if names.len > 1 { | ||||||
|  | 			if names.len != types.len { | ||||||
|  | 				mr_fn := p.cgen.cur_line.find_between('=', '(').trim_space() | ||||||
|  | 				p.error('assignment mismatch: ${names.len} variables but `$mr_fn` returns $types.len values.') | ||||||
|  | 			} | ||||||
| 			p.gen(';\n') | 			p.gen(';\n') | ||||||
| 			p.gen('$typ $name = ${mr_var_name}.var_$i') | 			p.gen('$typ $name = ${mr_var_name}.var_$i') | ||||||
| 		} | 		} | ||||||
|  | @ -3563,9 +3568,11 @@ fn (p mut Parser) return_st() { | ||||||
| 				p.check(.comma) | 				p.check(.comma) | ||||||
| 				types << p.bool_expression() | 				types << p.bool_expression() | ||||||
| 			} | 			} | ||||||
|  | 			mut cur_fn_typ_chk := p.cur_fn.typ | ||||||
| 			// multiple returns
 | 			// multiple returns
 | ||||||
| 			if types.len > 1 { | 			if types.len > 1 { | ||||||
| 				expr_type = 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_') | 				expr_type = types.join(',') | ||||||
|  | 				cur_fn_typ_chk = cur_fn_typ_chk.replace('_V_MulRet_', '').replace('_PTR_', '*').replace('_V_', ',') | ||||||
| 				ret_vals := p.cgen.cur_line.right(ph) | 				ret_vals := p.cgen.cur_line.right(ph) | ||||||
| 				mut ret_fields := '' | 				mut ret_fields := '' | ||||||
| 				for ret_val_idx, ret_val in ret_vals.split(' ') { | 				for ret_val_idx, ret_val in ret_vals.split(' ') { | ||||||
|  | @ -3574,7 +3581,7 @@ fn (p mut Parser) return_st() { | ||||||
| 					} | 					} | ||||||
| 					ret_fields += '.var_$ret_val_idx=$ret_val' | 					ret_fields += '.var_$ret_val_idx=$ret_val' | ||||||
| 				} | 				} | ||||||
| 				p.cgen.resetln('($expr_type){$ret_fields}') | 				p.cgen.resetln('($p.cur_fn.typ){$ret_fields}') | ||||||
| 			} | 			} | ||||||
| 			p.inside_return_expr = false | 			p.inside_return_expr = false | ||||||
| 			// Automatically wrap an object inside an option if the function
 | 			// Automatically wrap an object inside an option if the function
 | ||||||
|  | @ -3618,7 +3625,7 @@ fn (p mut Parser) return_st() { | ||||||
| 					p.genln('return $tmp;') | 					p.genln('return $tmp;') | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			p.check_types(expr_type, p.cur_fn.typ) | 			p.check_types(expr_type, cur_fn_typ_chk) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else { | 	else { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue