From f25182f46dd672eb5b10533c67ed462a3e5df999 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Nov 2019 17:51:37 -0500 Subject: [PATCH] structs can have fields with type `var` behavior tests passing now --- lib/std/builtin.zig | 12 +-- src/all_types.hpp | 1 + src/analyze.cpp | 8 ++ src/ast_render.cpp | 6 ++ src/ir.cpp | 115 +++++++++++++++++------------ src/parser.cpp | 8 +- test/stage1/behavior/type.zig | 2 +- test/stage1/behavior/type_info.zig | 6 +- 8 files changed, 97 insertions(+), 61 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 64fc68e4cc..af045c5231 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -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 diff --git a/src/all_types.hpp b/src/all_types.hpp index 1f785a63f3..3b5a067ffc 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -601,6 +601,7 @@ enum NodeType { NodeTypeSuspend, NodeTypeAnyFrameType, NodeTypeEnumLiteral, + NodeTypeVarFieldType, }; enum CallingConvention { diff --git a/src/analyze.cpp b/src/analyze.cpp index aa58d64aa4..d065f85c67 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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(); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index f4f97c3730..531fcf1852 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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: diff --git a/src/ir.cpp b/src/ir.cpp index a7a3fc51e4..df76d3f963 100644 --- a/src/ir.cpp +++ b/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: diff --git a/src/parser.cpp b/src/parser.cpp index 61f3120d0e..429566ecc1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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; } } diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index e3ce4d0904..f083359d1d 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -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 }); diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index dcd4da3d0f..598bbca6be 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -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);