checker: prohibit using non-lvalue as mut receiver (#10790)
							parent
							
								
									7c5f012cbc
								
							
						
					
					
						commit
						0d587d3580
					
				| 
						 | 
				
			
			@ -70,9 +70,10 @@ pub fn (mut b Builder) front_stages(v_files []string) ? {
 | 
			
		|||
	util.timing_start('PARSE')
 | 
			
		||||
	b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
 | 
			
		||||
	b.parse_imports()
 | 
			
		||||
	util.get_timers().show('SCAN')
 | 
			
		||||
	util.get_timers().show('PARSE')
 | 
			
		||||
	util.get_timers().show_if_exists('PARSE stmt')
 | 
			
		||||
	mut timers := util.get_timers()
 | 
			
		||||
	timers.show('SCAN')
 | 
			
		||||
	timers.show('PARSE')
 | 
			
		||||
	timers.show_if_exists('PARSE stmt')
 | 
			
		||||
	if b.pref.only_check_syntax {
 | 
			
		||||
		return error('stop_after_parser')
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,8 @@ pub fn compile(command string, pref &pref.Preferences) {
 | 
			
		|||
		.js { b.compile_js() }
 | 
			
		||||
		.native { b.compile_native() }
 | 
			
		||||
	}
 | 
			
		||||
	util.get_timers().show_remaining()
 | 
			
		||||
	mut timers := util.get_timers()
 | 
			
		||||
	timers.show_remaining()
 | 
			
		||||
	if pref.is_stats {
 | 
			
		||||
		compilation_time_micros := 1 + sw.elapsed().microseconds()
 | 
			
		||||
		scompilation_time_ms := util.bold('${f64(compilation_time_micros) / 1000.0:6.3f}')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2106,6 +2106,9 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
 | 
			
		|||
		}
 | 
			
		||||
		if method.params[0].is_mut {
 | 
			
		||||
			to_lock, pos := c.fail_if_immutable(call_expr.left)
 | 
			
		||||
			if !call_expr.left.is_lvalue() {
 | 
			
		||||
				c.error('cannot pass expression as `mut`', call_expr.left.position())
 | 
			
		||||
			}
 | 
			
		||||
			// call_expr.is_mut = true
 | 
			
		||||
			if to_lock != '' && rec_share != .shared_t {
 | 
			
		||||
				c.error('$to_lock is `shared` and must be `lock`ed to be passed as `mut`',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
vlib/v/checker/tests/mut_receiver_lit.vv:10:1: error: cannot pass expression as `mut`
 | 
			
		||||
    8 | }
 | 
			
		||||
    9 | 
 | 
			
		||||
   10 | Box{}.set(0)
 | 
			
		||||
      | ~~~~~
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
struct Box {
 | 
			
		||||
mut:
 | 
			
		||||
	value int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut box Box) set(value int) {
 | 
			
		||||
	box.value = value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Box{}.set(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -537,11 +537,12 @@ fn (mut s Scanner) end_of_file() token.Token {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut s Scanner) scan_all_tokens_in_buffer(mode CommentsMode) {
 | 
			
		||||
	util.get_timers().measure_pause('PARSE')
 | 
			
		||||
	mut timers := util.get_timers()
 | 
			
		||||
	timers.measure_pause('PARSE')
 | 
			
		||||
	util.timing_start('SCAN')
 | 
			
		||||
	defer {
 | 
			
		||||
		util.timing_measure_cumulative('SCAN')
 | 
			
		||||
		util.get_timers().measure_resume('PARSE')
 | 
			
		||||
		timers.measure_resume('PARSE')
 | 
			
		||||
	}
 | 
			
		||||
	oldmode := s.comments_mode
 | 
			
		||||
	s.comments_mode = mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,30 +0,0 @@
 | 
			
		|||
struct Test {
 | 
			
		||||
mut:
 | 
			
		||||
	val int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this must return a reference, or else you'll get a C error
 | 
			
		||||
// TODO: add a proper checker check for that case
 | 
			
		||||
fn new(x int) &Test {
 | 
			
		||||
	return &Test{x}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut t Test) inc() &Test {
 | 
			
		||||
	t.val++
 | 
			
		||||
	return unsafe { t }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut t Test) add(x int) &Test {
 | 
			
		||||
	t.val += x
 | 
			
		||||
	return unsafe { t }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut t Test) div(x int) &Test {
 | 
			
		||||
	t.val /= x
 | 
			
		||||
	return unsafe { t }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_method_call_chains() {
 | 
			
		||||
	mut x := new(4).inc().inc().inc().inc().add(4).div(2).inc()
 | 
			
		||||
	assert x.val == 7
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,15 +28,18 @@ pub fn get_timers() &Timers {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn timing_start(label string) {
 | 
			
		||||
	get_timers().start(label)
 | 
			
		||||
	mut t := get_timers()
 | 
			
		||||
	t.start(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn timing_measure(label string) {
 | 
			
		||||
	get_timers().show(label)
 | 
			
		||||
	mut t := get_timers()
 | 
			
		||||
	t.show(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn timing_measure_cumulative(label string) {
 | 
			
		||||
	get_timers().measure_cumulative(label)
 | 
			
		||||
	mut t := get_timers()
 | 
			
		||||
	t.measure_cumulative(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn timing_set_should_print(should_print bool) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue