checker: stricter `unknown type` checks, show better suggestions (#8816)
parent
6a752512b2
commit
ad162cd6fc
|
@ -67,7 +67,7 @@ pub struct C.FONStextIter {
|
||||||
codepoint u32
|
codepoint u32
|
||||||
isize i16
|
isize i16
|
||||||
iblur i16
|
iblur i16
|
||||||
font &FONSfont
|
font &C.FONSfont
|
||||||
prevGlyphIndex int
|
prevGlyphIndex int
|
||||||
str byteptr
|
str byteptr
|
||||||
next byteptr
|
next byteptr
|
||||||
|
|
|
@ -54,7 +54,7 @@ fn C.sqlite3_column_text(&C.sqlite3_stmt, int) byteptr
|
||||||
|
|
||||||
fn C.sqlite3_column_int(&C.sqlite3_stmt, int) int
|
fn C.sqlite3_column_int(&C.sqlite3_stmt, int) int
|
||||||
|
|
||||||
fn C.sqlite3_column_int64(&C.sqlite3_stmt, int) int64
|
fn C.sqlite3_column_int64(&C.sqlite3_stmt, int) i64
|
||||||
|
|
||||||
fn C.sqlite3_column_double(&C.sqlite3_stmt, int) f64
|
fn C.sqlite3_column_double(&C.sqlite3_stmt, int) f64
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ struct C.timespec {
|
||||||
tv_nsec i64
|
tv_nsec i64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C._mkgmtime(&C.tm) time_t
|
fn C._mkgmtime(&C.tm) C.time_t
|
||||||
|
|
||||||
fn C.QueryPerformanceCounter(&u64) C.BOOL
|
fn C.QueryPerformanceCounter(&u64) C.BOOL
|
||||||
|
|
||||||
|
|
|
@ -338,49 +338,21 @@ pub fn (mut c Checker) interface_decl(decl ast.InterfaceDecl) {
|
||||||
c.check_valid_pascal_case(decl.name, 'interface name', decl.pos)
|
c.check_valid_pascal_case(decl.name, 'interface name', decl.pos)
|
||||||
for method in decl.methods {
|
for method in decl.methods {
|
||||||
c.check_valid_snake_case(method.name, 'method name', method.pos)
|
c.check_valid_snake_case(method.name, 'method name', method.pos)
|
||||||
|
if method.return_type != table.Type(0) {
|
||||||
|
c.ensure_type_exists(method.return_type, method.pos) or { return }
|
||||||
|
}
|
||||||
|
for param in method.params {
|
||||||
|
c.ensure_type_exists(param.typ, param.pos) or { return }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: copy pasta from StructDecl
|
|
||||||
for i, field in decl.fields {
|
for i, field in decl.fields {
|
||||||
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
||||||
sym := c.table.get_type_symbol(field.typ)
|
c.ensure_type_exists(field.typ, field.pos) or { return }
|
||||||
for j in 0 .. i {
|
for j in 0 .. i {
|
||||||
if field.name == decl.fields[j].name {
|
if field.name == decl.fields[j].name {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sym.kind == .placeholder && !sym.name.starts_with('C.') {
|
|
||||||
c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `$sym.name`'),
|
|
||||||
field.type_pos)
|
|
||||||
}
|
|
||||||
// Separate error condition for `int_literal` and `float_literal` because `util.suggestion` may give different
|
|
||||||
// suggestions due to f32 comparision issue.
|
|
||||||
if sym.kind in [.int_literal, .float_literal] {
|
|
||||||
msg := if sym.kind == .int_literal {
|
|
||||||
'unknown type `$sym.name`.\nDid you mean `int`?'
|
|
||||||
} else {
|
|
||||||
'unknown type `$sym.name`.\nDid you mean `f64`?'
|
|
||||||
}
|
|
||||||
c.error(msg, field.type_pos)
|
|
||||||
}
|
|
||||||
if sym.kind == .array {
|
|
||||||
array_info := sym.array_info()
|
|
||||||
elem_sym := c.table.get_type_symbol(array_info.elem_type)
|
|
||||||
if elem_sym.kind == .placeholder {
|
|
||||||
c.error(util.new_suggestion(elem_sym.name, c.table.known_type_names()).say('unknown type `$elem_sym.name`'),
|
|
||||||
field.type_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sym.kind == .map {
|
|
||||||
info := sym.map_info()
|
|
||||||
key_sym := c.table.get_type_symbol(info.key_type)
|
|
||||||
value_sym := c.table.get_type_symbol(info.value_type)
|
|
||||||
if key_sym.kind == .placeholder {
|
|
||||||
c.error('unknown type `$key_sym.name`', field.type_pos)
|
|
||||||
}
|
|
||||||
if value_sym.kind == .placeholder {
|
|
||||||
c.error('unknown type `$value_sym.name`', field.type_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +379,7 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, field in decl.fields {
|
for i, field in decl.fields {
|
||||||
|
c.ensure_type_exists(field.typ, field.type_pos) or { return }
|
||||||
if decl.language == .v {
|
if decl.language == .v {
|
||||||
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
||||||
}
|
}
|
||||||
|
@ -416,45 +389,12 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sym.kind == .placeholder && decl.language != .c && !sym.name.starts_with('C.') {
|
|
||||||
c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `$sym.name`'),
|
|
||||||
field.type_pos)
|
|
||||||
}
|
|
||||||
// Separate error condition for `int_literal` and `float_literal` because `util.suggestion` may give different
|
|
||||||
// suggestions due to f32 comparision issue.
|
|
||||||
if sym.kind in [.int_literal, .float_literal] {
|
|
||||||
msg := if sym.kind == .int_literal {
|
|
||||||
'unknown type `$sym.name`.\nDid you mean `int`?'
|
|
||||||
} else {
|
|
||||||
'unknown type `$sym.name`.\nDid you mean `f64`?'
|
|
||||||
}
|
|
||||||
c.error(msg, field.type_pos)
|
|
||||||
}
|
|
||||||
if sym.kind == .array {
|
|
||||||
array_info := sym.array_info()
|
|
||||||
elem_sym := c.table.get_type_symbol(array_info.elem_type)
|
|
||||||
if elem_sym.kind == .placeholder {
|
|
||||||
c.error(util.new_suggestion(elem_sym.name, c.table.known_type_names()).say('unknown type `$elem_sym.name`'),
|
|
||||||
field.type_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sym.kind == .struct_ {
|
if sym.kind == .struct_ {
|
||||||
info := sym.info as table.Struct
|
info := sym.info as table.Struct
|
||||||
if info.is_heap && !field.typ.is_ptr() {
|
if info.is_heap && !field.typ.is_ptr() {
|
||||||
struct_sym.info.is_heap = true
|
struct_sym.info.is_heap = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sym.kind == .map {
|
|
||||||
info := sym.map_info()
|
|
||||||
key_sym := c.table.get_type_symbol(info.key_type)
|
|
||||||
value_sym := c.table.get_type_symbol(info.value_type)
|
|
||||||
if key_sym.kind == .placeholder {
|
|
||||||
c.error('unknown type `$key_sym.name`', field.type_pos)
|
|
||||||
}
|
|
||||||
if value_sym.kind == .placeholder {
|
|
||||||
c.error('unknown type `$value_sym.name`', field.type_pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if field.has_default_expr {
|
if field.has_default_expr {
|
||||||
c.expected_type = field.typ
|
c.expected_type = field.typ
|
||||||
field_expr_type := c.expr(field.default_expr)
|
field_expr_type := c.expr(field.default_expr)
|
||||||
|
@ -509,10 +449,8 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
||||||
struct_init.typ = c.expected_type
|
struct_init.typ = c.expected_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if struct_init.typ == 0 {
|
|
||||||
c.error('unknown type', struct_init.pos)
|
|
||||||
}
|
|
||||||
utyp := c.unwrap_generic(struct_init.typ)
|
utyp := c.unwrap_generic(struct_init.typ)
|
||||||
|
c.ensure_type_exists(utyp, struct_init.pos) or { }
|
||||||
type_sym := c.table.get_type_symbol(utyp)
|
type_sym := c.table.get_type_symbol(utyp)
|
||||||
if type_sym.kind == .sum_type && struct_init.fields.len == 1 {
|
if type_sym.kind == .sum_type && struct_init.fields.len == 1 {
|
||||||
sexpr := struct_init.fields[0].expr.str()
|
sexpr := struct_init.fields[0].expr.str()
|
||||||
|
@ -1107,14 +1045,8 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
// retrieve table.Field
|
// retrieve table.Field
|
||||||
if expr.expr_type == 0 {
|
c.ensure_type_exists(expr.expr_type, expr.pos) or { return '', pos }
|
||||||
c.error('0 type in SelectorExpr', expr.pos)
|
mut typ_sym := c.table.get_final_type_symbol(c.unwrap_generic(expr.expr_type))
|
||||||
return '', pos
|
|
||||||
}
|
|
||||||
mut typ_sym := c.table.get_type_symbol(c.unwrap_generic(expr.expr_type))
|
|
||||||
if mut typ_sym.info is table.Alias {
|
|
||||||
typ_sym = c.table.get_type_symbol(typ_sym.info.parent_type)
|
|
||||||
}
|
|
||||||
match typ_sym.kind {
|
match typ_sym.kind {
|
||||||
.struct_ {
|
.struct_ {
|
||||||
struct_info := typ_sym.info as table.Struct
|
struct_info := typ_sym.info as table.Struct
|
||||||
|
@ -1874,9 +1806,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
gts := c.table.get_type_symbol(call_expr.generic_types[0])
|
gts := c.table.get_type_symbol(call_expr.generic_types[0])
|
||||||
nrt := '$rts.name<$gts.name>'
|
nrt := '$rts.name<$gts.name>'
|
||||||
idx := c.table.type_idxs[nrt]
|
idx := c.table.type_idxs[nrt]
|
||||||
if idx == 0 {
|
c.ensure_type_exists(idx, call_expr.pos) or { }
|
||||||
c.error('unknown type: $nrt', call_expr.pos)
|
|
||||||
}
|
|
||||||
call_expr.return_type = table.new_type(idx).derive(f.return_type)
|
call_expr.return_type = table.new_type(idx).derive(f.return_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4278,10 +4208,8 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
||||||
cond_type := c.expr(node.cond)
|
cond_type := c.expr(node.cond)
|
||||||
// we setting this here rather than at the end of the method
|
// we setting this here rather than at the end of the method
|
||||||
// since it is used in c.match_exprs() it saves checking twice
|
// since it is used in c.match_exprs() it saves checking twice
|
||||||
node.cond_type = cond_type
|
node.cond_type = c.table.mktyp(cond_type)
|
||||||
if cond_type == 0 {
|
c.ensure_type_exists(node.cond_type, node.pos) or { return table.void_type }
|
||||||
c.error('compiler bug: match 0 cond type', node.pos)
|
|
||||||
}
|
|
||||||
cond_type_sym := c.table.get_type_symbol(cond_type)
|
cond_type_sym := c.table.get_type_symbol(cond_type)
|
||||||
if cond_type_sym.kind !in [.interface_, .sum_type] {
|
if cond_type_sym.kind !in [.interface_, .sum_type] {
|
||||||
node.is_sum_type = false
|
node.is_sum_type = false
|
||||||
|
@ -5661,17 +5589,10 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
|
||||||
defer {
|
defer {
|
||||||
c.inside_sql = false
|
c.inside_sql = false
|
||||||
}
|
}
|
||||||
sym := c.table.get_type_symbol(node.table_expr.typ)
|
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return table.void_type }
|
||||||
if node.table_expr.typ == 0 {
|
|
||||||
c.error('orm: unknown type `$sym.name`', node.pos)
|
|
||||||
}
|
|
||||||
if sym.kind == .placeholder {
|
|
||||||
c.error('orm: unknown type `$sym.name`', node.pos)
|
|
||||||
return table.void_type
|
|
||||||
}
|
|
||||||
c.cur_orm_ts = sym
|
|
||||||
info := sym.info as table.Struct
|
|
||||||
table_sym := c.table.get_type_symbol(node.table_expr.typ)
|
table_sym := c.table.get_type_symbol(node.table_expr.typ)
|
||||||
|
c.cur_orm_ts = table_sym
|
||||||
|
info := table_sym.info as table.Struct
|
||||||
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name)
|
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name)
|
||||||
mut sub_structs := map[int]ast.SqlStmt{}
|
mut sub_structs := map[int]ast.SqlStmt{}
|
||||||
for f in fields.filter(c.table.types[int(it.typ)].kind == .struct_) {
|
for f in fields.filter(c.table.types[int(it.typ)].kind == .struct_) {
|
||||||
|
@ -5788,19 +5709,11 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
if node.language == .v {
|
if node.language == .v {
|
||||||
// Make sure all types are valid
|
// Make sure all types are valid
|
||||||
for arg in node.params {
|
for arg in node.params {
|
||||||
sym := c.table.get_type_symbol(arg.typ)
|
c.ensure_type_exists(arg.typ, node.pos) or { return }
|
||||||
if sym.kind == .placeholder
|
|
||||||
|| (sym.kind in [table.Kind.int_literal, .float_literal] && !c.is_builtin_mod) {
|
|
||||||
c.error('unknown type `$sym.name`', node.pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.return_type != table.Type(0) {
|
if node.return_type != table.Type(0) {
|
||||||
return_sym := c.table.get_type_symbol(node.return_type)
|
c.ensure_type_exists(node.return_type, node.pos) or { return }
|
||||||
if node.language == .v && return_sym.kind in [.placeholder, .int_literal, .float_literal]
|
|
||||||
&& return_sym.language == .v {
|
|
||||||
c.error('unknown type `$return_sym.name`', node.pos)
|
|
||||||
}
|
|
||||||
if node.language == .v && node.is_method && node.name == 'str' {
|
if node.language == .v && node.is_method && node.name == 'str' {
|
||||||
if node.return_type != table.string_type {
|
if node.return_type != table.string_type {
|
||||||
c.error('.str() methods should return `string`', node.pos)
|
c.error('.str() methods should return `string`', node.pos)
|
||||||
|
@ -5949,3 +5862,41 @@ fn (mut c Checker) trace(fbase string, message string) {
|
||||||
println('> c.trace | ${fbase:-10s} | $message')
|
println('> c.trace | ${fbase:-10s} | $message')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) ensure_type_exists(typ table.Type, pos token.Position) ? {
|
||||||
|
if typ == 0 {
|
||||||
|
c.error('unknown type', pos)
|
||||||
|
}
|
||||||
|
sym := c.table.get_type_symbol(typ)
|
||||||
|
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 none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.int_literal, .float_literal {
|
||||||
|
// Separate error condition for `int_literal` and `float_literal` because `util.suggestion` may give different
|
||||||
|
// suggestions due to f32 comparision issue.
|
||||||
|
if !c.is_builtin_mod {
|
||||||
|
msg := if sym.kind == .int_literal {
|
||||||
|
'unknown type `$sym.name`.\nDid you mean `int`?'
|
||||||
|
} else {
|
||||||
|
'unknown type `$sym.name`.\nDid you mean `f64`?'
|
||||||
|
}
|
||||||
|
c.error(msg, pos)
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.array {
|
||||||
|
c.ensure_type_exists((sym.info as table.Array).elem_type, pos) ?
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
info := sym.info as table.Map
|
||||||
|
c.ensure_type_exists(info.key_type, pos) ?
|
||||||
|
c.ensure_type_exists(info.value_type, pos) ?
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,16 +9,14 @@ vlib/v/checker/tests/any_int_float_ban_err.vv:2:1: error: type `int_literal` doe
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
3 |
|
3 |
|
||||||
4 | struct Int {
|
4 | struct Int {
|
||||||
vlib/v/checker/tests/any_int_float_ban_err.vv:5:7: error: unknown type `int_literal`.
|
vlib/v/checker/tests/any_int_float_ban_err.vv:5:7: error: unknown type `int_literal`
|
||||||
Did you mean `float_literal`?
|
|
||||||
3 |
|
3 |
|
||||||
4 | struct Int {
|
4 | struct Int {
|
||||||
5 | i int_literal
|
5 | i int_literal
|
||||||
| ~~~~~~~~~~~
|
| ~~~~~~~~~~~
|
||||||
6 | f float_literal
|
6 | f float_literal
|
||||||
7 | }
|
7 | }
|
||||||
vlib/v/checker/tests/any_int_float_ban_err.vv:6:7: error: unknown type `float_literal`.
|
vlib/v/checker/tests/any_int_float_ban_err.vv:6:7: error: unknown type `float_literal`
|
||||||
Did you mean `int_literal`?
|
|
||||||
4 | struct Int {
|
4 | struct Int {
|
||||||
5 | i int_literal
|
5 | i int_literal
|
||||||
6 | f float_literal
|
6 | f float_literal
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
vlib/v/checker/tests/filter_on_non_arr_err.vv:2:14: error: unknown method: `string.filter`.
|
vlib/v/checker/tests/filter_on_non_arr_err.vv:2:14: error: unknown method: `string.filter`
|
||||||
Did you mean `after`?
|
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | _ := 'test'.filter(it == `t`)
|
2 | _ := 'test'.filter(it == `t`)
|
||||||
| ~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~
|
||||||
3 | }
|
3 | }
|
||||||
|
|
|
@ -3,7 +3,8 @@ vlib/v/checker/tests/import_symbol_type_err.vv:1:17: error: module `crypto` has
|
||||||
| ~~~~
|
| ~~~~
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | println(Coin{})
|
3 | println(Coin{})
|
||||||
vlib/v/checker/tests/import_symbol_type_err.vv:3:11: error: unknown struct: crypto.Coin
|
vlib/v/checker/tests/import_symbol_type_err.vv:3:11: error: unknown type `crypto.Coin`.
|
||||||
|
Did you mean `crypto.Hash`?
|
||||||
1 | import crypto { Coin }
|
1 | import crypto { Coin }
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | println(Coin{})
|
3 | println(Coin{})
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
vlib/v/checker/tests/interface_return_parameter_err.vv:2:5: error: unknown type `Baz`.
|
||||||
|
Did you mean `Foo`?
|
||||||
|
1 | interface Foo {
|
||||||
|
2 | bar(string) []Baz
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
3 | bar2(Bax) string
|
||||||
|
4 | }
|
||||||
|
vlib/v/checker/tests/interface_return_parameter_err.vv:3:10: error: unknown type `Bax`.
|
||||||
|
Did you mean `Foo`?
|
||||||
|
1 | interface Foo {
|
||||||
|
2 | bar(string) []Baz
|
||||||
|
3 | bar2(Bax) string
|
||||||
|
| ~~~
|
||||||
|
4 | }
|
|
@ -0,0 +1,4 @@
|
||||||
|
interface Foo {
|
||||||
|
bar(string) []Baz
|
||||||
|
bar2(Bax) string
|
||||||
|
}
|
|
@ -2,4 +2,4 @@ vlib/v/checker/tests/map_unknown_value.vv:2:23: error: unknown type `DoesNotExis
|
||||||
1 | struct App {
|
1 | struct App {
|
||||||
2 | my_map map[string]DoesNotExist
|
2 | my_map map[string]DoesNotExist
|
||||||
| ~~~~~~~~~~~~
|
| ~~~~~~~~~~~~
|
||||||
3 | }
|
3 | }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
vlib/v/checker/tests/unknown_array_element_type_b.vv:2:6: error: unknown type `abc`
|
vlib/v/checker/tests/unknown_array_element_type_b.vv:2:6: error: unknown type `abc`.
|
||||||
|
Did you mean `Aaa`?
|
||||||
1 | struct Aaa {
|
1 | struct Aaa {
|
||||||
2 | a []abc
|
2 | a []abc
|
||||||
| ~~~
|
| ~~~
|
||||||
3 | }
|
3 | }
|
||||||
4 |
|
4 |
|
||||||
|
|
|
@ -13,4 +13,4 @@ Did you mean `translate`?
|
||||||
27 | z := p.tranzlate(v)
|
27 | z := p.tranzlate(v)
|
||||||
| ~~~~~~~~~~~~
|
| ~~~~~~~~~~~~
|
||||||
28 | println('p: $p')
|
28 | println('p: $p')
|
||||||
29 | println('v: $v')
|
29 | println('v: $v')
|
||||||
|
|
|
@ -397,7 +397,27 @@ pub fn (mut t Table) register_type_symbol(typ TypeSymbol) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t &Table) known_type(name string) bool {
|
pub fn (t &Table) known_type(name string) bool {
|
||||||
t.find_type(name) or { return false }
|
return t.find_type_idx(name) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (t &Table) known_type_idx(typ Type) bool {
|
||||||
|
if typ == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sym := t.get_type_symbol(typ)
|
||||||
|
match sym.kind {
|
||||||
|
.placeholder {
|
||||||
|
return sym.language != .v || sym.name.starts_with('C.')
|
||||||
|
}
|
||||||
|
.array {
|
||||||
|
return t.known_type_idx((sym.info as Array).elem_type)
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
info := sym.info as Map
|
||||||
|
return t.known_type_idx(info.key_type) && t.known_type_idx(info.value_type)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,14 +776,13 @@ pub fn (mytable &Table) sumtype_has_variant(parent Type, variant Type) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mytable &Table) known_type_names() []string {
|
pub fn (t &Table) known_type_names() []string {
|
||||||
mut res := []string{}
|
mut res := []string{cap: t.type_idxs.len}
|
||||||
for _, idx in mytable.type_idxs {
|
for _, idx in t.type_idxs {
|
||||||
// Skip `int_literal_type_idx` and `float_literal_type_idx` because they shouldn't be visible to the User.
|
// Skip `int_literal_type_idx` and `float_literal_type_idx` because they shouldn't be visible to the User.
|
||||||
if idx in [0, int_literal_type_idx, float_literal_type_idx] {
|
if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(idx) {
|
||||||
continue
|
res << t.type_to_str(idx)
|
||||||
}
|
}
|
||||||
res << mytable.type_to_str(idx)
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,6 @@ mut:
|
||||||
similarity f32
|
similarity f32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_by_similarity(a &Possibility, b &Possibility) int {
|
|
||||||
if a.similarity < b.similarity {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if a.similarity > b.similarity {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
struct Suggestion {
|
struct Suggestion {
|
||||||
mut:
|
mut:
|
||||||
known []Possibility
|
known []Possibility
|
||||||
|
@ -45,10 +34,12 @@ pub fn (mut s Suggestion) add(val string) {
|
||||||
if sval in [s.wanted, s.swanted] {
|
if sval in [s.wanted, s.swanted] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// round to 3 decimal places to avoid float comparison issues
|
||||||
|
similarity := f32(int(strings.dice_coefficient(s.swanted, sval) * 1000)) / 1000
|
||||||
s.known << Possibility{
|
s.known << Possibility{
|
||||||
value: val
|
value: val
|
||||||
svalue: sval
|
svalue: sval
|
||||||
similarity: strings.dice_coefficient(s.swanted, sval)
|
similarity: similarity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +50,7 @@ pub fn (mut s Suggestion) add_many(many []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s Suggestion) sort() {
|
pub fn (mut s Suggestion) sort() {
|
||||||
s.known.sort_with_compare(compare_by_similarity)
|
s.known.sort(a.similarity < b.similarity)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s Suggestion) say(msg string) string {
|
pub fn (s Suggestion) say(msg string) string {
|
||||||
|
@ -67,7 +58,7 @@ pub fn (s Suggestion) say(msg string) string {
|
||||||
mut found := false
|
mut found := false
|
||||||
if s.known.len > 0 {
|
if s.known.len > 0 {
|
||||||
top_posibility := s.known.last()
|
top_posibility := s.known.last()
|
||||||
if top_posibility.similarity > 0.10 {
|
if top_posibility.similarity > 0.5 {
|
||||||
val := top_posibility.value
|
val := top_posibility.value
|
||||||
if !val.starts_with('[]') {
|
if !val.starts_with('[]') {
|
||||||
res += '.\nDid you mean `$val`?'
|
res += '.\nDid you mean `$val`?'
|
||||||
|
|
Loading…
Reference in New Issue