authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-06 22:36:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-06 22:36:28-07:00
logacf9151008d5a97e5d91b34cc29f73af79062b48
treec6c9d3e4b1560dfe45b73880c0036965785357b1
parent2adeace905d6c36e3a333647c21287493ab98485

stage2: implement field access for `Enum.tag` syntax


3 files changed, 90 insertions(+), 42 deletions(-)

src/Sema.zig+76-28
......@@ -4351,22 +4351,25 @@ fn namedFieldPtr(
43514351 field_name: []const u8,
43524352 field_name_src: LazySrcLoc,
43534353) InnerError!*Inst {
4354 const mod = sema.mod;
4355 const arena = sema.arena;
4356
43544357 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
43554358 .Pointer => object_ptr.ty.elemType(),
4356 else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
4359 else => return mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
43574360 };
43584361 switch (elem_ty.zigTypeTag()) {
43594362 .Array => {
43604363 if (mem.eql(u8, field_name, "len")) {
4361 return sema.mod.constInst(sema.arena, src, .{
4364 return mod.constInst(arena, src, .{
43624365 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
43634366 .val = try Value.Tag.ref_val.create(
4364 sema.arena,
4365 try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),
4367 arena,
4368 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
43664369 ),
43674370 });
43684371 } else {
4369 return sema.mod.fail(
4372 return mod.fail(
43704373 &block.base,
43714374 field_name_src,
43724375 "no member named '{s}' in '{}'",
......@@ -4379,15 +4382,15 @@ fn namedFieldPtr(
43794382 switch (ptr_child.zigTypeTag()) {
43804383 .Array => {
43814384 if (mem.eql(u8, field_name, "len")) {
4382 return sema.mod.constInst(sema.arena, src, .{
4385 return mod.constInst(arena, src, .{
43834386 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
43844387 .val = try Value.Tag.ref_val.create(
4385 sema.arena,
4386 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),
4388 arena,
4389 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
43874390 ),
43884391 });
43894392 } else {
4390 return sema.mod.fail(
4393 return mod.fail(
43914394 &block.base,
43924395 field_name_src,
43934396 "no member named '{s}' in '{}'",
......@@ -4402,7 +4405,7 @@ fn namedFieldPtr(
44024405 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
44034406 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
44044407 const val = result.value().?;
4405 const child_type = try val.toType(sema.arena);
4408 const child_type = try val.toType(arena);
44064409 switch (child_type.zigTypeTag()) {
44074410 .ErrorSet => {
44084411 // TODO resolve inferred error sets
......@@ -4416,42 +4419,87 @@ fn namedFieldPtr(
44164419 break :blk name;
44174420 }
44184421 }
4419 return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
4422 return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
44204423 field_name,
44214424 child_type,
44224425 });
4423 } else (try sema.mod.getErrorValue(field_name)).key;
4426 } else (try mod.getErrorValue(field_name)).key;
44244427
4425 return sema.mod.constInst(sema.arena, src, .{
4426 .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),
4428 return mod.constInst(arena, src, .{
4429 .ty = try mod.simplePtrType(arena, child_type, false, .One),
44274430 .val = try Value.Tag.ref_val.create(
4428 sema.arena,
4429 try Value.Tag.@"error".create(sema.arena, .{
4431 arena,
4432 try Value.Tag.@"error".create(arena, .{
44304433 .name = name,
44314434 }),
44324435 ),
44334436 });
44344437 },
4435 .Struct => {
4436 const container_scope = child_type.getContainerScope();
4437 if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4438 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4439 return sema.analyzeDeclRef(block, src, decl);
4440 }
4438 .Struct, .Opaque, .Union => {
4439 if (child_type.getContainerScope()) |container_scope| {
4440 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4441 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4442 return sema.analyzeDeclRef(block, src, decl);
4443 }
44414444
4442 if (container_scope.file_scope == sema.mod.root_scope) {
4443 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
4444 } else {
4445 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
4445 // TODO this will give false positives for structs inside the root file
4446 if (container_scope.file_scope == mod.root_scope) {
4447 return mod.fail(
4448 &block.base,
4449 src,
4450 "root source file has no member named '{s}'",
4451 .{field_name},
4452 );
4453 }
4454 }
4455 // TODO add note: declared here
4456 const kw_name = switch (child_type.zigTypeTag()) {
4457 .Struct => "struct",
4458 .Opaque => "opaque",
4459 .Union => "union",
4460 else => unreachable,
4461 };
4462 return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
4463 kw_name, child_type, field_name,
4464 });
4465 },
4466 .Enum => {
4467 if (child_type.getContainerScope()) |container_scope| {
4468 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4469 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4470 return sema.analyzeDeclRef(block, src, decl);
4471 }
44464472 }
4473 const maybe_field_index: ?usize = switch (child_type.tag()) {
4474 .enum_full, .enum_nonexhaustive => blk: {
4475 const enum_full = child_type.castTag(.enum_full).?.data;
4476 break :blk enum_full.fields.getIndex(field_name);
4477 },
4478 .enum_simple => blk: {
4479 const enum_simple = child_type.castTag(.enum_simple).?.data;
4480 break :blk enum_simple.fields.getIndex(field_name);
4481 },
4482 else => unreachable,
4483 };
4484 const field_index = maybe_field_index orelse {
4485 return mod.fail(&block.base, src, "enum '{}' has no member named '{s}'", .{
4486 child_type, field_name,
4487 });
4488 };
4489 const field_index_u32 = @intCast(u32, field_index);
4490 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
4491 return mod.constInst(arena, src, .{
4492 .ty = try mod.simplePtrType(arena, child_type, false, .One),
4493 .val = try Value.Tag.ref_val.create(arena, enum_val),
4494 });
44474495 },
4448 else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
4496 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
44494497 }
44504498 },
44514499 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
44524500 else => {},
44534501 }
4454 return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
4502 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
44554503}
44564504
44574505fn analyzeStructFieldPtr(
src/type.zig+13-13
......@@ -634,13 +634,13 @@ pub const Type = extern union {
634634 }
635635
636636 pub fn format(
637 self: Type,
637 start_type: Type,
638638 comptime fmt: []const u8,
639639 options: std.fmt.FormatOptions,
640640 writer: anytype,
641641 ) @TypeOf(writer).Error!void {
642642 comptime assert(fmt.len == 0);
643 var ty = self;
643 var ty = start_type;
644644 while (true) {
645645 const t = ty.tag();
646646 switch (t) {
......@@ -687,15 +687,15 @@ pub const Type = extern union {
687687 .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
688688
689689 .@"struct" => {
690 const struct_obj = self.castTag(.@"struct").?.data;
690 const struct_obj = ty.castTag(.@"struct").?.data;
691691 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
692692 },
693693 .enum_full, .enum_nonexhaustive => {
694 const enum_full = self.castTag(.enum_full).?.data;
694 const enum_full = ty.castTag(.enum_full).?.data;
695695 return enum_full.owner_decl.renderFullyQualifiedName(writer);
696696 },
697697 .enum_simple => {
698 const enum_simple = self.castTag(.enum_simple).?.data;
698 const enum_simple = ty.castTag(.enum_simple).?.data;
699699 return enum_simple.owner_decl.renderFullyQualifiedName(writer);
700700 },
701701 .@"opaque" => {
......@@ -1886,8 +1886,8 @@ pub const Type = extern union {
18861886 };
18871887 }
18881888
1889 pub fn onePossibleValue(self: Type) ?Value {
1890 var ty = self;
1889 pub fn onePossibleValue(starting_type: Type) ?Value {
1890 var ty = starting_type;
18911891 while (true) switch (ty.tag()) {
18921892 .f16,
18931893 .f32,
......@@ -1954,7 +1954,7 @@ pub const Type = extern union {
19541954 return Value.initTag(.empty_struct_value);
19551955 },
19561956 .enum_full => {
1957 const enum_full = self.castTag(.enum_full).?.data;
1957 const enum_full = ty.castTag(.enum_full).?.data;
19581958 if (enum_full.fields.count() == 1) {
19591959 return enum_full.values.entries.items[0].key;
19601960 } else {
......@@ -1962,14 +1962,14 @@ pub const Type = extern union {
19621962 }
19631963 },
19641964 .enum_simple => {
1965 const enum_simple = self.castTag(.enum_simple).?.data;
1965 const enum_simple = ty.castTag(.enum_simple).?.data;
19661966 if (enum_simple.fields.count() == 1) {
19671967 return Value.initTag(.zero);
19681968 } else {
19691969 return null;
19701970 }
19711971 },
1972 .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty.onePossibleValue(),
1972 .enum_nonexhaustive => ty = ty.castTag(.enum_full).?.data.tag_ty,
19731973
19741974 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
19751975 .void => return Value.initTag(.void_value),
......@@ -2016,15 +2016,15 @@ pub const Type = extern union {
20162016 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
20172017 }
20182018
2019 /// Asserts that the type is a container. (note: ErrorSet is not a container).
2020 pub fn getContainerScope(self: Type) *Module.Scope.Container {
2019 /// Returns null if the type has no container.
2020 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
20212021 return switch (self.tag()) {
20222022 .@"struct" => &self.castTag(.@"struct").?.data.container,
20232023 .enum_full => &self.castTag(.enum_full).?.data.container,
20242024 .empty_struct => self.castTag(.empty_struct).?.data,
20252025 .@"opaque" => &self.castTag(.@"opaque").?.data,
20262026
2027 else => unreachable,
2027 else => null,
20282028 };
20292029 }
20302030
src/zir.zig+1-1
......@@ -1572,6 +1572,7 @@ const Writer = struct {
15721572 .intcast,
15731573 .store,
15741574 .store_to_block_ptr,
1575 .store_to_inferred_ptr,
15751576 => try self.writeBin(stream, inst),
15761577
15771578 .alloc,
......@@ -1769,7 +1770,6 @@ const Writer = struct {
17691770
17701771 .bitcast,
17711772 .bitcast_result_ptr,
1772 .store_to_inferred_ptr,
17731773 => try stream.writeAll("TODO)"),
17741774 }
17751775 }