Fix literal-first conditional inference

60335cc12b5014ef3ad82606b8ace7cb15810c90f0df8432070328a73c0b4d12
Conditional-expression resolution inferred the then branch first and
forced the else branch to that provisional type. An unsuffixed integer
in the first branch therefore selected the pseudo-type `<int>` and
rejected a concrete integer expression in the other branch.

Infer both branches independently, choose an assignable common
direction, and record the required coercion on the branch that needs
it.
Alexis Sellier committed ago 1 parent 8301d68e
lib/std/lang/resolver.rad +13 -1
3980 3980
fn resolveCondExpr(self: *mut Resolver, node: *ast::Node, cond: ast::CondExpr) -> Type
3981 3981
    throws (ResolveError)
3982 3982
{
3983 3983
    try checkBoolean(self, cond.condition);
3984 3984
    let thenTy = try infer(self, cond.thenExpr);
3985 -
    let _ = try checkAssignable(self, cond.elseExpr, thenTy);
3985 +
    let elseTy = try infer(self, cond.elseExpr);
3986 +
3987 +
    // Either branch may supply the concrete type for an otherwise context-
3988 +
    // dependent expression, such as an unsuffixed integer or `nil`.
3989 +
    if let coercion = isAssignable(self, thenTy, elseTy, cond.elseExpr) {
3990 +
        setNodeCoercion(self, cond.elseExpr, coercion);
3991 +
        return setNodeType(self, node, thenTy);
3992 +
    }
3993 +
    if let coercion = isAssignable(self, elseTy, thenTy, cond.thenExpr) {
3994 +
        setNodeCoercion(self, cond.thenExpr, coercion);
3995 +
        return setNodeType(self, node, elseTy);
3996 +
    }
3997 +
    try expectAssignable(self, thenTy, elseTy, cond.elseExpr);
3986 3998
3987 3999
    return setNodeType(self, node, thenTy);
3988 4000
}
3989 4001
3990 4002
/// Analyze a pattern match structure (used by if-let, while-let).
test/tests/cond.expr.literal-first.rad added +16 -0
1 +
//! returns: 0
2 +
//! A conditional expression must infer the concrete type from either branch.
3 +
4 +
fn choose(flag: bool, value: u32) -> u32 {
5 +
    return 1 if flag else value;
6 +
}
7 +
8 +
@default fn main() -> i32 {
9 +
    if choose(true, 7) <> 1 {
10 +
        return 1;
11 +
    }
12 +
    if choose(false, 7) <> 7 {
13 +
        return 2;
14 +
    }
15 +
    return 0;
16 +
}