checker: no longer allow automatic dereferncing in `a = b`

pull/11456/head
Alexander Medvednikov 2021-09-09 20:21:01 +03:00
parent d1e9aa49ea
commit ab3adf3346
11 changed files with 63 additions and 34 deletions

View File

@ -131,7 +131,7 @@ fn break_if_debugger_attached() {
unsafe { unsafe {
mut ptr := &voidptr(0) mut ptr := &voidptr(0)
*ptr = voidptr(0) *ptr = voidptr(0)
_ = ptr //_ = ptr
} }
} }

View File

@ -152,7 +152,7 @@ pub fn get_clipboard_string() &char {
// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) // special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub)
[inline] [inline]
pub fn run(desc &C.sapp_desc) { pub fn run(desc &C.sapp_desc) {
g_desc = desc g_desc = *desc
C.sapp_run(desc) C.sapp_run(desc)
} }

View File

@ -122,28 +122,33 @@ pub mut:
typ Type typ Type
} }
pub fn (f Fn) new_method_with_receiver_type(new_type Type) Fn { pub fn (f &Fn) new_method_with_receiver_type(new_type Type) Fn {
mut new_method := f unsafe {
new_method.params = f.params.clone() mut new_method := f
for i in 1 .. new_method.params.len { new_method.params = f.params.clone()
if new_method.params[i].typ == new_method.params[0].typ { for i in 1 .. new_method.params.len {
new_method.params[i].typ = new_type if new_method.params[i].typ == new_method.params[0].typ {
new_method.params[i].typ = new_type
}
} }
new_method.params[0].typ = new_type
return *new_method
} }
new_method.params[0].typ = new_type
return new_method
} }
pub fn (f FnDecl) new_method_with_receiver_type(new_type Type) FnDecl { pub fn (f &FnDecl) new_method_with_receiver_type(new_type Type) FnDecl {
mut new_method := f unsafe {
new_method.params = f.params.clone() mut new_method := f
for i in 1 .. new_method.params.len { new_method.params = f.params.clone()
if new_method.params[i].typ == new_method.params[0].typ { for i in 1 .. new_method.params.len {
new_method.params[i].typ = new_type if new_method.params[i].typ == new_method.params[0].typ {
new_method.params[i].typ = new_type
}
} }
new_method.params[0].typ = new_type
return *new_method
} }
new_method.params[0].typ = new_type
return new_method
} }
fn (p &Param) equals(o &Param) bool { fn (p &Param) equals(o &Param) bool {

View File

@ -246,6 +246,11 @@ pub fn (t Type) str() string {
return 'ast.Type(0x$t.hex() = ${u32(t)})' return 'ast.Type(0x$t.hex() = ${u32(t)})'
} }
pub fn (t &Table) type_str(typ Type) string {
sym := t.get_type_symbol(typ)
return sym.name
}
// debug returns a verbose representation of the information in the type `t`, useful for tracing/debugging // debug returns a verbose representation of the information in the type `t`, useful for tracing/debugging
pub fn (t Type) debug() []string { pub fn (t Type) debug() []string {
mut res := []string{} mut res := []string{}
@ -309,6 +314,11 @@ pub fn (typ Type) is_pointer() bool {
return typ.idx() in ast.pointer_type_idxs return typ.idx() in ast.pointer_type_idxs
} }
[inline]
pub fn (typ Type) is_real_pointer() bool {
return typ.is_ptr() || typ.is_pointer()
}
[inline] [inline]
pub fn (typ Type) is_float() bool { pub fn (typ Type) is_float() bool {
return typ.clear_flags() in ast.float_type_idxs return typ.clear_flags() in ast.float_type_idxs

View File

@ -288,7 +288,7 @@ pub fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
} }
// allow direct int-literal assignment for pointers for now // allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that // maybe in the future optionals should be used for that
if expected.is_ptr() || expected.is_pointer() { if expected.is_real_pointer() {
if got == ast.int_literal_type { if got == ast.int_literal_type {
return true return true
} }

View File

@ -4020,6 +4020,14 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
} }
} }
} }
// Do not allow `a := 0; b := 0; a = &b`
if !is_decl && left is ast.Ident && !is_blank_ident && !left_type.is_real_pointer()
&& right_type.is_real_pointer() {
c.warn(
'cannot assign a reference to a value (this will be an error soon) left=${c.table.type_str(left_type)} $left_type.is_ptr() ' +
'right=${c.table.type_str(right_type)} $right_type.is_real_pointer() ptr=$right_type.is_ptr()',
node.pos)
}
node.left_types << left_type node.left_types << left_type
match mut left { match mut left {
ast.Ident { ast.Ident {
@ -5742,7 +5750,8 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
} }
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
node.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left))) sym := c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left)))
node.sym = *sym
if node.is_env { if node.is_env {
env_value := util.resolve_env_value("\$env('$node.args_var')", false) or { env_value := util.resolve_env_value("\$env('$node.args_var')", false) or {
c.error(err.msg, node.env_pos) c.error(err.msg, node.env_pos)
@ -7770,7 +7779,7 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
} }
sym := c.table.get_type_symbol(node.table_expr.typ) sym := c.table.get_type_symbol(node.table_expr.typ)
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type } c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type }
c.cur_orm_ts = sym c.cur_orm_ts = *sym
info := sym.info as ast.Struct info := sym.info as ast.Struct
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name) fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name)
mut sub_structs := map[int]ast.SqlExpr{} mut sub_structs := map[int]ast.SqlExpr{}
@ -7868,7 +7877,7 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
} }
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type } c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type }
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 c.cur_orm_ts = *table_sym
if table_sym.info !is ast.Struct { if table_sym.info !is ast.Struct {
c.error('unknown type `$table_sym.name`', node.pos) c.error('unknown type `$table_sym.name`', node.pos)
return ast.void_type return ast.void_type
@ -8071,7 +8080,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.check_valid_snake_case(node.name, 'function name', node.pos) c.check_valid_snake_case(node.name, 'function name', node.pos)
} }
if node.name == 'main.main' { if node.name == 'main.main' {
c.main_fn_decl_node = node c.main_fn_decl_node = *node
} }
if node.return_type != ast.void_type { if node.return_type != ast.void_type {
if ct_attr_idx := node.attrs.find_comptime_define() { if ct_attr_idx := node.attrs.find_comptime_define() {

View File

@ -76,7 +76,7 @@ mut:
cast_stack []ast.Type cast_stack []ast.Type
call_stack []ast.CallExpr call_stack []ast.CallExpr
is_vlines_enabled bool // is it safe to generate #line directives when -g is passed is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
sourcemap sourcemap.SourceMap // maps lines in generated javascrip file to original source files and line sourcemap &sourcemap.SourceMap // maps lines in generated javascrip file to original source files and line
comptime_var_type_map map[string]ast.Type comptime_var_type_map map[string]ast.Type
defer_ifdef string defer_ifdef string
out strings.Builder = strings.new_builder(128) out strings.Builder = strings.new_builder(128)
@ -98,6 +98,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
ns: 0 ns: 0
enable_doc: true enable_doc: true
file: 0 file: 0
sourcemap: 0
} }
g.doc = new_jsdoc(g) g.doc = new_jsdoc(g)
// TODO: Add '[-no]-jsdoc' flag // TODO: Add '[-no]-jsdoc' flag
@ -185,7 +186,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
// out += 'const $name = (function (' // out += 'const $name = (function ('
mut namespace := g.namespaces[node.name] mut namespace := g.namespaces[node.name]
if g.pref.sourcemap { if g.pref.sourcemap {
// calculate current output start line // calculate current output start line
mut current_line := u32(out.count('\n') + 1) mut current_line := u32(out.count('\n') + 1)
@ -206,7 +207,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
sm_pos = sourcemap_ns_entry.ns_pos sm_pos = sourcemap_ns_entry.ns_pos
} }
} }
// public scope // public scope
out += '\n' out += '\n'

