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') | ||||
| 	} | ||||
| 	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') | ||||
| 	} | ||||
| 	f.close() | ||||
|  |  | |||
|  | @ -13,10 +13,10 @@ import v.depgraph | |||
| pub struct Builder { | ||||
| pub: | ||||
| 	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 .`
 | ||||
| 	module_path         string | ||||
| mut: | ||||
| 	checker             checker.Checker | ||||
| 	pref                &pref.Preferences | ||||
| 	parsed_files        []ast.File | ||||
| 	global_scope        &ast.Scope | ||||
|  |  | |||
|  | @ -15,8 +15,8 @@ const ( | |||
| ) | ||||
| 
 | ||||
| pub struct Checker { | ||||
| 	table            &table.Table | ||||
| pub mut: | ||||
| 	table            &table.Table | ||||
| 	file             ast.File | ||||
| 	nr_errors        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) { | ||||
| 	match expr { | ||||
| 		ast.CastExpr { | ||||
| 			// TODO
 | ||||
| 			return | ||||
| 		} | ||||
| 		ast.Ident { | ||||
| 			scope := c.file.scope.innermost(it.pos.pos) | ||||
| 			if v := scope.find_var(it.name) { | ||||
|  | @ -580,7 +584,10 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) { | |||
| 						it.pos) | ||||
| 				} | ||||
| 			} 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 { | ||||
|  | @ -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')
 | ||||
| 			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 | ||||
| 			c.pref.compile_defines { | ||||
| 			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 { | ||||
| 			c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`', | ||||
| 				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
 | ||||
| 		if arg_typ_sym.kind == .interface_ { | ||||
|  |  | |||
|  | @ -8,10 +8,10 @@ import v.ast | |||
| import os | ||||
| 
 | ||||
| struct Doc { | ||||
| 	out   strings.Builder | ||||
| 	table &table.Table | ||||
| 	mod   string | ||||
| mut: | ||||
| 	out   strings.Builder | ||||
| 	stmts []ast.Stmt // all module statements from all files
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -46,6 +46,10 @@ const ( | |||
| ) | ||||
| 
 | ||||
| struct Gen { | ||||
| 	table                &table.Table | ||||
| 	pref                 &pref.Preferences | ||||
| 	module_built         string | ||||
| mut: | ||||
| 	out                  strings.Builder | ||||
| 	cheaders             strings.Builder | ||||
| 	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
 | ||||
| 	hotcode_definitions  strings.Builder // -live declarations & functions
 | ||||
| 	options              strings.Builder // `Option_xxxx` types
 | ||||
| 	table                &table.Table | ||||
| 	pref                 &pref.Preferences | ||||
| 	module_built         string | ||||
| mut: | ||||
| 	file                 ast.File | ||||
| 	fn_decl              &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
 | ||||
| 	last_fn_c_name       string | ||||
|  | @ -178,7 +178,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string | |||
| 	//
 | ||||
| 	g.finish() | ||||
| 	//
 | ||||
| 	b := strings.new_builder(250000) | ||||
| 	mut b := strings.new_builder(250000) | ||||
| 	b.writeln(g.hashes()) | ||||
| 	b.writeln(g.comptime_defines.str()) | ||||
| 	b.writeln('\n// V typedefs:') | ||||
|  | @ -311,7 +311,7 @@ pub fn (mut g Gen) write_typeof_functions() { | |||
| } | ||||
| 
 | ||||
| // 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) | ||||
| 	if styp.len == 1 && t == table.t_type && g.cur_generic_type != 0 { | ||||
| 		// T => int etc
 | ||||
|  | @ -339,7 +339,7 @@ fn (g &Gen) base_type(t table.Type) string { | |||
| } | ||||
| 
 | ||||
| // 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
 | ||||
| // if one location changes
 | ||||
| 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 { | ||||
| 						// Some of these structs may want to contain
 | ||||
| 						// 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
 | ||||
| 						// write the optional in and then continue
 | ||||
| 						if field.typ.flag_is(.optional) { | ||||
|  |  | |||
|  | @ -23,9 +23,9 @@ const ( | |||
| 
 | ||||
| struct JsGen { | ||||
| 	table             &table.Table | ||||
| 	definitions       strings.Builder | ||||
| 	pref              &pref.Preferences | ||||
| mut: | ||||
| 	definitions       strings.Builder | ||||
| 	out               strings.Builder | ||||
| 	namespaces        map[string]strings.Builder | ||||
| 	namespaces_pub    map[string][]string | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ module js | |||
| import v.ast | ||||
| 
 | ||||
| struct JsDoc { | ||||
| mut: | ||||
| 	gen        &JsGen | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -221,7 +221,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 				continue | ||||
| 			} | ||||
| 			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' + | ||||
| 					'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) { | ||||
| 	p.check(.lpar) | ||||
| 	mut args := []table.Arg{} | ||||
|  | @ -381,7 +383,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) { | |||
| 				is_variadic = true | ||||
| 			} | ||||
| 			mut arg_type := p.parse_type() | ||||
| 			if is_mut { | ||||
| 			if is_mut && arg_type != table.t_type { | ||||
| 				// if arg_type.is_ptr() {
 | ||||
| 				// p.error('cannot mut')
 | ||||
| 				// }
 | ||||
|  | @ -425,7 +427,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) { | |||
| 				is_variadic = true | ||||
| 			} | ||||
| 			mut typ := p.parse_type() | ||||
| 			if is_mut { | ||||
| 			if is_mut && typ != table.t_type { | ||||
| 				if typ.is_ptr() { | ||||
| 					// name := p.table.get_type_name(typ)
 | ||||
| 					// p.warn('`$name` is already a reference, it cannot be marked as `mut`')
 | ||||
|  |  | |||
|  | @ -16,10 +16,10 @@ import runtime | |||
| import time | ||||
| 
 | ||||
| pub struct Parser { | ||||
| 	scanner           &scanner.Scanner | ||||
| 	file_name         string // "/home/user/hello.v"
 | ||||
| 	file_name_dir     string // "/home/user"
 | ||||
| mut: | ||||
| 	scanner           &scanner.Scanner | ||||
| 	tok               token.Token | ||||
| 	prev_tok          token.Token | ||||
| 	peek_tok          token.Token | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ fn mpath() string { | |||
| } | ||||
| 
 | ||||
| pub fn new_preferences() Preferences { | ||||
| 	p := Preferences{} | ||||
| 	mut p := Preferences{} | ||||
| 	p.fill_with_defaults() | ||||
| 	return p | ||||
| } | ||||
|  |  | |||
|  | @ -2,8 +2,9 @@ module pref | |||
| 
 | ||||
| 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 files := files_.clone() | ||||
| 	files.sort() | ||||
| 	for file in files { | ||||
| 		if !file.ends_with('.v') && !file.ends_with('.vh') { | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ pub enum TypeFlag { | |||
| 	unset | ||||
| 	optional | ||||
| 	variadic | ||||
| 	generic | ||||
| } | ||||
| 
 | ||||
| pub fn (types []Type) contains(typ Type) bool { | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ fn test_foo() { | |||
| 
 | ||||
| fn create<T>() { | ||||
| 	a := T{} | ||||
| 	println(a.foo) | ||||
| 	mut xx := T{} | ||||
| 	xx.foo = 'foo' | ||||
| 	println(xx.foo) | ||||
|  | @ -63,10 +64,15 @@ fn (u User) init() { | |||
| fn (c City) init() { | ||||
| } | ||||
| 
 | ||||
| fn gen_arg<T>(mut x T) { | ||||
| 	println(x.foo) // = 'foo'
 | ||||
| } | ||||
| 
 | ||||
| fn test_create() { | ||||
| 	create<User>() | ||||
| 	create<City>() | ||||
| 	// create<User>()
 | ||||
| 	u := User{} | ||||
| 	//gen_arg<User>(mut u)
 | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  |  | |||
|  | @ -142,8 +142,8 @@ pub fn run<T>(port int) { | |||
| 	//app.reset()
 | ||||
| 	for { | ||||
| 		conn := l.accept() or { panic('accept() failed') } | ||||
| 		handle_conn<T>(conn, mut app) | ||||
| 		//foobar<T>()
 | ||||
| 		//handle_conn<T>(conn, mut app)
 | ||||
| 		app = handle_conn<T>(conn, app) | ||||
| 		// TODO move this to handle_conn<T>(conn, app)
 | ||||
| 		//message := readall(conn)
 | ||||
| 		//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 := conn.read_line() | ||||
| 	println('firstline="$first_line"') | ||||
|  | @ -182,7 +184,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) { | |||
| 		println('no vals for http') | ||||
| 		conn.send_string(http_500) or {} | ||||
| 		conn.close() or {} | ||||
| 		return | ||||
| 		return app | ||||
| 		//continue
 | ||||
| 	} | ||||
| 	mut headers := []string{} | ||||
|  | @ -263,7 +265,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) { | |||
| 			println('no vals for http') | ||||
| 		} | ||||
| 		conn.close() or {} | ||||
| 		return | ||||
| 		return app | ||||
| 		//continue
 | ||||
| 	} | ||||
| 
 | ||||
|  | @ -274,10 +276,10 @@ fn handle_conn<T>(conn net.Socket, app mut T) { | |||
| 	if static_file != '' && mime_type != '' { | ||||
| 		data := os.read_file(static_file) or { | ||||
| 			conn.send_string(http_404) or {} | ||||
| 			return | ||||
| 			return app | ||||
| 		} | ||||
| 		app.vweb.send_response_to_client(mime_type, data) | ||||
| 		return | ||||
| 		return app | ||||
| 	} | ||||
| 
 | ||||
| 	// Call the right action
 | ||||
|  | @ -292,6 +294,7 @@ fn handle_conn<T>(conn net.Socket, app mut T) { | |||
| 	*/ | ||||
| 	conn.close() or {} | ||||
| 	app.reset() | ||||
| 	return app | ||||
| } | ||||
| 
 | ||||
| fn (mut ctx Context) parse_form(s string) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue