compiler: Construct initialized container lengths

91c342336358f9fa25b611c39ef34bf8c45a066dadf104694e9892566032dc55
Alexis Sellier committed ago 1 parent 82bcbace
lib/std/lang/lower.rad +18 -10
2478 2478
    let lenReg = nextReg(self);
2479 2479
    emitLoadW32At(self, lenReg, sliceReg, SLICE_LEN_OFFSET);
2480 2480
    return il::Val::Reg(lenReg);
2481 2481
}
2482 2482
2483 +
/// Return a fixed array length or load the length from a slice value.
2484 +
unsafe fn containerLength 'arena 'phase 'function (
2485 +
    self: &mut FnLowerer 'arena 'phase 'function,
2486 +
    base: il::Reg,
2487 +
    length: ?u32
2488 +
) -> il::Val where 'arena: 'phase, 'phase: 'function {
2489 +
    if let len = length { // Array (length is known).
2490 +
        return il::Val::Imm(len as i64);
2491 +
    }
2492 +
    // Slice (length must be loaded).
2493 +
    return loadSliceLen(self, base);
2494 +
}
2495 +
2483 2496
/// Load the capacity from a slice value.
2484 2497
unsafe fn loadSliceCap 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function {
2485 2498
    let capReg = nextReg(self);
2486 2499
    emitLoadW32At(self, capReg, sliceReg, SLICE_CAP_OFFSET);
2487 2500
    return il::Val::Reg(capReg);
5111 5124
) -> SliceRangeResult throws (LowerError) where 'arena: 'phase, 'phase: 'function {
5112 5125
    let baseVal = try lowerExpr(self, container);
5113 5126
    let baseReg = emitValToReg(self, baseVal);
5114 5127
5115 5128
    // Extract data pointer and container length.
5129 +
    // Slice from array: the base register is the data pointer.
5116 5130
    let mut dataReg = baseReg;
5117 -
    let mut containerLen: il::Val = undefined;
5118 -
    if let cap = info.capacity { // Slice from array.
5119 -
        set containerLen = il::Val::Imm(cap as i64);
5120 -
    } else { // Slice from slice.
5131 +
    if info.capacity == nil { // Slice from slice.
5121 5132
        set dataReg = loadSlicePtr(self, baseReg);
5122 -
        set containerLen = loadSliceLen(self, baseReg);
5123 5133
    }
5134 +
    let containerLen = containerLength(self, baseReg, info.capacity);
5124 5135
5125 5136
    // Compute range bounds.
5126 5137
    let mut startVal: il::Val = il::Val::Imm(0);
5127 5138
    if let start = range.start {
5128 5139
        set startVal = try lowerExpr(self, start);
5873 5884
        case resolver::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
5874 5885
            let containerVal = try lowerExpr(self, f.iterable);
5875 5886
            let containerReg = emitValToReg(self, containerVal);
5876 5887
5877 5888
            let mut dataReg = containerReg;
5878 -
            let mut lengthVal: il::Val = undefined;
5879 -
            if let len = length { // Array (length is known).
5880 -
                set lengthVal = il::Val::Imm(len as i64);
5881 -
            } else { // Slice (length must be loaded).
5882 -
                set lengthVal = loadSliceLen(self, containerReg);
5889 +
            let lengthVal = containerLength(self, containerReg, length);
5890 +
            if length == nil {
5883 5891
                set dataReg = loadSlicePtr(self, containerReg);
5884 5892
            }
5885 5893
            // Declare index value binidng.
5886 5894
            let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5887 5895
test/tests/container.length.paths.rad added +42 -0
1 +
//! returns: 0
2 +
3 +
/// Sum a slice and check its iteration index.
4 +
fn sum(values: &[u32]) -> u32 {
5 +
    let mut result: u32 = 0;
6 +
    for value, index in values {
7 +
        assert value == values[index];
8 +
        set result += value;
9 +
    }
10 +
    return result;
11 +
}
12 +
13 +
/// Compare array and slice lengths through every valid subrange.
14 +
@default fn main() -> u32 {
15 +
    let data: [u32; 6] = [1, 2, 3, 4, 5, 6];
16 +
    let empty: [u32; 0] = [];
17 +
    let mut total: u32 = 0;
18 +
    for value, index in data {
19 +
        assert value == index + 1;
20 +
        set total += value;
21 +
    }
22 +
    assert total == 21;
23 +
    for value in empty {
24 +
        assert false;
25 +
    }
26 +
    assert sum(&empty[..]) == 0;
27 +
    for start in 0..7 {
28 +
        for end in start..7 {
29 +
            let mut expected: u32 = 0;
30 +
            for index in start..end {
31 +
                set expected += index + 1;
32 +
            }
33 +
            assert sum(&data[start..end]) == expected;
34 +
            let all: 'whole = &data[..] in {
35 +
                assert sum(&all[start..end]) == expected;
36 +
                assert sum(&all[start..]) == 21 - start * (start + 1) / 2;
37 +
                assert sum(&all[..end]) == end * (end + 1) / 2;
38 +
            }
39 +
        }
40 +
    }
41 +
    return 0;
42 +
}