checker: merge comptime_const_eval.v and noreturn.v into checker.v (#12573)
							parent
							
								
									9a2c563735
								
							
						
					
					
						commit
						ac3910b8c2
					
				| 
						 | 
				
			
			@ -8553,3 +8553,270 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Position) ? {
 | 
			
		|||
		else {}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// comptime const eval
 | 
			
		||||
fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue {
 | 
			
		||||
	if nlevel > 100 {
 | 
			
		||||
		// protect against a too deep comptime eval recursion
 | 
			
		||||
		return none
 | 
			
		||||
	}
 | 
			
		||||
	match expr {
 | 
			
		||||
		ast.IntegerLiteral {
 | 
			
		||||
			x := expr.val.u64()
 | 
			
		||||
			if x > 9223372036854775807 {
 | 
			
		||||
				return x
 | 
			
		||||
			}
 | 
			
		||||
			return expr.val.i64()
 | 
			
		||||
		}
 | 
			
		||||
		ast.StringLiteral {
 | 
			
		||||
			return expr.val
 | 
			
		||||
		}
 | 
			
		||||
		ast.CharLiteral {
 | 
			
		||||
			runes := expr.val.runes()
 | 
			
		||||
			if runes.len > 0 {
 | 
			
		||||
				return runes[0]
 | 
			
		||||
			}
 | 
			
		||||
			return none
 | 
			
		||||
		}
 | 
			
		||||
		ast.Ident {
 | 
			
		||||
			if expr.obj is ast.ConstField {
 | 
			
		||||
				// an existing constant?
 | 
			
		||||
				return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ast.CastExpr {
 | 
			
		||||
			cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
 | 
			
		||||
			if expr.typ == ast.i8_type {
 | 
			
		||||
				return cast_expr_value.i8() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.i16_type {
 | 
			
		||||
				return cast_expr_value.i16() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.int_type {
 | 
			
		||||
				return cast_expr_value.int() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.i64_type {
 | 
			
		||||
				return cast_expr_value.i64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			//
 | 
			
		||||
			if expr.typ == ast.byte_type {
 | 
			
		||||
				return cast_expr_value.byte() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u16_type {
 | 
			
		||||
				return cast_expr_value.u16() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u32_type {
 | 
			
		||||
				return cast_expr_value.u32() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u64_type {
 | 
			
		||||
				return cast_expr_value.u64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			//
 | 
			
		||||
			if expr.typ == ast.f32_type {
 | 
			
		||||
				return cast_expr_value.f32() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.f64_type {
 | 
			
		||||
				return cast_expr_value.f64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ast.InfixExpr {
 | 
			
		||||
			left := eval_comptime_const_expr(expr.left, nlevel + 1) ?
 | 
			
		||||
			right := eval_comptime_const_expr(expr.right, nlevel + 1) ?
 | 
			
		||||
			if left is string && right is string {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus {
 | 
			
		||||
						return left + right
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						return none
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is u64 && right is i64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return i64(left) + i64(right) }
 | 
			
		||||
					.minus { return i64(left) - i64(right) }
 | 
			
		||||
					.mul { return i64(left) * i64(right) }
 | 
			
		||||
					.div { return i64(left) / i64(right) }
 | 
			
		||||
					.mod { return i64(left) % i64(right) }
 | 
			
		||||
					.xor { return i64(left) ^ i64(right) }
 | 
			
		||||
					.pipe { return i64(left) | i64(right) }
 | 
			
		||||
					.amp { return i64(left) & i64(right) }
 | 
			
		||||
					.left_shift { return i64(left) << i64(right) }
 | 
			
		||||
					.right_shift { return i64(left) >> i64(right) }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is i64 && right is u64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return i64(left) + i64(right) }
 | 
			
		||||
					.minus { return i64(left) - i64(right) }
 | 
			
		||||
					.mul { return i64(left) * i64(right) }
 | 
			
		||||
					.div { return i64(left) / i64(right) }
 | 
			
		||||
					.mod { return i64(left) % i64(right) }
 | 
			
		||||
					.xor { return i64(left) ^ i64(right) }
 | 
			
		||||
					.pipe { return i64(left) | i64(right) }
 | 
			
		||||
					.amp { return i64(left) & i64(right) }
 | 
			
		||||
					.left_shift { return i64(left) << i64(right) }
 | 
			
		||||
					.right_shift { return i64(left) >> i64(right) }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is u64 && right is u64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is i64 && right is i64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is byte && right is byte {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
 | 
			
		||||
			return none
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return none
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut c Checker) check_noreturn_fn_decl(mut node ast.FnDecl) {
 | 
			
		||||
	if !node.is_noreturn {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if node.no_body {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if node.return_type != ast.void_type {
 | 
			
		||||
		c.error('[noreturn] functions cannot have return types', node.pos)
 | 
			
		||||
	}
 | 
			
		||||
	if uses_return_stmt(node.stmts) {
 | 
			
		||||
		c.error('[noreturn] functions cannot use return statements', node.pos)
 | 
			
		||||
	}
 | 
			
		||||
	if node.stmts.len != 0 {
 | 
			
		||||
		mut is_valid_end_of_noreturn_fn := false
 | 
			
		||||
		last_stmt := node.stmts.last()
 | 
			
		||||
		match last_stmt {
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				if last_stmt.expr is ast.CallExpr {
 | 
			
		||||
					if last_stmt.expr.should_be_skipped {
 | 
			
		||||
						c.error('[noreturn] functions cannot end with a skippable `[if ..]` call',
 | 
			
		||||
							last_stmt.pos)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
					if last_stmt.expr.is_noreturn {
 | 
			
		||||
						is_valid_end_of_noreturn_fn = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForStmt {
 | 
			
		||||
				if last_stmt.is_inf && last_stmt.stmts.len == 0 {
 | 
			
		||||
					is_valid_end_of_noreturn_fn = true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
		if !is_valid_end_of_noreturn_fn {
 | 
			
		||||
			c.error('[noreturn] functions should end with a call to another [noreturn] function, or with an infinite `for {}` loop',
 | 
			
		||||
				last_stmt.pos)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn uses_return_stmt(stmts []ast.Stmt) bool {
 | 
			
		||||
	if stmts.len == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for stmt in stmts {
 | 
			
		||||
		match stmt {
 | 
			
		||||
			ast.Return {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			ast.Block {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				match stmt.expr {
 | 
			
		||||
					ast.CallExpr {
 | 
			
		||||
						if uses_return_stmt(stmt.expr.or_block.stmts) {
 | 
			
		||||
							return true
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.MatchExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.SelectExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.IfExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else {}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForCStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForInStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,159 +0,0 @@
 | 
			
		|||
module checker
 | 
			
		||||
 | 
			
		||||
import v.ast
 | 
			
		||||
 | 
			
		||||
fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue {
 | 
			
		||||
	if nlevel > 100 {
 | 
			
		||||
		// protect against a too deep comptime eval recursion
 | 
			
		||||
		return none
 | 
			
		||||
	}
 | 
			
		||||
	match expr {
 | 
			
		||||
		ast.IntegerLiteral {
 | 
			
		||||
			x := expr.val.u64()
 | 
			
		||||
			if x > 9223372036854775807 {
 | 
			
		||||
				return x
 | 
			
		||||
			}
 | 
			
		||||
			return expr.val.i64()
 | 
			
		||||
		}
 | 
			
		||||
		ast.StringLiteral {
 | 
			
		||||
			return expr.val
 | 
			
		||||
		}
 | 
			
		||||
		ast.CharLiteral {
 | 
			
		||||
			runes := expr.val.runes()
 | 
			
		||||
			if runes.len > 0 {
 | 
			
		||||
				return runes[0]
 | 
			
		||||
			}
 | 
			
		||||
			return none
 | 
			
		||||
		}
 | 
			
		||||
		ast.Ident {
 | 
			
		||||
			if expr.obj is ast.ConstField {
 | 
			
		||||
				// an existing constant?
 | 
			
		||||
				return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ast.CastExpr {
 | 
			
		||||
			cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
 | 
			
		||||
			if expr.typ == ast.i8_type {
 | 
			
		||||
				return cast_expr_value.i8() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.i16_type {
 | 
			
		||||
				return cast_expr_value.i16() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.int_type {
 | 
			
		||||
				return cast_expr_value.int() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.i64_type {
 | 
			
		||||
				return cast_expr_value.i64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			//
 | 
			
		||||
			if expr.typ == ast.byte_type {
 | 
			
		||||
				return cast_expr_value.byte() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u16_type {
 | 
			
		||||
				return cast_expr_value.u16() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u32_type {
 | 
			
		||||
				return cast_expr_value.u32() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.u64_type {
 | 
			
		||||
				return cast_expr_value.u64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			//
 | 
			
		||||
			if expr.typ == ast.f32_type {
 | 
			
		||||
				return cast_expr_value.f32() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
			if expr.typ == ast.f64_type {
 | 
			
		||||
				return cast_expr_value.f64() or { return none }
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ast.InfixExpr {
 | 
			
		||||
			left := eval_comptime_const_expr(expr.left, nlevel + 1) ?
 | 
			
		||||
			right := eval_comptime_const_expr(expr.right, nlevel + 1) ?
 | 
			
		||||
			if left is string && right is string {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus {
 | 
			
		||||
						return left + right
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						return none
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is u64 && right is i64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return i64(left) + i64(right) }
 | 
			
		||||
					.minus { return i64(left) - i64(right) }
 | 
			
		||||
					.mul { return i64(left) * i64(right) }
 | 
			
		||||
					.div { return i64(left) / i64(right) }
 | 
			
		||||
					.mod { return i64(left) % i64(right) }
 | 
			
		||||
					.xor { return i64(left) ^ i64(right) }
 | 
			
		||||
					.pipe { return i64(left) | i64(right) }
 | 
			
		||||
					.amp { return i64(left) & i64(right) }
 | 
			
		||||
					.left_shift { return i64(left) << i64(right) }
 | 
			
		||||
					.right_shift { return i64(left) >> i64(right) }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is i64 && right is u64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return i64(left) + i64(right) }
 | 
			
		||||
					.minus { return i64(left) - i64(right) }
 | 
			
		||||
					.mul { return i64(left) * i64(right) }
 | 
			
		||||
					.div { return i64(left) / i64(right) }
 | 
			
		||||
					.mod { return i64(left) % i64(right) }
 | 
			
		||||
					.xor { return i64(left) ^ i64(right) }
 | 
			
		||||
					.pipe { return i64(left) | i64(right) }
 | 
			
		||||
					.amp { return i64(left) & i64(right) }
 | 
			
		||||
					.left_shift { return i64(left) << i64(right) }
 | 
			
		||||
					.right_shift { return i64(left) >> i64(right) }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is u64 && right is u64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is i64 && right is i64 {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			} else if left is byte && right is byte {
 | 
			
		||||
				match expr.op {
 | 
			
		||||
					.plus { return left + right }
 | 
			
		||||
					.minus { return left - right }
 | 
			
		||||
					.mul { return left * right }
 | 
			
		||||
					.div { return left / right }
 | 
			
		||||
					.mod { return left % right }
 | 
			
		||||
					.xor { return left ^ right }
 | 
			
		||||
					.pipe { return left | right }
 | 
			
		||||
					.amp { return left & right }
 | 
			
		||||
					.left_shift { return left << right }
 | 
			
		||||
					.right_shift { return left >> right }
 | 
			
		||||
					else { return none }
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
 | 
			
		||||
			return none
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return none
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,113 +0,0 @@
 | 
			
		|||
module checker
 | 
			
		||||
 | 
			
		||||
import v.ast
 | 
			
		||||
 | 
			
		||||
fn (mut c Checker) check_noreturn_fn_decl(mut node ast.FnDecl) {
 | 
			
		||||
	if !node.is_noreturn {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if node.no_body {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if node.return_type != ast.void_type {
 | 
			
		||||
		c.error('[noreturn] functions cannot have return types', node.pos)
 | 
			
		||||
	}
 | 
			
		||||
	if uses_return_stmt(node.stmts) {
 | 
			
		||||
		c.error('[noreturn] functions cannot use return statements', node.pos)
 | 
			
		||||
	}
 | 
			
		||||
	if node.stmts.len != 0 {
 | 
			
		||||
		mut is_valid_end_of_noreturn_fn := false
 | 
			
		||||
		last_stmt := node.stmts.last()
 | 
			
		||||
		match last_stmt {
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				if last_stmt.expr is ast.CallExpr {
 | 
			
		||||
					if last_stmt.expr.should_be_skipped {
 | 
			
		||||
						c.error('[noreturn] functions cannot end with a skippable `[if ..]` call',
 | 
			
		||||
							last_stmt.pos)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
					if last_stmt.expr.is_noreturn {
 | 
			
		||||
						is_valid_end_of_noreturn_fn = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForStmt {
 | 
			
		||||
				if last_stmt.is_inf && last_stmt.stmts.len == 0 {
 | 
			
		||||
					is_valid_end_of_noreturn_fn = true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
		if !is_valid_end_of_noreturn_fn {
 | 
			
		||||
			c.error('[noreturn] functions should end with a call to another [noreturn] function, or with an infinite `for {}` loop',
 | 
			
		||||
				last_stmt.pos)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn uses_return_stmt(stmts []ast.Stmt) bool {
 | 
			
		||||
	if stmts.len == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for stmt in stmts {
 | 
			
		||||
		match stmt {
 | 
			
		||||
			ast.Return {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			ast.Block {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				match stmt.expr {
 | 
			
		||||
					ast.CallExpr {
 | 
			
		||||
						if uses_return_stmt(stmt.expr.or_block.stmts) {
 | 
			
		||||
							return true
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.MatchExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.SelectExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					ast.IfExpr {
 | 
			
		||||
						for b in stmt.expr.branches {
 | 
			
		||||
							if uses_return_stmt(b.stmts) {
 | 
			
		||||
								return true
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else {}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForCStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.ForInStmt {
 | 
			
		||||
				if uses_return_stmt(stmt.stmts) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue