| ... | @@ -1703,6 +1703,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner | ... | @@ -1703,6 +1703,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner |
| 1703 | .struct_decl_packed, | 1703 | .struct_decl_packed, |
| 1704 | .struct_decl_extern, | 1704 | .struct_decl_extern, |
| 1705 | .union_decl, | 1705 | .union_decl, |
| | 1706 | .union_decl_packed, |
| | 1707 | .union_decl_extern, |
| 1706 | .enum_decl, | 1708 | .enum_decl, |
| 1707 | .enum_decl_nonexhaustive, | 1709 | .enum_decl_nonexhaustive, |
| 1708 | .opaque_decl, | 1710 | .opaque_decl, |
| ... | @@ -2897,7 +2899,7 @@ fn structDeclInner( | ... | @@ -2897,7 +2899,7 @@ fn structDeclInner( |
| 2897 | if (member.comptime_token) |comptime_token| { | 2899 | if (member.comptime_token) |comptime_token| { |
| 2898 | return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{}); | 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 | const field_name = try gz.identAsString(member.ast.name_token); | 2904 | const field_name = try gz.identAsString(member.ast.name_token); |
| 2903 | fields_data.appendAssumeCapacity(field_name); | 2905 | fields_data.appendAssumeCapacity(field_name); |
| ... | @@ -2969,6 +2971,229 @@ fn structDeclInner( | ... | @@ -2969,6 +2971,229 @@ fn structDeclInner( |
| 2969 | return gz.indexToRef(decl_inst); | 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 | fn containerDecl( | 3197 | fn containerDecl( |
| 2973 | gz: *GenZir, | 3198 | gz: *GenZir, |
| 2974 | scope: *Scope, | 3199 | scope: *Scope, |
| ... | @@ -3005,7 +3230,18 @@ fn containerDecl( | ... | @@ -3005,7 +3230,18 @@ fn containerDecl( |
| 3005 | return rvalue(gz, scope, rl, result, node); | 3230 | return rvalue(gz, scope, rl, result, node); |
| 3006 | }, | 3231 | }, |
| 3007 | .keyword_union => { | 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 | .keyword_enum => { | 3246 | .keyword_enum => { |
| 3011 | if (container_decl.layout_token) |t| { | 3247 | if (container_decl.layout_token) |t| { |
| ... | @@ -3224,6 +3460,20 @@ fn containerDecl( | ... | @@ -3224,6 +3460,20 @@ fn containerDecl( |
| 3224 | (@as(u32, @boolToInt(have_value)) << 31); | 3460 | (@as(u32, @boolToInt(have_value)) << 31); |
| 3225 | | 3461 | |
| 3226 | if (have_value) { | 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 | const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); | 3477 | const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); |
| 3228 | fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); | 3478 | fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); |
| 3229 | } | 3479 | } |
| ... | @@ -3232,12 +3482,15 @@ fn containerDecl( | ... | @@ -3232,12 +3482,15 @@ fn containerDecl( |
| 3232 | } | 3482 | } |
| 3233 | { | 3483 | { |
| 3234 | const empty_slot_count = 32 - (field_index % 32); | 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 | | 3489 | { |
| 3238 | if (wip_decls.decl_index != 0) { | | |
| 3239 | const empty_slot_count = 16 - (wip_decls.decl_index % 16); | 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 | const decl_inst = try gz.addBlock(tag, node); | 3496 | const decl_inst = try gz.addBlock(tag, node); |
| ... | @@ -4789,7 +5042,7 @@ fn switchExpr( | ... | @@ -4789,7 +5042,7 @@ fn switchExpr( |
| 4789 | .prong_index = capture_index, | 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 | capture_val_scope = .{ | 5046 | capture_val_scope = .{ |
| 4794 | .parent = &case_scope.base, | 5047 | .parent = &case_scope.base, |
| 4795 | .gen_zir = &case_scope, | 5048 | .gen_zir = &case_scope, |