cgen: fix print(ptr); checker: uninitialized reference error/warning

pull/4220/head
Alexander Medvednikov 2020-04-03 20:17:53 +02:00
parent 436ef12730
commit 1d2de44e19
2 changed files with 41 additions and 8 deletions

View File

@ -102,10 +102,12 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
if struct_init.exprs.len > info.fields.len {
c.error('too many fields', struct_init.pos)
}
mut inited_fields := []string
for i, expr in struct_init.exprs {
// struct_field info.
field_name := if is_short_syntax { info.fields[i].name } else { struct_init.fields[i] }
mut field := info.fields[i]
inited_fields << field_name
mut found_field := false
for f in info.fields {
if f.name == field_name {
@ -127,6 +129,15 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
struct_init.expr_types << expr_type
struct_init.expected_types << field.typ
}
// Check uninitialized refs
for field in info.fields {
if field.name in inited_fields {
continue
}
if table.type_is_ptr(field.typ) {
c.warn('reference field `Reference.value` must be initialized', struct_init.pos)
}
}
}
else {}
}
@ -1166,23 +1177,41 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
return map_type
}
pub fn (c mut Checker) warn(s string, pos token.Position) {
allow_warnings := !c.pref.is_prod // allow warnings only in dev builds
c.warn_or_error(s, pos, allow_warnings) // allow warnings only in dev builds
}
pub fn (c mut Checker) error(s string, pos token.Position) {
c.nr_errors++
c.warn_or_error(s, pos, false)
}
fn (c mut Checker) warn_or_error(s string, pos token.Position, warn bool) {
if !warn {
c.nr_errors++
}
//if c.pref.is_verbose {
if c.pref.verbosity.is_higher_or_equal(.level_one) {
print_backtrace()
}
typ := if warn { 'warning' } else { 'error' }
kind := if c.pref.verbosity.is_higher_or_equal(.level_one) {
'checker error #$c.nr_errors:'
'checker $typ #$c.nr_errors:'
} else {
'error:'
'$typ:'
}
ferror := util.formated_error(kind, s, c.file.path, pos)
c.errors << ferror
if !(pos.line_nr in c.error_lines) {
eprintln(ferror)
if warn {
println(ferror)
} else {
eprintln(ferror)
}
}
if !warn {
c.error_lines << pos.line_nr
}
c.error_lines << pos.line_nr
if c.pref.verbosity.is_higher_or_equal(.level_one) {
println('\n\n')
}

View File

@ -1884,7 +1884,7 @@ fn (g mut Gen) struct_init(it ast.StructInit) {
g.writeln('($styp){')
}
mut fields := []string
mut inited_fields := []string
mut inited_fields := []string // TODO this is done in checker, move to ast node
if it.fields.len == 0 && it.exprs.len > 0 {
// Get fields for {a,b} short syntax. Fields array wasn't set in the parser.
for f in info.fields {
@ -2447,10 +2447,14 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
else {
// `println(int_str(10))`
// sym := g.table.get_type_symbol(node.args[0].typ)
if table.type_is_ptr(typ) {
// ptr_str() for pointers
styp = 'ptr'
}
g.write('${print_method}(${styp}_str(')
if table.type_is_ptr(typ) {
// dereference
g.write('*')
//g.write('*')
}
g.expr(node.args[0].expr)
g.write('))')
@ -2883,7 +2887,7 @@ fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) {
fmt := type_to_fmt(field.typ)
g.definitions.write('\t$field.name: $fmt\\n')
}
g.definitions.write('\\n}"')
g.definitions.write('}"')
if info.fields.len > 0 {
g.definitions.write(', ')
}