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.
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 | + | } |