checker: handle multireturn fn calls as if/match last expressions
							parent
							
								
									b5bf0eeac5
								
							
						
					
					
						commit
						7815a5495c
					
				| 
						 | 
				
			
			@ -1099,32 +1099,38 @@ pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
 | 
			
		|||
 | 
			
		||||
pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
 | 
			
		||||
	c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
 | 
			
		||||
	if assign_stmt.right[0] is ast.CallExpr {
 | 
			
		||||
		call_expr := assign_stmt.right[0] as ast.CallExpr
 | 
			
		||||
	right_first := assign_stmt.right[0]
 | 
			
		||||
	mut right_len := assign_stmt.right.len
 | 
			
		||||
	if right_first is ast.CallExpr || right_first is ast.IfExpr || right_first is ast.MatchExpr {
 | 
			
		||||
		right_type0 := c.expr(assign_stmt.right[0])
 | 
			
		||||
		assign_stmt.right_types = [right_type0]
 | 
			
		||||
		right_type_sym0 := c.table.get_type_symbol(right_type0)
 | 
			
		||||
		mut right_len := if right_type0 == table.void_type { 0 } else { assign_stmt.right.len }
 | 
			
		||||
		right_len = if right_type0 == table.void_type { 0 } else { right_len }
 | 
			
		||||
		if right_type_sym0.kind == .multi_return {
 | 
			
		||||
			assign_stmt.right_types = right_type_sym0.mr_info().types
 | 
			
		||||
			right_len = assign_stmt.right_types.len
 | 
			
		||||
		}
 | 
			
		||||
		if assign_stmt.left.len != right_len {
 | 
			
		||||
			if right_first is ast.CallExpr {
 | 
			
		||||
				call_expr := assign_stmt.right[0] as ast.CallExpr
 | 
			
		||||
				c.error('assignment mismatch: $assign_stmt.left.len variable(s) but `${call_expr.name}()` returns $right_len value(s)',
 | 
			
		||||
					assign_stmt.pos)
 | 
			
		||||
				return
 | 
			
		||||
		}
 | 
			
		||||
			} else {
 | 
			
		||||
		if assign_stmt.left.len != assign_stmt.right.len {
 | 
			
		||||
				c.error('assignment mismatch: $assign_stmt.left.len variable(s) $right_len value(s)',
 | 
			
		||||
					assign_stmt.pos)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if assign_stmt.left.len != right_len {
 | 
			
		||||
		c.error('assignment mismatch: $assign_stmt.left.len variable(s) $assign_stmt.right.len value(s)',
 | 
			
		||||
			assign_stmt.pos)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
	mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
 | 
			
		||||
	for i, _ in assign_stmt.left {
 | 
			
		||||
		mut ident := assign_stmt.left[i]
 | 
			
		||||
		if assign_stmt.right_types.len < assign_stmt.right.len {
 | 
			
		||||
		if assign_stmt.right_types.len < right_len {
 | 
			
		||||
			assign_stmt.right_types << c.expr(assign_stmt.right[i])
 | 
			
		||||
		}
 | 
			
		||||
		val_type := assign_stmt.right_types[i]
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,7 +1999,7 @@ pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
 | 
			
		|||
	}
 | 
			
		||||
	if node.has_else && node.is_expr {
 | 
			
		||||
		last_branch := node.branches[node.branches.len - 1]
 | 
			
		||||
		if last_branch.stmts.len > 0 {
 | 
			
		||||
		if last_branch.stmts.len > 0 && node.branches[0].stmts.len > 0 {
 | 
			
		||||
			match last_branch.stmts[last_branch.stmts.len - 1] {
 | 
			
		||||
				ast.ExprStmt {
 | 
			
		||||
					// type_sym := p.table.get_type_symbol(it.typ)
 | 
			
		||||
| 
						 | 
				
			
			@ -2008,8 +2014,14 @@ pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
 | 
			
		|||
				}
 | 
			
		||||
				else {}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			c.error('`if` expression needs returns in both branches', node.pos)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// won't yet work due to eg: if true { println('foo') }
 | 
			
		||||
	/*if node.is_expr && !node.has_else {
 | 
			
		||||
		c.error('`if` expression needs `else` clause. remove return values or add `else`', node.pos)
 | 
			
		||||
	}*/
 | 
			
		||||
	return table.bool_type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -837,10 +837,18 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
 | 
			
		|||
		g.write('static ')
 | 
			
		||||
	}
 | 
			
		||||
	mut return_type := table.void_type
 | 
			
		||||
	if assign_stmt.right[0] is ast.CallExpr {
 | 
			
		||||
		it := assign_stmt.right[0] as ast.CallExpr
 | 
			
		||||
	match assign_stmt.right[0] {
 | 
			
		||||
		ast.CallExpr {
 | 
			
		||||
			return_type = it.return_type
 | 
			
		||||
		}
 | 
			
		||||
		ast.IfExpr {
 | 
			
		||||
			return_type = it.typ
 | 
			
		||||
		}
 | 
			
		||||
		ast.MatchExpr {
 | 
			
		||||
			return_type = it.return_type
 | 
			
		||||
		}
 | 
			
		||||
		else {}
 | 
			
		||||
	}
 | 
			
		||||
	mut is_multi := false
 | 
			
		||||
	// json_test failed w/o this check
 | 
			
		||||
	if return_type != 0 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
 | 
			
		||||
fn multireturner(n int, s string) (int, string) {
 | 
			
		||||
	return n + 1, s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_assign_multireturn_expression() {
 | 
			
		||||
	a, b := if true {
 | 
			
		||||
		multireturner(13, 'awesome')
 | 
			
		||||
	} else {
 | 
			
		||||
		multireturner(-1, 'notawesome')
 | 
			
		||||
	}
 | 
			
		||||
	assert a == 14
 | 
			
		||||
	assert b == 'awesome'
 | 
			
		||||
 | 
			
		||||
	c, d := if false {
 | 
			
		||||
		multireturner(-1, 'notawesome')
 | 
			
		||||
	} else if true {
 | 
			
		||||
		multireturner(17, 'awesomer')
 | 
			
		||||
	} else {
 | 
			
		||||
		multireturner(-1, 'notawesome')
 | 
			
		||||
	}
 | 
			
		||||
	assert c == 18
 | 
			
		||||
	assert d == 'awesomer'
 | 
			
		||||
 | 
			
		||||
	e, f := if false {
 | 
			
		||||
		multireturner(-1, 'notawesome')
 | 
			
		||||
	} else if false {
 | 
			
		||||
		multireturner(-1, 'notawesome')
 | 
			
		||||
	} else {
 | 
			
		||||
		multireturner(17, 'awesomer')
 | 
			
		||||
	}
 | 
			
		||||
	assert e == 18
 | 
			
		||||
	assert f == 'awesomer'
 | 
			
		||||
 | 
			
		||||
	g, h := match true {
 | 
			
		||||
		true { multireturner(0, 'good') }
 | 
			
		||||
		false { multireturner(100, 'bad') }
 | 
			
		||||
		else { multireturner(200, 'bad') }
 | 
			
		||||
	}
 | 
			
		||||
	assert g == 1
 | 
			
		||||
	assert h == 'good'
 | 
			
		||||
 | 
			
		||||
	i, j := match true {
 | 
			
		||||
		false { multireturner(100, 'bad') }
 | 
			
		||||
		else { multireturner(0, 'good') }
 | 
			
		||||
	}
 | 
			
		||||
	assert i == 1
 | 
			
		||||
	assert j == 'good'
 | 
			
		||||
 | 
			
		||||
	// TODO: returning non-function calls does not work yet due to parsing issues
 | 
			
		||||
	/*
 | 
			
		||||
	e, f := if true {
 | 
			
		||||
		1, 'awesome'
 | 
			
		||||
	} else {
 | 
			
		||||
		0, 'bad'
 | 
			
		||||
	}
 | 
			
		||||
	*/
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue