Commit e2cf2e015b

Vexu <git@vexu.eu>
2020-09-09 16:59:13
stage2: struct type field access
1 parent 7d910b0
Changed files (2)
src/type.zig
@@ -441,7 +441,7 @@ pub const Type = extern union {
             },
             .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
             .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),
-            .empty_struct  => return self.copyPayloadShallow(allocator, Payload.EmptyStruct),
+            .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct),
         }
     }
 
@@ -2789,6 +2789,80 @@ 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 {
+        return switch (self.tag()) {
+            .f16,
+            .f32,
+            .f64,
+            .f128,
+            .c_longdouble,
+            .comptime_int,
+            .comptime_float,
+            .u8,
+            .i8,
+            .u16,
+            .i16,
+            .u32,
+            .i32,
+            .u64,
+            .i64,
+            .usize,
+            .isize,
+            .c_short,
+            .c_ushort,
+            .c_int,
+            .c_uint,
+            .c_long,
+            .c_ulong,
+            .c_longlong,
+            .c_ulonglong,
+            .bool,
+            .type,
+            .anyerror,
+            .fn_noreturn_no_args,
+            .fn_void_no_args,
+            .fn_naked_noreturn_no_args,
+            .fn_ccc_void_no_args,
+            .function,
+            .single_const_pointer_to_comptime_int,
+            .const_slice_u8,
+            .c_void,
+            .void,
+            .noreturn,
+            .@"null",
+            .@"undefined",
+            .int_unsigned,
+            .int_signed,
+            .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
+            .single_const_pointer,
+            .single_mut_pointer,
+            .many_const_pointer,
+            .many_mut_pointer,
+            .const_slice,
+            .mut_slice,
+            .optional,
+            .optional_single_mut_pointer,
+            .optional_single_const_pointer,
+            .enum_literal,
+            .error_union,
+            .@"anyframe",
+            .anyframe_T,
+            .anyerror_void_error_union,
+            .error_set,
+            .error_set_single,
+            .c_const_pointer,
+            .c_mut_pointer,
+            .pointer,
+            => unreachable,
+
+            .empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope,
+        };
+    }
+
     /// This enum does not directly correspond to `std.builtin.TypeId` because
     /// it has extra enum tags in it, as a way of using less memory. For example,
     /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
src/zir_sema.zig
@@ -1048,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
                         .val = Value.initPayload(&ref_payload.base),
                     });
                 },
+                .Struct => {
+                    const container_scope = child_type.getContainerScope();
+                    if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
+                        // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
+                        return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
+                    }
+
+                    if (&container_scope.file_scope.base == mod.root_scope) {
+                        return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{}'", .{field_name});
+                    } else {
+                        return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{}'", .{ child_type, field_name });
+                    }
+                },
                 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
             }
         },
@@ -1203,8 +1216,8 @@ fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErr
         },
         else => {
             // TODO user friendly error to string
-            return mod.fail(scope, inst.base.src, "unable to open '{}': {}", .{operand, @errorName(err)});
-        }
+            return mod.fail(scope, inst.base.src, "unable to open '{}': {}", .{ operand, @errorName(err) });
+        },
     };
     return mod.constType(scope, inst.base.src, file_scope.root_container.ty);
 }