aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig135
1 files changed, 123 insertions, 12 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index eca73a88e2..b65e88360f 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -5799,8 +5799,12 @@ fn zirSwitchCond(
) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
+ const operand_src = src; // TODO make this point at the switch operand
const operand_ptr = sema.resolveInst(inst_data.operand);
- const operand = if (is_ref) try sema.analyzeLoad(block, src, operand_ptr, src) else operand_ptr;
+ const operand = if (is_ref)
+ try sema.analyzeLoad(block, src, operand_ptr, operand_src)
+ else
+ operand_ptr;
const operand_ty = sema.typeOf(operand);
switch (operand_ty.zigTypeTag()) {
@@ -5817,18 +5821,19 @@ fn zirSwitchCond(
.ErrorSet,
.Enum,
=> {
- if ((try sema.typeHasOnePossibleValue(block, src, operand_ty))) |opv| {
+ if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
return sema.addConstant(operand_ty, opv);
}
return operand;
},
.Union => {
- const enum_ty = operand_ty.unionTagType() orelse {
+ const union_ty = try sema.resolveTypeFields(block, operand_src, operand_ty);
+ const enum_ty = union_ty.unionTagType() orelse {
const msg = msg: {
const msg = try sema.errMsg(block, src, "switch on untagged union", .{});
errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, operand_ty);
+ try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -9154,9 +9159,107 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}),
);
},
+ .Union => {
+ // TODO: look into memoizing this result.
+
+ var fields_anon_decl = try block.startAnonDecl();
+ defer fields_anon_decl.deinit();
+
+ const union_field_ty = t: {
+ const union_field_ty_decl = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespace().?,
+ "UnionField",
+ )).?;
+ try sema.mod.declareDeclDependency(sema.owner_decl, union_field_ty_decl);
+ try sema.ensureDeclAnalyzed(union_field_ty_decl);
+ var buffer: Value.ToTypeBuffer = undefined;
+ break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
+ };
+
+ const union_ty = try sema.resolveTypeFields(block, src, ty);
+ const union_fields = union_ty.unionFields();
+ const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
+
+ for (union_field_vals) |*field_val, i| {
+ const field = union_fields.values()[i];
+ const name = union_fields.keys()[i];
+ const name_val = v: {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl = try anon_decl.finish(
+ try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
+ try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ );
+ break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
+ };
+
+ const union_field_fields = try fields_anon_decl.arena().create([3]Value);
+ union_field_fields.* = .{
+ // name: []const u8,
+ name_val,
+ // field_type: type,
+ try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
+ // alignment: comptime_int,
+ try field.abi_align.copy(fields_anon_decl.arena()),
+ };
+ field_val.* = try Value.Tag.@"struct".create(fields_anon_decl.arena(), union_field_fields);
+ }
+
+ const fields_val = v: {
+ const new_decl = try fields_anon_decl.finish(
+ try Type.Tag.array.create(fields_anon_decl.arena(), .{
+ .len = union_field_vals.len,
+ .elem_type = union_field_ty,
+ }),
+ try Value.Tag.array.create(
+ fields_anon_decl.arena(),
+ try fields_anon_decl.arena().dupe(Value, union_field_vals),
+ ),
+ );
+ break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
+ };
+
+ if (ty.getNamespace()) |namespace| {
+ if (namespace.decls.count() != 0) {
+ return sema.fail(block, src, "TODO: implement zirTypeInfo for Union which has declarations", .{});
+ }
+ }
+ const decls_val = Value.initTag(.empty_array);
+
+ const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
+ const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
+ break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
+ } else Value.@"null";
+
+ const field_values = try sema.arena.create([4]Value);
+ field_values.* = .{
+ // layout: ContainerLayout,
+ try Value.Tag.enum_field_index.create(
+ sema.arena,
+ @enumToInt(std.builtin.TypeInfo.ContainerLayout.Auto),
+ ),
+
+ // tag_type: ?type,
+ enum_tag_ty_val,
+ // fields: []const UnionField,
+ fields_val,
+ // decls: []const Declaration,
+ decls_val,
+ };
+
+ return sema.addConstant(
+ type_info_ty,
+ try Value.Tag.@"union".create(sema.arena, .{
+ .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)),
+ .val = try Value.Tag.@"struct".create(sema.arena, field_values),
+ }),
+ );
+ },
.Struct => return sema.fail(block, src, "TODO: implement zirTypeInfo for Struct", .{}),
.ErrorSet => return sema.fail(block, src, "TODO: implement zirTypeInfo for ErrorSet", .{}),
- .Union => return sema.fail(block, src, "TODO: implement zirTypeInfo for Union", .{}),
.BoundFn => @panic("TODO remove this type from the language and compiler"),
.Opaque => return sema.fail(block, src, "TODO: implement zirTypeInfo for Opaque", .{}),
.Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}),
@@ -11847,12 +11950,14 @@ fn fieldVal(
);
},
.Union => {
- if (child_type.getNamespace()) |namespace| {
+ const union_ty = try sema.resolveTypeFields(block, src, child_type);
+
+ if (union_ty.getNamespace()) |namespace| {
if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
return inst;
}
}
- if (child_type.unionTagType()) |enum_ty| {
+ if (union_ty.unionTagType()) |enum_ty| {
if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
const field_index = @intCast(u32, field_index_usize);
return sema.addConstant(
@@ -11861,7 +11966,7 @@ fn fieldVal(
);
}
}
- return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
+ return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name);
},
.Enum => {
if (child_type.getNamespace()) |namespace| {
@@ -15185,8 +15290,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
// The provided type is an integer type and we must construct the enum tag type here.
int_tag_ty = provided_ty;
union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty);
- enum_field_names = &union_obj.tag_ty.castTag(.enum_numbered).?.data.fields;
- enum_value_map = &union_obj.tag_ty.castTag(.enum_numbered).?.data.values;
+ const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
+ enum_field_names = &enum_obj.fields;
+ enum_value_map = &enum_obj.values;
} else {
// The provided type is the enum tag type.
union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
@@ -15239,14 +15345,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
const tag_ref: Zir.Inst.Ref = if (has_tag) blk: {
const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
extra_index += 1;
- break :blk tag_ref;
+ break :blk sema.resolveInst(tag_ref);
} else .none;
if (enum_value_map) |map| {
const tag_src = src; // TODO better source location
const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, tag_src);
const val = try sema.resolveConstValue(&block_scope, tag_src, coerced);
- map.putAssumeCapacityContext(val, {}, .{ .ty = int_tag_ty });
+
+ // This puts the memory into the union arena, not the enum arena, but
+ // it is OK since they share the same lifetime.
+ const copied_val = try val.copy(decl_arena_allocator);
+
+ map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty });
}
// This string needs to outlive the ZIR code.