Sema: implement @typeInfo for list literals

This commit is contained in:
Andrew Kelley 2022-02-19 15:02:50 -07:00
parent b0cdd3d0e6
commit 746435a954
3 changed files with 93 additions and 47 deletions

View File

@ -4192,12 +4192,12 @@ fn analyzeCall(
.auto,
.always_inline,
.compile_time,
.no_async,
=> {},
.async_kw,
.never_tail,
.never_inline,
.no_async,
.always_tail,
=> return sema.fail(block, call_src, "TODO implement call with modifier {}", .{
modifier,
@ -10035,51 +10035,93 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
var buffer: Value.ToTypeBuffer = undefined;
break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
};
const struct_ty = try sema.resolveTypeFields(block, src, ty);
const struct_fields = struct_ty.structFields();
const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count());
const layout = struct_ty.containerLayout();
for (struct_field_vals) |*field_val, i| {
const field = struct_fields.values()[i];
const name = struct_fields.keys()[i];
const name_val = v: {
var anon_decl = try block.startAnonDecl(src);
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 struct_field_vals = fv: {
if (struct_ty.castTag(.tuple)) |payload| {
const field_types = payload.data.types;
const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);
for (struct_field_vals) |*struct_field_val, i| {
const field_ty = field_types[i];
const name_val = v: {
var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const bytes = try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i});
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 struct_field_fields = try fields_anon_decl.arena().create([5]Value);
const opt_default_val = if (field.default_val.tag() == .unreachable_value)
null
else
field.default_val;
const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
const alignment = switch (layout) {
.Auto, .Extern => field.normalAlignment(target),
.Packed => field.packedAlignment(),
};
const struct_field_fields = try fields_anon_decl.arena().create([5]Value);
const field_val = payload.data.values[i];
const is_comptime = field_val.tag() != .unreachable_value;
const opt_default_val = if (is_comptime) field_val else null;
const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val);
const alignment = field_ty.abiAlignment(target);
struct_field_fields.* = .{
// name: []const u8,
name_val,
// field_type: type,
try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
// default_value: ?*const anyopaque,
try default_val_ptr.copy(fields_anon_decl.arena()),
// is_comptime: bool,
Value.makeBool(field.is_comptime),
// alignment: comptime_int,
try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
};
field_val.* = try Value.Tag.@"struct".create(fields_anon_decl.arena(), struct_field_fields);
}
struct_field_fields.* = .{
// name: []const u8,
name_val,
// field_type: type,
try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty),
// default_value: ?*const anyopaque,
try default_val_ptr.copy(fields_anon_decl.arena()),
// is_comptime: bool,
Value.makeBool(is_comptime),
// alignment: comptime_int,
try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
};
struct_field_val.* = try Value.Tag.@"struct".create(fields_anon_decl.arena(), struct_field_fields);
}
break :fv struct_field_vals;
}
const struct_fields = struct_ty.structFields();
const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count());
for (struct_field_vals) |*field_val, i| {
const field = struct_fields.values()[i];
const name = struct_fields.keys()[i];
const name_val = v: {
var anon_decl = try block.startAnonDecl(src);
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 struct_field_fields = try fields_anon_decl.arena().create([5]Value);
const opt_default_val = if (field.default_val.tag() == .unreachable_value)
null
else
field.default_val;
const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
const alignment = switch (layout) {
.Auto, .Extern => field.normalAlignment(target),
.Packed => field.packedAlignment(),
};
struct_field_fields.* = .{
// name: []const u8,
name_val,
// field_type: type,
try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
// default_value: ?*const anyopaque,
try default_val_ptr.copy(fields_anon_decl.arena()),
// is_comptime: bool,
Value.makeBool(field.is_comptime),
// alignment: comptime_int,
try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
};
field_val.* = try Value.Tag.@"struct".create(fields_anon_decl.arena(), struct_field_fields);
}
break :fv struct_field_vals;
};
const fields_val = v: {
const new_decl = try fields_anon_decl.finish(

View File

@ -2031,21 +2031,21 @@ pub const Type = extern union {
.empty_struct,
.void,
.anyopaque,
=> return 0,
.empty_struct_literal,
.type,
.comptime_int,
.comptime_float,
.noreturn,
.@"null",
.@"undefined",
.enum_literal,
.type_info,
=> return 0,
.noreturn,
.inferred_alloc_const,
.inferred_alloc_mut,
.@"opaque",
.var_args_param,
.type_info,
.bound_fn,
=> unreachable,
@ -4782,6 +4782,7 @@ pub const Type = extern union {
base: Payload = .{ .tag = .tuple },
data: struct {
types: []Type,
/// unreachable_value elements are used to indicate runtime-known.
values: []Value,
},
};

View File

@ -454,10 +454,13 @@ test "Declarations are returned in declaration order" {
try expect(std.mem.eql(u8, d[4].name, "e"));
}
test "Struct.is_tuple" {
test "Struct.is_tuple for anon list literal" {
try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
}
test "Struct.is_tuple for anon struct literal" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
}