Skip to content

Commit d4665a5

Browse files
authored
feat(rivet+rivetc): minor changes to mutability checking (#59)
Also fixed a bug where `match` branches did not have their own scope
1 parent 291ad1b commit d4665a5

File tree

24 files changed

+225
-168
lines changed

24 files changed

+225
-168
lines changed

lib/core/src/Box.ri

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ struct Box {
88
mut dtor: ?func(rawptr);
99

1010
func new(size: uint, dtor: ?func(rawptr)) -> rawptr {
11-
mut boxed := unsafe { @as(&Self, mem_alloc(@size_of(Self) + size)) };
11+
boxed := unsafe { @as(&mut Self, mem_alloc(@size_of(Self) + size)) };
1212
boxed.ref_count = 1;
1313
boxed.dtor = dtor;
1414
boxed.value = unsafe { @ptr_add(@as([&]uint8, boxed), @size_of(Self)) };
1515
return boxed.value;
1616
}
1717

1818
func retain(ptr: rawptr) {
19-
mut boxed := unsafe { @as(&Self, @ptr_sub(@as([&]uint8, ptr), @size_of(Self))) };
19+
boxed := unsafe { @as(&mut Self, @ptr_sub(@as([&]uint8, ptr), @size_of(Self))) };
2020
boxed.ref_count += 1;
2121
}
2222

2323
func release(ptr: rawptr) {
24-
mut boxed := unsafe { @as(&Self, @ptr_sub(@as([&]uint8, ptr), @size_of(Self))) };
24+
boxed := unsafe { @as(&mut Self, @ptr_sub(@as([&]uint8, ptr), @size_of(Self))) };
2525
boxed.ref_count -= 1;
2626
if boxed.ref_count == 0 {
2727
if dtor := boxed.dtor {

lib/core/src/StaticBuffer.c.ri

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ struct StaticBuffer {
1616
self.len += 1;
1717
}
1818

19-
pub func as_uint64(mut self) -> uint64 {
19+
pub func as_uint64(&self) -> uint64 {
2020
self.buf[self.len] = 0;
2121
return unsafe { libc.strtoul(&self.buf[0], none, 10) };
2222
}
2323

24-
pub func as_uint(mut self) -> uint {
24+
pub func as_uint(&self) -> uint {
2525
self.buf[self.len] = 0;
2626
return unsafe { @as(uint, libc.strtoul(&self.buf[0], none, 10)) };
2727
}
2828

29-
pub func as_int(mut self) -> int {
29+
pub func as_int(&self) -> int {
3030
self.buf[self.len] = 0;
3131
return unsafe { @as(int, libc.strtol(&self.buf[0], none, 10))};
3232
}
3333

34-
pub func as_string(mut self) -> string {
34+
pub func as_string(&self) -> string {
3535
self.buf[self.len] = 0;
3636
return unsafe { string.from_raw_with_len(&self.buf[0], self.len).clone() };
3737
}

lib/core/src/backtrace.c.ri

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ $if !_RELEASE_ { // skip backtrace in release mode
6161

6262
func bt_error_handler(data: rawptr, msg_ptr: ?[&]mut uint8, errnum: int32) {
6363
unsafe {
64-
mut bdata := @as(&mut BacktraceData, data);
64+
bdata := @as(&mut BacktraceData, data);
6565
if !bdata.has_error {
6666
bdata.has_error = true;
6767
console_ewrite(" libbacktrace error: ");

lib/rivet/src/ast/Expr.ri

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,5 +658,6 @@ pub struct MatchBranch {
658658
pub mut expr: Expr;
659659
pub is_else: bool;
660660
pub pos: token.Pos;
661+
pub mut scope: Scope;
661662
pub mut type: Type;
662663
}

lib/rivet/src/ast/Type.ri

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub enum Type < traits.Stringable {
122122
.Result(mut result) -> .Result(result.inner.unalias() ?? result.inner),
123123
.Option(mut option) -> .Option(option.inner.unalias() ?? option.inner),
124124
.Tuple(mut tuple_data) -> {
125-
mut unaliased_types := []mut Type(cap: tuple_data.inners.len);
125+
unaliased_types := []mut Type(cap: tuple_data.inners.len);
126126
for i, mut tuple_type in tuple_data.inners {
127127
unaliased_types[i] = tuple_type.unalias() ?? tuple_type;
128128
}

lib/rivet/src/checker/decls.ri

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,8 @@ extend Checker {
267267
},
268268
.Expr(expr3) if expr3 is .Block(block1) && block1.stmts.len > 0 -> {
269269
last_stmt := block1.stmts[block1.stmts.len - 1];
270-
if last_stmt is .Expr(last_expr) && last_expr is .Call(call) {
271-
if call.type !is .Never {
270+
if last_stmt is .Expr(last_expr) && last_expr is .Call(call_expr) {
271+
if call_expr.type !is .Never {
272272
report.error(
273273
"`{}` is not a `never` function".fmt(
274274
call_expr.func_.name

lib/rivet/src/checker/exprs.ri

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extend Checker {
1010
.Empty, .Comment -> .Void,
1111
.Type(type) -> type,
1212
.ComptimeIf(mut comptime_if) -> {
13-
mut exprs := ast.nodes_to_exprs(
13+
exprs := ast.nodes_to_exprs(
1414
self.env.evalue_comptime_if(comptime_if)
1515
);
1616
comptime_if.type = self.check_expr(exprs[0]);
@@ -758,6 +758,15 @@ extend Checker {
758758
variant := @as(ast.Expr.EnumLiteral, binary.right).variant;
759759
if variant.has_type {
760760
var_t := if binary.var_obj.is_ref {
761+
if variant.type is .Pointer {
762+
report.error(
763+
"cannot take the address of other pointer", binary.var_obj.pos
764+
);
765+
} else if variant.type.is_boxed() {
766+
report.error(
767+
"cannot take the address of a boxed value", binary.var_obj.pos
768+
);
769+
}
761770
ast.Type.Pointer(variant.type, binary.var_obj.is_mut)
762771
} else {
763772
variant.type

lib/rivet/src/checker/match_expr.ri

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,14 @@ extend Checker {
104104
if pattern0.has_type {
105105
branch_var.type = pattern0.type;
106106
if branch_var.is_ref {
107+
if branch_var.type is .Pointer {
108+
report.error("cannot take the address of other pointer", branch_var.pos);
109+
} else if branch_var.type.is_boxed() {
110+
report.error("cannot take the address of a boxed value", branch_var.pos);
111+
}
107112
branch_var.type = .Pointer(branch_var.type, branch_var.is_mut);
108113
} else {
109-
match_expr.scope.update_is_hidden_ref(
114+
branch.scope.update_is_hidden_ref(
110115
branch_var.name, branch_var.is_mut
111116
);
112117
}
@@ -116,8 +121,10 @@ extend Checker {
116121
branch.patterns[0].position()
117122
);
118123
}
124+
} else if branch_var.is_ref && branch_var.type.is_boxed() {
125+
report.error("cannot take the address of a boxed value", branch_var.pos);
119126
}
120-
match_expr.scope.update_type(branch_var.name, branch_var.type);
127+
branch.scope.update_type(branch_var.name, branch_var.type);
121128
} else {
122129
report.error("multiple patterns cannot have variable", branch_var.pos);
123130
}

lib/rivet/src/checker/mod.ri

Lines changed: 0 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -248,136 +248,6 @@ pub struct Checker {
248248
}
249249
}
250250

251-
func check_expr_is_mut(self, mut expr: ast.Expr, from_assign: bool := false) {
252-
match expr {
253-
.Paren(mut paren) -> self.check_expr_is_mut(paren.expr),
254-
.SelfLiteral(mut self_lit) -> if self_lit.obj.is_mut {
255-
self_lit.obj.is_changed = true;
256-
} else {
257-
mut err := report.error_builder(
258-
"cannot use `self` as mutable value", self_lit.pos
259-
);
260-
err.add_help("consider making `self` as mutable: `mut self`");
261-
err.emit();
262-
},
263-
.Ident(mut ident) -> if ident.is_comptime {
264-
report.error(
265-
"cannot use constant `@{}` as mutable value".fmt(ident.name),
266-
ident.pos
267-
);
268-
} else if ident.name == "_" {
269-
return;
270-
} else if ident.found && (ident.is_sym || ident.is_obj) {
271-
self.check_sym_is_mut(ident.sym, ident.pos);
272-
},
273-
.Selector(mut selector) -> if selector.is_path {
274-
self.check_sym_is_mut(selector.sym, selector.pos);
275-
} else {
276-
self.check_expr_is_mut(selector.left);
277-
if selector.found && !selector.field_is_mut {
278-
report.error(
279-
"field `{}` of type `{}` is immutable".fmt(
280-
selector.field_name, selector.left_type
281-
), selector.pos
282-
);
283-
}
284-
},
285-
.Indirect(indirect) -> if !indirect.is_mut {
286-
report.error("cannot use a immutable pointer as mutable value", selector.pos);
287-
},
288-
.OptionCheck(mut option_check) -> self.check_expr_is_mut(option_check.left),
289-
.NoneLiteral -> report.error("`none` cannot be modified", expr.position()),
290-
.StringLiteral -> report.error(
291-
"string literals cannot be modified", expr.position()
292-
),
293-
.TupleLiteral(mut tuple_lit) -> if from_assign {
294-
for mut value in tuple_lit.values {
295-
self.check_expr_is_mut(value);
296-
}
297-
} else {
298-
report.error("tuple literals cannot be modified", tuple_lit.pos);
299-
},
300-
.EnumLiteral(enum_lit) if !enum_lit.is_instance -> report.error(
301-
"enum literals cannot be modified", enum_lit.pos
302-
),
303-
.BuiltinCall(mut builtin_call) -> {
304-
for mut arg in builtin_call.args {
305-
self.check_expr_is_mut(arg.expr);
306-
}
307-
},
308-
.Block(mut block) if block.is_expr -> self.check_expr_is_mut(block.expr),
309-
.Index(mut index) -> {
310-
if index.left_type is .Pointer(ptr) {
311-
if !ptr.is_mut {
312-
report.error(
313-
"cannot modify elements of an immutable pointer", index.pos
314-
);
315-
}
316-
return;
317-
}
318-
self.check_expr_is_mut(index.left);
319-
expr_sym := index.left_type.symbol()?;
320-
if !expr_sym.info.is_mut_array() {
321-
report.error(
322-
"cannot modify elements of an immutable {}".fmt(expr_sym.info),
323-
index.pos
324-
);
325-
}
326-
},
327-
.Unary(mut unary) -> self.check_expr_is_mut(unary.right),
328-
.Binary(mut binary) -> {
329-
self.check_expr_is_mut(binary.left);
330-
self.check_expr_is_mut(binary.right);
331-
},
332-
.If(mut if_expr) -> {
333-
for mut branch in if_expr.branches {
334-
self.check_expr_is_mut(branch.expr);
335-
}
336-
},
337-
.Match(mut match_expr) -> {
338-
for mut branch in match_expr.branches {
339-
self.check_expr_is_mut(branch.expr);
340-
}
341-
},
342-
else -> {}
343-
}
344-
}
345-
346-
func check_sym_is_mut(self, mut sym: ast.Sym, pos: token.Pos) {
347-
_ = self;
348-
match sym is {
349-
ast.Const -> report.error(
350-
"cannot use constant `{}` as mutable value".fmt(sym.name), pos
351-
),
352-
ast.Var(mut var_info) -> {
353-
if var_info.is_mut {
354-
var_info.is_changed = true;
355-
} else {
356-
mut err := if var_info.level == .Argument {
357-
mut err_b := report.error_builder(
358-
"cannot use variable `{}` as mutable argument".fmt(sym.name), pos
359-
);
360-
err_b.add_help(
361-
"consider making this argument mutable: `mut {}`", var_info.name
362-
);
363-
err_b
364-
} else {
365-
mut err_b := report.error_builder(
366-
"cannot use variable `{}` as mutable value".fmt(sym.name), pos
367-
);
368-
err_b.add_help(
369-
"consider making this {} mutable: `mut {}`", var_info.type_of(),
370-
var_info.name
371-
);
372-
err_b
373-
};
374-
err.emit();
375-
}
376-
},
377-
else -> {}
378-
}
379-
}
380-
381251
func check_expr_evaluated_but_not_used(self, expr_type: ast.Type, pos: token.Pos) {
382252
_ = self;
383253
if !((expr_type is .Result(res) && !res.inner.is_void())

0 commit comments

Comments
 (0)