Skip to content

Commit

Permalink
some return types disqualify comptime fn call caching
Browse files Browse the repository at this point in the history
closes #828
  • Loading branch information
andrewrk committed Mar 12, 2018
1 parent 5834ff0 commit bcce777
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 4 deletions.
46 changes: 45 additions & 1 deletion src/analyze.cpp
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/analyze.hpp
Expand Up @@ -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
2 changes: 1 addition & 1 deletion src/ir.cpp
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion std/base64.zig
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions test/behavior.zig
Expand Up @@ -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");
Expand Down
37 changes: 37 additions & 0 deletions 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);
}

0 comments on commit bcce777

Please sign in to comment.