aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-07-24 18:35:50 -0700
committerAndrew Kelley <superjoe30@gmail.com>2016-07-25 22:55:15 -0700
commit78d4fb20c44488117cc450177d92c44a19d97c91 (patch)
tree3a39a09a30d7667de2e4fc62ab1c14fdaddb00b2 /src
parent425c0ffa014fb950a4f9f90aa9a200fbc4d8e091 (diff)
downloadzig-78d4fb20c44488117cc450177d92c44a19d97c91.tar.gz
zig-78d4fb20c44488117cc450177d92c44a19d97c91.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/all_types.hpp15
-rw-r--r--src/analyze.cpp470
-rw-r--r--src/ast_render.cpp3
-rw-r--r--src/codegen.cpp19
-rw-r--r--src/eval.cpp33
-rw-r--r--src/parser.cpp67
-rw-r--r--src/parser.hpp7
7 files changed, 418 insertions, 196 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 49336f8924..b94188bdbd 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -195,10 +195,8 @@ struct AstNodeRoot {
struct AstNodeFnProto {
TopLevelDecl top_level_decl;
Buf name;
- ZigList<AstNode *> generic_params;
ZigList<AstNode *> params;
AstNode *return_type;
- bool generic_params_is_var_args;
bool is_var_args;
bool is_extern;
bool is_inline;
@@ -210,7 +208,10 @@ struct AstNodeFnProto {
FnTableEntry *fn_table_entry;
bool skip;
Expr resolved_expr;
- TypeTableEntry *generic_fn_type;
+ // computed from params field
+ int inline_arg_count;
+ // if this is a generic function implementation, this points to the generic node
+ AstNode *generic_proto_node;
};
struct AstNodeFnDef {
@@ -219,6 +220,7 @@ struct AstNodeFnDef {
// populated by semantic analyzer
TypeTableEntry *implicit_return_type;
+ // the first child block context
BlockContext *block_context;
};
@@ -230,6 +232,7 @@ struct AstNodeParamDecl {
Buf name;
AstNode *type;
bool is_noalias;
+ bool is_inline;
// populated by semantic analyzer
VariableTableEntry *variable;
@@ -841,6 +844,7 @@ struct FnTypeId {
bool is_naked;
bool is_cold;
bool is_extern;
+ bool is_inline;
FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
};
@@ -1063,7 +1067,6 @@ struct FnTableEntry {
ZigList<LabelTableEntry *> all_labels;
Buf symbol_name;
TypeTableEntry *type_entry; // function type
- bool is_inline;
bool internal_linkage;
bool is_extern;
bool is_test;
@@ -1172,8 +1175,8 @@ struct CodeGen {
ZigList<ImportTableEntry *> import_queue;
int import_queue_index;
- ZigList<AstNode *> export_queue;
- int export_queue_index;
+ ZigList<AstNode *> resolve_queue;
+ int resolve_queue_index;
ZigList<AstNode *> use_queue;
int use_queue_index;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 2f7a1f78b7..d5a93a3980 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -32,6 +32,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
bool depends_on_compile_var);
+static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode *node,
+ TypeTableEntry *type_entry, bool depends_on_compile_var);
static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
bool depends_on_compile_var);
static 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
fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport);
fn_type_id.is_naked = is_naked;
fn_type_id.is_cold = is_cold;
- fn_type_id.param_count = node->data.fn_proto.params.length;
+ fn_type_id.is_inline = fn_proto->is_inline;
+ fn_type_id.param_count = fn_proto->params.length;
if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
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
}
fn_type_id.is_var_args = fn_proto->is_var_args;
- fn_type_id.return_type = analyze_type_expr(g, import, context, node->data.fn_proto.return_type);
+ fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);
- if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {
- fn_proto->skip = true;
+ switch (fn_type_id.return_type->id) {
+ case TypeTableEntryIdInvalid:
+ fn_proto->skip = true;
+ break;
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNamespace:
+ case TypeTableEntryIdGenericFn:
+ fn_proto->skip = true;
+ add_node_error(g, fn_proto->return_type,
+ buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
+ break;
+ case TypeTableEntryIdMetaType:
+ if (!fn_proto->is_inline) {
+ fn_proto->skip = true;
+ add_node_error(g, fn_proto->return_type,
+ buf_sprintf("function with return type '%s' must be declared inline",
+ buf_ptr(&fn_type_id.return_type->name)));
+ return g->builtin_types.entry_invalid;
+ }
+ break;
+ case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdVoid:
+ case TypeTableEntryIdBool:
+ case TypeTableEntryIdInt:
+ case TypeTableEntryIdFloat:
+ case TypeTableEntryIdPointer:
+ case TypeTableEntryIdArray:
+ case TypeTableEntryIdStruct:
+ case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
+ case TypeTableEntryIdEnum:
+ case TypeTableEntryIdUnion:
+ case TypeTableEntryIdFn:
+ case TypeTableEntryIdTypeDecl:
+ break;
}
for (int i = 0; i < fn_type_id.param_count; i += 1) {
- AstNode *child = node->data.fn_proto.params.at(i);
+ AstNode *child = fn_proto->params.at(i);
assert(child->type == NodeTypeParamDecl);
+
TypeTableEntry *type_entry = analyze_type_expr(g, import, context,
child->data.param_decl.type);
switch (type_entry->id) {
@@ -901,13 +941,20 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdGenericFn:
fn_proto->skip = true;
add_node_error(g, child->data.param_decl.type,
- buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name)));
+ buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
+ break;
+ case TypeTableEntryIdMetaType:
+ if (!child->data.param_decl.is_inline) {
+ fn_proto->skip = true;
+ add_node_error(g, child->data.param_decl.type,
+ buf_sprintf("parameter of type '%s' must be declared inline",
+ buf_ptr(&type_entry->name)));
+ }
break;
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
@@ -998,8 +1045,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
return;
}
- fn_table_entry->is_inline = fn_proto->is_inline;
-
bool is_cold = false;
bool is_naked = false;
bool is_test = false;
@@ -1095,7 +1140,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
return;
}
- if (fn_table_entry->is_inline && fn_table_entry->is_noinline) {
+ if (fn_proto->is_inline && fn_table_entry->is_noinline) {
add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
fn_proto->skip = true;
return;
@@ -1109,10 +1154,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
}
- fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
- fn_type->data.fn.raw_type_ref);
+ if (fn_table_entry->fn_def_node) {
+ BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context);
+ fn_table_entry->fn_def_node->data.fn_def.block_context = context;
+ }
+
+ fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
- if (fn_table_entry->is_inline) {
+ if (fn_proto->is_inline) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
}
if (fn_table_entry->is_noinline) {
@@ -1150,9 +1199,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
fn_type->di_type, fn_table_entry->internal_linkage,
is_definition, scope_line, flags, is_optimized, nullptr);
- BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context);
- fn_table_entry->fn_def_node->data.fn_def.block_context = context;
- context->di_scope = LLVMZigSubprogramToScope(subprogram);
+ fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
}
}
@@ -1176,6 +1223,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
return;
}
+ assert(decl_node->type == NodeTypeContainerDecl);
assert(enum_type->di_type);
enum_type->deep_const = true;
@@ -1370,7 +1418,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
return;
}
-
+ assert(decl_node->type == NodeTypeContainerDecl);
assert(struct_type->di_type);
struct_type->deep_const = true;
@@ -1496,38 +1544,30 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t
}
static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- if (node->type == NodeTypeFnProto) {
- if (node->data.fn_proto.generic_params_is_var_args) {
- add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
- node->data.fn_proto.skip = true;
- node->data.fn_proto.generic_fn_type = g->builtin_types.entry_invalid;
- return;
- }
-
- node->data.fn_proto.generic_fn_type = get_generic_fn_type(g, node);
- } else if (node->type == NodeTypeContainerDecl) {
- if (node->data.struct_decl.generic_params_is_var_args) {
- add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
- node->data.struct_decl.skip = true;
- node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
- return;
- }
+ assert(node->type == NodeTypeContainerDecl);
- node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
- } else {
- zig_unreachable();
+ if (node->data.struct_decl.generic_params_is_var_args) {
+ add_node_error(g, node, buf_sprintf("generic parameters cannot be var args"));
+ node->data.struct_decl.skip = true;
+ node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid;
+ return;
}
+ node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
}
static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
BlockContext *containing_context)
{
+ assert(proto_node->type == NodeTypeFnProto);
+
if (proto_node->data.fn_proto.skip) {
return;
}
- bool is_generic_instance = (proto_node->data.fn_proto.generic_params.length > 0);
+ bool is_generic_instance = proto_node->data.fn_proto.generic_proto_node;
+ bool is_generic_fn = proto_node->data.fn_proto.inline_arg_count > 0;
+ assert(!is_generic_instance || !is_generic_fn);
AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
Buf *proto_name = &proto_node->data.fn_proto.name;
@@ -1551,41 +1591,50 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
- g->fn_protos.append(fn_table_entry);
-
- if (fn_def_node) {
- g->fn_defs.append(fn_table_entry);
- }
+ proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
- bool is_main_fn = !is_generic_instance &&
- !parent_decl && (import == g->root_import) &&
- buf_eql_str(proto_name, "main");
- if (is_main_fn) {
- g->main_fn = fn_table_entry;
- }
+ if (is_generic_fn) {
+ fn_table_entry->type_entry = get_generic_fn_type(g, proto_node);
- proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
- resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context);
-
- if (is_main_fn && !g->link_libc) {
- TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
- TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
- if (actual_return_type != err_void) {
- AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type;
- add_node_error(g, return_type_node,
- buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
- buf_ptr(&actual_return_type->name)));
+ if (is_extern || proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModExport) {
+ for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
+ AstNode *param_decl_node = proto_node->data.fn_proto.params.at(i);
+ if (param_decl_node->data.param_decl.is_inline) {
+ proto_node->data.fn_proto.skip = true;
+ add_node_error(g, param_decl_node,
+ buf_sprintf("inline parameter not allowed in extern function"));
+ }
+ }
}
- }
-}
-static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) {
- if (proto_node->data.fn_proto.generic_params.length > 0) {
- return preview_generic_fn_proto(g, import, proto_node);
+
} else {
- return preview_fn_proto_instance(g, import, proto_node, proto_node->block_context);
- }
+ g->fn_protos.append(fn_table_entry);
+
+ if (fn_def_node) {
+ g->fn_defs.append(fn_table_entry);
+ }
+
+ bool is_main_fn = !is_generic_instance &&
+ !parent_decl && (import == g->root_import) &&
+ buf_eql_str(proto_name, "main");
+ if (is_main_fn) {
+ g->main_fn = fn_table_entry;
+ }
+ resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context);
+
+ if (is_main_fn && !g->link_libc) {
+ TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
+ TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
+ if (actual_return_type != err_void) {
+ AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type;
+ add_node_error(g, return_type_node,
+ buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
+ buf_ptr(&actual_return_type->name)));
+ }
+ }
+ }
}
static 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)
switch (node->type) {
case NodeTypeFnProto:
- preview_fn_proto(g, import, node);
+ preview_fn_proto_instance(g, import, node, node->block_context);
break;
case NodeTypeContainerDecl:
resolve_struct_decl(g, import, node);
@@ -2600,7 +2649,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
node->data.field_access_expr.is_member_fn = true;
FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
- return resolve_expr_const_val_as_fn(g, node, fn_entry, false);
+ if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
+ return resolve_expr_const_val_as_generic_fn(g, node, fn_entry->type_entry, false);
+ } else {
+ return resolve_expr_const_val_as_fn(g, node, fn_entry, false);
+ }
} else {
add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",
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
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var);
} else if (decl_node->type == NodeTypeFnProto) {
- if (decl_node->data.fn_proto.generic_params.length > 0) {
- TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
- assert(type_entry);
- return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
+ FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
+ assert(fn_entry->type_entry);
+ if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
+ return resolve_expr_const_val_as_generic_fn(g, source_node, fn_entry->type_entry, depends_on_compile_var);
} else {
- FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
- assert(fn_entry->type_entry);
return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
}
} else if (decl_node->type == NodeTypeContainerDecl) {
@@ -5238,6 +5289,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
zig_unreachable();
}
+// Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known
+// at compile time. Otherwise this is a function pointer call.
static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
AstNode *struct_node)
@@ -5248,26 +5301,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
return fn_type;
}
- // count parameters
- int src_param_count = fn_type->data.fn.fn_type_id.param_count;
- int actual_param_count = node->data.fn_call_expr.params.length;
+ // The function call might include inline parameters which we need to ignore according to the
+ // fn_type.
+ FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
+ AstNode *generic_proto_node = fn_table_entry ?
+ fn_table_entry->proto_node->data.fn_proto.generic_proto_node : nullptr;
- if (struct_node) {
- actual_param_count += 1;
- }
+ // count parameters
+ int struct_node_1_or_0 = struct_node ? 1 : 0;
+ int src_param_count = fn_type->data.fn.fn_type_id.param_count +
+ (generic_proto_node ? generic_proto_node->data.fn_proto.inline_arg_count : 0);
+ int call_param_count = node->data.fn_call_expr.params.length;
bool ok_invocation = true;
if (fn_type->data.fn.fn_type_id.is_var_args) {
- if (actual_param_count < src_param_count) {
+ if (call_param_count < src_param_count - struct_node_1_or_0) {
ok_invocation = false;
add_node_error(g, node,
- buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
+ buf_sprintf("expected at least %d arguments, got %d", src_param_count, call_param_count));
}
- } else if (src_param_count != actual_param_count) {
+ } else if (src_param_count - struct_node_1_or_0 != call_param_count) {
ok_invocation = false;
add_node_error(g, node,
- buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
+ buf_sprintf("expected %d arguments, got %d", src_param_count, call_param_count));
}
bool all_args_const_expr = true;
@@ -5281,17 +5338,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
// analyze each parameter. in the case of a method, we already analyzed the
// first parameter in order to figure out which struct we were calling a method on.
- for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
- AstNode **child = &node->data.fn_call_expr.params.at(i);
+ int next_type_i = struct_node_1_or_0;
+ for (int call_i = 0; call_i < call_param_count; call_i += 1) {
+ int proto_i = call_i + struct_node_1_or_0;
+ AstNode **param_node = &node->data.fn_call_expr.params.at(call_i);
// determine the expected type for each parameter
TypeTableEntry *expected_param_type = nullptr;
- int fn_proto_i = i + (struct_node ? 1 : 0);
- if (fn_proto_i < src_param_count) {
- expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;
+ if (proto_i < src_param_count) {
+ if (generic_proto_node &&
+ generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
+ {
+ continue;
+ }
+
+ FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[next_type_i];
+ next_type_i += 1;
+
+ expected_param_type = param_info->type;
+ }
+ TypeTableEntry *param_type = analyze_expression(g, import, context, expected_param_type, *param_node);
+ if (param_type->id == TypeTableEntryIdInvalid) {
+ return param_type;
}
- analyze_expression(g, import, context, expected_param_type, *child);
- ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val;
+ ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val;
if (!const_arg_val->ok) {
all_args_const_expr = false;
}
@@ -5303,7 +5373,6 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
return return_type;
}
- FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {
if (fn_table_entry->anal_state == FnAnalStateReady) {
@@ -5335,14 +5404,103 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
return return_type;
}
-static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node)
+static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableEntry *import,
+ BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *call_node,
+ FnTableEntry *fn_table_entry, AstNode *struct_node)
{
- assert(node->type == NodeTypeFnCallExpr);
+ assert(call_node->type == NodeTypeFnCallExpr);
+ assert(fn_table_entry);
+
+ AstNode *decl_node = fn_table_entry->proto_node;
+
+ // count parameters
+ int struct_node_1_or_0 = (struct_node ? 1 : 0);
+ int src_param_count = decl_node->data.fn_proto.params.length;
+ int call_param_count = call_node->data.fn_call_expr.params.length;
+
+ if (src_param_count != call_param_count + struct_node_1_or_0) {
+ add_node_error(g, call_node,
+ buf_sprintf("expected %d arguments, got %d", src_param_count, call_param_count));
+ return g->builtin_types.entry_invalid;
+ }
+
+ int inline_arg_count = decl_node->data.fn_proto.inline_arg_count;
+ assert(inline_arg_count > 0);
+
+ BlockContext *child_context = decl_node->owner->block_context;
+ int next_generic_param_index = 0;
+
+ GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
+ generic_fn_type_id->decl_node = decl_node;
+ generic_fn_type_id->generic_param_count = inline_arg_count;
+ generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_arg_count);
+
+ for (int call_i = 0; call_i < call_param_count; call_i += 1) {
+ int proto_i = call_i + struct_node_1_or_0;
+ AstNode *generic_param_decl_node = decl_node->data.fn_proto.params.at(proto_i);
+ assert(generic_param_decl_node->type == NodeTypeParamDecl);
+ bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
+ if (!is_inline) continue;
+
+ AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
+ TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, child_context,
+ *generic_param_type_node);
+ if (expected_param_type->id == TypeTableEntryIdInvalid) {
+ return expected_param_type;
+ }
+
+ AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
+ TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
+ expected_param_type, *param_node);
+ if (param_type->id == TypeTableEntryIdInvalid) {
+ return param_type;
+ }
+
+ // set child_context so that the previous param is in scope
+ child_context = new_block_context(generic_param_decl_node, child_context);
+
+ ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
+ if (const_val->ok) {
+ add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
+ &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
+ } else {
+ add_node_error(g, *param_node,
+ buf_sprintf("unable to evaluate constant expression for inline parameter"));
+
+ return g->builtin_types.entry_invalid;
+ }
+
+ GenericParamValue *generic_param_value =
+ &generic_fn_type_id->generic_params[next_generic_param_index];
+ generic_param_value->type = param_type;
+ generic_param_value->node = *param_node;
+ next_generic_param_index += 1;
+ }
+
+ assert(next_generic_param_index == inline_arg_count);
+
+ auto entry = g->generic_table.maybe_get(generic_fn_type_id);
+ FnTableEntry *impl_fn;
+ if (entry) {
+ AstNode *impl_decl_node = entry->value;
+ assert(impl_decl_node->type == NodeTypeFnProto);
+ impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
+ } else {
+ AstNode *decl_node = generic_fn_type_id->decl_node;
+ AstNode *impl_fn_def_node = ast_clone_subtree_special(decl_node->data.fn_proto.fn_def_node,
+ &g->next_node_index, AstCloneSpecialOmitInlineParams);
+ AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
+ impl_decl_node->data.fn_proto.inline_arg_count = 0;
+ impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
- node->data.fn_call_expr.fn_entry = fn_table_entry;
+ preview_fn_proto_instance(g, import, impl_decl_node, child_context);
+ g->generic_table.put(generic_fn_type_id, impl_decl_node);
+ impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
+ }
- return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node);
+ call_node->data.fn_call_expr.fn_entry = impl_fn;
+ return analyze_fn_call_ptr(g, import, parent_context, expected_type, call_node,
+ impl_fn->type_entry, struct_node);
}
static 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
assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
- ZigList<AstNode *> *generic_params;
- if (decl_node->type == NodeTypeFnProto) {
- generic_params = &decl_node->data.fn_proto.generic_params;
- } else if (decl_node->type == NodeTypeContainerDecl) {
- generic_params = &decl_node->data.struct_decl.generic_params;
- } else {
- zig_unreachable();
- }
+ assert(decl_node->type == NodeTypeContainerDecl);
+ ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
int expected_param_count = generic_params->length;
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
} else {
add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
- add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
- &generic_param_decl_node->data.param_decl.name, g->builtin_types.entry_invalid,
- true, nullptr);
-
return g->builtin_types.entry_invalid;
}
@@ -5420,36 +5568,19 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
auto entry = g->generic_table.maybe_get(generic_fn_type_id);
if (entry) {
AstNode *impl_decl_node = entry->value;
- if (impl_decl_node->type == NodeTypeFnProto) {
- FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
- return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
- } else if (impl_decl_node->type == NodeTypeContainerDecl) {
- TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
- return resolve_expr_const_val_as_type(g, node, type_entry, false);
- } else {
- zig_unreachable();
- }
- }
-
- // make a type from the generic parameters supplied
- if (decl_node->type == NodeTypeFnProto) {
- AstNode *impl_fn_def_node = ast_clone_subtree(decl_node->data.fn_proto.fn_def_node, &g->next_node_index);
- AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
-
- preview_fn_proto_instance(g, import, impl_decl_node, child_context);
- g->generic_table.put(generic_fn_type_id, impl_decl_node);
- FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
- return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
- } else if (decl_node->type == NodeTypeContainerDecl) {
- AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
- g->generic_table.put(generic_fn_type_id, impl_decl_node);
- scan_struct_decl(g, import, child_context, impl_decl_node);
+ assert(impl_decl_node->type == NodeTypeContainerDecl);
TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
- resolve_struct_type(g, import, type_entry);
return resolve_expr_const_val_as_type(g, node, type_entry, false);
- } else {
- zig_unreachable();
}
+
+ // make a type from the generic parameters supplied
+ assert(decl_node->type == NodeTypeContainerDecl);
+ AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
+ g->generic_table.put(generic_fn_type_id, impl_decl_node);
+ scan_struct_decl(g, import, child_context, impl_decl_node);
+ TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
+ resolve_struct_type(g, import, type_entry);
+ return resolve_expr_const_val_as_type(g, node, type_entry, false);
}
static 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
struct_node = nullptr;
}
- return analyze_fn_call_raw(g, import, context, expected_type, node,
- const_val->data.x_fn, struct_node);
+ FnTableEntry *fn_table_entry = const_val->data.x_fn;
+ node->data.fn_call_expr.fn_entry = fn_table_entry;
+ return analyze_fn_call_ptr(g, import, context, expected_type, node,
+ fn_table_entry->type_entry, struct_node);
} else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {
- return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
+ TypeTableEntry *generic_fn_type = const_val->data.x_type;
+ AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
+ if (decl_node->type == NodeTypeFnProto) {
+ AstNode *struct_node;
+ if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
+ fn_ref_expr->data.field_access_expr.is_member_fn)
+ {
+ struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
+ } else {
+ struct_node = nullptr;
+ }
+
+ FnTableEntry *fn_table_entry = decl_node->data.fn_proto.fn_table_entry;
+ if (fn_table_entry->proto_node->data.fn_proto.skip) {
+ return g->builtin_types.entry_invalid;
+ }
+ return analyze_fn_call_with_inline_args(g, import, context, expected_type, node,
+ fn_table_entry, struct_node);
+ } else {
+ return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
+ }
} else {
add_node_error(g, fn_ref_expr,
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) {
var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var;
- var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
+ if (fn_type->data.fn.gen_param_info) {
+ var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
+ }
if (!type->deep_const) {
fn_table_entry->is_pure = false;
@@ -6406,11 +6561,11 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
tld->import = import;
tld->name = name;
- bool want_as_export = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);
- bool is_generic = (node->type == NodeTypeFnProto && node->data.fn_proto.generic_params.length > 0) ||
- (node->type == NodeTypeContainerDecl && node->data.struct_decl.generic_params.length > 0);
- if (!is_generic && want_as_export) {
- g->export_queue.append(node);
+ bool want_to_resolve = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport);
+ bool is_generic_container = (node->type == NodeTypeContainerDecl &&
+ node->data.struct_decl.generic_params.length > 0);
+ if (want_to_resolve && !is_generic_container) {
+ g->resolve_queue.append(node);
}
node->block_context = block_context;
@@ -6425,6 +6580,18 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
}
}
+static int fn_proto_inline_arg_count(AstNode *proto_node) {
+ assert(proto_node->type == NodeTypeFnProto);
+ int result = 0;
+ for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
+ AstNode *param_node = proto_node->data.fn_proto.params.at(i);
+ assert(param_node->type == NodeTypeParamDecl);
+ result += param_node->data.param_decl.is_inline ? 1 : 0;
+ }
+ return result;
+}
+
+
static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
@@ -6467,6 +6634,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
add_node_error(g, node, buf_sprintf("missing function name"));
break;
}
+ node->data.fn_proto.inline_arg_count = fn_proto_inline_arg_count(node);
add_top_level_decl(g, import, context, node, fn_name);
break;
@@ -6692,8 +6860,8 @@ void semantic_analyze(CodeGen *g) {
resolve_use_decl(g, use_decl_node);
}
- for (; g->export_queue_index < g->export_queue.length; g->export_queue_index += 1) {
- AstNode *decl_node = g->export_queue.at(g->export_queue_index);
+ for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
+ AstNode *decl_node = g->resolve_queue.at(g->resolve_queue_index);
bool pointer_only = false;
resolve_top_level_decl(g, decl_node, pointer_only);
}
@@ -6983,11 +7151,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
FnTypeParamInfo *a_param_info = &a->param_info[i];
FnTypeParamInfo *b_param_info = &b->param_info[i];
- if (a_param_info->type != b_param_info->type) {
- return false;
- }
-
- if (a_param_info->is_noalias != b_param_info->is_noalias) {
+ if (a_param_info->type != b_param_info->type ||
+ a_param_info->is_noalias != b_param_info->is_noalias)
+ {
return false;
}
}
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 86b70d3c39..9d9f56cb3c 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -353,7 +353,8 @@ static void render_node(AstRender *ar, AstNode *node) {
assert(param_decl->type == NodeTypeParamDecl);
if (buf_len(&param_decl->data.param_decl.name) > 0) {
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
- fprintf(ar->f, "%s", noalias_str);
+ const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";
+ fprintf(ar->f, "%s%s", noalias_str, inline_str);
print_symbol(ar, &param_decl->data.param_decl.name);
fprintf(ar->f, ": ");
}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index da2aa25416..55e101fff8 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1062,12 +1062,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
TypeTableEntry *fn_type;
LLVMValueRef fn_val;
+ AstNode *generic_proto_node;
if (fn_table_entry) {
fn_val = fn_table_entry->fn_value;
fn_type = fn_table_entry->type_entry;
+ generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node;
} else {
fn_val = gen_expr(g, fn_ref_expr);
fn_type = get_expr_type(fn_ref_expr);
+ generic_proto_node = nullptr;
}
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) {
gen_param_index += 1;
}
- for (int i = 0; i < fn_call_param_count; i += 1) {
- AstNode *expr_node = node->data.fn_call_expr.params.at(i);
+ for (int call_i = 0; call_i < fn_call_param_count; call_i += 1) {
+ int proto_i = call_i + (struct_type ? 1 : 0);
+ if (generic_proto_node &&
+ generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
+ {
+ continue;
+ }
+ AstNode *expr_node = node->data.fn_call_expr.params.at(call_i);
LLVMValueRef param_value = gen_expr(g, expr_node);
assert(param_value);
TypeTableEntry *param_type = get_expr_type(expr_node);
@@ -3734,7 +3743,7 @@ static void delete_unused_builtin_fns(CodeGen *g) {
}
}
-static bool skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
+static bool should_skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
if (g->is_test_build) {
if (fn_entry->is_test) {
return false;
@@ -3889,7 +3898,7 @@ static void do_code_gen(CodeGen *g) {
// Generate function prototypes
for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
- if (skip_fn_codegen(g, fn_table_entry)) {
+ if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
LLVMDeleteFunction(fn_table_entry->fn_value);
fn_table_entry->fn_value = nullptr;
@@ -3995,7 +4004,7 @@ static void do_code_gen(CodeGen *g) {
// Generate function definitions.
for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
- if (skip_fn_codegen(g, fn_table_entry)) {
+ if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
continue;
}
diff --git a/src/eval.cpp b/src/eval.cpp
index 334a15fb4b..321a5d667f 100644
--- a/src/eval.cpp
+++ b/src/eval.cpp
@@ -884,9 +884,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
int param_count = node->data.fn_call_expr.params.length;
ConstExprValue *args = allocate<ConstExprValue>(param_count);
- for (int i = 0; i < param_count; i += 1) {
- AstNode *param_expr_node = node->data.fn_call_expr.params.at(i);
- ConstExprValue *param_val = &args[i];
+ for (int call_i = 0; call_i < param_count; call_i += 1) {
+ AstNode *param_expr_node = node->data.fn_call_expr.params.at(call_i);
+ ConstExprValue *param_val = &args[call_i];
if (eval_expr(ef, param_expr_node, param_val)) return true;
}
@@ -1291,6 +1291,13 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
}
static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) {
+ AstNode *acting_proto_node;
+ if (fn->proto_node->data.fn_proto.generic_proto_node) {
+ acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node;
+ } else {
+ acting_proto_node = fn->proto_node;
+ }
+
EvalFn ef = {0};
ef.root = efr;
ef.fn = fn;
@@ -1300,12 +1307,12 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context;
ef.scope_stack.append(root_scope);
- int param_count = fn->type_entry->data.fn.fn_type_id.param_count;
- for (int i = 0; i < param_count; i += 1) {
- AstNode *decl_param_node = fn->proto_node->data.fn_proto.params.at(i);
+ int param_count = acting_proto_node->data.fn_proto.params.length;
+ for (int proto_i = 0; proto_i < param_count; proto_i += 1) {
+ AstNode *decl_param_node = acting_proto_node->data.fn_proto.params.at(proto_i);
assert(decl_param_node->type == NodeTypeParamDecl);
- ConstExprValue *src_const_val = &args[i];
+ ConstExprValue *src_const_val = &args[proto_i];
assert(src_const_val->ok);
root_scope->vars.add_one();
@@ -1315,7 +1322,6 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
}
return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val);
-
}
bool 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
efr.call_node = node;
efr.branch_quota = branch_quota;
+ AstNode *acting_proto_node;
+ if (fn->proto_node->data.fn_proto.generic_proto_node) {
+ acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node;
+ } else {
+ acting_proto_node = fn->proto_node;
+ }
+
int call_param_count = node->data.fn_call_expr.params.length;
- int type_param_count = fn->type_entry->data.fn.fn_type_id.param_count;
- ConstExprValue *args = allocate<ConstExprValue>(type_param_count);
+ int proto_param_count = acting_proto_node->data.fn_proto.params.length;
+ ConstExprValue *args = allocate<ConstExprValue>(proto_param_count);
int next_arg_index = 0;
if (struct_node) {
ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val;
diff --git a/src/parser.cpp b/src/parser.cpp
index ff9a6268f9..418a9d210f 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -747,7 +747,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
}
/*
-ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..."
+ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
*/
static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
Token *token = &pc->tokens->at(*token_index);
@@ -763,6 +763,10 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
node->data.param_decl.is_noalias = true;
*token_index += 1;
token = &pc->tokens->at(*token_index);
+ } else if (token->id == TokenIdKeywordInline) {
+ node->data.param_decl.is_inline = true;
+ *token_index += 1;
+ token = &pc->tokens->at(*token_index);
}
buf_resize(&node->data.param_decl.name, 0);
@@ -2472,7 +2476,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
}
/*
-FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr)
+FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
@@ -2502,17 +2506,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
- Token *maybe_lparen = &pc->tokens->at(*token_index);
- if (maybe_lparen->id == TokenIdLParen) {
- for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
- node->data.fn_proto.generic_params.append(node->data.fn_proto.params.at(i));
- }
- node->data.fn_proto.generic_params_is_var_args = node->data.fn_proto.is_var_args;
-
- node->data.fn_proto.params.resize(0);
- ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
- }
-
Token *next_token = &pc->tokens->at(*token_index);
if (next_token->id == TokenIdArrow) {
*token_index += 1;
@@ -2931,7 +2924,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeFnProto:
visit_field(&node->data.fn_proto.return_type, visit, context);
visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context);
- visit_node_list(&node->data.fn_proto.generic_params, visit, context);
visit_node_list(&node->data.fn_proto.params, visit, context);
break;
case NodeTypeFnDef:
@@ -3123,6 +3115,22 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src
}
}
+static void clone_subtree_list_omit_inline_params(ZigList<AstNode *> *dest, ZigList<AstNode *> *src,
+ uint32_t *next_node_index)
+{
+ memset(dest, 0, sizeof(ZigList<AstNode *>));
+ dest->ensure_capacity(src->length);
+ for (int i = 0; i < src->length; i += 1) {
+ AstNode *src_node = src->at(i);
+ assert(src_node->type == NodeTypeParamDecl);
+ if (src_node->data.param_decl.is_inline) {
+ continue;
+ }
+ dest->append(ast_clone_subtree(src_node, next_node_index));
+ dest->last()->parent_field = &dest->last();
+ }
+}
+
static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,
uint32_t *next_node_index)
{
@@ -3133,20 +3141,26 @@ static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNod
}
}
-static void clone_subtree_field(AstNode **dest, AstNode *src, uint32_t *next_node_index) {
+static void clone_subtree_field_special(AstNode **dest, AstNode *src, uint32_t *next_node_index,
+ enum AstCloneSpecial special)
+{
if (src) {
- *dest = ast_clone_subtree(src, next_node_index);
+ *dest = ast_clone_subtree_special(src, next_node_index, special);
(*dest)->parent_field = dest;
} else {
*dest = nullptr;
}
}
+static void clone_subtree_field(AstNode **dest, AstNode *src, uint32_t *next_node_index) {
+ return clone_subtree_field_special(dest, src, next_node_index, AstCloneSpecialNone);
+}
+
static void clone_subtree_tld(TopLevelDecl *dest, TopLevelDecl *src, uint32_t *next_node_index) {
clone_subtree_list_ptr(&dest->directives, src->directives, next_node_index);
}
-AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
+AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, enum AstCloneSpecial special) {
AstNode *new_node = allocate_nonzero<AstNode>(1);
memcpy(new_node, old_node, sizeof(AstNode));
new_node->create_index = *next_node_index;
@@ -3163,14 +3177,19 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
next_node_index);
clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,
next_node_index);
- clone_subtree_list(&new_node->data.fn_proto.generic_params,
- &old_node->data.fn_proto.generic_params, next_node_index);
- clone_subtree_list(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
- next_node_index);
+
+ if (special == AstCloneSpecialOmitInlineParams) {
+ clone_subtree_list_omit_inline_params(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
+ next_node_index);
+ } else {
+ clone_subtree_list(&new_node->data.fn_proto.params, &old_node->data.fn_proto.params,
+ next_node_index);
+ }
break;
case NodeTypeFnDef:
- clone_subtree_field(&new_node->data.fn_def.fn_proto, old_node->data.fn_def.fn_proto, next_node_index);
+ clone_subtree_field_special(&new_node->data.fn_def.fn_proto, old_node->data.fn_def.fn_proto,
+ next_node_index, special);
new_node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = new_node;
clone_subtree_field(&new_node->data.fn_def.body, old_node->data.fn_def.body, next_node_index);
break;
@@ -3354,3 +3373,7 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
return new_node;
}
+
+AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) {
+ return ast_clone_subtree_special(old_node, next_node_index, AstCloneSpecialNone);
+}
diff --git a/src/parser.hpp b/src/parser.hpp
index 58da0234e6..ce8a42a4d8 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -25,6 +25,13 @@ void ast_print(AstNode *node, int indent);
void normalize_parent_ptrs(AstNode *node);
AstNode *ast_clone_subtree(AstNode *node, uint32_t *next_node_index);
+
+enum AstCloneSpecial {
+ AstCloneSpecialNone,
+ AstCloneSpecialOmitInlineParams,
+};
+AstNode *ast_clone_subtree_special(AstNode *node, uint32_t *next_node_index, enum AstCloneSpecial special);
+
void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context);
#endif