diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-07-24 18:35:50 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-07-25 22:55:15 -0700 |
| commit | 78d4fb20c44488117cc450177d92c44a19d97c91 (patch) | |
| tree | 3a39a09a30d7667de2e4fc62ab1c14fdaddb00b2 /src/analyze.cpp | |
| parent | 425c0ffa014fb950a4f9f90aa9a200fbc4d8e091 (diff) | |
| download | zig-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.cpp | 470 |
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; } } |
