checker: check fn return type mismatch (#14081)
							parent
							
								
									4400efeb9f
								
							
						
					
					
						commit
						6164654d11
					
				|  | @ -32,7 +32,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	mut got_types := []ast.Type{} | 	mut got_types := []ast.Type{} | ||||||
| 	for expr in node.exprs { | 	mut expr_idxs := []int{} | ||||||
|  | 	for i, expr in node.exprs { | ||||||
| 		typ := c.expr(expr) | 		typ := c.expr(expr) | ||||||
| 		if typ == ast.void_type { | 		if typ == ast.void_type { | ||||||
| 			c.error('`$expr` used as value', node.pos) | 			c.error('`$expr` used as value', node.pos) | ||||||
|  | @ -42,9 +43,11 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { | ||||||
| 		if sym.kind == .multi_return { | 		if sym.kind == .multi_return { | ||||||
| 			for t in sym.mr_info().types { | 			for t in sym.mr_info().types { | ||||||
| 				got_types << t | 				got_types << t | ||||||
|  | 				expr_idxs << i | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			got_types << typ | 			got_types << typ | ||||||
|  | 			expr_idxs << i | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	node.types = got_types | 	node.types = got_types | ||||||
|  | @ -82,7 +85,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { | ||||||
| 		got_typ := c.unwrap_generic(got_types[i]) | 		got_typ := c.unwrap_generic(got_types[i]) | ||||||
| 		if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional) | 		if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional) | ||||||
| 			|| c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { | 			|| c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { | ||||||
| 			pos := node.exprs[i].pos() | 			pos := node.exprs[expr_idxs[i]].pos() | ||||||
| 			c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', | 			c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', | ||||||
| 				pos) | 				pos) | ||||||
| 		} | 		} | ||||||
|  | @ -93,19 +96,19 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { | ||||||
| 				if c.type_implements(got_typ, exp_type, node.pos) { | 				if c.type_implements(got_typ, exp_type, node.pos) { | ||||||
| 					if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_ | 					if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_ | ||||||
| 						&& !c.inside_unsafe { | 						&& !c.inside_unsafe { | ||||||
| 						c.mark_as_referenced(mut &node.exprs[i], true) | 						c.mark_as_referenced(mut &node.exprs[expr_idxs[i]], true) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			pos := node.exprs[i].pos() | 			pos := node.exprs[expr_idxs[i]].pos() | ||||||
| 			c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument', | 			c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument', | ||||||
| 				pos) | 				pos) | ||||||
| 		} | 		} | ||||||
| 		if (got_typ.is_ptr() || got_typ.is_pointer()) | 		if (got_typ.is_ptr() || got_typ.is_pointer()) | ||||||
| 			&& (!exp_type.is_ptr() && !exp_type.is_pointer()) { | 			&& (!exp_type.is_ptr() && !exp_type.is_pointer()) { | ||||||
| 			pos := node.exprs[i].pos() | 			pos := node.exprs[expr_idxs[i]].pos() | ||||||
| 			if node.exprs[i].is_auto_deref_var() { | 			if node.exprs[expr_idxs[i]].is_auto_deref_var() { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			c.error('fn `$c.table.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | 			c.error('fn `$c.table.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | ||||||
|  | @ -114,8 +117,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { | ||||||
| 		if (exp_type.is_ptr() || exp_type.is_pointer()) | 		if (exp_type.is_ptr() || exp_type.is_pointer()) | ||||||
| 			&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type | 			&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type | ||||||
| 			&& !c.pref.translated && !c.file.is_translated { | 			&& !c.pref.translated && !c.file.is_translated { | ||||||
| 			pos := node.exprs[i].pos() | 			pos := node.exprs[expr_idxs[i]].pos() | ||||||
| 			if node.exprs[i].is_auto_deref_var() { | 			if node.exprs[expr_idxs[i]].is_auto_deref_var() { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			c.error('fn `$c.table.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | 			c.error('fn `$c.table.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | ||||||
|  |  | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | vlib/v/checker/tests/fn_return_type_mismatch.vv:6:9: error: cannot use `i64` as type `int` in return argument | ||||||
|  |     4 | | ||||||
|  |     5 | fn func2() (int, int) { | ||||||
|  |     6 |     return func1() | ||||||
|  |       |            ~~~~~~~ | ||||||
|  |     7 | } | ||||||
|  |     8 | | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | fn func1() (i64, i64) { | ||||||
|  | 	return i64(1), i64(2) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() (int, int) { | ||||||
|  | 	return func1() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() {} | ||||||
		Loading…
	
		Reference in New Issue