Skip to content

Commit

Permalink
checker: clean up ensure_type_exists() (#18860)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Jul 14, 2023
1 parent 4413808 commit b06811c
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 92 deletions.
99 changes: 68 additions & 31 deletions vlib/v/checker/checker.v
Expand Up @@ -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')
Expand Down Expand Up @@ -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)
Expand All @@ -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('.')
Expand Down Expand Up @@ -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_ {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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++
Expand All @@ -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)
Expand All @@ -4574,66 +4580,82 @@ 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_ {
info := sym.info as ast.Struct
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_ {
info := sym.info as ast.Interface
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 {
Expand All @@ -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
Expand Down
8 changes: 4 additions & 4 deletions vlib/v/checker/containers.v
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
12 changes: 8 additions & 4 deletions vlib/v/checker/fn.v
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]()',
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/infix.v
Expand Up @@ -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())
}
}
}
Expand Down
12 changes: 9 additions & 3 deletions vlib/v/checker/interface.v
Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion vlib/v/checker/match.v
Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions vlib/v/checker/orm.v
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit b06811c

Please sign in to comment.