1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: clean up ensure_type_exists() (#18860)

This commit is contained in:
yuyi 2023-07-15 01:44:01 +08:00 committed by GitHub
parent 4413808941
commit b06811cb0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 115 additions and 92 deletions

View File

@ -459,7 +459,9 @@ fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
if c.file.mod.name != 'builtin' {
c.check_valid_pascal_case(node.name, 'type alias', node.pos)
}
c.ensure_type_exists(node.parent_type, node.type_pos) or { return }
if !c.ensure_type_exists(node.parent_type, node.type_pos) {
return
}
mut parent_typ_sym := c.table.sym(node.parent_type)
if node.parent_type.has_flag(.result) {
c.add_error_detail('Result types cannot be stored and have to be unwrapped immediately')
@ -551,13 +553,15 @@ fn (mut c Checker) fn_type_decl(node ast.FnTypeDecl) {
typ_sym := c.table.sym(node.typ)
fn_typ_info := typ_sym.info as ast.FnType
fn_info := fn_typ_info.func
c.ensure_type_exists(fn_info.return_type, fn_info.return_type_pos) or {}
c.ensure_type_exists(fn_info.return_type, fn_info.return_type_pos)
ret_sym := c.table.sym(fn_info.return_type)
if ret_sym.kind == .placeholder {
c.error('unknown type `${ret_sym.name}`', fn_info.return_type_pos)
}
for arg in fn_info.params {
c.ensure_type_exists(arg.typ, arg.type_pos) or { return }
if !c.ensure_type_exists(arg.typ, arg.type_pos) {
return
}
arg_sym := c.table.sym(arg.typ)
if arg_sym.kind == .placeholder {
c.error('unknown type `${arg_sym.name}`', arg.type_pos)
@ -569,7 +573,7 @@ fn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) {
c.check_valid_pascal_case(node.name, 'sum type', node.pos)
mut names_used := []string{}
for variant in node.variants {
c.ensure_type_exists(variant.typ, variant.pos) or {}
c.ensure_type_exists(variant.typ, variant.pos)
sym := c.table.sym(variant.typ)
if variant.typ.is_ptr() {
variant_name := sym.name.all_after_last('.')
@ -761,7 +765,9 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) {
return '', expr.pos
}
// retrieve ast.Field
c.ensure_type_exists(expr.expr_type, expr.pos) or { return '', expr.pos }
if !c.ensure_type_exists(expr.expr_type, expr.pos) {
return '', expr.pos
}
mut typ_sym := c.table.final_sym(c.unwrap_generic(expr.expr_type))
match typ_sym.kind {
.struct_ {
@ -2492,14 +2498,14 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
expr_type_sym := c.table.sym(node.expr_type)
type_sym := c.table.sym(node.typ)
if expr_type_sym.kind == .sum_type {
c.ensure_type_exists(node.typ, node.pos) or {}
c.ensure_type_exists(node.typ, node.pos)
if !c.table.sumtype_has_variant(node.expr_type, node.typ, true) {
addr := '&'.repeat(node.typ.nr_muls())
c.error('cannot cast `${expr_type_sym.name}` to `${addr}${type_sym.name}`',
node.pos)
}
} else if expr_type_sym.kind == .interface_ && type_sym.kind == .interface_ {
c.ensure_type_exists(node.typ, node.pos) or {}
c.ensure_type_exists(node.typ, node.pos)
} else if node.expr_type.clear_flag(.option) != node.typ.clear_flag(.option) {
mut s := 'cannot cast non-sum type `${expr_type_sym.name}` using `as`'
if type_sym.kind == .sum_type {
@ -2865,7 +2871,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
}
if to_sym.language != .c {
c.ensure_type_exists(to_type, node.pos) or {}
c.ensure_type_exists(to_type, node.pos)
if to_sym.info is ast.Alias && to_sym.info.parent_type.has_flag(.option)
&& !to_type.has_flag(.option) {
@ -4548,10 +4554,10 @@ fn (mut c Checker) trace(fbase string, message string) {
}
}
fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) ? {
fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) bool {
if typ == 0 {
c.error('unknown type', pos)
return none
return false
}
c.ensure_generic_type_level++
@ -4561,7 +4567,7 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
if c.ensure_generic_type_level > checker.expr_level_cutoff_limit {
c.error('checker: too many levels of Checker.ensure_generic_type_specify_type_names calls: ${c.ensure_generic_type_level} ',
pos)
return none
return false
}
sym := c.table.final_sym(typ)
@ -4574,29 +4580,42 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
match sym.kind {
.function {
fn_info := sym.info as ast.FnType
c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos)?
if !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos) {
return false
}
for param in fn_info.func.params {
c.ensure_generic_type_specify_type_names(param.typ, param.type_pos)?
if !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos) {
return false
}
}
}
.array {
c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type,
pos)?
if !c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type,
pos) {
return false
}
}
.array_fixed {
c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type,
pos)?
if !c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type,
pos) {
return false
}
}
.map {
info := sym.info as ast.Map
c.ensure_generic_type_specify_type_names(info.key_type, pos)?
c.ensure_generic_type_specify_type_names(info.value_type, pos)?
if !c.ensure_generic_type_specify_type_names(info.key_type, pos) {
return false
}
if !c.ensure_generic_type_specify_type_names(info.value_type, pos) {
return false
}
}
.sum_type {
info := sym.info as ast.SumType
if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {
c.error('`${sym.name}` type is generic sumtype, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',
pos)
return false
}
}
.struct_ {
@ -4604,6 +4623,7 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {
c.error('`${sym.name}` type is generic struct, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',
pos)
return false
}
}
.interface_ {
@ -4611,29 +4631,31 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {
c.error('`${sym.name}` type is generic interface, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',
pos)
return false
}
}
else {}
}
return true
}
fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) ? {
fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) bool {
if typ == 0 {
c.error('unknown type', pos)
return
return false
}
sym := c.table.sym(typ)
if !c.is_builtin_mod && sym.kind == .struct_ && !sym.is_pub && sym.mod != c.mod {
c.error('struct `${sym.name}` was declared as private to module `${sym.mod}`, so it can not be used inside module `${c.mod}`',
pos)
return
return false
}
match sym.kind {
.placeholder {
if sym.language == .v && !sym.name.starts_with('C.') {
c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}`'),
pos)
return
return false
}
}
.int_literal, .float_literal {
@ -4646,35 +4668,50 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) ? {
'unknown type `${sym.name}`.\nDid you mean `f64`?'
}
c.error(msg, pos)
return
return false
}
}
.function {
fn_info := sym.info as ast.FnType
c.ensure_type_exists(fn_info.func.return_type, fn_info.func.return_type_pos)?
if !c.ensure_type_exists(fn_info.func.return_type, fn_info.func.return_type_pos) {
return false
}
for param in fn_info.func.params {
c.ensure_type_exists(param.typ, param.type_pos)?
if !c.ensure_type_exists(param.typ, param.type_pos) {
return false
}
}
}
.array {
c.ensure_type_exists((sym.info as ast.Array).elem_type, pos)?
if !c.ensure_type_exists((sym.info as ast.Array).elem_type, pos) {
return false
}
}
.array_fixed {
c.ensure_type_exists((sym.info as ast.ArrayFixed).elem_type, pos)?
if !c.ensure_type_exists((sym.info as ast.ArrayFixed).elem_type, pos) {
return false
}
}
.map {
info := sym.info as ast.Map
c.ensure_type_exists(info.key_type, pos)?
c.ensure_type_exists(info.value_type, pos)?
if !c.ensure_type_exists(info.key_type, pos) {
return false
}
if !c.ensure_type_exists(info.value_type, pos) {
return false
}
}
.sum_type {
info := sym.info as ast.SumType
for concrete_typ in info.concrete_types {
c.ensure_type_exists(concrete_typ, pos)?
if !c.ensure_type_exists(concrete_typ, pos) {
return false
}
}
}
else {}
}
return true
}
// return true if a violation of a shared variable access rule is detected

View File

@ -92,7 +92,7 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
c.error('cannot use unwrapped Option as capacity', node.cap_expr.pos())
}
}
c.ensure_type_exists(node.elem_type, node.elem_type_pos) or {}
c.ensure_type_exists(node.elem_type, node.elem_type_pos)
if node.typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil }
&& c.table.cur_fn.generic_names.len == 0 {
c.error('generic struct cannot be used in non-generic function', node.pos)
@ -108,7 +108,7 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
if node.is_fixed {
c.ensure_sumtype_array_has_default_value(node)
c.ensure_type_exists(node.elem_type, node.elem_type_pos) or {}
c.ensure_type_exists(node.elem_type, node.elem_type_pos)
if node.elem_type.is_any_kind_of_pointer() && !c.inside_unsafe && !c.is_builtin_mod {
c.warn('fixed arrays of references need to be initialized right away (unless inside `unsafe`)',
node.pos)
@ -367,8 +367,8 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
}
}
}
c.ensure_type_exists(info.key_type, node.pos) or {}
c.ensure_type_exists(info.value_type, node.pos) or {}
c.ensure_type_exists(info.key_type, node.pos)
c.ensure_type_exists(info.value_type, node.pos)
node.key_type = info.key_type
node.value_type = info.value_type
return node.typ

View File

@ -209,7 +209,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if node.language == .v {
// Make sure all types are valid
for mut param in node.params {
c.ensure_type_exists(param.typ, param.type_pos) or { return }
if !c.ensure_type_exists(param.typ, param.type_pos) {
return
}
if reserved_type_names_chk.matches(param.name) {
c.error('invalid use of reserved type `${param.name}` as a parameter name',
param.pos)
@ -277,7 +279,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.error('top level declaration cannot shadow builtin type', node.pos)
}
if node.return_type != ast.Type(0) {
c.ensure_type_exists(node.return_type, node.return_type_pos) or { return }
if !c.ensure_type_exists(node.return_type, node.return_type_pos) {
return
}
if node.language == .v && node.is_method && node.name == 'str' {
if node.return_type != ast.string_type {
c.error('.str() methods should return `string`', node.pos)
@ -981,7 +985,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
node.concrete_list_pos)
}
for concrete_type in node.concrete_types {
c.ensure_type_exists(concrete_type, node.concrete_list_pos) or {}
c.ensure_type_exists(concrete_type, node.concrete_list_pos)
}
if func.generic_names.len > 0 && node.args.len == 0 && node.concrete_types.len == 0 {
c.error('no argument generic function must add concrete types, e.g. foo[int]()',
@ -1877,7 +1881,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
node.concrete_list_pos)
}
for concrete_type in node.concrete_types {
c.ensure_type_exists(concrete_type, node.concrete_list_pos) or {}
c.ensure_type_exists(concrete_type, node.concrete_list_pos)
}
if method.return_type == ast.void_type && method.is_conditional
&& method.ctdefine_idx != ast.invalid_type_idx {

View File

@ -195,7 +195,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
} else {
if mut node.right is ast.ArrayInit {
for i, typ in node.right.expr_types {
c.ensure_type_exists(typ, node.right.exprs[i].pos()) or {}
c.ensure_type_exists(typ, node.right.exprs[i].pos())
}
}
}

View File

@ -118,7 +118,9 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
if node.language == .v {
c.check_valid_snake_case(method.name, 'method name', method.pos)
}
c.ensure_type_exists(method.return_type, method.return_type_pos) or { return }
if !c.ensure_type_exists(method.return_type, method.return_type_pos) {
continue
}
if is_js {
mtyp := c.table.sym(method.return_type)
if !mtyp.is_js_compatible() {
@ -147,7 +149,9 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
if param.typ.has_flag(.generic) {
has_generic_types = true
}
c.ensure_type_exists(param.typ, param.pos) or { return }
if !c.ensure_type_exists(param.typ, param.pos) {
continue
}
if reserved_type_names_chk.matches(param.name) {
c.error('invalid use of reserved type `${param.name}` as a parameter name',
param.pos)
@ -190,7 +194,9 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
if node.language == .v {
c.check_valid_snake_case(field.name, 'field name', field.pos)
}
c.ensure_type_exists(field.typ, field.pos) or { return }
if !c.ensure_type_exists(field.typ, field.pos) {
continue
}
if field.typ.has_flag(.generic) {
has_generic_types = true
}

View File

@ -26,7 +26,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|| (node.cond is ast.SelectorExpr && node.cond.is_mut) {
c.fail_if_immutable(mut node.cond)
}
c.ensure_type_exists(node.cond_type, node.pos) or { return ast.void_type }
if !c.ensure_type_exists(node.cond_type, node.pos) {
return ast.void_type
}
c.check_expr_opt_call(node.cond, cond_type)
cond_type_sym := c.table.sym(cond_type)
cond_is_option := cond_type.has_flag(.option)

View File

@ -26,7 +26,9 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
// To avoid panics while working with `table_expr`,
// it is necessary to check if its type exists.
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type }
if !c.ensure_type_exists(node.table_expr.typ, node.pos) {
return ast.void_type
}
table_sym := c.table.sym(node.table_expr.typ)
if !c.check_orm_table_expr_type(node.table_expr) {
@ -175,7 +177,9 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
// To avoid panics while working with `table_expr`,
// it is necessary to check if its type exists.
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type }
if !c.ensure_type_exists(node.table_expr.typ, node.pos) {
return ast.void_type
}
table_sym := c.table.sym(node.table_expr.typ)
if !c.check_orm_table_expr_type(node.table_expr) {

View File

@ -88,8 +88,12 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
if field.typ.has_flag(.result) {
c.error('struct field does not support storing Result', field.option_pos)
}
c.ensure_type_exists(field.typ, field.type_pos) or { return }
c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) or { return }
if !c.ensure_type_exists(field.typ, field.type_pos) {
continue
}
if !c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) {
continue
}
if field.typ.has_flag(.generic) {
has_generic_types = true
}
@ -366,7 +370,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
c.table.unwrap_generic_type(node.typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types)
}
if !is_field_zero_struct_init {
c.ensure_type_exists(node.typ, node.pos) or {}
c.ensure_type_exists(node.typ, node.pos)
}
type_sym := c.table.sym(node.typ)
if !c.inside_unsafe && type_sym.kind == .sum_type {

View File

@ -7,10 +7,10 @@ vlib/v/checker/tests/any_int_float_ban_err.vv:2:12: error: unknown type `int_lit
1 | type Foo = int_literal | float_literal
2 | type Fo2 = int_literal
| ~~~~~~~~~~~
3 |
3 |
4 | struct Int {
vlib/v/checker/tests/any_int_float_ban_err.vv:5:7: error: unknown type `int_literal`
3 |
3 |
4 | struct Int {
5 | i int_literal
| ~~~~~~~~~~~
@ -25,21 +25,15 @@ vlib/v/checker/tests/any_int_float_ban_err.vv:6:7: error: unknown type `float_li
8 |
vlib/v/checker/tests/any_int_float_ban_err.vv:9:10: error: unknown type `int_literal`
7 | }
8 |
8 |
9 | fn foo(i int_literal) int_literal {
| ~~~~~~~~~~~
10 | return i
11 | }
vlib/v/checker/tests/any_int_float_ban_err.vv:13:11: error: unknown type `int_literal`
11 | }
12 |
12 |
13 | fn foo2() int_literal {
| ~~~~~~~~~~~
14 | return 1
15 | }
vlib/v/checker/tests/any_int_float_ban_err.vv:14:12: error: cannot use `int literal` as type `int_literal` in return argument
12 |
13 | fn foo2() int_literal {
14 | return 1
| ^
15 | }

View File

@ -1,54 +1,26 @@
vlib/sokol/audio/audio.v:107:26: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
105 | fn C.saudio_userdata() voidptr
106 |
106 |
107 | fn C.saudio_query_desc() C.saudio_desc
| ~~~~~~~~~~~~~
108 |
108 |
109 | fn C.saudio_sample_rate() int
vlib/sokol/audio/audio.v:122:19: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
120 |
120 |
121 | // setup - setup sokol-audio
122 | pub fn setup(desc &C.saudio_desc) {
| ~~~~~~~~~~~~~~
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
124 | unsafe {
vlib/sokol/audio/audio.v:125:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
124 | unsafe {
125 | desc.allocator.alloc = memory.salloc
| ~~~~~~~~~
126 | desc.allocator.free = memory.sfree
127 | desc.allocator.user_data = voidptr(0x100a0d10)
vlib/sokol/audio/audio.v:126:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
124 | unsafe {
125 | desc.allocator.alloc = memory.salloc
126 | desc.allocator.free = memory.sfree
| ~~~~~~~~~
127 | desc.allocator.user_data = voidptr(0x100a0d10)
128 | }
vlib/sokol/audio/audio.v:127:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
125 | desc.allocator.alloc = memory.salloc
126 | desc.allocator.free = memory.sfree
127 | desc.allocator.user_data = voidptr(0x100a0d10)
| ~~~~~~~~~
128 | }
129 | }
vlib/sokol/audio/audio.v:132:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
130 | if desc.logger.log_cb == unsafe { nil } {
131 | unsafe {
132 | desc.logger.log_cb = memory.slog
| ~~~~~~
133 | }
134 | }
vlib/sokol/audio/audio.v:154:16: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
152 |
152 |
153 | // query - return a copy of the original saudio_desc struct
154 | pub fn query() C.saudio_desc {
| ~~~~~~~~~~~~~
155 | return C.saudio_query_desc()
156 | }
vlib/v/checker/tests/private_redeclaration_of_C_struct.vv:7:10: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `main`
5 |
5 |
6 | fn main() {
7 | sd := C.saudio_desc{}
| ~~~~~~~~~~~~~