From ee64a22045ccbc39773779d4e386e25f563c8a90 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 26 Jul 2019 19:52:35 -0400 Subject: [PATCH] add the `anyframe` and `anyframe->T` types --- BRANCH_TODO | 6 +- src/all_types.hpp | 21 ++++++ src/analyze.cpp | 111 ++++++++++++++++++++++++++++- src/analyze.hpp | 1 + src/ast_render.cpp | 10 +++ src/codegen.cpp | 16 ++++- src/ir.cpp | 86 +++++++++++++++++++++- src/ir_print.cpp | 12 ++++ src/parser.cpp | 22 +++++- src/tokenizer.cpp | 2 + src/tokenizer.hpp | 1 + std/hash_map.zig | 1 + std/testing.zig | 1 + std/zig/ast.zig | 16 ++--- std/zig/parse.zig | 40 +++++------ std/zig/parser_test.zig | 4 +- std/zig/render.zig | 10 +-- std/zig/tokenizer.zig | 4 +- test/stage1/behavior/type_info.zig | 23 +++++- 19 files changed, 337 insertions(+), 50 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index d10bc704d8..e2c4fec436 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,4 @@ - * reimplement @frameSize with Prefix Data - * reimplement with function splitting rather than switch - * add the `anyframe` type and `anyframe->T` + * make the anyframe type and anyframe->T type work with resume * await * await of a non async function * await in single-threaded mode @@ -12,3 +10,5 @@ * implicit cast of normal function to async function should be allowed when it is inferred to be async * go over the commented out tests * revive std.event.Loop + * reimplement with function splitting rather than switch + * @typeInfo for @Frame(func) diff --git a/src/all_types.hpp b/src/all_types.hpp index c9bdfabb0d..1096feade0 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -479,6 +479,7 @@ enum NodeType { NodeTypeResume, NodeTypeAwaitExpr, NodeTypeSuspend, + NodeTypeAnyFrameType, NodeTypeEnumLiteral, }; @@ -936,6 +937,10 @@ struct AstNodeSuspend { AstNode *block; }; +struct AstNodeAnyFrameType { + AstNode *payload_type; // can be NULL +}; + struct AstNodeEnumLiteral { Token *period; Token *identifier; @@ -1001,6 +1006,7 @@ struct AstNode { AstNodeResumeExpr resume_expr; AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; + AstNodeAnyFrameType anyframe_type; AstNodeEnumLiteral enum_literal; } data; }; @@ -1253,6 +1259,7 @@ enum ZigTypeId { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdCoroFrame, + ZigTypeIdAnyFrame, ZigTypeIdVector, ZigTypeIdEnumLiteral, }; @@ -1272,6 +1279,10 @@ struct ZigTypeCoroFrame { ZigType *locals_struct; }; +struct ZigTypeAnyFrame { + ZigType *result_type; // null if `anyframe` instead of `anyframe->T` +}; + struct ZigType { ZigTypeId id; Buf name; @@ -1298,11 +1309,13 @@ struct ZigType { ZigTypeVector vector; ZigTypeOpaque opaque; ZigTypeCoroFrame frame; + ZigTypeAnyFrame any_frame; } data; // use these fields to make sure we don't duplicate type table entries for the same type ZigType *pointer_parent[2]; // [0 - mut, 1 - const] ZigType *optional_parent; + ZigType *any_frame_parent; // If we generate a constant name value for this type, we memoize it here. // The type of this is array ConstExprValue *cached_const_name_val; @@ -1781,6 +1794,7 @@ struct CodeGen { ZigType *entry_arg_tuple; ZigType *entry_enum_literal; ZigType *entry_frame_header; + ZigType *entry_any_frame; } builtin_types; ZigType *align_amt_type; ZigType *stack_trace_type; @@ -2208,6 +2222,7 @@ enum IrInstructionId { IrInstructionIdSetRuntimeSafety, IrInstructionIdSetFloatMode, IrInstructionIdArrayType, + IrInstructionIdAnyFrameType, IrInstructionIdSliceType, IrInstructionIdGlobalAsm, IrInstructionIdAsm, @@ -2709,6 +2724,12 @@ struct IrInstructionPtrType { bool is_allow_zero; }; +struct IrInstructionAnyFrameType { + IrInstruction base; + + IrInstruction *payload_type; +}; + struct IrInstructionSliceType { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index e1fedab7cf..e47be8f14c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -256,6 +256,7 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdVector: + case ZigTypeIdAnyFrame: return nullptr; } zig_unreachable(); @@ -322,6 +323,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdVector: + case ZigTypeIdAnyFrame: return true; } zig_unreachable(); @@ -354,6 +356,31 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { return get_int_type(g, false, bits_needed_for_unsigned(x)); } +ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) { + if (result_type != nullptr && result_type->any_frame_parent != nullptr) { + return result_type->any_frame_parent; + } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) { + return g->builtin_types.entry_any_frame; + } + + ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame); + entry->abi_size = g->builtin_types.entry_usize->abi_size; + entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; + entry->abi_align = g->builtin_types.entry_usize->abi_align; + entry->data.any_frame.result_type = result_type; + buf_init_from_str(&entry->name, "anyframe"); + if (result_type != nullptr) { + buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name)); + } + + if (result_type != nullptr) { + result_type->any_frame_parent = entry; + } else if (result_type == nullptr) { + g->builtin_types.entry_any_frame = entry; + } + return entry; +} + static const char *ptr_len_to_star_str(PtrLen ptr_len) { switch (ptr_len) { case PtrLenSingle: @@ -1080,6 +1107,7 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: add_node_error(g, source_node, buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation", buf_ptr(&type_entry->name))); @@ -1169,6 +1197,7 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdVoid: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return false; case ZigTypeIdOpaque: case ZigTypeIdUnreachable: @@ -1340,6 +1369,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: switch (type_requires_comptime(g, type_entry)) { case ReqCompTimeNo: break; @@ -1436,6 +1466,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: switch (type_requires_comptime(g, fn_type_id.return_type)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; @@ -2997,6 +3028,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeAwaitExpr: case NodeTypeSuspend: case NodeTypeEnumLiteral: + case NodeTypeAnyFrameType: zig_unreachable(); } } @@ -3049,6 +3081,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry case ZigTypeIdBoundFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return type_entry; } zig_unreachable(); @@ -3550,6 +3583,7 @@ bool is_container(ZigType *type_entry) { case ZigTypeIdOpaque: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return false; } zig_unreachable(); @@ -3607,6 +3641,7 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdOpaque: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); } zig_unreachable(); @@ -3615,11 +3650,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) { ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdPointer) return type; if (type->id == ZigTypeIdFn) return type; + if (type->id == ZigTypeIdAnyFrame) return type; if (type->id == ZigTypeIdOptional) { if (type->data.maybe.child_type->id == ZigTypeIdPointer) { return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; } if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; + if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type; } return nullptr; } @@ -3635,6 +3672,13 @@ bool type_is_nonnull_ptr(ZigType *type) { return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type); } +static uint32_t get_coro_frame_align_bytes(CodeGen *g) { + uint32_t a = g->pointer_size_bytes * 2; + // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw + if (a < 8) a = 8; + return a; +} + uint32_t get_ptr_align(CodeGen *g, ZigType *type) { ZigType *ptr_type = get_src_ptr_type(type); if (ptr_type->id == ZigTypeIdPointer) { @@ -3646,6 +3690,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { // when getting the alignment of `?extern fn() void`. // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; + } else if (ptr_type->id == ZigTypeIdAnyFrame) { + return get_coro_frame_align_bytes(g); } else { zig_unreachable(); } @@ -3657,6 +3703,8 @@ bool get_ptr_const(ZigType *type) { return ptr_type->data.pointer.is_const; } else if (ptr_type->id == ZigTypeIdFn) { return true; + } else if (ptr_type->id == ZigTypeIdAnyFrame) { + return true; } else { zig_unreachable(); } @@ -4153,6 +4201,7 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdFn: case ZigTypeIdEnum: case ZigTypeIdVector: + case ZigTypeIdAnyFrame: return false; case ZigTypeIdArray: case ZigTypeIdStruct: @@ -4404,6 +4453,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { case ZigTypeIdCoroFrame: // TODO better hashing algorithm return 675741936; + case ZigTypeIdAnyFrame: + // TODO better hashing algorithm + return 3747294894; case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -4469,6 +4521,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return false; case ZigTypeIdPointer: @@ -4541,6 +4594,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdPointer: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return true; case ZigTypeIdArray: @@ -4673,6 +4727,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdFloat: case ZigTypeIdErrorUnion: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return OnePossibleValueNo; case ZigTypeIdUndefined: case ZigTypeIdNull: @@ -4761,6 +4816,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { case ZigTypeIdVoid: case ZigTypeIdUnreachable: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return ReqCompTimeNo; } zig_unreachable(); @@ -5433,6 +5489,8 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { return true; case ZigTypeIdCoroFrame: zig_panic("TODO"); + case ZigTypeIdAnyFrame: + zig_panic("TODO"); case ZigTypeIdUndefined: zig_panic("TODO"); case ZigTypeIdNull: @@ -5786,7 +5844,11 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case ZigTypeIdCoroFrame: - buf_appendf(buf, "(TODO: coroutine frame value)"); + buf_appendf(buf, "(TODO: async function frame value)"); + return; + + case ZigTypeIdAnyFrame: + buf_appendf(buf, "(TODO: anyframe value)"); return; } @@ -5836,6 +5898,7 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdErrorUnion: return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type); @@ -5885,6 +5948,7 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdErrorUnion: return a.data.error_union.err_set_type == b.data.error_union.err_set_type && @@ -6051,6 +6115,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdCoroFrame, + ZigTypeIdAnyFrame, ZigTypeIdVector, ZigTypeIdEnumLiteral, }; @@ -6116,10 +6181,12 @@ size_t type_id_index(ZigType *entry) { return 21; case ZigTypeIdCoroFrame: return 22; - case ZigTypeIdVector: + case ZigTypeIdAnyFrame: return 23; - case ZigTypeIdEnumLiteral: + case ZigTypeIdVector: return 24; + case ZigTypeIdEnumLiteral: + return 25; } zig_unreachable(); } @@ -6178,6 +6245,8 @@ const char *type_id_name(ZigTypeId id) { return "Vector"; case ZigTypeIdCoroFrame: return "Frame"; + case ZigTypeIdAnyFrame: + return "AnyFrame"; } zig_unreachable(); } @@ -7398,6 +7467,40 @@ static void resolve_llvm_types_coro_frame(CodeGen *g, ZigType *frame_type, Resol frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type; } +static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, ResolveStatus wanted_resolve_status) { + if (any_frame_type->llvm_di_type != nullptr) return; + + ZigType *result_type = any_frame_type->data.any_frame.result_type; + Buf *name = buf_sprintf("(%s header)", buf_ptr(&any_frame_type->name)); + + ZigType *frame_header_type; + if (result_type == nullptr || !type_has_bits(result_type)) { + const char *field_names[] = {"resume_index", "fn_ptr", "awaiter"}; + ZigType *field_types[] = { + g->builtin_types.entry_usize, + g->builtin_types.entry_usize, + g->builtin_types.entry_usize, + }; + frame_header_type = get_struct_type(g, buf_ptr(name), field_names, field_types, 3); + } else { + ZigType *ptr_result_type = get_pointer_to_type(g, result_type, false); + + const char *field_names[] = {"resume_index", "fn_ptr", "awaiter", "result_ptr", "result"}; + ZigType *field_types[] = { + g->builtin_types.entry_usize, + g->builtin_types.entry_usize, + g->builtin_types.entry_usize, + ptr_result_type, + result_type, + }; + frame_header_type = get_struct_type(g, buf_ptr(name), field_names, field_types, 5); + } + + ZigType *ptr_type = get_pointer_to_type(g, frame_header_type, false); + any_frame_type->llvm_type = get_llvm_type(g, ptr_type); + any_frame_type->llvm_di_type = get_llvm_di_type(g, ptr_type); +} + static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown)); assert(wanted_resolve_status > ResolveStatusSizeKnown); @@ -7460,6 +7563,8 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r } case ZigTypeIdCoroFrame: return resolve_llvm_types_coro_frame(g, type, wanted_resolve_status); + case ZigTypeIdAnyFrame: + return resolve_llvm_types_any_frame(g, type, wanted_resolve_status); } zig_unreachable(); } diff --git a/src/analyze.hpp b/src/analyze.hpp index 47ff4344ba..3115c79b40 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -41,6 +41,7 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[], ZigType *field_types[], size_t field_count); ZigType *get_test_fn_type(CodeGen *g); +ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type); bool handle_is_ptr(ZigType *type_entry); bool type_has_bits(ZigType *type_entry); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index d97f58fdec..4d6bae311b 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -259,6 +259,8 @@ static const char *node_type_str(NodeType node_type) { return "Suspend"; case NodeTypePointerType: return "PointerType"; + case NodeTypeAnyFrameType: + return "AnyFrameType"; case NodeTypeEnumLiteral: return "EnumLiteral"; } @@ -847,6 +849,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { render_node_ungrouped(ar, node->data.inferred_array_type.child_type); break; } + case NodeTypeAnyFrameType: { + fprintf(ar->f, "anyframe"); + if (node->data.anyframe_type.payload_type != nullptr) { + fprintf(ar->f, "->"); + render_node_grouped(ar, node->data.anyframe_type.payload_type); + } + break; + } case NodeTypeErrorType: fprintf(ar->f, "anyerror"); break; diff --git a/src/codegen.cpp b/src/codegen.cpp index 63018cb6a3..c666317c17 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4947,6 +4947,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSetRuntimeSafety: case IrInstructionIdSetFloatMode: case IrInstructionIdArrayType: + case IrInstructionIdAnyFrameType: case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdSwitchTarget: @@ -5438,7 +5439,9 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con return val; } case ZigTypeIdCoroFrame: - zig_panic("TODO bit pack a coroutine frame"); + zig_panic("TODO bit pack an async function frame"); + case ZigTypeIdAnyFrame: + zig_panic("TODO bit pack an anyframe"); } zig_unreachable(); } @@ -5961,6 +5964,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c zig_unreachable(); case ZigTypeIdCoroFrame: zig_panic("TODO"); + case ZigTypeIdAnyFrame: + zig_panic("TODO"); } zig_unreachable(); } @@ -7176,6 +7181,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " ArgTuple: void,\n" " Opaque: void,\n" " Frame: void,\n" + " AnyFrame: AnyFrame,\n" " Vector: Vector,\n" " EnumLiteral: void,\n" "\n\n" @@ -7291,6 +7297,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " args: []FnArg,\n" " };\n" "\n" + " pub const AnyFrame = struct {\n" + " child: ?type,\n" + " };\n" + "\n" " pub const Vector = struct {\n" " len: comptime_int,\n" " child: type,\n" @@ -8448,6 +8458,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdVoid: case ZigTypeIdUnreachable: @@ -8632,6 +8643,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu case ZigTypeIdNull: case ZigTypeIdArgTuple: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); } } @@ -8800,7 +8812,9 @@ static void gen_h_file(CodeGen *g) { case ZigTypeIdFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: zig_unreachable(); + case ZigTypeIdEnum: if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry))); diff --git a/src/ir.cpp b/src/ir.cpp index 7a5af347b7..e6d987a2ee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -303,6 +303,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { case ZigTypeIdBoundFn: case ZigTypeIdErrorSet: case ZigTypeIdOpaque: + case ZigTypeIdAnyFrame: return true; case ZigTypeIdFloat: return a->data.floating.bit_count == b->data.floating.bit_count; @@ -563,6 +564,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { return IrInstructionIdArrayType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAnyFrameType *) { + return IrInstructionIdAnyFrameType; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { return IrInstructionIdSliceType; } @@ -1696,6 +1701,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *payload_type) +{ + IrInstructionAnyFrameType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->payload_type = payload_type; + + if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); + + return &instruction->base; +} static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero) { @@ -6515,6 +6530,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n } } +static IrInstruction *ir_gen_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeAnyFrameType); + + AstNode *payload_type_node = node->data.anyframe_type.payload_type; + IrInstruction *payload_type_value = nullptr; + + if (payload_type_node != nullptr) { + payload_type_value = ir_gen_node(irb, payload_type_node, scope); + if (payload_type_value == irb->codegen->invalid_instruction) + return payload_type_value; + + } + + return ir_build_anyframe_type(irb, scope, node, payload_type_value); +} + static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeUndefinedLiteral); return ir_build_const_undefined(irb, scope, node); @@ -7884,6 +7915,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc); case NodeTypePointerType: return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc); + case NodeTypeAnyFrameType: + return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc); case NodeTypeStringLiteral: return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc); case NodeTypeUndefinedLiteral: @@ -12775,6 +12808,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdArgTuple: case ZigTypeIdEnum: case ZigTypeIdEnumLiteral: + case ZigTypeIdAnyFrame: operator_allowed = is_equality_cmp; break; @@ -14155,6 +14189,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: ir_add_error(ira, target, buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); break; @@ -14180,6 +14215,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdOpaque: case ZigTypeIdEnumLiteral: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: ir_add_error(ira, target, buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name))); break; @@ -15720,7 +15756,9 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry)); + case ZigTypeIdUnreachable: case ZigTypeIdOpaque: ir_add_error_node(ira, un_op_instruction->base.source_node, @@ -17443,6 +17481,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, return ir_const_void(ira, &instruction->base); } +static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, + IrInstructionAnyFrameType *instruction) +{ + ZigType *payload_type = nullptr; + if (instruction->payload_type != nullptr) { + payload_type = ir_resolve_type(ira, instruction->payload_type->child); + if (type_is_invalid(payload_type)) + return ira->codegen->invalid_instruction; + } + + ZigType *any_frame_type = get_any_frame_type(ira->codegen, payload_type); + return ir_const_type(ira, &instruction->base, any_frame_type); +} + static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, IrInstructionSliceType *slice_type_instruction) { @@ -17492,6 +17544,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdBoundFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: { ResolveStatus needed_status = (align_bytes == 0) ? ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; @@ -17607,6 +17660,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdBoundFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: { if ((err = ensure_complete_type(ira->codegen, child_type))) return ira->codegen->invalid_instruction; @@ -17658,6 +17712,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: { uint64_t size_in_bytes = type_size(ira->codegen, type_entry); return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); @@ -18222,6 +18277,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdOpaque: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: ir_add_error(ira, &switch_target_instruction->base, buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; @@ -19656,6 +19712,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr break; } + case ZigTypeIdAnyFrame: { + result = create_const_vals(1); + result->special = ConstValSpecialStatic; + result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr); + + ConstExprValue *fields = create_const_vals(1); + result->data.x_struct.fields = fields; + + // child: ?type + ensure_field_index(result->type, "child", 0); + fields[0].special = ConstValSpecialStatic; + fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); + fields[0].data.x_optional = (type_entry->data.any_frame.result_type == nullptr) ? nullptr : + create_const_type(ira->codegen, type_entry->data.any_frame.result_type); + break; + } case ZigTypeIdEnum: { result = create_const_vals(1); @@ -20062,7 +20134,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr break; } case ZigTypeIdCoroFrame: - zig_panic("TODO @typeInfo for coro frames"); + zig_panic("TODO @typeInfo for async function frames"); } assert(result != nullptr); @@ -21852,6 +21924,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct case ZigTypeIdFn: case ZigTypeIdVector: case ZigTypeIdCoroFrame: + case ZigTypeIdAnyFrame: { uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); return ir_const_unsigned(ira, &instruction->base, align_in_bytes); @@ -23004,7 +23077,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdUnion: zig_panic("TODO buf_write_value_bytes union type"); case ZigTypeIdCoroFrame: - zig_panic("TODO buf_write_value_bytes coro frame type"); + zig_panic("TODO buf_write_value_bytes async fn frame type"); + case ZigTypeIdAnyFrame: + zig_panic("TODO buf_write_value_bytes anyframe type"); } zig_unreachable(); } @@ -23185,7 +23260,9 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou case ZigTypeIdUnion: zig_panic("TODO buf_read_value_bytes union type"); case ZigTypeIdCoroFrame: - zig_panic("TODO buf_read_value_bytes coro frame type"); + zig_panic("TODO buf_read_value_bytes async fn frame type"); + case ZigTypeIdAnyFrame: + zig_panic("TODO buf_read_value_bytes anyframe type"); } zig_unreachable(); } @@ -24327,6 +24404,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction); case IrInstructionIdSetFloatMode: return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction); + case IrInstructionIdAnyFrameType: + return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction); case IrInstructionIdSliceType: return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); case IrInstructionIdGlobalAsm: @@ -24707,6 +24786,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdStructFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdSliceType: + case IrInstructionIdAnyFrameType: case IrInstructionIdSizeOf: case IrInstructionIdTestNonNull: case IrInstructionIdOptionalUnwrapPtr: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index ae467bdc8c..284ebed2f3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -471,6 +471,15 @@ static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instructio ir_print_other_instruction(irp, instruction->child_type); } +static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *instruction) { + if (instruction->payload_type == nullptr) { + fprintf(irp->f, "anyframe"); + } else { + fprintf(irp->f, "anyframe->"); + ir_print_other_instruction(irp, instruction->payload_type); + } +} + static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) { fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code)); } @@ -1629,6 +1638,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSliceType: ir_print_slice_type(irp, (IrInstructionSliceType *)instruction); break; + case IrInstructionIdAnyFrameType: + ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction); + break; case IrInstructionIdGlobalAsm: ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction); break; diff --git a/src/parser.cpp b/src/parser.cpp index b1a593d9c9..82312aacf3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -282,6 +282,9 @@ static AstNode *ast_parse_prefix_op_expr( case NodeTypeAwaitExpr: right = &prefix->data.await_expr.expr; break; + case NodeTypeAnyFrameType: + right = &prefix->data.anyframe_type.payload_type; + break; case NodeTypeArrayType: right = &prefix->data.array_type.child_type; break; @@ -1640,6 +1643,10 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { if (null != nullptr) return ast_create_node(pc, NodeTypeNullLiteral, null); + Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); + if (anyframe != nullptr) + return ast_create_node(pc, NodeTypeAnyFrameType, anyframe); + Token *true_token = eat_token_if(pc, TokenIdKeywordTrue); if (true_token != nullptr) { AstNode *res = ast_create_node(pc, NodeTypeBoolLiteral, true_token); @@ -2510,7 +2517,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) { // PrefixTypeOp // <- QUESTIONMARK -// / KEYWORD_promise MINUSRARROW +// / KEYWORD_anyframe MINUSRARROW // / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)* // / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)* static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { @@ -2521,6 +2528,16 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { return res; } + Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); + if (anyframe != nullptr) { + if (eat_token_if(pc, TokenIdArrow) != nullptr) { + AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe); + return res; + } + + put_back_token(pc); + } + AstNode *array = ast_parse_array_type_start(pc); if (array != nullptr) { assert(array->type == NodeTypeArrayType); @@ -3005,6 +3022,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeInferredArrayType: visit_field(&node->data.array_type.child_type, visit, context); break; + case NodeTypeAnyFrameType: + visit_field(&node->data.anyframe_type.payload_type, visit, context); + break; case NodeTypeErrorType: // none break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 0869c3ba9c..38c6c7153e 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -109,6 +109,7 @@ static const struct ZigKeyword zig_keywords[] = { {"align", TokenIdKeywordAlign}, {"allowzero", TokenIdKeywordAllowZero}, {"and", TokenIdKeywordAnd}, + {"anyframe", TokenIdKeywordAnyFrame}, {"asm", TokenIdKeywordAsm}, {"async", TokenIdKeywordAsync}, {"await", TokenIdKeywordAwait}, @@ -1533,6 +1534,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordCancel: return "cancel"; case TokenIdKeywordAlign: return "align"; case TokenIdKeywordAnd: return "and"; + case TokenIdKeywordAnyFrame: return "anyframe"; case TokenIdKeywordAsm: return "asm"; case TokenIdKeywordBreak: return "break"; case TokenIdKeywordCatch: return "catch"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 253e0bd1e5..98bdfea907 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -53,6 +53,7 @@ enum TokenId { TokenIdKeywordAlign, TokenIdKeywordAllowZero, TokenIdKeywordAnd, + TokenIdKeywordAnyFrame, TokenIdKeywordAsm, TokenIdKeywordAsync, TokenIdKeywordAwait, diff --git a/std/hash_map.zig b/std/hash_map.zig index bdd6cc7519..431fbb35ab 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -540,6 +540,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type .Undefined, .ArgTuple, .Frame, + .AnyFrame, => @compileError("cannot hash this type"), .Void, diff --git a/std/testing.zig b/std/testing.zig index 3c4772cf37..7f347b0c24 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -30,6 +30,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { .ArgTuple, .Opaque, .Frame, + .AnyFrame, => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"), .Undefined, diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 38bd94339f..475a0e4e13 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -400,7 +400,7 @@ pub const Node = struct { VarType, ErrorType, FnProto, - PromiseType, + AnyFrameType, // Primary expressions IntegerLiteral, @@ -952,9 +952,9 @@ pub const Node = struct { } }; - pub const PromiseType = struct { + pub const AnyFrameType = struct { base: Node, - promise_token: TokenIndex, + anyframe_token: TokenIndex, result: ?Result, pub const Result = struct { @@ -962,7 +962,7 @@ pub const Node = struct { return_type: *Node, }; - pub fn iterate(self: *PromiseType, index: usize) ?*Node { + pub fn iterate(self: *AnyFrameType, index: usize) ?*Node { var i = index; if (self.result) |result| { @@ -973,13 +973,13 @@ pub const Node = struct { return null; } - pub fn firstToken(self: *const PromiseType) TokenIndex { - return self.promise_token; + pub fn firstToken(self: *const AnyFrameType) TokenIndex { + return self.anyframe_token; } - pub fn lastToken(self: *const PromiseType) TokenIndex { + pub fn lastToken(self: *const AnyFrameType) TokenIndex { if (self.result) |result| return result.return_type.lastToken(); - return self.promise_token; + return self.anyframe_token; } }; diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 59acf99890..600178cdce 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -1201,7 +1201,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / KEYWORD_error DOT IDENTIFIER /// / KEYWORD_false /// / KEYWORD_null -/// / KEYWORD_promise +/// / KEYWORD_anyframe /// / KEYWORD_true /// / KEYWORD_undefined /// / KEYWORD_unreachable @@ -1256,11 +1256,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N } if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token); if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token); - if (eatToken(it, .Keyword_promise)) |token| { - const node = try arena.create(Node.PromiseType); - node.* = Node.PromiseType{ - .base = Node{ .id = .PromiseType }, - .promise_token = token, + if (eatToken(it, .Keyword_anyframe)) |token| { + const node = try arena.create(Node.AnyFrameType); + node.* = Node.AnyFrameType{ + .base = Node{ .id = .AnyFrameType }, + .anyframe_token = token, .result = null, }; return &node.base; @@ -2194,7 +2194,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// PrefixTypeOp /// <- QUESTIONMARK -/// / KEYWORD_promise MINUSRARROW +/// / KEYWORD_anyframe MINUSRARROW /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { @@ -2209,20 +2209,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return &node.base; } - // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or + // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or // .return_type more difficult for the caller (see parsePrefixOpExpr helper). - // Consider making the PromiseType a member of PrefixOp and add a - // PrefixOp.PromiseType variant? - if (eatToken(it, .Keyword_promise)) |token| { + // Consider making the AnyFrameType a member of PrefixOp and add a + // PrefixOp.AnyFrameType variant? + if (eatToken(it, .Keyword_anyframe)) |token| { const arrow = eatToken(it, .Arrow) orelse { putBackToken(it, token); return null; }; - const node = try arena.create(Node.PromiseType); - node.* = Node.PromiseType{ - .base = Node{ .id = .PromiseType }, - .promise_token = token, - .result = Node.PromiseType.Result{ + const node = try arena.create(Node.AnyFrameType); + node.* = Node.AnyFrameType{ + .base = Node{ .id = .AnyFrameType }, + .anyframe_token = token, + .result = Node.AnyFrameType.Result{ .arrow_token = arrow, .return_type = undefined, // set by caller }, @@ -2903,8 +2903,8 @@ fn parsePrefixOpExpr( rightmost_op = rhs; } else break; }, - .PromiseType => { - const prom = rightmost_op.cast(Node.PromiseType).?; + .AnyFrameType => { + const prom = rightmost_op.cast(Node.AnyFrameType).?; if (try opParseFn(arena, it, tree)) |rhs| { prom.result.?.return_type = rhs; rightmost_op = rhs; @@ -2922,8 +2922,8 @@ fn parsePrefixOpExpr( .InvalidToken = AstError.InvalidToken{ .token = it.index }, }); }, - .PromiseType => { - const prom = rightmost_op.cast(Node.PromiseType).?; + .AnyFrameType => { + const prom = rightmost_op.cast(Node.AnyFrameType).?; prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{ .InvalidToken = AstError.InvalidToken{ .token = it.index }, }); diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index f6f3363bf6..28cde6de01 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -2111,12 +2111,12 @@ test "zig fmt: coroutines" { \\ suspend; \\ x += 1; \\ suspend; - \\ const p: promise->void = async simpleAsyncFn() catch unreachable; + \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; \\ await p; \\} \\ \\test "coroutine suspend, resume, cancel" { - \\ const p: promise = try async testAsyncSeq(); + \\ const p: anyframe = try async testAsyncSeq(); \\ resume p; \\ cancel p; \\} diff --git a/std/zig/render.zig b/std/zig/render.zig index b85c11c6ac..c6bb51267d 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -1205,15 +1205,15 @@ fn renderExpression( } }, - ast.Node.Id.PromiseType => { - const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base); + ast.Node.Id.AnyFrameType => { + const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base); - if (promise_type.result) |result| { - try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise + if (anyframe_type.result) |result| { + try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // -> return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space); } else { - return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise + return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe } }, diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 4539e1e5b2..9de20c39f2 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -15,6 +15,7 @@ pub const Token = struct { Keyword{ .bytes = "align", .id = Id.Keyword_align }, Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero }, Keyword{ .bytes = "and", .id = Id.Keyword_and }, + Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe }, Keyword{ .bytes = "asm", .id = Id.Keyword_asm }, Keyword{ .bytes = "async", .id = Id.Keyword_async }, Keyword{ .bytes = "await", .id = Id.Keyword_await }, @@ -42,7 +43,6 @@ pub const Token = struct { Keyword{ .bytes = "or", .id = Id.Keyword_or }, Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse }, Keyword{ .bytes = "packed", .id = Id.Keyword_packed }, - Keyword{ .bytes = "promise", .id = Id.Keyword_promise }, Keyword{ .bytes = "pub", .id = Id.Keyword_pub }, Keyword{ .bytes = "resume", .id = Id.Keyword_resume }, Keyword{ .bytes = "return", .id = Id.Keyword_return }, @@ -174,7 +174,7 @@ pub const Token = struct { Keyword_or, Keyword_orelse, Keyword_packed, - Keyword_promise, + Keyword_anyframe, Keyword_pub, Keyword_resume, Keyword_return, diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 6a51015124..b86ba27c13 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -177,11 +177,11 @@ fn testUnion() void { expect(TypeId(typeinfo_info) == TypeId.Union); expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); expect(typeinfo_info.Union.tag_type.? == TypeId); - expect(typeinfo_info.Union.fields.len == 25); + expect(typeinfo_info.Union.fields.len == 26); expect(typeinfo_info.Union.fields[4].enum_field != null); expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - expect(typeinfo_info.Union.decls.len == 20); + expect(typeinfo_info.Union.decls.len == 21); const TestNoTagUnion = union { Foo: void, @@ -280,6 +280,25 @@ fn testVector() void { expect(vec_info.Vector.child == i32); } +test "type info: anyframe and anyframe->T" { + testAnyFrame(); + comptime testAnyFrame(); +} + +fn testAnyFrame() void { + { + const anyframe_info = @typeInfo(anyframe->i32); + expect(TypeId(anyframe_info) == .AnyFrame); + expect(anyframe_info.AnyFrame.child.? == i32); + } + + { + const anyframe_info = @typeInfo(anyframe); + expect(TypeId(anyframe_info) == .AnyFrame); + expect(anyframe_info.AnyFrame.child == null); + } +} + test "type info: optional field unwrapping" { const Struct = struct { cdOffset: u32,