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 {
10061006 // populated if the "align(A)" is present
10071007 AstNode *align_expr;
10081008 Buf doc_comments;
1009 Token *comptime_token;
10091010};
10101011
10111012struct AstNodeStringLiteral {
src/analyze.cpp+10
......@@ -2736,6 +2736,16 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
27362736 field_node = decl_node->data.container_decl.fields.at(i);
27372737 type_struct_field->name = field_node->data.struct_field.name;
27382738 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
27402750 if (field_node->data.struct_field.type == nullptr) {
27412751 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,
1951419514 return ira->codegen->invalid_instruction;
1951519515}
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
1951719529static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr,
1951819530 TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing)
1951919531{
......@@ -19523,6 +19535,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
1952319535 return ira->codegen->invalid_instruction;
1952419536 if (field->is_comptime) {
1952519537 IrInstruction *elem = ir_const(ira, source_instr, field_type);
19538 memoize_field_init_val(ira->codegen, struct_type, field);
1952619539 copy_const_val(elem->value, field->init_val);
1952719540 return ir_get_ref(ira, source_instr, elem, true, false);
1952819541 }
......@@ -21556,25 +21569,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
2155621569
2155721570 // look for a default field value
2155821571 TypeStructField *field = container_type->data.structure.fields[i];
21572 memoize_field_init_val(ira->codegen, container_type, field);
2155921573 if (field->init_val == nullptr) {
21560 // it's not memoized. time to go analyze it
21561 AstNode *init_node;
21562 if (field->decl_node->type == NodeTypeStructField) {
21563 init_node = field->decl_node->data.struct_field.value;
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);
21574 ir_add_error_node(ira, instruction->source_node,
21575 buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
21576 any_missing = true;
21577 continue;
2157821578 }
2157921579 if (type_is_invalid(field->init_val->type))
2158021580 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) {
536536// <- TestDecl ContainerMembers
537537// / TopLevelComptime ContainerMembers
538538// / KEYWORD_pub? TopLevelDecl ContainerMembers
539// / ContainerField COMMA ContainerMembers
540// / ContainerField
539// / KEYWORD_comptime? ContainerField COMMA ContainerMembers
540// / KEYWORD_comptime? ContainerField
541541// /
542542static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
543543 AstNodeContainerDecl res = {};
......@@ -574,10 +574,13 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
574574 ast_error(pc, peek_token(pc), "expected function or variable declaration after pub");
575575 }
576576
577 Token *comptime_token = eat_token_if(pc, TokenIdKeywordCompTime);
578
577579 AstNode *container_field = ast_parse_container_field(pc);
578580 if (container_field != nullptr) {
579581 assert(container_field->type == NodeTypeStructField);
580582 container_field->data.struct_field.doc_comments = doc_comment_buf;
583 container_field->data.struct_field.comptime_token = comptime_token;
581584 res.fields.append(container_field);
582585 if (eat_token_if(pc, TokenIdComma) != nullptr) {
583586 continue;
......@@ -612,6 +615,13 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) {
612615 if (comptime == nullptr)
613616 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
615625 AstNode *block = ast_expect(pc, ast_parse_block_expr);
616626 AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime);
617627 res->data.comptime_expr.expr = block;
test/compile_errors.zig+10-1
......@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub 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
514 cases.add(
615 "bad usage of @call",
716 \\export fn entry1() void {
......@@ -32,7 +41,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3241 "tmp.zig:15:43: error: unable to evaluate constant expression",
3342 );
3443
35 cases.add(
44 cases.add("exported async function",
3645 \\export async fn foo() void {}
3746 , "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" {
789789 expect(pt.x == 1);
790790 expect(pt.y == 2);
791791}
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}