checker: disallow pub in main

pull/4498/head
Enzo Baldisserri 2020-04-19 00:07:57 +02:00 committed by GitHub
parent de9f302412
commit 57c142b993
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 193 additions and 67 deletions

View File

@ -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' + ' }'
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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| }

View File

@ -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
}

View File

@ -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| }

View File

@ -1,3 +0,0 @@
pub fn main() {
println('Hello world !')
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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{