authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-08 12:13:34-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-08 12:26:20-05:00
logfe8d65556dc49bb0da7ee621597c3b24f0e879f6
tree18af2a2e0e21b1dbec889564f9e49b7992ed20b2
parent119ed128c05e95a4779a00cd87d3e2d5b01f9f17
signature Commit is signed but in an unrecognized format.

add syntax for comptime struct fields


6 files changed, 61 insertions(+), 21 deletions(-)

src/all_types.hpp+1
...@@ -1006,6 +1006,7 @@ struct AstNodeStructField {...@@ -1006,6 +1006,7 @@ struct AstNodeStructField {
1006 // populated if the "align(A)" is present1006 // populated if the "align(A)" is present
1007 AstNode *align_expr;1007 AstNode *align_expr;
1008 Buf doc_comments;1008 Buf doc_comments;
1009 Token *comptime_token;
1009};1010};
10101011
1011struct AstNodeStringLiteral {1012struct AstNodeStringLiteral {
src/analyze.cpp+10
...@@ -2736,6 +2736,16 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {...@@ -2736,6 +2736,16 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
2736 field_node = decl_node->data.container_decl.fields.at(i);2736 field_node = decl_node->data.container_decl.fields.at(i);
2737 type_struct_field->name = field_node->data.struct_field.name;2737 type_struct_field->name = field_node->data.struct_field.name;
2738 type_struct_field->decl_node = field_node;2738 type_struct_field->decl_node = field_node;
2739 if (field_node->data.struct_field.comptime_token != nullptr) {
2740 if (field_node->data.struct_field.value == nullptr) {
2741 add_token_error(g, field_node->owner,
2742 field_node->data.struct_field.comptime_token,
2743 buf_sprintf("comptime struct field missing initialization value"));
2744 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2745 return ErrorSemanticAnalyzeFail;
2746 }
2747 type_struct_field->is_comptime = true;
2748 }
27392749
2740 if (field_node->data.struct_field.type == nullptr) {2750 if (field_node->data.struct_field.type == nullptr) {
2741 add_node_error(g, field_node, buf_sprintf("struct field missing type"));2751 add_node_error(g, field_node, buf_sprintf("struct field missing type"));
src/ir.cpp+18-18
...@@ -19514,6 +19514,18 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -19514,6 +19514,18 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
19514 return ira->codegen->invalid_instruction;19514 return ira->codegen->invalid_instruction;
19515}19515}
1951619516
19517static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field) {
19518 if (field->init_val != nullptr) return;
19519 if (field->decl_node->type != NodeTypeStructField) return;
19520 AstNode *init_node = field->decl_node->data.struct_field.value;
19521 if (init_node == nullptr) return;
19522 // scope is not the scope of the struct init, it's the scope of the struct type decl
19523 Scope *analyze_scope = &get_container_scope(container_type)->base;
19524 // memoize it
19525 field->init_val = analyze_const_value(codegen, analyze_scope, init_node,
19526 field->type_entry, nullptr, UndefOk);
19527}
19528
19517static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr,19529static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr,
19518 TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing)19530 TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing)
19519{19531{
...@@ -19523,6 +19535,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction...@@ -19523,6 +19535,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
19523 return ira->codegen->invalid_instruction;19535 return ira->codegen->invalid_instruction;
19524 if (field->is_comptime) {19536 if (field->is_comptime) {
19525 IrInstruction *elem = ir_const(ira, source_instr, field_type);19537 IrInstruction *elem = ir_const(ira, source_instr, field_type);
19538 memoize_field_init_val(ira->codegen, struct_type, field);
19526 copy_const_val(elem->value, field->init_val);19539 copy_const_val(elem->value, field->init_val);
19527 return ir_get_ref(ira, source_instr, elem, true, false);19540 return ir_get_ref(ira, source_instr, elem, true, false);
19528 }19541 }
...@@ -21556,25 +21569,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc...@@ -21556,25 +21569,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
2155621569
21557 // look for a default field value21570 // look for a default field value
21558 TypeStructField *field = container_type->data.structure.fields[i];21571 TypeStructField *field = container_type->data.structure.fields[i];
21572 memoize_field_init_val(ira->codegen, container_type, field);
21559 if (field->init_val == nullptr) {21573 if (field->init_val == nullptr) {
21560 // it's not memoized. time to go analyze it21574 ir_add_error_node(ira, instruction->source_node,
21561 AstNode *init_node;21575 buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
21562 if (field->decl_node->type == NodeTypeStructField) {21576 any_missing = true;
21563 init_node = field->decl_node->data.struct_field.value;21577 continue;
21564 } else {
21565 init_node = nullptr;
21566 }
21567 if (init_node == nullptr) {
21568 ir_add_error_node(ira, instruction->source_node,
21569 buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
21570 any_missing = true;
21571 continue;
21572 }
21573 // scope is not the scope of the struct init, it's the scope of the struct type decl
21574 Scope *analyze_scope = &get_container_scope(container_type)->base;
21575 // memoize it
21576 field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node,
21577 field->type_entry, nullptr, UndefOk);
21578 }21578 }
21579 if (type_is_invalid(field->init_val->type))21579 if (type_is_invalid(field->init_val->type))
21580 return ira->codegen->invalid_instruction;21580 return ira->codegen->invalid_instruction;
src/parser.cpp+12-2
...@@ -536,8 +536,8 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {...@@ -536,8 +536,8 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {
536// <- TestDecl ContainerMembers536// <- TestDecl ContainerMembers
537// / TopLevelComptime ContainerMembers537// / TopLevelComptime ContainerMembers
538// / KEYWORD_pub? TopLevelDecl ContainerMembers538// / KEYWORD_pub? TopLevelDecl ContainerMembers
539// / ContainerField COMMA ContainerMembers539// / KEYWORD_comptime? ContainerField COMMA ContainerMembers
540// / ContainerField540// / KEYWORD_comptime? ContainerField
541// /541// /
542static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {542static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
543 AstNodeContainerDecl res = {};543 AstNodeContainerDecl res = {};
...@@ -574,10 +574,13 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {...@@ -574,10 +574,13 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
574 ast_error(pc, peek_token(pc), "expected function or variable declaration after pub");574 ast_error(pc, peek_token(pc), "expected function or variable declaration after pub");
575 }575 }
576576
577 Token *comptime_token = eat_token_if(pc, TokenIdKeywordCompTime);
578
577 AstNode *container_field = ast_parse_container_field(pc);579 AstNode *container_field = ast_parse_container_field(pc);
578 if (container_field != nullptr) {580 if (container_field != nullptr) {
579 assert(container_field->type == NodeTypeStructField);581 assert(container_field->type == NodeTypeStructField);
580 container_field->data.struct_field.doc_comments = doc_comment_buf;582 container_field->data.struct_field.doc_comments = doc_comment_buf;
583 container_field->data.struct_field.comptime_token = comptime_token;
581 res.fields.append(container_field);584 res.fields.append(container_field);
582 if (eat_token_if(pc, TokenIdComma) != nullptr) {585 if (eat_token_if(pc, TokenIdComma) != nullptr) {
583 continue;586 continue;
...@@ -612,6 +615,13 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) {...@@ -612,6 +615,13 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) {
612 if (comptime == nullptr)615 if (comptime == nullptr)
613 return nullptr;616 return nullptr;
614617
618 // 1 token lookahead because it could be a comptime struct field
619 Token *lbrace = peek_token(pc);
620 if (lbrace->id != TokenIdLBrace) {
621 put_back_token(pc);
622 return nullptr;
623 }
624
615 AstNode *block = ast_expect(pc, ast_parse_block_expr);625 AstNode *block = ast_expect(pc, ast_parse_block_expr);
616 AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime);626 AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime);
617 res->data.comptime_expr.expr = block;627 res->data.comptime_expr.expr = block;
test/compile_errors.zig+10-1
...@@ -2,6 +2,15 @@ const tests = @import("tests.zig");...@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add("comptime struct field, no init value",
6 \\const Foo = struct {
7 \\ comptime b: i32,
8 \\};
9 \\export fn entry() void {
10 \\ var f: Foo = undefined;
11 \\}
12 , "tmp.zig:2:5: error: comptime struct field missing initialization value");
13
5 cases.add(14 cases.add(
6 "bad usage of @call",15 "bad usage of @call",
7 \\export fn entry1() void {16 \\export fn entry1() void {
...@@ -32,7 +41,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -32,7 +41,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32 "tmp.zig:15:43: error: unable to evaluate constant expression",41 "tmp.zig:15:43: error: unable to evaluate constant expression",
33 );42 );
3443
35 cases.add(44 cases.add("exported async function",
36 \\export async fn foo() void {}45 \\export async fn foo() void {}
37 , "tmp.zig:1:1: error: exported function cannot be async");46 , "tmp.zig:1:1: error: exported function cannot be async");
3847
test/stage1/behavior/struct.zig+10
...@@ -789,3 +789,13 @@ test "struct with var field" {...@@ -789,3 +789,13 @@ test "struct with var field" {
789 expect(pt.x == 1);789 expect(pt.x == 1);
790 expect(pt.y == 2);790 expect(pt.y == 2);
791}791}
792
793test "comptime struct field" {
794 const T = struct {
795 a: i32,
796 comptime b: i32 = 1234,
797 };
798
799 var foo: T = undefined;
800 comptime expect(foo.b == 1234);
801}