structs can have fields with type var
behavior tests passing now
This commit is contained in:
parent
7597735bad
commit
f25182f46d
@ -146,10 +146,8 @@ pub const TypeInfo = union(enum) {
|
||||
is_allowzero: bool,
|
||||
/// The type of the sentinel is the element type of the pointer, which is
|
||||
/// the value of the `child` field in this struct. However there is no way
|
||||
/// to refer to that type here, so this is a pointer to an opaque value.
|
||||
/// It will be known at compile-time to be the correct type. Dereferencing
|
||||
/// this pointer will work at compile-time.
|
||||
sentinel: ?*const c_void,
|
||||
/// to refer to that type here, so we use `var`.
|
||||
sentinel: var,
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
@ -168,10 +166,8 @@ pub const TypeInfo = union(enum) {
|
||||
child: type,
|
||||
/// The type of the sentinel is the element type of the array, which is
|
||||
/// the value of the `child` field in this struct. However there is no way
|
||||
/// to refer to that type here, so this is a pointer to an opaque value.
|
||||
/// It will be known at compile-time to be the correct type. Dereferencing
|
||||
/// this pointer will work at compile-time.
|
||||
sentinel: ?*const c_void,
|
||||
/// to refer to that type here, so we use `var`.
|
||||
sentinel: var,
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
|
@ -601,6 +601,7 @@ enum NodeType {
|
||||
NodeTypeSuspend,
|
||||
NodeTypeAnyFrameType,
|
||||
NodeTypeEnumLiteral,
|
||||
NodeTypeVarFieldType,
|
||||
};
|
||||
|
||||
enum CallingConvention {
|
||||
|
@ -1179,6 +1179,10 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *
|
||||
Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
assert(type_val->special == ConstValSpecialStatic);
|
||||
if (type_val->data.x_type == g->builtin_types.entry_var) {
|
||||
*is_opaque_type = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
*is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque);
|
||||
return ErrorNone;
|
||||
}
|
||||
@ -3667,6 +3671,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeEnumLiteral:
|
||||
case NodeTypeAnyFrameType:
|
||||
case NodeTypeErrorSetField:
|
||||
case NodeTypeVarFieldType:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
@ -5587,6 +5592,9 @@ ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
|
||||
|
||||
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) {
|
||||
Error err;
|
||||
if (ty == g->builtin_types.entry_var) {
|
||||
return ReqCompTimeYes;
|
||||
}
|
||||
switch (ty->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
|
@ -268,6 +268,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "EnumLiteral";
|
||||
case NodeTypeErrorSetField:
|
||||
return "ErrorSetField";
|
||||
case NodeTypeVarFieldType:
|
||||
return "VarFieldType";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1184,6 +1186,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str));
|
||||
break;
|
||||
}
|
||||
case NodeTypeVarFieldType: {
|
||||
fprintf(ar->f, "var");
|
||||
break;
|
||||
}
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeTestDecl:
|
||||
case NodeTypeStructField:
|
||||
|
115
src/ir.cpp
115
src/ir.cpp
@ -8556,6 +8556,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
add_node_error(irb->codegen, node,
|
||||
buf_sprintf("inferred array size invalid here"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
case NodeTypeVarFieldType:
|
||||
return ir_lval_wrap(irb, scope,
|
||||
ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var), lval, result_loc);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -8715,6 +8718,9 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
|
||||
assert(val != nullptr);
|
||||
assert(const_val->type->id == ZigTypeIdPointer);
|
||||
ZigType *expected_type = const_val->type->data.pointer.child_type;
|
||||
if (expected_type == codegen->builtin_types.entry_var) {
|
||||
return val;
|
||||
}
|
||||
switch (type_has_one_possible_value(codegen, expected_type)) {
|
||||
case OnePossibleValueInvalid:
|
||||
return nullptr;
|
||||
@ -13502,6 +13508,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
||||
}
|
||||
if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
|
||||
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
|
||||
if (child_type == ira->codegen->builtin_types.entry_var) {
|
||||
child_type = pointee->type;
|
||||
}
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
IrInstruction *result = ir_const(ira, source_instruction, child_type);
|
||||
|
||||
@ -19857,13 +19866,24 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
|
||||
return ir_analyze_test_non_null(ira, &instruction->base, value);
|
||||
}
|
||||
|
||||
static ZigType *get_ptr_elem_type(CodeGen *g, IrInstruction *ptr) {
|
||||
ir_assert(ptr->value.type->id == ZigTypeIdPointer, ptr);
|
||||
ZigType *elem_type = ptr->value.type->data.pointer.child_type;
|
||||
if (elem_type != g->builtin_types.entry_var)
|
||||
return elem_type;
|
||||
|
||||
if (ir_resolve_lazy(g, ptr->source_node, &ptr->value))
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
||||
assert(value_is_comptime(&ptr->value));
|
||||
ConstExprValue *pointee = const_ptr_pointee_unchecked(g, &ptr->value);
|
||||
return pointee->type;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *base_ptr, bool safety_check_on, bool initializing)
|
||||
{
|
||||
ZigType *ptr_type = base_ptr->value.type;
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
ZigType *type_entry = ptr_type->data.pointer.child_type;
|
||||
ZigType *type_entry = get_ptr_elem_type(ira->codegen, base_ptr);
|
||||
if (type_is_invalid(type_entry))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
@ -19901,7 +19921,8 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
|
||||
|
||||
ZigType *child_type = type_entry->data.maybe.child_type;
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
|
||||
base_ptr->value.type->data.pointer.is_const, base_ptr->value.type->data.pointer.is_volatile,
|
||||
PtrLenSingle, 0, 0, 0, false);
|
||||
|
||||
bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry);
|
||||
|
||||
@ -21627,20 +21648,15 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
|
||||
fields[5]->special = ConstValSpecialStatic;
|
||||
fields[5]->type = ira->codegen->builtin_types.entry_bool;
|
||||
fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero;
|
||||
// sentinel: ?*const c_void
|
||||
ZigType *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_c_void, true);
|
||||
// sentinel: var
|
||||
ensure_field_index(result->type, "sentinel", 6);
|
||||
fields[6]->special = ConstValSpecialStatic;
|
||||
fields[6]->type = get_optional_type(ira->codegen, ptr_type);
|
||||
if (attrs_type->data.pointer.sentinel == nullptr) {
|
||||
fields[6]->data.x_optional = nullptr;
|
||||
if (attrs_type->data.pointer.sentinel != nullptr) {
|
||||
fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type);
|
||||
fields[6]->data.x_optional = attrs_type->data.pointer.sentinel;
|
||||
} else {
|
||||
ConstExprValue *ptr_val = create_const_vals(1);
|
||||
fields[6]->data.x_optional = ptr_val;
|
||||
ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
|
||||
copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, attrs_type->data.pointer.sentinel, false);
|
||||
fields[6]->type = ira->codegen->builtin_types.entry_null;
|
||||
fields[6]->data.x_optional = nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -21762,23 +21778,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
fields[1]->special = ConstValSpecialStatic;
|
||||
fields[1]->type = ira->codegen->builtin_types.entry_type;
|
||||
fields[1]->data.x_type = type_entry->data.array.child_type;
|
||||
// sentinel: ?*const c_void
|
||||
// sentinel: var
|
||||
fields[2]->special = ConstValSpecialStatic;
|
||||
ZigType *ptr_type = get_pointer_to_type(ira->codegen,
|
||||
ira->codegen->builtin_types.entry_c_void, true);
|
||||
fields[2]->type = get_optional_type(ira->codegen, ptr_type);
|
||||
if (type_entry->data.array.sentinel == nullptr) {
|
||||
fields[2]->data.x_optional = nullptr;
|
||||
} else {
|
||||
ConstExprValue *ptr_val = create_const_vals(1);
|
||||
fields[2]->data.x_optional = ptr_val;
|
||||
ptr_val->type = ptr_type;
|
||||
ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
|
||||
copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, type_entry->data.array.sentinel, false);
|
||||
}
|
||||
|
||||
fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type);
|
||||
fields[2]->data.x_optional = type_entry->data.array.sentinel;
|
||||
break;
|
||||
}
|
||||
case ZigTypeIdVector: {
|
||||
@ -22290,15 +22293,18 @@ static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_va
|
||||
return struct_value->data.x_struct.fields[field_index];
|
||||
}
|
||||
|
||||
static ConstExprValue *get_const_field_variant(IrAnalyze *ira, ConstExprValue *struct_value,
|
||||
const char *name, size_t field_index)
|
||||
static Error get_const_field_sentinel(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *struct_value,
|
||||
const char *name, size_t field_index, ZigType *elem_type, ConstExprValue **result)
|
||||
{
|
||||
ConstExprValue *field_val = get_const_field(ira, struct_value, name, field_index);
|
||||
assert(field_val->type->id == ZigTypeIdOptional);
|
||||
ConstExprValue *opt_val = field_val->data.x_optional;
|
||||
if (opt_val == nullptr) return nullptr;
|
||||
assert(opt_val->type->id == ZigTypeIdPointer);
|
||||
return const_ptr_pointee_unchecked(ira->codegen, opt_val);
|
||||
IrInstruction *field_inst = ir_const(ira, source_instr, field_val->type);
|
||||
IrInstruction *casted_field_inst = ir_implicit_cast(ira, field_inst,
|
||||
get_optional_type(ira->codegen, elem_type));
|
||||
if (type_is_invalid(casted_field_inst->value.type))
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
*result = casted_field_inst->value.data.x_optional;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index)
|
||||
@ -22323,6 +22329,7 @@ static ZigType *get_const_field_meta_type(IrAnalyze *ira, ConstExprValue *struct
|
||||
}
|
||||
|
||||
static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, ZigTypeId tagTypeId, ConstExprValue *payload) {
|
||||
Error err;
|
||||
switch (tagTypeId) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -22364,8 +22371,16 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
|
||||
assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type));
|
||||
BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag);
|
||||
PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index);
|
||||
ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 4);
|
||||
ConstExprValue *sentinel;
|
||||
if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 6,
|
||||
elem_type, &sentinel)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen,
|
||||
get_const_field_meta_type(ira, payload, "child", 4),
|
||||
elem_type,
|
||||
get_const_field_bool(ira, payload, "is_const", 1),
|
||||
get_const_field_bool(ira, payload, "is_volatile", 2),
|
||||
ptr_len,
|
||||
@ -22373,22 +22388,26 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
|
||||
0, // bit_offset_in_host
|
||||
0, // host_int_bytes
|
||||
get_const_field_bool(ira, payload, "is_allowzero", 5),
|
||||
VECTOR_INDEX_NONE,
|
||||
nullptr,
|
||||
get_const_field_variant(ira, payload, "sentinel", 6)
|
||||
);
|
||||
VECTOR_INDEX_NONE, nullptr, sentinel);
|
||||
if (size_enum_index != 2)
|
||||
return ptr_type;
|
||||
return get_slice_type(ira->codegen, ptr_type);
|
||||
}
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdArray: {
|
||||
assert(payload->special == ConstValSpecialStatic);
|
||||
assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr));
|
||||
ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 1);
|
||||
ConstExprValue *sentinel;
|
||||
if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 2,
|
||||
elem_type, &sentinel)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return get_array_type(ira->codegen,
|
||||
get_const_field_meta_type(ira, payload, "child", 1),
|
||||
elem_type,
|
||||
bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)),
|
||||
get_const_field_variant(ira, payload, "sentinel", 2)
|
||||
);
|
||||
sentinel);
|
||||
}
|
||||
case ZigTypeIdComptimeFloat:
|
||||
return ira->codegen->builtin_types.entry_num_lit_float;
|
||||
case ZigTypeIdComptimeInt:
|
||||
|
@ -848,7 +848,12 @@ static AstNode *ast_parse_container_field(ParseContext *pc) {
|
||||
|
||||
AstNode *type_expr = nullptr;
|
||||
if (eat_token_if(pc, TokenIdColon) != nullptr) {
|
||||
type_expr = ast_expect(pc, ast_parse_type_expr);
|
||||
Token *var_tok = eat_token_if(pc, TokenIdKeywordVar);
|
||||
if (var_tok != nullptr) {
|
||||
type_expr = ast_create_node(pc, NodeTypeVarFieldType, var_tok);
|
||||
} else {
|
||||
type_expr = ast_expect(pc, ast_parse_type_expr);
|
||||
}
|
||||
}
|
||||
AstNode *align_expr = ast_parse_byte_align(pc);
|
||||
AstNode *expr = nullptr;
|
||||
@ -3163,6 +3168,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
visit_field(&node->data.suspend.block, visit, context);
|
||||
break;
|
||||
case NodeTypeEnumLiteral:
|
||||
case NodeTypeVarFieldType:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ test "Type.Array" {
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel = &0,
|
||||
.sentinel = 0,
|
||||
},
|
||||
}));
|
||||
testTypes([_]type{ [1]u8, [30]usize, [7]bool });
|
||||
|
@ -46,7 +46,7 @@ fn testPointer() void {
|
||||
expect(u32_ptr_info.Pointer.is_volatile == false);
|
||||
expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
|
||||
expect(u32_ptr_info.Pointer.child == u32);
|
||||
expect(u32_ptr_info.Pointer.is_null_terminated == false);
|
||||
expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
}
|
||||
|
||||
test "type info: unknown length pointer type info" {
|
||||
@ -60,7 +60,7 @@ fn testUnknownLenPtr() void {
|
||||
expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
expect(u32_ptr_info.Pointer.is_const == true);
|
||||
expect(u32_ptr_info.Pointer.is_volatile == true);
|
||||
expect(u32_ptr_info.Pointer.is_null_terminated == false);
|
||||
expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
|
||||
expect(u32_ptr_info.Pointer.child == f64);
|
||||
}
|
||||
@ -76,7 +76,7 @@ fn testNullTerminatedPtr() void {
|
||||
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
expect(ptr_info.Pointer.is_const == false);
|
||||
expect(ptr_info.Pointer.is_volatile == false);
|
||||
expect(ptr_info.Pointer.is_null_terminated == true);
|
||||
expect(ptr_info.Pointer.sentinel.? == 0);
|
||||
|
||||
expect(@typeInfo([:0]u8).Pointer.sentinel != null);
|
||||
expect(@typeInfo([10:0]u8).Array.sentinel != null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user