authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-12 08:35:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-12 08:35:41-04:00
log5834ff0cc58ffba8e4fe218fcf888d9f9fcf95b2
tree46eb8f1c9b74a9b9793aa67323661644b959d2cf
parent1bf2810f338a7bf83455266ef66a535bdc1d4f83

don't memoize comptime fn calls that access comptime mutable state

closes #827

3 files changed, 84 insertions(+), 19 deletions(-)

src/all_types.hpp-7
......@@ -1174,13 +1174,6 @@ struct TypeTableEntry {
11741174 bool is_copyable;
11751175 bool gen_h_loop_flag;
11761176
1177 // This is denormalized data. The simplest type that has this
1178 // flag set to true is a mutable pointer. A const pointer has
1179 // the same value for this flag as the child type.
1180 // If a struct has any fields that have this flag true, then
1181 // the flag is true for the struct.
1182 bool can_mutate_state_through_it;
1183
11841177 union {
11851178 TypeTableEntryPointer pointer;
11861179 TypeTableEntryInt integral;
src/analyze.cpp+67-12
......@@ -398,7 +398,6 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
398398
399399 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
400400 entry->is_copyable = true;
401 entry->can_mutate_state_through_it = is_const ? child_type->can_mutate_state_through_it : true;
402401
403402 const char *const_str = is_const ? "const " : "";
404403 const char *volatile_str = is_volatile ? "volatile " : "";
......@@ -483,7 +482,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
483482 assert(child_type->type_ref || child_type->zero_bits);
484483 assert(child_type->di_type);
485484 entry->is_copyable = type_is_copyable(g, child_type);
486 entry->can_mutate_state_through_it = child_type->can_mutate_state_through_it;
487485
488486 buf_resize(&entry->name, 0);
489487 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
......@@ -574,7 +572,6 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T
574572 entry->is_copyable = true;
575573 assert(payload_type->di_type);
576574 ensure_complete_type(g, payload_type);
577 entry->can_mutate_state_through_it = payload_type->can_mutate_state_through_it;
578575
579576 buf_resize(&entry->name, 0);
580577 buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
......@@ -733,7 +730,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
733730
734731 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
735732 entry->is_copyable = true;
736 entry->can_mutate_state_through_it = ptr_type->can_mutate_state_through_it;
737733
738734 // replace the & with [] to go from a ptr type name to a slice type name
739735 buf_resize(&entry->name, 0);
......@@ -1739,8 +1735,6 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
17391735 struct_type->data.structure.gen_field_count += 1;
17401736 } else {
17411737 field->gen_index = SIZE_MAX;
1742 struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it ||
1743 field->type_entry->can_mutate_state_through_it;
17441738 }
17451739
17461740 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
......@@ -2481,9 +2475,6 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
24812475 if (!type_has_bits(field_type))
24822476 continue;
24832477
2484 struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it ||
2485 field_type->can_mutate_state_through_it;
2486
24872478 if (gen_field_index == 0) {
24882479 if (struct_type->data.structure.layout == ContainerLayoutPacked) {
24892480 struct_type->data.structure.abi_alignment = 1;
......@@ -2671,8 +2662,6 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
26712662 }
26722663 }
26732664 union_field->type_entry = field_type;
2674 union_type->can_mutate_state_through_it = union_type->can_mutate_state_through_it ||
2675 field_type->can_mutate_state_through_it;
26762665
26772666 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
26782667 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
......@@ -4576,11 +4565,77 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
45764565 return true;
45774566}
45784567
4568static bool can_mutate_comptime_var_state(ConstExprValue *value) {
4569 assert(value != nullptr);
4570 switch (value->type->id) {
4571 case TypeTableEntryIdInvalid:
4572 zig_unreachable();
4573 case TypeTableEntryIdMetaType:
4574 case TypeTableEntryIdVoid:
4575 case TypeTableEntryIdBool:
4576 case TypeTableEntryIdUnreachable:
4577 case TypeTableEntryIdInt:
4578 case TypeTableEntryIdFloat:
4579 case TypeTableEntryIdNumLitFloat:
4580 case TypeTableEntryIdNumLitInt:
4581 case TypeTableEntryIdUndefLit:
4582 case TypeTableEntryIdNullLit:
4583 case TypeTableEntryIdNamespace:
4584 case TypeTableEntryIdBoundFn:
4585 case TypeTableEntryIdFn:
4586 case TypeTableEntryIdBlock:
4587 case TypeTableEntryIdOpaque:
4588 case TypeTableEntryIdPromise:
4589 case TypeTableEntryIdErrorSet:
4590 case TypeTableEntryIdEnum:
4591 return false;
4592
4593 case TypeTableEntryIdPointer:
4594 return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
4595
4596 case TypeTableEntryIdArray:
4597 if (value->type->data.array.len == 0)
4598 return false;
4599 if (value->data.x_array.special == ConstArraySpecialUndef)
4600 return false;
4601 for (uint32_t i = 0; i < value->type->data.array.len; i += 1) {
4602 if (can_mutate_comptime_var_state(&value->data.x_array.s_none.elements[i]))
4603 return true;
4604 }
4605 return false;
4606
4607 case TypeTableEntryIdStruct:
4608 for (uint32_t i = 0; i < value->type->data.structure.src_field_count; i += 1) {
4609 if (can_mutate_comptime_var_state(&value->data.x_struct.fields[i]))
4610 return true;
4611 }
4612 return false;
4613
4614 case TypeTableEntryIdMaybe:
4615 if (value->data.x_maybe == nullptr)
4616 return false;
4617 return can_mutate_comptime_var_state(value->data.x_maybe);
4618
4619 case TypeTableEntryIdErrorUnion:
4620 if (value->data.x_err_union.err != nullptr)
4621 return false;
4622 assert(value->data.x_err_union.payload != nullptr);
4623 return can_mutate_comptime_var_state(value->data.x_err_union.payload);
4624
4625 case TypeTableEntryIdUnion:
4626 return can_mutate_comptime_var_state(value->data.x_union.payload);
4627
4628 case TypeTableEntryIdArgTuple:
4629 zig_panic("TODO var args at comptime is currently not supported");
4630 }
4631 zig_unreachable();
4632}
4633
45794634bool fn_eval_cacheable(Scope *scope) {
45804635 while (scope) {
45814636 if (scope->id == ScopeIdVarDecl) {
45824637 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
4583 if (var_scope->var->value->type->can_mutate_state_through_it)
4638 if (can_mutate_comptime_var_state(var_scope->var->value))
45844639 return false;
45854640 } else if (scope->id == ScopeIdFnDef) {
45864641 return true;
test/cases/eval.zig+17
......@@ -486,3 +486,20 @@ test "comptime slice of pointer preserves comptime var" {
486486 assert(buff[0..][0..][0] == 1);
487487 }
488488}
489
490const SingleFieldStruct = struct {
491 x: i32,
492
493 fn read_x(self: &const SingleFieldStruct) i32 {
494 return self.x;
495 }
496};
497test "const ptr to comptime mutable data is not memoized" {
498
499 comptime {
500 var foo = SingleFieldStruct {.x = 1};
501 assert(foo.read_x() == 1);
502 foo.x = 2;
503 assert(foo.read_x() == 2);
504 }
505}