Commit bcce77700f

Andrew Kelley <superjoe30@gmail.com>
2018-03-12 17:56:25
some return types disqualify comptime fn call caching
closes #828
1 parent 5834ff0
Changed files (6)
src/analyze.cpp
@@ -4631,7 +4631,51 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
     zig_unreachable();
 }
 
-bool fn_eval_cacheable(Scope *scope) {
+static bool return_type_is_cacheable(TypeTableEntry *return_type) {
+    switch (return_type->id) {
+        case TypeTableEntryIdInvalid:
+            zig_unreachable();
+        case TypeTableEntryIdMetaType:
+        case TypeTableEntryIdVoid:
+        case TypeTableEntryIdBool:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdInt:
+        case TypeTableEntryIdFloat:
+        case TypeTableEntryIdNumLitFloat:
+        case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdUndefLit:
+        case TypeTableEntryIdNullLit:
+        case TypeTableEntryIdNamespace:
+        case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdFn:
+        case TypeTableEntryIdBlock:
+        case TypeTableEntryIdOpaque:
+        case TypeTableEntryIdPromise:
+        case TypeTableEntryIdErrorSet:
+        case TypeTableEntryIdEnum:
+        case TypeTableEntryIdPointer:
+            return true;
+
+        case TypeTableEntryIdArray:
+        case TypeTableEntryIdStruct:
+        case TypeTableEntryIdUnion:
+            return false;
+
+        case TypeTableEntryIdMaybe:
+            return return_type_is_cacheable(return_type->data.maybe.child_type);
+
+        case TypeTableEntryIdErrorUnion:
+            return return_type_is_cacheable(return_type->data.error_union.payload_type);
+
+        case TypeTableEntryIdArgTuple:
+            zig_panic("TODO var args at comptime is currently not supported");
+    }
+    zig_unreachable();
+}
+
+bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type) {
+    if (!return_type_is_cacheable(return_type))
+        return false;
     while (scope) {
         if (scope->id == ScopeIdVarDecl) {
             ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
src/analyze.hpp
@@ -196,6 +196,6 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
 uint32_t get_coro_frame_align_bytes(CodeGen *g);
 bool fn_type_can_fail(FnTypeId *fn_type_id);
 bool type_can_fail(TypeTableEntry *type_entry);
-bool fn_eval_cacheable(Scope *scope);
+bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type);
 
 #endif
src/ir.cpp
@@ -11878,7 +11878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
             return_type = specified_return_type;
         }
 
-        bool cacheable = fn_eval_cacheable(exec_scope);
+        bool cacheable = fn_eval_cacheable(exec_scope, return_type);
         IrInstruction *result = nullptr;
         if (cacheable) {
             auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
std/base64.zig
@@ -369,7 +369,7 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {
 
 
 test "base64" {
-    @setEvalBranchQuota(5000);
+    @setEvalBranchQuota(8000);
     testBase64() catch unreachable;
     comptime (testBase64() catch unreachable);
 }
test/cases/bugs/828.zig
@@ -0,0 +1,37 @@
+const CountBy = struct {
+    a: usize,
+    
+    const One = CountBy {
+        .a = 1,
+    };
+    
+    pub fn counter(self: &const CountBy) Counter {
+        return Counter {
+            .i = 0,
+        };
+    }
+};
+
+const Counter = struct {
+    i: usize,
+    
+    pub fn count(self: &Counter) bool {
+        self.i += 1;
+        return self.i <= 10;
+    }
+};
+
+fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
+    comptime {
+        var cnt = cb.counter();
+        if(cnt.i != 0) @compileError("Counter instance reused!");
+        while(cnt.count()){}
+    }
+}
+
+test "comptime struct return should not return the same instance" {
+    //the first parameter must be passed by reference to trigger the bug
+    //a second parameter is required to trigger the bug
+    const ValA = constCount(&CountBy.One, 12);
+    const ValB = constCount(&CountBy.One, 15);
+}
test/behavior.zig
@@ -11,6 +11,7 @@ comptime {
     _ = @import("cases/bugs/394.zig");
     _ = @import("cases/bugs/655.zig");
     _ = @import("cases/bugs/656.zig");
+    _ = @import("cases/bugs/828.zig");
     _ = @import("cases/cast.zig");
     _ = @import("cases/const_slice_child.zig");
     _ = @import("cases/coroutines.zig");