IR: enum init support
parent
c10ae8622b
commit
1f6dacbb2f
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
194
src/analyze.cpp
194
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
429
src/eval.cpp
429
src/eval.cpp
|
@ -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<ConstExprValue>(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();
|
||||
}
|
||||
}
|
23
src/eval.hpp
23
src/eval.hpp
|
@ -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
|
358
src/ir.cpp
358
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<typename T>
|
||||
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(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<IrInstructionInitEnum>(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<ConstExprValue>(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<ConstExprValue>(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<ConstExprValue>(elem_count);
|
||||
const_val.data.x_array.size = elem_count;
|
||||
|
||||
IrInstruction **new_items = allocate<IrInstruction *>(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<IrInstruction *>(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:
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue