Skip to content

Commit a0e8316

Browse files
committed
[Tolk] Readonly fields in structs
1 parent b175341 commit a0e8316

15 files changed

+121
-12
lines changed

tolk-tester/tests/assignment-tests.tolk

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,32 @@ fun test119(a: int, b: int) {
257257
return (l, c, d);
258258
}
259259

260+
struct Point {
261+
x: int
262+
y: int
263+
}
264+
265+
struct ROLine {
266+
readonly from: Point
267+
readonly to: Point
268+
}
269+
270+
fun eq<T>(v: T) { return v }
271+
272+
@method_id(120)
273+
fun test120() {
274+
val p: Point = { x: 10, y: 20 };
275+
eq(p).x = 30;
276+
return p;
277+
}
278+
279+
@method_id(121)
280+
fun test121(l: ROLine) {
281+
eq(l.from).x = eq(l.to).y;
282+
eq(l.from).y += 10;
283+
return l
284+
}
285+
260286

261287

262288
fun main(value: int, ) {
@@ -288,6 +314,8 @@ fun main(value: int, ) {
288314
@testcase | 117 | | [ 20 ]
289315
@testcase | 118 | 3 | 10 3 0 1
290316
@testcase | 119 | 1 2 | 2 2 4
317+
@testcase | 120 | | 10 20
318+
@testcase | 121 | null | (null)
291319

292320

293321
@fif_codegen
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct Point {
2+
x: int
3+
y: int
4+
}
5+
6+
struct ROLine {
7+
readonly p1: Point
8+
readonly p2: Point
9+
}
10+
11+
fun eq<T>(v: T) { return v }
12+
13+
fun f(l: ROLine) {
14+
l.p1; l.p2; l.p1.x; eq(l.p2.y); eq(eq(l).p2).y;
15+
16+
l.p2!.x += 1;
17+
}
18+
19+
/**
20+
@compilation_should_fail
21+
@stderr modifying readonly field `ROLine.p2`
22+
*/
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
struct ImmSlice {
2+
readonly s: slice
3+
}
4+
5+
fun ImmSlice.read(mutate self) {
6+
self.s.loadRef()
7+
}
8+
9+
/**
10+
@compilation_should_fail
11+
@stderr modifying readonly field `ImmSlice.s`
12+
*/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct ROPoint {
2+
readonly x: int
3+
readonly y: int
4+
}
5+
6+
fun increment(mutate x: int) {}
7+
8+
fun main(p1: ROPoint, p2: ROPoint) {
9+
increment(mutate (p1 = p2).x);
10+
}
11+
12+
/**
13+
@compilation_should_fail
14+
@stderr modifying readonly field `ROPoint.x`
15+
*/

tolk-tester/tests/invalid-semantics/err-4572.tolk

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
fun eq<T>(v: T) { return v }
2+
13
fun checkCantMutateFieldOfImmutableTuple() {
24
val ks = null as [int, [int, [int]]]?;
3-
ks!.1.1.0 = 10;
5+
eq(ks!.1.1 = [10]).0 = 10;
46
}
57

68
/**

tolk-tester/tests/invalid-semantics/err-4822.tolk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ struct Coord2 {
88
p2: Point;
99
}
1010

11-
fun increment(mutate x: int) {
12-
x += 1;
11+
fun int.increment(mutate self) {
12+
self += 1;
1313
}
1414

1515
fun checkCantMutateFieldOfImmutableTuple(p1: Point?, p2: Point) {
@@ -19,5 +19,5 @@ fun checkCantMutateFieldOfImmutableTuple(p1: Point?, p2: Point) {
1919

2020
/**
2121
@compilation_should_fail
22-
@modifying immutable variable `c2`
22+
@stderr modifying immutable variable `c2`
2323
*/

tolk/ast-from-tokens.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,13 @@ static AnyV parse_function_declaration(Lexer& lex, const std::vector<V<ast_annot
15421542

15431543
static AnyV parse_struct_field(Lexer& lex) {
15441544
SrcLocation loc = lex.cur_location();
1545+
1546+
bool is_readonly = false;
1547+
if (lex.tok() == tok_readonly) {
1548+
lex.next();
1549+
is_readonly = true;
1550+
}
1551+
15451552
lex.check(tok_identifier, "field name");
15461553
auto v_ident = createV<ast_identifier>(lex.cur_location(), lex.cur_str());
15471554
lex.next();
@@ -1554,7 +1561,7 @@ static AnyV parse_struct_field(Lexer& lex) {
15541561
default_value = parse_expr(lex);
15551562
}
15561563

1557-
return createV<ast_struct_field>(loc, v_ident, default_value, declared_type);
1564+
return createV<ast_struct_field>(loc, v_ident, is_readonly, default_value, declared_type);
15581565
}
15591566

15601567
static V<ast_struct_body> parse_struct_body(Lexer& lex) {

tolk/ast-replicator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class ASTReplicator final {
235235
return createV<ast_parameter_list>(v->loc, clone(v->get_params()));
236236
}
237237
static V<ast_struct_field> clone(V<ast_struct_field> v) {
238-
return createV<ast_struct_field>(v->loc, clone(v->get_identifier()), v->default_value ? clone(v->default_value) : nullptr, clone(v->type_node));
238+
return createV<ast_struct_field>(v->loc, clone(v->get_identifier()), v->is_readonly, v->default_value ? clone(v->default_value) : nullptr, clone(v->type_node));
239239
}
240240
static V<ast_struct_body> clone(V<ast_struct_body> v) {
241241
return createV<ast_struct_body>(v->loc, clone(v->get_all_fields()));

tolk/ast.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,14 +1353,15 @@ template<>
13531353
// ast_struct_field is one field at struct declaration
13541354
// example: `struct Point { x: int, y: int }` is struct declaration, its body contains 2 fields
13551355
struct Vertex<ast_struct_field> final : ASTOtherVararg {
1356+
bool is_readonly; // declared as `readonly field: int`
13561357
AnyTypeV type_node; // always exists, typing struct fields is mandatory
13571358
AnyExprV default_value; // nullptr if no default
13581359

13591360
auto get_identifier() const { return children.at(0)->as<ast_identifier>(); }
13601361

1361-
Vertex(SrcLocation loc, V<ast_identifier> name_identifier, AnyExprV default_value, AnyTypeV type_node)
1362+
Vertex(SrcLocation loc, V<ast_identifier> name_identifier, bool is_readonly, AnyExprV default_value, AnyTypeV type_node)
13621363
: ASTOtherVararg(ast_struct_field, loc, {name_identifier})
1363-
, type_node(type_node), default_value(default_value) {}
1364+
, is_readonly(is_readonly), type_node(type_node), default_value(default_value) {}
13641365
};
13651366

13661367
template<>

tolk/lexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ struct ChunkIdentifierOrKeyword final : ChunkLexerBase {
382382
if (str == "builtin") return tok_builtin;
383383
break;
384384
case 8:
385+
if (str == "readonly") return tok_readonly;
385386
if (str == "continue") return tok_continue;
386387
if (str == "operator") return tok_operator;
387388
break;

0 commit comments

Comments
 (0)