aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-06 22:36:28 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-06 22:36:28 -0700
commitacf9151008d5a97e5d91b34cc29f73af79062b48 (patch)
treec6c9d3e4b1560dfe45b73880c0036965785357b1 /src/Sema.zig
parent2adeace905d6c36e3a333647c21287493ab98485 (diff)
downloadzig-acf9151008d5a97e5d91b34cc29f73af79062b48.tar.gz
zig-acf9151008d5a97e5d91b34cc29f73af79062b48.zip
stage2: implement field access for `Enum.tag` syntax
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig104
1 files changed, 76 insertions, 28 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 771da877b4..8ff71ce8f2 100644
--- a/src/Sema.zig
+++ b/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,
+ });
+ },
+ .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 sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
+ 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(