switch statements resolve peer compatibility

This commit is contained in:
Andrew Kelley 2016-02-04 15:50:06 -07:00
parent fcbeaddbb2
commit 5490f907fe
4 changed files with 38 additions and 13 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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);

View File

@ -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{},
}
}