Require `&` for re-slicing

18a8980798c23a67d02435bc2473205eacabc41dff188e5f28be3be9965c1732
Like arrays, slicing a slice now requires an explicit address-of
operator. This enables taking an immutable slice from a mutable one.
Alexis Sellier committed ago 1 parent 9aad4c31
compiler/radiance.rad +5 -5
534 534
/// Synthesize a `testing::test("mod", "name", mod::fn)` call for one test.
535 535
fn synthTestCall(arena: *mut ast::NodeArena, desc: *TestDesc) -> *ast::Node {
536 536
    let callee = synthScopeAccess(arena, &["testing", "test"]);
537 537
    let modStr = il::formatQualifiedName(
538 538
        &mut arena.arena,
539 -
        desc.modPath[..desc.modPath.len - 1],
539 +
        &desc.modPath[..desc.modPath.len - 1],
540 540
        desc.modPath[desc.modPath.len - 1]
541 541
    );
542 542
    let modArg = ast::synthNode(arena, ast::NodeValue::String(modStr));
543 543
    let nameArg = ast::synthNode(arena, ast::NodeValue::String(desc.fnName));
544 544
721 721
    for i in 0..entries.len {
722 722
        let entry = &entries[i];
723 723
        let modEntry = module::get(graph, entry.moduleId) else {
724 724
            panic "writeDebugInfo: module not found for debug entry";
725 725
        };
726 -
        pos = pos + try! mem::copy(buf[pos..], @sliceOf(&entry.pc as *u8, 4));
727 -
        pos = pos + try! mem::copy(buf[pos..], @sliceOf(&entry.offset as *u8, 4));
728 -
        pos = pos + try! mem::copy(buf[pos..], modEntry.filePath);
726 +
        pos = pos + try! mem::copy(&mut buf[pos..], @sliceOf(&entry.pc as *u8, 4));
727 +
        pos = pos + try! mem::copy(&mut buf[pos..], @sliceOf(&entry.offset as *u8, 4));
728 +
        pos = pos + try! mem::copy(&mut buf[pos..], modEntry.filePath);
729 729
730 730
        buf[pos] = 0;
731 731
        pos = pos + 1;
732 732
    }
733 -
    try writeDataWithExt(buf[..pos], basePath, DEBUG_EXT);
733 +
    try writeDataWithExt(&buf[..pos], basePath, DEBUG_EXT);
734 734
}
735 735
736 736
/// Run the resolver on the parsed modules.
737 737
fn runResolver(ctx: *mut CompileContext, nodeCount: u32) -> resolver::Resolver throws (Error) {
738 738
    let mut mainArena = alloc::new(&mut MAIN_ARENA[..]);
lib/std/arch/rv64.rad +7 -7
241 241
                for _ in 0..v.count {
242 242
                    match v.item {
243 243
                        case il::DataItem::Val { typ, val } => {
244 244
                            let size = il::typeSize(typ);
245 245
                            let valPtr = &val as *u8;
246 -
                            try! mem::copy(buf[offset..], @sliceOf(valPtr, size));
246 +
                            try! mem::copy(&mut buf[offset..], @sliceOf(valPtr, size));
247 247
                            offset = offset + size;
248 248
                        },
249 249
                        case il::DataItem::Sym(name) => {
250 250
                            let addr = lookupDataSymAddr(dataSyms, name) else {
251 251
                                panic "emitSection: data symbol not found";
256 256
                            let lo: u32 = addr;
257 257
                            let hi: u32 = 0;
258 258
                            let loPtr = &lo as *u8;
259 259
                            let hiPtr = &hi as *u8;
260 260
261 -
                            try! mem::copy(buf[offset..], @sliceOf(loPtr, 4));
262 -
                            try! mem::copy(buf[(offset + 4)..], @sliceOf(hiPtr, 4));
261 +
                            try! mem::copy(&mut buf[offset..], @sliceOf(loPtr, 4));
262 +
                            try! mem::copy(&mut buf[(offset + 4)..], @sliceOf(hiPtr, 4));
263 263
264 264
                            offset = offset + 8;
265 265
                        },
266 266
                        case il::DataItem::Fn(name) => {
267 267
                            let addr = codeBase + labels::funcOffset(fnLabels, name) as u32;
268 268
                            let lo: u32 = addr;
269 269
                            let hi: u32 = 0;
270 270
                            let loPtr = &lo as *u8;
271 271
                            let hiPtr = &hi as *u8;
272 272
273 -
                            try! mem::copy(buf[offset..], @sliceOf(loPtr, 4));
274 -
                            try! mem::copy(buf[(offset + 4)..], @sliceOf(hiPtr, 4));
273 +
                            try! mem::copy(&mut buf[offset..], @sliceOf(loPtr, 4));
274 +
                            try! mem::copy(&mut buf[(offset + 4)..], @sliceOf(hiPtr, 4));
275 275
276 276
                            offset = offset + 8;
277 277
                        },
278 278
                        case il::DataItem::Str(s) => {
279 -
                            try! mem::copy(buf[offset..], s);
279 +
                            try! mem::copy(&mut buf[offset..], s);
280 280
                            offset = offset + s.len;
281 281
                        },
282 282
                        case il::DataItem::Undef => {
283 283
                            buf[offset] = 0;
284 284
                            offset = offset + 1;
331 331
        emit::emit(&mut e, encode::nop()); // Placeholder for two-instruction jump.
332 332
        emit::emit(&mut e, encode::nop()); //
333 333
    }
334 334
335 335
    // Generate code for all functions.
336 -
    let dataSyms = storage.dataSyms[..dataSymCount];
336 +
    let dataSyms = &storage.dataSyms[..dataSymCount];
337 337
338 338
    for i in 0..program.fns.len {
339 339
        let func = program.fns[i];
340 340
        if not func.isExtern {
341 341
            let checkpoint = alloc::save(arena);
lib/std/arch/rv64/emit.rad +3 -3
657 657
// Code Access  //
658 658
//////////////////
659 659
660 660
/// Get emitted code as a slice.
661 661
pub fn getCode(e: *Emitter) -> *[u32] {
662 -
    return e.code[..e.codeLen];
662 +
    return &e.code[..e.codeLen];
663 663
}
664 664
665 665
/// Get function addresses for printing.
666 666
pub fn getFuncs(e: *Emitter) -> *[FuncAddr] {
667 -
    return e.funcs[..e.funcsLen];
667 +
    return &e.funcs[..e.funcsLen];
668 668
}
669 669
670 670
/// Record a debug entry mapping the current PC to a source location.
671 671
/// Deduplicates consecutive entries with the same location.
672 672
pub fn recordSrcLoc(e: *mut Emitter, loc: il::SrcLoc) {
690 690
    e.debugEntriesLen = e.debugEntriesLen + 1;
691 691
}
692 692
693 693
/// Get debug entries as a slice.
694 694
pub fn getDebugEntries(e: *Emitter) -> *[DebugEntry] {
695 -
    return e.debugEntries[..e.debugEntriesLen];
695 +
    return &e.debugEntries[..e.debugEntriesLen];
696 696
}
lib/std/arch/rv64/printer.rad +1 -1
343 343
pub fn printCode(pkgName: *[u8], code: *[u32], funcs: *[emit::FuncAddr], arena: *mut alloc::Arena, buf: *mut [u8]) -> *[u8] {
344 344
    let mut pos: u32 = 0;
345 345
    let mut out = sexpr::Output::Buffer { buf, pos: &mut pos };
346 346
    printCodeTo(&mut out, pkgName, code, funcs, arena);
347 347
348 -
    return buf[..pos];
348 +
    return &buf[..pos];
349 349
}
lib/std/arch/rv64/tests/cond.match.guard.regalloc.rad +2 -2
23 23
    let mut out: *[*[u8]] = &[];
24 24
25 25
    match node.kind {
26 26
        case Kind::Name(name) if name.len > 0 => {
27 27
            buf[0] = name;
28 -
            out = buf[..1];
28 +
            out = &buf[..1];
29 29
        }
30 30
        case Kind::Pair { a, b } => {
31 -
            out = buf[..1];
31 +
            out = &buf[..1];
32 32
        }
33 33
        else => {}
34 34
    }
35 35
    return out;
36 36
}
lib/std/arch/rv64/tests/const.slice.param.rad +2 -2
7 7
}
8 8
9 9
@default fn main() -> i32 {
10 10
    let all: *[i32] = &DATA[..];
11 11
    let head: i32 = sumPair(all);
12 -
    let tail: i32 = sumPair(all[2..]);
13 -
    let mid: i32 = sumPair(all[1..3]);
12 +
    let tail: i32 = sumPair(&all[2..]);
13 +
    let mid: i32 = sumPair(&all[1..3]);
14 14
15 15
    return head + tail + mid;
16 16
}
lib/std/arch/rv64/tests/prog.tokenizer.rad +1 -1
457 457
        return 2;
458 458
    }
459 459
460 460
    // Count number tokens using for-in.
461 461
    let mut numCount: u32 = 0;
462 -
    let slice = tokenBuf[0..list.count];
462 +
    let slice = &tokenBuf[0..list.count];
463 463
    for tok in slice {
464 464
        match tok {
465 465
            case Token::Number(_) => {
466 466
                numCount = numCount + 1;
467 467
            }
lib/std/arch/rv64/tests/slice.subslice.rad +6 -6
1 1
//! returns: 42
2 2
3 3
fn testBasicSubslice() -> bool {
4 4
    let arr: [i32; 5] = [10, 20, 30, 40, 50];
5 5
    let slice: *[i32] = &arr[..];        // Full slice [10, 20, 30, 40, 50]
6 -
    let subslice: *[i32] = slice[1..4]; // Sub-slice [20, 30, 40]
6 +
    let subslice: *[i32] = &slice[1..4]; // Sub-slice [20, 30, 40]
7 7
8 8
    return subslice[0] == 20 and subslice[1] == 30 and subslice[2] == 40;
9 9
}
10 10
11 11
fn testNestedSubslice() -> bool {
12 12
    let arr: [i32; 6] = [100, 200, 300, 400, 500, 600];
13 13
    let slice1: *[i32] = &arr[1..5];     // [200, 300, 400, 500]
14 -
    let slice2: *[i32] = slice1[1..3];  // [300, 400]
15 -
    let slice3: *[i32] = slice2[0..1];  // [300]
14 +
    let slice2: *[i32] = &slice1[1..3];  // [300, 400]
15 +
    let slice3: *[i32] = &slice2[0..1];  // [300]
16 16
17 17
    return slice3[0] == 300;
18 18
}
19 19
20 20
fn testSubsliceLength() -> bool {
21 21
    let arr: [i32; 4] = [1, 2, 3, 4];
22 22
    let slice: *[i32] = &arr[..];
23 -
    let subslice: *[i32] = slice[1..3];
23 +
    let subslice: *[i32] = &slice[1..3];
24 24
25 25
    return subslice.len == 2;
26 26
}
27 27
28 28
fn testEdgeCases() -> bool {
29 29
    let arr: [i32; 3] = [7, 8, 9];
30 30
    let slice: *[i32] = &arr[..];
31 31
32 32
    // Test single element subslice
33 -
    let single: *[i32] = slice[1..2];
33 +
    let single: *[i32] = &slice[1..2];
34 34
    if (single[0] != 8 or single.len != 1) {
35 35
        return false;
36 36
    }
37 37
38 38
    // Test empty subslice
39 -
    let empty: *[i32] = slice[2..2];
39 +
    let empty: *[i32] = &slice[2..2];
40 40
    if (empty.len != 0) {
41 41
        return false;
42 42
    }
43 43
    return true;
44 44
}
lib/std/fmt.rad +6 -6
32 32
            x = x / 10;
33 33
        }
34 34
    }
35 35
    // Return the slice from the start of the written number to
36 36
    // the end of the buffer.
37 -
    return buffer[i..];
37 +
    return &buffer[i..];
38 38
}
39 39
40 40
/// Format a i32 by writing it to the provided buffer.
41 41
pub fn formatI32(val: i32, buffer: *mut [u8]) -> *[u8] {
42 42
    debug::assert(buffer.len >= I32_STR_LEN);
65 65
        if neg {
66 66
            i = i - 1;
67 67
            buffer[i] = '-';
68 68
        }
69 69
    }
70 -
    return buffer[i..];
70 +
    return &buffer[i..];
71 71
}
72 72
73 73
/// Format a u64 by writing it to the provided buffer.
74 74
pub fn formatU64(val: u64, buffer: *mut [u8]) -> *[u8] {
75 75
    debug::assert(buffer.len >= U64_STR_LEN);
85 85
            i = i - 1;
86 86
            buffer[i] = ('0' + (x % 10) as u8);
87 87
            x = x / 10;
88 88
        }
89 89
    }
90 -
    return buffer[i..];
90 +
    return &buffer[i..];
91 91
}
92 92
93 93
/// Format a i64 by writing it to the provided buffer.
94 94
pub fn formatI64(val: i64, buffer: *mut [u8]) -> *[u8] {
95 95
    debug::assert(buffer.len >= I64_STR_LEN);
115 115
        if neg {
116 116
            i = i - 1;
117 117
            buffer[i] = '-';
118 118
        }
119 119
    }
120 -
    return buffer[i..];
120 +
    return &buffer[i..];
121 121
}
122 122
123 123
/// Format a i8 by writing it to the provided buffer.
124 124
pub fn formatI8(val: i8, buffer: *mut [u8]) -> *[u8] {
125 125
    return formatI32(val as i32, buffer);
142 142
143 143
/// Format a bool by writing it to the provided buffer.
144 144
pub fn formatBool(val: bool, buffer: *mut [u8]) -> *[u8] {
145 145
    if val {
146 146
        try! mem::copy(buffer, "true");
147 -
        return buffer[..4];
147 +
        return &buffer[..4];
148 148
    } else {
149 149
        try! mem::copy(buffer, "false");
150 -
        return buffer[..5];
150 +
        return &buffer[..5];
151 151
    }
152 152
}
lib/std/io.rad +2 -2
39 39
40 40
pub fn readToEnd(buf: *mut [u8]) -> *[u8] {
41 41
    let mut total: u32 = 0;
42 42
43 43
    while total < buf.len {
44 -
        let chunk: *mut [u8] = buf[total..];
44 +
        let chunk: *mut [u8] = &mut buf[total..];
45 45
        let n: u32 = read(chunk);
46 46
47 47
        if n == 0 {
48 48
            break;
49 49
        }
51 51
            total = buf.len;
52 52
            break;
53 53
        }
54 54
        total = total + n;
55 55
    }
56 -
    return buf[..total];
56 +
    return &buf[..total];
57 57
}
lib/std/lang/alloc.rad +1 -1
80 80
    return arena.data.len as u32 - arena.offset;
81 81
}
82 82
83 83
/// Returns the remaining buffer as a mutable slice.
84 84
pub fn remainingBuf(arena: *mut Arena) -> *mut [u8] {
85 -
    return arena.data[arena.offset..];
85 +
    return &mut arena.data[arena.offset..];
86 86
}
87 87
88 88
/// Commits `size` bytes of allocation, advancing the offset.
89 89
/// Use after writing to the buffer returned by [`remainingBuf`].
90 90
pub fn commit(arena: *mut Arena, size: u32) {
lib/std/lang/il.rad +4 -4
89 89
    }
90 90
    let buf = try! alloc::allocSlice(arena, 1, 1, totalLen) as *mut [u8];
91 91
    let mut pos: u32 = 0;
92 92
93 93
    for segment in path {
94 -
        pos = pos + try! mem::copy(buf[pos..], segment);
95 -
        pos = pos + try! mem::copy(buf[pos..], PATH_SEPARATOR);
94 +
        pos = pos + try! mem::copy(&mut buf[pos..], segment);
95 +
        pos = pos + try! mem::copy(&mut buf[pos..], PATH_SEPARATOR);
96 96
    }
97 -
    try! mem::copy(buf[pos..], name);
97 +
    try! mem::copy(&mut buf[pos..], name);
98 98
99 -
    return buf[..totalLen];
99 +
    return &buf[..totalLen];
100 100
}
101 101
102 102
///////////
103 103
// Types //
104 104
///////////
lib/std/lang/il/printer.rad +3 -3
46 46
fn prefixStr(a: *mut alloc::Arena, prefix: u8, str: *[u8]) -> *[u8] {
47 47
    let len = str.len + 1;
48 48
    let ptr = try! alloc::allocSlice(a, 1, 1, len);
49 49
    let slice = ptr as *mut [u8];
50 50
    slice[0] = prefix;
51 -
    try! mem::copy(slice[1..], str);
51 +
    try! mem::copy(&mut slice[1..], str);
52 52
53 53
    return slice;
54 54
}
55 55
56 56
/// Format a register reference (`%n`).
433 433
        write(out, ")");
434 434
    }
435 435
    write(out, "\n");
436 436
437 437
    // Instructions.
438 -
    let instrs = block.instrs.list[0..block.instrs.len];
438 +
    let instrs = &block.instrs.list[0..block.instrs.len];
439 439
    for i in 0..instrs.len {
440 440
        indent(out, 1);
441 441
        writeInstr(out, a, blocks, instrs[i]);
442 442
        write(out, ";\n");
443 443
    }
565 565
) -> *[u8] {
566 566
    let mut pos: u32 = 0;
567 567
    let mut out = sexpr::Output::Buffer { buf, pos: &mut pos };
568 568
    printProgram(&mut out, arena, program);
569 569
570 -
    return buf[..pos];
570 +
    return &buf[..pos];
571 571
}
lib/std/lang/lower.rad +20 -20
389 389
}
390 390
391 391
/// Return the accumulated values.
392 392
fn dataBuilderFinish(b: *DataValueBuilder) -> ConstDataResult {
393 393
    return ConstDataResult {
394 -
        values: b.values[..b.len],
394 +
        values: &b.values[..b.len],
395 395
        isUndefined: b.allUndef,
396 396
    };
397 397
}
398 398
399 399
///////////////////////////
755 755
        options: LowerOptions { debug: false, buildTest: false },
756 756
    };
757 757
    let defaultFnIdx = try lowerDecls(&mut low, root, true);
758 758
759 759
    return il::Program {
760 -
        data: low.data[..low.dataCount],
761 -
        fns: low.fns[..low.fnCount],
760 +
        data: &low.data[..low.dataCount],
761 +
        fns: &low.fns[..low.fnCount],
762 762
        defaultFnIdx,
763 763
    };
764 764
}
765 765
766 766
/////////////////////////////////
855 855
}
856 856
857 857
/// Finalize lowering and return the unified IL program.
858 858
pub fn finalize(low: *Lowerer, defaultFnIdx: ?u32) -> il::Program {
859 859
    return il::Program {
860 -
        data: low.data[..low.dataCount],
861 -
        fns: low.fns[..low.fnCount],
860 +
        data: &low.data[..low.dataCount],
861 +
        fns: &low.fns[..low.fnCount],
862 862
        defaultFnIdx,
863 863
    };
864 864
}
865 865
866 866
/////////////////////////////////
1049 1049
    let mut digits: [u8; fmt::U32_STR_LEN] = undefined;
1050 1050
    let suffixText = fmt::formatU32(suffix, &mut digits[..]);
1051 1051
    let totalLen = base.len + suffixText.len;
1052 1052
    let buf = try! alloc::allocSlice(self.low.arena, 1, 1, totalLen) as *mut [u8];
1053 1053
1054 -
    try! mem::copy(buf[..base.len], base);
1055 -
    try! mem::copy(buf[base.len..totalLen], suffixText);
1054 +
    try! mem::copy(&mut buf[..base.len], base);
1055 +
    try! mem::copy(&mut buf[base.len..totalLen], suffixText);
1056 1056
1057 -
    return buf[..totalLen];
1057 +
    return &buf[..totalLen];
1058 1058
}
1059 1059
1060 1060
/// Generate a unique label by appending the global counter to the base.
1061 1061
fn nextLabel(self: *mut FnLowerer, base: *[u8]) -> *[u8] throws (LowerError) {
1062 1062
    let idx = self.labelCounter;
1519 1519
    let suffix = fmt::formatU32(count, &mut digits[..]);
1520 1520
    let suffixStart = prefix.len + 1;
1521 1521
    let totalLen = suffixStart + suffix.len;
1522 1522
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1523 1523
1524 -
    try! mem::copy(buf[..prefix.len], prefix);
1524 +
    try! mem::copy(&mut buf[..prefix.len], prefix);
1525 1525
    buf[prefix.len] = '$';
1526 -
    try! mem::copy(buf[suffixStart..], suffix);
1526 +
    try! mem::copy(&mut buf[suffixStart..], suffix);
1527 1527
1528 -
    return buf[..totalLen];
1528 +
    return &buf[..totalLen];
1529 1529
}
1530 1530
1531 1531
/// Append a data entry using a declaration-scoped name (`prefix$N`).
1532 1532
fn pushDeclData(
1533 1533
    self: *mut Lowerer,
1558 1558
1559 1559
    values[0] = il::DataValue {
1560 1560
        item: il::DataItem::Str(s),
1561 1561
        count: 1
1562 1562
    };
1563 -
    return try pushDeclData(self, s.len, 1, true, values[..1], dataPrefix);
1563 +
    return try pushDeclData(self, s.len, 1, true, &values[..1], dataPrefix);
1564 1564
}
1565 1565
1566 1566
/// Compare two data items for structural equality.
1567 1567
/// Unlike raw byte comparison, this correctly ignores padding bytes in unions.
1568 1568
fn dataItemEq(a: il::DataItem, b: il::DataItem) -> bool {
2389 2389
    let mut count: u32 = 0;
2390 2390
2391 2391
    for i in 0..self.blockCount {
2392 2392
        let data = &self.blockData[i];
2393 2393
2394 -
        let params = data.params.list[..data.params.len];
2395 -
        let preds = data.preds.list[..data.preds.len];
2394 +
        let params = &data.params.list[..data.params.len];
2395 +
        let preds = &data.preds.list[..data.preds.len];
2396 2396
        blocks[count] = il::Block {
2397 2397
            label: data.label,
2398 2398
            params,
2399 2399
            instrs: data.instrs,
2400 -
            locs: data.locs[..data.locsLen],
2400 +
            locs: &data.locs[..data.locsLen],
2401 2401
            preds,
2402 2402
            loopDepth: data.loopDepth,
2403 2403
        };
2404 2404
        count = count + 1;
2405 2405
    }
2406 -
    return blocks[..count];
2406 +
    return &blocks[..count];
2407 2407
}
2408 2408
2409 2409
/////////////////////
2410 2410
// Loop Management //
2411 2411
/////////////////////
3253 3253
    }
3254 3254
    emit(self, il::Instr::Switch {
3255 3255
        val: subject.val,
3256 3256
        defaultTarget: blocks[defaultIdx].n,
3257 3257
        defaultArgs: &mut [],
3258 -
        cases: cases[..caseIdx]
3258 +
        cases: &mut cases[..caseIdx]
3259 3259
    });
3260 3260
3261 3261
    for i in 0..prongs.len {
3262 3262
        let p = prongs.list[i];
3263 3263
        let case ast::NodeValue::MatchProng(prong) = p.value
4790 4790
4791 4791
/// Lower a subscript expression.
4792 4792
fn lowerSubscript(self: *mut FnLowerer, node: *ast::Node, container: *ast::Node, index: *ast::Node) -> il::Val
4793 4793
    throws (LowerError)
4794 4794
{
4795 -
    if let case ast::NodeValue::Range(range) = index.value {
4796 -
        return try lowerSliceRange(self, container, range, node);
4795 +
    if let case ast::NodeValue::Range(_) = index.value {
4796 +
        panic "lowerSubscript: range subscript must use address-of (&)";
4797 4797
    }
4798 4798
    let result = try lowerElemPtr(self, container, index);
4799 4799
4800 4800
    return emitRead(self, result.elemReg, 0, result.elemType);
4801 4801
}
5940 5940
    }
5941 5941
    emit(self, il::Instr::Switch {
5942 5942
        val: il::Val::Reg(tagReg),
5943 5943
        defaultTarget: defaultTarget.n,
5944 5944
        defaultArgs: &mut [],
5945 -
        cases: cases[..caseIdx]
5945 +
        cases: &mut cases[..caseIdx]
5946 5946
    });
5947 5947
5948 5948
    // Second pass: emit each catch clause body.
5949 5949
    for i in 0..catches.len {
5950 5950
        let clauseNode = catches.list[i];
lib/std/lang/lower/tests/slice.range.rad +4 -4
1 1
/// Returns a subslice with explicit bounds.
2 2
fn sliceRange(s: *[i32], start: u32, end: u32) -> *[i32] {
3 -
    return s[start..end];
3 +
    return &s[start..end];
4 4
}
5 5
6 6
/// Returns a subslice with an open end bound.
7 7
fn sliceRangeOpenEnd(s: *[i32], start: u32) -> *[i32] {
8 -
    return s[start..];
8 +
    return &s[start..];
9 9
}
10 10
11 11
/// Returns a subslice with an open start bound.
12 12
fn sliceRangeOpenStart(s: *[i32], end: u32) -> *[i32] {
13 -
    return s[..end];
13 +
    return &s[..end];
14 14
}
15 15
16 16
/// Returns a full reslice of a slice.
17 17
fn sliceRangeFull(s: *[i32]) -> *[i32] {
18 -
    return s[..];
18 +
    return &s[..];
19 19
}
20 20
21 21
/// Returns a subslice from an array parameter.
22 22
fn sliceArray(a: [i32; 4]) -> *[i32] {
23 23
    return &a[1..3];
lib/std/lang/module.rad +7 -7
199 199
    return m.children[index];
200 200
}
201 201
202 202
/// Public accessor for a module's directory prefix.
203 203
pub fn moduleDir(m: *ModuleEntry) -> *[u8] {
204 -
    return m.filePath[..m.dirLen];
204 +
    return &m.filePath[..m.dirLen];
205 205
}
206 206
207 207
/// Public accessor to the logical module path segments.
208 208
pub fn moduleQualifiedPath(m: *ModuleEntry) -> *[*[u8]] {
209 209
    debug::assertMsg(m.pathDepth > 0, "moduleQualifiedPath: path must not be empty");
262 262
    // Split on '/' to extract all but the last component.
263 263
    for i in 0..filePath.len {
264 264
        if filePath[i] == PATH_SEP {
265 265
            if i > last {
266 266
                debug::assertMsg(count < components.len, "parsePath: output slice is large enough");
267 -
                components[count] = filePath[last..i];
267 +
                components[count] = &filePath[last..i];
268 268
                count = count + 1;
269 269
            }
270 270
            last = i + 1;
271 271
        }
272 272
    }
274 274
        return nil; // Path ends with separator or is empty.
275 275
    }
276 276
277 277
    // Handle the last component by removing extension.
278 278
    debug::assertMsg(count < components.len, "parsePath: output slice is large enough");
279 -
    if let name = trimExtension(filePath[last..]) {
279 +
    if let name = trimExtension(&filePath[last..]) {
280 280
        components[count] = name;
281 281
    } else {
282 282
        return nil;
283 283
    };
284 284
    count = count + 1;
323 323
    }
324 324
    let childName = childPath[childPath.len - 1];
325 325
326 326
    // Navigate through all but the last segment to find the parent.
327 327
    let mut parentId = root;
328 -
    for part in childPath[..(childPath.len - 1)] {
328 +
    for part in &childPath[..(childPath.len - 1)] {
329 329
        let child = findChild(graph, part, parentId) else {
330 330
            throw ModuleError::MissingParent;
331 331
        };
332 332
        parentId = child.id;
333 333
    }
410 410
fn basenameSlice(path: *[u8]) -> *[u8] throws (ModuleError) {
411 411
    let start = basenameStart(path);
412 412
    let withoutExt = trimExtension(path) else {
413 413
        throw ModuleError::InvalidPath;
414 414
    };
415 -
    return withoutExt[start..];
415 +
    return &withoutExt[start..];
416 416
}
417 417
418 418
/// Find the byte offset immediately following the last separator.
419 419
fn basenameStart(path: *[u8]) -> u32 {
420 420
    let mut start: u32 = 0;
436 436
    for i in 0..SOURCE_EXT.len {
437 437
        if path[extStart + i] != SOURCE_EXT[i] {
438 438
            return nil;
439 439
        }
440 440
    }
441 -
    return path[..extStart];
441 +
    return &path[..extStart];
442 442
}
443 443
444 444
/// Strip prefix from path, and return the suffix.
445 445
fn stripPathPrefix(prefix: *[*[u8]], path: *[*[u8]]) -> ?*[*[u8]] {
446 446
    if prefix.len == 0 {
452 452
    for segment, i in prefix {
453 453
        if not mem::eq(segment, path[i]) {
454 454
            return nil;
455 455
        }
456 456
    }
457 -
    return path[prefix.len..];
457 +
    return &path[prefix.len..];
458 458
}
lib/std/lang/parser.rad +3 -3
738 738
            return nodeChar(p, ch);
739 739
        }
740 740
        case scanner::TokenKind::String => {
741 741
            advance(p);
742 742
            let src = p.previous.source;
743 -
            let raw = src[1..src.len - 1]; // Strip quotes.
743 +
            let raw = &src[1..src.len - 1]; // Strip quotes.
744 744
745 745
            // Process escape sequences into arena buffer.
746 746
            let buf = alloc::remainingBuf(&mut p.arena.arena);
747 747
            let len = unescapeString(raw, buf);
748 748
            alloc::commit(&mut p.arena.arena, len);
749 749
750 -
            return nodeString(p, buf[..len]);
750 +
            return nodeString(p, &buf[..len]);
751 751
        }
752 752
        case scanner::TokenKind::Underscore => {
753 753
            advance(p);
754 754
            return node(p, ast::NodeValue::Placeholder);
755 755
        }
921 921
fn tryParseAnnotation(p: *mut Parser) -> ?*ast::Node {
922 922
    if not check(p, scanner::TokenKind::AtIdent) {
923 923
        return nil;
924 924
    }
925 925
    // Token is @identifier, skip the '@' to get the name.
926 -
    let ident = p.current.source[..];
926 +
    let ident = &p.current.source[..];
927 927
    if ident == "@default" {
928 928
        advance(p); // Consume `@default`.
929 929
        return nodeAttribute(p, ast::Attribute::Default);
930 930
    }
931 931
    if ident == "@test" {
lib/std/lang/resolver.rad +43 -69
2063 2063
        case ast::NodeValue::Ident(name) if name.len > 0 => {
2064 2064
            if buf.len < 1 {
2065 2065
                panic "flattenPath: invalid output buffer size";
2066 2066
            }
2067 2067
            buf[0] = name;
2068 -
            out = buf[..1];
2068 +
            out = &buf[..1];
2069 2069
        }
2070 2070
        case ast::NodeValue::ScopeAccess(access) => {
2071 2071
            // Recursively flatten parent path.
2072 2072
            let parent = try flattenPath(self, access.parent, buf);
2073 2073
            if parent.len >= buf.len {
2074 2074
                panic "flattenPath: invalid output buffer size";
2075 2075
            }
2076 2076
            let child = try nodeName(self, access.child);
2077 2077
            buf[parent.len] = child;
2078 -
            out = buf[..parent.len + 1];
2078 +
            out = &buf[..parent.len + 1];
2079 2079
        }
2080 2080
        case ast::NodeValue::Super => {
2081 2081
            // `super` is handled by scope adjustment in `checkSuperAccess`.
2082 2082
            // Return empty prefix so the path continues from the next segment.
2083 -
            out = buf[..0];
2083 +
            out = &buf[..0];
2084 2084
            return out;
2085 2085
        }
2086 2086
        else => {
2087 2087
            // Fallthrough to error.
2088 2088
        }
2202 2202
    }
2203 2203
    // Start by finding the root of the path.
2204 2204
    let root = path[0];
2205 2205
    let sym = findInScopeRecursive(scope, root, isAnySymbol) else
2206 2206
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
2207 -
    let suffix = path[1..];
2207 +
    let suffix = &path[1..];
2208 2208
2209 2209
    // Check visibility for symbol.
2210 2210
    if not isSymbolVisible(sym, scope, self.scope) {
2211 2211
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
2212 2212
    }
2263 2263
    }
2264 2264
    let parentName = path[0];
2265 2265
2266 2266
    // First, check if this is a sub-module of the start scope.
2267 2267
    if let sym = findSymbolInScope(startScope, parentName) {
2268 -
        return try resolveModulePathRecursive(self, module, path[1..], sym);
2268 +
        return try resolveModulePathRecursive(self, module, &path[1..], sym);
2269 2269
    }
2270 2270
    // Not a sub-module, so look in the global scope for a package root.
2271 2271
    let sym = findSymbolInScope(self.pkgScope, parentName)
2272 2272
        else throw emitError(self, module, ErrorKind::UnresolvedSymbol(parentName));
2273 2273
2274 -
    return try resolveModulePathRecursive(self, module, path[1..], sym);
2274 +
    return try resolveModulePathRecursive(self, module, &path[1..], sym);
2275 2275
}
2276 2276
2277 2277
/// Recursively resolve the remaining path segments by traversing child modules.
2278 2278
fn resolveModulePathRecursive(
2279 2279
    self: *mut Resolver,
2295 2295
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(childName));
2296 2296
    }
2297 2297
    return try resolveModulePathRecursive(
2298 2298
        self,
2299 2299
        node,
2300 -
        path[1..],
2300 +
        &path[1..],
2301 2301
        childSym
2302 2302
    );
2303 2303
}
2304 2304
2305 2305
/// Resolve a type name, which could be an identifier or scoped path.
4228 4228
4229 4229
/// Analyze an array or slice subscript expression.
4230 4230
fn resolveSubscript(self: *mut Resolver, node: *ast::Node, container: *ast::Node, indexNode: *ast::Node) -> Type
4231 4231
    throws (ResolveError)
4232 4232
{
4233 -
    let containerTy = try infer(self, container);
4234 -
    let mut indexTy: Type = undefined;
4235 -
    let mut rangeExpr: ?ast::Range = nil;
4236 -
4237 -
    match indexNode.value {
4238 -
        case ast::NodeValue::Range(range) => {
4239 -
            indexTy = try infer(self, indexNode);
4240 -
            rangeExpr = range;
4241 -
        }
4242 -
        else => {
4243 -
            indexTy = try checkAssignable(self, indexNode, Type::U32);
4244 -
        }
4233 +
    // Range subscripts always require `&` to form a slice.
4234 +
    if let case ast::NodeValue::Range(range) = indexNode.value {
4235 +
        let _ = try infer(self, indexNode);
4236 +
        let _ = try infer(self, container);
4237 +
        try checkSliceRangeIndices(self, range);
4238 +
        throw emitError(self, node, ErrorKind::SliceRequiresAddress);
4245 4239
    }
4240 +
    let containerTy = try infer(self, container);
4241 +
    let _ = try checkAssignable(self, indexNode, Type::U32);
4246 4242
    let subjectTy = autoDeref(containerTy);
4247 4243
4248 4244
    match subjectTy {
4249 4245
        case Type::Array(arrayInfo) => {
4250 -
            if let range = rangeExpr {
4251 -
                try checkSliceRangeIndices(self, range);
4252 -
                throw emitError(self, node, ErrorKind::SliceRequiresAddress);
4253 -
            }
4254 4246
            return try setNodeType(self, node, *arrayInfo.item);
4255 4247
        }
4256 -
        case Type::Slice { item, mutable } => {
4257 -
            if let range = rangeExpr {
4258 -
                try checkSliceRangeIndices(self, range);
4259 -
                try setSliceRangeInfo(self, node, SliceRangeInfo {
4260 -
                    itemType: item,
4261 -
                    mutable,
4262 -
                    capacity: nil,
4263 -
                });
4264 -
                return try setNodeType(self, node, *allocType(self, Type::Slice {
4265 -
                    item,
4266 -
                    mutable,
4267 -
                }));
4268 -
            }
4248 +
        case Type::Slice { item, .. } => {
4269 4249
            return try setNodeType(self, node, *item);
4270 4250
        }
4271 4251
        else => {
4272 4252
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
4273 4253
        }
4739 4719
    if let case ast::NodeValue::Subscript { container, index } = addr.target.value {
4740 4720
        if let case ast::NodeValue::Range(range) = index.value {
4741 4721
            let containerTy = try infer(self, container);
4742 4722
            let subjectTy = autoDeref(containerTy);
4743 4723
4744 -
            if let case Type::Array(arrayInfo) = subjectTy {
4745 -
                try checkSliceRangeIndices(self, range);
4746 -
                try validateArraySliceBounds(self, range, arrayInfo.length, node);
4747 -
                let sliceTy = Type::Slice {
4748 -
                    item: arrayInfo.item,
4749 -
                    mutable: addr.mutable,
4750 -
                };
4751 -
                let alloc = allocType(self, sliceTy);
4752 -
                try setSliceRangeInfo(self, node, SliceRangeInfo {
4753 -
                    itemType: arrayInfo.item,
4754 -
                    mutable: addr.mutable,
4755 -
                    capacity: arrayInfo.length,
4756 -
                });
4757 -
                try setNodeType(self, addr.target, *alloc);
4724 +
            try checkSliceRangeIndices(self, range);
4758 4725
4759 -
                return try setNodeType(self, node, *alloc);
4760 -
            }
4761 -
            if let case Type::Slice { item, mutable } = subjectTy {
4762 -
                if addr.mutable and not mutable {
4763 -
                    throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
4764 -
                }
4765 -
                try checkSliceRangeIndices(self, range);
4766 -
                let sliceTy = Type::Slice {
4767 -
                    item,
4768 -
                    mutable: addr.mutable,
4769 -
                };
4770 -
                let alloc = allocType(self, sliceTy);
4771 -
                try setSliceRangeInfo(self, node, SliceRangeInfo {
4772 -
                    itemType: item,
4773 -
                    mutable: addr.mutable,
4774 -
                    capacity: nil,
4775 -
                });
4776 -
                try setNodeType(self, addr.target, *alloc);
4726 +
            let mut item: *Type = undefined;
4727 +
            let mut capacity: ?u32 = nil;
4777 4728
4778 -
                return try setNodeType(self, node, *alloc);
4729 +
            match subjectTy {
4730 +
                case Type::Array(arrayInfo) => {
4731 +
                    try validateArraySliceBounds(self, range, arrayInfo.length, node);
4732 +
                    item = arrayInfo.item;
4733 +
                    capacity = arrayInfo.length;
4734 +
                }
4735 +
                case Type::Slice { item: sliceItem, mutable } => {
4736 +
                    if addr.mutable and not mutable {
4737 +
                        throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
4738 +
                    }
4739 +
                    item = sliceItem;
4740 +
                }
4741 +
                else => {
4742 +
                    throw emitError(self, container, ErrorKind::ExpectedIndexable);
4743 +
                }
4779 4744
            }
4745 +
            let sliceTy = Type::Slice { item, mutable: addr.mutable };
4746 +
            let alloc = allocType(self, sliceTy);
4747 +
            try setSliceRangeInfo(self, node, SliceRangeInfo {
4748 +
                itemType: item,
4749 +
                mutable: addr.mutable,
4750 +
                capacity,
4751 +
            });
4752 +
            try setNodeType(self, addr.target, *alloc);
4753 +
            return try setNodeType(self, node, *alloc);
4780 4754
        }
4781 4755
    }
4782 4756
    // Derive a hint for the target type from the slice hint.
4783 4757
    let mut targetHint: Type = Type::Unknown;
4784 4758
    if let case Type::Slice { item, .. } = hint {
lib/std/lang/resolver/tests.rad +7 -0
933 933
    let program = "let xs: [u8; 2] = [1, 2]; xs[..];";
934 934
    let result = try resolveProgramStr(&mut a, program);
935 935
    try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
936 936
}
937 937
938 +
@test fn testResolveSliceResliceRequiresAddressOf() throws (testing::TestError) {
939 +
    let mut a = testResolver();
940 +
    let program = "fn f(s: *[u8]) -> *[u8] { return s[..]; }";
941 +
    let result = try resolveProgramStr(&mut a, program);
942 +
    try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
943 +
}
944 +
938 945
@test fn testResolveSliceRangeOutOfBounds() throws (testing::TestError) {
939 946
    {
940 947
        let mut a = testResolver();
941 948
        let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[..3];";
942 949
        let result = try resolveProgramStr(&mut a, program);
lib/std/lang/scanner.rad +4 -4
367 367
    return false;
368 368
}
369 369
370 370
/// Create a token from the current scanner state.
371 371
fn tok(s: *Scanner, kind: TokenKind) -> Token {
372 -
    return Token { kind, source: s.source[s.token..s.cursor], offset: s.token };
372 +
    return Token { kind, source: &s.source[s.token..s.cursor], offset: s.token };
373 373
}
374 374
375 375
/// Create an invalid token with the given message.
376 376
pub fn invalid(offset: u32, message: *[u8]) -> Token {
377 377
    return Token { kind: TokenKind::Invalid, source: message, offset };
526 526
/// Scan an identifier, keyword, or label.
527 527
fn scanIdentifier(s: *mut Scanner) -> Token {
528 528
    while let ch = current(s); isAlpha(ch) or isDigit(ch) or ch == '_' or ch == '#' {
529 529
        advance(s);
530 530
    }
531 -
    let ident = s.source[s.token..s.cursor];
531 +
    let ident = &s.source[s.token..s.cursor];
532 532
    let kind = keywordOrIdent(ident);
533 533
534 534
    // Only intern actual identifiers, not keywords.
535 535
    if kind == TokenKind::Ident {
536 536
        return Token { kind, source: strings::intern(s.pool, ident), offset: s.token };
683 683
            }
684 684
            // Must have at least one character after `@`.
685 685
            if s.cursor - s.token <= 1 {
686 686
                return invalid(s.token, "expected identifier after `@`");
687 687
            }
688 -
            let name = s.source[s.token..s.cursor];
688 +
            let name = &s.source[s.token..s.cursor];
689 689
            return Token {
690 690
                kind: TokenKind::AtIdent,
691 691
                source: strings::intern(s.pool, name),
692 692
                offset: s.token,
693 693
            };
709 709
    let mut c: u16 = 1;
710 710
711 711
    if offset >= source.len {
712 712
        return nil;
713 713
    }
714 -
    for ch in source[..offset] {
714 +
    for ch in &source[..offset] {
715 715
        if ch == '\n' {
716 716
            c = 1;
717 717
            l = l + 1;
718 718
        } else {
719 719
            c = c + 1;
lib/std/mem.rad +1 -1
29 29
    for i in 0..prefix.len {
30 30
        if prefix[i] != input[i] {
31 31
            return nil;
32 32
        }
33 33
    }
34 -
    return input[prefix.len..];
34 +
    return &input[prefix.len..];
35 35
}
36 36
37 37
/// Align value up to alignment boundary.
38 38
pub fn alignUp(value: u32, alignment: u32) -> u32 {
39 39
    return (value + alignment - 1) & ~(alignment - 1);
lib/std/sys/unix.rad +3 -3
54 54
/// Reads from a file descriptor until EOF or buffer is full.
55 55
/// Returns the total number of bytes read, or a negative value on error.
56 56
pub fn readToEnd(fd: i32, buf: *mut [u8]) -> i32 {
57 57
    let mut total: u32 = 0;
58 58
    while total < buf.len {
59 -
        let chunk = buf[total..];
59 +
        let chunk = &mut buf[total..];
60 60
        let n = read(fd, chunk);
61 61
62 62
        if n < 0 {
63 63
            return n;
64 64
        }
96 96
        return nil;
97 97
    }
98 98
    if n < 0 {
99 99
        return nil;
100 100
    }
101 -
    return buf[..(n as u32)];
101 +
    return &buf[..(n as u32)];
102 102
}
103 103
104 104
/// Exit the current process with the given status code.
105 105
pub fn exit(status: i32) {
106 106
    intrinsics::ecall(93, status, 0, 0, 0);
117 117
    if fd < 0 {
118 118
        return false;
119 119
    }
120 120
    let mut written: u32 = 0;
121 121
    while written < data.len {
122 -
        let chunk = data[written..];
122 +
        let chunk = &data[written..];
123 123
        let n = write(fd, chunk);
124 124
        if n <= 0 {
125 125
            close(fd);
126 126
            return false;
127 127
        }
test/lower/lower-test.rad +4 -4
41 41
        if line[i] != ' ' and line[i] != '\t' {
42 42
            end = i + 1;
43 43
        }
44 44
        i = i + 1;
45 45
    }
46 -
    return line[..end];
46 +
    return &line[..end];
47 47
}
48 48
49 49
/// Get next line from string at offset. Returns the line and updates offset past newline.
50 50
fn nextLine(s: *[u8], offset: *mut u32) -> *[u8] {
51 51
    let start = *offset;
52 52
    let mut i = start;
53 53
54 54
    while i < s.len and s[i] != '\n' {
55 55
        i = i + 1;
56 56
    }
57 -
    let line = s[start..i];
57 +
    let line = &s[start..i];
58 58
    if i < s.len {
59 59
        *offset = i + 1;
60 60
    } else {
61 61
        *offset = i;
62 62
    }
102 102
    if len < 4 {
103 103
        return nil;
104 104
    }
105 105
    // Check for .rad extension.
106 106
    let extStart = len - 4; // TODO: language support for additions in ranges.
107 -
    if not mem::eq(sourcePath[extStart..len], ".rad") {
107 +
    if not mem::eq(&sourcePath[extStart..len], ".rad") {
108 108
        return nil;
109 109
    }
110 110
    if len + 1 > buf.len {
111 111
        return nil;
112 112
    }
119 119
    buf[len - 3] = 'r';
120 120
    buf[len - 2] = 'i';
121 121
    buf[len - 1] = 'l';
122 122
    buf[len] = 0;
123 123
124 -
    return buf[..len];
124 +
    return &buf[..len];
125 125
}
126 126
127 127
/// Run a single lowering test case. Returns `true` on success.
128 128
fn runTest(sourcePath: *[u8]) -> bool {
129 129
    // Buffers for file I/O.