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