diff --git a/CMakeLists.txt b/CMakeLists.txt index 902831fde..76eef8558 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/codegen.cpp" "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp" - "${CMAKE_SOURCE_DIR}/src/eval.cpp" "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp" diff --git a/src/all_types.hpp b/src/all_types.hpp index 922bf363b..df6a5a211 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -848,6 +848,11 @@ struct TypeTableEntryEnum { bool complete; }; +struct TypeTableEntryEnumTag { + TypeTableEntry *enum_type; + TypeTableEntry *int_type; +}; + struct TypeTableEntryUnion { AstNode *decl_node; bool is_extern; @@ -914,6 +919,7 @@ enum TypeTableEntryId { TypeTableEntryIdErrorUnion, TypeTableEntryIdPureError, TypeTableEntryIdEnum, + TypeTableEntryIdEnumTag, TypeTableEntryIdUnion, TypeTableEntryIdFn, TypeTableEntryIdTypeDecl, @@ -940,6 +946,7 @@ struct TypeTableEntry { TypeTableEntryMaybe maybe; TypeTableEntryError error; TypeTableEntryEnum enumeration; + TypeTableEntryEnumTag enum_tag; TypeTableEntryUnion unionation; TypeTableEntryFn fn; TypeTableEntryTypeDecl type_decl; @@ -1452,6 +1459,7 @@ enum IrInstructionId { IrInstructionIdErrWrapPayload, IrInstructionIdFnProto, IrInstructionIdTestComptime, + IrInstructionIdInitEnum, }; struct IrInstruction { @@ -2078,6 +2086,15 @@ struct IrInstructionTestComptime { IrInstruction *value; }; +struct IrInstructionInitEnum { + IrInstruction base; + + TypeTableEntry *enum_type; + TypeEnumField *field; + IrInstruction *init_value; + LLVMValueRef tmp_ptr; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/analyze.cpp b/src/analyze.cpp index c7f698942..221868deb 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -9,7 +9,6 @@ #include "ast_render.hpp" #include "config.h" #include "error.hpp" -#include "eval.hpp" #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" @@ -252,6 +251,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: return true; } zig_unreachable(); @@ -677,14 +677,8 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * entry->type_ref = child_type->type_ref; entry->di_type = child_type->di_type; entry->zero_bits = child_type->zero_bits; - entry->data.type_decl.child_type = child_type; - - if (child_type->id == TypeTableEntryIdTypeDecl) { - entry->data.type_decl.canonical_type = child_type->data.type_decl.canonical_type; - } else { - entry->data.type_decl.canonical_type = child_type; - } + entry->data.type_decl.canonical_type = get_underlying_type(child_type); return entry; } @@ -985,6 +979,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdEnumTag: break; } FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; @@ -1033,12 +1028,28 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdEnumTag: break; } return get_fn_type(g, &fn_type_id); } +static TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) { + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag); + + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name)); + + entry->data.enum_tag.enum_type = enum_type; + entry->data.enum_tag.int_type = int_type; + entry->type_ref = int_type->type_ref; + entry->di_type = int_type->di_type; + entry->zero_bits = int_type->zero_bits; + + return entry; +} + static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // if you change this logic you likely must also change similar logic in parseh.cpp assert(enum_type->id == TypeTableEntryIdEnum); @@ -1134,7 +1145,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { enum_type->data.enumeration.gen_field_count = gen_field_index; enum_type->data.enumeration.union_type = biggest_union_member; - TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); + TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); + TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); enum_type->data.enumeration.tag_type = tag_type_entry; if (biggest_union_member) { @@ -1686,6 +1698,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: return type_entry; } zig_unreachable(); @@ -1890,6 +1903,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: case TypeTableEntryIdFn: + case TypeTableEntryIdEnumTag: return true; case TypeTableEntryIdTypeDecl: @@ -2110,6 +2124,7 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: return false; } zig_unreachable(); @@ -2159,6 +2174,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdVar: + case TypeTableEntryIdEnumTag: zig_unreachable(); } } @@ -2509,6 +2525,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { case TypeTableEntryIdPointer: case TypeTableEntryIdPureError: case TypeTableEntryIdFn: + case TypeTableEntryIdEnumTag: return false; case TypeTableEntryIdArray: case TypeTableEntryIdStruct: @@ -2650,6 +2667,8 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) return hash_ptr(const_val->data.x_import); case TypeTableEntryIdBlock: return hash_ptr(const_val->data.x_block); + case TypeTableEntryIdEnumTag: + return 983996406 + hash_const_val(type->data.enum_tag.int_type, const_val); case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: @@ -2794,16 +2813,18 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) case TypeTableEntryIdInt: case TypeTableEntryIdFloat: case TypeTableEntryIdPointer: + case TypeTableEntryIdEnumTag: return type_entry; } zig_unreachable(); } bool type_requires_comptime(TypeTableEntry *type_entry) { - switch (type_entry->id) { + switch (get_underlying_type(type_entry)->id) { case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: + case TypeTableEntryIdTypeDecl: zig_unreachable(); case TypeTableEntryIdNumLitFloat: case TypeTableEntryIdNumLitInt: @@ -2820,7 +2841,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { case TypeTableEntryIdUnion: case TypeTableEntryIdMaybe: case TypeTableEntryIdErrorUnion: - case TypeTableEntryIdTypeDecl: case TypeTableEntryIdEnum: case TypeTableEntryIdPureError: case TypeTableEntryIdFn: @@ -2828,6 +2848,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { case TypeTableEntryIdInt: case TypeTableEntryIdFloat: case TypeTableEntryIdPointer: + case TypeTableEntryIdEnumTag: return false; } zig_unreachable(); @@ -2933,3 +2954,154 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) { return var->is_comptime->static_value.data.x_bool; } +bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { + switch (type_entry->id) { + case TypeTableEntryIdEnum: + { + ConstEnumValue *enum1 = &a->data.x_enum; + ConstEnumValue *enum2 = &b->data.x_enum; + if (enum1->tag == enum2->tag) { + TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; + if (type_has_bits(enum_field->type_entry)) { + zig_panic("TODO const expr analyze enum special value for equality"); + } else { + return true; + } + } + return false; + } + case TypeTableEntryIdMetaType: + return a->data.x_type == b->data.x_type; + case TypeTableEntryIdVoid: + return true; + case TypeTableEntryIdPureError: + return a->data.x_pure_err == b->data.x_pure_err; + case TypeTableEntryIdFn: + return a->data.x_fn == b->data.x_fn; + case TypeTableEntryIdBool: + return a->data.x_bool == b->data.x_bool; + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); + case TypeTableEntryIdEnumTag: + return const_values_equal(a, b, type_entry->data.enum_tag.int_type); + case TypeTableEntryIdPointer: + zig_panic("TODO"); + case TypeTableEntryIdArray: + zig_panic("TODO"); + case TypeTableEntryIdStruct: + zig_panic("TODO"); + case TypeTableEntryIdUnion: + zig_panic("TODO"); + case TypeTableEntryIdUndefLit: + zig_panic("TODO"); + case TypeTableEntryIdNullLit: + zig_panic("TODO"); + case TypeTableEntryIdMaybe: + zig_panic("TODO"); + case TypeTableEntryIdErrorUnion: + zig_panic("TODO"); + case TypeTableEntryIdTypeDecl: + zig_panic("TODO"); + case TypeTableEntryIdNamespace: + zig_panic("TODO"); + case TypeTableEntryIdBlock: + zig_panic("TODO"); + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdInvalid: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdVar: + zig_unreachable(); + } + zig_unreachable(); +} + +static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { + assert(int_type->id == TypeTableEntryIdInt); + + for (size_t i = 0; i < CIntTypeCount; i += 1) { + if (int_type == g->builtin_types.entry_c_int[i]) { + return true; + } + } + return false; +} + +static uint64_t max_unsigned_val(TypeTableEntry *type_entry) { + assert(type_entry->id == TypeTableEntryIdInt); + if (type_entry->data.integral.bit_count == 64) { + return UINT64_MAX; + } else if (type_entry->data.integral.bit_count == 32) { + return UINT32_MAX; + } else if (type_entry->data.integral.bit_count == 16) { + return UINT16_MAX; + } else if (type_entry->data.integral.bit_count == 8) { + return UINT8_MAX; + } else { + zig_unreachable(); + } +} + +static int64_t max_signed_val(TypeTableEntry *type_entry) { + assert(type_entry->id == TypeTableEntryIdInt); + if (type_entry->data.integral.bit_count == 64) { + return INT64_MAX; + } else if (type_entry->data.integral.bit_count == 32) { + return INT32_MAX; + } else if (type_entry->data.integral.bit_count == 16) { + return INT16_MAX; + } else if (type_entry->data.integral.bit_count == 8) { + return INT8_MAX; + } else { + zig_unreachable(); + } +} + +static int64_t min_signed_val(TypeTableEntry *type_entry) { + assert(type_entry->id == TypeTableEntryIdInt); + if (type_entry->data.integral.bit_count == 64) { + return INT64_MIN; + } else if (type_entry->data.integral.bit_count == 32) { + return INT32_MIN; + } else if (type_entry->data.integral.bit_count == 16) { + return INT16_MIN; + } else if (type_entry->data.integral.bit_count == 8) { + return INT8_MIN; + } else { + zig_unreachable(); + } +} + +void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { + if (type_entry->id == TypeTableEntryIdInt) { + const_val->special = ConstValSpecialStatic; + 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 = max_signed_val(type_entry); + bignum_init_signed(&const_val->data.x_bignum, val); + } else { + uint64_t val = max_unsigned_val(type_entry); + bignum_init_unsigned(&const_val->data.x_bignum, val); + } + } else { + if (type_entry->data.integral.is_signed) { + int64_t val = min_signed_val(type_entry); + bignum_init_signed(&const_val->data.x_bignum, val); + } else { + bignum_init_unsigned(&const_val->data.x_bignum, 0); + } + } + } else if (type_entry->id == TypeTableEntryIdFloat) { + zig_panic("TODO analyze_min_max_value float"); + } else if (type_entry->id == TypeTableEntryIdBool) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_bool = is_max; + } else if (type_entry->id == TypeTableEntryIdVoid) { + // nothing to do + } else { + zig_unreachable(); + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 1bb389cb1..d4861979e 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -77,6 +77,8 @@ bool type_requires_comptime(TypeTableEntry *type_entry); void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry); void complete_enum(CodeGen *g, TypeTableEntry *enum_type); bool ir_get_var_is_comptime(VariableTableEntry *var); +bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); +void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); ScopeBlock *create_block_scope(AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5094e7f9b..e60e641b2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2144,6 +2144,10 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI return get_handle_value(g, tag_field_ptr, tag_type); } +static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) { + zig_panic("TODO ir_render_init_enum"); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2278,6 +2282,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdEnumTag: return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); + case IrInstructionIdInitEnum: + return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); case IrInstructionIdSwitchVar: zig_panic("TODO render switch var instruction to LLVM"); case IrInstructionIdContainerInitList: @@ -2497,6 +2503,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE } case TypeTableEntryIdVoid: return nullptr; + case TypeTableEntryIdEnumTag: + return gen_const_val(g, type_entry->data.enum_tag.int_type, const_val); case TypeTableEntryIdInvalid: case TypeTableEntryIdMetaType: case TypeTableEntryIdUnreachable: @@ -2876,6 +2884,9 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdErrWrapCode) { IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; slot = &err_wrap_code_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdInitEnum) { + IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction; + slot = &init_enum_instruction->tmp_ptr; } else { zig_unreachable(); } @@ -3793,7 +3804,8 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: - zig_panic("TODO"); + case TypeTableEntryIdEnumTag: + zig_panic("TODO implement get_c_type for more types"); case TypeTableEntryIdInvalid: case TypeTableEntryIdMetaType: case TypeTableEntryIdBoundFn: diff --git a/src/eval.cpp b/src/eval.cpp deleted file mode 100644 index c1a8bc604..000000000 --- a/src/eval.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "eval.hpp" -#include "analyze.hpp" -#include "error.hpp" - -bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { - switch (type_entry->id) { - case TypeTableEntryIdEnum: - { - ConstEnumValue *enum1 = &a->data.x_enum; - ConstEnumValue *enum2 = &b->data.x_enum; - if (enum1->tag == enum2->tag) { - TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; - if (type_has_bits(enum_field->type_entry)) { - zig_panic("TODO const expr analyze enum special value for equality"); - } else { - return true; - } - } - return false; - } - case TypeTableEntryIdMetaType: - return a->data.x_type == b->data.x_type; - case TypeTableEntryIdVoid: - return true; - case TypeTableEntryIdPureError: - return a->data.x_pure_err == b->data.x_pure_err; - case TypeTableEntryIdFn: - return a->data.x_fn == b->data.x_fn; - case TypeTableEntryIdBool: - return a->data.x_bool == b->data.x_bool; - case TypeTableEntryIdInt: - case TypeTableEntryIdFloat: - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: - return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); - case TypeTableEntryIdPointer: - zig_panic("TODO"); - case TypeTableEntryIdArray: - zig_panic("TODO"); - case TypeTableEntryIdStruct: - zig_panic("TODO"); - case TypeTableEntryIdUnion: - zig_panic("TODO"); - case TypeTableEntryIdUndefLit: - zig_panic("TODO"); - case TypeTableEntryIdNullLit: - zig_panic("TODO"); - case TypeTableEntryIdMaybe: - zig_panic("TODO"); - case TypeTableEntryIdErrorUnion: - zig_panic("TODO"); - case TypeTableEntryIdTypeDecl: - zig_panic("TODO"); - case TypeTableEntryIdNamespace: - zig_panic("TODO"); - case TypeTableEntryIdBlock: - zig_panic("TODO"); - case TypeTableEntryIdBoundFn: - case TypeTableEntryIdInvalid: - case TypeTableEntryIdUnreachable: - case TypeTableEntryIdVar: - zig_unreachable(); - } - zig_unreachable(); -} - - -static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { - if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) { - return a || b; - } else if (bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeAssignBoolAnd) { - return a && b; - } else { - zig_unreachable(); - } -} - -static uint64_t max_unsigned_val(TypeTableEntry *type_entry) { - assert(type_entry->id == TypeTableEntryIdInt); - if (type_entry->data.integral.bit_count == 64) { - return UINT64_MAX; - } else if (type_entry->data.integral.bit_count == 32) { - return UINT32_MAX; - } else if (type_entry->data.integral.bit_count == 16) { - return UINT16_MAX; - } else if (type_entry->data.integral.bit_count == 8) { - return UINT8_MAX; - } else { - zig_unreachable(); - } -} - -static int64_t max_signed_val(TypeTableEntry *type_entry) { - assert(type_entry->id == TypeTableEntryIdInt); - if (type_entry->data.integral.bit_count == 64) { - return INT64_MAX; - } else if (type_entry->data.integral.bit_count == 32) { - return INT32_MAX; - } else if (type_entry->data.integral.bit_count == 16) { - return INT16_MAX; - } else if (type_entry->data.integral.bit_count == 8) { - return INT8_MAX; - } else { - zig_unreachable(); - } -} - -static int64_t min_signed_val(TypeTableEntry *type_entry) { - assert(type_entry->id == TypeTableEntryIdInt); - if (type_entry->data.integral.bit_count == 64) { - return INT64_MIN; - } else if (type_entry->data.integral.bit_count == 32) { - return INT32_MIN; - } else if (type_entry->data.integral.bit_count == 16) { - return INT16_MIN; - } else if (type_entry->data.integral.bit_count == 8) { - return INT8_MIN; - } else { - zig_unreachable(); - } -} - -static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, - ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), - TypeTableEntry *type, bool wrapping_op) -{ - bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); - if (overflow) { - return ErrorOverflow; - } - - if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum, - type->data.integral.bit_count, type->data.integral.is_signed)) - { - if (wrapping_op) { - if (type->data.integral.is_signed) { - out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; - out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative; - } else if (out_val->data.x_bignum.is_negative) { - out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; - out_val->data.x_bignum.is_negative = false; - } else { - bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count); - } - } else { - return ErrorOverflow; - } - } - - out_val->special = ConstValSpecialStatic; - out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; - return 0; -} - -int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, - BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) -{ - assert(op1_val->special != ConstValSpecialRuntime); - assert(op2_val->special != ConstValSpecialRuntime); - assert(op1_type->id != TypeTableEntryIdInvalid); - assert(op2_type->id != TypeTableEntryIdInvalid); - - switch (bin_op) { - case BinOpTypeAssign: - *out_val = *op2_val; - return 0; - case BinOpTypeBoolOr: - case BinOpTypeBoolAnd: - case BinOpTypeAssignBoolAnd: - case BinOpTypeAssignBoolOr: - assert(op1_type->id == TypeTableEntryIdBool); - assert(op2_type->id == TypeTableEntryIdBool); - out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool); - out_val->special = ConstValSpecialStatic; - out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; - return 0; - case BinOpTypeCmpEq: - case BinOpTypeCmpNotEq: - case BinOpTypeCmpLessThan: - case BinOpTypeCmpGreaterThan: - case BinOpTypeCmpLessOrEq: - case BinOpTypeCmpGreaterOrEq: - { - bool type_can_gt_lt_cmp = (op1_type->id == TypeTableEntryIdNumLitFloat || - op1_type->id == TypeTableEntryIdNumLitInt || - op1_type->id == TypeTableEntryIdFloat || - op1_type->id == TypeTableEntryIdInt); - bool answer; - if (type_can_gt_lt_cmp) { - bool (*bignum_cmp)(BigNum *, BigNum *); - if (bin_op == BinOpTypeCmpEq) { - bignum_cmp = bignum_cmp_eq; - } else if (bin_op == BinOpTypeCmpNotEq) { - bignum_cmp = bignum_cmp_neq; - } else if (bin_op == BinOpTypeCmpLessThan) { - bignum_cmp = bignum_cmp_lt; - } else if (bin_op == BinOpTypeCmpGreaterThan) { - bignum_cmp = bignum_cmp_gt; - } else if (bin_op == BinOpTypeCmpLessOrEq) { - bignum_cmp = bignum_cmp_lte; - } else if (bin_op == BinOpTypeCmpGreaterOrEq) { - bignum_cmp = bignum_cmp_gte; - } else { - zig_unreachable(); - } - - answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); - } else { - bool are_equal = const_values_equal(op1_val, op2_val, op1_type); - if (bin_op == BinOpTypeCmpEq) { - answer = are_equal; - } else if (bin_op == BinOpTypeCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - } - - out_val->depends_on_compile_var = - op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; - out_val->data.x_bool = answer; - out_val->special = ConstValSpecialStatic; - return 0; - } - case BinOpTypeAdd: - case BinOpTypeAssignPlus: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false); - case BinOpTypeAddWrap: - case BinOpTypeAssignPlusWrap: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true); - case BinOpTypeBinOr: - case BinOpTypeAssignBitOr: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false); - case BinOpTypeBinXor: - case BinOpTypeAssignBitXor: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false); - case BinOpTypeBinAnd: - case BinOpTypeAssignBitAnd: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false); - case BinOpTypeBitShiftLeft: - case BinOpTypeAssignBitShiftLeft: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false); - case BinOpTypeBitShiftLeftWrap: - case BinOpTypeAssignBitShiftLeftWrap: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true); - case BinOpTypeBitShiftRight: - case BinOpTypeAssignBitShiftRight: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false); - case BinOpTypeSub: - case BinOpTypeAssignMinus: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false); - case BinOpTypeSubWrap: - case BinOpTypeAssignMinusWrap: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true); - case BinOpTypeMult: - case BinOpTypeAssignTimes: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false); - case BinOpTypeMultWrap: - case BinOpTypeAssignTimesWrap: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true); - case BinOpTypeDiv: - case BinOpTypeAssignDiv: - { - bool is_int = false; - bool is_float = false; - if (op1_type->id == TypeTableEntryIdInt || - op1_type->id == TypeTableEntryIdNumLitInt) - { - is_int = true; - } else if (op1_type->id == TypeTableEntryIdFloat || - op1_type->id == TypeTableEntryIdNumLitFloat) - { - is_float = true; - } - if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || - (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) - { - return ErrorDivByZero; - } else { - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false); - } - } - case BinOpTypeMod: - case BinOpTypeAssignMod: - return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false); - case BinOpTypeUnwrapMaybe: - zig_panic("TODO"); - case BinOpTypeArrayCat: - case BinOpTypeArrayMult: - case BinOpTypeInvalid: - zig_unreachable(); - } - zig_unreachable(); -} - -void eval_const_expr_implicit_cast(CastOp cast_op, - ConstExprValue *other_val, TypeTableEntry *other_type, - ConstExprValue *const_val, TypeTableEntry *new_type) -{ - const_val->depends_on_compile_var = other_val->depends_on_compile_var; - const_val->special = other_val->special; - - assert(other_val != const_val); - switch (cast_op) { - case CastOpNoCast: - zig_unreachable(); - case CastOpNoop: - case CastOpWidenOrShorten: - *const_val = *other_val; - break; - case CastOpPointerReinterpret: - zig_panic("TODO compile time pointer reinterpret"); - break; - case CastOpPtrToInt: - case CastOpIntToPtr: - case CastOpResizeSlice: - case CastOpBytesToSlice: - // can't do it - break; - case CastOpToUnknownSizeArray: - { - assert(other_type->id == TypeTableEntryIdArray); - assert(other_val->data.x_array.size == other_type->data.array.len); - - const_val->data.x_struct.fields = allocate(2); - ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index]; - ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index]; - - ptr_field->special = ConstValSpecialStatic; - ptr_field->data.x_ptr.base_ptr = other_val; - - len_field->special = ConstValSpecialStatic; - bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); - - const_val->special = ConstValSpecialStatic; - break; - } - case CastOpErrToInt: - { - uint64_t value; - if (other_type->id == TypeTableEntryIdErrorUnion) { - value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0; - } else if (other_type->id == TypeTableEntryIdPureError) { - value = other_val->data.x_pure_err->value; - } else { - zig_unreachable(); - } - bignum_init_unsigned(&const_val->data.x_bignum, value); - const_val->special = ConstValSpecialStatic; - break; - } - case CastOpIntToFloat: - bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); - const_val->special = ConstValSpecialStatic; - break; - case CastOpFloatToInt: - bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); - const_val->special = ConstValSpecialStatic; - break; - case CastOpBoolToInt: - bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); - const_val->special = ConstValSpecialStatic; - break; - case CastOpIntToEnum: - { - uint64_t value = other_val->data.x_bignum.data.x_uint; - assert(new_type->id == TypeTableEntryIdEnum); - assert(value < new_type->data.enumeration.src_field_count); - const_val->data.x_enum.tag = value; - const_val->data.x_enum.payload = NULL; - const_val->special = ConstValSpecialStatic; - break; - } - case CastOpEnumToInt: - bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); - const_val->special = ConstValSpecialStatic; - break; - } -} - -static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { - assert(int_type->id == TypeTableEntryIdInt); - - for (size_t i = 0; i < CIntTypeCount; i += 1) { - if (int_type == g->builtin_types.entry_c_int[i]) { - return true; - } - } - return false; -} - -void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { - if (type_entry->id == TypeTableEntryIdInt) { - const_val->special = ConstValSpecialStatic; - 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 = max_signed_val(type_entry); - bignum_init_signed(&const_val->data.x_bignum, val); - } else { - uint64_t val = max_unsigned_val(type_entry); - bignum_init_unsigned(&const_val->data.x_bignum, val); - } - } else { - if (type_entry->data.integral.is_signed) { - int64_t val = min_signed_val(type_entry); - bignum_init_signed(&const_val->data.x_bignum, val); - } else { - bignum_init_unsigned(&const_val->data.x_bignum, 0); - } - } - } else if (type_entry->id == TypeTableEntryIdFloat) { - zig_panic("TODO analyze_min_max_value float"); - } else if (type_entry->id == TypeTableEntryIdBool) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_bool = is_max; - } else if (type_entry->id == TypeTableEntryIdVoid) { - // nothing to do - } else { - zig_unreachable(); - } -} diff --git a/src/eval.hpp b/src/eval.hpp deleted file mode 100644 index b90aca21a..000000000 --- a/src/eval.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_EVAL_HPP -#define ZIG_EVAL_HPP - -#include "all_types.hpp" - -bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); -int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, - BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val); - -void eval_const_expr_implicit_cast(CastOp cast_op, - ConstExprValue *other_val, TypeTableEntry *other_type, - ConstExprValue *const_val, TypeTableEntry *new_type); - -void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); - -#endif diff --git a/src/ir.cpp b/src/ir.cpp index 69b843efa..ad05c8e23 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8,7 +8,6 @@ #include "analyze.hpp" #include "ast_render.hpp" #include "error.hpp" -#include "eval.hpp" #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" @@ -447,6 +446,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) return IrInstructionIdTestComptime; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) { + return IrInstructionIdInitEnum; +} + template static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1861,6 +1864,28 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } +static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, + TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) +{ + IrInstructionInitEnum *instruction = ir_build_instruction(irb, scope, source_node); + instruction->enum_type = enum_type; + instruction->field = field; + instruction->init_value = init_value; + + ir_ref_instruction(init_value); + + return &instruction->base; +} + +static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction, + TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) +{ + IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node, + enum_type, field, init_value); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -4596,6 +4621,90 @@ static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableE } } +static void eval_const_expr_implicit_cast(CastOp cast_op, + ConstExprValue *other_val, TypeTableEntry *other_type, + ConstExprValue *const_val, TypeTableEntry *new_type) +{ + const_val->depends_on_compile_var = other_val->depends_on_compile_var; + const_val->special = other_val->special; + + assert(other_val != const_val); + switch (cast_op) { + case CastOpNoCast: + zig_unreachable(); + case CastOpNoop: + case CastOpWidenOrShorten: + *const_val = *other_val; + break; + case CastOpPointerReinterpret: + zig_panic("TODO compile time pointer reinterpret"); + break; + case CastOpPtrToInt: + case CastOpIntToPtr: + case CastOpResizeSlice: + case CastOpBytesToSlice: + // can't do it + break; + case CastOpToUnknownSizeArray: + { + assert(other_type->id == TypeTableEntryIdArray); + assert(other_val->data.x_array.size == other_type->data.array.len); + + const_val->data.x_struct.fields = allocate(2); + ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index]; + + ptr_field->special = ConstValSpecialStatic; + ptr_field->data.x_ptr.base_ptr = other_val; + + len_field->special = ConstValSpecialStatic; + bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); + + const_val->special = ConstValSpecialStatic; + break; + } + case CastOpErrToInt: + { + uint64_t value; + if (other_type->id == TypeTableEntryIdErrorUnion) { + value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0; + } else if (other_type->id == TypeTableEntryIdPureError) { + value = other_val->data.x_pure_err->value; + } else { + zig_unreachable(); + } + bignum_init_unsigned(&const_val->data.x_bignum, value); + const_val->special = ConstValSpecialStatic; + break; + } + case CastOpIntToFloat: + bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); + const_val->special = ConstValSpecialStatic; + break; + case CastOpFloatToInt: + bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); + const_val->special = ConstValSpecialStatic; + break; + case CastOpBoolToInt: + bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); + const_val->special = ConstValSpecialStatic; + break; + case CastOpIntToEnum: + { + uint64_t value = other_val->data.x_bignum.data.x_uint; + assert(new_type->id == TypeTableEntryIdEnum); + assert(value < new_type->data.enumeration.src_field_count); + const_val->data.x_enum.tag = value; + const_val->data.x_enum.payload = NULL; + const_val->special = ConstValSpecialStatic; + break; + } + case CastOpEnumToInt: + bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); + const_val->special = ConstValSpecialStatic; + break; + } +} static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca) { @@ -5562,6 +5671,9 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdEnumTag: + zig_panic("TODO implement comparison for enum tag type"); + case TypeTableEntryIdVar: zig_unreachable(); } @@ -6074,6 +6186,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: // OK break; } @@ -6517,6 +6630,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, value->static_value.depends_on_compile_var); @@ -6603,6 +6717,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, value->static_value.depends_on_compile_var); @@ -7175,7 +7290,11 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru create_const_enum_tag(field->value), child_type, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); } else { - zig_panic("TODO enum tag type"); + bool ptr_is_const = true; + return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, + create_const_unsigned_negative(field->value, false), + child_type->data.enumeration.tag_type, depends_on_compile_var, + ConstPtrSpecialNone, ptr_is_const); } } } @@ -7377,6 +7496,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdEnumTag: { ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); // TODO depends_on_compile_var should be set based on whether the type of the expression @@ -7596,6 +7716,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: { TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base, @@ -7685,6 +7806,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: { TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size); bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var || @@ -7774,6 +7896,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, case TypeTableEntryIdPureError: case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: + case TypeTableEntryIdEnumTag: { uint64_t size_in_bytes = type_size(ira->codegen, type_entry); bool depends_on_compile_var = false; // TODO types should be able to depend on compile var @@ -8089,6 +8212,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, case TypeTableEntryIdErrorUnion: // see https://github.com/andrewrk/zig/issues/83 zig_panic("TODO switch on error union"); + case TypeTableEntryIdEnumTag: + zig_panic("TODO switch on enum tag type"); case TypeTableEntryIdUnreachable: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: @@ -8347,86 +8472,133 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { IrInstruction *container_type_value = instruction->container_type->other; - TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); - if (container_type->id == TypeTableEntryIdInvalid) + if (container_type_value->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; size_t elem_count = instruction->item_count; - bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; + if (container_type_value->type_entry->id == TypeTableEntryIdMetaType) { + TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); + if (container_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; - if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); - } else if (is_slice(container_type)) { - TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; - assert(pointer_type->id == TypeTableEntryIdPointer); - TypeTableEntry *child_type = pointer_type->data.pointer.child_type; + bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.depends_on_compile_var = depends_on_compile_var; - const_val.data.x_array.elements = allocate(elem_count); - const_val.data.x_array.size = elem_count; + if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); + } else if (is_slice(container_type)) { + TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; + assert(pointer_type->id == TypeTableEntryIdPointer); + TypeTableEntry *child_type = pointer_type->data.pointer.child_type; - FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); - bool outside_fn = (fn_entry == nullptr); + ConstExprValue const_val = {}; + const_val.special = ConstValSpecialStatic; + const_val.depends_on_compile_var = depends_on_compile_var; + const_val.data.x_array.elements = allocate(elem_count); + const_val.data.x_array.size = elem_count; - IrInstruction **new_items = allocate(elem_count); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); + bool outside_fn = (fn_entry == nullptr); - IrInstruction *first_non_const_instruction = nullptr; + IrInstruction **new_items = allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - IrInstruction *arg_value = instruction->items[i]->other; - if (arg_value->type_entry->id == TypeTableEntryIdInvalid) - return ira->codegen->builtin_types.entry_invalid; + IrInstruction *first_non_const_instruction = nullptr; - new_items[i] = arg_value; + for (size_t i = 0; i < elem_count; i += 1) { + IrInstruction *arg_value = instruction->items[i]->other; + if (arg_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; - if (const_val.special == ConstValSpecialStatic) { - if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad); - if (!elem_val) - return ira->codegen->builtin_types.entry_invalid; + new_items[i] = arg_value; - const_val.data.x_array.elements[i] = *elem_val; - const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; - } else { - first_non_const_instruction = arg_value; - const_val.special = ConstValSpecialRuntime; + if (const_val.special == ConstValSpecialStatic) { + if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad); + if (!elem_val) + return ira->codegen->builtin_types.entry_invalid; + + const_val.data.x_array.elements[i] = *elem_val; + const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; + } else { + first_non_const_instruction = arg_value; + const_val.special = ConstValSpecialRuntime; + } } } - } - TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); - if (const_val.special == ConstValSpecialStatic) { - ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var); - *out_val = const_val; + TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); + if (const_val.special == ConstValSpecialStatic) { + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var); + *out_val = const_val; + return fixed_size_array_type; + } + + if (outside_fn) { + ir_add_error_node(ira, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base, + container_type_value, elem_count, new_items); + ir_add_alloca(ira, new_instruction, fixed_size_array_type); return fixed_size_array_type; - } - - if (outside_fn) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->builtin_types.entry_invalid; - } - - IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base, - container_type_value, elem_count, new_items); - ir_add_alloca(ira, new_instruction, fixed_size_array_type); - return fixed_size_array_type; - } else if (container_type->id == TypeTableEntryIdArray) { - // same as slice init but we make a compile error if the length is wrong - zig_panic("TODO array container init"); - } else if (container_type->id == TypeTableEntryIdVoid) { - if (elem_count != 0) { + } else if (container_type->id == TypeTableEntryIdArray) { + // same as slice init but we make a compile error if the length is wrong + zig_panic("TODO array container init"); + } else if (container_type->id == TypeTableEntryIdVoid) { + if (elem_count != 0) { + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("void expression expects no arguments")); + return ira->codegen->builtin_types.entry_invalid; + } + return ir_analyze_void(ira, &instruction->base); + } else { ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); + buf_sprintf("type '%s' does not support array initialization", + buf_ptr(&container_type->name))); return ira->codegen->builtin_types.entry_invalid; } - return ir_analyze_void(ira, &instruction->base); + } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) { + // TODO I wrote this commit message when I had some sake + // might be worth re-examining sober + if (elem_count != 1) { + ir_add_error(ira, &instruction->base, buf_sprintf("expected 1 elment")); + return ira->codegen->builtin_types.entry_invalid; + } + ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad); + if (!tag_value) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *enum_type = container_type_value->type_entry->data.enum_tag.enum_type; + + uint64_t tag_uint = tag_value->data.x_bignum.data.x_uint; + TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint]; + TypeTableEntry *this_field_type = field->type_entry; + + IrInstruction *init_value = instruction->items[0]->other; + + IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type); + if (casted_init_value == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + if (instr_is_comptime(casted_init_value)) { + ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk); + if (!init_val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, + casted_init_value->static_value.depends_on_compile_var); + out_val->data.x_enum.tag = tag_uint; + out_val->data.x_enum.payload = init_val; + return enum_type; + } + + IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base, + enum_type, field, casted_init_value); + ir_add_alloca(ira, new_instruction, enum_type); + return enum_type; } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); + ir_add_error(ira, container_type_value, + buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->type_entry->name))); return ira->codegen->builtin_types.entry_invalid; } } @@ -8471,6 +8643,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ eval_min_max_value(ira->codegen, canon_type, out_val, is_max); return target_type; } + case TypeTableEntryIdEnumTag: + zig_panic("TODO min/max value for enum tag type"); case TypeTableEntryIdVar: case TypeTableEntryIdMetaType: case TypeTableEntryIdUnreachable: @@ -8984,55 +9158,17 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi return ira->codegen->builtin_types.entry_invalid; TypeTableEntry *child_type = ir_resolve_type(ira, type_value); - TypeTableEntry *canon_type = get_underlying_type(child_type); - if (count_value->static_value.special == ConstValSpecialStatic) { - // this should be the same as an array declaration - - uint64_t count; - if (!ir_resolve_usize(ira, count_value, &count)) - return ira->codegen->builtin_types.entry_invalid; - - zig_panic("TODO alloca with compile time known count"); - } - - switch (canon_type->id) { - case TypeTableEntryIdInvalid: - case TypeTableEntryIdTypeDecl: - zig_unreachable(); - case TypeTableEntryIdBool: - case TypeTableEntryIdVoid: - case TypeTableEntryIdInt: - case TypeTableEntryIdFloat: - case TypeTableEntryIdPointer: - case TypeTableEntryIdArray: - case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: - case TypeTableEntryIdErrorUnion: - case TypeTableEntryIdPureError: - case TypeTableEntryIdEnum: - case TypeTableEntryIdUnion: - case TypeTableEntryIdFn: - { - TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false); - IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value); - ir_add_alloca(ira, new_instruction, slice_type); - return slice_type; - } - case TypeTableEntryIdVar: - case TypeTableEntryIdMetaType: - case TypeTableEntryIdUnreachable: - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: - case TypeTableEntryIdUndefLit: - case TypeTableEntryIdNullLit: - case TypeTableEntryIdNamespace: - case TypeTableEntryIdBlock: - case TypeTableEntryIdBoundFn: - ir_add_error(ira, type_value, - buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name))); - // TODO if this is a typedecl, add error note showing the declaration of the type decl - return ira->codegen->builtin_types.entry_invalid; + if (type_requires_comptime(child_type)) { + ir_add_error(ira, type_value, + buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + } else { + TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false); + IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value); + ir_add_alloca(ira, new_instruction, slice_type); + return slice_type; } zig_unreachable(); } @@ -9804,6 +9940,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: case IrInstructionIdStructInit: + case IrInstructionIdInitEnum: zig_panic("TODO analyze more instructions"); } zig_unreachable(); @@ -9959,6 +10096,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: + case IrInstructionIdInitEnum: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7ebae91d5..c723da472 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -183,6 +183,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const fprintf(irp->f, "(pure error constant)"); return; } + case TypeTableEntryIdEnumTag: + { + TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type; + TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint]; + fprintf(irp->f, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); + return; + } } zig_unreachable(); } @@ -911,6 +918,12 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst fprintf(irp->f, ")"); } +static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) { + fprintf(irp->f, "%s.%s { ", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name)); + ir_print_other_instruction(irp, instruction->init_value); + fprintf(irp->f, "{"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1147,6 +1160,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTestComptime: ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); break; + case IrInstructionIdInitEnum: + ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/cases3/enum.zig b/test/cases3/enum.zig new file mode 100644 index 000000000..e588a1909 --- /dev/null +++ b/test/cases3/enum.zig @@ -0,0 +1,37 @@ +fn enumType() { + @setFnTest(this); + + const foo1 = Foo.One {13}; + const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }}; + const bar = Bar.B; + + assert(bar == Bar.B); + assert(@memberCount(Foo) == 3); + assert(@memberCount(Bar) == 4); + const expected_foo_size = 16 + @sizeOf(usize); + assert(@sizeOf(Foo) == expected_foo_size); + assert(@sizeOf(Bar) == 1); +} +const Point = struct { + x: u64, + y: u64, +}; +const Foo = enum { + One: i32, + Two: Point, + Three: void, +}; +const Bar = enum { + A, + B, + C, + D, +}; + +fn assert(ok: bool) { + if (!ok) + @unreachable(); +} + + + diff --git a/test/self_hosted.zig b/test/self_hosted.zig index d29c960a7..c987d53a1 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -333,41 +333,6 @@ fn maybeType() { } -fn enumType() { - @setFnTest(this, true); - - const foo1 = EnumTypeFoo.One {13}; - const foo2 = EnumTypeFoo.Two {EnumType { .x = 1234, .y = 5678, }}; - const bar = EnumTypeBar.B; - - assert(bar == EnumTypeBar.B); - assert(@memberCount(EnumTypeFoo) == 3); - assert(@memberCount(EnumTypeBar) == 4); - const expected_foo_size = switch (@compileVar("arch")) { - i386 => 20, - x86_64 => 24, - else => @unreachable(), - }; - assert(@sizeOf(EnumTypeFoo) == expected_foo_size); - assert(@sizeOf(EnumTypeBar) == 1); -} -struct EnumType { - x: u64, - y: u64, -} -enum EnumTypeFoo { - One: i32, - Two: EnumType, - Three: void, -} -enum EnumTypeBar { - A, - B, - C, - D, -} - - fn arrayLiteral() { @setFnTest(this, true); diff --git a/test/self_hosted3.zig b/test/self_hosted3.zig index 329e8571c..6a5a301b8 100644 --- a/test/self_hosted3.zig +++ b/test/self_hosted3.zig @@ -8,3 +8,4 @@ const test_for = @import("cases3/for.zig"); const test_math = @import("cases3/math.zig"); const test_generics = @import("cases3/generics.zig"); const test_defer = @import("cases3/defer.zig"); +const test_enum = @import("cases3/enum.zig");