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 {}
 | 
							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