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)
 | 
			
		||||
			// 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
 | 
			
		||||
			&& method.ctdefine !in c.pref.compile_defines {
 | 
			
		||||
			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
 | 
			
		||||
		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 {
 | 
			
		||||
		sym := c.table.get_type_symbol(generic_type)
 | 
			
		||||
		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()
 | 
			
		||||
	}
 | 
			
		||||
	mut type_sym_method_idx := 0
 | 
			
		||||
	no_body := p.tok.kind != .lcbr
 | 
			
		||||
	// Register
 | 
			
		||||
	if is_method {
 | 
			
		||||
		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_deprecated: is_deprecated
 | 
			
		||||
			is_unsafe: is_unsafe
 | 
			
		||||
			no_body: no_body
 | 
			
		||||
			mod: p.mod
 | 
			
		||||
			attrs: p.attrs
 | 
			
		||||
		})
 | 
			
		||||
| 
						 | 
				
			
			@ -369,6 +371,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
 | 
			
		|||
			is_pub: is_pub
 | 
			
		||||
			is_deprecated: is_deprecated
 | 
			
		||||
			is_unsafe: is_unsafe
 | 
			
		||||
			no_body: no_body
 | 
			
		||||
			mod: p.mod
 | 
			
		||||
			attrs: p.attrs
 | 
			
		||||
			language: language
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +381,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
 | 
			
		|||
	// Body
 | 
			
		||||
	p.cur_fn_name = name
 | 
			
		||||
	mut stmts := []ast.Stmt{}
 | 
			
		||||
	no_body := p.tok.kind != .lcbr
 | 
			
		||||
	body_start_pos := p.peek_tok.position()
 | 
			
		||||
	if p.tok.kind == .lcbr {
 | 
			
		||||
		p.inside_fn = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@ pub:
 | 
			
		|||
	is_deprecated  bool
 | 
			
		||||
	is_unsafe      bool
 | 
			
		||||
	is_placeholder bool
 | 
			
		||||
	no_body        bool
 | 
			
		||||
	mod            string
 | 
			
		||||
	ctdefine       string // compile time define. myflag, when [if myflag] tag
 | 
			
		||||
	attrs          []Attr
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -573,6 +573,11 @@ pub fn (t &TypeSymbol) is_primitive() bool {
 | 
			
		|||
	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
 | 
			
		||||
pub fn (k Kind) str() string {
 | 
			
		||||
	k_str := match k {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue