Skip to content

Commit

Permalink
checker: check receiver mutability when using DynamicArray methods
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Jan 2, 2024
1 parent 2749618 commit 3169fb7
Show file tree
Hide file tree
Showing 10 changed files with 25 additions and 20 deletions.
4 changes: 2 additions & 2 deletions lib/core/src/string.c.ri
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub struct string < Stringable, Hashable, Throwable {
/// Returns a string array of the string split by '\t' and ' '.
pub func fields(&self) -> []Self {
res := []Self();
mut res := []Self();
mut word_start: uint := 0;
mut word_len: uint := 0;
mut is_in_word := false;
Expand Down Expand Up @@ -190,7 +190,7 @@ pub struct string < Stringable, Hashable, Throwable {
/// Returns an array of all the UTF8 runes in the string `self` which is useful
/// if you want random access to them.
pub func as_runes(&self) -> []rune {
runes := []rune(cap: self.runes_count());
mut runes := []rune(cap: self.runes_count());
mut i: uint := 0;
while i < self.len : i += 1 {
char_len := unsafe { self.ptr[i] }.len_utf8();
Expand Down
6 changes: 3 additions & 3 deletions lib/core/src/string_predicates.ri
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ extend string {
/// remainder contains more `delim` substrings.
pub func split(&self, delim: Self, nth: uint := 0) -> []Self {
mut i: uint := 0;
res := []Self();
mut res := []Self();
match delim.len {
0 -> {
i = 1;
Expand Down Expand Up @@ -406,7 +406,7 @@ extend string {
/// If the delimiter string is empty then `.split()` is used.
pub func split_any(&self, delim: Self) -> []Self {
mut i: uint := 0;
res := []Self();
mut res := []Self();
// check empty source string
if self.len > 0 {
// if empty delimiter string using default split
Expand All @@ -433,7 +433,7 @@ extend string {
/// NOTE: algorithm is "greedy", consuming '\r\n' as a single line ending with higher
/// priority than '\r' and '\n' as multiple endings
pub func split_into_lines(&self) -> []Self {
res := []Self();
mut res := []Self();
if self.len == 0 {
return res;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/core/tests/string_test.ri
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ test "string.runes_count()" {

test "string.tokenize()" {
mut iterator := " abc def ghi ".tokenize(' ');
res := []string(cap: 3);
mut res := []string(cap: 3);
while w := iterator.next() {
res.push(w);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/core/tests/vector_test.ri
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test "dynamic arrays: push and pop" {
vec := +["A", "B"];
mut vec := +["A", "B"];
@assert(vec.len == 2);

vec.push("C");
Expand Down
6 changes: 3 additions & 3 deletions lib/std/src/flag/mod.ri
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ pub struct FlagParser {
/// Call .finalize() after all arguments are defined.
pub func finalize(+mut self) -> ![]string {
self.handle_builtin_options();
remaining := self.args.clone();
mut remaining := self.args.clone();
if !self.allow_unknown_args_ {
for arg in remaining {
if (arg.len >= 2 && arg.substr(end: 2) == "--")
Expand Down Expand Up @@ -402,8 +402,8 @@ pub struct FlagParser {
/// - found arguments and corresponding values are removed from args list.
func parse_value(+mut self, long_hand: string, short_hand: uint8) -> []string {
full := "--".concat(long_hand);
found_entries := []string();
to_delete := []uint();
mut found_entries := []string();
mut to_delete := []uint();
mut should_skip_one := false;
for i, arg in self.args {
if should_skip_one {
Expand Down
2 changes: 1 addition & 1 deletion lib/std/src/fs/Directory.c.ri
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub struct Directory {
rpath := Path.resolve(path_)!;
unsafe {
if dir := libc.opendir(path_.ptr) {
res := []string(cap: 15);
mut res := []string(cap: 15);
while ent := libc.readdir(dir) {
bptr: [&]uint8 := &ent.*.d_name[0];
if (bptr[0] == 0 || (bptr[0] == '.' && bptr[1] == 0)
Expand Down
2 changes: 1 addition & 1 deletion lib/std/src/semver/parse.ri
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct RawVersion {
}

func complete(&self) -> RawVersion {
raw_ints := self.raw_ints.clone();
mut raw_ints := self.raw_ints.clone();
while raw_ints.len < 3 {
raw_ints.push("0");
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/src/semver/range.ri
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct ComparatorSet {
"invalid format of comparator set for input '{}'".fmt(input)
);
}
comparators := []Comparator();
mut comparators := []Comparator();
for raw_comp in raw_comparators {
comparators.push(
Comparator.parse(raw_comp) ?? throw InvalidComparatorFormatError(
Expand Down Expand Up @@ -116,7 +116,7 @@ struct Range {

func parse(input: string) -> ?Range {
raw_comparator_sets := input.split(comparator_set_sep);
comparator_sets := []ComparatorSet();
mut comparator_sets := []ComparatorSet();
for raw_comp_set in raw_comparator_sets {
if can_expand(raw_comp_set) {
comparator_sets.push(ComparatorSet.expand(raw_comp_set) ?? return none);
Expand Down
11 changes: 8 additions & 3 deletions rivetc/src/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1782,20 +1782,25 @@ def check_call(self, info, expr):
return expr.typ

def check_receiver(self, info, recv):
if not isinstance(info.self_typ, type.Ptr) and isinstance(recv.typ, type.Ptr):
if not info.self_is_ptr and isinstance(recv.typ, type.Ptr):
if not info.self_is_boxed:
# valid, the receiver will be dereferenced after: (self.*).method()
return

if isinstance(info.self_typ, type.Ptr) and not isinstance(recv.typ, type.Ptr):
if info.self_is_ptr and not isinstance(recv.typ, type.Ptr):
# valid, the receiver will be referenced later: (&self).method()
if info.self_typ.is_mut:
# if the pointer is mutable, we must check that the receiver is also mutable.
self.check_expr_is_mut(recv)
return

recv_sym = recv.typ.symbol()
if recv_sym.kind == TypeKind.DynArray and info.self_is_mut:
# `DynamicArray` has methods that modify its receiver by reference, so we
# check that we use mutable values
self.check_expr_is_mut(recv)

if info.self_is_boxed:
recv_sym = recv.typ.symbol()
if recv_sym.kind == TypeKind.Trait:
# traits are boxed values behind the scenes
if info.self_is_mut:
Expand Down
6 changes: 3 additions & 3 deletions tests/valid/src/dynamic_array.ri
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
test "dynamic array from fixed array" {
arr := [1, 2, 3];
dyn_array := arr[:].to_dynamic_array();
mut dyn_array := arr[:].to_dynamic_array();
dyn_array.push(2);
@assert(dyn_array.len == 4);

Expand All @@ -11,12 +11,12 @@ test "dynamic array from fixed array" {

test "dynamic array constructor" {
{
da := []int32();
mut da := []int32();
da.push(5);
@assert(da[0] == 5);
}
{
da := []int32(cap: 2);
mut da := []int32(cap: 2);
da.push(10);
@assert(da.cap == 2);
@assert(da[0] == 10);
Expand Down

0 comments on commit 3169fb7

Please sign in to comment.