checker: minor cleanup in check_types.v (#13816)
parent
5b668dba2b
commit
1566f7f766
|
@ -4,7 +4,6 @@
|
||||||
module checker
|
module checker
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.token
|
|
||||||
|
|
||||||
// TODO: promote(), check_types(), symmetric_check() and check() overlap - should be rearranged
|
// TODO: promote(), check_types(), symmetric_check() and check() overlap - should be rearranged
|
||||||
pub fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
|
pub fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
|
||||||
|
@ -524,226 +523,6 @@ pub fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool {
|
||||||
return c.check_basic(left, right)
|
return c.check_basic(left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte {
|
|
||||||
if ftyp.has_flag(.optional) {
|
|
||||||
return `s`
|
|
||||||
} else if typ.is_float() {
|
|
||||||
return `g`
|
|
||||||
} else if typ.is_signed() || typ.is_int_literal() {
|
|
||||||
return `d`
|
|
||||||
} else if typ.is_unsigned() {
|
|
||||||
return `u`
|
|
||||||
} else if typ.is_pointer() {
|
|
||||||
return `p`
|
|
||||||
} else {
|
|
||||||
mut sym := c.table.sym(c.unwrap_generic(ftyp))
|
|
||||||
if sym.kind == .alias {
|
|
||||||
// string aliases should be printable
|
|
||||||
info := sym.info as ast.Alias
|
|
||||||
sym = c.table.sym(info.parent_type)
|
|
||||||
if info.parent_type == ast.string_type {
|
|
||||||
return `s`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sym.kind == .function {
|
|
||||||
return `s`
|
|
||||||
}
|
|
||||||
if ftyp in [ast.string_type, ast.bool_type]
|
|
||||||
|| sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .interface_, .none_]
|
|
||||||
|| ftyp.has_flag(.optional) || sym.has_method('str') {
|
|
||||||
return `s`
|
|
||||||
} else {
|
|
||||||
return `_`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) {
|
|
||||||
mut pos := token.Pos{}
|
|
||||||
match expr {
|
|
||||||
ast.Ident {
|
|
||||||
if typ.has_flag(.shared_f) {
|
|
||||||
if expr.name !in c.rlocked_names && expr.name !in c.locked_names {
|
|
||||||
action := if what == 'argument' { 'passed' } else { 'used' }
|
|
||||||
c.error('`$expr.name` is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
|
|
||||||
expr.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ast.SelectorExpr {
|
|
||||||
pos = expr.pos
|
|
||||||
if typ.has_flag(.shared_f) {
|
|
||||||
expr_name := '${expr.expr}.$expr.field_name'
|
|
||||||
if expr_name !in c.rlocked_names && expr_name !in c.locked_names {
|
|
||||||
action := if what == 'argument' { 'passed' } else { 'used' }
|
|
||||||
c.error('`$expr_name` is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
|
|
||||||
expr.pos)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
c.fail_if_unreadable(expr.expr, expr.expr_type, what)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.IndexExpr {
|
|
||||||
pos = expr.left.pos().extend(expr.pos)
|
|
||||||
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pos = expr.pos()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.has_flag(.shared_f) {
|
|
||||||
c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what',
|
|
||||||
pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
|
|
||||||
inside_println_arg_save := c.inside_println_arg
|
|
||||||
c.inside_println_arg = true
|
|
||||||
for i, expr in node.exprs {
|
|
||||||
ftyp := c.expr(expr)
|
|
||||||
if ftyp == ast.void_type {
|
|
||||||
c.error('expression does not return a value', expr.pos())
|
|
||||||
} else if ftyp == ast.char_type && ftyp.nr_muls() == 0 {
|
|
||||||
c.error('expression returning type `char` cannot be used in string interpolation directly, print its address or cast it to an integer instead',
|
|
||||||
expr.pos())
|
|
||||||
}
|
|
||||||
c.fail_if_unreadable(expr, ftyp, 'interpolation object')
|
|
||||||
node.expr_types << ftyp
|
|
||||||
ftyp_sym := c.table.sym(ftyp)
|
|
||||||
typ := if ftyp_sym.kind == .alias && !ftyp_sym.has_method('str') {
|
|
||||||
c.table.unalias_num_type(ftyp)
|
|
||||||
} else {
|
|
||||||
ftyp
|
|
||||||
}
|
|
||||||
mut fmt := node.fmts[i]
|
|
||||||
// analyze and validate format specifier
|
|
||||||
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `S`, `p`,
|
|
||||||
`b`, `_`] {
|
|
||||||
c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
|
|
||||||
}
|
|
||||||
if fmt == `_` { // set default representation for type if none has been given
|
|
||||||
fmt = c.get_default_fmt(ftyp, typ)
|
|
||||||
if fmt == `_` {
|
|
||||||
if typ != ast.void_type {
|
|
||||||
c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
|
|
||||||
node.fmt_poss[i])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
node.fmts[i] = fmt
|
|
||||||
node.need_fmts[i] = false
|
|
||||||
}
|
|
||||||
} else { // check if given format specifier is valid for type
|
|
||||||
if node.precisions[i] != 987698 && !typ.is_float() {
|
|
||||||
c.error('precision specification only valid for float types', node.fmt_poss[i])
|
|
||||||
}
|
|
||||||
if node.pluss[i] && !typ.is_number() {
|
|
||||||
c.error('plus prefix only allowed for numbers', node.fmt_poss[i])
|
|
||||||
}
|
|
||||||
if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`, `b`])
|
|
||||||
|| (typ.is_signed() && fmt !in [`d`, `x`, `X`, `o`, `c`, `b`])
|
|
||||||
|| (typ.is_int_literal()
|
|
||||||
&& fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`, `b`])
|
|
||||||
|| (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`])
|
|
||||||
|| (typ.is_pointer() && fmt !in [`p`, `x`, `X`])
|
|
||||||
|| (typ.is_string() && fmt !in [`s`, `S`])
|
|
||||||
|| (typ.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`) {
|
|
||||||
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
|
|
||||||
node.fmt_poss[i])
|
|
||||||
}
|
|
||||||
node.need_fmts[i] = fmt != c.get_default_fmt(ftyp, typ)
|
|
||||||
}
|
|
||||||
// check recursive str
|
|
||||||
if c.table.cur_fn.is_method && c.table.cur_fn.name == 'str'
|
|
||||||
&& c.table.cur_fn.receiver.name == expr.str() {
|
|
||||||
c.error('cannot call `str()` method recursively', expr.pos())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.inside_println_arg = inside_println_arg_save
|
|
||||||
return ast.string_type
|
|
||||||
}
|
|
||||||
|
|
||||||
const unicode_lit_overflow_message = 'unicode character exceeds max allowed value of 0x10ffff, consider using a unicode literal (\\u####)'
|
|
||||||
|
|
||||||
// unicode character literals are limited to a maximum value of 0x10ffff
|
|
||||||
// https://stackoverflow.com/questions/52203351/why-unicode-is-restricted-to-0x10ffff
|
|
||||||
pub fn (mut c Checker) string_lit(mut node ast.StringLiteral) ast.Type {
|
|
||||||
mut idx := 0
|
|
||||||
for idx < node.val.len {
|
|
||||||
match node.val[idx] {
|
|
||||||
`\\` {
|
|
||||||
mut start_pos := token.Pos{
|
|
||||||
...node.pos
|
|
||||||
col: node.pos.col + 1 + idx
|
|
||||||
}
|
|
||||||
start_idx := idx
|
|
||||||
idx++
|
|
||||||
next_ch := node.val[idx] or { return ast.string_type }
|
|
||||||
if next_ch == `u` {
|
|
||||||
idx++
|
|
||||||
mut ch := node.val[idx] or { return ast.string_type }
|
|
||||||
mut hex_char_count := 0
|
|
||||||
for ch.is_hex_digit() {
|
|
||||||
hex_char_count++
|
|
||||||
end_pos := token.Pos{
|
|
||||||
...start_pos
|
|
||||||
len: idx + 1 - start_idx
|
|
||||||
}
|
|
||||||
match hex_char_count {
|
|
||||||
1...5 {}
|
|
||||||
6 {
|
|
||||||
first_digit := node.val[idx - 5] - 48
|
|
||||||
second_digit := node.val[idx - 4] - 48
|
|
||||||
if first_digit > 1 {
|
|
||||||
c.error(checker.unicode_lit_overflow_message, end_pos)
|
|
||||||
} else if first_digit == 1 && second_digit > 0 {
|
|
||||||
c.error(checker.unicode_lit_overflow_message, end_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.error(checker.unicode_lit_overflow_message, end_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idx++
|
|
||||||
ch = node.val[idx] or { return ast.string_type }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ast.string_type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut c Checker) int_lit(mut node ast.IntegerLiteral) ast.Type {
|
|
||||||
if node.val.len < 17 {
|
|
||||||
// can not be a too large number, no need for more expensive checks
|
|
||||||
return ast.int_literal_type
|
|
||||||
}
|
|
||||||
lit := node.val.replace('_', '').all_after('-')
|
|
||||||
is_neg := node.val.starts_with('-')
|
|
||||||
limit := if is_neg { '9223372036854775808' } else { '18446744073709551615' }
|
|
||||||
message := 'integer literal $node.val overflows int'
|
|
||||||
|
|
||||||
if lit.len > limit.len {
|
|
||||||
c.error(message, node.pos)
|
|
||||||
} else if lit.len == limit.len {
|
|
||||||
for i, digit in lit {
|
|
||||||
if digit > limit[i] {
|
|
||||||
c.error(message, node.pos)
|
|
||||||
} else if digit < limit[i] {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ast.int_literal_type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) {
|
pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) {
|
||||||
mut inferred_types := []ast.Type{}
|
mut inferred_types := []ast.Type{}
|
||||||
for gi, gt_name in func.generic_names {
|
for gi, gt_name in func.generic_names {
|
||||||
|
|
|
@ -4171,3 +4171,44 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) ? {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) {
|
||||||
|
mut pos := token.Pos{}
|
||||||
|
match expr {
|
||||||
|
ast.Ident {
|
||||||
|
if typ.has_flag(.shared_f) {
|
||||||
|
if expr.name !in c.rlocked_names && expr.name !in c.locked_names {
|
||||||
|
action := if what == 'argument' { 'passed' } else { 'used' }
|
||||||
|
c.error('`$expr.name` is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
|
||||||
|
expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ast.SelectorExpr {
|
||||||
|
pos = expr.pos
|
||||||
|
if typ.has_flag(.shared_f) {
|
||||||
|
expr_name := '${expr.expr}.$expr.field_name'
|
||||||
|
if expr_name !in c.rlocked_names && expr_name !in c.locked_names {
|
||||||
|
action := if what == 'argument' { 'passed' } else { 'used' }
|
||||||
|
c.error('`$expr_name` is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
|
||||||
|
expr.pos)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.fail_if_unreadable(expr.expr, expr.expr_type, what)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.IndexExpr {
|
||||||
|
pos = expr.left.pos().extend(expr.pos)
|
||||||
|
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pos = expr.pos()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typ.has_flag(.shared_f) {
|
||||||
|
c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what',
|
||||||
|
pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module checker
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import v.token
|
||||||
|
|
||||||
|
pub fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte {
|
||||||
|
if ftyp.has_flag(.optional) {
|
||||||
|
return `s`
|
||||||
|
} else if typ.is_float() {
|
||||||
|
return `g`
|
||||||
|
} else if typ.is_signed() || typ.is_int_literal() {
|
||||||
|
return `d`
|
||||||
|
} else if typ.is_unsigned() {
|
||||||
|
return `u`
|
||||||
|
} else if typ.is_pointer() {
|
||||||
|
return `p`
|
||||||
|
} else {
|
||||||
|
mut sym := c.table.sym(c.unwrap_generic(ftyp))
|
||||||
|
if sym.kind == .alias {
|
||||||
|
// string aliases should be printable
|
||||||
|
info := sym.info as ast.Alias
|
||||||
|
sym = c.table.sym(info.parent_type)
|
||||||
|
if info.parent_type == ast.string_type {
|
||||||
|
return `s`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sym.kind == .function {
|
||||||
|
return `s`
|
||||||
|
}
|
||||||
|
if ftyp in [ast.string_type, ast.bool_type]
|
||||||
|
|| sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .interface_, .none_]
|
||||||
|
|| ftyp.has_flag(.optional) || sym.has_method('str') {
|
||||||
|
return `s`
|
||||||
|
} else {
|
||||||
|
return `_`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
|
||||||
|
inside_println_arg_save := c.inside_println_arg
|
||||||
|
c.inside_println_arg = true
|
||||||
|
for i, expr in node.exprs {
|
||||||
|
ftyp := c.expr(expr)
|
||||||
|
if ftyp == ast.void_type {
|
||||||
|
c.error('expression does not return a value', expr.pos())
|
||||||
|
} else if ftyp == ast.char_type && ftyp.nr_muls() == 0 {
|
||||||
|
c.error('expression returning type `char` cannot be used in string interpolation directly, print its address or cast it to an integer instead',
|
||||||
|
expr.pos())
|
||||||
|
}
|
||||||
|
c.fail_if_unreadable(expr, ftyp, 'interpolation object')
|
||||||
|
node.expr_types << ftyp
|
||||||
|
ftyp_sym := c.table.sym(ftyp)
|
||||||
|
typ := if ftyp_sym.kind == .alias && !ftyp_sym.has_method('str') {
|
||||||
|
c.table.unalias_num_type(ftyp)
|
||||||
|
} else {
|
||||||
|
ftyp
|
||||||
|
}
|
||||||
|
mut fmt := node.fmts[i]
|
||||||
|
// analyze and validate format specifier
|
||||||
|
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `S`, `p`,
|
||||||
|
`b`, `_`] {
|
||||||
|
c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
|
||||||
|
}
|
||||||
|
if fmt == `_` { // set default representation for type if none has been given
|
||||||
|
fmt = c.get_default_fmt(ftyp, typ)
|
||||||
|
if fmt == `_` {
|
||||||
|
if typ != ast.void_type {
|
||||||
|
c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
|
||||||
|
node.fmt_poss[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.fmts[i] = fmt
|
||||||
|
node.need_fmts[i] = false
|
||||||
|
}
|
||||||
|
} else { // check if given format specifier is valid for type
|
||||||
|
if node.precisions[i] != 987698 && !typ.is_float() {
|
||||||
|
c.error('precision specification only valid for float types', node.fmt_poss[i])
|
||||||
|
}
|
||||||
|
if node.pluss[i] && !typ.is_number() {
|
||||||
|
c.error('plus prefix only allowed for numbers', node.fmt_poss[i])
|
||||||
|
}
|
||||||
|
if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`, `b`])
|
||||||
|
|| (typ.is_signed() && fmt !in [`d`, `x`, `X`, `o`, `c`, `b`])
|
||||||
|
|| (typ.is_int_literal()
|
||||||
|
&& fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`, `b`])
|
||||||
|
|| (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`])
|
||||||
|
|| (typ.is_pointer() && fmt !in [`p`, `x`, `X`])
|
||||||
|
|| (typ.is_string() && fmt !in [`s`, `S`])
|
||||||
|
|| (typ.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`) {
|
||||||
|
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
|
||||||
|
node.fmt_poss[i])
|
||||||
|
}
|
||||||
|
node.need_fmts[i] = fmt != c.get_default_fmt(ftyp, typ)
|
||||||
|
}
|
||||||
|
// check recursive str
|
||||||
|
if c.table.cur_fn.is_method && c.table.cur_fn.name == 'str'
|
||||||
|
&& c.table.cur_fn.receiver.name == expr.str() {
|
||||||
|
c.error('cannot call `str()` method recursively', expr.pos())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.inside_println_arg = inside_println_arg_save
|
||||||
|
return ast.string_type
|
||||||
|
}
|
||||||
|
|
||||||
|
const unicode_lit_overflow_message = 'unicode character exceeds max allowed value of 0x10ffff, consider using a unicode literal (\\u####)'
|
||||||
|
|
||||||
|
// unicode character literals are limited to a maximum value of 0x10ffff
|
||||||
|
// https://stackoverflow.com/questions/52203351/why-unicode-is-restricted-to-0x10ffff
|
||||||
|
pub fn (mut c Checker) string_lit(mut node ast.StringLiteral) ast.Type {
|
||||||
|
mut idx := 0
|
||||||
|
for idx < node.val.len {
|
||||||
|
match node.val[idx] {
|
||||||
|
`\\` {
|
||||||
|
mut start_pos := token.Pos{
|
||||||
|
...node.pos
|
||||||
|
col: node.pos.col + 1 + idx
|
||||||
|
}
|
||||||
|
start_idx := idx
|
||||||
|
idx++
|
||||||
|
next_ch := node.val[idx] or { return ast.string_type }
|
||||||
|
if next_ch == `u` {
|
||||||
|
idx++
|
||||||
|
mut ch := node.val[idx] or { return ast.string_type }
|
||||||
|
mut hex_char_count := 0
|
||||||
|
for ch.is_hex_digit() {
|
||||||
|
hex_char_count++
|
||||||
|
end_pos := token.Pos{
|
||||||
|
...start_pos
|
||||||
|
len: idx + 1 - start_idx
|
||||||
|
}
|
||||||
|
match hex_char_count {
|
||||||
|
1...5 {}
|
||||||
|
6 {
|
||||||
|
first_digit := node.val[idx - 5] - 48
|
||||||
|
second_digit := node.val[idx - 4] - 48
|
||||||
|
if first_digit > 1 {
|
||||||
|
c.error(checker.unicode_lit_overflow_message, end_pos)
|
||||||
|
} else if first_digit == 1 && second_digit > 0 {
|
||||||
|
c.error(checker.unicode_lit_overflow_message, end_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c.error(checker.unicode_lit_overflow_message, end_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
ch = node.val[idx] or { return ast.string_type }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ast.string_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) int_lit(mut node ast.IntegerLiteral) ast.Type {
|
||||||
|
if node.val.len < 17 {
|
||||||
|
// can not be a too large number, no need for more expensive checks
|
||||||
|
return ast.int_literal_type
|
||||||
|
}
|
||||||
|
lit := node.val.replace('_', '').all_after('-')
|
||||||
|
is_neg := node.val.starts_with('-')
|
||||||
|
limit := if is_neg { '9223372036854775808' } else { '18446744073709551615' }
|
||||||
|
message := 'integer literal $node.val overflows int'
|
||||||
|
|
||||||
|
if lit.len > limit.len {
|
||||||
|
c.error(message, node.pos)
|
||||||
|
} else if lit.len == limit.len {
|
||||||
|
for i, digit in lit {
|
||||||
|
if digit > limit[i] {
|
||||||
|
c.error(message, node.pos)
|
||||||
|
} else if digit < limit[i] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast.int_literal_type
|
||||||
|
}
|
Loading…
Reference in New Issue