compiler: Select parameter names in checked code

b4557190c4e4a7bf0d88410fa9abc4fc26a8fb7d556329f7ca7158e9d528b4e6
Alexis Sellier committed ago 1 parent 2707105e
lib/std/lang/lower.rad +14 -16
3211 3211
        newArgs.append(il::Val::Undef, alloc::arenaAllocator(self.arena));
3212 3212
    }
3213 3213
    return (&mut newArgs[..]) as *unsafe mut [il::Val];
3214 3214
}
3215 3215
3216 -
/// Extract the parameter name from an [`FnParam`] AST node value.
3217 -
fn paramName(value: *ast::NodeValue) -> *[u8] throws (LowerError) {
3218 -
    let case ast::NodeValue::FnParam(param) = *value else {
3216 +
/// Select a receiver or explicit parameter name from its AST declaration.
3217 +
fn paramName(params: &[*ast::Node], receiver: ?*ast::Node, index: u32) -> *[u8] throws (LowerError) {
3218 +
    let mut position = index;
3219 +
    if let node = receiver {
3220 +
        if index == 0 {
3221 +
            let case ast::NodeValue::Ident(name) = node.value else {
3222 +
                throw LowerError::ExpectedIdentifier;
3223 +
            };
3224 +
            return name;
3225 +
        }
3226 +
        set position -= 1;
3227 +
    }
3228 +
    let case ast::NodeValue::FnParam(param) = params[position].value else {
3219 3229
        throw LowerError::ExpectedFunctionParam;
3220 3230
    };
3221 3231
    let case ast::NodeValue::Ident(name) = param.name.value else {
3222 3232
        throw LowerError::ExpectedIdentifier;
3223 3233
    };
3251 3261
        params.append(il::Param { value: reg, type }, alloc::arenaAllocator(self.arena));
3252 3262
3253 3263
        // Declare the parameter variable. For the receiver, the name comes
3254 3264
        // from the receiver node.
3255 3265
        // For all other parameters, the name comes from the AST params.
3256 -
        let mut name: *[u8] = undefined;
3257 -
        if let recNode = receiverName {
3258 -
            if i == 0 {
3259 -
                let case ast::NodeValue::Ident(recName) = recNode.value else {
3260 -
                    throw LowerError::ExpectedIdentifier;
3261 -
                };
3262 -
                set name = recName;
3263 -
            } else {
3264 -
                set name = try paramName(&astParams[i - 1].value);
3265 -
            }
3266 -
        } else {
3267 -
            set name = try paramName(&astParams[i].value);
3268 -
        }
3266 +
        let name = try paramName(&astParams[..], receiverName, i);
3269 3267
        let v = newVar(self, name, type, false, il::Val::Undef);
3270 3268
3271 3269
        set self.params[i] = FnParamBinding { var: v, reg };
3272 3270
        set self.paramsLen += 1;
3273 3271
    }
test/tests/parameter.receiver.names.rad added +43 -0
1 +
//! returns: 0
2 +
3 +
/// Receiver with a value distinct from every explicit argument.
4 +
record Counter: Copy {
5 +
    /// Receiver contribution.
6 +
    value: u32,
7 +
}
8 +
9 +
/// Check a standalone receiver without explicit parameters.
10 +
fn (counter: &Counter) read() -> u32 {
11 +
    return counter.value;
12 +
}
13 +
14 +
/// Check standalone receiver and parameter-name indexing.
15 +
fn (counter: &Counter) add(amount: u32) -> u32 {
16 +
    return counter.value + amount;
17 +
}
18 +
19 +
/// Dynamic dispatch with the maximum register-only argument count.
20 +
trait Weighted {
21 +
    /// Include all seven explicit arguments in order.
22 +
    fn (&Weighted) sum(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32) -> u32;
23 +
}
24 +
25 +
instance Weighted for Counter {
26 +
    /// Include the receiver and every named parameter in the result.
27 +
    fn (counter: &Counter) sum(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32) -> u32 {
28 +
        return counter.value + a + 2*b + 3*c + 4*d + 5*e + 6*f + 7*g;
29 +
    }
30 +
}
31 +
32 +
/// Check receiver names and explicit names over repeated dispatches.
33 +
@default unsafe fn main() -> u32 {
34 +
    for value in 0..8 {
35 +
        let counter = Counter { value };
36 +
        assert counter.read() == value;
37 +
        assert counter.add(17) == value + 17;
38 +
        let weighted: *unsafe opaque Weighted = &counter;
39 +
        assert weighted.sum(1, 2, 3, 4, 5, 6, 7) == value + 140;
40 +
        assert weighted.sum(7, 6, 5, 4, 3, 2, 1) == value + 84;
41 +
    }
42 +
    return 0;
43 +
}