checker: check mutating methods; generics fixes
parent
945439dab6
commit
3d83934caf
|
@ -621,7 +621,7 @@ pub fn is_writable_folder(folder string) ?bool {
|
||||||
return error('`folder` is not a folder')
|
return error('`folder` is not a folder')
|
||||||
}
|
}
|
||||||
tmp_perm_check := os.join_path(folder, 'tmp_perm_check')
|
tmp_perm_check := os.join_path(folder, 'tmp_perm_check')
|
||||||
f := os.open_file(tmp_perm_check, 'w+', 0o700) or {
|
mut f := os.open_file(tmp_perm_check, 'w+', 0o700) or {
|
||||||
return error('cannot write to folder `$folder`: $err')
|
return error('cannot write to folder `$folder`: $err')
|
||||||
}
|
}
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
@ -13,10 +13,10 @@ import v.depgraph
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
pub:
|
pub:
|
||||||
table &table.Table
|
table &table.Table
|
||||||
checker checker.Checker
|
|
||||||
compiled_dir string // contains os.real_path() of the dir of the final file beeing compiled, or the dir itself when doing `v .`
|
compiled_dir string // contains os.real_path() of the dir of the final file beeing compiled, or the dir itself when doing `v .`
|
||||||
module_path string
|
module_path string
|
||||||
mut:
|
mut:
|
||||||
|
checker checker.Checker
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
parsed_files []ast.File
|
parsed_files []ast.File
|
||||||
global_scope &ast.Scope
|
global_scope &ast.Scope
|
||||||
|
|
|
@ -15,8 +15,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct Checker {
|
pub struct Checker {
|
||||||
table &table.Table
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
table &table.Table
|
||||||
file ast.File
|
file ast.File
|
||||||
nr_errors int
|
nr_errors int
|
||||||
nr_warnings int
|
nr_warnings int
|
||||||
|
@ -572,6 +572,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
|
|
||||||
fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
|
fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
|
ast.CastExpr {
|
||||||
|
// TODO
|
||||||
|
return
|
||||||
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
scope := c.file.scope.innermost(it.pos.pos)
|
scope := c.file.scope.innermost(it.pos.pos)
|
||||||
if v := scope.find_var(it.name) {
|
if v := scope.find_var(it.name) {
|
||||||
|
@ -580,7 +584,10 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
|
||||||
it.pos)
|
it.pos)
|
||||||
}
|
}
|
||||||
} else if it.name in c.const_names {
|
} else if it.name in c.const_names {
|
||||||
c.error('cannot assign to constant `$it.name`', it.pos)
|
if it.name .contains('mod_file_cacher') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.error('cannot modify constant `$it.name`', it.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
|
@ -766,6 +773,9 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
// println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
|
// println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
|
||||||
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
|
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
|
||||||
}
|
}
|
||||||
|
if method.args[0].is_mut {
|
||||||
|
c.fail_if_immutable(call_expr.left)
|
||||||
|
}
|
||||||
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in
|
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in
|
||||||
c.pref.compile_defines {
|
c.pref.compile_defines {
|
||||||
call_expr.should_be_skipped = true
|
call_expr.should_be_skipped = true
|
||||||
|
@ -999,6 +1009,8 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
if arg.is_mut && !call_arg.is_mut {
|
if arg.is_mut && !call_arg.is_mut {
|
||||||
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
||||||
call_arg.expr.position())
|
call_arg.expr.position())
|
||||||
|
} else if !arg.is_mut && call_arg.is_mut {
|
||||||
|
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
|
||||||
}
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
if arg_typ_sym.kind == .interface_ {
|
if arg_typ_sym.kind == .interface_ {
|
||||||
|
|
|
@ -8,10 +8,10 @@ import v.ast
|
||||||
import os
|
import os
|
||||||
|
|
||||||
struct Doc {
|
struct Doc {
|
||||||
out strings.Builder
|
|
||||||
table &table.Table
|
table &table.Table
|
||||||
mod string
|
mod string
|
||||||
mut:
|
mut:
|
||||||
|
out strings.Builder
|
||||||
stmts []ast.Stmt // all module statements from all files
|
stmts []ast.Stmt // all module statements from all files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
|
table &table.Table
|
||||||
|
pref &pref.Preferences
|
||||||
|
module_built string
|
||||||
|
mut:
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
cheaders strings.Builder
|
cheaders strings.Builder
|
||||||
includes strings.Builder // all C #includes required by V modules
|
includes strings.Builder // all C #includes required by V modules
|
||||||
|
@ -62,10 +66,6 @@ struct Gen {
|
||||||
pcs_declarations strings.Builder // -prof profile counter declarations for each function
|
pcs_declarations strings.Builder // -prof profile counter declarations for each function
|
||||||
hotcode_definitions strings.Builder // -live declarations & functions
|
hotcode_definitions strings.Builder // -live declarations & functions
|
||||||
options strings.Builder // `Option_xxxx` types
|
options strings.Builder // `Option_xxxx` types
|
||||||
table &table.Table
|
|
||||||
pref &pref.Preferences
|
|
||||||
module_built string
|
|
||||||
mut:
|
|
||||||
file ast.File
|
file ast.File
|
||||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||||
last_fn_c_name string
|
last_fn_c_name string
|
||||||
|
@ -178,7 +178,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
//
|
//
|
||||||
g.finish()
|
g.finish()
|
||||||
//
|
//
|
||||||
b := strings.new_builder(250000)
|
mut b := strings.new_builder(250000)
|
||||||
b.writeln(g.hashes())
|
b.writeln(g.hashes())
|
||||||
b.writeln(g.comptime_defines.str())
|
b.writeln(g.comptime_defines.str())
|
||||||
b.writeln('\n// V typedefs:')
|
b.writeln('\n// V typedefs:')
|
||||||
|
@ -311,7 +311,7 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// V type to C type
|
// V type to C type
|
||||||
fn (mut g Gen) typ(t table.Type) string {
|
fn (g &Gen) typ(t table.Type) string {
|
||||||
mut styp := g.base_type(t)
|
mut styp := g.base_type(t)
|
||||||
if styp.len == 1 && t == table.t_type && g.cur_generic_type != 0 {
|
if styp.len == 1 && t == table.t_type && g.cur_generic_type != 0 {
|
||||||
// T => int etc
|
// T => int etc
|
||||||
|
@ -339,7 +339,7 @@ fn (g &Gen) base_type(t table.Type) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this really shouldnt be seperate from typ
|
// TODO this really shouldnt be seperate from typ
|
||||||
// but I(emily) would rather have this generation
|
// but I(emily) would rather have this generation
|
||||||
// all unified in one place so that it doesnt break
|
// all unified in one place so that it doesnt break
|
||||||
// if one location changes
|
// if one location changes
|
||||||
fn (g &Gen) optional_type_name(t table.Type) (string, string) {
|
fn (g &Gen) optional_type_name(t table.Type) (string, string) {
|
||||||
|
@ -2796,7 +2796,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
||||||
for field in info.fields {
|
for field in info.fields {
|
||||||
// Some of these structs may want to contain
|
// Some of these structs may want to contain
|
||||||
// optionals that may not be defined at this point
|
// optionals that may not be defined at this point
|
||||||
// if this is the case then we are going to
|
// if this is the case then we are going to
|
||||||
// buffer manip out in front of the struct
|
// buffer manip out in front of the struct
|
||||||
// write the optional in and then continue
|
// write the optional in and then continue
|
||||||
if field.typ.flag_is(.optional) {
|
if field.typ.flag_is(.optional) {
|
||||||
|
|
|
@ -23,9 +23,9 @@ const (
|
||||||
|
|
||||||
struct JsGen {
|
struct JsGen {
|
||||||
table &table.Table
|
table &table.Table
|
||||||
definitions strings.Builder
|
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
|
definitions strings.Builder
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
namespaces map[string]strings.Builder
|
namespaces map[string]strings.Builder
|
||||||
namespaces_pub map[string][]string
|
namespaces_pub map[string][]string
|
||||||
|
|
|
@ -3,6 +3,7 @@ module js
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
struct JsDoc {
|
struct JsDoc {
|
||||||
|
mut:
|
||||||
gen &JsGen
|
gen &JsGen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sym := p.table.get_type_symbol(arg.typ)
|
sym := p.table.get_type_symbol(arg.typ)
|
||||||
if sym.kind !in [.array, .struct_, .map, .placeholder] && !arg.typ.is_ptr() {
|
if sym.kind !in [.array, .struct_, .map, .placeholder] && arg.typ != table.t_type &&
|
||||||
|
!arg.typ.is_ptr() {
|
||||||
p.error('mutable arguments are only allowed for arrays, maps, and structs\n' +
|
p.error('mutable arguments are only allowed for arrays, maps, and structs\n' +
|
||||||
'return values instead: `fn foo(n mut int) {` => `fn foo(n int) int {`')
|
'return values instead: `fn foo(n mut int) {` => `fn foo(n int) int {`')
|
||||||
}
|
}
|
||||||
|
@ -359,6 +360,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn decl
|
||||||
fn (mut p Parser) fn_args() ([]table.Arg, bool) {
|
fn (mut p Parser) fn_args() ([]table.Arg, bool) {
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
mut args := []table.Arg{}
|
mut args := []table.Arg{}
|
||||||
|
@ -381,7 +383,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) {
|
||||||
is_variadic = true
|
is_variadic = true
|
||||||
}
|
}
|
||||||
mut arg_type := p.parse_type()
|
mut arg_type := p.parse_type()
|
||||||
if is_mut {
|
if is_mut && arg_type != table.t_type {
|
||||||
// if arg_type.is_ptr() {
|
// if arg_type.is_ptr() {
|
||||||
// p.error('cannot mut')
|
// p.error('cannot mut')
|
||||||
// }
|
// }
|
||||||
|
@ -425,7 +427,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) {
|
||||||
is_variadic = true
|
is_variadic = true
|
||||||
}
|
}
|
||||||
mut typ := p.parse_type()
|
mut typ := p.parse_type()
|
||||||
if is_mut {
|
if is_mut && typ != table.t_type {
|
||||||
if typ.is_ptr() {
|
if typ.is_ptr() {
|
||||||
// name := p.table.get_type_name(typ)
|
// name := p.table.get_type_name(typ)
|
||||||
// p.warn('`$name` is already a reference, it cannot be marked as `mut`')
|
// p.warn('`$name` is already a reference, it cannot be marked as `mut`')
|
||||||
|
|
|
@ -16,10 +16,10 @@ import runtime
|
||||||
import time
|
import time
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
scanner &scanner.Scanner
|
|
||||||
file_name string // "/home/user/hello.v"
|
file_name string // "/home/user/hello.v"
|
||||||
file_name_dir string // "/home/user"
|
file_name_dir string // "/home/user"
|
||||||
mut:
|
mut:
|
||||||
|
scanner &scanner.Scanner
|
||||||
tok token.Token
|
tok token.Token
|
||||||
prev_tok token.Token
|
prev_tok token.Token
|
||||||
peek_tok token.Token
|
peek_tok token.Token
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn mpath() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_preferences() Preferences {
|
pub fn new_preferences() Preferences {
|
||||||
p := Preferences{}
|
mut p := Preferences{}
|
||||||
p.fill_with_defaults()
|
p.fill_with_defaults()
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@ module pref
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files []string) []string {
|
pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []string) []string {
|
||||||
mut res := []string{}
|
mut res := []string{}
|
||||||
|
mut files := files_.clone()
|
||||||
files.sort()
|
files.sort()
|
||||||
for file in files {
|
for file in files {
|
||||||
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub enum TypeFlag {
|
||||||
unset
|
unset
|
||||||
optional
|
optional
|
||||||
variadic
|
variadic
|
||||||
|
generic
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (types []Type) contains(typ Type) bool {
|
pub fn (types []Type) contains(typ Type) bool {
|
||||||
|
|
|
@ -40,6 +40,7 @@ fn test_foo() {
|
||||||
|
|
||||||
fn create<T>() {
|
fn create<T>() {
|
||||||
a := T{}
|
a := T{}
|
||||||
|
println(a.foo)
|
||||||
mut xx := T{}
|
mut xx := T{}
|
||||||
xx.foo = 'foo'
|
xx.foo = 'foo'
|
||||||
println(xx.foo)
|
println(xx.foo)
|
||||||
|
@ -63,10 +64,15 @@ fn (u User) init() {
|
||||||
fn (c City) init() {
|
fn (c City) init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gen_arg<T>(mut x T) {
|
||||||
|
println(x.foo) // = 'foo'
|
||||||
|
}
|
||||||
|
|
||||||
fn test_create() {
|
fn test_create() {
|
||||||
create<User>()
|
create<User>()
|
||||||
create<City>()
|
create<City>()
|
||||||
// create<User>()
|
u := User{}
|
||||||
|
//gen_arg<User>(mut u)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -142,8 +142,8 @@ pub fn run<T>(port int) {
|
||||||
//app.reset()
|
//app.reset()
|
||||||
for {
|
for {
|
||||||
conn := l.accept() or { panic('accept() failed') }
|
conn := l.accept() or { panic('accept() failed') }
|
||||||
handle_conn<T>(conn, mut app)
|
//handle_conn<T>(conn, mut app)
|
||||||
//foobar<T>()
|
app = handle_conn<T>(conn, app)
|
||||||
// TODO move this to handle_conn<T>(conn, app)
|
// TODO move this to handle_conn<T>(conn, app)
|
||||||
//message := readall(conn)
|
//message := readall(conn)
|
||||||
//println(message)
|
//println(message)
|
||||||
|
@ -169,7 +169,9 @@ pub fn run<T>(port int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_conn<T>(conn net.Socket, app mut T) {
|
//fn handle_conn<T>(conn net.Socket, app mut T) {
|
||||||
|
fn handle_conn<T>(conn net.Socket, app_ T) T {
|
||||||
|
mut app := app_
|
||||||
//first_line := strip(lines[0])
|
//first_line := strip(lines[0])
|
||||||
first_line := conn.read_line()
|
first_line := conn.read_line()
|
||||||
println('firstline="$first_line"')
|
println('firstline="$first_line"')
|
||||||
|
@ -182,7 +184,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) {
|
||||||
println('no vals for http')
|
println('no vals for http')
|
||||||
conn.send_string(http_500) or {}
|
conn.send_string(http_500) or {}
|
||||||
conn.close() or {}
|
conn.close() or {}
|
||||||
return
|
return app
|
||||||
//continue
|
//continue
|
||||||
}
|
}
|
||||||
mut headers := []string{}
|
mut headers := []string{}
|
||||||
|
@ -263,7 +265,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) {
|
||||||
println('no vals for http')
|
println('no vals for http')
|
||||||
}
|
}
|
||||||
conn.close() or {}
|
conn.close() or {}
|
||||||
return
|
return app
|
||||||
//continue
|
//continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,10 +276,10 @@ fn handle_conn<T>(conn net.Socket, app mut T) {
|
||||||
if static_file != '' && mime_type != '' {
|
if static_file != '' && mime_type != '' {
|
||||||
data := os.read_file(static_file) or {
|
data := os.read_file(static_file) or {
|
||||||
conn.send_string(http_404) or {}
|
conn.send_string(http_404) or {}
|
||||||
return
|
return app
|
||||||
}
|
}
|
||||||
app.vweb.send_response_to_client(mime_type, data)
|
app.vweb.send_response_to_client(mime_type, data)
|
||||||
return
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the right action
|
// Call the right action
|
||||||
|
@ -292,6 +294,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) {
|
||||||
*/
|
*/
|
||||||
conn.close() or {}
|
conn.close() or {}
|
||||||
app.reset()
|
app.reset()
|
||||||
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut ctx Context) parse_form(s string) {
|
fn (mut ctx Context) parse_form(s string) {
|
||||||
|
|
Loading…
Reference in New Issue