Fix literal-first conditional inference

67b3d2590e8f6257e7f3dae09b9bf6f1a242ff5e8ff7aa0cc49003ab8baae884
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 b9457de1
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 +
}