Commit a31b23c46b

Andrew Kelley <superjoe30@gmail.com>
2017-11-03 05:00:57
more compile-time type reflection
See #383
1 parent dc8b011
Changed files (4)
src
src-self-hosted
test
src/ir.cpp
@@ -11643,6 +11643,55 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                         buf_ptr(&child_type->name), buf_ptr(field_name)));
                 return ira->codegen->builtin_types.entry_invalid;
             }
+        } else if (child_type->id == TypeTableEntryIdErrorUnion) {
+            if (buf_eql_str(field_name, "Child")) {
+                bool ptr_is_const = true;
+                bool ptr_is_volatile = false;
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_type(ira->codegen, child_type->data.error.child_type),
+                    ira->codegen->builtin_types.entry_type,
+                    ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+            } else {
+                ir_add_error(ira, &field_ptr_instruction->base,
+                    buf_sprintf("type '%s' has no member called '%s'",
+                        buf_ptr(&child_type->name), buf_ptr(field_name)));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+        } else if (child_type->id == TypeTableEntryIdMaybe) {
+            if (buf_eql_str(field_name, "Child")) {
+                bool ptr_is_const = true;
+                bool ptr_is_volatile = false;
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_type(ira->codegen, child_type->data.maybe.child_type),
+                    ira->codegen->builtin_types.entry_type,
+                    ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+            } else {
+                ir_add_error(ira, &field_ptr_instruction->base,
+                    buf_sprintf("type '%s' has no member called '%s'",
+                        buf_ptr(&child_type->name), buf_ptr(field_name)));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+        } else if (child_type->id == TypeTableEntryIdFn) {
+            if (buf_eql_str(field_name, "ReturnType")) {
+                bool ptr_is_const = true;
+                bool ptr_is_volatile = false;
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type),
+                    ira->codegen->builtin_types.entry_type,
+                    ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+            } else if (buf_eql_str(field_name, "is_var_args")) {
+                bool ptr_is_const = true;
+                bool ptr_is_volatile = false;
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args),
+                    ira->codegen->builtin_types.entry_bool,
+                    ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+            } else {
+                ir_add_error(ira, &field_ptr_instruction->base,
+                    buf_sprintf("type '%s' has no member called '%s'",
+                        buf_ptr(&child_type->name), buf_ptr(field_name)));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
         } else {
             ir_add_error(ira, &field_ptr_instruction->base,
                 buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
src-self-hosted/main.zig
@@ -3,24 +3,28 @@ const io = @import("std").io;
 const os = @import("std").os;
 const heap = @import("std").mem;
 
-// TODO: OutSteam and InStream interface
-// TODO: move allocator to heap namespace
 // TODO: sync up CLI with c++ code
+// TODO: concurrency
+// TODO: ability to iterate over enums at compile time (for listing targets)
 
 error InvalidArgument;
 error MissingArg0;
 
 var arg0: []u8 = undefined;
 
+var stderr_file: io.File = undefined;
+const stderr = &stderr_file.out_stream;
+
 pub fn main() -> %void {
+    stderr_file = %return io.getStdErr();
     if (internal_main()) |_| {
         return;
     } else |err| {
         if (err == error.InvalidArgument) {
-            io.stderr.printf("\n") %% return err;
-            printUsage(&io.stderr) %% return err;
+            stderr.print("\n") %% return err;
+            printUsage(stderr) %% return err;
         } else {
-            io.stderr.printf("{}\n", err) %% return err;
+            stderr.print("{}\n", err) %% return err;
         }
         return err;
     }
@@ -266,7 +270,6 @@ fn printUsage(outstream: &io.OutStream) -> %void {
         \\  --test-cmd-bin               appends test binary path to test cmd args
         \\
     );
-    %return outstream.flush();
 }
 
 const ZIG_ZEN =
test/cases/reflection.zig
@@ -0,0 +1,22 @@
+const assert = @import("std").debug.assert;
+const mem = @import("std").mem;
+
+test "reflection: array, pointer, nullable, error union type child" {
+    comptime {
+        assert(([10]u8).Child == u8);
+        assert((&u8).Child == u8);
+        assert((%u8).Child == u8);
+        assert((?u8).Child == u8);
+    }
+}
+
+test "reflection: function return type and var args" {
+    comptime {
+        assert(@typeOf(dummy).ReturnType == i32);
+        assert(!@typeOf(dummy).is_var_args);
+        assert(@typeOf(dummy_varargs).is_var_args);
+    }
+}
+
+fn dummy() -> i32 { 1234 }
+fn dummy_varargs(args: ...) {}
test/behavior.zig
@@ -29,6 +29,7 @@ comptime {
     _ = @import("cases/null.zig");
     _ = @import("cases/pub_enum/index.zig");
     _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
+    _ = @import("cases/reflection.zig");
     _ = @import("cases/sizeof_and_typeof.zig");
     _ = @import("cases/slice.zig");
     _ = @import("cases/struct.zig");