authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-03 15:06:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-03 15:06:34-07:00
log7f589c0cab105a79ff6d71233538dca8a39f8152
treecd3a1eb6b05578bbddbe76feab6ffb63d76f5610
parent9ccd0ba9611d7828f42bffca919c7ad3177cbbe1

support maybe destructuring into a pointer variable


6 files changed, 156 insertions(+), 34 deletions(-)

doc/langref.md+1-1
...@@ -93,7 +93,7 @@ IfExpression = IfVarExpression | IfBoolExpression...@@ -93,7 +93,7 @@ IfExpression = IfVarExpression | IfBoolExpression
9393
94IfBoolExpression = "if" "(" Expression ")" Expression option(Else)94IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
9595
96IfVarExpression = "if" "(" ("const" | "var") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)96IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
9797
98Else = "else" Expression98Else = "else" Expression
9999
src/all_types.hpp+2-1
...@@ -479,6 +479,7 @@ struct AstNodeIfVarExpr {...@@ -479,6 +479,7 @@ struct AstNodeIfVarExpr {
479 AstNodeVariableDeclaration var_decl;479 AstNodeVariableDeclaration var_decl;
480 AstNode *then_block;480 AstNode *then_block;
481 AstNode *else_node; // null, block node, or other if expr node481 AstNode *else_node; // null, block node, or other if expr node
482 bool var_is_ptr;
482483
483 // populated by semantic analyzer484 // populated by semantic analyzer
484 TypeTableEntry *type;485 TypeTableEntry *type;
...@@ -502,6 +503,7 @@ struct AstNodeForExpr {...@@ -502,6 +503,7 @@ struct AstNodeForExpr {
502 AstNode *elem_node; // always a symbol503 AstNode *elem_node; // always a symbol
503 AstNode *index_node; // always a symbol, might be null504 AstNode *index_node; // always a symbol, might be null
504 AstNode *body;505 AstNode *body;
506 bool elem_is_ptr;
505507
506 // populated by semantic analyzer508 // populated by semantic analyzer
507 bool contains_break;509 bool contains_break;
...@@ -509,7 +511,6 @@ struct AstNodeForExpr {...@@ -509,7 +511,6 @@ struct AstNodeForExpr {
509 Expr resolved_expr;511 Expr resolved_expr;
510 VariableTableEntry *elem_var;512 VariableTableEntry *elem_var;
511 VariableTableEntry *index_var;513 VariableTableEntry *index_var;
512 bool elem_is_ptr;
513};514};
514515
515struct AstNodeSwitchExpr {516struct AstNodeSwitchExpr {
src/analyze.cpp+12-6
...@@ -41,7 +41,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node);...@@ -41,7 +41,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node);
41static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,41static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
42 BlockContext *context, AstNode *source_node,42 BlockContext *context, AstNode *source_node,
43 AstNodeVariableDeclaration *variable_declaration,43 AstNodeVariableDeclaration *variable_declaration,
44 bool expr_is_maybe, AstNode *decl_node);44 bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr);
45static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node);45static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node);
46static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);46static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
4747
...@@ -1582,7 +1582,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)...@@ -1582,7 +1582,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
1582 {1582 {
1583 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;1583 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
1584 VariableTableEntry *var = analyze_variable_declaration_raw(g, import, import->block_context,1584 VariableTableEntry *var = analyze_variable_declaration_raw(g, import, import->block_context,
1585 node, variable_declaration, false, node);1585 node, variable_declaration, false, node, false);
15861586
1587 g->global_vars.append(var);1587 g->global_vars.append(var);
1588 break;1588 break;
...@@ -3503,7 +3503,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i...@@ -3503,7 +3503,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i
3503static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,3503static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
3504 BlockContext *context, AstNode *source_node,3504 BlockContext *context, AstNode *source_node,
3505 AstNodeVariableDeclaration *variable_declaration,3505 AstNodeVariableDeclaration *variable_declaration,
3506 bool expr_is_maybe, AstNode *decl_node)3506 bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr)
3507{3507{
3508 bool is_const = variable_declaration->is_const;3508 bool is_const = variable_declaration->is_const;
3509 bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);3509 bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
...@@ -3528,7 +3528,12 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -3528,7 +3528,12 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
3528 // ignore the poison value3528 // ignore the poison value
3529 } else if (expr_is_maybe) {3529 } else if (expr_is_maybe) {
3530 if (implicit_type->id == TypeTableEntryIdMaybe) {3530 if (implicit_type->id == TypeTableEntryIdMaybe) {
3531 implicit_type = implicit_type->data.maybe.child_type;3531 if (var_is_ptr) {
3532 // TODO if the expression is constant, can't get pointer to it
3533 implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false);
3534 } else {
3535 implicit_type = implicit_type->data.maybe.child_type;
3536 }
3532 } else {3537 } else {
3533 add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));3538 add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));
3534 implicit_type = g->builtin_types.entry_invalid;3539 implicit_type = g->builtin_types.entry_invalid;
...@@ -3575,7 +3580,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE...@@ -3575,7 +3580,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
3575 BlockContext *context, TypeTableEntry *expected_type, AstNode *node)3580 BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
3576{3581{
3577 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;3582 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
3578 return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false, nullptr);3583 return analyze_variable_declaration_raw(g, import, context, node, variable_declaration,
3584 false, nullptr, false);
3579}3585}
35803586
3581static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,3587static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
...@@ -3945,7 +3951,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,...@@ -3945,7 +3951,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
3945 BlockContext *child_context = new_block_context(node, parent_context);3951 BlockContext *child_context = new_block_context(node, parent_context);
39463952
3947 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,3953 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
3948 nullptr);3954 nullptr, node->data.if_var_expr.var_is_ptr);
3949 VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;3955 VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
3950 if (var->type->id == TypeTableEntryIdInvalid) {3956 if (var->type->id == TypeTableEntryIdInvalid) {
3951 return g->builtin_types.entry_invalid;3957 return g->builtin_types.entry_invalid;
src/codegen.cpp+94-23
...@@ -212,7 +212,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);...@@ -212,7 +212,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
212static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);212static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
213static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);213static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
214static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,214static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
215 bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type);215 bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type, bool var_is_ptr);
216static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,216static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
217 LLVMValueRef target_ref, LLVMValueRef value,217 LLVMValueRef target_ref, LLVMValueRef value,
218 TypeTableEntry *op1_type, TypeTableEntry *op2_type);218 TypeTableEntry *op1_type, TypeTableEntry *op2_type);
...@@ -2102,21 +2102,32 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {...@@ -2102,21 +2102,32 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
2102 }2102 }
2103}2103}
21042104
2105static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
2106 BlockContext *block_context = var->block_context;
2107 AstNode *source_node = var->decl_node;
2108 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
2109 block_context->di_scope);
2110 LLVMZigInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
2111 LLVMGetInsertBlock(g->builder));
2112}
2113
2105static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {2114static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
2106 assert(node->type == NodeTypeIfVarExpr);2115 assert(node->type == NodeTypeIfVarExpr);
2107 assert(node->data.if_var_expr.var_decl.expr);2116 assert(node->data.if_var_expr.var_decl.expr);
21082117
2109 LLVMValueRef init_val;2118 AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
2110 TypeTableEntry *expr_type;2119 VariableTableEntry *variable = var_decl->variable;
2111 gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val, &expr_type);
21122120
2113 // test if value is the maybe state2121 // test if value is the maybe state
2114 assert(expr_type->id == TypeTableEntryIdMaybe);2122 TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
2115 TypeTableEntry *child_type = expr_type->data.maybe.child_type;2123 TypeTableEntry *child_type = expr_type->data.maybe.child_type;
2124
2125 LLVMValueRef init_val = gen_expr(g, var_decl->expr);
2126
2116 LLVMValueRef cond_value;2127 LLVMValueRef cond_value;
2117 if (child_type->id == TypeTableEntryIdPointer ||2128 bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
2118 child_type->id == TypeTableEntryIdFn)2129 if (maybe_is_ptr) {
2119 {2130 set_debug_source_node(g, node);
2120 cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");2131 cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
2121 } else {2132 } else {
2122 set_debug_source_node(g, node);2133 set_debug_source_node(g, node);
...@@ -2124,11 +2135,80 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {...@@ -2124,11 +2135,80 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
2124 cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");2135 cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
2125 }2136 }
21262137
2127 LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value,2138 AstNode *then_node = node->data.if_var_expr.then_block;
2128 node->data.if_var_expr.then_block,2139 AstNode *else_node = node->data.if_var_expr.else_node;
2129 node->data.if_var_expr.else_node);2140
2141 TypeTableEntry *then_type = get_expr_type(then_node);
2142 TypeTableEntry *else_type = get_expr_type(else_node);
2143
2144 bool use_then_value = type_has_bits(then_type);
2145 bool use_else_value = type_has_bits(else_type);
2146
2147 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen");
2148 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse");
2149
2150 LLVMBasicBlockRef endif_block;
2151 bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
2152 bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
2153 if (then_endif_reachable || else_endif_reachable) {
2154 endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf");
2155 }
2156
2157 set_debug_source_node(g, node);
2158 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
2159
2160 LLVMPositionBuilderAtEnd(g->builder, then_block);
2161 if (node->data.if_var_expr.var_is_ptr) {
2162 LLVMValueRef payload_ptr;
2163 if (maybe_is_ptr) {
2164 zig_panic("TODO");
2165 } else {
2166 payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
2167 }
2168 LLVMBuildStore(g->builder, payload_ptr, variable->value_ref);
2169 } else {
2170 LLVMValueRef payload_val;
2171 if (maybe_is_ptr) {
2172 payload_val = init_val;
2173 } else {
2174 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
2175 payload_val = get_handle_value(g, node, payload_ptr, child_type);
2176 }
2177 gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val,
2178 variable->type, child_type);
2179 }
2180 gen_var_debug_decl(g, variable);
2181
2182 LLVMValueRef then_expr_result = gen_expr(g, then_node);
2183 if (then_endif_reachable) {
2184 LLVMBuildBr(g->builder, endif_block);
2185 }
2186 LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
2187
21302188
2131 return return_value;2189 LLVMPositionBuilderAtEnd(g->builder, else_block);
2190 LLVMValueRef else_expr_result = gen_expr(g, else_node);
2191 if (else_endif_reachable) {
2192 LLVMBuildBr(g->builder, endif_block);
2193 }
2194 LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
2195
2196 if (then_endif_reachable || else_endif_reachable) {
2197 LLVMPositionBuilderAtEnd(g->builder, endif_block);
2198 if (use_then_value && use_else_value) {
2199 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
2200 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
2201 LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
2202 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
2203 return phi;
2204 } else if (use_then_value) {
2205 return then_expr_result;
2206 } else if (use_else_value) {
2207 return else_expr_result;
2208 }
2209 }
2210
2211 return nullptr;
2132}2212}
21332213
2134static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {2214static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
...@@ -2456,15 +2536,6 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -2456,15 +2536,6 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
2456 return nullptr;2536 return nullptr;
2457}2537}
24582538
2459static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
2460 BlockContext *block_context = var->block_context;
2461 AstNode *source_node = var->decl_node;
2462 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
2463 block_context->di_scope);
2464 LLVMZigInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
2465 LLVMGetInsertBlock(g->builder));
2466}
2467
2468static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {2539static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
2469 assert(node->type == NodeTypeForExpr);2540 assert(node->type == NodeTypeForExpr);
2470 assert(node->data.for_expr.array_expr);2541 assert(node->data.for_expr.array_expr);
...@@ -2564,7 +2635,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {...@@ -2564,7 +2635,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
2564}2635}
25652636
2566static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,2637static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
2567 bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type)2638 bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
2568{2639{
2569 VariableTableEntry *variable = var_decl->variable;2640 VariableTableEntry *variable = var_decl->variable;
25702641
...@@ -2683,7 +2754,7 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {...@@ -2683,7 +2754,7 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
26832754
2684 LLVMValueRef init_val;2755 LLVMValueRef init_val;
2685 TypeTableEntry *init_val_type;2756 TypeTableEntry *init_val_type;
2686 return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type);2757 return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false);
2687}2758}
26882759
2689static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {2760static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
src/parser.cpp+14-3
...@@ -1755,7 +1755,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator...@@ -1755,7 +1755,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator
1755/*1755/*
1756IfExpression : IfVarExpression | IfBoolExpression1756IfExpression : IfVarExpression | IfBoolExpression
1757IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)1757IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
1758IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)1758IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
1759*/1759*/
1760static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {1760static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
1761 Token *if_tok = &pc->tokens->at(*token_index);1761 Token *if_tok = &pc->tokens->at(*token_index);
...@@ -1776,8 +1776,19 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda...@@ -1776,8 +1776,19 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
1776 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);1776 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
1777 *token_index += 1;1777 *token_index += 1;
17781778
1779 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);1779 Token *star_or_symbol = &pc->tokens->at(*token_index);
1780 ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol);1780 if (star_or_symbol->id == TokenIdStar) {
1781 *token_index += 1;
1782 node->data.if_var_expr.var_is_ptr = true;
1783 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
1784 ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol);
1785 } else if (star_or_symbol->id == TokenIdSymbol) {
1786 *token_index += 1;
1787 ast_buf_from_token(pc, star_or_symbol, &node->data.if_var_expr.var_decl.symbol);
1788 } else {
1789 ast_invalid_token_error(pc, star_or_symbol);
1790 }
1791
17811792
1782 Token *eq_or_colon = &pc->tokens->at(*token_index);1793 Token *eq_or_colon = &pc->tokens->at(*token_index);
1783 if (eq_or_colon->id == TokenIdMaybeAssign) {1794 if (eq_or_colon->id == TokenIdMaybeAssign) {
test/self_hosted.zig+33
...@@ -1409,3 +1409,36 @@ fn string_escapes() {...@@ -1409,3 +1409,36 @@ fn string_escapes() {
1409 assert(str.eql("\\", "\x5c"));1409 assert(str.eql("\\", "\x5c"));
1410 assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69"));1410 assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69"));
1411}1411}
1412
1413#attribute("test")
1414fn if_var_maybe_pointer() {
1415 assert(should_be_a_plus_1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);
1416}
1417#static_eval_enable(false)
1418fn should_be_a_plus_1(p: Particle) -> u64 {
1419 var maybe_particle: ?Particle = p;
1420 if (const *particle ?= maybe_particle) {
1421 particle.a += 1;
1422 }
1423 if (const particle ?= maybe_particle) {
1424 return particle.a;
1425 }
1426 return 0;
1427}
1428struct Particle {
1429 a: u64,
1430 b: u64,
1431 c: u64,
1432 d: u64,
1433}
1434
1435#attribute("test")
1436fn assign_to_if_var_ptr() {
1437 var maybe_bool: ?bool = true;
1438
1439 if (const *b ?= maybe_bool) {
1440 *b = false;
1441 }
1442
1443 assert(??maybe_bool == false);
1444}