checker: make a calling no-body function a checker error (#8265)
							parent
							
								
									2007dbc7b5
								
							
						
					
					
						commit
						3959ba5751
					
				|  | @ -1432,6 +1432,10 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | ||||||
| 			c.fail_if_immutable(call_expr.left) | 			c.fail_if_immutable(call_expr.left) | ||||||
| 			// call_expr.is_mut = true
 | 			// call_expr.is_mut = true
 | ||||||
| 		} | 		} | ||||||
|  | 		if (!left_type_sym.is_builtin() && method.mod != 'builtin') && method.language == .v | ||||||
|  | 			&& method.no_body { | ||||||
|  | 			c.error('cannot call a method that does not have a body', call_expr.pos) | ||||||
|  | 		} | ||||||
| 		if method.return_type == table.void_type && method.ctdefine.len > 0 | 		if method.return_type == table.void_type && method.ctdefine.len > 0 | ||||||
| 			&& method.ctdefine !in c.pref.compile_defines { | 			&& method.ctdefine !in c.pref.compile_defines { | ||||||
| 			call_expr.should_be_skipped = true | 			call_expr.should_be_skipped = true | ||||||
|  | @ -1726,6 +1730,9 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { | ||||||
| 		// builtin C.m*, C.s* only - temp
 | 		// builtin C.m*, C.s* only - temp
 | ||||||
| 		c.warn('function `$f.name` must be called from an `unsafe` block', call_expr.pos) | 		c.warn('function `$f.name` must be called from an `unsafe` block', call_expr.pos) | ||||||
| 	} | 	} | ||||||
|  | 	if f.mod != 'builtin' && f.language == .v && f.no_body { | ||||||
|  | 		c.error('cannot call a function that does not have a body', call_expr.pos) | ||||||
|  | 	} | ||||||
| 	for generic_type in call_expr.generic_types { | 	for generic_type in call_expr.generic_types { | ||||||
| 		sym := c.table.get_type_symbol(generic_type) | 		sym := c.table.get_type_symbol(generic_type) | ||||||
| 		if sym.kind == .placeholder { | 		if sym.kind == .placeholder { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | vlib/v/checker/tests/fn_call_no_body.vv:7:9: error: cannot call a method that does not have a body | ||||||
|  |     5 | | ||||||
|  |     6 | fn main() { | ||||||
|  |     7 |     Foo(0).f() | ||||||
|  |       |            ~~~ | ||||||
|  |     8 |     f() | ||||||
|  |     9 | } | ||||||
|  | vlib/v/checker/tests/fn_call_no_body.vv:8:2: error: cannot call a function that does not have a body | ||||||
|  |     6 | fn main() { | ||||||
|  |     7 |     Foo(0).f() | ||||||
|  |     8 |     f() | ||||||
|  |       |     ~~~ | ||||||
|  |     9 | } | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | type Foo = int | ||||||
|  | fn (_ Foo) f() | ||||||
|  | 
 | ||||||
|  | fn f() | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  | 	Foo(0).f() | ||||||
|  | 	f() | ||||||
|  | } | ||||||
|  | @ -315,6 +315,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | ||||||
| 		return_type = p.parse_type() | 		return_type = p.parse_type() | ||||||
| 	} | 	} | ||||||
| 	mut type_sym_method_idx := 0 | 	mut type_sym_method_idx := 0 | ||||||
|  | 	no_body := p.tok.kind != .lcbr | ||||||
| 	// Register
 | 	// Register
 | ||||||
| 	if is_method { | 	if is_method { | ||||||
| 		mut type_sym := p.table.get_type_symbol(rec_type) | 		mut type_sym := p.table.get_type_symbol(rec_type) | ||||||
|  | @ -345,6 +346,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | ||||||
| 			is_pub: is_pub | 			is_pub: is_pub | ||||||
| 			is_deprecated: is_deprecated | 			is_deprecated: is_deprecated | ||||||
| 			is_unsafe: is_unsafe | 			is_unsafe: is_unsafe | ||||||
|  | 			no_body: no_body | ||||||
| 			mod: p.mod | 			mod: p.mod | ||||||
| 			attrs: p.attrs | 			attrs: p.attrs | ||||||
| 		}) | 		}) | ||||||
|  | @ -369,6 +371,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | ||||||
| 			is_pub: is_pub | 			is_pub: is_pub | ||||||
| 			is_deprecated: is_deprecated | 			is_deprecated: is_deprecated | ||||||
| 			is_unsafe: is_unsafe | 			is_unsafe: is_unsafe | ||||||
|  | 			no_body: no_body | ||||||
| 			mod: p.mod | 			mod: p.mod | ||||||
| 			attrs: p.attrs | 			attrs: p.attrs | ||||||
| 			language: language | 			language: language | ||||||
|  | @ -378,7 +381,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | ||||||
| 	// Body
 | 	// Body
 | ||||||
| 	p.cur_fn_name = name | 	p.cur_fn_name = name | ||||||
| 	mut stmts := []ast.Stmt{} | 	mut stmts := []ast.Stmt{} | ||||||
| 	no_body := p.tok.kind != .lcbr |  | ||||||
| 	body_start_pos := p.peek_tok.position() | 	body_start_pos := p.peek_tok.position() | ||||||
| 	if p.tok.kind == .lcbr { | 	if p.tok.kind == .lcbr { | ||||||
| 		p.inside_fn = true | 		p.inside_fn = true | ||||||
|  |  | ||||||
|  | @ -32,6 +32,7 @@ pub: | ||||||
| 	is_deprecated  bool | 	is_deprecated  bool | ||||||
| 	is_unsafe      bool | 	is_unsafe      bool | ||||||
| 	is_placeholder bool | 	is_placeholder bool | ||||||
|  | 	no_body        bool | ||||||
| 	mod            string | 	mod            string | ||||||
| 	ctdefine       string // compile time define. myflag, when [if myflag] tag
 | 	ctdefine       string // compile time define. myflag, when [if myflag] tag
 | ||||||
| 	attrs          []Attr | 	attrs          []Attr | ||||||
|  |  | ||||||
|  | @ -573,6 +573,11 @@ pub fn (t &TypeSymbol) is_primitive() bool { | ||||||
| 	return t.is_number() || t.is_pointer() || t.is_string() | 	return t.is_number() || t.is_pointer() || t.is_string() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [inline] | ||||||
|  | pub fn (t &TypeSymbol) is_builtin() bool { | ||||||
|  | 	return t.mod == 'builtin' | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // for debugging/errors only, perf is not an issue
 | // for debugging/errors only, perf is not an issue
 | ||||||
| pub fn (k Kind) str() string { | pub fn (k Kind) str() string { | ||||||
| 	k_str := match k { | 	k_str := match k { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue