compiler: Construct initialized match payload values

d335f4853a2b54338a2a87b861bd3346b5a616efa351d9ad064881cea52dbff9
Alexis Sellier committed ago 1 parent b4557190
lib/std/lang/lower.rad +22 -22
3368 3368
        return il::Val::Undef;
3369 3369
    }
3370 3370
    return emitRead(self, base, valOffset, payload);
3371 3371
}
3372 3372
3373 -
/// Compute the address of the payload in a tagged value aggregate.
3374 -
unsafe fn tvalPayloadAddr 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg, valOffset: i32) -> il::Val where 'arena: 'phase, 'phase: 'function {
3375 -
    return il::Val::Reg(emitPtrOffset(self, base, valOffset));
3373 +
/// Select the payload value or address for the declared match mode.
3374 +
unsafe fn tvalPayloadBinding 'arena 'phase 'function (
3375 +
    self: &mut FnLowerer 'arena 'phase 'function,
3376 +
    base: il::Reg,
3377 +
    bindType: resolver::Type,
3378 +
    matchBy: resolver::MatchBy,
3379 +
    valOffset: i32
3380 +
) -> il::Val where 'arena: 'phase, 'phase: 'function {
3381 +
    match matchBy {
3382 +
        case resolver::MatchBy::Value =>
3383 +
            return tvalPayloadVal(self, base, bindType, valOffset),
3384 +
        case resolver::MatchBy::Ref, resolver::MatchBy::MutRef =>
3385 +
            return il::Val::Reg(emitPtrOffset(self, base, valOffset)),
3386 +
    }
3376 3387
}
3377 3388
3378 3389
/// Bind a variable to a tagged value's payload.
3379 3390
unsafe fn bindPayloadVariable 'arena 'phase 'function (
3380 3391
    self: &mut FnLowerer 'arena 'phase 'function,
3384 3395
    matchBy: resolver::MatchBy,
3385 3396
    valOffset: i32,
3386 3397
    mutable: bool
3387 3398
) -> Var throws (LowerError) where 'arena: 'phase, 'phase: 'function {
3388 3399
    let base = emitValToReg(self, subjectVal);
3389 -
    let mut payload: il::Val = undefined;
3390 -
3391 -
    match matchBy {
3392 -
        case resolver::MatchBy::Value =>
3393 -
            set payload = tvalPayloadVal(self, base, bindType, valOffset),
3394 -
        case resolver::MatchBy::Ref, resolver::MatchBy::MutRef =>
3395 -
            set payload = tvalPayloadAddr(self, base, valOffset),
3396 -
    };
3400 +
    let payload = tvalPayloadBinding(self, base, bindType, matchBy, valOffset);
3397 3401
    return newVar(self, name, ilType(self.low, bindType), mutable, payload);
3398 3402
}
3399 3403
3400 3404
/// Bind an identifier from a matched subject.
3401 3405
unsafe fn bindMatchVariable 'arena 'phase 'function (
3623 3627
    // Build a MatchSubject for the nested field.
3624 3628
    let ilTy = ilType(self.low, fieldType);
3625 3629
    let kind = matchSubjectKind(fieldType);
3626 3630
3627 3631
    // Determine the subject value.
3628 -
    let mut val: il::Val = undefined;
3629 -
    if let reg = derefBase {
3630 -
        // Auto-deref: the loaded pointer is the address of the target value.
3631 -
        set val = il::Val::Reg(reg);
3632 -
    } else if isAggregateType(fieldType) {
3633 -
        // Aggregate: use the pointer.
3634 -
        set val = il::Val::Reg(fieldPtr);
3635 -
    } else {
3636 -
        // Scalar: load the value.
3637 -
        set val = emitRead(self, base, fieldInfo.offset, fieldType);
3638 -
    }
3632 +
    // Auto-deref: the loaded pointer is the address of the target value.
3633 +
    let subjectBase = derefBase else fieldPtr;
3634 +
    // Aggregate: use the pointer.
3635 +
    // Scalar: load the value.
3636 +
    let val = il::Val::Reg(subjectBase)
3637 +
        if derefBase <> nil or isAggregateType(fieldType)
3638 +
        else emitRead(self, base, fieldInfo.offset, fieldType);
3639 3639
    let nestedSubject = MatchSubject {
3640 3640
        val,
3641 3641
        type: fieldType,
3642 3642
        ilType: ilTy,
3643 3643
        bindType: fieldType,
test/tests/match.payload.modes.rad added +47 -0
1 +
//! returns: 0
2 +
3 +
/// Read an optional payload by value.
4 +
fn byValue(value: ?u32) -> u32 {
5 +
    match value {
6 +
        payload => return payload,
7 +
        case nil => return 0,
8 +
    }
9 +
}
10 +
11 +
/// Read an optional payload through a shared reference.
12 +
fn byRef(value: &?u32) -> u32 {
13 +
    match value {
14 +
        payload => return *payload,
15 +
        case nil => return 0,
16 +
    }
17 +
}
18 +
19 +
/// Update an optional payload through a mutable reference.
20 +
fn byMutRef(value: &mut ?u32) -> u32 {
21 +
    match value {
22 +
        payload => {
23 +
            let previous = *payload;
24 +
            set *payload += 1;
25 +
            return previous;
26 +
        }
27 +
        case nil => return 0,
28 +
    }
29 +
}
30 +
31 +
/// Compare all payload modes and confirm mutation of the original optional.
32 +
@default fn main() -> u32 {
33 +
    let mut absent: ?u32 = nil;
34 +
    assert byValue(absent) == 0;
35 +
    assert byRef(&absent) == 0;
36 +
    assert byMutRef(&mut absent) == 0;
37 +
    assert absent == nil;
38 +
    for initial in 1..10 {
39 +
        let mut present: ?u32 = initial;
40 +
        assert byValue(present) == initial;
41 +
        assert byRef(&present) == initial;
42 +
        assert byMutRef(&mut present) == initial;
43 +
        assert byValue(present) == initial + 1;
44 +
        assert byRef(&present) == initial + 1;
45 +
    }
46 +
    return 0;
47 +
}