Skip to content

Commit ac3910b

Browse files
authored
checker: merge comptime_const_eval.v and noreturn.v into checker.v (#12573)
1 parent 9a2c563 commit ac3910b

3 files changed

Lines changed: 267 additions & 272 deletions

File tree

vlib/v/checker/checker.v

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8553,3 +8553,270 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Position) ? {
85538553
else {}
85548554
}
85558555
}
8556+
8557+
// comptime const eval
8558+
fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue {
8559+
if nlevel > 100 {
8560+
// protect against a too deep comptime eval recursion
8561+
return none
8562+
}
8563+
match expr {
8564+
ast.IntegerLiteral {
8565+
x := expr.val.u64()
8566+
if x > 9223372036854775807 {
8567+
return x
8568+
}
8569+
return expr.val.i64()
8570+
}
8571+
ast.StringLiteral {
8572+
return expr.val
8573+
}
8574+
ast.CharLiteral {
8575+
runes := expr.val.runes()
8576+
if runes.len > 0 {
8577+
return runes[0]
8578+
}
8579+
return none
8580+
}
8581+
ast.Ident {
8582+
if expr.obj is ast.ConstField {
8583+
// an existing constant?
8584+
return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
8585+
}
8586+
}
8587+
ast.CastExpr {
8588+
cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
8589+
if expr.typ == ast.i8_type {
8590+
return cast_expr_value.i8() or { return none }
8591+
}
8592+
if expr.typ == ast.i16_type {
8593+
return cast_expr_value.i16() or { return none }
8594+
}
8595+
if expr.typ == ast.int_type {
8596+
return cast_expr_value.int() or { return none }
8597+
}
8598+
if expr.typ == ast.i64_type {
8599+
return cast_expr_value.i64() or { return none }
8600+
}
8601+
//
8602+
if expr.typ == ast.byte_type {
8603+
return cast_expr_value.byte() or { return none }
8604+
}
8605+
if expr.typ == ast.u16_type {
8606+
return cast_expr_value.u16() or { return none }
8607+
}
8608+
if expr.typ == ast.u32_type {
8609+
return cast_expr_value.u32() or { return none }
8610+
}
8611+
if expr.typ == ast.u64_type {
8612+
return cast_expr_value.u64() or { return none }
8613+
}
8614+
//
8615+
if expr.typ == ast.f32_type {
8616+
return cast_expr_value.f32() or { return none }
8617+
}
8618+
if expr.typ == ast.f64_type {
8619+
return cast_expr_value.f64() or { return none }
8620+
}
8621+
}
8622+
ast.InfixExpr {
8623+
left := eval_comptime_const_expr(expr.left, nlevel + 1) ?
8624+
right := eval_comptime_const_expr(expr.right, nlevel + 1) ?
8625+
if left is string && right is string {
8626+
match expr.op {
8627+
.plus {
8628+
return left + right
8629+
}
8630+
else {
8631+
return none
8632+
}
8633+
}
8634+
} else if left is u64 && right is i64 {
8635+
match expr.op {
8636+
.plus { return i64(left) + i64(right) }
8637+
.minus { return i64(left) - i64(right) }
8638+
.mul { return i64(left) * i64(right) }
8639+
.div { return i64(left) / i64(right) }
8640+
.mod { return i64(left) % i64(right) }
8641+
.xor { return i64(left) ^ i64(right) }
8642+
.pipe { return i64(left) | i64(right) }
8643+
.amp { return i64(left) & i64(right) }
8644+
.left_shift { return i64(left) << i64(right) }
8645+
.right_shift { return i64(left) >> i64(right) }
8646+
else { return none }
8647+
}
8648+
} else if left is i64 && right is u64 {
8649+
match expr.op {
8650+
.plus { return i64(left) + i64(right) }
8651+
.minus { return i64(left) - i64(right) }
8652+
.mul { return i64(left) * i64(right) }
8653+
.div { return i64(left) / i64(right) }
8654+
.mod { return i64(left) % i64(right) }
8655+
.xor { return i64(left) ^ i64(right) }
8656+
.pipe { return i64(left) | i64(right) }
8657+
.amp { return i64(left) & i64(right) }
8658+
.left_shift { return i64(left) << i64(right) }
8659+
.right_shift { return i64(left) >> i64(right) }
8660+
else { return none }
8661+
}
8662+
} else if left is u64 && right is u64 {
8663+
match expr.op {
8664+
.plus { return left + right }
8665+
.minus { return left - right }
8666+
.mul { return left * right }
8667+
.div { return left / right }
8668+
.mod { return left % right }
8669+
.xor { return left ^ right }
8670+
.pipe { return left | right }
8671+
.amp { return left & right }
8672+
.left_shift { return left << right }
8673+
.right_shift { return left >> right }
8674+
else { return none }
8675+
}
8676+
} else if left is i64 && right is i64 {
8677+
match expr.op {
8678+
.plus { return left + right }
8679+
.minus { return left - right }
8680+
.mul { return left * right }
8681+
.div { return left / right }
8682+
.mod { return left % right }
8683+
.xor { return left ^ right }
8684+
.pipe { return left | right }
8685+
.amp { return left & right }
8686+
.left_shift { return left << right }
8687+
.right_shift { return left >> right }
8688+
else { return none }
8689+
}
8690+
} else if left is byte && right is byte {
8691+
match expr.op {
8692+
.plus { return left + right }
8693+
.minus { return left - right }
8694+
.mul { return left * right }
8695+
.div { return left / right }
8696+
.mod { return left % right }
8697+
.xor { return left ^ right }
8698+
.pipe { return left | right }
8699+
.amp { return left & right }
8700+
.left_shift { return left << right }
8701+
.right_shift { return left >> right }
8702+
else { return none }
8703+
}
8704+
}
8705+
}
8706+
else {
8707+
// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
8708+
return none
8709+
}
8710+
}
8711+
return none
8712+
}
8713+
8714+
fn (mut c Checker) check_noreturn_fn_decl(mut node ast.FnDecl) {
8715+
if !node.is_noreturn {
8716+
return
8717+
}
8718+
if node.no_body {
8719+
return
8720+
}
8721+
if node.return_type != ast.void_type {
8722+
c.error('[noreturn] functions cannot have return types', node.pos)
8723+
}
8724+
if uses_return_stmt(node.stmts) {
8725+
c.error('[noreturn] functions cannot use return statements', node.pos)
8726+
}
8727+
if node.stmts.len != 0 {
8728+
mut is_valid_end_of_noreturn_fn := false
8729+
last_stmt := node.stmts.last()
8730+
match last_stmt {
8731+
ast.ExprStmt {
8732+
if last_stmt.expr is ast.CallExpr {
8733+
if last_stmt.expr.should_be_skipped {
8734+
c.error('[noreturn] functions cannot end with a skippable `[if ..]` call',
8735+
last_stmt.pos)
8736+
return
8737+
}
8738+
if last_stmt.expr.is_noreturn {
8739+
is_valid_end_of_noreturn_fn = true
8740+
}
8741+
}
8742+
}
8743+
ast.ForStmt {
8744+
if last_stmt.is_inf && last_stmt.stmts.len == 0 {
8745+
is_valid_end_of_noreturn_fn = true
8746+
}
8747+
}
8748+
else {}
8749+
}
8750+
if !is_valid_end_of_noreturn_fn {
8751+
c.error('[noreturn] functions should end with a call to another [noreturn] function, or with an infinite `for {}` loop',
8752+
last_stmt.pos)
8753+
return
8754+
}
8755+
}
8756+
}
8757+
8758+
fn uses_return_stmt(stmts []ast.Stmt) bool {
8759+
if stmts.len == 0 {
8760+
return false
8761+
}
8762+
for stmt in stmts {
8763+
match stmt {
8764+
ast.Return {
8765+
return true
8766+
}
8767+
ast.Block {
8768+
if uses_return_stmt(stmt.stmts) {
8769+
return true
8770+
}
8771+
}
8772+
ast.ExprStmt {
8773+
match stmt.expr {
8774+
ast.CallExpr {
8775+
if uses_return_stmt(stmt.expr.or_block.stmts) {
8776+
return true
8777+
}
8778+
}
8779+
ast.MatchExpr {
8780+
for b in stmt.expr.branches {
8781+
if uses_return_stmt(b.stmts) {
8782+
return true
8783+
}
8784+
}
8785+
}
8786+
ast.SelectExpr {
8787+
for b in stmt.expr.branches {
8788+
if uses_return_stmt(b.stmts) {
8789+
return true
8790+
}
8791+
}
8792+
}
8793+
ast.IfExpr {
8794+
for b in stmt.expr.branches {
8795+
if uses_return_stmt(b.stmts) {
8796+
return true
8797+
}
8798+
}
8799+
}
8800+
else {}
8801+
}
8802+
}
8803+
ast.ForStmt {
8804+
if uses_return_stmt(stmt.stmts) {
8805+
return true
8806+
}
8807+
}
8808+
ast.ForCStmt {
8809+
if uses_return_stmt(stmt.stmts) {
8810+
return true
8811+
}
8812+
}
8813+
ast.ForInStmt {
8814+
if uses_return_stmt(stmt.stmts) {
8815+
return true
8816+
}
8817+
}
8818+
else {}
8819+
}
8820+
}
8821+
return false
8822+
}

0 commit comments

Comments
 (0)