diff options
Diffstat (limited to 'src/analyze.cpp')
| -rw-r--r-- | src/analyze.cpp | 136 |
1 files changed, 105 insertions, 31 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 700a3e7a85..02b1c3010e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2159,6 +2159,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val; if (field_val->ok) { const_val->data.x_struct.fields[field_index] = field_val; + const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var; } else { const_val->ok = false; } @@ -2197,6 +2198,8 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val; if (elem_const_val->ok) { const_val->data.x_array.fields[i] = elem_const_val; + const_val->depends_on_compile_var = const_val->depends_on_compile_var || + elem_const_val->depends_on_compile_var; } else { const_val->ok = false; } @@ -2431,9 +2434,12 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, return g->builtin_types.entry_pure_error; } -static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) { +static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value, + bool depends_on_compile_var) +{ Expr *expr = get_resolved_expr(node); expr->const_val.ok = true; + expr->const_val.depends_on_compile_var = depends_on_compile_var; expr->const_val.data.x_bool = value; return g->builtin_types.entry_bool; } @@ -2817,7 +2823,8 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im zig_unreachable(); } - return resolve_expr_const_val_as_bool(g, node, answer); + bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; + return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); } static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, @@ -2844,7 +2851,8 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i } bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool); - return resolve_expr_const_val_as_bool(g, node, answer); + bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; + return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); } static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, @@ -3001,6 +3009,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, } ConstExprValue *const_val = &get_resolved_expr(node)->const_val; const_val->ok = true; + const_val->depends_on_compile_var = op1_val->depends_on_compile_var || + op2_val->depends_on_compile_var; ConstExprValue *all_fields = allocate<ConstExprValue>(2); ConstExprValue *ptr_field = &all_fields[0]; @@ -3444,51 +3454,111 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor return g->builtin_types.entry_unreachable; } -static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import, BlockContext *context, - TypeTableEntry *expected_type, AstNode *then_block, AstNode *else_node, AstNode *parent_node) +static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *context, + TypeTableEntry *expected_type, AstNode *node, + AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val) { - TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, then_block); - - TypeTableEntry *else_type; - if (else_node) { - else_type = analyze_expression(g, import, context, expected_type, else_node); - } else { - else_type = resolve_type_compatibility(g, import, context, parent_node, expected_type, - g->builtin_types.entry_void); + if (!*else_node) { + *else_node = create_ast_void_node(g, import, node); + normalize_parent_ptrs(node); } + TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, *then_node); + TypeTableEntry *else_type = analyze_expression(g, import, context, expected_type, *else_node); + if (then_type->id == TypeTableEntryIdInvalid || else_type->id == TypeTableEntryIdInvalid) { + return g->builtin_types.entry_invalid; + } + + TypeTableEntry *result_type; if (expected_type) { - return (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type; + result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type; } else { - AstNode *op_nodes[] = {then_block, else_node}; + AstNode *op_nodes[] = {*then_node, *else_node}; TypeTableEntry *op_types[] = {then_type, else_type}; - return resolve_peer_type_compatibility(g, import, context, parent_node, op_nodes, op_types, 2); + result_type = resolve_peer_type_compatibility(g, import, context, node, op_nodes, op_types, 2); + } + + if (!cond_is_const) { + return result_type; } + + ConstExprValue *other_const_val; + if (cond_bool_val) { + other_const_val = &get_resolved_expr(*then_node)->const_val; + } else { + other_const_val = &get_resolved_expr(*else_node)->const_val; + } + if (!other_const_val->ok) { + return result_type; + } + + ConstExprValue *const_val = &get_resolved_expr(node)->const_val; + *const_val = *other_const_val; + return result_type; } static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { - analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_bool_expr.condition); + AstNode **cond = &node->data.if_bool_expr.condition; + TypeTableEntry *cond_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *cond); + + if (cond_type->id == TypeTableEntryIdInvalid) { + return cond_type; + } - return analyze_if_then_else(g, import, context, expected_type, - node->data.if_bool_expr.then_block, - node->data.if_bool_expr.else_node, - node); + ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; + if (cond_val->ok && !cond_val->depends_on_compile_var) { + const char *str_val = cond_val->data.x_bool ? "true" : "false"; + add_node_error(g, first_executing_node(*cond), + buf_sprintf("condition is always %s; unnecessary if statement", str_val)); + } + + bool cond_is_const = cond_val->ok; + bool cond_bool_val = cond_val->data.x_bool; + + AstNode **then_node = &node->data.if_bool_expr.then_block; + AstNode **else_node = &node->data.if_bool_expr.else_node; + + return analyze_if(g, import, context, expected_type, node, + then_node, else_node, cond_is_const, cond_bool_val); } -static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node) { assert(node->type == NodeTypeIfVarExpr); - BlockContext *child_context = new_block_context(node, context); + BlockContext *child_context = new_block_context(node, parent_context); analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true); + VariableTableEntry *var = node->data.if_var_expr.var_decl.variable; + if (var->type->id == TypeTableEntryIdInvalid) { + return g->builtin_types.entry_invalid; + } + AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr; + ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val; + bool cond_is_const = var_const_val->ok; + bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false; + + + AstNode **then_node = &node->data.if_var_expr.then_block; + AstNode **else_node = &node->data.if_var_expr.else_node; - return analyze_if_then_else(g, import, child_context, expected_type, - node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node); + return analyze_if(g, import, child_context, expected_type, + node, then_node, else_node, cond_is_const, cond_bool_val); +} + +static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { + assert(int_type->id == TypeTableEntryIdInt); + + for (int i = 0; i < CIntTypeCount; i += 1) { + if (int_type == g->builtin_types.entry_c_int[i]) { + return true; + } + } + return false; } static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, @@ -3504,6 +3574,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor } else if (type_entry->id == TypeTableEntryIdInt) { ConstExprValue *const_val = &get_resolved_expr(node)->const_val; const_val->ok = true; + const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); if (is_max) { if (type_entry->data.integral.is_signed) { int64_t val; @@ -3558,7 +3629,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor zig_panic("TODO analyze_min_max_value float"); return type_entry; } else if (type_entry->id == TypeTableEntryIdBool) { - return resolve_expr_const_val_as_bool(g, node, is_max); + return resolve_expr_const_val_as_bool(g, node, is_max, false); } else { add_node_error(g, node, buf_sprintf(err_format, buf_ptr(&type_entry->name))); @@ -3573,6 +3644,8 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex if (!other_val->ok) { return; } + const_val->depends_on_compile_var = other_val->depends_on_compile_var; + assert(other_val != const_val); switch (node->data.fn_call_expr.cast_op) { case CastOpNoCast: @@ -4132,11 +4205,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry const_val->depends_on_compile_var = true; if (buf_eql_str(&var_name, "is_big_endian")) { - return resolve_expr_const_val_as_bool(g, node, g->is_big_endian); + return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true); } else if (buf_eql_str(&var_name, "is_release")) { - return resolve_expr_const_val_as_bool(g, node, g->is_release_build); + return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true); } else if (buf_eql_str(&var_name, "is_test")) { - return resolve_expr_const_val_as_bool(g, node, g->is_test_build); + return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true); } else { add_node_error(g, *str_node, buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name))); @@ -4353,7 +4426,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo } bool answer = !target_const_val->data.x_bool; - return resolve_expr_const_val_as_bool(g, node, answer); + return resolve_expr_const_val_as_bool(g, node, answer, target_const_val->depends_on_compile_var); } case PrefixOpBinNot: { @@ -4390,6 +4463,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo } ConstExprValue *const_val = &get_resolved_expr(node)->const_val; const_val->ok = true; + const_val->depends_on_compile_var = target_const_val->depends_on_compile_var; bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum); return expr_type; } else { @@ -4880,7 +4954,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, node->data.char_literal.value); break; case NodeTypeBoolLiteral: - return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value); + return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value, false); break; case NodeTypeNullLiteral: return_type = analyze_null_literal_expr(g, import, context, expected_type, node); |
