checker: fix position of unknown type errors (#10110)

pull/10123/head
crthpl 2021-05-15 18:51:23 -07:00 committed by GitHub
parent ed6ad728d9
commit 0d44c8857e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 54 additions and 50 deletions

View File

@ -572,6 +572,9 @@ pub fn (t &Table) known_type_idx(typ Type) bool {
.array {
return t.known_type_idx((sym.info as Array).elem_type)
}
.array_fixed {
return t.known_type_idx((sym.info as ArrayFixed).elem_type)
}
.map {
info := sym.info as Map
return t.known_type_idx(info.key_type) && t.known_type_idx(info.value_type)
@ -965,7 +968,8 @@ pub fn (t &Table) known_type_names() []string {
mut res := []string{cap: t.type_idxs.len}
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.
if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(idx) {
if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(idx)
&& t.get_type_symbol(idx).kind != .function {
res << t.type_to_str(idx)
}
}

View File

@ -309,18 +309,19 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
pub fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
// TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available
if c.file.mod.name != 'time' && c.file.mod.name != 'builtin' {
if c.file.mod.name !in ['time', 'builtin'] {
c.check_valid_pascal_case(node.name, 'type alias', node.pos)
}
c.ensure_type_exists(node.parent_type, node.type_pos) or { return }
typ_sym := c.table.get_type_symbol(node.parent_type)
if typ_sym.kind in [.placeholder, .int_literal, .float_literal] {
c.error("type `$typ_sym.name` doesn't exist", node.pos)
c.error('unknown type `$typ_sym.name`', node.type_pos)
} else if typ_sym.kind == .alias {
orig_sym := c.table.get_type_symbol((typ_sym.info as ast.Alias).parent_type)
c.error('type `$typ_sym.str()` is an alias, use the original alias type `$orig_sym.name` instead',
node.pos)
node.type_pos)
} else if typ_sym.kind == .chan {
c.error('aliases of `chan` types are not allowed.', node.pos)
c.error('aliases of `chan` types are not allowed.', node.type_pos)
}
}
@ -329,14 +330,16 @@ pub fn (mut c Checker) fn_type_decl(node ast.FnTypeDecl) {
typ_sym := c.table.get_type_symbol(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 {}
ret_sym := c.table.get_type_symbol(fn_info.return_type)
if ret_sym.kind == .placeholder {
c.error("type `$ret_sym.name` doesn't exist", node.pos)
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 }
arg_sym := c.table.get_type_symbol(arg.typ)
if arg_sym.kind == .placeholder {
c.error("type `$arg_sym.name` doesn't exist", node.pos)
c.error('unknown type `$arg_sym.name`', arg.type_pos)
}
}
}
@ -348,12 +351,13 @@ pub fn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) {
if variant.typ.is_ptr() {
c.error('sum type cannot hold a reference type', variant.pos)
}
c.ensure_type_exists(variant.typ, variant.pos) or {}
mut sym := c.table.get_type_symbol(variant.typ)
if sym.name in names_used {
c.error('sum type $node.name cannot hold the type `$sym.name` more than once',
variant.pos)
} else if sym.kind in [.placeholder, .int_literal, .float_literal] {
c.error("type `$sym.name` doesn't exist", variant.pos)
c.error('unknown type `$sym.name`', variant.pos)
} else if sym.kind == .interface_ {
c.error('sum type cannot hold an interface', variant.pos)
}
@ -7017,7 +7021,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if node.language == .v {
// Make sure all types are valid
for arg in node.params {
c.ensure_type_exists(arg.typ, node.pos) or { return }
c.ensure_type_exists(arg.typ, arg.type_pos) or { return }
}
}
if node.language == .v && node.name.after_char(`.`) == 'init' && !node.is_method
@ -7030,7 +7034,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
}
}
if node.return_type != ast.Type(0) {
c.ensure_type_exists(node.return_type, node.pos) or { return }
c.ensure_type_exists(node.return_type, node.return_type_pos) or { 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)
@ -7214,6 +7218,9 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Position) ? {
.array {
c.ensure_type_exists((sym.info as ast.Array).elem_type, pos) ?
}
.array_fixed {
c.ensure_type_exists((sym.info as ast.ArrayFixed).elem_type, pos) ?
}
.map {
info := sym.info as ast.Map
c.ensure_type_exists(info.key_type, pos) ?

View File

@ -1,5 +1,3 @@
vlib/v/checker/tests/alias_type_exists.vv:1:1: error: type `Bird` doesn't exist
vlib/v/checker/tests/alias_type_exists.vv:1:15: error: unknown type `Bird`
1 | type Pigeon = Bird
| ~~~~~~~~~~~
2 |
3 | fn main() {
| ~~~~

View File

@ -1,5 +1 @@
type Pigeon = Bird
fn main() {
}

View File

@ -1,12 +1,12 @@
vlib/v/checker/tests/any_int_float_ban_err.vv:1:12: error: type `int_literal` doesn't exist
vlib/v/checker/tests/any_int_float_ban_err.vv:1:12: error: unknown type `int_literal`
1 | type Foo = int_literal | float_literal
| ~~~~~~~~~~~
2 | type Fo2 = int_literal
3 |
vlib/v/checker/tests/any_int_float_ban_err.vv:2:1: error: type `int_literal` doesn't exist
vlib/v/checker/tests/any_int_float_ban_err.vv:2:12: error: unknown type `int_literal`
1 | type Foo = int_literal | float_literal
2 | type Fo2 = int_literal
| ~~~~~~~~
| ~~~~~~~~~~~
3 |
4 | struct Int {
vlib/v/checker/tests/any_int_float_ban_err.vv:5:7: error: unknown type `int_literal`
@ -23,18 +23,18 @@ vlib/v/checker/tests/any_int_float_ban_err.vv:6:7: error: unknown type `float_li
| ~~~~~~~~~~~~~
7 | }
8 |
vlib/v/checker/tests/any_int_float_ban_err.vv:9:1: error: unknown type `int_literal`
vlib/v/checker/tests/any_int_float_ban_err.vv:9:10: error: unknown type `int_literal`
7 | }
8 |
9 | fn foo(i int_literal) int_literal {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ~~~~~~~~~~~
10 | return i
11 | }
vlib/v/checker/tests/any_int_float_ban_err.vv:13:1: error: unknown type `int_literal`
vlib/v/checker/tests/any_int_float_ban_err.vv:13:11: error: unknown type `int_literal`
11 | }
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

View File

@ -0,0 +1,4 @@
vlib/v/checker/tests/const_array_unknown_type_err.vv:1:11: error: unknown type `BB`.
Did you mean `AA`?
1 | type AA = [20]BB
| ~~~~~~

View File

@ -0,0 +1 @@
type AA = [20]BB

View File

@ -1,12 +1,10 @@
vlib/v/checker/tests/fn_type_exists.vv:1:1: error: type `Pants` doesn't exist
vlib/v/checker/tests/fn_type_exists.vv:1:34: error: unknown type `Pants`
1 | type PantsCreator = fn (a Shirt) Pants
| ~~~~~~~~~~~~~~~~~
| ~~~~~
2 |
3 | type PantsConsumer = fn (p Pants)
vlib/v/checker/tests/fn_type_exists.vv:3:1: error: type `Pants` doesn't exist
vlib/v/checker/tests/fn_type_exists.vv:3:28: error: unknown type `Pants`
1 | type PantsCreator = fn (a Shirt) Pants
2 |
3 | type PantsConsumer = fn (p Pants)
| ~~~~~~~~~~~~~~~~~~
4 |
5 | fn main() {
| ~~~~~

View File

@ -1,7 +1,3 @@
type PantsCreator = fn (a Shirt) Pants
type PantsConsumer = fn (p Pants)
fn main() {
}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/nested_aliases.vv:2:1: error: type `MyInt` is an alias, use the original alias type `int` instead
vlib/v/checker/tests/nested_aliases.vv:2:16: error: type `MyInt` is an alias, use the original alias type `int` instead
1 | type MyInt = int
2 | type MyMyInt = MyInt
| ~~~~~~~~~~~~
| ~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/receiver_unknown_type_single_letter.vv:1:1: error: unknown type `Abc`
vlib/v/checker/tests/receiver_unknown_type_single_letter.vv:1:7: error: unknown type `Abc`
1 | fn (p Abc) foo() {}
| ~~~~~~~~~~~~~~~~
| ~~~
2 |

View File

@ -1,5 +1,3 @@
vlib/v/checker/tests/sum_type_exists.vv:1:22: error: type `Nope` doesn't exist
1 | type Miscellaneous = Nope | Inexistant | int
| ~~~~
2 |
3 | fn main() {
vlib/v/checker/tests/sum_type_exists.vv:1:22: error: unknown type `Inexistant`
1 | type Miscellaneous = Inexistant | Nope | int
| ~~~~~~~~~~

View File

@ -1,5 +1 @@
type Miscellaneous = Nope | Inexistant | int
fn main() {
}
type Miscellaneous = Inexistant | Nope | int

View File

@ -5,6 +5,7 @@ module parser
import v.ast
import v.util
import v.token
pub fn (mut p Parser) parse_array_type() ast.Type {
p.check(.lsbr)
@ -203,17 +204,21 @@ pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
}
}
mut return_type := ast.void_type
mut return_type_pos := token.Position{}
if p.tok.line_nr == line_nr && p.tok.kind.is_start_of_type() {
return_type_pos = p.tok.position()
return_type = p.parse_type()
if return_type.has_flag(.generic) {
has_generic = true
}
return_type_pos = return_type_pos.extend(p.prev_tok.position())
}
func := ast.Fn{
name: name
params: args
is_variadic: is_variadic
return_type: return_type
return_type_pos: return_type_pos
}
// MapFooFn typedefs are manually added in cheaders.v
// because typedefs get generated after the map struct is generated

View File

@ -3073,6 +3073,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
}
is_public: is_pub
})
type_end_pos := p.prev_tok.position()
if idx == -1 {
p.error_with_pos('cannot register alias `$name`, another type with this name exists',
decl_pos.extend(type_alias_pos))
@ -3087,7 +3088,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
name: name
is_pub: is_pub
parent_type: parent_type
type_pos: type_pos
type_pos: type_pos.extend(type_end_pos)
pos: decl_pos
comments: comments
}