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') | 	util.timing_start('PARSE') | ||||||
| 	b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) | 	b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) | ||||||
| 	b.parse_imports() | 	b.parse_imports() | ||||||
| 	util.get_timers().show('SCAN') | 	mut timers := util.get_timers() | ||||||
| 	util.get_timers().show('PARSE') | 	timers.show('SCAN') | ||||||
| 	util.get_timers().show_if_exists('PARSE stmt') | 	timers.show('PARSE') | ||||||
|  | 	timers.show_if_exists('PARSE stmt') | ||||||
| 	if b.pref.only_check_syntax { | 	if b.pref.only_check_syntax { | ||||||
| 		return error('stop_after_parser') | 		return error('stop_after_parser') | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -43,7 +43,8 @@ pub fn compile(command string, pref &pref.Preferences) { | ||||||
| 		.js { b.compile_js() } | 		.js { b.compile_js() } | ||||||
| 		.native { b.compile_native() } | 		.native { b.compile_native() } | ||||||
| 	} | 	} | ||||||
| 	util.get_timers().show_remaining() | 	mut timers := util.get_timers() | ||||||
|  | 	timers.show_remaining() | ||||||
| 	if pref.is_stats { | 	if pref.is_stats { | ||||||
| 		compilation_time_micros := 1 + sw.elapsed().microseconds() | 		compilation_time_micros := 1 + sw.elapsed().microseconds() | ||||||
| 		scompilation_time_ms := util.bold('${f64(compilation_time_micros) / 1000.0:6.3f}') | 		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 { | 		if method.params[0].is_mut { | ||||||
| 			to_lock, pos := c.fail_if_immutable(call_expr.left) | 			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
 | 			// call_expr.is_mut = true
 | ||||||
| 			if to_lock != '' && rec_share != .shared_t { | 			if to_lock != '' && rec_share != .shared_t { | ||||||
| 				c.error('$to_lock is `shared` and must be `lock`ed to be passed as `mut`', | 				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) { | 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') | 	util.timing_start('SCAN') | ||||||
| 	defer { | 	defer { | ||||||
| 		util.timing_measure_cumulative('SCAN') | 		util.timing_measure_cumulative('SCAN') | ||||||
| 		util.get_timers().measure_resume('PARSE') | 		timers.measure_resume('PARSE') | ||||||
| 	} | 	} | ||||||
| 	oldmode := s.comments_mode | 	oldmode := s.comments_mode | ||||||
| 	s.comments_mode = 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) { | pub fn timing_start(label string) { | ||||||
| 	get_timers().start(label) | 	mut t := get_timers() | ||||||
|  | 	t.start(label) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn timing_measure(label string) { | pub fn timing_measure(label string) { | ||||||
| 	get_timers().show(label) | 	mut t := get_timers() | ||||||
|  | 	t.show(label) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn timing_measure_cumulative(label string) { | 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) { | pub fn timing_set_should_print(should_print bool) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue