diff options
| -rw-r--r-- | src/Sema.zig | 104 | ||||
| -rw-r--r-- | src/type.zig | 26 | ||||
| -rw-r--r-- | src/zir.zig | 2 |
3 files changed, 90 insertions, 42 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( diff --git a/src/type.zig b/src/type.zig index c338072c15..576dc46e7e 100644 --- a/src/type.zig +++ b/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, }; } diff --git a/src/zir.zig b/src/zir.zig index e63d36bced..00ff23acb0 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -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)"), } } |
