Commit abf5ae6897

Andrew Kelley <superjoe30@gmail.com>
2018-02-03 17:51:29
*WIP* error sets - support fns called at comptime
1 parent b8f59e1
src/ir.cpp
@@ -10123,6 +10123,13 @@ static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
     if (type_is_invalid(payload_type))
         return ira->codegen->builtin_types.entry_invalid;
 
+    if (err_set_type->id != TypeTableEntryIdErrorSet) {
+        ir_add_error(ira, instruction->err_set->other,
+            buf_sprintf("expected error set type, found type '%s'",
+                buf_ptr(&err_set_type->name)));
+        return ira->codegen->builtin_types.entry_invalid;
+    }
+
     TypeTableEntry *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type);
 
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
@@ -10412,9 +10419,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         }
 
         AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
-        TypeTableEntry *return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
-        if (type_is_invalid(return_type))
+        TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
+        if (type_is_invalid(specified_return_type))
             return ira->codegen->builtin_types.entry_invalid;
+        TypeTableEntry *return_type;
+        TypeTableEntry *inferred_err_set_type = nullptr;
+        if (fn_proto_node->data.fn_proto.auto_err_set) {
+            inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry);
+            return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
+        } else {
+            return_type = specified_return_type;
+        }
 
         IrInstruction *result;
 
@@ -10428,6 +10443,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
                 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
                 nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
 
+            if (inferred_err_set_type != nullptr) {
+                inferred_err_set_type->data.error_set.infer_fn = nullptr;
+                if (result->value.type->id == TypeTableEntryIdErrorUnion) {
+                    TypeTableEntry *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
+                    inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
+                    inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
+                } else if (result->value.type->id == TypeTableEntryIdErrorSet) {
+                    inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
+                    inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
+                }
+            }
+
             ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
 
             if (type_is_invalid(result->value.type))
src/parser.cpp
@@ -2589,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
             Token *colon_token = &pc->tokens->at(*token_index);
             if (colon_token->id == TokenIdColon) {
                 *token_index += 1;
-                field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
+                field_node->data.struct_field.type = ast_parse_type_expr(pc, token_index, true);
             }
             Token *eq_token = &pc->tokens->at(*token_index);
             if (eq_token->id == TokenIdEq) {
std/fmt/index.zig
@@ -198,7 +198,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
             return formatInt(value, 10, false, 0, context, Errors, output);
         },
         builtin.TypeId.Float => {
-            return formatFloat(value, context, output);
+            return formatFloat(value, context, Errors, output);
         },
         builtin.TypeId.Void => {
             return output(context, "void");
@@ -417,7 +417,7 @@ const FormatIntBuf = struct {
     out_buf: []u8,
     index: usize,
 };
-fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) !void {
+fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
     mem.copy(u8, context.out_buf[context.index..], bytes);
     context.index += bytes.len;
 }
@@ -499,7 +499,7 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
 
 pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
     var context = BufPrintContext { .remaining = buf, };
-    try format(&context, bufPrintWrite, fmt, args);
+    try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
     return buf[0..buf.len - context.remaining.len];
 }
 
std/os/child_process.zig
@@ -28,7 +28,7 @@ pub const ChildProcess = struct {
     pub stdout: ?io.File,
     pub stderr: ?io.File,
 
-    pub term: ?%Term,
+    pub term: ?SpawnError!Term,
 
     pub argv: []const []const u8,
 
@@ -54,6 +54,10 @@ pub const ChildProcess = struct {
     err_pipe: if (is_windows) void else [2]i32,
     llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
 
+    pub const SpawnError = error {
+
+    };
+
     pub const Term = union(enum) {
         Exited: i32,
         Signal: i32,
@@ -185,7 +189,7 @@ pub const ChildProcess = struct {
     /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
     /// If it succeeds, the caller owns result.stdout and result.stderr memory.
     pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
-        env_map: ?&const BufMap, max_output_size: usize) %ExecResult
+        env_map: ?&const BufMap, max_output_size: usize) !ExecResult
     {
         const child = try ChildProcess.init(argv, allocator);
         defer child.deinit();
@@ -246,7 +250,7 @@ pub const ChildProcess = struct {
     fn waitUnwrappedWindows(self: &ChildProcess) !void {
         const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
 
-        self.term = (%Term)(x: {
+        self.term = (SpawnError!Term)(x: {
             var exit_code: windows.DWORD = undefined;
             if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
                 break :x Term { .Unknown = 0 };
@@ -631,7 +635,7 @@ pub const ChildProcess = struct {
 };
 
 fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,
-    lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) %void
+    lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void
 {
     if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
         @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)
std/os/index.zig
@@ -1072,7 +1072,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void {
 }
 
 /// Read value of a symbolic link.
-pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
+pub fn readLink(allocator: &Allocator, pathname: []const u8) error![]u8 {
     const path_buf = try allocator.alloc(u8, pathname.len + 1);
     defer allocator.free(path_buf);
 
@@ -1267,7 +1267,7 @@ pub const ArgIteratorWindows = struct {
     }
 
     /// You must free the returned memory when done.
-    pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?internalNext.errors![]u8 {
+    pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(@typeOf(internalNext).ReturnType.ErrorSet![]u8) {
         // march forward over whitespace
         while (true) : (self.index += 1) {
             const byte = self.cmd_line[self.index];
std/base64.zig
@@ -181,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct {
     }
 
     /// If no characters end up being ignored or padding, this will be the exact decoded size.
-    pub fn calcSizeUpperBound(encoded_len: usize) !usize {
+    pub fn calcSizeUpperBound(encoded_len: usize) usize {
         return @divTrunc(encoded_len, 4) * 3;
     }
 
@@ -430,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
         const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
             standard_alphabet_chars, standard_pad_char, "");
         var buffer: [0x100]u8 = undefined;
-        var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
+        var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
         var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
         assert(written <= decoded.len);
         assert(mem.eql(u8, decoded[0..written], expected_decoded));
@@ -449,7 +449,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi
     const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
         standard_alphabet_chars, standard_pad_char, " ");
     var buffer: [0x100]u8 = undefined;
-    var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
+    var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
     var written = try standard_decoder_ignore_space.decode(decoded, encoded);
     assert(mem.eql(u8, decoded[0..written], expected_decoded));
 }
std/build.zig
@@ -554,7 +554,7 @@ pub const Builder = struct {
     }
 
     fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
-        argv: []const []const u8) %void
+        argv: []const []const u8) !void
     {
         if (self.verbose) {
             printCmd(cwd, argv);
@@ -1942,12 +1942,12 @@ pub const RemoveDirStep = struct {
 
 pub const Step = struct {
     name: []const u8,
-    makeFn: fn(self: &Step) %void,
+    makeFn: fn(self: &Step) error!void,
     dependencies: ArrayList(&Step),
     loop_flag: bool,
     done_flag: bool,
 
-    pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)%void) Step {
+    pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {
         return Step {
             .name = name,
             .makeFn = makeFn,
@@ -1972,11 +1972,11 @@ pub const Step = struct {
         self.dependencies.append(other) catch unreachable;
     }
 
-    fn makeNoOp(self: &Step) %void {}
+    fn makeNoOp(self: &Step) (error{}!void) {}
 };
 
 fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
-    filename_name_only: []const u8) %void
+    filename_name_only: []const u8) !void
 {
     const out_dir = os.path.dirname(output_path);
     const out_basename = os.path.basename(output_path);
TODO
@@ -25,3 +25,7 @@ comptime test for err
 
 
 undefined in infer error 
+
+change readlink back to inferred error
+
+syntax -  ?a!b  should be ?(a!b) but it's (?a)!b