authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-07 17:26:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-07 18:07:30-04:00
log31aefa6a2179dfae752020195fb193c6333bae7e
tree3bf77a35c39424e736da020a0451d6fe32d7648b
parentb11c5d8f8256fc19e08eacfc50be209878f00e73

fix structs that contain types which require comptime

Now, if a struct has any fields which require comptime, such as `type`, then the struct is marked as requiring comptime as well. Same goes for unions. This means that a function will implicitly be called at comptime if the return type is a struct which contains a field of type `type`. closes #586

5 files changed, 77 insertions(+), 81 deletions(-)

src/all_types.hpp+8
......@@ -1037,6 +1037,10 @@ struct TypeTableEntryStruct {
10371037 // whether we've finished resolving it
10381038 bool complete;
10391039
1040 // whether any of the fields require comptime
1041 // the value is not valid until zero_bits_known == true
1042 bool requires_comptime;
1043
10401044 bool zero_bits_loop_flag;
10411045 bool zero_bits_known;
10421046 uint32_t abi_alignment; // also figured out with zero_bits pass
......@@ -1105,6 +1109,10 @@ struct TypeTableEntryUnion {
11051109 // whether we've finished resolving it
11061110 bool complete;
11071111
1112 // whether any of the fields require comptime
1113 // the value is not valid until zero_bits_known == true
1114 bool requires_comptime;
1115
11081116 bool zero_bits_loop_flag;
11091117 bool zero_bits_known;
11101118 uint32_t abi_alignment; // also figured out with zero_bits pass
src/analyze.cpp+22-1
......@@ -2533,6 +2533,10 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
25332533 continue;
25342534 }
25352535
2536 if (type_requires_comptime(field_type)) {
2537 struct_type->data.structure.requires_comptime = true;
2538 }
2539
25362540 if (!type_has_bits(field_type))
25372541 continue;
25382542
......@@ -2724,6 +2728,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
27242728 }
27252729 union_field->type_entry = field_type;
27262730
2731 if (type_requires_comptime(field_type)) {
2732 union_type->data.unionation.requires_comptime = true;
2733 }
2734
2735
27272736 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
27282737 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
27292738 buf_sprintf("non-enum union field assignment"));
......@@ -4944,17 +4953,29 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
49444953 case TypeTableEntryIdArgTuple:
49454954 return true;
49464955 case TypeTableEntryIdArray:
4956 return type_requires_comptime(type_entry->data.array.child_type);
49474957 case TypeTableEntryIdStruct:
4958 assert(type_has_zero_bits_known(type_entry));
4959 return type_entry->data.structure.requires_comptime;
49484960 case TypeTableEntryIdUnion:
4961 assert(type_has_zero_bits_known(type_entry));
4962 return type_entry->data.unionation.requires_comptime;
49494963 case TypeTableEntryIdMaybe:
4964 return type_requires_comptime(type_entry->data.maybe.child_type);
49504965 case TypeTableEntryIdErrorUnion:
4966 return type_requires_comptime(type_entry->data.error_union.payload_type);
4967 case TypeTableEntryIdPointer:
4968 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
4969 return false;
4970 } else {
4971 return type_requires_comptime(type_entry->data.pointer.child_type);
4972 }
49514973 case TypeTableEntryIdEnum:
49524974 case TypeTableEntryIdErrorSet:
49534975 case TypeTableEntryIdFn:
49544976 case TypeTableEntryIdBool:
49554977 case TypeTableEntryIdInt:
49564978 case TypeTableEntryIdFloat:
4957 case TypeTableEntryIdPointer:
49584979 case TypeTableEntryIdVoid:
49594980 case TypeTableEntryIdUnreachable:
49604981 case TypeTableEntryIdPromise:
src/ir.cpp+33-79
......@@ -11624,61 +11624,6 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
1162411624 zig_unreachable();
1162511625}
1162611626
11627enum VarClassRequired {
11628 VarClassRequiredAny,
11629 VarClassRequiredConst,
11630 VarClassRequiredIllegal,
11631};
11632
11633static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
11634 switch (type_entry->id) {
11635 case TypeTableEntryIdInvalid:
11636 zig_unreachable();
11637 case TypeTableEntryIdUnreachable:
11638 return VarClassRequiredIllegal;
11639 case TypeTableEntryIdBool:
11640 case TypeTableEntryIdInt:
11641 case TypeTableEntryIdFloat:
11642 case TypeTableEntryIdVoid:
11643 case TypeTableEntryIdErrorSet:
11644 case TypeTableEntryIdFn:
11645 case TypeTableEntryIdPromise:
11646 return VarClassRequiredAny;
11647 case TypeTableEntryIdComptimeFloat:
11648 case TypeTableEntryIdComptimeInt:
11649 case TypeTableEntryIdUndefined:
11650 case TypeTableEntryIdBlock:
11651 case TypeTableEntryIdNull:
11652 case TypeTableEntryIdOpaque:
11653 case TypeTableEntryIdMetaType:
11654 case TypeTableEntryIdNamespace:
11655 case TypeTableEntryIdBoundFn:
11656 case TypeTableEntryIdArgTuple:
11657 return VarClassRequiredConst;
11658
11659 case TypeTableEntryIdPointer:
11660 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
11661 return VarClassRequiredAny;
11662 } else {
11663 return get_var_class_required(type_entry->data.pointer.child_type);
11664 }
11665 case TypeTableEntryIdArray:
11666 return get_var_class_required(type_entry->data.array.child_type);
11667 case TypeTableEntryIdMaybe:
11668 return get_var_class_required(type_entry->data.maybe.child_type);
11669 case TypeTableEntryIdErrorUnion:
11670 return get_var_class_required(type_entry->data.error_union.payload_type);
11671
11672 case TypeTableEntryIdStruct:
11673 case TypeTableEntryIdEnum:
11674 case TypeTableEntryIdUnion:
11675 // TODO check the fields of these things and make sure that they don't recursively
11676 // contain any of the other variable classes
11677 return VarClassRequiredAny;
11678 }
11679 zig_unreachable();
11680}
11681
1168211627static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
1168311628 VariableTableEntry *var = decl_var_instruction->var;
1168411629
......@@ -11713,36 +11658,41 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1171311658 if (type_is_invalid(result_type)) {
1171411659 result_type = ira->codegen->builtin_types.entry_invalid;
1171511660 } else {
11716 switch (get_var_class_required(result_type)) {
11717 case VarClassRequiredIllegal:
11661 type_ensure_zero_bits_known(ira->codegen, result_type);
11662 if (type_is_invalid(result_type)) {
11663 result_type = ira->codegen->builtin_types.entry_invalid;
11664 }
11665 }
11666
11667 if (!type_is_invalid(result_type)) {
11668 if (result_type->id == TypeTableEntryIdUnreachable ||
11669 result_type->id == TypeTableEntryIdOpaque)
11670 {
11671 ir_add_error_node(ira, source_node,
11672 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
11673 result_type = ira->codegen->builtin_types.entry_invalid;
11674 } else if (type_requires_comptime(result_type)) {
11675 var_class_requires_const = true;
11676 if (!var->src_is_const && !is_comptime_var) {
1171811677 ir_add_error_node(ira, source_node,
11719 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
11678 buf_sprintf("variable of type '%s' must be const or comptime",
11679 buf_ptr(&result_type->name)));
1172011680 result_type = ira->codegen->builtin_types.entry_invalid;
11721 break;
11722 case VarClassRequiredConst:
11681 }
11682 } else {
11683 if (casted_init_value->value.special == ConstValSpecialStatic &&
11684 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11685 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11686 {
1172311687 var_class_requires_const = true;
1172411688 if (!var->src_is_const && !is_comptime_var) {
11725 ir_add_error_node(ira, source_node,
11726 buf_sprintf("variable of type '%s' must be const or comptime",
11727 buf_ptr(&result_type->name)));
11689 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11690 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11691 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11692 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
1172811693 result_type = ira->codegen->builtin_types.entry_invalid;
1172911694 }
11730 break;
11731 case VarClassRequiredAny:
11732 if (casted_init_value->value.special == ConstValSpecialStatic &&
11733 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11734 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11735 {
11736 var_class_requires_const = true;
11737 if (!var->src_is_const && !is_comptime_var) {
11738 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11739 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11740 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11741 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
11742 result_type = ira->codegen->builtin_types.entry_invalid;
11743 }
11744 }
11745 break;
11695 }
1174611696 }
1174711697 }
1174811698
......@@ -12623,6 +12573,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1262312573 inst_fn_type_id.return_type = specified_return_type;
1262412574 }
1262512575
12576 type_ensure_zero_bits_known(ira->codegen, specified_return_type);
12577 if (type_is_invalid(specified_return_type))
12578 return ira->codegen->builtin_types.entry_invalid;
12579
1262612580 if (type_requires_comptime(specified_return_type)) {
1262712581 // Throw out our work and call the function as if it were comptime.
1262812582 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
test/cases/eval.zig+13
......@@ -610,3 +610,16 @@ test "slice of type" {
610610 }
611611 }
612612}
613
614const Wrapper = struct {
615 T: type,
616};
617
618fn wrap(comptime T: type) Wrapper {
619 return Wrapper{ .T = T };
620}
621
622test "function which returns struct with type field causes implicit comptime" {
623 const ty = wrap(i32).T;
624 assert(ty == i32);
625}
test/compile_errors.zig+1-1
......@@ -3329,7 +3329,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33293329 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
33303330 ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
33313331 ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
3332 ".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime",
3332 ".tmp_source.zig:12:4: error: variable of type 'Opaque' not allowed",
33333333 ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
33343334 ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
33353335 ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",