View File

@ -6,7 +6,7 @@ import v.token
pub struct Amd64 { pub struct Amd64 {
mut: mut:
g Gen g &Gen
// arm64 specific stuff for code generation // arm64 specific stuff for code generation
} }

View File

@ -38,7 +38,7 @@ enum Arm64Register {
pub struct Arm64 { pub struct Arm64 {
mut: mut:
g Gen g &Gen
// arm64 specific stuff for code generation // arm64 specific stuff for code generation
} }

View File

@ -16,7 +16,7 @@ pub const builtins = ['assert', 'print', 'eprint', 'println', 'eprintln', 'exit'
interface CodeGen { interface CodeGen {
mut: mut:
g Gen g &Gen
gen_exit(mut g Gen, expr ast.Expr) gen_exit(mut g Gen, expr ast.Expr)
// XXX WHY gen_exit fn (expr ast.Expr) // XXX WHY gen_exit fn (expr ast.Expr)
} }
@ -58,10 +58,14 @@ enum Size {
fn get_backend(arch pref.Arch) ?CodeGen { fn get_backend(arch pref.Arch) ?CodeGen {
match arch { match arch {
.arm64 { .arm64 {
return Arm64{} return Arm64{
g: 0
}
} }
.amd64 { .amd64 {
return Amd64{} return Amd64{
g: 0
}
} }
else {} else {}
} }

View File

@ -147,12 +147,12 @@ pub fn (mut p Parser) set_path(path string) {
} }
before_dot_v := path.all_before_last('.v') // also works for .vv and .vsh before_dot_v := path.all_before_last('.v') // also works for .vv and .vsh
language := before_dot_v.all_after_last('.') language := before_dot_v.all_after_last('.')
langauge_with_underscore := before_dot_v.all_after_last('_') language_with_underscore := before_dot_v.all_after_last('_')
if language == before_dot_v && langauge_with_underscore == before_dot_v { if language == before_dot_v && language_with_underscore == before_dot_v {
p.file_backend_mode = .v p.file_backend_mode = .v
return return
} }
actual_language := if language == before_dot_v { langauge_with_underscore } else { language } actual_language := if language == before_dot_v { language_with_underscore } else { language }
match actual_language { match actual_language {
'c' { 'c' {
p.file_backend_mode = .c p.file_backend_mode = .c