checker: check if the type in `as` exists, skip void type errors

pull/5387/head
Alexander Medvednikov 2020-06-19 11:15:15 +02:00
parent 5a6d440f68
commit ef36520509
3 changed files with 37 additions and 25 deletions

View File

@ -133,10 +133,12 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
[inline]
fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
if !left_type.is_int() {
c.error('cannot shift type ${c.table.get_type_symbol(right_type).name} into non-integer type ${c.table.get_type_symbol(left_type).name}', left_pos)
c.error('cannot shift type ${c.table.get_type_symbol(right_type).name} into non-integer type ${c.table.get_type_symbol(left_type).name}',
left_pos)
return table.void_type
} else if !right_type.is_int() {
c.error('cannot shift non-integer type ${c.table.get_type_symbol(right_type).name} into type ${c.table.get_type_symbol(left_type).name}', right_pos)
c.error('cannot shift non-integer type ${c.table.get_type_symbol(right_type).name} into type ${c.table.get_type_symbol(left_type).name}',
right_pos)
return table.void_type
}
return left_type
@ -269,9 +271,8 @@ pub fn (c &Checker) get_default_fmt(ftyp, typ table.Type) byte {
return `p`
} else {
sym := c.table.get_type_symbol(ftyp)
if ftyp in [table.string_type, table.bool_type] || sym.kind in
[.enum_, .array, .array_fixed, .struct_, .map] || ftyp.has_flag(.optional) ||
sym.has_method('str') {
if ftyp in [table.string_type, table.bool_type] || sym.kind in [.enum_, .array, .array_fixed,
.struct_, .map] || ftyp.has_flag(.optional) || sym.has_method('str') {
return `s`
} else {
return `_`
@ -292,8 +293,10 @@ pub fn (c &Checker) string_inter_lit(mut node ast.StringInterLiteral) table.Type
if fmt == `_` { // set default representation for type if none has been given
fmt = c.get_default_fmt(ftyp, typ)
if fmt == `_` {
if typ != table.void_type {
c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i])
}
} else {
node.fmts[i] = fmt
node.need_fmts[i] = false
@ -305,13 +308,12 @@ pub fn (c &Checker) string_inter_lit(mut node ast.StringInterLiteral) table.Type
if node.pluss[i] && !typ.is_number() {
c.error('plus prefix only allowd for numbers', node.fmt_poss[i])
}
if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`]) ||
(typ.is_signed() && fmt !in [`d`, `x`, `X`, `o`, `c`]) ||
(typ.is_any_int() && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`]) ||
(typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`]) ||
(typ.is_pointer() && fmt !in [`p`, `x`, `X`]) ||
(typ.is_string() && fmt != `s`) ||
(typ.idx() in [table.i64_type_idx, table.f64_type_idx] && fmt == `c`) {
if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`]) || (typ.is_signed() &&
fmt !in [`d`, `x`, `X`, `o`, `c`]) || (typ.is_any_int() && fmt !in [`d`, `c`, `x`, `X`, `o`,
`u`, `x`, `X`, `o`]) || (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`]) || (typ.is_pointer() &&
fmt !in [`p`, `x`, `X`]) || (typ.is_string() && fmt != `s`) || (typ.idx() in [table.i64_type_idx,
table.f64_type_idx
] && fmt == `c`) {
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i])
}

View File

@ -780,8 +780,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.error('type mismatch, should use `$elem_sym.name[]`', arg_expr.position())
}
} else {
if arg_sym.kind != elem_sym.kind && ((elem_sym.kind == .int && arg_sym.kind != .any_int) ||
(elem_sym.kind == .f64 && arg_sym.kind != .any_float)) {
if arg_sym.kind != elem_sym.kind && ((elem_sym.kind == .int && arg_sym.kind !=
.any_int) || (elem_sym.kind == .f64 && arg_sym.kind != .any_float)) {
c.error('type mismatch, should use `$elem_sym.name`', arg_expr.position())
}
}
@ -838,10 +838,12 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
if exp_arg_sym.kind == .string && got_arg_sym.has_method('str') {
continue
}
if got_arg_typ != table.void_type {
c.error('cannot use type `$got_arg_sym.str()` as type `$exp_arg_sym.str()` in argument ${i+1} to `${left_type_sym.name}.$method_name`',
call_expr.pos)
}
}
}
// TODO: typ optimize.. this node can get processed more than once
if call_expr.expected_arg_types.len == 0 {
for i in 1 .. method.args.len {
@ -1207,7 +1209,9 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T
return field.typ
}
if sym.kind != .struct_ {
if sym.kind != .placeholder {
c.error('`$sym.name` is not a struct', selector_expr.pos)
}
} else {
c.error('type `$sym.name` has no field or method `$field_name`', selector_expr.pos)
}
@ -1731,8 +1735,10 @@ fn (mut c Checker) stmt(node ast.Stmt) {
}
value_type := c.table.value_type(typ)
if value_type == table.void_type || typ.has_flag(.optional) {
if typ != table.void_type {
c.error('for in: cannot index `${c.table.type_to_str(typ)}`', it.cond.position())
}
}
it.cond_type = typ
it.kind = sym.kind
it.val_type = value_type
@ -1849,6 +1855,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
type_sym := c.table.get_type_symbol(node.typ)
if expr_type_sym.kind == .sum_type {
info := expr_type_sym.info as table.SumType
if type_sym.kind == .placeholder {
// Unknown type used in the right part of `as`
c.error('unknown type `$type_sym.name`', node.pos)
}
if node.typ !in info.variants {
c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', node.pos)
// c.error('only $info.variants can be casted to `$typ`', it.pos)

View File

@ -310,7 +310,7 @@ pub fn (mut g Gen) write_typeof_functions() {
g.writeln('// >> typeof() support for sum types')
for typ in g.table.types {
if typ.kind == .sum_type {
sum_info := typ.info as table.SumType
sum_info := typ.info as table.SumTypee
tidx := g.table.find_type_idx(typ.name)
g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* $typ.name */ ')
g.writeln(' switch(sidx) {')