Resolve coerced throw types

5579ed175341f1c57cabd28ce6dbad6c4a1908820bcd4487e9673581d336f70a
Throw resolution recorded the error tag from the expression's
pre-coercion type. Throwing an unsuffixed integer from a `throws(u8)`
function therefore emitted the tag for `Int` while typed `u8` catch
dispatch expected the `u8` tag and missed the handler.

Select the throw's resolved coerced type when registering and lowering
its error payload, while retaining the original type when no coercion
exists.
Alexis Sellier committed ago 1 parent c08a46ca
lib/std/lang/lower.rad +2 -1
5683 5683
5684 5684
/// Lower a throw statement.
5685 5685
fn lowerThrowStmt(self: *mut FnLowerer, expr: *ast::Node) throws (LowerError) {
5686 5686
    assert self.fnType.throwList.len > 0;
5687 5687
5688 -
    let errType = try typeOf(self, expr);
5688 +
    let errType = *self.fnType.throwList[0] if self.fnType.throwList.len == 1
5689 +
        else try typeOf(self, expr);
5689 5690
    let tag = getOrAssignErrorTag(self.low, errType) as i64;
5690 5691
    let errVal = try lowerExpr(self, expr);
5691 5692
    let resultVal = try buildResult(self, tag, errVal, errType);
5692 5693
5693 5694
    try emitRetVal(self, resultVal);
test/tests/error.throw.coercion.rad added +16 -0
1 +
//! returns: 0
2 +
//! A coerced error value must use the declared error type's dispatch tag.
3 +
4 +
fn fail() throws (u8) {
5 +
    throw 7;
6 +
}
7 +
8 +
@default fn main() -> i32 {
9 +
    let mut caught = false;
10 +
    try fail() catch value as u8 {
11 +
        assert value == 7;
12 +
        set caught = true;
13 +
    };
14 +
    assert caught;
15 +
    return 0;
16 +
}