Commit 5490f907fe

Andrew Kelley <superjoe30@gmail.com>
2016-02-04 23:50:06
switch statements resolve peer compatibility
1 parent fcbeadd
doc/langref.md
@@ -79,7 +79,7 @@ BlockExpression = IfExpression | Block | WhileExpression | ForExpression | Switc
 
 SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
 
-SwitchProng = (list(SwitchItem, ",") | "else") option(":" "(" "Symbol" ")") "=>" Expression ","
+SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Expression ","
 
 SwitchItem = Expression | (Expression "..." Expression)
 
src/analyze.cpp
@@ -4479,9 +4479,9 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
     AstNode *expr_node = node->data.switch_expr.expr;
     TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, expr_node);
 
-    if (expected_type == nullptr) {
-        zig_panic("TODO resolve peer compatibility of switch prongs");
-    }
+    int prong_count = node->data.switch_expr.prongs.length;
+    AstNode **peer_nodes = allocate<AstNode*>(prong_count);
+    TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
 
     if (expr_type->id == TypeTableEntryIdInvalid) {
         return expr_type;
@@ -4491,7 +4491,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
         return g->builtin_types.entry_invalid;
     } else {
         AstNode *else_prong = nullptr;
-        for (int prong_i = 0; prong_i < node->data.switch_expr.prongs.length; prong_i += 1) {
+        for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
             AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
 
             TypeTableEntry *var_type;
@@ -4528,11 +4528,12 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
                         var_type, true);
             }
 
-            analyze_expression(g, import, child_context, expected_type,
+            peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
                     prong_node->data.switch_prong.expr);
+            peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
         }
     }
-    return expected_type;
+    return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);
 }
 
 static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
src/parser.cpp
@@ -1834,7 +1834,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
 
 /*
 SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"
-SwitchProng : (list(SwitchItem, ",") | "else") option("," "(" "Symbol" ")") "=>" Expression ","
+SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Expression ","
 SwitchItem : Expression | (Expression "..." Expression)
 */
 static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool mandatory) {
@@ -1895,15 +1895,15 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
             break;
         }
 
-        Token *arrow_or_colon = &pc->tokens->at(*token_index);
-        if (arrow_or_colon->id == TokenIdColon) {
+        ast_eat_token(pc, token_index, TokenIdFatArrow);
+
+        Token *maybe_bar = &pc->tokens->at(*token_index);
+        if (maybe_bar->id == TokenIdBinOr) {
             *token_index += 1;
-            ast_eat_token(pc, token_index, TokenIdLParen);
             prong_node->data.switch_prong.var_symbol = ast_parse_symbol(pc, token_index);
-            ast_eat_token(pc, token_index, TokenIdRParen);
+            ast_eat_token(pc, token_index, TokenIdBinOr);
         }
 
-        ast_eat_token(pc, token_index, TokenIdFatArrow);
         prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true);
         ast_eat_token(pc, token_index, TokenIdComma);
 
test/self_hosted.zig
@@ -105,3 +105,27 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {
     if (i32(t) != i32(1)) unreachable{}
     if (i32(f) != i32(0)) unreachable{}
 }
+
+
+#attribute("test")
+fn switch_on_enum() {
+    const fruit = Fruit.Orange;
+    switch (fruit) {
+        Fruit.Apple => unreachable{},
+        Fruit.Orange => {},
+        Fruit.Banana => unreachable{},
+    }
+    non_const_switch_on_enum(fruit);
+}
+enum Fruit {
+    Apple,
+    Orange,
+    Banana,
+}
+fn non_const_switch_on_enum(fruit: Fruit) {
+    switch (fruit) {
+        Fruit.Apple => unreachable{},
+        Fruit.Orange => {},
+        Fruit.Banana => unreachable{},
+    }
+}