| ... | ... | @@ -493,65 +493,67 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 493 | 493 | }; |
| 494 | 494 | defer block.instructions.deinit(gpa); |
| 495 | 495 | |
| 496 | | // MLUGG TODO: this is fucking ugly bro |
| 497 | | const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: { |
| 498 | | break :ty switch (union_obj.enum_tag_mode) { |
| 499 | | .explicit => .fromInterned(union_obj.enum_tag_type), |
| 500 | | .auto => null, |
| 501 | | }; |
| 502 | | } else ty: { |
| 503 | | const zir_union = sema.code.getUnionDecl(zir_index); |
| 504 | | if (zir_union.kind != .tagged_explicit) { |
| 505 | | break :ty null; // enum tag type will be automatically generated |
| 506 | | } |
| 507 | | // Explicitly specified, so evaluate the enum tag type expression. |
| 508 | | const tag_type_body = zir_union.arg_type_body.?; |
| 509 | | const tag_type_src = block.src(.container_arg); |
| 510 | | block.comptime_reason = .{ .reason = .{ |
| 511 | | .src = tag_type_src, |
| 512 | | .r = .{ .simple = .union_enum_tag_type }, |
| 513 | | } }; |
| 514 | | const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index); |
| 515 | | break :ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref); |
| 516 | | }; |
| 517 | | const enum_tag_ty: Type = if (explicit_enum_tag_ty) |enum_tag_ty| ty: { |
| 518 | | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail( |
| 519 | | &block, |
| 520 | | block.src(.container_arg), |
| 521 | | "expected enum tag type, found '{f}'", |
| 522 | | .{enum_tag_ty.fmt(pt)}, |
| 523 | | ); |
| 524 | | break :ty enum_tag_ty; |
| 525 | | } else switch (try ip.getGeneratedEnumTagType(gpa, io, pt.tid, .{ |
| 526 | | .union_type = union_ty.toIntern(), |
| 527 | | // MLUGG TODO: a bit hacky icl |
| 528 | | .int_tag_mode = mode: { |
| 529 | | if (union_obj.is_reified) break :mode .auto; |
| 530 | | const zir_union = sema.code.getUnionDecl(zir_index); |
| 531 | | if (zir_union.kind != .tagged_enum_explicit) break :mode .auto; |
| 532 | | break :mode .explicit; |
| 496 | const enum_tag_ty: Type = switch (union_obj.enum_tag_mode) { |
| 497 | .explicit => validated_tag_ty: { |
| 498 | // If the union is reified, its enum tag type is already populated. If the union is |
| 499 | // declared, we need to evaluate the enum tag type expression (the `E` in `union(E)`). |
| 500 | const tag_ty: Type = switch (union_obj.is_reified) { |
| 501 | true => .fromInterned(union_obj.enum_tag_type), |
| 502 | false => tag_ty: { |
| 503 | const zir_union = sema.code.getUnionDecl(zir_index); |
| 504 | assert(zir_union.kind == .tagged_explicit); // `Zcu.mapOldZirToNew` guarantees that the ZIR mapping preserves `kind` |
| 505 | const tag_type_body = zir_union.arg_type_body.?; |
| 506 | const tag_type_src = block.src(.container_arg); |
| 507 | block.comptime_reason = .{ .reason = .{ |
| 508 | .src = tag_type_src, |
| 509 | .r = .{ .simple = .union_enum_tag_type }, |
| 510 | } }; |
| 511 | const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index); |
| 512 | break :tag_ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref); |
| 513 | }, |
| 514 | }; |
| 515 | // Because the type is explicitly specified, we need to validate it. |
| 516 | if (tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail( |
| 517 | &block, |
| 518 | block.src(.container_arg), |
| 519 | "expected enum tag type, found '{f}'", |
| 520 | .{tag_ty.fmt(pt)}, |
| 521 | ); |
| 522 | break :validated_tag_ty tag_ty; |
| 533 | 523 | }, |
| 534 | | .fields_len = @intCast(union_obj.field_types.len), |
| 535 | | })) { |
| 536 | | .existing => |tag_ty| .fromInterned(tag_ty), |
| 537 | | .wip => |wip| tag_ty: { |
| 538 | | errdefer wip.cancel(ip, pt.tid); |
| 539 | | _ = wip.setName(ip, try ip.getOrPutStringFmt( |
| 540 | | gpa, |
| 541 | | io, |
| 542 | | pt.tid, |
| 543 | | "@typeInfo({f}).@\"union\".tag_type.?", |
| 544 | | .{union_obj.name.fmt(ip)}, |
| 545 | | .no_embedded_nulls, |
| 546 | | ), .none); |
| 547 | | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ |
| 548 | | .parent = union_obj.namespace.toOptional(), |
| 549 | | .owner_type = wip.index, |
| 550 | | .file_scope = zcu.namespacePtr(union_obj.namespace).file_scope, |
| 551 | | .generation = zcu.generation, |
| 552 | | }); |
| 553 | | if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 554 | | break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 524 | // If no tag type was specified, we generate one keyed on this union type. |
| 525 | .auto => switch (try ip.getGeneratedEnumTagType(gpa, io, pt.tid, .{ |
| 526 | .union_type = union_ty.toIntern(), |
| 527 | // The int tag for this enum is usually inferred---the exception is `union(enum(T))`. |
| 528 | .int_tag_mode = switch (union_obj.is_reified) { |
| 529 | true => .auto, |
| 530 | false => switch (sema.code.getUnionDecl(zir_index).kind) { |
| 531 | .tagged_enum_explicit => .auto, |
| 532 | else => .explicit, |
| 533 | }, |
| 534 | }, |
| 535 | .fields_len = @intCast(union_obj.field_types.len), |
| 536 | })) { |
| 537 | .existing => |tag_ty| .fromInterned(tag_ty), |
| 538 | .wip => |wip| tag_ty: { |
| 539 | errdefer wip.cancel(ip, pt.tid); |
| 540 | _ = wip.setName(ip, try ip.getOrPutStringFmt( |
| 541 | gpa, |
| 542 | io, |
| 543 | pt.tid, |
| 544 | "@typeInfo({f}).@\"union\".tag_type.?", |
| 545 | .{union_obj.name.fmt(ip)}, |
| 546 | .no_embedded_nulls, |
| 547 | ), .none); |
| 548 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ |
| 549 | .parent = union_obj.namespace.toOptional(), |
| 550 | .owner_type = wip.index, |
| 551 | .file_scope = zcu.namespacePtr(union_obj.namespace).file_scope, |
| 552 | .generation = zcu.generation, |
| 553 | }); |
| 554 | if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 555 | break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 556 | }, |
| 555 | 557 | }, |
| 556 | 558 | }; |
| 557 | 559 | |