aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
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/analyze.cpp
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/analyze.cpp')
-rw-r--r--src/analyze.cpp470
1 files changed, 318 insertions, 152 deletions
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;
}
}