aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
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;
}
}