Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Private Function

unionDeclInner

Private Function
std.zig.AstGen.unionDeclInner
fn unionDeclInner(
    gz: *GenZir,
    scope: *Scope,
    node: Ast.Node.Index,
    members: []const Ast.Node.Index,
    layout: std.lang.Type.ContainerLayout,
    opt_arg_node: Ast.Node.OptionalIndex,
    auto_enum_tok: ?Ast.TokenIndex,
    name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref

Params

Errors

OutOfMemory
AnalysisFail

File

zig/AstGen.zig:5130
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
fn unionDeclInner(
    gz: *GenZir,
    scope: *Scope,
    node: Ast.Node.Index,
    members: []const Ast.Node.Index,
    layout: std.lang.Type.ContainerLayout,
    opt_arg_node: Ast.Node.OptionalIndex,
    auto_enum_tok: ?Ast.TokenIndex,
    name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref {
    const astgen = gz.astgen;
    const gpa = astgen.gpa;

    const explicit_int_or_enum_tag = switch (layout) {
        .auto => opt_arg_node != .none,
        .@"extern" => if (opt_arg_node.unwrap()) |arg_node| {
            return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{@tagName(layout)});
        } else false,
        .@"packed" => false,
    };

    if (auto_enum_tok) |t| {
        if (layout != .auto) {
            return astgen.failTok(t, "{s} union does not support enum tag type", .{@tagName(layout)});
        }
    }

    const is_tagged = explicit_int_or_enum_tag or auto_enum_tok != null;

    astgen.advanceSourceCursorToNode(node);

    const decl_inst = try gz.reserveInstructionIndex();
    const src_line = astgen.source_line;
    const src_column = astgen.source_column;

    var namespace: Scope.Namespace = .{
        .parent = scope,
        .node = node,
        .inst = decl_inst,
        .declaring_gz = gz,
        .maybe_generic = astgen.within_fn,
    };
    defer namespace.deinit(gpa);

    // The union_decl instruction introduces a scope in which the decls of the union
    // are in scope, so that field types, alignments, and default value expressions
    // can refer to decls within the union itself.
    var block_scope: GenZir = .{
        .parent = &namespace.base,
        .decl_node_index = node,
        .decl_line = gz.decl_line,
        .astgen = astgen,
        .is_comptime = true,
        .instructions = gz.instructions,
        .instructions_top = gz.instructions.items.len,
    };
    defer block_scope.unstack();

    const scan_result = try astgen.scanContainer(&namespace, members, .@"union");

    var scratch: Scratch = .init(astgen);
    defer scratch.reset();

    // Replicate the structure of the ZIR trailing data in `scratch`
    var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
    const field_names = try scratch.addSlice(scan_result.fields_len);
    const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
    const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
    const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);

    const old_hasher = astgen.src_hasher;
    defer astgen.src_hasher = old_hasher;
    astgen.src_hasher = .init(.{});

    // Before any field bodies comes the tag/backing type, if specified.
    const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: {
        astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
        const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node);
        if (!block_scope.endsWithNoReturn()) {
            _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
        }
        const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
        block_scope.instructions.items.len = block_scope.instructions_top;
        break :len body_len;
    } else null;

    var next_field_idx: u32 = 0;
    for (members) |member_node| {
        var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
            .decl => continue,
            .field => |field| field,
        };
        const field_idx = next_field_idx;
        next_field_idx += 1;

        astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
        member.convertToNonTupleLike(astgen.tree);
        if (member.ast.tuple_like) {
            return astgen.failTok(member.ast.main_token, "union field missing name", .{});
        }
        if (member.comptime_token) |comptime_token| {
            return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
        }

        field_names.get(astgen)[field_idx] = @backingInt(try astgen.identAsString(member.ast.main_token));

        if (member.ast.type_expr.unwrap()) |type_node| {
            const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_type_body_lens.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        } else if (!is_tagged) {
            return astgen.failNode(member_node, "union field missing type", .{});
        } else {
            field_type_body_lens.get(astgen)[field_idx] = 0;
        }

        if (member.ast.align_expr.unwrap()) |align_node| {
            if (layout == .@"packed") {
                return astgen.failNode(align_node, "unable to override alignment of packed union fields", .{});
            }
            const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_align_body_lens.?.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        } else if (field_align_body_lens) |lens| {
            lens.get(astgen)[field_idx] = 0;
        }

        if (member.ast.value_expr.unwrap()) |value_node| {
            if (!explicit_int_or_enum_tag) return astgen.failNodeNotes(
                node,
                "explicitly valued tagged union missing integer tag type",
                .{},
                &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
            );
            if (auto_enum_tok == null) return astgen.failNodeNotes(
                node,
                "explicitly valued tagged union requires inferred enum tag type",
                .{},
                &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
            );
            const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
            const value_ref = try expr(&block_scope, &namespace.base, ri, value_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, value_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_value_body_lens.?.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        } else if (field_value_body_lens) |lens| {
            lens.get(astgen)[field_idx] = 0;
        }
    }
    assert(next_field_idx == scan_result.fields_len);
    wip_decls.finish();

    var fields_hash: std.zig.SrcHash = undefined;
    astgen.src_hasher.final(&fields_hash);

    try gz.setUnion(decl_inst, .{
        .src_line = src_line,
        .src_column = src_column,
        .src_node = node,
        .name_strat = name_strat,
        .kind = switch (layout) {
            .auto => if (auto_enum_tok == null) l: {
                break :l if (opt_arg_node == .none) .auto else .tagged_explicit;
            } else l: {
                break :l if (opt_arg_node == .none) .tagged_enum else .tagged_enum_explicit;
            },
            .@"extern" => .@"extern",
            .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",
        },
        .arg_type_body_len = arg_type_body_len,
        .decls_len = scan_result.decls_len,
        .fields_len = scan_result.fields_len,
        .any_field_aligns = scan_result.any_field_aligns,
        .any_field_values = scan_result.any_field_values,
        .fields_hash = fields_hash,
        .captures = namespace.captures.keys(),
        .capture_names = namespace.captures.values(),
        .remaining = scratch.all().get(astgen),
    });

    block_scope.unstack();
    return decl_inst.toRef();
}