Skip to content

Commit

Permalink
ast: improve Type and TypeFlag related operations (#22107)
Browse files Browse the repository at this point in the history
  • Loading branch information
spytheman authored Aug 23, 2024
1 parent 637291d commit 19c5670
Show file tree
Hide file tree
Showing 25 changed files with 98 additions and 90 deletions.
5 changes: 2 additions & 3 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ pub fn (mut t Table) free() {
}
}

pub const invalid_type_idx = -1
pub const fn_type_escape_seq = [' ', '', '(', '_', ')', '']
pub const map_cname_escape_seq = ['[', '_T_', ', ', '_', ']', '']

Expand Down Expand Up @@ -768,7 +767,7 @@ fn (mut t Table) rewrite_already_registered_symbol(typ TypeSymbol, existing_idx
}
return existing_idx
}
return ast.invalid_type_idx
return invalid_type_idx
}

@[inline]
Expand Down Expand Up @@ -1559,7 +1558,7 @@ pub fn (mut t Table) resolve_generic_static_type_name(fn_name string, generic_na
valid_generic := util.is_generic_type_name(generic_name)
&& generic_name in generic_names
if valid_generic {
name_type := Type(t.find_type_idx(generic_name)).set_flag(.generic)
name_type := idx_to_type(t.find_type_idx(generic_name)).set_flag(.generic)
if typ := t.resolve_generic_to_concrete(name_type, generic_names, concrete_types) {
return '${t.type_to_str(typ)}${fn_name[index..]}'
}
Expand Down
71 changes: 40 additions & 31 deletions vlib/v/ast/types.v
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import strings
import v.pref
import v.token

pub type Type = int
pub type Type = u32

@[inline]
pub fn idx_to_type(idx int) Type {
return Type(u32(idx))
}

pub struct UnknownTypeInfo {}

Expand Down Expand Up @@ -110,13 +115,13 @@ pub mut:
}

// max of 8
pub enum TypeFlag {
option
result
variadic
generic
shared_f
atomic_f
pub enum TypeFlag as u32 {
option = 1 << 24
result = 1 << 25
variadic = 1 << 26
generic = 1 << 27
shared_f = 1 << 28
atomic_f = 1 << 29
}

/*
Expand Down Expand Up @@ -307,15 +312,15 @@ pub fn (t Type) is_full() bool {
// return nr_muls for `t`
@[inline]
pub fn (t Type) nr_muls() int {
return (int(t) >> 16) & 0xff
return (t >> 16) & 0xff
}

// return true if `t` is a pointer (nr_muls>0)
@[inline]
pub fn (t Type) is_ptr() bool {
// any normal pointer, i.e. &Type, &&Type etc;
// Note: voidptr, charptr and byteptr are NOT included!
return (int(t) >> 16) & 0xff != 0
return (t >> 16) & 0xff != 0
}

// is_pointer returns true if `typ` is any of the builtin pointer types (voidptr, byteptr, charptr)
Expand All @@ -334,7 +339,7 @@ pub fn (typ Type) is_voidptr() bool {
// is_any_kind_of_pointer returns true if t is any type of pointer
@[inline]
pub fn (t Type) is_any_kind_of_pointer() bool {
return (int(t) >> 16) & 0xff != 0 || (u16(t) & 0xffff) in ast.pointer_type_idxs
return (t >> 16) & 0xff != 0 || (u16(t) & 0xffff) in ast.pointer_type_idxs
}

// set nr_muls on `t` and return it
Expand All @@ -343,50 +348,56 @@ pub fn (t Type) set_nr_muls(nr_muls int) Type {
if nr_muls < 0 || nr_muls > 255 {
panic('set_nr_muls: nr_muls must be between 0 & 255')
}
return int(t) & 0xff00ffff | int(u32(nr_muls) << 16)
return t & 0xff00ffff | u32(nr_muls) << 16
}

// increments nr_muls on `t` and return it
@[inline]
pub fn (t Type) ref() Type {
nr_muls := (int(t) >> 16) & 0xff
nr_muls := (t >> 16) & 0xff
if nr_muls == 255 {
panic('ref: nr_muls is already at max of 255')
}
return int(t) & 0xff00ffff | int(u32(nr_muls + 1) << 16)
return t & 0xff00ffff | (nr_muls + 1) << 16
}

// decrement nr_muls on `t` and return it
@[inline]
pub fn (t Type) deref() Type {
nr_muls := (int(t) >> 16) & 0xff
nr_muls := (t >> 16) & 0xff
if nr_muls == 0 {
panic('deref: type `${t}` is not a pointer')
}
return int(t) & 0xff00ffff | int(u32(nr_muls - 1) << 16)
return t & 0xff00ffff | (nr_muls - 1) << 16
}

// set `flag` on `t` and return `t`
// has_flag returns whether the given named `flag` is set
@[inline]
pub fn (t Type) has_flag(flag TypeFlag) bool {
return (t & u32(flag)) != 0
}

// set_flag returns a new type, that is like the input `t`, but with the named `flag` set
@[inline]
pub fn (t Type) set_flag(flag TypeFlag) Type {
return int(t) | (1 << (int(flag) + 24))
return t | u32(flag)
}

// clear `flag` on `t` and return `t`
// clear_flag returns a new type, that is like `t`, but with the named `flag` cleared
@[inline]
pub fn (t Type) clear_flag(flag TypeFlag) Type {
return int(t) & ~(1 << (int(flag) + 24))
return t & ~(u32(flag))
}

// clear all flags or multi flags
// clear_flags returns a new type, based on `t`, but with cleared named `flags`
@[inline]
pub fn (t Type) clear_flags(flags ...TypeFlag) Type {
if flags.len == 0 {
return int(t) & 0xffffff
return t & 0xffffff
} else {
mut typ := int(t)
for flag in flags {
typ = typ & ~(1 << (int(flag) + 24))
typ = typ & ~(u32(flag))
}
return typ
}
Expand All @@ -395,18 +406,12 @@ pub fn (t Type) clear_flags(flags ...TypeFlag) Type {
// clear option and result flags
@[inline]
pub fn (t Type) clear_option_and_result() Type {
return u32(t) & ~0x0300_0000
}

// return true if `flag` is set on `t`
@[inline]
pub fn (t Type) has_flag(flag TypeFlag) bool {
return int(t) & (1 << (int(flag) + 24)) != 0
return t & ~0x0300_0000
}

@[inline]
pub fn (t Type) has_option_or_result() bool {
return u32(t) & 0x0300_0000 != 0
return t & 0x0300_0000 != 0
}

// debug returns a verbose representation of the information in ts, useful for tracing/debugging
Expand Down Expand Up @@ -594,6 +599,8 @@ pub fn (typ Type) is_bool() bool {
return typ.idx() == ast.bool_type_idx
}

pub const invalid_type_idx = -1
pub const no_type_idx = 0
pub const void_type_idx = 1
pub const voidptr_type_idx = 2
pub const byteptr_type_idx = 3
Expand Down Expand Up @@ -651,6 +658,8 @@ pub const number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i32_type_
rune_type_idx]
pub const pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx, nil_type_idx]

pub const invalid_type = idx_to_type(invalid_type_idx) // -1 is a purposefully invalid type, not by default, but to signify checker errors
pub const no_type = idx_to_type(no_type_idx) // 0 is an invalid type, but it is useful for initialising default ast.Type values, in fields or before loops
pub const void_type = new_type(void_type_idx)
pub const ovoid_type = new_type(void_type_idx).set_flag(.option) // the return type of `fn ()?`
pub const rvoid_type = new_type(void_type_idx).set_flag(.result) // the return type of `fn () !`
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/check_types.v
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type_ ast.Type, righ
// part of the quotient of E1/2^E2. If E1 has a signed type and
// a negative value, the resulting value is implementation-defined (ID).
left_sym_final := c.table.final_sym(left_type)
left_type_final := ast.Type(left_sym_final.idx)
left_type_final := ast.idx_to_type(left_sym_final.idx)
if !(c.is_generated || c.inside_unsafe || c.file.is_translated || c.pref.translated) {
if node.op == .left_shift && left_type_final.is_signed() {
c.note('shifting a value from a signed type `${left_sym_final.name}` can change the sign',
Expand Down
8 changes: 4 additions & 4 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ fn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos t
}

fn (mut c Checker) type_decl(node ast.TypeDecl) {
if node.typ == ast.invalid_type_idx && (node is ast.AliasTypeDecl || node is ast.SumTypeDecl) {
if node.typ == ast.invalid_type && (node is ast.AliasTypeDecl || node is ast.SumTypeDecl) {
typ_desc := if node is ast.AliasTypeDecl { 'alias' } else { 'sum type' }
c.error('cannot register ${typ_desc} `${node.name}`, another type with this name exists',
node.pos)
Expand Down Expand Up @@ -852,7 +852,7 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) {
return to_lock, pos
}
left_sym := c.table.sym(expr.left_type)
mut elem_type := ast.Type(0)
mut elem_type := ast.no_type
mut kind := ''
match left_sym.info {
ast.Array {
Expand Down Expand Up @@ -1469,7 +1469,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
valid_generic := util.is_generic_type_name(name) && c.table.cur_fn != unsafe { nil }
&& name in c.table.cur_fn.generic_names
if valid_generic {
name_type = ast.Type(c.table.find_type_idx(name)).set_flag(.generic)
name_type = ast.idx_to_type(c.table.find_type_idx(name)).set_flag(.generic)
}
}
ast.TypeOf {
Expand Down Expand Up @@ -1813,7 +1813,7 @@ fn (mut c Checker) const_decl(mut node ast.ConstDecl) {

fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
c.check_valid_pascal_case(node.name, 'enum name', node.pos)
if node.typ == ast.invalid_type_idx {
if node.typ == ast.invalid_type {
c.error('cannot register enum `${node.name}`, another type with this name exists',
node.pos)
return
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.push_new_comptime_info()
c.comptime.inside_comptime_for = true
if c.field_data_type == 0 {
c.field_data_type = ast.Type(c.table.find_type_idx('FieldData'))
c.field_data_type = ast.idx_to_type(c.table.find_type_idx('FieldData'))
}
c.comptime.comptime_for_field_value = field
c.comptime.comptime_for_field_var = node.val_var
Expand Down Expand Up @@ -298,7 +298,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.push_new_comptime_info()
c.comptime.inside_comptime_for = true
if c.enum_data_type == 0 {
c.enum_data_type = ast.Type(c.table.find_type_idx('EnumData'))
c.enum_data_type = ast.idx_to_type(c.table.find_type_idx('EnumData'))
}
c.comptime.comptime_for_enum_var = node.val_var
c.comptime.type_map[node.val_var] = c.enum_data_type
Expand Down Expand Up @@ -327,7 +327,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
}
} else if node.kind == .variants {
if c.variant_data_type == 0 {
c.variant_data_type = ast.Type(c.table.find_type_idx('VariantData'))
c.variant_data_type = ast.idx_to_type(c.table.find_type_idx('VariantData'))
}
mut variants := []ast.Type{}
if c.comptime.comptime_for_field_var != '' && typ == c.field_data_type {
Expand Down
14 changes: 7 additions & 7 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
}
}
}
if node.return_type != ast.Type(0) {
if node.return_type != ast.no_type {
if !c.ensure_type_exists(node.return_type, node.return_type_pos) {
return
}
Expand Down Expand Up @@ -886,7 +886,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
node.name = ''
c.expr(mut node.left)
left := node.left as ast.AnonFn
if left.typ != ast.Type(0) {
if left.typ != ast.no_type {
anon_fn_sym := c.table.sym(left.typ)
func = (anon_fn_sym.info as ast.FnType).func
found = true
Expand Down Expand Up @@ -1011,7 +1011,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
return ast.void_type
}

ret_typ := ast.Type(idx).set_flag(.option)
ret_typ := ast.idx_to_type(idx).set_flag(.option)
if node.args.len != 1 {
c.error('expected 1 argument, but got ${node.args.len}', node.pos)
} else {
Expand Down Expand Up @@ -2103,7 +2103,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
ast.Array {
typ := c.table.unaliased_type(final_left_sym.info.elem_type)
parent_type = ast.Type(c.table.find_or_register_array(typ))
parent_type = ast.idx_to_type(c.table.find_or_register_array(typ))
}
else {}
}
Expand Down Expand Up @@ -2357,7 +2357,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
node.should_be_skipped = c.evaluate_once_comptime_if_attribute(mut method.attrs[method.ctdefine_idx])
}
c.check_expected_arg_count(mut node, method) or { return method.return_type }
mut exp_arg_typ := ast.Type(0) // type of 1st arg for special builtin methods
mut exp_arg_typ := ast.no_type // type of 1st arg for special builtin methods
mut param_is_mut := false
mut no_type_promotion := false
if left_sym.info is ast.Chan {
Expand All @@ -2371,7 +2371,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}

for i, mut arg in node.args {
if i > 0 || exp_arg_typ == ast.Type(0) {
if i > 0 || exp_arg_typ == ast.no_type {
exp_arg_typ = if method.is_variadic && i >= method.params.len - 1 {
method.params.last().typ
} else {
Expand Down Expand Up @@ -3021,7 +3021,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type_ ast
} else {
c.table.find_or_register_array(info.value_type)
}
ret_type = ast.Type(typ)
ret_type = ast.idx_to_type(typ)
if info.key_type.has_flag(.generic) && method_name == 'keys' {
ret_type = ret_type.set_flag(.generic)
}
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -570,15 +570,15 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ']
} else {
c.error('invalid type `${right_expr}`', right_expr.pos)
ast.Type(0)
ast.no_type
}
}
else {
c.error('invalid type `${right_expr}`', right_expr.pos())
ast.Type(0)
ast.no_type
}
}
if right_type != ast.Type(0) {
if right_type != ast.no_type {
right_sym := c.table.sym(right_type)
mut expr_type := c.unwrap_generic(node.left_type)
left_sym := c.table.sym(expr_type)
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/infix.v
Original file line number Diff line number Diff line change
Expand Up @@ -731,15 +731,15 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ']
} else {
c.error('invalid type `${right_expr}`', right_expr.pos)
ast.Type(0)
ast.no_type
}
}
else {
c.error('invalid type `${right_expr}`', right_expr.pos())
ast.Type(0)
ast.no_type
}
}
if typ != ast.Type(0) {
if typ != ast.no_type {
typ_sym := c.table.sym(typ)
op := node.op.str()
if typ_sym.kind == .placeholder {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/match.v
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
// when match is type matching, then register smart cast for every branch
if expr_types.len > 0 {
if cond_type_sym.kind in [.sum_type, .interface_] {
mut expr_type := ast.Type(0)
mut expr_type := ast.no_type
if expr_types.len > 1 {
mut agg_name := strings.new_builder(20)
mut agg_cname := strings.new_builder(20)
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ fn (mut c Checker) check_orm_or_expr(mut expr ORMExpr) {
// check_db_expr checks the `db_expr` implements `orm.Connection` and has no `option` flag.
fn (mut c Checker) check_db_expr(mut db_expr ast.Expr) bool {
connection_type_index := c.table.find_type_idx('orm.Connection')
connection_typ := ast.Type(connection_type_index)
connection_typ := ast.idx_to_type(connection_type_index)
db_expr_type := c.expr(mut db_expr)

// If we didn't find `orm.Connection`, we don't have any imported modules
Expand Down Expand Up @@ -678,7 +678,7 @@ fn (c &Checker) get_field_foreign_table_type(table_field &ast.StructField) ast.T
} else if c.table.sym(table_field.typ).kind == .array {
return c.table.sym(table_field.typ).array_info().elem_type
} else {
return ast.Type(0)
return ast.no_type
}
}

Expand Down
Loading

0 comments on commit 19c5670

Please sign in to comment.