| ... | ... | @@ -1703,6 +1703,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner |
| 1703 | 1703 | .struct_decl_packed, |
| 1704 | 1704 | .struct_decl_extern, |
| 1705 | 1705 | .union_decl, |
| 1706 | .union_decl_packed, |
| 1707 | .union_decl_extern, |
| 1706 | 1708 | .enum_decl, |
| 1707 | 1709 | .enum_decl_nonexhaustive, |
| 1708 | 1710 | .opaque_decl, |
| ... | ... | @@ -2897,7 +2899,7 @@ fn structDeclInner( |
| 2897 | 2899 | if (member.comptime_token) |comptime_token| { |
| 2898 | 2900 | return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{}); |
| 2899 | 2901 | } |
| 2900 | | try fields_data.ensureCapacity(gpa, fields_data.items.len + 4); |
| 2902 | try fields_data.ensureUnusedCapacity(gpa, 4); |
| 2901 | 2903 | |
| 2902 | 2904 | const field_name = try gz.identAsString(member.ast.name_token); |
| 2903 | 2905 | fields_data.appendAssumeCapacity(field_name); |
| ... | ... | @@ -2969,6 +2971,229 @@ fn structDeclInner( |
| 2969 | 2971 | return gz.indexToRef(decl_inst); |
| 2970 | 2972 | } |
| 2971 | 2973 | |
| 2974 | fn unionDeclInner( |
| 2975 | gz: *GenZir, |
| 2976 | scope: *Scope, |
| 2977 | node: ast.Node.Index, |
| 2978 | members: []const ast.Node.Index, |
| 2979 | tag: Zir.Inst.Tag, |
| 2980 | arg_inst: Zir.Inst.Ref, |
| 2981 | have_auto_enum: bool, |
| 2982 | ) InnerError!Zir.Inst.Ref { |
| 2983 | const astgen = gz.astgen; |
| 2984 | const gpa = astgen.gpa; |
| 2985 | const tree = &astgen.file.tree; |
| 2986 | const node_tags = tree.nodes.items(.tag); |
| 2987 | const node_datas = tree.nodes.items(.data); |
| 2988 | |
| 2989 | // The union_decl instruction introduces a scope in which the decls of the union |
| 2990 | // are in scope, so that field types, alignments, and default value expressions |
| 2991 | // can refer to decls within the union itself. |
| 2992 | var block_scope: GenZir = .{ |
| 2993 | .parent = scope, |
| 2994 | .decl_node_index = node, |
| 2995 | .astgen = astgen, |
| 2996 | .force_comptime = true, |
| 2997 | .ref_start_index = gz.ref_start_index, |
| 2998 | }; |
| 2999 | defer block_scope.instructions.deinit(gpa); |
| 3000 | |
| 3001 | var wip_decls: WipDecls = .{}; |
| 3002 | defer wip_decls.deinit(gpa); |
| 3003 | |
| 3004 | // We don't know which members are fields until we iterate, so cannot do |
| 3005 | // an accurate ensureCapacity yet. |
| 3006 | var fields_data = ArrayListUnmanaged(u32){}; |
| 3007 | defer fields_data.deinit(gpa); |
| 3008 | |
| 3009 | const bits_per_field = 4; |
| 3010 | const fields_per_u32 = 32 / bits_per_field; |
| 3011 | // We only need this if there are greater than fields_per_u32 fields. |
| 3012 | var bit_bag = ArrayListUnmanaged(u32){}; |
| 3013 | defer bit_bag.deinit(gpa); |
| 3014 | |
| 3015 | var cur_bit_bag: u32 = 0; |
| 3016 | var field_index: usize = 0; |
| 3017 | for (members) |member_node| { |
| 3018 | const member = switch (node_tags[member_node]) { |
| 3019 | .container_field_init => tree.containerFieldInit(member_node), |
| 3020 | .container_field_align => tree.containerFieldAlign(member_node), |
| 3021 | .container_field => tree.containerField(member_node), |
| 3022 | |
| 3023 | .fn_decl => { |
| 3024 | const fn_proto = node_datas[member_node].lhs; |
| 3025 | const body = node_datas[member_node].rhs; |
| 3026 | switch (node_tags[fn_proto]) { |
| 3027 | .fn_proto_simple => { |
| 3028 | var params: [1]ast.Node.Index = undefined; |
| 3029 | try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(&params, fn_proto)); |
| 3030 | continue; |
| 3031 | }, |
| 3032 | .fn_proto_multi => { |
| 3033 | try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto)); |
| 3034 | continue; |
| 3035 | }, |
| 3036 | .fn_proto_one => { |
| 3037 | var params: [1]ast.Node.Index = undefined; |
| 3038 | try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(&params, fn_proto)); |
| 3039 | continue; |
| 3040 | }, |
| 3041 | .fn_proto => { |
| 3042 | try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto)); |
| 3043 | continue; |
| 3044 | }, |
| 3045 | else => unreachable, |
| 3046 | } |
| 3047 | }, |
| 3048 | .fn_proto_simple => { |
| 3049 | var params: [1]ast.Node.Index = undefined; |
| 3050 | try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(&params, member_node)); |
| 3051 | continue; |
| 3052 | }, |
| 3053 | .fn_proto_multi => { |
| 3054 | try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node)); |
| 3055 | continue; |
| 3056 | }, |
| 3057 | .fn_proto_one => { |
| 3058 | var params: [1]ast.Node.Index = undefined; |
| 3059 | try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(&params, member_node)); |
| 3060 | continue; |
| 3061 | }, |
| 3062 | .fn_proto => { |
| 3063 | try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node)); |
| 3064 | continue; |
| 3065 | }, |
| 3066 | |
| 3067 | .global_var_decl => { |
| 3068 | try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node)); |
| 3069 | continue; |
| 3070 | }, |
| 3071 | .local_var_decl => { |
| 3072 | try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node)); |
| 3073 | continue; |
| 3074 | }, |
| 3075 | .simple_var_decl => { |
| 3076 | try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node)); |
| 3077 | continue; |
| 3078 | }, |
| 3079 | .aligned_var_decl => { |
| 3080 | try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node)); |
| 3081 | continue; |
| 3082 | }, |
| 3083 | |
| 3084 | .@"comptime" => { |
| 3085 | try astgen.comptimeDecl(gz, scope, member_node); |
| 3086 | continue; |
| 3087 | }, |
| 3088 | .@"usingnamespace" => { |
| 3089 | try astgen.usingnamespaceDecl(gz, scope, member_node); |
| 3090 | continue; |
| 3091 | }, |
| 3092 | .test_decl => { |
| 3093 | try astgen.testDecl(gz, scope, member_node); |
| 3094 | continue; |
| 3095 | }, |
| 3096 | else => unreachable, |
| 3097 | }; |
| 3098 | if (field_index % fields_per_u32 == 0 and field_index != 0) { |
| 3099 | try bit_bag.append(gpa, cur_bit_bag); |
| 3100 | cur_bit_bag = 0; |
| 3101 | } |
| 3102 | if (member.comptime_token) |comptime_token| { |
| 3103 | return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); |
| 3104 | } |
| 3105 | try fields_data.ensureUnusedCapacity(gpa, 4); |
| 3106 | |
| 3107 | const field_name = try gz.identAsString(member.ast.name_token); |
| 3108 | fields_data.appendAssumeCapacity(field_name); |
| 3109 | |
| 3110 | const have_type = member.ast.type_expr != 0; |
| 3111 | const have_align = member.ast.align_expr != 0; |
| 3112 | const have_value = member.ast.value_expr != 0; |
| 3113 | cur_bit_bag = (cur_bit_bag >> bits_per_field) | |
| 3114 | (@as(u32, @boolToInt(have_type)) << 28) | |
| 3115 | (@as(u32, @boolToInt(have_align)) << 29) | |
| 3116 | (@as(u32, @boolToInt(have_value)) << 30) | |
| 3117 | (@as(u32, @boolToInt(have_auto_enum)) << 31); |
| 3118 | |
| 3119 | if (have_type) { |
| 3120 | const field_type = try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr); |
| 3121 | fields_data.appendAssumeCapacity(@enumToInt(field_type)); |
| 3122 | } |
| 3123 | if (have_align) { |
| 3124 | const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); |
| 3125 | fields_data.appendAssumeCapacity(@enumToInt(align_inst)); |
| 3126 | } |
| 3127 | if (have_value) { |
| 3128 | if (arg_inst == .none) { |
| 3129 | return astgen.failNodeNotes( |
| 3130 | node, |
| 3131 | "explicitly valued tagged union missing integer tag type", |
| 3132 | .{}, |
| 3133 | &[_]u32{ |
| 3134 | try astgen.errNoteNode( |
| 3135 | member.ast.value_expr, |
| 3136 | "tag value specified here", |
| 3137 | .{}, |
| 3138 | ), |
| 3139 | }, |
| 3140 | ); |
| 3141 | } |
| 3142 | const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); |
| 3143 | fields_data.appendAssumeCapacity(@enumToInt(tag_value)); |
| 3144 | } |
| 3145 | |
| 3146 | field_index += 1; |
| 3147 | } |
| 3148 | if (field_index == 0) { |
| 3149 | return astgen.failNode(node, "union declarations must have at least one tag", .{}); |
| 3150 | } |
| 3151 | { |
| 3152 | const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32); |
| 3153 | if (empty_slot_count < fields_per_u32) { |
| 3154 | cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field); |
| 3155 | } |
| 3156 | } |
| 3157 | { |
| 3158 | const empty_slot_count = 16 - (wip_decls.decl_index % 16); |
| 3159 | if (empty_slot_count < 16) { |
| 3160 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); |
| 3161 | } |
| 3162 | } |
| 3163 | |
| 3164 | const decl_inst = try gz.addBlock(tag, node); |
| 3165 | try gz.instructions.append(gpa, decl_inst); |
| 3166 | if (block_scope.instructions.items.len != 0) { |
| 3167 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 3168 | } |
| 3169 | |
| 3170 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + |
| 3171 | bit_bag.items.len + 1 + fields_data.items.len + |
| 3172 | block_scope.instructions.items.len + |
| 3173 | wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + |
| 3174 | wip_decls.name_and_value.items.len); |
| 3175 | const zir_datas = astgen.instructions.items(.data); |
| 3176 | zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{ |
| 3177 | .tag_type = arg_inst, |
| 3178 | .body_len = @intCast(u32, block_scope.instructions.items.len), |
| 3179 | .fields_len = @intCast(u32, field_index), |
| 3180 | .decls_len = @intCast(u32, wip_decls.decl_index), |
| 3181 | }); |
| 3182 | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 3183 | |
| 3184 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. |
| 3185 | astgen.extra.appendAssumeCapacity(cur_bit_bag); |
| 3186 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); |
| 3187 | |
| 3188 | astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. |
| 3189 | if (wip_decls.decl_index != 0) { |
| 3190 | astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); |
| 3191 | } |
| 3192 | astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items); |
| 3193 | |
| 3194 | return gz.indexToRef(decl_inst); |
| 3195 | } |
| 3196 | |
| 2972 | 3197 | fn containerDecl( |
| 2973 | 3198 | gz: *GenZir, |
| 2974 | 3199 | scope: *Scope, |
| ... | ... | @@ -3005,7 +3230,18 @@ fn containerDecl( |
| 3005 | 3230 | return rvalue(gz, scope, rl, result, node); |
| 3006 | 3231 | }, |
| 3007 | 3232 | .keyword_union => { |
| 3008 | | return astgen.failTok(container_decl.ast.main_token, "TODO AstGen for union decl", .{}); |
| 3233 | const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) { |
| 3234 | .keyword_packed => Zir.Inst.Tag.union_decl_packed, |
| 3235 | .keyword_extern => Zir.Inst.Tag.union_decl_extern, |
| 3236 | else => unreachable, |
| 3237 | } else Zir.Inst.Tag.union_decl; |
| 3238 | |
| 3239 | // See `Zir.Inst.UnionDecl` doc comments for why this is stored along |
| 3240 | // with fields instead of separately. |
| 3241 | const have_auto_enum = container_decl.ast.enum_token != null; |
| 3242 | |
| 3243 | const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, tag, arg_inst, have_auto_enum); |
| 3244 | return rvalue(gz, scope, rl, result, node); |
| 3009 | 3245 | }, |
| 3010 | 3246 | .keyword_enum => { |
| 3011 | 3247 | if (container_decl.layout_token) |t| { |
| ... | ... | @@ -3224,6 +3460,20 @@ fn containerDecl( |
| 3224 | 3460 | (@as(u32, @boolToInt(have_value)) << 31); |
| 3225 | 3461 | |
| 3226 | 3462 | if (have_value) { |
| 3463 | if (arg_inst == .none) { |
| 3464 | return astgen.failNodeNotes( |
| 3465 | node, |
| 3466 | "explicitly valued enum missing integer tag type", |
| 3467 | .{}, |
| 3468 | &[_]u32{ |
| 3469 | try astgen.errNoteNode( |
| 3470 | member.ast.value_expr, |
| 3471 | "tag value specified here", |
| 3472 | .{}, |
| 3473 | ), |
| 3474 | }, |
| 3475 | ); |
| 3476 | } |
| 3227 | 3477 | const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); |
| 3228 | 3478 | fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); |
| 3229 | 3479 | } |
| ... | ... | @@ -3232,12 +3482,15 @@ fn containerDecl( |
| 3232 | 3482 | } |
| 3233 | 3483 | { |
| 3234 | 3484 | const empty_slot_count = 32 - (field_index % 32); |
| 3235 | | cur_bit_bag >>= @intCast(u5, empty_slot_count); |
| 3485 | if (empty_slot_count < 32) { |
| 3486 | cur_bit_bag >>= @intCast(u5, empty_slot_count); |
| 3487 | } |
| 3236 | 3488 | } |
| 3237 | | |
| 3238 | | if (wip_decls.decl_index != 0) { |
| 3489 | { |
| 3239 | 3490 | const empty_slot_count = 16 - (wip_decls.decl_index % 16); |
| 3240 | | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); |
| 3491 | if (empty_slot_count < 16) { |
| 3492 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); |
| 3493 | } |
| 3241 | 3494 | } |
| 3242 | 3495 | |
| 3243 | 3496 | const decl_inst = try gz.addBlock(tag, node); |
| ... | ... | @@ -4789,7 +5042,7 @@ fn switchExpr( |
| 4789 | 5042 | .prong_index = capture_index, |
| 4790 | 5043 | } }, |
| 4791 | 5044 | }); |
| 4792 | | const capture_name = try astgen.identifierTokenString(payload_token); |
| 5045 | const capture_name = try astgen.identifierTokenString(ident); |
| 4793 | 5046 | capture_val_scope = .{ |
| 4794 | 5047 | .parent = &case_scope.base, |
| 4795 | 5048 | .gen_zir = &case_scope, |