authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-07-24 18:35:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-07-25 22:55:15-07:00
log78d4fb20c44488117cc450177d92c44a19d97c91
tree3a39a09a30d7667de2e4fc62ab1c14fdaddb00b2
parent425c0ffa014fb950a4f9f90aa9a200fbc4d8e091

inline parameters

This replaces the current generic syntax for functions and replaces it with the concept of inline parameters. This paves the way for the "all structs anonymous" proposal. Closes #151.

19 files changed, 565 insertions(+), 293 deletions(-)

doc/langref.md+2-2
...@@ -25,7 +25,7 @@ UseDecl = "use" Expression ";"...@@ -25,7 +25,7 @@ UseDecl = "use" Expression ";"
2525
26ExternDecl = "extern" (FnProto | VariableDeclaration) ";"26ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
2727
28FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr)28FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
2929
30Directive = "#" "Symbol" "(" Expression ")"30Directive = "#" "Symbol" "(" Expression ")"
3131
...@@ -35,7 +35,7 @@ FnDef = option("inline" | "extern") FnProto Block...@@ -35,7 +35,7 @@ FnDef = option("inline" | "extern") FnProto Block
3535
36ParamDeclList = "(" list(ParamDecl, ",") ")"36ParamDeclList = "(" list(ParamDecl, ",") ")"
3737
38ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."38ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
3939
40Block = "{" list(option(Statement), ";") "}"40Block = "{" list(option(Statement), ";") "}"
4141
example/guess_number/main.zig+1-1
...@@ -23,7 +23,7 @@ pub fn main(args: [][]u8) -> %void {...@@ -23,7 +23,7 @@ pub fn main(args: [][]u8) -> %void {
23 return err;23 return err;
24 };24 };
2525
26 const guess = io.parse_unsigned(u8)(line_buf[0...line_len - 1], 10) %% {26 const guess = io.parse_unsigned(u8, line_buf[0...line_len - 1], 10) %% {
27 %%io.stdout.printf("Invalid number.\n");27 %%io.stdout.printf("Invalid number.\n");
28 continue;28 continue;
29 };29 };
src/all_types.hpp+9-6
...@@ -195,10 +195,8 @@ struct AstNodeRoot {...@@ -195,10 +195,8 @@ struct AstNodeRoot {
195struct AstNodeFnProto {195struct AstNodeFnProto {
196 TopLevelDecl top_level_decl;196 TopLevelDecl top_level_decl;
197 Buf name;197 Buf name;
198 ZigList<AstNode *> generic_params;
199 ZigList<AstNode *> params;198 ZigList<AstNode *> params;
200 AstNode *return_type;199 AstNode *return_type;
201 bool generic_params_is_var_args;
202 bool is_var_args;200 bool is_var_args;
203 bool is_extern;201 bool is_extern;
204 bool is_inline;202 bool is_inline;
...@@ -210,7 +208,10 @@ struct AstNodeFnProto {...@@ -210,7 +208,10 @@ struct AstNodeFnProto {
210 FnTableEntry *fn_table_entry;208 FnTableEntry *fn_table_entry;
211 bool skip;209 bool skip;
212 Expr resolved_expr;210 Expr resolved_expr;
213 TypeTableEntry *generic_fn_type;211 // computed from params field
212 int inline_arg_count;
213 // if this is a generic function implementation, this points to the generic node
214 AstNode *generic_proto_node;
214};215};
215216
216struct AstNodeFnDef {217struct AstNodeFnDef {
...@@ -219,6 +220,7 @@ struct AstNodeFnDef {...@@ -219,6 +220,7 @@ struct AstNodeFnDef {
219220
220 // populated by semantic analyzer221 // populated by semantic analyzer
221 TypeTableEntry *implicit_return_type;222 TypeTableEntry *implicit_return_type;
223 // the first child block context
222 BlockContext *block_context;224 BlockContext *block_context;
223};225};
224226
...@@ -230,6 +232,7 @@ struct AstNodeParamDecl {...@@ -230,6 +232,7 @@ struct AstNodeParamDecl {
230 Buf name;232 Buf name;
231 AstNode *type;233 AstNode *type;
232 bool is_noalias;234 bool is_noalias;
235 bool is_inline;
233236
234 // populated by semantic analyzer237 // populated by semantic analyzer
235 VariableTableEntry *variable;238 VariableTableEntry *variable;
...@@ -841,6 +844,7 @@ struct FnTypeId {...@@ -841,6 +844,7 @@ struct FnTypeId {
841 bool is_naked;844 bool is_naked;
842 bool is_cold;845 bool is_cold;
843 bool is_extern;846 bool is_extern;
847 bool is_inline;
844 FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];848 FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
845};849};
846850
...@@ -1063,7 +1067,6 @@ struct FnTableEntry {...@@ -1063,7 +1067,6 @@ struct FnTableEntry {
1063 ZigList<LabelTableEntry *> all_labels;1067 ZigList<LabelTableEntry *> all_labels;
1064 Buf symbol_name;1068 Buf symbol_name;
1065 TypeTableEntry *type_entry; // function type1069 TypeTableEntry *type_entry; // function type
1066 bool is_inline;
1067 bool internal_linkage;1070 bool internal_linkage;
1068 bool is_extern;1071 bool is_extern;
1069 bool is_test;1072 bool is_test;
...@@ -1172,8 +1175,8 @@ struct CodeGen {...@@ -1172,8 +1175,8 @@ struct CodeGen {
11721175
1173 ZigList<ImportTableEntry *> import_queue;1176 ZigList<ImportTableEntry *> import_queue;
1174 int import_queue_index;1177 int import_queue_index;
1175 ZigList<AstNode *> export_queue;1178 ZigList<AstNode *> resolve_queue;
1176 int export_queue_index;1179 int resolve_queue_index;
1177 ZigList<AstNode *> use_queue;1180 ZigList<AstNode *> use_queue;
1178 int use_queue_index;1181 int use_queue_index;
11791182
src/analyze.cpp+318-152
...@@ -32,6 +32,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,...@@ -32,6 +32,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
32static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);32static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
33static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,33static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
34 bool depends_on_compile_var);34 bool depends_on_compile_var);
35static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode *node,
36 TypeTableEntry *type_entry, bool depends_on_compile_var);
35static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,37static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
36 bool depends_on_compile_var);38 bool depends_on_compile_var);
37static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,39static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
...@@ -874,7 +876,8 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -874,7 +876,8 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
874 fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport);876 fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport);
875 fn_type_id.is_naked = is_naked;877 fn_type_id.is_naked = is_naked;
876 fn_type_id.is_cold = is_cold;878 fn_type_id.is_cold = is_cold;
877 fn_type_id.param_count = node->data.fn_proto.params.length;879 fn_type_id.is_inline = fn_proto->is_inline;
880 fn_type_id.param_count = fn_proto->params.length;
878881
879 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {882 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
880 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);883 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
...@@ -883,15 +886,52 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -883,15 +886,52 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
883 }886 }
884887
885 fn_type_id.is_var_args = fn_proto->is_var_args;888 fn_type_id.is_var_args = fn_proto->is_var_args;
886 fn_type_id.return_type = analyze_type_expr(g, import, context, node->data.fn_proto.return_type);889 fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);
887890
888 if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {891 switch (fn_type_id.return_type->id) {
889 fn_proto->skip = true;892 case TypeTableEntryIdInvalid:
893 fn_proto->skip = true;
894 break;
895 case TypeTableEntryIdNumLitFloat:
896 case TypeTableEntryIdNumLitInt:
897 case TypeTableEntryIdUndefLit:
898 case TypeTableEntryIdNamespace:
899 case TypeTableEntryIdGenericFn:
900 fn_proto->skip = true;
901 add_node_error(g, fn_proto->return_type,
902 buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
903 break;
904 case TypeTableEntryIdMetaType:
905 if (!fn_proto->is_inline) {
906 fn_proto->skip = true;
907 add_node_error(g, fn_proto->return_type,
908 buf_sprintf("function with return type '%s' must be declared inline",
909 buf_ptr(&fn_type_id.return_type->name)));
910 return g->builtin_types.entry_invalid;
911 }
912 break;
913 case TypeTableEntryIdUnreachable:
914 case TypeTableEntryIdVoid:
915 case TypeTableEntryIdBool:
916 case TypeTableEntryIdInt:
917 case TypeTableEntryIdFloat:
918 case TypeTableEntryIdPointer:
919 case TypeTableEntryIdArray:
920 case TypeTableEntryIdStruct:
921 case TypeTableEntryIdMaybe:
922 case TypeTableEntryIdErrorUnion:
923 case TypeTableEntryIdPureError:
924 case TypeTableEntryIdEnum:
925 case TypeTableEntryIdUnion:
926 case TypeTableEntryIdFn:
927 case TypeTableEntryIdTypeDecl:
928 break;
890 }929 }
891930
892 for (int i = 0; i < fn_type_id.param_count; i += 1) {931 for (int i = 0; i < fn_type_id.param_count; i += 1) {
893 AstNode *child = node->data.fn_proto.params.at(i);932 AstNode *child = fn_proto->params.at(i);
894 assert(child->type == NodeTypeParamDecl);933 assert(child->type == NodeTypeParamDecl);
934
895 TypeTableEntry *type_entry = analyze_type_expr(g, import, context,935 TypeTableEntry *type_entry = analyze_type_expr(g, import, context,
896 child->data.param_decl.type);936 child->data.param_decl.type);
897 switch (type_entry->id) {937 switch (type_entry->id) {
...@@ -901,13 +941,20 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -901,13 +941,20 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
901 case TypeTableEntryIdNumLitFloat:941 case TypeTableEntryIdNumLitFloat:
902 case TypeTableEntryIdNumLitInt:942 case TypeTableEntryIdNumLitInt:
903 case TypeTableEntryIdUndefLit:943 case TypeTableEntryIdUndefLit:
904 case TypeTableEntryIdMetaType:
905 case TypeTableEntryIdUnreachable:944 case TypeTableEntryIdUnreachable:
906 case TypeTableEntryIdNamespace:945 case TypeTableEntryIdNamespace:
907 case TypeTableEntryIdGenericFn:946 case TypeTableEntryIdGenericFn:
908 fn_proto->skip = true;947 fn_proto->skip = true;
909 add_node_error(g, child->data.param_decl.type,948 add_node_error(g, child->data.param_decl.type,
910 buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name)));949 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
950 break;
951 case TypeTableEntryIdMetaType:
952 if (!child->data.param_decl.is_inline) {
953 fn_proto->skip = true;
954 add_node_error(g, child->data.param_decl.type,
955 buf_sprintf("parameter of type '%s' must be declared inline",
956 buf_ptr(&type_entry->name)));
957 }
911 break;958 break;
912 case TypeTableEntryIdVoid:959 case TypeTableEntryIdVoid:
913 case TypeTableEntryIdBool:960 case TypeTableEntryIdBool:
...@@ -998,8 +1045,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -998,8 +1045,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
998 return;1045 return;
999 }1046 }
10001047
1001 fn_table_entry->is_inline = fn_proto->is_inline;
1002
1003 bool is_cold = false;1048 bool is_cold = false;
1004 bool is_naked = false;1049 bool is_naked = false;
1005 bool is_test = false;1050 bool is_test = false;
...@@ -1095,7 +1140,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -1095,7 +1140,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
1095 return;1140 return;
1096 }1141 }
10971142
1098 if (fn_table_entry->is_inline && fn_table_entry->is_noinline) {1143 if (fn_proto->is_inline && fn_table_entry->is_noinline) {
1099 add_node_error(g, node, buf_sprintf("function is both inline and noinline"));1144 add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
1100 fn_proto->skip = true;1145 fn_proto->skip = true;
1101 return;1146 return;
...@@ -1109,10 +1154,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -1109,10 +1154,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
1109 symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));1154 symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
1110 }1155 }
11111156
1112 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),1157 if (fn_table_entry->fn_def_node) {
1113 fn_type->data.fn.raw_type_ref);1158 BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context);
1159 fn_table_entry->fn_def_node->data.fn_def.block_context = context;
1160 }
1161
1162 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
11141163
1115 if (fn_table_entry->is_inline) {1164 if (fn_proto->is_inline) {
1116 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);1165 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
1117 }1166 }
1118 if (fn_table_entry->is_noinline) {1167 if (fn_table_entry->is_noinline) {
...@@ -1150,9 +1199,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -1150,9 +1199,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
1150 fn_type->di_type, fn_table_entry->internal_linkage,1199 fn_type->di_type, fn_table_entry->internal_linkage,
1151 is_definition, scope_line, flags, is_optimized, nullptr);1200 is_definition, scope_line, flags, is_optimized, nullptr);
11521201
1153 BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context);1202 fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
1154 fn_table_entry->fn_def_node->data.fn_def.block_context = context;
1155 context->di_scope = LLVMZigSubprogramToScope(subprogram);
1156 ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);1203 ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
1157 }1204 }
1158}1205}
...@@ -1176,6 +1223,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt...@@ -1176,6 +1223,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
1176 return;1223 return;
1177 }1224 }
11781225
1226 assert(decl_node->type == NodeTypeContainerDecl);
1179 assert(enum_type->di_type);1227 assert(enum_type->di_type);
11801228
1181 enum_type->deep_const = true;1229 enum_type->deep_const = true;
...@@ -1370,7 +1418,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -1370,7 +1418,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
1370 return;1418 return;
1371 }1419 }
13721420
13731421 assert(decl_node->type == NodeTypeContainerDecl);
1374 assert(struct_type->di_type);1422 assert(struct_type->di_type);
13751423
1376 struct_type->deep_const = true;1424 struct_type->deep_const = true;
...@@ -1496,38 +1544,30 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t...@@ -1496,38 +1544,30 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t
1496}1544}
14971545
1498static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {1546static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1499 if (node->type == NodeTypeFnProto) {1547 assert(node->type == NodeTypeContainerDecl);
1500 if (node->data.fn_proto.generic_params_is_var_args) {
1501 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1502 node->data.fn_proto.skip = true;
1503 node->data.fn_proto.generic_fn_type = g->builtin_types.entry_invalid;
1504 return;
1505 }
1506
1507 node->data.fn_proto.generic_fn_type = get_generic_fn_type(g, node);
1508 } else if (node->type == NodeTypeContainerDecl) {
1509 if (node->data.struct_decl.generic_params_is_var_args) {
1510 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1511 node->data.struct_decl.skip = true;
1512 node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
1513 return;
1514 }
15151548
1516 node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);1549 if (node->data.struct_decl.generic_params_is_var_args) {
1517 } else {1550 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1518 zig_unreachable();1551 node->data.struct_decl.skip = true;
1552 node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
1553 return;
1519 }1554 }
15201555
1556 node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
1521}1557}
15221558
1523static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,1559static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
1524 BlockContext *containing_context)1560 BlockContext *containing_context)
1525{1561{
1562 assert(proto_node->type == NodeTypeFnProto);
1563
1526 if (proto_node->data.fn_proto.skip) {1564 if (proto_node->data.fn_proto.skip) {
1527 return;1565 return;
1528 }1566 }
15291567
1530 bool is_generic_instance = (proto_node->data.fn_proto.generic_params.length > 0);1568 bool is_generic_instance = proto_node->data.fn_proto.generic_proto_node;
1569 bool is_generic_fn = proto_node->data.fn_proto.inline_arg_count > 0;
1570 assert(!is_generic_instance || !is_generic_fn);
15311571
1532 AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;1572 AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
1533 Buf *proto_name = &proto_node->data.fn_proto.name;1573 Buf *proto_name = &proto_node->data.fn_proto.name;
...@@ -1551,41 +1591,50 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN...@@ -1551,41 +1591,50 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
15511591
1552 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');1592 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
15531593
1554 g->fn_protos.append(fn_table_entry);1594 proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
1555
1556 if (fn_def_node) {
1557 g->fn_defs.append(fn_table_entry);
1558 }
15591595
1560 bool is_main_fn = !is_generic_instance &&1596 if (is_generic_fn) {
1561 !parent_decl && (import == g->root_import) &&1597 fn_table_entry->type_entry = get_generic_fn_type(g, proto_node);
1562 buf_eql_str(proto_name, "main");
1563 if (is_main_fn) {
1564 g->main_fn = fn_table_entry;
1565 }
15661598
1567 proto_node->data.fn_proto.fn_table_entry = fn_table_entry;1599 if (is_extern || proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModExport) {
1568 resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context);1600 for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
15691601 AstNode *param_decl_node = proto_node->data.fn_proto.params.at(i);
1570 if (is_main_fn && !g->link_libc) {1602 if (param_decl_node->data.param_decl.is_inline) {
1571 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);1603 proto_node->data.fn_proto.skip = true;
1572 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;1604 add_node_error(g, param_decl_node,
1573 if (actual_return_type != err_void) {1605 buf_sprintf("inline parameter not allowed in extern function"));
1574 AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type;1606 }
1575 add_node_error(g, return_type_node,1607 }
1576 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
1577 buf_ptr(&actual_return_type->name)));
1578 }1608 }
1579 }
1580}
15811609
1582static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) {1610
1583 if (proto_node->data.fn_proto.generic_params.length > 0) {
1584 return preview_generic_fn_proto(g, import, proto_node);
1585 } else {1611 } else {
1586 return preview_fn_proto_instance(g, import, proto_node, proto_node->block_context);1612 g->fn_protos.append(fn_table_entry);
1587 }1613
1614 if (fn_def_node) {
1615 g->fn_defs.append(fn_table_entry);
1616 }
1617
1618 bool is_main_fn = !is_generic_instance &&
1619 !parent_decl && (import == g->root_import) &&
1620 buf_eql_str(proto_name, "main");
1621 if (is_main_fn) {
1622 g->main_fn = fn_table_entry;
1623 }
15881624
1625 resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context);
1626
1627 if (is_main_fn && !g->link_libc) {
1628 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
1629 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
1630 if (actual_return_type != err_void) {
1631 AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type;
1632 add_node_error(g, return_type_node,
1633 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
1634 buf_ptr(&actual_return_type->name)));
1635 }
1636 }
1637 }
1589}1638}
15901639
1591static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {1640static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
...@@ -1683,7 +1732,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)...@@ -1683,7 +1732,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
16831732
1684 switch (node->type) {1733 switch (node->type) {
1685 case NodeTypeFnProto:1734 case NodeTypeFnProto:
1686 preview_fn_proto(g, import, node);1735 preview_fn_proto_instance(g, import, node, node->block_context);
1687 break;1736 break;
1688 case NodeTypeContainerDecl:1737 case NodeTypeContainerDecl:
1689 resolve_struct_decl(g, import, node);1738 resolve_struct_decl(g, import, node);
...@@ -2600,7 +2649,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -2600,7 +2649,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
26002649
2601 node->data.field_access_expr.is_member_fn = true;2650 node->data.field_access_expr.is_member_fn = true;
2602 FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;2651 FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
2603 return resolve_expr_const_val_as_fn(g, node, fn_entry, false);2652 if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
2653 return resolve_expr_const_val_as_generic_fn(g, node, fn_entry->type_entry, false);
2654 } else {
2655 return resolve_expr_const_val_as_fn(g, node, fn_entry, false);
2656 }
2604 } else {2657 } else {
2605 add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",2658 add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",
2606 buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));2659 buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
...@@ -3004,13 +3057,11 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod...@@ -3004,13 +3057,11 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
3004 VariableTableEntry *var = decl_node->data.variable_declaration.variable;3057 VariableTableEntry *var = decl_node->data.variable_declaration.variable;
3005 return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var);3058 return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var);
3006 } else if (decl_node->type == NodeTypeFnProto) {3059 } else if (decl_node->type == NodeTypeFnProto) {
3007 if (decl_node->data.fn_proto.generic_params.length > 0) {3060 FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
3008 TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;3061 assert(fn_entry->type_entry);
3009 assert(type_entry);3062 if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
3010 return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);3063 return resolve_expr_const_val_as_generic_fn(g, source_node, fn_entry->type_entry, depends_on_compile_var);
3011 } else {3064 } else {
3012 FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
3013 assert(fn_entry->type_entry);
3014 return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);3065 return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
3015 }3066 }
3016 } else if (decl_node->type == NodeTypeContainerDecl) {3067 } else if (decl_node->type == NodeTypeContainerDecl) {
...@@ -5238,6 +5289,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -5238,6 +5289,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
5238 zig_unreachable();5289 zig_unreachable();
5239}5290}
52405291
5292// Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known
5293// at compile time. Otherwise this is a function pointer call.
5241static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,5294static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
5242 TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,5295 TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
5243 AstNode *struct_node)5296 AstNode *struct_node)
...@@ -5248,26 +5301,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5248,26 +5301,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
5248 return fn_type;5301 return fn_type;
5249 }5302 }
52505303
5251 // count parameters5304 // The function call might include inline parameters which we need to ignore according to the
5252 int src_param_count = fn_type->data.fn.fn_type_id.param_count;5305 // fn_type.
5253 int actual_param_count = node->data.fn_call_expr.params.length;5306 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
5307 AstNode *generic_proto_node = fn_table_entry ?
5308 fn_table_entry->proto_node->data.fn_proto.generic_proto_node : nullptr;
52545309
5255 if (struct_node) {5310 // count parameters
5256 actual_param_count += 1;5311 int struct_node_1_or_0 = struct_node ? 1 : 0;
5257 }5312 int src_param_count = fn_type->data.fn.fn_type_id.param_count +
5313 (generic_proto_node ? generic_proto_node->data.fn_proto.inline_arg_count : 0);
5314 int call_param_count = node->data.fn_call_expr.params.length;
52585315
5259 bool ok_invocation = true;5316 bool ok_invocation = true;
52605317
5261 if (fn_type->data.fn.fn_type_id.is_var_args) {5318 if (fn_type->data.fn.fn_type_id.is_var_args) {
5262 if (actual_param_count < src_param_count) {5319 if (call_param_count < src_param_count - struct_node_1_or_0) {
5263 ok_invocation = false;5320 ok_invocation = false;
5264 add_node_error(g, node,5321 add_node_error(g, node,
5265 buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));5322 buf_sprintf("expected at least %d arguments, got %d", src_param_count, call_param_count));
5266 }5323 }
5267 } else if (src_param_count != actual_param_count) {5324 } else if (src_param_count - struct_node_1_or_0 != call_param_count) {
5268 ok_invocation = false;5325 ok_invocation = false;
5269 add_node_error(g, node,5326 add_node_error(g, node,
5270 buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));5327 buf_sprintf("expected %d arguments, got %d", src_param_count, call_param_count));
5271 }5328 }
52725329
5273 bool all_args_const_expr = true;5330 bool all_args_const_expr = true;
...@@ -5281,17 +5338,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5281,17 +5338,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
52815338
5282 // analyze each parameter. in the case of a method, we already analyzed the5339 // analyze each parameter. in the case of a method, we already analyzed the
5283 // first parameter in order to figure out which struct we were calling a method on.5340 // first parameter in order to figure out which struct we were calling a method on.
5284 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {5341 int next_type_i = struct_node_1_or_0;
5285 AstNode **child = &node->data.fn_call_expr.params.at(i);5342 for (int call_i = 0; call_i < call_param_count; call_i += 1) {
5343 int proto_i = call_i + struct_node_1_or_0;
5344 AstNode **param_node = &node->data.fn_call_expr.params.at(call_i);
5286 // determine the expected type for each parameter5345 // determine the expected type for each parameter
5287 TypeTableEntry *expected_param_type = nullptr;5346 TypeTableEntry *expected_param_type = nullptr;
5288 int fn_proto_i = i + (struct_node ? 1 : 0);5347 if (proto_i < src_param_count) {
5289 if (fn_proto_i < src_param_count) {5348 if (generic_proto_node &&
5290 expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;5349 generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
5350 {
5351 continue;
5352 }
5353
5354 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[next_type_i];
5355 next_type_i += 1;
5356
5357 expected_param_type = param_info->type;
5358 }
5359 TypeTableEntry *param_type = analyze_expression(g, import, context, expected_param_type, *param_node);
5360 if (param_type->id == TypeTableEntryIdInvalid) {
5361 return param_type;
5291 }5362 }
5292 analyze_expression(g, import, context, expected_param_type, *child);
52935363
5294 ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val;5364 ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val;
5295 if (!const_arg_val->ok) {5365 if (!const_arg_val->ok) {
5296 all_args_const_expr = false;5366 all_args_const_expr = false;
5297 }5367 }
...@@ -5303,7 +5373,6 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5303,7 +5373,6 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
5303 return return_type;5373 return return_type;
5304 }5374 }
53055375
5306 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
5307 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;5376 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
5308 if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {5377 if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {
5309 if (fn_table_entry->anal_state == FnAnalStateReady) {5378 if (fn_table_entry->anal_state == FnAnalStateReady) {
...@@ -5335,14 +5404,103 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5335,14 +5404,103 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
5335 return return_type;5404 return return_type;
5336}5405}
53375406
5338static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,5407static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableEntry *import,
5339 TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node)5408 BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *call_node,
5409 FnTableEntry *fn_table_entry, AstNode *struct_node)
5340{5410{
5341 assert(node->type == NodeTypeFnCallExpr);5411 assert(call_node->type == NodeTypeFnCallExpr);
5412 assert(fn_table_entry);
5413
5414 AstNode *decl_node = fn_table_entry->proto_node;
5415
5416 // count parameters
5417 int struct_node_1_or_0 = (struct_node ? 1 : 0);
5418 int src_param_count = decl_node->data.fn_proto.params.length;
5419 int call_param_count = call_node->data.fn_call_expr.params.length;
5420
5421 if (src_param_count != call_param_count + struct_node_1_or_0) {
5422 add_node_error(g, call_node,
5423 buf_sprintf("expected %d arguments, got %d", src_param_count, call_param_count));
5424 return g->builtin_types.entry_invalid;
5425 }
5426
5427 int inline_arg_count = decl_node->data.fn_proto.inline_arg_count;
5428 assert(inline_arg_count > 0);
5429
5430 BlockContext *child_context = decl_node->owner->block_context;
5431 int next_generic_param_index = 0;
5432
5433 GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
5434 generic_fn_type_id->decl_node = decl_node;
5435 generic_fn_type_id->generic_param_count = inline_arg_count;
5436 generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_arg_count);
5437
5438 for (int call_i = 0; call_i < call_param_count; call_i += 1) {
5439 int proto_i = call_i + struct_node_1_or_0;
5440 AstNode *generic_param_decl_node = decl_node->data.fn_proto.params.at(proto_i);
5441 assert(generic_param_decl_node->type == NodeTypeParamDecl);
5442 bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
5443 if (!is_inline) continue;
5444
5445 AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
5446 TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, child_context,
5447 *generic_param_type_node);
5448 if (expected_param_type->id == TypeTableEntryIdInvalid) {
5449 return expected_param_type;
5450 }
5451
5452 AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
5453 TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
5454 expected_param_type, *param_node);
5455 if (param_type->id == TypeTableEntryIdInvalid) {
5456 return param_type;
5457 }
5458
5459 // set child_context so that the previous param is in scope
5460 child_context = new_block_context(generic_param_decl_node, child_context);
5461
5462 ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
5463 if (const_val->ok) {
5464 add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
5465 &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
5466 } else {
5467 add_node_error(g, *param_node,
5468 buf_sprintf("unable to evaluate constant expression for inline parameter"));
5469
5470 return g->builtin_types.entry_invalid;
5471 }
5472
5473 GenericParamValue *generic_param_value =
5474 &generic_fn_type_id->generic_params[next_generic_param_index];
5475 generic_param_value->type = param_type;
5476 generic_param_value->node = *param_node;
5477 next_generic_param_index += 1;
5478 }
5479
5480 assert(next_generic_param_index == inline_arg_count);
5481
5482 auto entry = g->generic_table.maybe_get(generic_fn_type_id);
5483 FnTableEntry *impl_fn;
5484 if (entry) {
5485 AstNode *impl_decl_node = entry->value;
5486 assert(impl_decl_node->type == NodeTypeFnProto);
5487 impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
5488 } else {
5489 AstNode *decl_node = generic_fn_type_id->decl_node;
5490 AstNode *impl_fn_def_node = ast_clone_subtree_special(decl_node->data.fn_proto.fn_def_node,
5491 &g->next_node_index, AstCloneSpecialOmitInlineParams);
5492 AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
5493 impl_decl_node->data.fn_proto.inline_arg_count = 0;
5494 impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
53425495
5343 node->data.fn_call_expr.fn_entry = fn_table_entry;5496 preview_fn_proto_instance(g, import, impl_decl_node, child_context);
5497 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5498 impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
5499 }
53445500
5345 return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node);5501 call_node->data.fn_call_expr.fn_entry = impl_fn;
5502 return analyze_fn_call_ptr(g, import, parent_context, expected_type, call_node,
5503 impl_fn->type_entry, struct_node);
5346}5504}
53475505
5348static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,5506static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
...@@ -5352,14 +5510,8 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5352,14 +5510,8 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
5352 assert(generic_fn_type->id == TypeTableEntryIdGenericFn);5510 assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
53535511
5354 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;5512 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
5355 ZigList<AstNode *> *generic_params;5513 assert(decl_node->type == NodeTypeContainerDecl);
5356 if (decl_node->type == NodeTypeFnProto) {5514 ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
5357 generic_params = &decl_node->data.fn_proto.generic_params;
5358 } else if (decl_node->type == NodeTypeContainerDecl) {
5359 generic_params = &decl_node->data.struct_decl.generic_params;
5360 } else {
5361 zig_unreachable();
5362 }
53635515
5364 int expected_param_count = generic_params->length;5516 int expected_param_count = generic_params->length;
5365 int actual_param_count = node->data.fn_call_expr.params.length;5517 int actual_param_count = node->data.fn_call_expr.params.length;
...@@ -5405,10 +5557,6 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5405,10 +5557,6 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
5405 } else {5557 } else {
5406 add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));5558 add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
54075559
5408 add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
5409 &generic_param_decl_node->data.param_decl.name, g->builtin_types.entry_invalid,
5410 true, nullptr);
5411
5412 return g->builtin_types.entry_invalid;5560 return g->builtin_types.entry_invalid;
5413 }5561 }
54145562
...@@ -5420,36 +5568,19 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5420,36 +5568,19 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
5420 auto entry = g->generic_table.maybe_get(generic_fn_type_id);5568 auto entry = g->generic_table.maybe_get(generic_fn_type_id);
5421 if (entry) {5569 if (entry) {
5422 AstNode *impl_decl_node = entry->value;5570 AstNode *impl_decl_node = entry->value;
5423 if (impl_decl_node->type == NodeTypeFnProto) {5571 assert(impl_decl_node->type == NodeTypeContainerDecl);
5424 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
5425 return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
5426 } else if (impl_decl_node->type == NodeTypeContainerDecl) {
5427 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5428 return resolve_expr_const_val_as_type(g, node, type_entry, false);
5429 } else {
5430 zig_unreachable();
5431 }
5432 }
5433
5434 // make a type from the generic parameters supplied
5435 if (decl_node->type == NodeTypeFnProto) {
5436 AstNode *impl_fn_def_node = ast_clone_subtree(decl_node->data.fn_proto.fn_def_node, &g->next_node_index);
5437 AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
5438
5439 preview_fn_proto_instance(g, import, impl_decl_node, child_context);
5440 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5441 FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
5442 return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
5443 } else if (decl_node->type == NodeTypeContainerDecl) {
5444 AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
5445 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5446 scan_struct_decl(g, import, child_context, impl_decl_node);
5447 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;5572 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5448 resolve_struct_type(g, import, type_entry);
5449 return resolve_expr_const_val_as_type(g, node, type_entry, false);5573 return resolve_expr_const_val_as_type(g, node, type_entry, false);
5450 } else {
5451 zig_unreachable();
5452 }5574 }
5575
5576 // make a type from the generic parameters supplied
5577 assert(decl_node->type == NodeTypeContainerDecl);
5578 AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
5579 g->generic_table.put(generic_fn_type_id, impl_decl_node);
5580 scan_struct_decl(g, import, child_context, impl_decl_node);
5581 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5582 resolve_struct_type(g, import, type_entry);
5583 return resolve_expr_const_val_as_type(g, node, type_entry, false);
5453}5584}
54545585
5455static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,5586static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -5487,10 +5618,32 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -5487,10 +5618,32 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
5487 struct_node = nullptr;5618 struct_node = nullptr;
5488 }5619 }
54895620
5490 return analyze_fn_call_raw(g, import, context, expected_type, node,5621 FnTableEntry *fn_table_entry = const_val->data.x_fn;
5491 const_val->data.x_fn, struct_node);5622 node->data.fn_call_expr.fn_entry = fn_table_entry;
5623 return analyze_fn_call_ptr(g, import, context, expected_type, node,
5624 fn_table_entry->type_entry, struct_node);
5492 } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {5625 } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {
5493 return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);5626 TypeTableEntry *generic_fn_type = const_val->data.x_type;
5627 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
5628 if (decl_node->type == NodeTypeFnProto) {
5629 AstNode *struct_node;
5630 if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
5631 fn_ref_expr->data.field_access_expr.is_member_fn)
5632 {
5633 struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
5634 } else {
5635 struct_node = nullptr;
5636 }
5637
5638 FnTableEntry *fn_table_entry = decl_node->data.fn_proto.fn_table_entry;
5639 if (fn_table_entry->proto_node->data.fn_proto.skip) {
5640 return g->builtin_types.entry_invalid;
5641 }
5642 return analyze_fn_call_with_inline_args(g, import, context, expected_type, node,
5643 fn_table_entry, struct_node);
5644 } else {
5645 return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
5646 }
5494 } else {5647 } else {
5495 add_node_error(g, fn_ref_expr,5648 add_node_error(g, fn_ref_expr,
5496 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));5649 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
...@@ -6367,7 +6520,9 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -6367,7 +6520,9 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
6367 var->src_arg_index = i;6520 var->src_arg_index = i;
6368 param_decl_node->data.param_decl.variable = var;6521 param_decl_node->data.param_decl.variable = var;
63696522
6370 var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;6523 if (fn_type->data.fn.gen_param_info) {
6524 var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
6525 }
63716526
6372 if (!type->deep_const) {6527 if (!type->deep_const) {
6373 fn_table_entry->is_pure = false;6528 fn_table_entry->is_pure = false;
...@@ -6406,11 +6561,11 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex...@@ -6406,11 +6561,11 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
6406 tld->import = import;6561 tld->import = import;
6407 tld->name = name;6562 tld->name = name;
64086563
6409 bool want_as_export = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);6564 bool want_to_resolve = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);
6410 bool is_generic = (node->type == NodeTypeFnProto && node->data.fn_proto.generic_params.length > 0) ||6565 bool is_generic_container = (node->type == NodeTypeContainerDecl &&
6411 (node->type == NodeTypeContainerDecl && node->data.struct_decl.generic_params.length > 0);6566 node->data.struct_decl.generic_params.length > 0);
6412 if (!is_generic && want_as_export) {6567 if (want_to_resolve && !is_generic_container) {
6413 g->export_queue.append(node);6568 g->resolve_queue.append(node);
6414 }6569 }
64156570
6416 node->block_context = block_context;6571 node->block_context = block_context;
...@@ -6425,6 +6580,18 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex...@@ -6425,6 +6580,18 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
6425 }6580 }
6426}6581}
64276582
6583static int fn_proto_inline_arg_count(AstNode *proto_node) {
6584 assert(proto_node->type == NodeTypeFnProto);
6585 int result = 0;
6586 for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
6587 AstNode *param_node = proto_node->data.fn_proto.params.at(i);
6588 assert(param_node->type == NodeTypeParamDecl);
6589 result += param_node->data.param_decl.is_inline ? 1 : 0;
6590 }
6591 return result;
6592}
6593
6594
6428static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {6595static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
6429 switch (node->type) {6596 switch (node->type) {
6430 case NodeTypeRoot:6597 case NodeTypeRoot:
...@@ -6467,6 +6634,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte...@@ -6467,6 +6634,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
6467 add_node_error(g, node, buf_sprintf("missing function name"));6634 add_node_error(g, node, buf_sprintf("missing function name"));
6468 break;6635 break;
6469 }6636 }
6637 node->data.fn_proto.inline_arg_count = fn_proto_inline_arg_count(node);
64706638
6471 add_top_level_decl(g, import, context, node, fn_name);6639 add_top_level_decl(g, import, context, node, fn_name);
6472 break;6640 break;
...@@ -6692,8 +6860,8 @@ void semantic_analyze(CodeGen *g) {...@@ -6692,8 +6860,8 @@ void semantic_analyze(CodeGen *g) {
6692 resolve_use_decl(g, use_decl_node);6860 resolve_use_decl(g, use_decl_node);
6693 }6861 }
66946862
6695 for (; g->export_queue_index < g->export_queue.length; g->export_queue_index += 1) {6863 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
6696 AstNode *decl_node = g->export_queue.at(g->export_queue_index);6864 AstNode *decl_node = g->resolve_queue.at(g->resolve_queue_index);
6697 bool pointer_only = false;6865 bool pointer_only = false;
6698 resolve_top_level_decl(g, decl_node, pointer_only);6866 resolve_top_level_decl(g, decl_node, pointer_only);
6699 }6867 }
...@@ -6983,11 +7151,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {...@@ -6983,11 +7151,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
6983 FnTypeParamInfo *a_param_info = &a->param_info[i];7151 FnTypeParamInfo *a_param_info = &a->param_info[i];
6984 FnTypeParamInfo *b_param_info = &b->param_info[i];7152 FnTypeParamInfo *b_param_info = &b->param_info[i];
69857153
6986 if (a_param_info->type != b_param_info->type) {7154 if (a_param_info->type != b_param_info->type ||
6987 return false;7155 a_param_info->is_noalias != b_param_info->is_noalias)
6988 }7156 {
6989
6990 if (a_param_info->is_noalias != b_param_info->is_noalias) {
6991 return false;7157 return false;
6992 }7158 }
6993 }7159 }
src/ast_render.cpp+2-1
...@@ -353,7 +353,8 @@ static void render_node(AstRender *ar, AstNode *node) {...@@ -353,7 +353,8 @@ static void render_node(AstRender *ar, AstNode *node) {
353 assert(param_decl->type == NodeTypeParamDecl);353 assert(param_decl->type == NodeTypeParamDecl);
354 if (buf_len(&param_decl->data.param_decl.name) > 0) {354 if (buf_len(&param_decl->data.param_decl.name) > 0) {
355 const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";355 const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
356 fprintf(ar->f, "%s", noalias_str);356 const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";
357 fprintf(ar->f, "%s%s", noalias_str, inline_str);
357 print_symbol(ar, &param_decl->data.param_decl.name);358 print_symbol(ar, &param_decl->data.param_decl.name);
358 fprintf(ar->f, ": ");359 fprintf(ar->f, ": ");
359 }360 }
src/codegen.cpp+14-5
...@@ -1062,12 +1062,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -1062,12 +1062,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
10621062
1063 TypeTableEntry *fn_type;1063 TypeTableEntry *fn_type;
1064 LLVMValueRef fn_val;1064 LLVMValueRef fn_val;
1065 AstNode *generic_proto_node;
1065 if (fn_table_entry) {1066 if (fn_table_entry) {
1066 fn_val = fn_table_entry->fn_value;1067 fn_val = fn_table_entry->fn_value;
1067 fn_type = fn_table_entry->type_entry;1068 fn_type = fn_table_entry->type_entry;
1069 generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node;
1068 } else {1070 } else {
1069 fn_val = gen_expr(g, fn_ref_expr);1071 fn_val = gen_expr(g, fn_ref_expr);
1070 fn_type = get_expr_type(fn_ref_expr);1072 fn_type = get_expr_type(fn_ref_expr);
1073 generic_proto_node = nullptr;
1071 }1074 }
10721075
1073 TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;1076 TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
...@@ -1093,8 +1096,14 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -1093,8 +1096,14 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
1093 gen_param_index += 1;1096 gen_param_index += 1;
1094 }1097 }
10951098
1096 for (int i = 0; i < fn_call_param_count; i += 1) {1099 for (int call_i = 0; call_i < fn_call_param_count; call_i += 1) {
1097 AstNode *expr_node = node->data.fn_call_expr.params.at(i);1100 int proto_i = call_i + (struct_type ? 1 : 0);
1101 if (generic_proto_node &&
1102 generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
1103 {
1104 continue;
1105 }
1106 AstNode *expr_node = node->data.fn_call_expr.params.at(call_i);
1098 LLVMValueRef param_value = gen_expr(g, expr_node);1107 LLVMValueRef param_value = gen_expr(g, expr_node);
1099 assert(param_value);1108 assert(param_value);
1100 TypeTableEntry *param_type = get_expr_type(expr_node);1109 TypeTableEntry *param_type = get_expr_type(expr_node);
...@@ -3734,7 +3743,7 @@ static void delete_unused_builtin_fns(CodeGen *g) {...@@ -3734,7 +3743,7 @@ static void delete_unused_builtin_fns(CodeGen *g) {
3734 }3743 }
3735}3744}
37363745
3737static bool skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {3746static bool should_skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
3738 if (g->is_test_build) {3747 if (g->is_test_build) {
3739 if (fn_entry->is_test) {3748 if (fn_entry->is_test) {
3740 return false;3749 return false;
...@@ -3889,7 +3898,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3889,7 +3898,7 @@ static void do_code_gen(CodeGen *g) {
3889 // Generate function prototypes3898 // Generate function prototypes
3890 for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {3899 for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
3891 FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);3900 FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
3892 if (skip_fn_codegen(g, fn_table_entry)) {3901 if (should_skip_fn_codegen(g, fn_table_entry)) {
3893 // huge time saver3902 // huge time saver
3894 LLVMDeleteFunction(fn_table_entry->fn_value);3903 LLVMDeleteFunction(fn_table_entry->fn_value);
3895 fn_table_entry->fn_value = nullptr;3904 fn_table_entry->fn_value = nullptr;
...@@ -3995,7 +4004,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3995,7 +4004,7 @@ static void do_code_gen(CodeGen *g) {
3995 // Generate function definitions.4004 // Generate function definitions.
3996 for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {4005 for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
3997 FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);4006 FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
3998 if (skip_fn_codegen(g, fn_table_entry)) {4007 if (should_skip_fn_codegen(g, fn_table_entry)) {
3999 // huge time saver4008 // huge time saver
4000 continue;4009 continue;
4001 }4010 }
src/eval.cpp+23-10
...@@ -884,9 +884,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val...@@ -884,9 +884,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
884884
885 int param_count = node->data.fn_call_expr.params.length;885 int param_count = node->data.fn_call_expr.params.length;
886 ConstExprValue *args = allocate<ConstExprValue>(param_count);886 ConstExprValue *args = allocate<ConstExprValue>(param_count);
887 for (int i = 0; i < param_count; i += 1) {887 for (int call_i = 0; call_i < param_count; call_i += 1) {
888 AstNode *param_expr_node = node->data.fn_call_expr.params.at(i);888 AstNode *param_expr_node = node->data.fn_call_expr.params.at(call_i);
889 ConstExprValue *param_val = &args[i];889 ConstExprValue *param_val = &args[call_i];
890 if (eval_expr(ef, param_expr_node, param_val)) return true;890 if (eval_expr(ef, param_expr_node, param_val)) return true;
891 }891 }
892892
...@@ -1291,6 +1291,13 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {...@@ -1291,6 +1291,13 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
1291}1291}
12921292
1293static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) {1293static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) {
1294 AstNode *acting_proto_node;
1295 if (fn->proto_node->data.fn_proto.generic_proto_node) {
1296 acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node;
1297 } else {
1298 acting_proto_node = fn->proto_node;
1299 }
1300
1294 EvalFn ef = {0};1301 EvalFn ef = {0};
1295 ef.root = efr;1302 ef.root = efr;
1296 ef.fn = fn;1303 ef.fn = fn;
...@@ -1300,12 +1307,12 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args...@@ -1300,12 +1307,12 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
1300 root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context;1307 root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context;
1301 ef.scope_stack.append(root_scope);1308 ef.scope_stack.append(root_scope);
13021309
1303 int param_count = fn->type_entry->data.fn.fn_type_id.param_count;1310 int param_count = acting_proto_node->data.fn_proto.params.length;
1304 for (int i = 0; i < param_count; i += 1) {1311 for (int proto_i = 0; proto_i < param_count; proto_i += 1) {
1305 AstNode *decl_param_node = fn->proto_node->data.fn_proto.params.at(i);1312 AstNode *decl_param_node = acting_proto_node->data.fn_proto.params.at(proto_i);
1306 assert(decl_param_node->type == NodeTypeParamDecl);1313 assert(decl_param_node->type == NodeTypeParamDecl);
13071314
1308 ConstExprValue *src_const_val = &args[i];1315 ConstExprValue *src_const_val = &args[proto_i];
1309 assert(src_const_val->ok);1316 assert(src_const_val->ok);
13101317
1311 root_scope->vars.add_one();1318 root_scope->vars.add_one();
...@@ -1315,7 +1322,6 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args...@@ -1315,7 +1322,6 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
1315 }1322 }
13161323
1317 return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val);1324 return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val);
1318
1319}1325}
13201326
1321bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val,1327bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val,
...@@ -1329,9 +1335,16 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va...@@ -1329,9 +1335,16 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
1329 efr.call_node = node;1335 efr.call_node = node;
1330 efr.branch_quota = branch_quota;1336 efr.branch_quota = branch_quota;
13311337
1338 AstNode *acting_proto_node;
1339 if (fn->proto_node->data.fn_proto.generic_proto_node) {
1340 acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node;
1341 } else {
1342 acting_proto_node = fn->proto_node;
1343 }
1344
1332 int call_param_count = node->data.fn_call_expr.params.length;1345 int call_param_count = node->data.fn_call_expr.params.length;
1333 int type_param_count = fn->type_entry->data.fn.fn_type_id.param_count;1346 int proto_param_count = acting_proto_node->data.fn_proto.params.length;
1334 ConstExprValue *args = allocate<ConstExprValue>(type_param_count);1347 ConstExprValue *args = allocate<ConstExprValue>(proto_param_count);
1335 int next_arg_index = 0;1348 int next_arg_index = 0;
1336 if (struct_node) {1349 if (struct_node) {
1337 ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val;1350 ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val;
src/parser.cpp+45-22
...@@ -747,7 +747,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,...@@ -747,7 +747,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
747}747}
748748
749/*749/*
750ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..."750ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
751*/751*/
752static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {752static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
753 Token *token = &pc->tokens->at(*token_index);753 Token *token = &pc->tokens->at(*token_index);
...@@ -763,6 +763,10 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {...@@ -763,6 +763,10 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
763 node->data.param_decl.is_noalias = true;763 node->data.param_decl.is_noalias = true;
764 *token_index += 1;764 *token_index += 1;
765 token = &pc->tokens->at(*token_index);765 token = &pc->tokens->at(*token_index);
766 } else if (token->id == TokenIdKeywordInline) {
767 node->data.param_decl.is_inline = true;
768 *token_index += 1;
769 token = &pc->tokens->at(*token_index);
766 }770 }
767771
768 buf_resize(&node->data.param_decl.name, 0);772 buf_resize(&node->data.param_decl.name, 0);
...@@ -2472,7 +2476,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato...@@ -2472,7 +2476,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
2472}2476}
24732477
2474/*2478/*
2475FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr)2479FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
2476*/2480*/
2477static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,2481static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
2478 ZigList<AstNode*> *directives, VisibMod visib_mod)2482 ZigList<AstNode*> *directives, VisibMod visib_mod)
...@@ -2502,17 +2506,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand...@@ -2502,17 +2506,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
25022506
2503 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);2507 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
25042508
2505 Token *maybe_lparen = &pc->tokens->at(*token_index);
2506 if (maybe_lparen->id == TokenIdLParen) {
2507 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
2508 node->data.fn_proto.generic_params.append(node->data.fn_proto.params.at(i));
2509 }
2510 node->data.fn_proto.generic_params_is_var_args = node->data.fn_proto.is_var_args;
2511
2512 node->data.fn_proto.params.resize(0);
2513 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
2514 }
2515
2516 Token *next_token = &pc->tokens->at(*token_index);2509 Token *next_token = &pc->tokens->at(*token_index);
2517 if (next_token->id == TokenIdArrow) {2510 if (next_token->id == TokenIdArrow) {
2518 *token_index += 1;2511 *token_index += 1;
...@@ -2931,7 +2924,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2931,7 +2924,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2931 case NodeTypeFnProto:2924 case NodeTypeFnProto:
2932 visit_field(&node->data.fn_proto.return_type, visit, context);2925 visit_field(&node->data.fn_proto.return_type, visit, context);
2933 visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context);2926 visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context);
2934 visit_node_list(&node->data.fn_proto.generic_params, visit, context);
2935 visit_node_list(&node->data.fn_proto.params, visit, context);2927 visit_node_list(&node->data.fn_proto.params, visit, context);
2936 break;2928 break;
2937 case NodeTypeFnDef:2929 case NodeTypeFnDef:
...@@ -3123,6 +3115,22 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src...@@ -3123,6 +3115,22 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src
3123 }3115 }
3124}3116}
31253117
3118static void clone_subtree_list_omit_inline_params(ZigList<AstNode *> *dest, ZigList<AstNode *> *src,
3119 uint32_t *next_node_index)
3120{
3121 memset(dest, 0, sizeof(ZigList<AstNode *>));
3122 dest->ensure_capacity(src->length);
3123 for (int i = 0; i < src->length; i += 1) {
3124 AstNode *src_node = src->at(i);
3125 assert(src_node->type == NodeTypeParamDecl);
3126 if (src_node->data.param_decl.is_inline) {
3127 continue;
3128 }
3129 dest->append(ast_clone_subtree(src_node, next_node_index));
3130 dest->last()->parent_field = &dest->last();
3131 }
3132}
3133
3126static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,3134static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,
3127 uint32_t *next_node_index)3135 uint32_t *next_node_index)
3128{3136{
...@@ -3133,20 +3141,26 @@ static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNod...@@ -3133,20 +3141,26 @@ static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNod
3133 }3141 }
3134}3142}
31353143
3136static void clone_subtree_field(AstNode **dest, AstNode *src, uint32_t *next_node_index) {3144static void clone_subtree_field_special(AstNode **dest, AstNode *src, uint32_t *next_node_index,
3145 enum AstCloneSpecial special)
3146{
3137 if (src) {3147 if (src) {
3138 *dest = ast_clone_subtree(src, next_node_index);3148 *dest = ast_clone_subtree_special(src, next_node_index, special);
3139 (*dest)->parent_field = dest;3149 (*dest)->parent_field = dest;
3140 } else {3150 } else {
3141 *dest = nullptr;3151 *dest = nullptr;
3142 }3152 }
3143}3153}
31443154
3155static void clone_subtree_field(AstNode **dest, AstNode *src, uint32_t *next_node_index) {
3156 return clone_subtree_field_special(dest, src, next_node_index, AstCloneSpecialNone);
3157}
3158
3145static void clone_subtree_tld(TopLevelDecl *dest, TopLevelDecl *src, uint32_t *next_node_index) {3159static void clone_subtree_tld(TopLevelDecl *dest, TopLevelDecl *src, uint32_t *next_node_index) {
3146 clone_subtree_list_ptr(&dest->directives, src->directives, next_node_index);3160 clone_subtree_list_ptr(&dest->directives, src->directives, next_node_index);
3147}3161}
31483162
3149AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {3163AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, enum AstCloneSpecial special) {
3150 AstNode *new_node = allocate_nonzero<AstNode>(1);3164 AstNode *new_node = allocate_nonzero<AstNode>(1);
3151 memcpy(new_node, old_node, sizeof(AstNode));3165 memcpy(new_node, old_node, sizeof(AstNode));
3152 new_node->create_index = *next_node_index;3166 new_node->create_index = *next_node_index;
...@@ -3163,14 +3177,19 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {...@@ -3163,14 +3177,19 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
3163 next_node_index);3177 next_node_index);
3164 clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,3178 clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,
3165 next_node_index);3179 next_node_index);
3166 clone_subtree_list(&new_node->data.fn_proto.generic_params,3180
3167 &old_node->data.fn_proto.generic_params, next_node_index);3181 if (special == AstCloneSpecialOmitInlineParams) {
3168 clone_subtree_list(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,3182 clone_subtree_list_omit_inline_params(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
3169 next_node_index);3183 next_node_index);
3184 } else {
3185 clone_subtree_list(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
3186 next_node_index);
3187 }
31703188
3171 break;3189 break;
3172 case NodeTypeFnDef:3190 case NodeTypeFnDef:
3173 clone_subtree_field(&new_node->data.fn_def.fn_proto, old_node->data.fn_def.fn_proto, next_node_index);3191 clone_subtree_field_special(&new_node->data.fn_def.fn_proto, old_node->data.fn_def.fn_proto,
3192 next_node_index, special);
3174 new_node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = new_node;3193 new_node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = new_node;
3175 clone_subtree_field(&new_node->data.fn_def.body, old_node->data.fn_def.body, next_node_index);3194 clone_subtree_field(&new_node->data.fn_def.body, old_node->data.fn_def.body, next_node_index);
3176 break;3195 break;
...@@ -3354,3 +3373,7 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {...@@ -3354,3 +3373,7 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
33543373
3355 return new_node;3374 return new_node;
3356}3375}
3376
3377AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
3378 return ast_clone_subtree_special(old_node, next_node_index, AstCloneSpecialNone);
3379}
src/parser.hpp+7
...@@ -25,6 +25,13 @@ void ast_print(AstNode *node, int indent);...@@ -25,6 +25,13 @@ void ast_print(AstNode *node, int indent);
25void normalize_parent_ptrs(AstNode *node);25void normalize_parent_ptrs(AstNode *node);
2626
27AstNode *ast_clone_subtree(AstNode *node, uint32_t *next_node_index);27AstNode *ast_clone_subtree(AstNode *node, uint32_t *next_node_index);
28
29enum AstCloneSpecial {
30 AstCloneSpecialNone,
31 AstCloneSpecialOmitInlineParams,
32};
33AstNode *ast_clone_subtree_special(AstNode *node, uint32_t *next_node_index, enum AstCloneSpecial special);
34
28void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context);35void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context);
2936
30#endif37#endif
std/hash_map.zig+10-9
...@@ -7,7 +7,7 @@ const want_modification_safety = !@compile_var("is_release");...@@ -7,7 +7,7 @@ const want_modification_safety = !@compile_var("is_release");
7const debug_u32 = if (want_modification_safety) u32 else void;7const debug_u32 = if (want_modification_safety) u32 else void;
88
9/*9/*
10pub fn HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)->bool) {10pub inline fn HashMap(inline K: type, inline V: type, inline hash: fn(key: K)->u32, inline eql: fn(a: K, b: K)->bool) {
11 SmallHashMap(K, V, hash, eql, 8);11 SmallHashMap(K, V, hash, eql, 8);
12}12}
13*/13*/
...@@ -70,7 +70,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -70,7 +70,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
7070
71 pub fn deinit(hm: &Self) {71 pub fn deinit(hm: &Self) {
72 if (hm.entries.ptr != &hm.prealloc_entries[0]) {72 if (hm.entries.ptr != &hm.prealloc_entries[0]) {
73 hm.allocator.free(hm.allocator, ([]u8)(hm.entries));73 hm.allocator.free(Entry, hm.entries);
74 }74 }
75 }75 }
7676
...@@ -103,7 +103,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -103,7 +103,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
103 }103 }
104 }104 }
105 if (old_entries.ptr != &hm.prealloc_entries[0]) {105 if (old_entries.ptr != &hm.prealloc_entries[0]) {
106 hm.allocator.free(hm.allocator, ([]u8)(old_entries));106 hm.allocator.free(Entry, old_entries);
107 }107 }
108 }108 }
109109
...@@ -152,7 +152,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -152,7 +152,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
152 }152 }
153153
154 fn init_capacity(hm: &Self, capacity: isize) -> %void {154 fn init_capacity(hm: &Self, capacity: isize) -> %void {
155 hm.entries = ([]Entry)(%return hm.allocator.alloc(hm.allocator, capacity * @sizeof(Entry)));155 hm.entries = %return hm.allocator.alloc(Entry, capacity);
156 hm.size = 0;156 hm.size = 0;
157 hm.max_distance_from_start_index = 0;157 hm.max_distance_from_start_index = 0;
158 for (hm.entries) |*entry| {158 for (hm.entries) |*entry| {
...@@ -180,7 +180,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -180,7 +180,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
180 if (entry.distance_from_start_index < distance_from_start_index) {180 if (entry.distance_from_start_index < distance_from_start_index) {
181 // robin hood to the rescue181 // robin hood to the rescue
182 const tmp = *entry;182 const tmp = *entry;
183 hm.max_distance_from_start_index = math.max(isize)(183 hm.max_distance_from_start_index = math.max(isize,
184 hm.max_distance_from_start_index, distance_from_start_index);184 hm.max_distance_from_start_index, distance_from_start_index);
185 *entry = Entry {185 *entry = Entry {
186 .used = true,186 .used = true,
...@@ -201,7 +201,8 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -201,7 +201,8 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
201 hm.size += 1;201 hm.size += 1;
202 }202 }
203203
204 hm.max_distance_from_start_index = math.max(isize)(distance_from_start_index, hm.max_distance_from_start_index);204 hm.max_distance_from_start_index = math.max(isize, distance_from_start_index,
205 hm.max_distance_from_start_index);
205 *entry = Entry {206 *entry = Entry {
206 .used = true,207 .used = true,
207 .distance_from_start_index = distance_from_start_index,208 .distance_from_start_index = distance_from_start_index,
...@@ -231,9 +232,9 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b...@@ -231,9 +232,9 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
231}232}
232233
233var global_allocator = Allocator {234var global_allocator = Allocator {
234 .alloc = global_alloc,235 .alloc_fn = global_alloc,
235 .realloc = global_realloc,236 .realloc_fn = global_realloc,
236 .free = global_free,237 .free_fn = global_free,
237 .context = null,238 .context = null,
238};239};
239240
std/io.zig+22-32
...@@ -69,7 +69,7 @@ pub struct OutStream {...@@ -69,7 +69,7 @@ pub struct OutStream {
69 const dest_space_left = os.buffer.len - os.index;69 const dest_space_left = os.buffer.len - os.index;
7070
71 while (src_bytes_left > 0) {71 while (src_bytes_left > 0) {
72 const copy_amt = math.min(isize)(dest_space_left, src_bytes_left);72 const copy_amt = math.min(isize, dest_space_left, src_bytes_left);
73 @memcpy(&os.buffer[os.index], &bytes[src_index], copy_amt);73 @memcpy(&os.buffer[os.index], &bytes[src_index], copy_amt);
74 os.index += copy_amt;74 os.index += copy_amt;
75 if (os.index == os.buffer.len) {75 if (os.index == os.buffer.len) {
...@@ -208,59 +208,47 @@ pub struct InStream {...@@ -208,59 +208,47 @@ pub struct InStream {
208 }208 }
209}209}
210210
211pub error InvalidChar;211pub fn parse_unsigned(inline T: type, buf: []u8, radix: u8) -> %T {
212pub error Overflow;
213
214pub fn parse_unsigned(T: type)(buf: []u8, radix: u8) -> %T {
215 var x: T = 0;212 var x: T = 0;
216213
217 for (buf) |c| {214 for (buf) |c| {
218 const digit = char_to_digit(c);215 const digit = %return char_to_digit(c, radix);
219216 x = %return math.mul_overflow(T, x, radix);
220 if (digit >= radix) {217 x = %return math.add_overflow(T, x, digit);
221 return error.InvalidChar;
222 }
223
224 // x *= radix
225 if (@mul_with_overflow(T, x, radix, &x)) {
226 return error.Overflow;
227 }
228
229 // x += digit
230 if (@add_with_overflow(T, x, digit, &x)) {
231 return error.Overflow;
232 }
233 }218 }
234219
235 return x;220 return x;
236}221}
237222
238fn char_to_digit(c: u8) -> u8 {223pub error InvalidChar;
239 // TODO use switch with range224fn char_to_digit(c: u8, radix: u8) -> %u8 {
240 if ('0' <= c && c <= '9') {225 const value = if ('0' <= c && c <= '9') {
241 c - '0'226 c - '0'
242 } else if ('A' <= c && c <= 'Z') {227 } else if ('A' <= c && c <= 'Z') {
243 c - 'A' + 10228 c - 'A' + 10
244 } else if ('a' <= c && c <= 'z') {229 } else if ('a' <= c && c <= 'z') {
245 c - 'a' + 10230 c - 'a' + 10
246 } else {231 } else {
247 @max_value(u8)232 return error.InvalidChar;
248 }233 };
234 return if (value >= radix) error.InvalidChar else value;
249}235}
250236
251pub fn buf_print_signed(T: type)(out_buf: []u8, x: T) -> isize {237pub fn buf_print_signed(inline T: type, out_buf: []u8, x: T) -> isize {
252 const uint = @int_type(false, T.bit_count, false);238 const uint = @int_type(false, T.bit_count, false);
253 if (x < 0) {239 if (x < 0) {
254 out_buf[0] = '-';240 out_buf[0] = '-';
255 return 1 + buf_print_unsigned(uint)(out_buf[1...], uint(-(x + 1)) + 1);241 return 1 + buf_print_unsigned(uint, out_buf[1...], uint(-(x + 1)) + 1);
256 } else {242 } else {
257 return buf_print_unsigned(uint)(out_buf, uint(x));243 return buf_print_unsigned(uint, out_buf, uint(x));
258 }244 }
259}245}
260246
261pub const buf_print_i64 = buf_print_signed(i64);247pub fn buf_print_i64(out_buf: []u8, x: i64) -> isize {
248 buf_print_signed(i64, out_buf, x)
249}
262250
263pub fn buf_print_unsigned(T: type)(out_buf: []u8, x: T) -> isize {251pub fn buf_print_unsigned(inline T: type, out_buf: []u8, x: T) -> isize {
264 var buf: [max_u64_base10_digits]u8 = undefined;252 var buf: [max_u64_base10_digits]u8 = undefined;
265 var a = x;253 var a = x;
266 var index: isize = buf.len;254 var index: isize = buf.len;
...@@ -281,7 +269,9 @@ pub fn buf_print_unsigned(T: type)(out_buf: []u8, x: T) -> isize {...@@ -281,7 +269,9 @@ pub fn buf_print_unsigned(T: type)(out_buf: []u8, x: T) -> isize {
281 return len;269 return len;
282}270}
283271
284pub const buf_print_u64 = buf_print_unsigned(u64);272pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize {
273 buf_print_unsigned(u64, out_buf, x)
274}
285275
286pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {276pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
287 const numExpBits = 11;277 const numExpBits = 11;
...@@ -409,7 +399,7 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {...@@ -409,7 +399,7 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
409399
410#attribute("test")400#attribute("test")
411fn parse_u64_digit_too_big() {401fn parse_u64_digit_too_big() {
412 parse_unsigned(u64)("123a", 10) %% |err| {402 parse_unsigned(u64, "123a", 10) %% |err| {
413 if (err == error.InvalidChar) return;403 if (err == error.InvalidChar) return;
414 unreachable{};404 unreachable{};
415 };405 };
std/list.zig+14-15
...@@ -2,59 +2,58 @@ const assert = @import("debug.zig").assert;...@@ -2,59 +2,58 @@ const assert = @import("debug.zig").assert;
2const mem = @import("mem.zig");2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;3const Allocator = mem.Allocator;
44
5/*5pub inline fn List(inline T: type) -> type {
6pub fn List(T: type) -> type {
7 SmallList(T, 8)6 SmallList(T, 8)
8}7}
9*/
108
11pub struct SmallList(T: type, STATIC_SIZE: isize) {9pub struct SmallList(T: type, STATIC_SIZE: isize) {
10 const Self = SmallList(T, STATIC_SIZE);
11
12 items: []T,12 items: []T,
13 length: isize,13 length: isize,
14 prealloc_items: [STATIC_SIZE]T,14 prealloc_items: [STATIC_SIZE]T,
15 allocator: &Allocator,15 allocator: &Allocator,
1616
17 pub fn init(l: &SmallList(T, STATIC_SIZE), allocator: &Allocator) {17 pub fn init(l: &Self, allocator: &Allocator) {
18 l.items = l.prealloc_items[0...];18 l.items = l.prealloc_items[0...];
19 l.length = 0;19 l.length = 0;
20 l.allocator = allocator;20 l.allocator = allocator;
21 }21 }
2222
23 pub fn deinit(l: &SmallList(T, STATIC_SIZE)) {23 pub fn deinit(l: &Self) {
24 if (l.items.ptr != &l.prealloc_items[0]) {24 if (l.items.ptr != &l.prealloc_items[0]) {
25 l.allocator.free(l.allocator, ([]u8)(l.items));25 l.allocator.free(T, l.items);
26 }26 }
27 }27 }
2828
29 pub fn append(l: &SmallList(T, STATIC_SIZE), item: T) -> %void {29 pub fn append(l: &Self, item: T) -> %void {
30 const new_length = l.length + 1;30 const new_length = l.length + 1;
31 %return l.ensure_capacity(new_length);31 %return l.ensure_capacity(new_length);
32 l.items[l.length] = item;32 l.items[l.length] = item;
33 l.length = new_length;33 l.length = new_length;
34 }34 }
3535
36 pub fn ensure_capacity(l: &SmallList(T, STATIC_SIZE), new_capacity: isize) -> %void {36 pub fn ensure_capacity(l: &Self, new_capacity: isize) -> %void {
37 const old_capacity = l.items.len;37 const old_capacity = l.items.len;
38 var better_capacity = old_capacity;38 var better_capacity = old_capacity;
39 while (better_capacity < new_capacity) {39 while (better_capacity < new_capacity) {
40 better_capacity *= 2;40 better_capacity *= 2;
41 }41 }
42 if (better_capacity != old_capacity) {42 if (better_capacity != old_capacity) {
43 const alloc_bytes = better_capacity * @sizeof(T);
44 if (l.items.ptr == &l.prealloc_items[0]) {43 if (l.items.ptr == &l.prealloc_items[0]) {
45 l.items = ([]T)(%return l.allocator.alloc(l.allocator, alloc_bytes));44 l.items = %return l.allocator.alloc(T, better_capacity);
46 @memcpy(l.items.ptr, &l.prealloc_items[0], old_capacity * @sizeof(T));45 mem.copy(T, l.items, l.prealloc_items[0...old_capacity]);
47 } else {46 } else {
48 l.items = ([]T)(%return l.allocator.realloc(l.allocator, ([]u8)(l.items), alloc_bytes));47 l.items = %return l.allocator.realloc(T, l.items, better_capacity);
49 }48 }
50 }49 }
51 }50 }
52}51}
5352
54var global_allocator = Allocator {53var global_allocator = Allocator {
55 .alloc = global_alloc,54 .alloc_fn = global_alloc,
56 .realloc = global_realloc,55 .realloc_fn = global_realloc,
57 .free = global_free,56 .free_fn = global_free,
58 .context = null,57 .context = null,
59};58};
6059
std/math.zig+16-2
...@@ -26,10 +26,24 @@ pub fn f64_is_inf(f: f64) -> bool {...@@ -26,10 +26,24 @@ pub fn f64_is_inf(f: f64) -> bool {
26 f == f64_get_neg_inf() || f == f64_get_pos_inf()26 f == f64_get_neg_inf() || f == f64_get_pos_inf()
27}27}
2828
29pub fn min(T: type)(x: T, y: T) -> T {29pub fn min(inline T: type, x: T, y: T) -> T {
30 if (x < y) x else y30 if (x < y) x else y
31}31}
3232
33pub fn max(T: type)(x: T, y: T) -> T {33pub fn max(inline T: type, x: T, y: T) -> T {
34 if (x > y) x else y34 if (x > y) x else y
35}35}
36
37pub error Overflow;
38pub fn mul_overflow(inline T: type, a: T, b: T) -> %T {
39 var answer: T = undefined;
40 if (@mul_with_overflow(T, a, b, &answer)) error.Overflow else answer
41}
42pub fn add_overflow(inline T: type, a: T, b: T) -> %T {
43 var answer: T = undefined;
44 if (@add_with_overflow(T, a, b, &answer)) error.Overflow else answer
45}
46pub fn sub_overflow(inline T: type, a: T, b: T) -> %T {
47 var answer: T = undefined;
48 if (@sub_with_overflow(T, a, b, &answer)) error.Overflow else answer
49}
std/mem.zig+32-4
...@@ -1,18 +1,46 @@...@@ -1,18 +1,46 @@
1const assert = @import("debug.zig").assert;1const assert = @import("debug.zig").assert;
2const math = @import("math.zig");
3const os = @import("os.zig");
4const io = @import("io.zig");
25
3pub error NoMem;6pub error NoMem;
47
5pub type Context = u8;8pub type Context = u8;
6pub struct Allocator {9pub struct Allocator {
7 alloc: fn (self: &Allocator, n: isize) -> %[]u8,10 alloc_fn: fn (self: &Allocator, n: isize) -> %[]u8,
8 realloc: fn (self: &Allocator, old_mem: []u8, new_size: isize) -> %[]u8,11 realloc_fn: fn (self: &Allocator, old_mem: []u8, new_size: isize) -> %[]u8,
9 free: fn (self: &Allocator, mem: []u8),12 free_fn: fn (self: &Allocator, mem: []u8),
10 context: ?&Context,13 context: ?&Context,
14
15 /// Aborts the program if an allocation fails.
16 fn checked_alloc(self: &Allocator, inline T: type, n: isize) -> []T {
17 alloc(self, T, n) %% |err| {
18 // TODO var args printf
19 %%io.stderr.write("allocation failure: ");
20 %%io.stderr.write(@err_name(err));
21 %%io.stderr.printf("\n");
22 os.abort()
23 }
24 }
25
26 fn alloc(self: &Allocator, inline T: type, n: isize) -> %[]T {
27 const byte_count = %return math.mul_overflow(isize, @sizeof(T), n);
28 ([]T)(%return self.alloc_fn(self, byte_count))
29 }
30
31 fn realloc(self: &Allocator, inline T: type, old_mem: []T, n: isize) -> %[]T {
32 const byte_count = %return math.mul_overflow(isize, @sizeof(T), n);
33 ([]T)(%return self.realloc_fn(self, ([]u8)(old_mem), byte_count))
34 }
35
36 fn free(self: &Allocator, inline T: type, mem: []T) {
37 self.free_fn(self, ([]u8)(mem));
38 }
11}39}
1240
13/// Copy all of source into dest at position 0.41/// Copy all of source into dest at position 0.
14/// dest.len must be >= source.len.42/// dest.len must be >= source.len.
15pub fn copy(T)(dest: []T, source: []T) {43pub fn copy(inline T: type, dest: []T, source: []T) {
16 assert(dest.len >= source.len);44 assert(dest.len >= source.len);
17 @memcpy(dest.ptr, source.ptr, @sizeof(T) * source.len);45 @memcpy(dest.ptr, source.ptr, @sizeof(T) * source.len);
18}46}
std/net.zig+6-7
...@@ -99,14 +99,14 @@ pub fn connect_addr(addr: &Address, port: u16) -> %Connection {...@@ -99,14 +99,14 @@ pub fn connect_addr(addr: &Address, port: u16) -> %Connection {
99 const connect_ret = if (addr.family == linux.AF_INET) {99 const connect_ret = if (addr.family == linux.AF_INET) {
100 var os_addr: linux.sockaddr_in = undefined;100 var os_addr: linux.sockaddr_in = undefined;
101 os_addr.family = addr.family;101 os_addr.family = addr.family;
102 os_addr.port = host_to_be(u16)(port);102 os_addr.port = swap_if_little_endian(u16, port);
103 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);103 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
104 @memset(&os_addr.zero, 0, @sizeof(@typeof(os_addr.zero)));104 @memset(&os_addr.zero, 0, @sizeof(@typeof(os_addr.zero)));
105 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeof(linux.sockaddr_in))105 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeof(linux.sockaddr_in))
106 } else if (addr.family == linux.AF_INET6) {106 } else if (addr.family == linux.AF_INET6) {
107 var os_addr: linux.sockaddr_in6 = undefined;107 var os_addr: linux.sockaddr_in6 = undefined;
108 os_addr.family = addr.family;108 os_addr.family = addr.family;
109 os_addr.port = host_to_be(u16)(port);109 os_addr.port = swap_if_little_endian(u16, port);
110 os_addr.flowinfo = 0;110 os_addr.flowinfo = 0;
111 os_addr.scope_id = addr.scope_id;111 os_addr.scope_id = addr.scope_id;
112 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);112 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
...@@ -319,7 +319,7 @@ fn parse_ip4(buf: []const u8) -> %u32 {...@@ -319,7 +319,7 @@ fn parse_ip4(buf: []const u8) -> %u32 {
319319
320#attribute("test")320#attribute("test")
321fn test_parse_ip4() {321fn test_parse_ip4() {
322 assert(%%parse_ip4("127.0.0.1") == be_to_host(u32)(0x7f000001));322 assert(%%parse_ip4("127.0.0.1") == swap_if_little_endian(u32, 0x7f000001));
323 switch (parse_ip4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }323 switch (parse_ip4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
324 switch (parse_ip4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }324 switch (parse_ip4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
325 switch (parse_ip4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }325 switch (parse_ip4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
...@@ -352,12 +352,11 @@ fn test_lookup_simple_ip() {...@@ -352,12 +352,11 @@ fn test_lookup_simple_ip() {
352 }352 }
353}353}
354354
355const be_to_host = host_to_be;355fn swap_if_little_endian(inline T: type, x: T) -> T {
356fn host_to_be(T: type)(x: T) -> T {356 if (@compile_var("is_big_endian")) x else endian_swap(T, x)
357 if (@compile_var("is_big_endian")) x else endian_swap(T)(x)
358}357}
359358
360fn endian_swap(T: type)(x: T) -> T {359fn endian_swap(inline T: type, x: T) -> T {
361 const x_slice = ([]u8)((&const x)[0...1]);360 const x_slice = ([]u8)((&const x)[0...1]);
362 var result: T = undefined;361 var result: T = undefined;
363 const result_slice = ([]u8)((&result)[0...1]);362 const result_slice = ([]u8)((&result)[0...1]);
std/str.zig+4-2
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1const assert = @import("debug.zig").assert;1const assert = @import("debug.zig").assert;
22
3pub const eql = slice_eql(u8);3pub fn eql(a: []const u8, b: []const u8) -> bool {
4 slice_eql(u8, a, b)
5}
46
5pub fn slice_eql(T: type)(a: []const T, b: []const T) -> bool {7pub fn slice_eql(inline T: type, a: []const T, b: []const T) -> bool {
6 if (a.len != b.len) return false;8 if (a.len != b.len) return false;
7 for (a) |item, index| {9 for (a) |item, index| {
8 if (b[index] != item) return false;10 if (b[index] != item) return false;
std/test_runner.zig+1
...@@ -9,6 +9,7 @@ extern var zig_test_fn_list: []TestFn;...@@ -9,6 +9,7 @@ extern var zig_test_fn_list: []TestFn;
99
10pub fn run_tests() -> %void {10pub fn run_tests() -> %void {
11 for (zig_test_fn_list) |test_fn, i| {11 for (zig_test_fn_list) |test_fn, i| {
12 // TODO: print var args
12 %%io.stderr.write("Test ");13 %%io.stderr.write("Test ");
13 %%io.stderr.print_i64(i + 1);14 %%io.stderr.print_i64(i + 1);
14 %%io.stderr.write("/");15 %%io.stderr.write("/");
test/run_tests.cpp+24-3
...@@ -1181,11 +1181,11 @@ const invalid = foo > foo;...@@ -1181,11 +1181,11 @@ const invalid = foo > foo;
1181 )SOURCE", 1, ".tmp_source.zig:3:21: error: operator not allowed for type 'fn()'");1181 )SOURCE", 1, ".tmp_source.zig:3:21: error: operator not allowed for type 'fn()'");
11821182
1183 add_compile_fail_case("generic function instance with non-constant expression", R"SOURCE(1183 add_compile_fail_case("generic function instance with non-constant expression", R"SOURCE(
1184fn foo(x: i32)(y: i32) -> i32 { return x + y; }1184fn foo(inline x: i32, y: i32) -> i32 { return x + y; }
1185fn test1(a: i32, b: i32) -> i32 {1185fn test1(a: i32, b: i32) -> i32 {
1186 return foo(a)(b);1186 return foo(a, b);
1187}1187}
1188 )SOURCE", 1, ".tmp_source.zig:4:16: error: unable to evaluate constant expression");1188 )SOURCE", 1, ".tmp_source.zig:4:16: error: unable to evaluate constant expression for inline parameter");
11891189
1190 add_compile_fail_case("goto jumping into block", R"SOURCE(1190 add_compile_fail_case("goto jumping into block", R"SOURCE(
1191fn f() {1191fn f() {
...@@ -1406,6 +1406,27 @@ fn f() {...@@ -1406,6 +1406,27 @@ fn f() {
1406}1406}
1407 )SOURCE", 1, ".tmp_source.zig:3:13: error: unable to evaluate constant expression");1407 )SOURCE", 1, ".tmp_source.zig:3:13: error: unable to evaluate constant expression");
14081408
1409 add_compile_fail_case("export function with inline parameter", R"SOURCE(
1410export fn foo(inline x: i32, y: i32) -> i32{
1411 x + y
1412}
1413 )SOURCE", 1, ".tmp_source.zig:2:15: error: inline parameter not allowed in extern function");
1414
1415 add_compile_fail_case("extern function with inline parameter", R"SOURCE(
1416extern fn foo(inline x: i32, y: i32) -> i32;
1417fn f() -> i32 {
1418 foo(1, 2)
1419}
1420 )SOURCE", 1, ".tmp_source.zig:2:15: error: inline parameter not allowed in extern function");
1421
1422 /* TODO
1423 add_compile_fail_case("inline export function", R"SOURCE(
1424export inline fn foo(x: i32, y: i32) -> i32{
1425 x + y
1426}
1427 )SOURCE", 1, ".tmp_source.zig:2:1: error: extern functions cannot be inline");
1428 */
1429
1409}1430}
14101431
1411//////////////////////////////////////////////////////////////////////////////1432//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+15-20
...@@ -712,17 +712,17 @@ three)";...@@ -712,17 +712,17 @@ three)";
712712
713#attribute("test")713#attribute("test")
714fn simple_generic_fn() {714fn simple_generic_fn() {
715 assert(max(i32)(3, -1) == 3);715 assert(max(i32, 3, -1) == 3);
716 assert(max(f32)(0.123, 0.456) == 0.456);716 assert(max(f32, 0.123, 0.456) == 0.456);
717 assert(add(2)(3) == 5);717 assert(add(2, 3) == 5);
718}718}
719719
720fn max(T: type)(a: T, b: T) -> T {720fn max(inline T: type, a: T, b: T) -> T {
721 return if (a > b) a else b;721 return if (a > b) a else b;
722}722}
723723
724fn add(a: i32)(b: i32) -> i32 {724fn add(inline a: i32, b: i32) -> i32 {
725 return a + b;725 return @const_eval(a) + b;
726}726}
727727
728728
...@@ -734,23 +734,18 @@ fn constant_equal_function_pointers() {...@@ -734,23 +734,18 @@ fn constant_equal_function_pointers() {
734734
735fn empty_fn() {}735fn empty_fn() {}
736736
737#attribute("test")
738fn generic_function_equality() {
739 assert(max(i32) == max(i32));
740}
741
742737
743#attribute("test")738#attribute("test")
744fn generic_malloc_free() {739fn generic_malloc_free() {
745 const a = %%mem_alloc(u8)(10);740 const a = %%mem_alloc(u8, 10);
746 mem_free(u8)(a);741 mem_free(u8, a);
747}742}
748const some_mem : [100]u8 = undefined;743const some_mem : [100]u8 = undefined;
749#static_eval_enable(false)744#static_eval_enable(false)
750fn mem_alloc(T: type)(n: isize) -> %[]T {745fn mem_alloc(inline T: type, n: isize) -> %[]T {
751 return (&T)(&some_mem[0])[0...n];746 return (&T)(&some_mem[0])[0...n];
752}747}
753fn mem_free(T: type)(mem: []T) { }748fn mem_free(inline T: type, mem: []T) { }
754749
755750
756#attribute("test")751#attribute("test")
...@@ -982,11 +977,11 @@ pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {...@@ -982,11 +977,11 @@ pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
982977
983#attribute("test")978#attribute("test")
984fn generic_fn_with_implicit_cast() {979fn generic_fn_with_implicit_cast() {
985 assert(get_first_byte(u8)([]u8 {13}) == 13);980 assert(get_first_byte(u8, []u8 {13}) == 13);
986 assert(get_first_byte(u16)([]u16 {0, 13}) == 0);981 assert(get_first_byte(u16, []u16 {0, 13}) == 0);
987}982}
988fn get_byte(ptr: ?&u8) -> u8 {*??ptr}983fn get_byte(ptr: ?&u8) -> u8 {*??ptr}
989fn get_first_byte(T: type)(mem: []T) -> u8 {984fn get_first_byte(inline T: type, mem: []T) -> u8 {
990 get_byte((&u8)(&mem[0]))985 get_byte((&u8)(&mem[0]))
991}986}
992987
...@@ -1651,9 +1646,9 @@ struct GenericDataThing(count: isize) {...@@ -1651,9 +1646,9 @@ struct GenericDataThing(count: isize) {
16511646
1652#attribute("test")1647#attribute("test")
1653fn use_generic_param_in_generic_param() {1648fn use_generic_param_in_generic_param() {
1654 assert(a_generic_fn(i32, 3)(4) == 7);1649 assert(a_generic_fn(i32, 3, 4) == 7);
1655}1650}
1656fn a_generic_fn(T: type, a: T)(b: T) -> T {1651fn a_generic_fn(inline T: type, inline a: T, b: T) -> T {
1657 return a + b;1652 return a + b;
1658}1653}
16591654