authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-07 17:00:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-07 17:00:58-07:00
log2ed72022ce56b06bb3e90ca9259065452e209eb9
treee583301a3d037577ee8aff73f5ad91177d72c98f
parent01c46eef3a7e4fd5a96f364541c539746ae1ea3b

support generic data structures

See #22

7 files changed, 155 insertions(+), 69 deletions(-)

doc/langref.md+1-1
...@@ -15,7 +15,7 @@ GlobalVarDecl = VariableDeclaration ";"...@@ -15,7 +15,7 @@ GlobalVarDecl = VariableDeclaration ";"
1515
16VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression16VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression
1717
18ContainerDecl = ("struct" | "enum" | "union") "Symbol" "{" many(StructMember) "}"18ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
1919
20StructMember = many(Directive) option(VisibleMod) (StructField | FnDef)20StructMember = many(Directive) option(VisibleMod) (StructField | FnDef)
2121
src/all_types.hpp+4
...@@ -600,12 +600,16 @@ struct AstNodeStructDecl {...@@ -600,12 +600,16 @@ struct AstNodeStructDecl {
600 TopLevelDecl top_level_decl;600 TopLevelDecl top_level_decl;
601 Buf name;601 Buf name;
602 ContainerKind kind;602 ContainerKind kind;
603 ZigList<AstNode *> generic_params;
604 bool generic_params_is_var_args; // always an error but it can happen from parsing
603 ZigList<AstNode *> fields;605 ZigList<AstNode *> fields;
604 ZigList<AstNode *> fns;606 ZigList<AstNode *> fns;
605607
606 // populated by semantic analyzer608 // populated by semantic analyzer
607 BlockContext *block_context;609 BlockContext *block_context;
608 TypeTableEntry *type_entry;610 TypeTableEntry *type_entry;
611 TypeTableEntry *generic_fn_type;
612 bool skip;
609};613};
610614
611struct AstNodeStructField {615struct AstNodeStructField {
src/analyze.cpp+122-61
...@@ -756,11 +756,11 @@ static TypeTableEntryId container_to_type(ContainerKind kind) {...@@ -756,11 +756,11 @@ static TypeTableEntryId container_to_type(ContainerKind kind) {
756 zig_unreachable();756 zig_unreachable();
757}757}
758758
759TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,759TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
760 ContainerKind kind, AstNode *decl_node, const char *name)760 ContainerKind kind, AstNode *decl_node, const char *name)
761{761{
762 TypeTableEntryId type_id = container_to_type(kind);762 TypeTableEntryId type_id = container_to_type(kind);
763 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, import->block_context);763 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, context);
764764
765 switch (kind) {765 switch (kind) {
766 case ContainerKindStruct:766 case ContainerKindStruct:
...@@ -1171,6 +1171,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt...@@ -1171,6 +1171,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
1171 uint64_t biggest_align_in_bits = 0;1171 uint64_t biggest_align_in_bits = 0;
1172 uint64_t biggest_union_member_size_in_bits = 0;1172 uint64_t biggest_union_member_size_in_bits = 0;
11731173
1174 BlockContext *context = enum_type->data.enumeration.block_context;
1175
1174 // set temporary flag1176 // set temporary flag
1175 enum_type->data.enumeration.embedded_in_current = true;1177 enum_type->data.enumeration.embedded_in_current = true;
11761178
...@@ -1179,7 +1181,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt...@@ -1179,7 +1181,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
1179 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);1181 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
1180 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];1182 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
1181 type_enum_field->name = &field_node->data.struct_field.name;1183 type_enum_field->name = &field_node->data.struct_field.name;
1182 TypeTableEntry *field_type = analyze_type_expr(g, import, import->block_context,1184 TypeTableEntry *field_type = analyze_type_expr(g, import, context,
1183 field_node->data.struct_field.type);1185 field_node->data.struct_field.type);
1184 type_enum_field->type_entry = field_type;1186 type_enum_field->type_entry = field_type;
1185 type_enum_field->value = i;1187 type_enum_field->value = i;
...@@ -1362,12 +1364,14 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -1362,12 +1364,14 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
1362 // this field should be set to true only during the recursive calls to resolve_struct_type1364 // this field should be set to true only during the recursive calls to resolve_struct_type
1363 struct_type->data.structure.embedded_in_current = true;1365 struct_type->data.structure.embedded_in_current = true;
13641366
1367 BlockContext *context = struct_type->data.structure.block_context;
1368
1365 int gen_field_index = 0;1369 int gen_field_index = 0;
1366 for (int i = 0; i < field_count; i += 1) {1370 for (int i = 0; i < field_count; i += 1) {
1367 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);1371 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
1368 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];1372 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
1369 type_struct_field->name = &field_node->data.struct_field.name;1373 type_struct_field->name = &field_node->data.struct_field.name;
1370 TypeTableEntry *field_type = analyze_type_expr(g, import, import->block_context,1374 TypeTableEntry *field_type = analyze_type_expr(g, import, context,
1371 field_node->data.struct_field.type);1375 field_node->data.struct_field.type);
1372 type_struct_field->type_entry = field_type;1376 type_struct_field->type_entry = field_type;
1373 type_struct_field->src_index = i;1377 type_struct_field->src_index = i;
...@@ -1469,16 +1473,28 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t...@@ -1469,16 +1473,28 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t
1469}1473}
14701474
1471static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {1475static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1472 assert(node->type == NodeTypeFnProto);1476 if (node->type == NodeTypeFnProto) {
1477 if (node->data.fn_proto.generic_params_is_var_args) {
1478 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1479 node->data.fn_proto.skip = true;
1480 node->data.fn_proto.generic_fn_type = g->builtin_types.entry_invalid;
1481 return;
1482 }
14731483
1474 if (node->data.fn_proto.generic_params_is_var_args) {1484 node->data.fn_proto.generic_fn_type = get_generic_fn_type(g, node);
1475 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));1485 } else if (node->type == NodeTypeStructDecl) {
1476 node->data.fn_proto.skip = true;1486 if (node->data.struct_decl.generic_params_is_var_args) {
1477 node->data.fn_proto.generic_fn_type = g->builtin_types.entry_invalid;1487 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1478 return;1488 node->data.struct_decl.skip = true;
1489 node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
1490 return;
1491 }
1492
1493 node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
1494 } else {
1495 zig_unreachable();
1479 }1496 }
14801497
1481 node->data.fn_proto.generic_fn_type = get_generic_fn_type(g, node);
1482}1498}
14831499
1484static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,1500static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
...@@ -1538,6 +1554,50 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *prot...@@ -1538,6 +1554,50 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *prot
15381554
1539}1555}
15401556
1557static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
1558 assert(node->type == NodeTypeStructDecl);
1559
1560 Buf *name = &node->data.struct_decl.name;
1561 TypeTableEntry *container_type = get_partial_container_type(g, import, context,
1562 node->data.struct_decl.kind, node, buf_ptr(name));
1563 node->data.struct_decl.type_entry = container_type;
1564
1565 // handle the member function definitions independently
1566 for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
1567 AstNode *child_node = node->data.struct_decl.fns.at(i);
1568 get_as_top_level_decl(child_node)->parent_decl = node;
1569 BlockContext *child_context = get_container_block_context(container_type);
1570 scan_decls(g, import, child_context, child_node);
1571 }
1572}
1573
1574static void resolve_struct_instance(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1575 TypeTableEntry *type_entry = node->data.struct_decl.type_entry;
1576 assert(type_entry);
1577
1578 // struct/enum member fns will get resolved independently
1579
1580 switch (node->data.struct_decl.kind) {
1581 case ContainerKindStruct:
1582 resolve_struct_type(g, import, type_entry);
1583 break;
1584 case ContainerKindEnum:
1585 resolve_enum_type(g, import, type_entry);
1586 break;
1587 case ContainerKindUnion:
1588 resolve_union_type(g, import, type_entry);
1589 break;
1590 }
1591}
1592
1593static void resolve_struct_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1594 if (node->data.struct_decl.generic_params.length > 0) {
1595 return preview_generic_fn_proto(g, import, node);
1596 } else {
1597 return resolve_struct_instance(g, import, node);
1598 }
1599}
1600
1541static void preview_error_value_decl(CodeGen *g, AstNode *node) {1601static void preview_error_value_decl(CodeGen *g, AstNode *node) {
1542 assert(node->type == NodeTypeErrorValueDecl);1602 assert(node->type == NodeTypeErrorValueDecl);
15431603
...@@ -1587,25 +1647,8 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)...@@ -1587,25 +1647,8 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
1587 preview_fn_proto(g, import, node);1647 preview_fn_proto(g, import, node);
1588 break;1648 break;
1589 case NodeTypeStructDecl:1649 case NodeTypeStructDecl:
1590 {1650 resolve_struct_decl(g, import, node);
1591 TypeTableEntry *type_entry = node->data.struct_decl.type_entry;1651 break;
1592
1593 // struct/enum member fns will get resolved independently
1594
1595 switch (node->data.struct_decl.kind) {
1596 case ContainerKindStruct:
1597 resolve_struct_type(g, import, type_entry);
1598 break;
1599 case ContainerKindEnum:
1600 resolve_enum_type(g, import, type_entry);
1601 break;
1602 case ContainerKindUnion:
1603 resolve_union_type(g, import, type_entry);
1604 break;
1605 }
1606
1607 break;
1608 }
1609 case NodeTypeVariableDeclaration:1652 case NodeTypeVariableDeclaration:
1610 {1653 {
1611 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;1654 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
...@@ -2729,6 +2772,7 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode...@@ -2729,6 +2772,7 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode
2729 return type_entry;2772 return type_entry;
2730}2773}
27312774
2775
2732static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) {2776static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) {
2733 Expr *expr = get_resolved_expr(node);2777 Expr *expr = get_resolved_expr(node);
2734 expr->const_val.ok = true;2778 expr->const_val.ok = true;
...@@ -2888,7 +2932,13 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod...@@ -2888,7 +2932,13 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
2888 return resolve_expr_const_val_as_fn(g, source_node, fn_entry);2932 return resolve_expr_const_val_as_fn(g, source_node, fn_entry);
2889 }2933 }
2890 } else if (decl_node->type == NodeTypeStructDecl) {2934 } else if (decl_node->type == NodeTypeStructDecl) {
2891 return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry);2935 if (decl_node->data.struct_decl.generic_params.length > 0) {
2936 TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type;
2937 assert(type_entry);
2938 return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry);
2939 } else {
2940 return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry);
2941 }
2892 } else if (decl_node->type == NodeTypeTypeDecl) {2942 } else if (decl_node->type == NodeTypeTypeDecl) {
2893 return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry);2943 return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry);
2894 } else {2944 } else {
...@@ -5043,9 +5093,16 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5043,9 +5093,16 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
5043 assert(generic_fn_type->id == TypeTableEntryIdGenericFn);5093 assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
50445094
5045 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;5095 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
5046 assert(decl_node->type == NodeTypeFnProto);5096 ZigList<AstNode *> *generic_params;
5097 if (decl_node->type == NodeTypeFnProto) {
5098 generic_params = &decl_node->data.fn_proto.generic_params;
5099 } else if (decl_node->type == NodeTypeStructDecl) {
5100 generic_params = &decl_node->data.struct_decl.generic_params;
5101 } else {
5102 zig_unreachable();
5103 }
50475104
5048 int expected_param_count = decl_node->data.fn_proto.generic_params.length;5105 int expected_param_count = generic_params->length;
5049 int actual_param_count = node->data.fn_call_expr.params.length;5106 int actual_param_count = node->data.fn_call_expr.params.length;
50505107
5051 if (actual_param_count != expected_param_count) {5108 if (actual_param_count != expected_param_count) {
...@@ -5061,7 +5118,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5061,7 +5118,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
50615118
5062 BlockContext *child_context = decl_node->owner->block_context;5119 BlockContext *child_context = decl_node->owner->block_context;
5063 for (int i = 0; i < actual_param_count; i += 1) {5120 for (int i = 0; i < actual_param_count; i += 1) {
5064 AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i);5121 AstNode *generic_param_decl_node = generic_params->at(i);
5065 assert(generic_param_decl_node->type == NodeTypeParamDecl);5122 assert(generic_param_decl_node->type == NodeTypeParamDecl);
50665123
5067 AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;5124 AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
...@@ -5104,24 +5161,36 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5104,24 +5161,36 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
5104 auto entry = g->generic_table.maybe_get(generic_fn_type_id);5161 auto entry = g->generic_table.maybe_get(generic_fn_type_id);
5105 if (entry) {5162 if (entry) {
5106 AstNode *impl_decl_node = entry->value;5163 AstNode *impl_decl_node = entry->value;
5107 assert(impl_decl_node->type == NodeTypeFnProto);5164 if (impl_decl_node->type == NodeTypeFnProto) {
5108 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;5165 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
5109 return resolve_expr_const_val_as_fn(g, node, fn_table_entry);5166 return resolve_expr_const_val_as_fn(g, node, fn_table_entry);
5167 } else if (impl_decl_node->type == NodeTypeStructDecl) {
5168 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5169 return resolve_expr_const_val_as_type(g, node, type_entry);
5170 } else {
5171 zig_unreachable();
5172 }
5110 }5173 }
51115174
5112 // make a type from the generic parameters supplied5175 // make a type from the generic parameters supplied
5113 assert(decl_node->type == NodeTypeFnProto);5176 if (decl_node->type == NodeTypeFnProto) {
5114 AstNode *impl_fn_def_node = ast_clone_subtree(decl_node->data.fn_proto.fn_def_node, &g->next_node_index);5177 AstNode *impl_fn_def_node = ast_clone_subtree(decl_node->data.fn_proto.fn_def_node, &g->next_node_index);
5115 AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;5178 AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
5116
5117
51185179
5119 preview_fn_proto_instance(g, import, impl_decl_node, child_context);5180 preview_fn_proto_instance(g, import, impl_decl_node, child_context);
51205181 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5121 g->generic_table.put(generic_fn_type_id, impl_decl_node);5182 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
51225183 return resolve_expr_const_val_as_fn(g, node, fn_table_entry);
5123 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;5184 } else if (decl_node->type == NodeTypeStructDecl) {
5124 return resolve_expr_const_val_as_fn(g, node, fn_table_entry);5185 AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
5186 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5187 scan_struct_decl(g, import, child_context, impl_decl_node);
5188 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5189 resolve_struct_type(g, import, type_entry);
5190 return resolve_expr_const_val_as_type(g, node, type_entry);
5191 } else {
5192 zig_unreachable();
5193 }
5125}5194}
51265195
5127static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,5196static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -6065,7 +6134,8 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex...@@ -6065,7 +6134,8 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
6065 tld->name = name;6134 tld->name = name;
60666135
6067 bool want_as_export = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);6136 bool want_as_export = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);
6068 bool is_generic = (node->type == NodeTypeFnProto && node->data.fn_proto.generic_params.length > 0);6137 bool is_generic = (node->type == NodeTypeFnProto && node->data.fn_proto.generic_params.length > 0) ||
6138 (node->type == NodeTypeStructDecl && node->data.struct_decl.generic_params.length > 0);
6069 if (!is_generic && want_as_export) {6139 if (!is_generic && want_as_export) {
6070 g->export_queue.append(node);6140 g->export_queue.append(node);
6071 }6141 }
...@@ -6093,21 +6163,12 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte...@@ -6093,21 +6163,12 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
6093 case NodeTypeStructDecl:6163 case NodeTypeStructDecl:
6094 {6164 {
6095 Buf *name = &node->data.struct_decl.name;6165 Buf *name = &node->data.struct_decl.name;
6096 TypeTableEntry *container_type = get_partial_container_type(g, import,
6097 node->data.struct_decl.kind, node, buf_ptr(name));
6098 node->data.struct_decl.type_entry = container_type;
6099 add_top_level_decl(g, import, context, node, name);6166 add_top_level_decl(g, import, context, node, name);
61006167 if (node->data.struct_decl.generic_params.length == 0) {
6101 // handle the member function definitions independently6168 scan_struct_decl(g, import, context, node);
6102 for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
6103 AstNode *child_node = node->data.struct_decl.fns.at(i);
6104 get_as_top_level_decl(child_node)->parent_decl = node;
6105 BlockContext *child_context = get_container_block_context(container_type);
6106 scan_decls(g, import, child_context, child_node);
6107 }6169 }
6108
6109 break;
6110 }6170 }
6171 break;
6111 case NodeTypeFnDef:6172 case NodeTypeFnDef:
6112 node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;6173 node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
6113 scan_decls(g, import, context, node->data.fn_def.fn_proto);6174 scan_decls(g, import, context, node->data.fn_def.fn_proto);
src/analyze.hpp+1-1
...@@ -27,7 +27,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);...@@ -27,7 +27,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
30TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,30TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
31 ContainerKind kind, AstNode *decl_node, const char *name);31 ContainerKind kind, AstNode *decl_node, const char *name);
32TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);32TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
33bool handle_is_ptr(TypeTableEntry *type_entry);33bool handle_is_ptr(TypeTableEntry *type_entry);
src/parseh.cpp+3-1
...@@ -801,6 +801,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)...@@ -801,6 +801,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
801 const EnumDecl *enum_def = enum_decl->getDefinition();801 const EnumDecl *enum_def = enum_decl->getDefinition();
802 if (!enum_def) {802 if (!enum_def) {
803 TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,803 TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
804 c->import->block_context,
804 ContainerKindEnum, c->source_node, buf_ptr(full_type_name));805 ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
805 c->enum_type_table.put(bare_name, enum_type);806 c->enum_type_table.put(bare_name, enum_type);
806 c->decl_table.put(enum_decl, enum_type);807 c->decl_table.put(enum_decl, enum_type);
...@@ -825,6 +826,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)...@@ -825,6 +826,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
825826
826 if (pure_enum) {827 if (pure_enum) {
827 TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,828 TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
829 c->import->block_context,
828 ContainerKindEnum, c->source_node, buf_ptr(full_type_name));830 ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
829 c->enum_type_table.put(bare_name, enum_type);831 c->enum_type_table.put(bare_name, enum_type);
830 c->decl_table.put(enum_decl, enum_type);832 c->decl_table.put(enum_decl, enum_type);
...@@ -985,7 +987,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_...@@ -985,7 +987,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
985987
986988
987 TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,989 TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,
988 ContainerKindStruct, c->source_node, buf_ptr(full_type_name));990 c->import->block_context, ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
989991
990 c->struct_type_table.put(bare_name, struct_type);992 c->struct_type_table.put(bare_name, struct_type);
991 c->decl_table.put(record_decl, struct_type);993 c->decl_table.put(record_decl, struct_type);
src/parser.cpp+12-5
...@@ -762,9 +762,7 @@ static void ast_parse_param_decl_list(ParseContext *pc, int *token_index,...@@ -762,9 +762,7 @@ static void ast_parse_param_decl_list(ParseContext *pc, int *token_index,
762{762{
763 *is_var_args = false;763 *is_var_args = false;
764764
765 Token *l_paren = &pc->tokens->at(*token_index);765 ast_eat_token(pc, token_index, TokenIdLParen);
766 *token_index += 1;
767 ast_expect_token(pc, l_paren, TokenIdLParen);
768766
769 Token *token = &pc->tokens->at(*token_index);767 Token *token = &pc->tokens->at(*token_index);
770 if (token->id == TokenIdRParen) {768 if (token->id == TokenIdRParen) {
...@@ -2606,7 +2604,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index,...@@ -2606,7 +2604,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index,
2606}2604}
26072605
2608/*2606/*
2609ContainerDecl = ("struct" | "enum" | "union") "Symbol" "{" many(StructMember) "}"2607ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
2610StructMember: many(Directive) option(VisibleMod) (StructField | FnDef)2608StructMember: many(Directive) option(VisibleMod) (StructField | FnDef)
2611StructField : "Symbol" option(":" Expression) ",")2609StructField : "Symbol" option(":" Expression) ",")
2612*/2610*/
...@@ -2636,7 +2634,16 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index,...@@ -2636,7 +2634,16 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index,
2636 node->data.struct_decl.top_level_decl.visib_mod = visib_mod;2634 node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
2637 node->data.struct_decl.top_level_decl.directives = directives;2635 node->data.struct_decl.top_level_decl.directives = directives;
26382636
2639 ast_eat_token(pc, token_index, TokenIdLBrace);2637 Token *paren_or_brace = &pc->tokens->at(*token_index);
2638 if (paren_or_brace->id == TokenIdLParen) {
2639 ast_parse_param_decl_list(pc, token_index, &node->data.struct_decl.generic_params,
2640 &node->data.struct_decl.generic_params_is_var_args);
2641 ast_eat_token(pc, token_index, TokenIdLBrace);
2642 } else if (paren_or_brace->id == TokenIdLBrace) {
2643 *token_index += 1;
2644 } else {
2645 ast_invalid_token_error(pc, paren_or_brace);
2646 }
26402647
2641 for (;;) {2648 for (;;) {
2642 Token *directive_token = &pc->tokens->at(*token_index);2649 Token *directive_token = &pc->tokens->at(*token_index);
test/self_hosted.zig+12
...@@ -1566,3 +1566,15 @@ fn c_string_concatenation() {...@@ -1566,3 +1566,15 @@ fn c_string_concatenation() {
1566 assert(a[len] == 0);1566 assert(a[len] == 0);
1567 assert(b[len] == 0);1567 assert(b[len] == 0);
1568}1568}
1569
1570#attribute("test")
1571fn generic_struct() {
1572 var a1 = GenNode(i32) {.value = 13, .next = null,};
1573 var b1 = GenNode(bool) {.value = true, .next = null,};
1574 assert(a1.value == 13);
1575 assert(b1.value);
1576}
1577struct GenNode(T: type) {
1578 value: T,
1579 next: ?&GenNode(T),
1580}