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 ";"
2525
2626ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
2727
28FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr)
28FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
2929
3030Directive = "#" "Symbol" "(" Expression ")"
3131
......@@ -35,7 +35,7 @@ FnDef = option("inline" | "extern") FnProto Block
3535
3636ParamDeclList = "(" list(ParamDecl, ",") ")"
3737
38ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."
38ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
3939
4040Block = "{" list(option(Statement), ";") "}"
4141
example/guess_number/main.zig+1-1
......@@ -23,7 +23,7 @@ pub fn main(args: [][]u8) -> %void {
2323 return err;
2424 };
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) %% {
2727 %%io.stdout.printf("Invalid number.\n");
2828 continue;
2929 };
src/all_types.hpp+9-6
......@@ -195,10 +195,8 @@ struct AstNodeRoot {
195195struct AstNodeFnProto {
196196 TopLevelDecl top_level_decl;
197197 Buf name;
198 ZigList<AstNode *> generic_params;
199198 ZigList<AstNode *> params;
200199 AstNode *return_type;
201 bool generic_params_is_var_args;
202200 bool is_var_args;
203201 bool is_extern;
204202 bool is_inline;
......@@ -210,7 +208,10 @@ struct AstNodeFnProto {
210208 FnTableEntry *fn_table_entry;
211209 bool skip;
212210 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;
214215};
215216
216217struct AstNodeFnDef {
......@@ -219,6 +220,7 @@ struct AstNodeFnDef {
219220
220221 // populated by semantic analyzer
221222 TypeTableEntry *implicit_return_type;
223 // the first child block context
222224 BlockContext *block_context;
223225};
224226
......@@ -230,6 +232,7 @@ struct AstNodeParamDecl {
230232 Buf name;
231233 AstNode *type;
232234 bool is_noalias;
235 bool is_inline;
233236
234237 // populated by semantic analyzer
235238 VariableTableEntry *variable;
......@@ -841,6 +844,7 @@ struct FnTypeId {
841844 bool is_naked;
842845 bool is_cold;
843846 bool is_extern;
847 bool is_inline;
844848 FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
845849};
846850
......@@ -1063,7 +1067,6 @@ struct FnTableEntry {
10631067 ZigList<LabelTableEntry *> all_labels;
10641068 Buf symbol_name;
10651069 TypeTableEntry *type_entry; // function type
1066 bool is_inline;
10671070 bool internal_linkage;
10681071 bool is_extern;
10691072 bool is_test;
......@@ -1172,8 +1175,8 @@ struct CodeGen {
11721175
11731176 ZigList<ImportTableEntry *> import_queue;
11741177 int import_queue_index;
1175 ZigList<AstNode *> export_queue;
1176 int export_queue_index;
1178 ZigList<AstNode *> resolve_queue;
1179 int resolve_queue_index;
11771180 ZigList<AstNode *> use_queue;
11781181 int use_queue_index;
11791182
src/analyze.cpp+318-152
......@@ -32,6 +32,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
3232static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
3333static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
3434 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);
3537static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
3638 bool depends_on_compile_var);
3739static 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
874876 fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport);
875877 fn_type_id.is_naked = is_naked;
876878 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
879882 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
880883 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
883886 }
884887
885888 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) {
889 fn_proto->skip = true;
891 switch (fn_type_id.return_type->id) {
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;
890929 }
891930
892931 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);
894933 assert(child->type == NodeTypeParamDecl);
934
895935 TypeTableEntry *type_entry = analyze_type_expr(g, import, context,
896936 child->data.param_decl.type);
897937 switch (type_entry->id) {
......@@ -901,13 +941,20 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
901941 case TypeTableEntryIdNumLitFloat:
902942 case TypeTableEntryIdNumLitInt:
903943 case TypeTableEntryIdUndefLit:
904 case TypeTableEntryIdMetaType:
905944 case TypeTableEntryIdUnreachable:
906945 case TypeTableEntryIdNamespace:
907946 case TypeTableEntryIdGenericFn:
908947 fn_proto->skip = true;
909948 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 }
911958 break;
912959 case TypeTableEntryIdVoid:
913960 case TypeTableEntryIdBool:
......@@ -998,8 +1045,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
9981045 return;
9991046 }
10001047
1001 fn_table_entry->is_inline = fn_proto->is_inline;
1002
10031048 bool is_cold = false;
10041049 bool is_naked = false;
10051050 bool is_test = false;
......@@ -1095,7 +1140,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
10951140 return;
10961141 }
10971142
1098 if (fn_table_entry->is_inline && fn_table_entry->is_noinline) {
1143 if (fn_proto->is_inline && fn_table_entry->is_noinline) {
10991144 add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
11001145 fn_proto->skip = true;
11011146 return;
......@@ -1109,10 +1154,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
11091154 symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
11101155 }
11111156
1112 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
1113 fn_type->data.fn.raw_type_ref);
1157 if (fn_table_entry->fn_def_node) {
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) {
11161165 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
11171166 }
11181167 if (fn_table_entry->is_noinline) {
......@@ -1150,9 +1199,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
11501199 fn_type->di_type, fn_table_entry->internal_linkage,
11511200 is_definition, scope_line, flags, is_optimized, nullptr);
11521201
1153 BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context);
1154 fn_table_entry->fn_def_node->data.fn_def.block_context = context;
1155 context->di_scope = LLVMZigSubprogramToScope(subprogram);
1202 fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
11561203 ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
11571204 }
11581205}
......@@ -1176,6 +1223,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
11761223 return;
11771224 }
11781225
1226 assert(decl_node->type == NodeTypeContainerDecl);
11791227 assert(enum_type->di_type);
11801228
11811229 enum_type->deep_const = true;
......@@ -1370,7 +1418,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
13701418 return;
13711419 }
13721420
1373
1421 assert(decl_node->type == NodeTypeContainerDecl);
13741422 assert(struct_type->di_type);
13751423
13761424 struct_type->deep_const = true;
......@@ -1496,38 +1544,30 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t
14961544}
14971545
14981546static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1499 if (node->type == NodeTypeFnProto) {
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 }
1547 assert(node->type == NodeTypeContainerDecl);
15151548
1516 node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
1517 } else {
1518 zig_unreachable();
1549 if (node->data.struct_decl.generic_params_is_var_args) {
1550 add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
1551 node->data.struct_decl.skip = true;
1552 node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
1553 return;
15191554 }
15201555
1556 node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
15211557}
15221558
15231559static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
15241560 BlockContext *containing_context)
15251561{
1562 assert(proto_node->type == NodeTypeFnProto);
1563
15261564 if (proto_node->data.fn_proto.skip) {
15271565 return;
15281566 }
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
15321572 AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
15331573 Buf *proto_name = &proto_node->data.fn_proto.name;
......@@ -1551,41 +1591,50 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
15511591
15521592 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
15531593
1554 g->fn_protos.append(fn_table_entry);
1555
1556 if (fn_def_node) {
1557 g->fn_defs.append(fn_table_entry);
1558 }
1594 proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
15591595
1560 bool is_main_fn = !is_generic_instance &&
1561 !parent_decl && (import == g->root_import) &&
1562 buf_eql_str(proto_name, "main");
1563 if (is_main_fn) {
1564 g->main_fn = fn_table_entry;
1565 }
1596 if (is_generic_fn) {
1597 fn_table_entry->type_entry = get_generic_fn_type(g, proto_node);
15661598
1567 proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
1568 resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context);
1569
1570 if (is_main_fn && !g->link_libc) {
1571 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
1572 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
1573 if (actual_return_type != err_void) {
1574 AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type;
1575 add_node_error(g, return_type_node,
1576 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
1577 buf_ptr(&actual_return_type->name)));
1599 if (is_extern || proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModExport) {
1600 for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
1601 AstNode *param_decl_node = proto_node->data.fn_proto.params.at(i);
1602 if (param_decl_node->data.param_decl.is_inline) {
1603 proto_node->data.fn_proto.skip = true;
1604 add_node_error(g, param_decl_node,
1605 buf_sprintf("inline parameter not allowed in extern function"));
1606 }
1607 }
15781608 }
1579 }
1580}
15811609
1582static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) {
1583 if (proto_node->data.fn_proto.generic_params.length > 0) {
1584 return preview_generic_fn_proto(g, import, proto_node);
1610
15851611 } else {
1586 return preview_fn_proto_instance(g, import, proto_node, proto_node->block_context);
1587 }
1612 g->fn_protos.append(fn_table_entry);
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 }
15891638}
15901639
15911640static 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)
16831732
16841733 switch (node->type) {
16851734 case NodeTypeFnProto:
1686 preview_fn_proto(g, import, node);
1735 preview_fn_proto_instance(g, import, node, node->block_context);
16871736 break;
16881737 case NodeTypeContainerDecl:
16891738 resolve_struct_decl(g, import, node);
......@@ -2600,7 +2649,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
26002649
26012650 node->data.field_access_expr.is_member_fn = true;
26022651 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 }
26042657 } else {
26052658 add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",
26062659 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
30043057 VariableTableEntry *var = decl_node->data.variable_declaration.variable;
30053058 return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var);
30063059 } else if (decl_node->type == NodeTypeFnProto) {
3007 if (decl_node->data.fn_proto.generic_params.length > 0) {
3008 TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
3009 assert(type_entry);
3010 return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
3060 FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
3061 assert(fn_entry->type_entry);
3062 if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
3063 return resolve_expr_const_val_as_generic_fn(g, source_node, fn_entry->type_entry, depends_on_compile_var);
30113064 } else {
3012 FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
3013 assert(fn_entry->type_entry);
30143065 return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
30153066 }
30163067 } else if (decl_node->type == NodeTypeContainerDecl) {
......@@ -5238,6 +5289,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
52385289 zig_unreachable();
52395290}
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.
52415294static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
52425295 TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
52435296 AstNode *struct_node)
......@@ -5248,26 +5301,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
52485301 return fn_type;
52495302 }
52505303
5251 // count parameters
5252 int src_param_count = fn_type->data.fn.fn_type_id.param_count;
5253 int actual_param_count = node->data.fn_call_expr.params.length;
5304 // The function call might include inline parameters which we need to ignore according to the
5305 // fn_type.
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) {
5256 actual_param_count += 1;
5257 }
5310 // count parameters
5311 int struct_node_1_or_0 = struct_node ? 1 : 0;
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
52595316 bool ok_invocation = true;
52605317
52615318 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) {
52635320 ok_invocation = false;
52645321 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));
52665323 }
5267 } else if (src_param_count != actual_param_count) {
5324 } else if (src_param_count - struct_node_1_or_0 != call_param_count) {
52685325 ok_invocation = false;
52695326 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));
52715328 }
52725329
52735330 bool all_args_const_expr = true;
......@@ -5281,17 +5338,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
52815338
52825339 // analyze each parameter. in the case of a method, we already analyzed the
52835340 // 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) {
5285 AstNode **child = &node->data.fn_call_expr.params.at(i);
5341 int next_type_i = struct_node_1_or_0;
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);
52865345 // determine the expected type for each parameter
52875346 TypeTableEntry *expected_param_type = nullptr;
5288 int fn_proto_i = i + (struct_node ? 1 : 0);
5289 if (fn_proto_i < src_param_count) {
5290 expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;
5347 if (proto_i < src_param_count) {
5348 if (generic_proto_node &&
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;
52915362 }
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;
52955365 if (!const_arg_val->ok) {
52965366 all_args_const_expr = false;
52975367 }
......@@ -5303,7 +5373,6 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
53035373 return return_type;
53045374 }
53055375
5306 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
53075376 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
53085377 if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {
53095378 if (fn_table_entry->anal_state == FnAnalStateReady) {
......@@ -5335,14 +5404,103 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
53355404 return return_type;
53365405}
53375406
5338static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,
5339 TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node)
5407static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableEntry *import,
5408 BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *call_node,
5409 FnTableEntry *fn_table_entry, AstNode *struct_node)
53405410{
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);
53465504}
53475505
53485506static 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
53525510 assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
53535511
53545512 AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
5355 ZigList<AstNode *> *generic_params;
5356 if (decl_node->type == NodeTypeFnProto) {
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 }
5513 assert(decl_node->type == NodeTypeContainerDecl);
5514 ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
53635515
53645516 int expected_param_count = generic_params->length;
53655517 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
54055557 } else {
54065558 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
54125560 return g->builtin_types.entry_invalid;
54135561 }
54145562
......@@ -5420,36 +5568,19 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
54205568 auto entry = g->generic_table.maybe_get(generic_fn_type_id);
54215569 if (entry) {
54225570 AstNode *impl_decl_node = entry->value;
5423 if (impl_decl_node->type == NodeTypeFnProto) {
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);
5571 assert(impl_decl_node->type == NodeTypeContainerDecl);
54475572 TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
5448 resolve_struct_type(g, import, type_entry);
54495573 return resolve_expr_const_val_as_type(g, node, type_entry, false);
5450 } else {
5451 zig_unreachable();
54525574 }
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);
54535584}
54545585
54555586static 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
54875618 struct_node = nullptr;
54885619 }
54895620
5490 return analyze_fn_call_raw(g, import, context, expected_type, node,
5491 const_val->data.x_fn, struct_node);
5621 FnTableEntry *fn_table_entry = const_val->data.x_fn;
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);
54925625 } 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 }
54945647 } else {
54955648 add_node_error(g, fn_ref_expr,
54965649 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) {
63676520 var->src_arg_index = i;
63686521 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
63726527 if (!type->deep_const) {
63736528 fn_table_entry->is_pure = false;
......@@ -6406,11 +6561,11 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
64066561 tld->import = import;
64076562 tld->name = name;
64086563
6409 bool want_as_export = (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) ||
6411 (node->type == NodeTypeContainerDecl && node->data.struct_decl.generic_params.length > 0);
6412 if (!is_generic && want_as_export) {
6413 g->export_queue.append(node);
6564 bool want_to_resolve = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);
6565 bool is_generic_container = (node->type == NodeTypeContainerDecl &&
6566 node->data.struct_decl.generic_params.length > 0);
6567 if (want_to_resolve && !is_generic_container) {
6568 g->resolve_queue.append(node);
64146569 }
64156570
64166571 node->block_context = block_context;
......@@ -6425,6 +6580,18 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
64256580 }
64266581}
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
64286595static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
64296596 switch (node->type) {
64306597 case NodeTypeRoot:
......@@ -6467,6 +6634,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
64676634 add_node_error(g, node, buf_sprintf("missing function name"));
64686635 break;
64696636 }
6637 node->data.fn_proto.inline_arg_count = fn_proto_inline_arg_count(node);
64706638
64716639 add_top_level_decl(g, import, context, node, fn_name);
64726640 break;
......@@ -6692,8 +6860,8 @@ void semantic_analyze(CodeGen *g) {
66926860 resolve_use_decl(g, use_decl_node);
66936861 }
66946862
6695 for (; g->export_queue_index < g->export_queue.length; g->export_queue_index += 1) {
6696 AstNode *decl_node = g->export_queue.at(g->export_queue_index);
6863 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
6864 AstNode *decl_node = g->resolve_queue.at(g->resolve_queue_index);
66976865 bool pointer_only = false;
66986866 resolve_top_level_decl(g, decl_node, pointer_only);
66996867 }
......@@ -6983,11 +7151,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
69837151 FnTypeParamInfo *a_param_info = &a->param_info[i];
69847152 FnTypeParamInfo *b_param_info = &b->param_info[i];
69857153
6986 if (a_param_info->type != b_param_info->type) {
6987 return false;
6988 }
6989
6990 if (a_param_info->is_noalias != b_param_info->is_noalias) {
7154 if (a_param_info->type != b_param_info->type ||
7155 a_param_info->is_noalias != b_param_info->is_noalias)
7156 {
69917157 return false;
69927158 }
69937159 }
src/ast_render.cpp+2-1
......@@ -353,7 +353,8 @@ static void render_node(AstRender *ar, AstNode *node) {
353353 assert(param_decl->type == NodeTypeParamDecl);
354354 if (buf_len(&param_decl->data.param_decl.name) > 0) {
355355 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);
357358 print_symbol(ar, &param_decl->data.param_decl.name);
358359 fprintf(ar->f, ": ");
359360 }
src/codegen.cpp+14-5
......@@ -1062,12 +1062,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
10621062
10631063 TypeTableEntry *fn_type;
10641064 LLVMValueRef fn_val;
1065 AstNode *generic_proto_node;
10651066 if (fn_table_entry) {
10661067 fn_val = fn_table_entry->fn_value;
10671068 fn_type = fn_table_entry->type_entry;
1069 generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node;
10681070 } else {
10691071 fn_val = gen_expr(g, fn_ref_expr);
10701072 fn_type = get_expr_type(fn_ref_expr);
1073 generic_proto_node = nullptr;
10711074 }
10721075
10731076 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) {
10931096 gen_param_index += 1;
10941097 }
10951098
1096 for (int i = 0; i < fn_call_param_count; i += 1) {
1097 AstNode *expr_node = node->data.fn_call_expr.params.at(i);
1099 for (int call_i = 0; call_i < fn_call_param_count; call_i += 1) {
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);
10981107 LLVMValueRef param_value = gen_expr(g, expr_node);
10991108 assert(param_value);
11001109 TypeTableEntry *param_type = get_expr_type(expr_node);
......@@ -3734,7 +3743,7 @@ static void delete_unused_builtin_fns(CodeGen *g) {
37343743 }
37353744}
37363745
3737static bool skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
3746static bool should_skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
37383747 if (g->is_test_build) {
37393748 if (fn_entry->is_test) {
37403749 return false;
......@@ -3889,7 +3898,7 @@ static void do_code_gen(CodeGen *g) {
38893898 // Generate function prototypes
38903899 for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
38913900 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)) {
38933902 // huge time saver
38943903 LLVMDeleteFunction(fn_table_entry->fn_value);
38953904 fn_table_entry->fn_value = nullptr;
......@@ -3995,7 +4004,7 @@ static void do_code_gen(CodeGen *g) {
39954004 // Generate function definitions.
39964005 for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
39974006 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)) {
39994008 // huge time saver
40004009 continue;
40014010 }
src/eval.cpp+23-10
......@@ -884,9 +884,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
884884
885885 int param_count = node->data.fn_call_expr.params.length;
886886 ConstExprValue *args = allocate<ConstExprValue>(param_count);
887 for (int i = 0; i < param_count; i += 1) {
888 AstNode *param_expr_node = node->data.fn_call_expr.params.at(i);
889 ConstExprValue *param_val = &args[i];
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(call_i);
889 ConstExprValue *param_val = &args[call_i];
890890 if (eval_expr(ef, param_expr_node, param_val)) return true;
891891 }
892892
......@@ -1291,6 +1291,13 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
12911291}
12921292
12931293static 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
12941301 EvalFn ef = {0};
12951302 ef.root = efr;
12961303 ef.fn = fn;
......@@ -1300,12 +1307,12 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
13001307 root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context;
13011308 ef.scope_stack.append(root_scope);
13021309
1303 int param_count = fn->type_entry->data.fn.fn_type_id.param_count;
1304 for (int i = 0; i < param_count; i += 1) {
1305 AstNode *decl_param_node = fn->proto_node->data.fn_proto.params.at(i);
1310 int param_count = acting_proto_node->data.fn_proto.params.length;
1311 for (int proto_i = 0; proto_i < param_count; proto_i += 1) {
1312 AstNode *decl_param_node = acting_proto_node->data.fn_proto.params.at(proto_i);
13061313 assert(decl_param_node->type == NodeTypeParamDecl);
13071314
1308 ConstExprValue *src_const_val = &args[i];
1315 ConstExprValue *src_const_val = &args[proto_i];
13091316 assert(src_const_val->ok);
13101317
13111318 root_scope->vars.add_one();
......@@ -1315,7 +1322,6 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
13151322 }
13161323
13171324 return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val);
1318
13191325}
13201326
13211327bool 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
13291335 efr.call_node = node;
13301336 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
13321345 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;
1334 ConstExprValue *args = allocate<ConstExprValue>(type_param_count);
1346 int proto_param_count = acting_proto_node->data.fn_proto.params.length;
1347 ConstExprValue *args = allocate<ConstExprValue>(proto_param_count);
13351348 int next_arg_index = 0;
13361349 if (struct_node) {
13371350 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,
747747}
748748
749749/*
750ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..."
750ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
751751*/
752752static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
753753 Token *token = &pc->tokens->at(*token_index);
......@@ -763,6 +763,10 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
763763 node->data.param_decl.is_noalias = true;
764764 *token_index += 1;
765765 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);
766770 }
767771
768772 buf_resize(&node->data.param_decl.name, 0);
......@@ -2472,7 +2476,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
24722476}
24732477
24742478/*
2475FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr)
2479FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
24762480*/
24772481static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
24782482 ZigList<AstNode*> *directives, VisibMod visib_mod)
......@@ -2502,17 +2506,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
25022506
25032507 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
25162509 Token *next_token = &pc->tokens->at(*token_index);
25172510 if (next_token->id == TokenIdArrow) {
25182511 *token_index += 1;
......@@ -2931,7 +2924,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29312924 case NodeTypeFnProto:
29322925 visit_field(&node->data.fn_proto.return_type, visit, context);
29332926 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);
29352927 visit_node_list(&node->data.fn_proto.params, visit, context);
29362928 break;
29372929 case NodeTypeFnDef:
......@@ -3123,6 +3115,22 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src
31233115 }
31243116}
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
31263134static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,
31273135 uint32_t *next_node_index)
31283136{
......@@ -3133,20 +3141,26 @@ static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNod
31333141 }
31343142}
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{
31373147 if (src) {
3138 *dest = ast_clone_subtree(src, next_node_index);
3148 *dest = ast_clone_subtree_special(src, next_node_index, special);
31393149 (*dest)->parent_field = dest;
31403150 } else {
31413151 *dest = nullptr;
31423152 }
31433153}
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
31453159static void clone_subtree_tld(TopLevelDecl *dest, TopLevelDecl *src, uint32_t *next_node_index) {
31463160 clone_subtree_list_ptr(&dest->directives, src->directives, next_node_index);
31473161}
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) {
31503164 AstNode *new_node = allocate_nonzero<AstNode>(1);
31513165 memcpy(new_node, old_node, sizeof(AstNode));
31523166 new_node->create_index = *next_node_index;
......@@ -3163,14 +3177,19 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
31633177 next_node_index);
31643178 clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,
31653179 next_node_index);
3166 clone_subtree_list(&new_node->data.fn_proto.generic_params,
3167 &old_node->data.fn_proto.generic_params, next_node_index);
3168 clone_subtree_list(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
3169 next_node_index);
3180
3181 if (special == AstCloneSpecialOmitInlineParams) {
3182 clone_subtree_list_omit_inline_params(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
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
31713189 break;
31723190 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);
31743193 new_node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = new_node;
31753194 clone_subtree_field(&new_node->data.fn_def.body, old_node->data.fn_def.body, next_node_index);
31763195 break;
......@@ -3354,3 +3373,7 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
33543373
33553374 return new_node;
33563375}
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);
2525void normalize_parent_ptrs(AstNode *node);
2626
2727AstNode *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
2835void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context);
2936
3037#endif
std/hash_map.zig+10-9
......@@ -7,7 +7,7 @@ const want_modification_safety = !@compile_var("is_release");
77const debug_u32 = if (want_modification_safety) u32 else void;
88
99/*
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) {
1111 SmallHashMap(K, V, hash, eql, 8);
1212}
1313*/
......@@ -70,7 +70,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
7070
7171 pub fn deinit(hm: &Self) {
7272 if (hm.entries.ptr != &hm.prealloc_entries[0]) {
73 hm.allocator.free(hm.allocator, ([]u8)(hm.entries));
73 hm.allocator.free(Entry, hm.entries);
7474 }
7575 }
7676
......@@ -103,7 +103,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
103103 }
104104 }
105105 if (old_entries.ptr != &hm.prealloc_entries[0]) {
106 hm.allocator.free(hm.allocator, ([]u8)(old_entries));
106 hm.allocator.free(Entry, old_entries);
107107 }
108108 }
109109
......@@ -152,7 +152,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
152152 }
153153
154154 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);
156156 hm.size = 0;
157157 hm.max_distance_from_start_index = 0;
158158 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
180180 if (entry.distance_from_start_index < distance_from_start_index) {
181181 // robin hood to the rescue
182182 const tmp = *entry;
183 hm.max_distance_from_start_index = math.max(isize)(
183 hm.max_distance_from_start_index = math.max(isize,
184184 hm.max_distance_from_start_index, distance_from_start_index);
185185 *entry = Entry {
186186 .used = true,
......@@ -201,7 +201,8 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
201201 hm.size += 1;
202202 }
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);
205206 *entry = Entry {
206207 .used = true,
207208 .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
231232}
232233
233234var global_allocator = Allocator {
234 .alloc = global_alloc,
235 .realloc = global_realloc,
236 .free = global_free,
235 .alloc_fn = global_alloc,
236 .realloc_fn = global_realloc,
237 .free_fn = global_free,
237238 .context = null,
238239};
239240
std/io.zig+22-32
......@@ -69,7 +69,7 @@ pub struct OutStream {
6969 const dest_space_left = os.buffer.len - os.index;
7070
7171 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);
7373 @memcpy(&os.buffer[os.index], &bytes[src_index], copy_amt);
7474 os.index += copy_amt;
7575 if (os.index == os.buffer.len) {
......@@ -208,59 +208,47 @@ pub struct InStream {
208208 }
209209}
210210
211pub error InvalidChar;
212pub error Overflow;
213
214pub fn parse_unsigned(T: type)(buf: []u8, radix: u8) -> %T {
211pub fn parse_unsigned(inline T: type, buf: []u8, radix: u8) -> %T {
215212 var x: T = 0;
216213
217214 for (buf) |c| {
218 const digit = char_to_digit(c);
219
220 if (digit >= radix) {
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 }
215 const digit = %return char_to_digit(c, radix);
216 x = %return math.mul_overflow(T, x, radix);
217 x = %return math.add_overflow(T, x, digit);
233218 }
234219
235220 return x;
236221}
237222
238fn char_to_digit(c: u8) -> u8 {
239 // TODO use switch with range
240 if ('0' <= c && c <= '9') {
223pub error InvalidChar;
224fn char_to_digit(c: u8, radix: u8) -> %u8 {
225 const value = if ('0' <= c && c <= '9') {
241226 c - '0'
242227 } else if ('A' <= c && c <= 'Z') {
243228 c - 'A' + 10
244229 } else if ('a' <= c && c <= 'z') {
245230 c - 'a' + 10
246231 } else {
247 @max_value(u8)
248 }
232 return error.InvalidChar;
233 };
234 return if (value >= radix) error.InvalidChar else value;
249235}
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 {
252238 const uint = @int_type(false, T.bit_count, false);
253239 if (x < 0) {
254240 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);
256242 } else {
257 return buf_print_unsigned(uint)(out_buf, uint(x));
243 return buf_print_unsigned(uint, out_buf, uint(x));
258244 }
259245}
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 {
264252 var buf: [max_u64_base10_digits]u8 = undefined;
265253 var a = x;
266254 var index: isize = buf.len;
......@@ -281,7 +269,9 @@ pub fn buf_print_unsigned(T: type)(out_buf: []u8, x: T) -> isize {
281269 return len;
282270}
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
286276pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
287277 const numExpBits = 11;
......@@ -409,7 +399,7 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
409399
410400#attribute("test")
411401fn parse_u64_digit_too_big() {
412 parse_unsigned(u64)("123a", 10) %% |err| {
402 parse_unsigned(u64, "123a", 10) %% |err| {
413403 if (err == error.InvalidChar) return;
414404 unreachable{};
415405 };
std/list.zig+14-15
......@@ -2,59 +2,58 @@ const assert = @import("debug.zig").assert;
22const mem = @import("mem.zig");
33const Allocator = mem.Allocator;
44
5/*
6pub fn List(T: type) -> type {
5pub inline fn List(inline T: type) -> type {
76 SmallList(T, 8)
87}
9*/
108
119pub struct SmallList(T: type, STATIC_SIZE: isize) {
10 const Self = SmallList(T, STATIC_SIZE);
11
1212 items: []T,
1313 length: isize,
1414 prealloc_items: [STATIC_SIZE]T,
1515 allocator: &Allocator,
1616
17 pub fn init(l: &SmallList(T, STATIC_SIZE), allocator: &Allocator) {
17 pub fn init(l: &Self, allocator: &Allocator) {
1818 l.items = l.prealloc_items[0...];
1919 l.length = 0;
2020 l.allocator = allocator;
2121 }
2222
23 pub fn deinit(l: &SmallList(T, STATIC_SIZE)) {
23 pub fn deinit(l: &Self) {
2424 if (l.items.ptr != &l.prealloc_items[0]) {
25 l.allocator.free(l.allocator, ([]u8)(l.items));
25 l.allocator.free(T, l.items);
2626 }
2727 }
2828
29 pub fn append(l: &SmallList(T, STATIC_SIZE), item: T) -> %void {
29 pub fn append(l: &Self, item: T) -> %void {
3030 const new_length = l.length + 1;
3131 %return l.ensure_capacity(new_length);
3232 l.items[l.length] = item;
3333 l.length = new_length;
3434 }
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 {
3737 const old_capacity = l.items.len;
3838 var better_capacity = old_capacity;
3939 while (better_capacity < new_capacity) {
4040 better_capacity *= 2;
4141 }
4242 if (better_capacity != old_capacity) {
43 const alloc_bytes = better_capacity * @sizeof(T);
4443 if (l.items.ptr == &l.prealloc_items[0]) {
45 l.items = ([]T)(%return l.allocator.alloc(l.allocator, alloc_bytes));
46 @memcpy(l.items.ptr, &l.prealloc_items[0], old_capacity * @sizeof(T));
44 l.items = %return l.allocator.alloc(T, better_capacity);
45 mem.copy(T, l.items, l.prealloc_items[0...old_capacity]);
4746 } 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);
4948 }
5049 }
5150 }
5251}
5352
5453var global_allocator = Allocator {
55 .alloc = global_alloc,
56 .realloc = global_realloc,
57 .free = global_free,
54 .alloc_fn = global_alloc,
55 .realloc_fn = global_realloc,
56 .free_fn = global_free,
5857 .context = null,
5958};
6059
std/math.zig+16-2
......@@ -26,10 +26,24 @@ pub fn f64_is_inf(f: f64) -> bool {
2626 f == f64_get_neg_inf() || f == f64_get_pos_inf()
2727}
2828
29pub fn min(T: type)(x: T, y: T) -> T {
29pub fn min(inline T: type, x: T, y: T) -> T {
3030 if (x < y) x else y
3131}
3232
33pub fn max(T: type)(x: T, y: T) -> T {
33pub fn max(inline T: type, x: T, y: T) -> T {
3434 if (x > y) x else y
3535}
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 @@
11const assert = @import("debug.zig").assert;
2const math = @import("math.zig");
3const os = @import("os.zig");
4const io = @import("io.zig");
25
36pub error NoMem;
47
58pub type Context = u8;
69pub struct Allocator {
7 alloc: fn (self: &Allocator, n: isize) -> %[]u8,
8 realloc: fn (self: &Allocator, old_mem: []u8, new_size: isize) -> %[]u8,
9 free: fn (self: &Allocator, mem: []u8),
10 alloc_fn: fn (self: &Allocator, n: isize) -> %[]u8,
11 realloc_fn: fn (self: &Allocator, old_mem: []u8, new_size: isize) -> %[]u8,
12 free_fn: fn (self: &Allocator, mem: []u8),
1013 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 }
1139}
1240
1341/// Copy all of source into dest at position 0.
1442/// dest.len must be >= source.len.
15pub fn copy(T)(dest: []T, source: []T) {
43pub fn copy(inline T: type, dest: []T, source: []T) {
1644 assert(dest.len >= source.len);
1745 @memcpy(dest.ptr, source.ptr, @sizeof(T) * source.len);
1846}
std/net.zig+6-7
......@@ -99,14 +99,14 @@ pub fn connect_addr(addr: &Address, port: u16) -> %Connection {
9999 const connect_ret = if (addr.family == linux.AF_INET) {
100100 var os_addr: linux.sockaddr_in = undefined;
101101 os_addr.family = addr.family;
102 os_addr.port = host_to_be(u16)(port);
102 os_addr.port = swap_if_little_endian(u16, port);
103103 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
104104 @memset(&os_addr.zero, 0, @sizeof(@typeof(os_addr.zero)));
105105 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeof(linux.sockaddr_in))
106106 } else if (addr.family == linux.AF_INET6) {
107107 var os_addr: linux.sockaddr_in6 = undefined;
108108 os_addr.family = addr.family;
109 os_addr.port = host_to_be(u16)(port);
109 os_addr.port = swap_if_little_endian(u16, port);
110110 os_addr.flowinfo = 0;
111111 os_addr.scope_id = addr.scope_id;
112112 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
......@@ -319,7 +319,7 @@ fn parse_ip4(buf: []const u8) -> %u32 {
319319
320320#attribute("test")
321321fn 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));
323323 switch (parse_ip4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
324324 switch (parse_ip4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
325325 switch (parse_ip4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
......@@ -352,12 +352,11 @@ fn test_lookup_simple_ip() {
352352 }
353353}
354354
355const be_to_host = host_to_be;
356fn host_to_be(T: type)(x: T) -> T {
357 if (@compile_var("is_big_endian")) x else endian_swap(T)(x)
355fn swap_if_little_endian(inline T: type, x: T) -> T {
356 if (@compile_var("is_big_endian")) x else endian_swap(T, x)
358357}
359358
360fn endian_swap(T: type)(x: T) -> T {
359fn endian_swap(inline T: type, x: T) -> T {
361360 const x_slice = ([]u8)((&const x)[0...1]);
362361 var result: T = undefined;
363362 const result_slice = ([]u8)((&result)[0...1]);
std/str.zig+4-2
......@@ -1,8 +1,10 @@
11const 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 {
68 if (a.len != b.len) return false;
79 for (a) |item, index| {
810 if (b[index] != item) return false;
std/test_runner.zig+1
......@@ -9,6 +9,7 @@ extern var zig_test_fn_list: []TestFn;
99
1010pub fn run_tests() -> %void {
1111 for (zig_test_fn_list) |test_fn, i| {
12 // TODO: print var args
1213 %%io.stderr.write("Test ");
1314 %%io.stderr.print_i64(i + 1);
1415 %%io.stderr.write("/");
test/run_tests.cpp+24-3
......@@ -1181,11 +1181,11 @@ const invalid = foo > foo;
11811181 )SOURCE", 1, ".tmp_source.zig:3:21: error: operator not allowed for type 'fn()'");
11821182
11831183 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; }
11851185fn test1(a: i32, b: i32) -> i32 {
1186 return foo(a)(b);
1186 return foo(a, b);
11871187}
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
11901190 add_compile_fail_case("goto jumping into block", R"SOURCE(
11911191fn f() {
......@@ -1406,6 +1406,27 @@ fn f() {
14061406}
14071407 )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
14091430}
14101431
14111432//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+15-20
......@@ -712,17 +712,17 @@ three)";
712712
713713#attribute("test")
714714fn simple_generic_fn() {
715 assert(max(i32)(3, -1) == 3);
716 assert(max(f32)(0.123, 0.456) == 0.456);
717 assert(add(2)(3) == 5);
715 assert(max(i32, 3, -1) == 3);
716 assert(max(f32, 0.123, 0.456) == 0.456);
717 assert(add(2, 3) == 5);
718718}
719719
720fn max(T: type)(a: T, b: T) -> T {
720fn max(inline T: type, a: T, b: T) -> T {
721721 return if (a > b) a else b;
722722}
723723
724fn add(a: i32)(b: i32) -> i32 {
725 return a + b;
724fn add(inline a: i32, b: i32) -> i32 {
725 return @const_eval(a) + b;
726726}
727727
728728
......@@ -734,23 +734,18 @@ fn constant_equal_function_pointers() {
734734
735735fn empty_fn() {}
736736
737#attribute("test")
738fn generic_function_equality() {
739 assert(max(i32) == max(i32));
740}
741
742737
743738#attribute("test")
744739fn generic_malloc_free() {
745 const a = %%mem_alloc(u8)(10);
746 mem_free(u8)(a);
740 const a = %%mem_alloc(u8, 10);
741 mem_free(u8, a);
747742}
748743const some_mem : [100]u8 = undefined;
749744#static_eval_enable(false)
750fn mem_alloc(T: type)(n: isize) -> %[]T {
745fn mem_alloc(inline T: type, n: isize) -> %[]T {
751746 return (&T)(&some_mem[0])[0...n];
752747}
753fn mem_free(T: type)(mem: []T) { }
748fn mem_free(inline T: type, mem: []T) { }
754749
755750
756751#attribute("test")
......@@ -982,11 +977,11 @@ pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
982977
983978#attribute("test")
984979fn generic_fn_with_implicit_cast() {
985 assert(get_first_byte(u8)([]u8 {13}) == 13);
986 assert(get_first_byte(u16)([]u16 {0, 13}) == 0);
980 assert(get_first_byte(u8, []u8 {13}) == 13);
981 assert(get_first_byte(u16, []u16 {0, 13}) == 0);
987982}
988983fn 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 {
990985 get_byte((&u8)(&mem[0]))
991986}
992987
......@@ -1651,9 +1646,9 @@ struct GenericDataThing(count: isize) {
16511646
16521647#attribute("test")
16531648fn use_generic_param_in_generic_param() {
1654 assert(a_generic_fn(i32, 3)(4) == 7);
1649 assert(a_generic_fn(i32, 3, 4) == 7);
16551650}
1656fn a_generic_fn(T: type, a: T)(b: T) -> T {
1651fn a_generic_fn(inline T: type, inline a: T, b: T) -> T {
16571652 return a + b;
16581653}
16591654