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 {...@@ -1037,6 +1037,10 @@ struct TypeTableEntryStruct {
1037 // whether we've finished resolving it1037 // whether we've finished resolving it
1038 bool complete;1038 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
1040 bool zero_bits_loop_flag;1044 bool zero_bits_loop_flag;
1041 bool zero_bits_known;1045 bool zero_bits_known;
1042 uint32_t abi_alignment; // also figured out with zero_bits pass1046 uint32_t abi_alignment; // also figured out with zero_bits pass
...@@ -1105,6 +1109,10 @@ struct TypeTableEntryUnion {...@@ -1105,6 +1109,10 @@ struct TypeTableEntryUnion {
1105 // whether we've finished resolving it1109 // whether we've finished resolving it
1106 bool complete;1110 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
1108 bool zero_bits_loop_flag;1116 bool zero_bits_loop_flag;
1109 bool zero_bits_known;1117 bool zero_bits_known;
1110 uint32_t abi_alignment; // also figured out with zero_bits pass1118 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) {...@@ -2533,6 +2533,10 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
2533 continue;2533 continue;
2534 }2534 }
25352535
2536 if (type_requires_comptime(field_type)) {
2537 struct_type->data.structure.requires_comptime = true;
2538 }
2539
2536 if (!type_has_bits(field_type))2540 if (!type_has_bits(field_type))
2537 continue;2541 continue;
25382542
...@@ -2724,6 +2728,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2724,6 +2728,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2724 }2728 }
2725 union_field->type_entry = field_type;2729 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
2727 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {2736 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
2728 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,2737 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
2729 buf_sprintf("non-enum union field assignment"));2738 buf_sprintf("non-enum union field assignment"));
...@@ -4944,17 +4953,29 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {...@@ -4944,17 +4953,29 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
4944 case TypeTableEntryIdArgTuple:4953 case TypeTableEntryIdArgTuple:
4945 return true;4954 return true;
4946 case TypeTableEntryIdArray:4955 case TypeTableEntryIdArray:
4956 return type_requires_comptime(type_entry->data.array.child_type);
4947 case TypeTableEntryIdStruct:4957 case TypeTableEntryIdStruct:
4958 assert(type_has_zero_bits_known(type_entry));
4959 return type_entry->data.structure.requires_comptime;
4948 case TypeTableEntryIdUnion:4960 case TypeTableEntryIdUnion:
4961 assert(type_has_zero_bits_known(type_entry));
4962 return type_entry->data.unionation.requires_comptime;
4949 case TypeTableEntryIdMaybe:4963 case TypeTableEntryIdMaybe:
4964 return type_requires_comptime(type_entry->data.maybe.child_type);
4950 case TypeTableEntryIdErrorUnion:4965 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 }
4951 case TypeTableEntryIdEnum:4973 case TypeTableEntryIdEnum:
4952 case TypeTableEntryIdErrorSet:4974 case TypeTableEntryIdErrorSet:
4953 case TypeTableEntryIdFn:4975 case TypeTableEntryIdFn:
4954 case TypeTableEntryIdBool:4976 case TypeTableEntryIdBool:
4955 case TypeTableEntryIdInt:4977 case TypeTableEntryIdInt:
4956 case TypeTableEntryIdFloat:4978 case TypeTableEntryIdFloat:
4957 case TypeTableEntryIdPointer:
4958 case TypeTableEntryIdVoid:4979 case TypeTableEntryIdVoid:
4959 case TypeTableEntryIdUnreachable:4980 case TypeTableEntryIdUnreachable:
4960 case TypeTableEntryIdPromise:4981 case TypeTableEntryIdPromise:
src/ir.cpp+33-79
...@@ -11624,61 +11624,6 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi...@@ -11624,61 +11624,6 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
11624 zig_unreachable();11624 zig_unreachable();
11625}11625}
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
11682static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {11627static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
11683 VariableTableEntry *var = decl_var_instruction->var;11628 VariableTableEntry *var = decl_var_instruction->var;
1168411629
...@@ -11713,36 +11658,41 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -11713,36 +11658,41 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
11713 if (type_is_invalid(result_type)) {11658 if (type_is_invalid(result_type)) {
11714 result_type = ira->codegen->builtin_types.entry_invalid;11659 result_type = ira->codegen->builtin_types.entry_invalid;
11715 } else {11660 } else {
11716 switch (get_var_class_required(result_type)) {11661 type_ensure_zero_bits_known(ira->codegen, result_type);
11717 case VarClassRequiredIllegal: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) {
11718 ir_add_error_node(ira, source_node,11677 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)));
11720 result_type = ira->codegen->builtin_types.entry_invalid;11680 result_type = ira->codegen->builtin_types.entry_invalid;
11721 break;11681 }
11722 case VarClassRequiredConst: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 {
11723 var_class_requires_const = true;11687 var_class_requires_const = true;
11724 if (!var->src_is_const && !is_comptime_var) {11688 if (!var->src_is_const && !is_comptime_var) {
11725 ir_add_error_node(ira, source_node,11689 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11726 buf_sprintf("variable of type '%s' must be const or comptime",11690 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11727 buf_ptr(&result_type->name)));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"));
11728 result_type = ira->codegen->builtin_types.entry_invalid;11693 result_type = ira->codegen->builtin_types.entry_invalid;
11729 }11694 }
11730 break;11695 }
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;
11746 }11696 }
11747 }11697 }
1174811698
...@@ -12623,6 +12573,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12623,6 +12573,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12623 inst_fn_type_id.return_type = specified_return_type;12573 inst_fn_type_id.return_type = specified_return_type;
12624 }12574 }
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
12626 if (type_requires_comptime(specified_return_type)) {12580 if (type_requires_comptime(specified_return_type)) {
12627 // Throw out our work and call the function as if it were comptime.12581 // Throw out our work and call the function as if it were comptime.
12628 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);12582 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" {...@@ -610,3 +610,16 @@ test "slice of type" {
610 }610 }
611 }611 }
612}612}
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 {...@@ -3329,7 +3329,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3329 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",3329 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
3330 ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",3330 ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
3331 ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",3331 ".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",
3333 ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",3333 ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
3334 ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",3334 ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
3335 ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",3335 ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",