mirror of
https://github.com/ziglang/zig.git
synced 2026-01-02 11:33:21 +00:00
stage2: implement field access for Enum.tag syntax
This commit is contained in:
parent
2adeace905
commit
acf9151008
104
src/Sema.zig
104
src/Sema.zig
@ -4351,22 +4351,25 @@ fn namedFieldPtr(
|
||||
field_name: []const u8,
|
||||
field_name_src: LazySrcLoc,
|
||||
) InnerError!*Inst {
|
||||
const mod = sema.mod;
|
||||
const arena = sema.arena;
|
||||
|
||||
const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
|
||||
.Pointer => object_ptr.ty.elemType(),
|
||||
else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
|
||||
else => return mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
|
||||
};
|
||||
switch (elem_ty.zigTypeTag()) {
|
||||
.Array => {
|
||||
if (mem.eql(u8, field_name, "len")) {
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
return mod.constInst(arena, src, .{
|
||||
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
sema.arena,
|
||||
try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),
|
||||
arena,
|
||||
try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
return sema.mod.fail(
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
field_name_src,
|
||||
"no member named '{s}' in '{}'",
|
||||
@ -4379,15 +4382,15 @@ fn namedFieldPtr(
|
||||
switch (ptr_child.zigTypeTag()) {
|
||||
.Array => {
|
||||
if (mem.eql(u8, field_name, "len")) {
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
return mod.constInst(arena, src, .{
|
||||
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
sema.arena,
|
||||
try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),
|
||||
arena,
|
||||
try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
return sema.mod.fail(
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
field_name_src,
|
||||
"no member named '{s}' in '{}'",
|
||||
@ -4402,7 +4405,7 @@ fn namedFieldPtr(
|
||||
_ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
|
||||
const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
|
||||
const val = result.value().?;
|
||||
const child_type = try val.toType(sema.arena);
|
||||
const child_type = try val.toType(arena);
|
||||
switch (child_type.zigTypeTag()) {
|
||||
.ErrorSet => {
|
||||
// TODO resolve inferred error sets
|
||||
@ -4416,42 +4419,87 @@ fn namedFieldPtr(
|
||||
break :blk name;
|
||||
}
|
||||
}
|
||||
return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
|
||||
return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
|
||||
field_name,
|
||||
child_type,
|
||||
});
|
||||
} else (try sema.mod.getErrorValue(field_name)).key;
|
||||
} else (try mod.getErrorValue(field_name)).key;
|
||||
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),
|
||||
return mod.constInst(arena, src, .{
|
||||
.ty = try mod.simplePtrType(arena, child_type, false, .One),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
sema.arena,
|
||||
try Value.Tag.@"error".create(sema.arena, .{
|
||||
arena,
|
||||
try Value.Tag.@"error".create(arena, .{
|
||||
.name = name,
|
||||
}),
|
||||
),
|
||||
});
|
||||
},
|
||||
.Struct => {
|
||||
const container_scope = child_type.getContainerScope();
|
||||
if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
|
||||
// TODO if !decl.is_pub and inDifferentFiles() "{} is private"
|
||||
return sema.analyzeDeclRef(block, src, decl);
|
||||
}
|
||||
.Struct, .Opaque, .Union => {
|
||||
if (child_type.getContainerScope()) |container_scope| {
|
||||
if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
|
||||
// TODO if !decl.is_pub and inDifferentFiles() "{} is private"
|
||||
return sema.analyzeDeclRef(block, src, decl);
|
||||
}
|
||||
|
||||
if (container_scope.file_scope == sema.mod.root_scope) {
|
||||
return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
|
||||
} else {
|
||||
return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
|
||||
// TODO this will give false positives for structs inside the root file
|
||||
if (container_scope.file_scope == mod.root_scope) {
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
src,
|
||||
"root source file has no member named '{s}'",
|
||||
.{field_name},
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO add note: declared here
|
||||
const kw_name = switch (child_type.zigTypeTag()) {
|
||||
.Struct => "struct",
|
||||
.Opaque => "opaque",
|
||||
.Union => "union",
|
||||
else => unreachable,
|
||||
};
|
||||
return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
|
||||
kw_name, child_type, field_name,
|
||||
});
|
||||
},
|
||||
else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
|
||||
.Enum => {
|
||||
if (child_type.getContainerScope()) |container_scope| {
|
||||
if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
|
||||
// TODO if !decl.is_pub and inDifferentFiles() "{} is private"
|
||||
return sema.analyzeDeclRef(block, src, decl);
|
||||
}
|
||||
}
|
||||
const maybe_field_index: ?usize = switch (child_type.tag()) {
|
||||
.enum_full, .enum_nonexhaustive => blk: {
|
||||
const enum_full = child_type.castTag(.enum_full).?.data;
|
||||
break :blk enum_full.fields.getIndex(field_name);
|
||||
},
|
||||
.enum_simple => blk: {
|
||||
const enum_simple = child_type.castTag(.enum_simple).?.data;
|
||||
break :blk enum_simple.fields.getIndex(field_name);
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const field_index = maybe_field_index orelse {
|
||||
return mod.fail(&block.base, src, "enum '{}' has no member named '{s}'", .{
|
||||
child_type, field_name,
|
||||
});
|
||||
};
|
||||
const field_index_u32 = @intCast(u32, field_index);
|
||||
const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
|
||||
return mod.constInst(arena, src, .{
|
||||
.ty = try mod.simplePtrType(arena, child_type, false, .One),
|
||||
.val = try Value.Tag.ref_val.create(arena, enum_val),
|
||||
});
|
||||
},
|
||||
else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
|
||||
}
|
||||
},
|
||||
.Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
|
||||
else => {},
|
||||
}
|
||||
return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
|
||||
return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
|
||||
}
|
||||
|
||||
fn analyzeStructFieldPtr(
|
||||
|
||||
26
src/type.zig
26
src/type.zig
@ -634,13 +634,13 @@ pub const Type = extern union {
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Type,
|
||||
start_type: Type,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
comptime assert(fmt.len == 0);
|
||||
var ty = self;
|
||||
var ty = start_type;
|
||||
while (true) {
|
||||
const t = ty.tag();
|
||||
switch (t) {
|
||||
@ -687,15 +687,15 @@ pub const Type = extern union {
|
||||
.empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
|
||||
|
||||
.@"struct" => {
|
||||
const struct_obj = self.castTag(.@"struct").?.data;
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
return struct_obj.owner_decl.renderFullyQualifiedName(writer);
|
||||
},
|
||||
.enum_full, .enum_nonexhaustive => {
|
||||
const enum_full = self.castTag(.enum_full).?.data;
|
||||
const enum_full = ty.castTag(.enum_full).?.data;
|
||||
return enum_full.owner_decl.renderFullyQualifiedName(writer);
|
||||
},
|
||||
.enum_simple => {
|
||||
const enum_simple = self.castTag(.enum_simple).?.data;
|
||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||
return enum_simple.owner_decl.renderFullyQualifiedName(writer);
|
||||
},
|
||||
.@"opaque" => {
|
||||
@ -1886,8 +1886,8 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn onePossibleValue(self: Type) ?Value {
|
||||
var ty = self;
|
||||
pub fn onePossibleValue(starting_type: Type) ?Value {
|
||||
var ty = starting_type;
|
||||
while (true) switch (ty.tag()) {
|
||||
.f16,
|
||||
.f32,
|
||||
@ -1954,7 +1954,7 @@ pub const Type = extern union {
|
||||
return Value.initTag(.empty_struct_value);
|
||||
},
|
||||
.enum_full => {
|
||||
const enum_full = self.castTag(.enum_full).?.data;
|
||||
const enum_full = ty.castTag(.enum_full).?.data;
|
||||
if (enum_full.fields.count() == 1) {
|
||||
return enum_full.values.entries.items[0].key;
|
||||
} else {
|
||||
@ -1962,14 +1962,14 @@ pub const Type = extern union {
|
||||
}
|
||||
},
|
||||
.enum_simple => {
|
||||
const enum_simple = self.castTag(.enum_simple).?.data;
|
||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||
if (enum_simple.fields.count() == 1) {
|
||||
return Value.initTag(.zero);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
.enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty.onePossibleValue(),
|
||||
.enum_nonexhaustive => ty = ty.castTag(.enum_full).?.data.tag_ty,
|
||||
|
||||
.empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
|
||||
.void => return Value.initTag(.void_value),
|
||||
@ -2016,15 +2016,15 @@ pub const Type = extern union {
|
||||
(self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
|
||||
}
|
||||
|
||||
/// Asserts that the type is a container. (note: ErrorSet is not a container).
|
||||
pub fn getContainerScope(self: Type) *Module.Scope.Container {
|
||||
/// Returns null if the type has no container.
|
||||
pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
|
||||
return switch (self.tag()) {
|
||||
.@"struct" => &self.castTag(.@"struct").?.data.container,
|
||||
.enum_full => &self.castTag(.enum_full).?.data.container,
|
||||
.empty_struct => self.castTag(.empty_struct).?.data,
|
||||
.@"opaque" => &self.castTag(.@"opaque").?.data,
|
||||
|
||||
else => unreachable,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1572,6 +1572,7 @@ const Writer = struct {
|
||||
.intcast,
|
||||
.store,
|
||||
.store_to_block_ptr,
|
||||
.store_to_inferred_ptr,
|
||||
=> try self.writeBin(stream, inst),
|
||||
|
||||
.alloc,
|
||||
@ -1769,7 +1770,6 @@ const Writer = struct {
|
||||
|
||||
.bitcast,
|
||||
.bitcast_result_ptr,
|
||||
.store_to_inferred_ptr,
|
||||
=> try stream.writeAll("TODO)"),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user