checker: disallow pub in main
							parent
							
								
									de9f302412
								
							
						
					
					
						commit
						57c142b993
					
				|  | @ -235,7 +235,7 @@ fn find_working_diff_command() ?string { | |||
| 	return error('no working diff command found') | ||||
| } | ||||
| 
 | ||||
| pub fn (f FormatOptions) str() string { | ||||
| fn (f FormatOptions) str() string { | ||||
| 	return 'FormatOptions{ is_l: $f.is_l' + ' is_w: $f.is_w' + ' is_diff: $f.is_diff' + ' is_verbose: $f.is_verbose' + | ||||
| 		' is_all: $f.is_all' + ' is_worker: $f.is_worker' + ' is_debug: $f.is_debug' + ' }' | ||||
| } | ||||
|  |  | |||
|  | @ -3,10 +3,8 @@ | |||
| // that can be found in the LICENSE file.
 | ||||
| module ast | ||||
| 
 | ||||
| import ( | ||||
| 	v.token | ||||
| 	v.table | ||||
| ) | ||||
| import v.token | ||||
| import v.table | ||||
| 
 | ||||
| pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl | ||||
| 
 | ||||
|  | @ -95,9 +93,9 @@ mut: | |||
| // module declaration
 | ||||
| pub struct Module { | ||||
| pub: | ||||
| 	name string | ||||
| 	path string | ||||
| 	expr Expr | ||||
| 	name       string | ||||
| 	path       string | ||||
| 	expr       Expr | ||||
| 	is_skipped bool // module main can be skipped in single file programs
 | ||||
| } | ||||
| 
 | ||||
|  | @ -162,7 +160,7 @@ pub struct StructInitField { | |||
| pub: | ||||
| 	name          string | ||||
| 	expr          Expr | ||||
| 	pos			  token.Position | ||||
| 	pos           token.Position | ||||
| mut: | ||||
| 	typ           table.Type | ||||
| 	expected_type table.Type | ||||
|  | @ -189,7 +187,7 @@ pub struct AnonFn { | |||
| pub: | ||||
| 	decl FnDecl | ||||
| mut: | ||||
| 	typ table.Type | ||||
| 	typ  table.Type | ||||
| } | ||||
| 
 | ||||
| pub struct FnDecl { | ||||
|  | @ -228,7 +226,7 @@ mut: | |||
| 	args               []CallArg | ||||
| 	expected_arg_types []table.Type | ||||
| 	is_c               bool | ||||
| 	is_js			   bool | ||||
| 	is_js              bool | ||||
| 	or_block           OrExpr | ||||
| 	left_type          table.Type // type of `user`
 | ||||
| 	receiver_type      table.Type // User
 | ||||
|  | @ -326,7 +324,7 @@ pub: | |||
| 	tok_kind token.Kind | ||||
| 	mod      string | ||||
| 	pos      token.Position | ||||
| 	is_mut bool | ||||
| 	is_mut   bool | ||||
| mut: | ||||
| 	name     string | ||||
| 	kind     IdentKind | ||||
|  | @ -537,11 +535,11 @@ pub struct EnumField { | |||
| 
 | ||||
| pub struct EnumDecl { | ||||
| pub: | ||||
| 	name          string | ||||
| 	is_pub        bool | ||||
| 	fields        []EnumField | ||||
| 	// vals          []string
 | ||||
| 	name   string | ||||
| 	is_pub bool | ||||
| 	fields []EnumField | ||||
| 	// default_exprs []Expr
 | ||||
| 	pos    token.Position | ||||
| } | ||||
| 
 | ||||
| pub struct AliasTypeDecl { | ||||
|  | @ -549,6 +547,7 @@ pub: | |||
| 	name        string | ||||
| 	is_pub      bool | ||||
| 	parent_type table.Type | ||||
| 	pos         token.Position | ||||
| } | ||||
| 
 | ||||
| pub struct SumTypeDecl { | ||||
|  | @ -556,6 +555,7 @@ pub: | |||
| 	name      string | ||||
| 	is_pub    bool | ||||
| 	sub_types []table.Type | ||||
| 	pos       token.Position | ||||
| } | ||||
| 
 | ||||
| pub struct FnTypeDecl { | ||||
|  | @ -563,6 +563,7 @@ pub: | |||
| 	name   string | ||||
| 	is_pub bool | ||||
| 	typ    table.Type | ||||
| 	pos    token.Position | ||||
| } | ||||
| 
 | ||||
| // TODO: handle this differently
 | ||||
|  | @ -720,30 +721,22 @@ pub: | |||
| [inline] | ||||
| pub fn expr_is_blank_ident(expr Expr) bool { | ||||
| 	match expr { | ||||
| 		Ident { | ||||
| 			return it.kind == .blank_ident | ||||
| 		} | ||||
| 		else { | ||||
| 			return false | ||||
| 		} | ||||
| 		Ident { return it.kind == .blank_ident } | ||||
| 		else { return false } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| pub fn expr_is_call(expr Expr) bool { | ||||
| 	return match expr { | ||||
| 		CallExpr { | ||||
| 			true | ||||
| 		} | ||||
| 		else { | ||||
| 			false | ||||
| 		} | ||||
| 		CallExpr { true } | ||||
| 		else { false } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (expr Expr) position() token.Position { | ||||
| 	// all uncommented have to be implemented
 | ||||
| 	match mut expr { | ||||
| 	match var expr { | ||||
| 		ArrayInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
|  |  | |||
|  | @ -66,11 +66,8 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) { | |||
| 	for file in ast_files { | ||||
| 		c.check(file) | ||||
| 		if file.mod.name == 'main' { | ||||
| 			if fn_decl := get_main_fn_decl(file) { | ||||
| 			if c.check_file_in_main(file) { | ||||
| 				has_main_fn = true | ||||
| 				if fn_decl.is_pub { | ||||
| 					c.error('function `main` cannot be declared public', fn_decl.pos) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -87,16 +84,71 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn get_main_fn_decl(file ast.File) ?ast.FnDecl { | ||||
| const ( | ||||
| 	no_pub_in_main_warning = 'in module main cannot be declared public' | ||||
| ) | ||||
| 
 | ||||
| // do checks specific to files in main module
 | ||||
| // returns `true` if a main function is in the file
 | ||||
| fn (c mut Checker) check_file_in_main(file ast.File) bool { | ||||
| 	mut has_main_fn := false | ||||
| 	for stmt in file.stmts { | ||||
| 		if stmt is ast.FnDecl { | ||||
| 			fn_decl := stmt as ast.FnDecl | ||||
| 			if fn_decl.name == 'main' { | ||||
| 				return fn_decl | ||||
| 		match stmt { | ||||
| 			ast.ConstDecl { | ||||
| 				if it.is_pub { | ||||
| 					c.warn('const $no_pub_in_main_warning', it.pos) | ||||
| 				} | ||||
| 			} | ||||
| 			ast.ConstField { | ||||
| 				if it.is_pub { | ||||
| 					c.warn('const field `$it.name` $no_pub_in_main_warning', it.pos) | ||||
| 				} | ||||
| 			} | ||||
| 			ast.EnumDecl { | ||||
| 				if it.is_pub { | ||||
| 					c.warn('enum `$it.name` $no_pub_in_main_warning', it.pos) | ||||
| 				} | ||||
| 			} | ||||
| 			ast.FnDecl { | ||||
| 				if it.name == 'main' { | ||||
| 					has_main_fn = true | ||||
| 					if it.is_pub { | ||||
| 						c.error('function `main` cannot be declared public', it.pos) | ||||
| 					} | ||||
| 				} else { | ||||
| 					if it.is_pub { | ||||
| 						c.warn('function `$it.name` $no_pub_in_main_warning', it.pos) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			ast.StructDecl { | ||||
| 				if it.is_pub { | ||||
| 					c.warn('struct `$it.name` $no_pub_in_main_warning', it.pos) | ||||
| 				} | ||||
| 			} | ||||
| 			ast.TypeDecl { | ||||
| 				type_decl := stmt as ast.TypeDecl | ||||
| 				if type_decl is ast.AliasTypeDecl { | ||||
| 					alias_decl := type_decl as ast.AliasTypeDecl | ||||
| 					if alias_decl.is_pub { | ||||
| 						c.warn('type alias `$alias_decl.name` $no_pub_in_main_warning', alias_decl.pos) | ||||
| 					} | ||||
| 				} else if type_decl is ast.SumTypeDecl { | ||||
| 					sum_decl := type_decl as ast.SumTypeDecl | ||||
| 					if sum_decl.is_pub { | ||||
| 						c.warn('sum type `$sum_decl.name` $no_pub_in_main_warning', sum_decl.pos) | ||||
| 					} | ||||
| 				} else if type_decl is ast.FnTypeDecl { | ||||
| 					fn_decl := type_decl as ast.FnTypeDecl | ||||
| 					if fn_decl.is_pub { | ||||
| 						c.warn('type alias `$fn_decl.name` $no_pub_in_main_warning', fn_decl.pos) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else {} | ||||
| 		} | ||||
| 	} | ||||
| 	return none | ||||
| 	return has_main_fn | ||||
| } | ||||
| 
 | ||||
| pub fn (c mut Checker) struct_decl(decl ast.StructDecl) { | ||||
|  |  | |||
|  | @ -24,7 +24,8 @@ fn test_all() { | |||
| 		os.cp(path, program) or { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 		res := os.exec('$vexe $program') or { | ||||
| 		// -prod so that warn are errors
 | ||||
| 		res := os.exec('$vexe -prod $program') or { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 		mut expected := os.read_file(program.replace('.v', '') + '.out') or { | ||||
|  |  | |||
|  | @ -0,0 +1,49 @@ | |||
| vlib/v/checker/tests/inout/no_pub_in_main.v:3:1: error: type alias `Integer` in module main cannot be declared public | ||||
|     1| module main | ||||
|     2| | ||||
|     3| pub type Integer = int | ||||
|        ~~~~~~~~~~~~~~~~ | ||||
|     4| | ||||
|     5| pub type Float = f32 | f64 | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:5:1: error: sum type `Float` in module main cannot be declared public | ||||
|     3| pub type Integer = int | ||||
|     4| | ||||
|     5| pub type Float = f32 | f64 | ||||
|        ~~~~~~~~~~~~~~ | ||||
|     6| | ||||
|     7| // Buggy ATM | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:10:1: error: enum `Color` in module main cannot be declared public | ||||
|     8| // pub type Fn = fn () int | ||||
|     9| | ||||
|    10| pub enum Color { | ||||
|        ~~~~~~~~~~~~~~ | ||||
|    11|     red | ||||
|    12|     green | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:16:1: error: const in module main cannot be declared public | ||||
|    14| } | ||||
|    15| | ||||
|    16| pub const ( | ||||
|        ~~~~~~~~~ | ||||
|    17|     w = 'world' | ||||
|    18| ) | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:20:1: error: function `my_fn` in module main cannot be declared public | ||||
|    18| ) | ||||
|    19| | ||||
|    20| pub fn my_fn() int { | ||||
|        ~~~~~~~~~~~~~~~~~~ | ||||
|    21|     return 1 | ||||
|    22| } | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:24:1: error: function `main` cannot be declared public | ||||
|    22| } | ||||
|    23| | ||||
|    24| pub fn main() { | ||||
|        ~~~~~~~~~~~~~ | ||||
|    25|     println('main') | ||||
|    26| } | ||||
| vlib/v/checker/tests/inout/no_pub_in_main.v:28:1: error: struct `MyStruct` in module main cannot be declared public | ||||
|    26| } | ||||
|    27| | ||||
|    28| pub struct MyStruct { | ||||
|        ~~~~~~~~~~~~~~~~~~~ | ||||
|    29|     field int | ||||
|    30| } | ||||
|  | @ -0,0 +1,30 @@ | |||
| module main | ||||
| 
 | ||||
| pub type Integer = int | ||||
| 
 | ||||
| pub type Float = f32 | f64 | ||||
| 
 | ||||
| // Buggy ATM
 | ||||
| // pub type Fn = fn () int
 | ||||
| 
 | ||||
| pub enum Color { | ||||
| 	red | ||||
| 	green | ||||
| 	blue | ||||
| } | ||||
| 
 | ||||
| pub const ( | ||||
| 	w = 'world' | ||||
| ) | ||||
| 
 | ||||
| pub fn my_fn() int { | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| pub fn main() { | ||||
| 	println('main') | ||||
| } | ||||
| 
 | ||||
| pub struct MyStruct { | ||||
| 	field int | ||||
| } | ||||
|  | @ -1,5 +0,0 @@ | |||
| vlib/v/checker/tests/inout/pub_fn_main.v:1:1: error: function `main` cannot be declared public | ||||
|     1| pub fn main() { | ||||
|        ~~~ | ||||
|     2|     println('Hello world !') | ||||
|     3| } | ||||
|  | @ -1,3 +0,0 @@ | |||
| pub fn main() { | ||||
| 	println('Hello world !') | ||||
| } | ||||
|  | @ -85,7 +85,7 @@ pub fn (var p Parser) call_args() []ast.CallArg { | |||
| 
 | ||||
| fn (var p Parser) fn_decl() ast.FnDecl { | ||||
| 	// p.table.clear_vars()
 | ||||
| 	pos := p.tok.position() | ||||
| 	start_pos := p.tok.position() | ||||
| 	p.open_scope() | ||||
| 	is_deprecated := p.attr == 'deprecated' | ||||
| 	is_pub := p.tok.kind == .key_pub | ||||
|  | @ -165,9 +165,11 @@ fn (var p Parser) fn_decl() ast.FnDecl { | |||
| 			typ: arg.typ | ||||
| 		}) | ||||
| 	} | ||||
| 	var end_pos := p.prev_tok.position() | ||||
| 	// Return type
 | ||||
| 	var return_type := table.void_type | ||||
| 	if p.tok.kind.is_start_of_type() { | ||||
| 		end_pos = p.tok.position() | ||||
| 		return_type = p.parse_type() | ||||
| 	} | ||||
| 	// Register
 | ||||
|  | @ -229,7 +231,7 @@ fn (var p Parser) fn_decl() ast.FnDecl { | |||
| 		is_c: is_c | ||||
| 		is_js: is_js | ||||
| 		no_body: no_body | ||||
| 		pos: pos | ||||
| 		pos: start_pos.extend(end_pos) | ||||
| 		is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -945,11 +945,12 @@ fn (var p Parser) import_stmt() []ast.Import { | |||
| } | ||||
| 
 | ||||
| fn (var p Parser) const_decl() ast.ConstDecl { | ||||
| 	start_pos := p.tok.position() | ||||
| 	is_pub := p.tok.kind == .key_pub | ||||
| 	if is_pub { | ||||
| 		p.next() | ||||
| 	} | ||||
| 	pos := p.tok.position() | ||||
| 	end_pos := p.tok.position() | ||||
| 	p.check(.key_const) | ||||
| 	if p.tok.kind != .lpar { | ||||
| 		p.error('consts must be grouped, e.g.\nconst (\n\ta = 1\n)') | ||||
|  | @ -975,7 +976,7 @@ fn (var p Parser) const_decl() ast.ConstDecl { | |||
| 	} | ||||
| 	p.check(.rpar) | ||||
| 	return ast.ConstDecl{ | ||||
| 		pos: pos | ||||
| 		pos: start_pos.extend(end_pos) | ||||
| 		fields: fields | ||||
| 		is_pub: is_pub | ||||
| 	} | ||||
|  | @ -1000,14 +1001,10 @@ fn (var p Parser) return_stmt() ast.Return { | |||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	last_pos := exprs.last().position() | ||||
| 	end_pos := exprs.last().position() | ||||
| 	return ast.Return{ | ||||
| 		exprs: exprs | ||||
| 		pos: token.Position{ | ||||
| 			line_nr: first_pos.line_nr | ||||
| 			pos: first_pos.pos | ||||
| 			len: last_pos.pos - first_pos.pos + last_pos.len | ||||
| 		} | ||||
| 		pos: first_pos.extend(end_pos) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -1054,10 +1051,12 @@ fn (var p Parser) global_decl() ast.GlobalDecl { | |||
| 
 | ||||
| fn (var p Parser) enum_decl() ast.EnumDecl { | ||||
| 	is_pub := p.tok.kind == .key_pub | ||||
| 	start_pos := p.tok.position() | ||||
| 	if is_pub { | ||||
| 		p.next() | ||||
| 	} | ||||
| 	p.check(.key_enum) | ||||
| 	end_pos := p.tok.position() | ||||
| 	name := p.prepend_mod(p.check_name()) | ||||
| 	p.check(.lcbr) | ||||
| 	var vals := []string | ||||
|  | @ -1101,15 +1100,19 @@ fn (var p Parser) enum_decl() ast.EnumDecl { | |||
| 		name: name | ||||
| 		is_pub: is_pub | ||||
| 		fields: fields | ||||
| 		pos: start_pos.extend(end_pos) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (var p Parser) type_decl() ast.TypeDecl { | ||||
| 	start_pos := p.tok.position() | ||||
| 	is_pub := p.tok.kind == .key_pub | ||||
| 	if is_pub { | ||||
| 		p.next() | ||||
| 	} | ||||
| 	p.check(.key_type) | ||||
| 	end_pos := p.tok.position() | ||||
| 	decl_pos := start_pos.extend(end_pos) | ||||
| 	name := p.check_name() | ||||
| 	var sum_variants := []table.Type | ||||
| 	if p.tok.kind == .assign { | ||||
|  | @ -1123,6 +1126,7 @@ fn (var p Parser) type_decl() ast.TypeDecl { | |||
| 			name: fn_name | ||||
| 			is_pub: is_pub | ||||
| 			typ: fn_type | ||||
| 			pos: decl_pos | ||||
| 		} | ||||
| 	} | ||||
| 	first_type := p.parse_type()	// need to parse the first type before we can check if it's `type A = X | Y`
 | ||||
|  | @ -1149,6 +1153,7 @@ fn (var p Parser) type_decl() ast.TypeDecl { | |||
| 			name: name | ||||
| 			is_pub: is_pub | ||||
| 			sub_types: sum_variants | ||||
| 			pos: decl_pos | ||||
| 		} | ||||
| 	} | ||||
| 	// type MyType int
 | ||||
|  | @ -1166,6 +1171,7 @@ fn (var p Parser) type_decl() ast.TypeDecl { | |||
| 		name: name | ||||
| 		is_pub: is_pub | ||||
| 		parent_type: parent_type | ||||
| 		pos: decl_pos | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ import v.table | |||
| import v.token | ||||
| 
 | ||||
| fn (var p Parser) struct_decl() ast.StructDecl { | ||||
| 	first_pos := p.tok.position() | ||||
| 	start_pos := p.tok.position() | ||||
| 	is_pub := p.tok.kind == .key_pub | ||||
| 	if is_pub { | ||||
| 		p.next() | ||||
|  | @ -30,6 +30,7 @@ fn (var p Parser) struct_decl() ast.StructDecl { | |||
| 	if !is_c && !is_js && no_body { | ||||
| 		p.error('`$p.tok.lit` lacks body') | ||||
| 	} | ||||
| 	end_pos := p.tok.position() | ||||
| 	var name := p.check_name() | ||||
| 	// println('struct decl $name')
 | ||||
| 	var ast_fields := []ast.StructField | ||||
|  | @ -37,7 +38,6 @@ fn (var p Parser) struct_decl() ast.StructDecl { | |||
| 	var mut_pos := -1 | ||||
| 	var pub_pos := -1 | ||||
| 	var pub_mut_pos := -1 | ||||
| 	var last_pos := token.Position{} | ||||
| 	if !no_body { | ||||
| 		p.check(.lcbr) | ||||
| 		for p.tok.kind != .rcbr { | ||||
|  | @ -113,7 +113,6 @@ fn (var p Parser) struct_decl() ast.StructDecl { | |||
| 			} | ||||
| 			// println('struct field $ti.name $field_name')
 | ||||
| 		} | ||||
| 		last_pos = p.tok.position() | ||||
| 		p.check(.rcbr) | ||||
| 	} | ||||
| 	if is_c { | ||||
|  | @ -145,16 +144,11 @@ fn (var p Parser) struct_decl() ast.StructDecl { | |||
| 		p.error('cannot register type `$name`, another type with this name exists') | ||||
| 	} | ||||
| 	p.expr_mod = '' | ||||
| 	pos := token.Position{ | ||||
| 		line_nr: first_pos.line_nr | ||||
| 		pos: first_pos.pos | ||||
| 		len: last_pos.pos - first_pos.pos + last_pos.len | ||||
| 	} | ||||
| 	return ast.StructDecl{ | ||||
| 		name: name | ||||
| 		is_pub: is_pub | ||||
| 		fields: ast_fields | ||||
| 		pos: pos | ||||
| 		pos: start_pos.extend(end_pos) | ||||
| 		mut_pos: mut_pos | ||||
| 		pub_pos: pub_pos | ||||
| 		pub_mut_pos: pub_mut_pos | ||||
|  |  | |||
|  | @ -14,6 +14,13 @@ pub fn (pos Position) str() string { | |||
| 	return 'Position{ line_nr: $pos.line_nr, pos: $pos.pos, len: $pos.len }' | ||||
| } | ||||
| 
 | ||||
| pub fn (pos Position) extend(end Position) Position { | ||||
| 	return { | ||||
| 		pos | | ||||
| 		len: end.pos - pos.pos + end.len | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| pub fn (tok &Token) position() Position { | ||||
| 	return Position{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue