| ... | ... | @@ -106,6 +106,11 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| 106 | 106 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); |
| 107 | 107 | entry->arrays_by_size.init(2); |
| 108 | 108 | entry->id = id; |
| 109 | |
| 110 | if (id == TypeTableEntryIdStruct) { |
| 111 | entry->data.structure.fn_table.init(8); |
| 112 | } |
| 113 | |
| 109 | 114 | return entry; |
| 110 | 115 | } |
| 111 | 116 | |
| ... | ... | @@ -461,6 +466,68 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 461 | 466 | struct_type->di_type = replacement_di_type; |
| 462 | 467 | } |
| 463 | 468 | |
| 469 | static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node, TypeTableEntry *struct_type) { |
| 470 | assert(node->type == NodeTypeFnDef); |
| 471 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 472 | assert(proto_node->type == NodeTypeFnProto); |
| 473 | Buf *proto_name = &proto_node->data.fn_proto.name; |
| 474 | |
| 475 | auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table; |
| 476 | |
| 477 | auto entry = fn_table->maybe_get(proto_name); |
| 478 | bool skip = false; |
| 479 | bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); |
| 480 | bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); |
| 481 | if (entry) { |
| 482 | add_node_error(g, node, |
| 483 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 484 | alloc_codegen_node(node); |
| 485 | node->codegen_node->data.fn_def_node.skip = true; |
| 486 | skip = true; |
| 487 | } else if (is_pub) { |
| 488 | auto entry = fn_table->maybe_get(proto_name); |
| 489 | if (entry) { |
| 490 | add_node_error(g, node, |
| 491 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 492 | alloc_codegen_node(node); |
| 493 | node->codegen_node->data.fn_def_node.skip = true; |
| 494 | skip = true; |
| 495 | } |
| 496 | } |
| 497 | if (proto_node->data.fn_proto.is_var_args) { |
| 498 | add_node_error(g, node, |
| 499 | buf_sprintf("variadic arguments only allowed in extern functions")); |
| 500 | } |
| 501 | if (!skip) { |
| 502 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 503 | fn_table_entry->import_entry = import; |
| 504 | fn_table_entry->proto_node = proto_node; |
| 505 | fn_table_entry->fn_def_node = node; |
| 506 | fn_table_entry->internal_linkage = is_internal; |
| 507 | fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; |
| 508 | fn_table_entry->label_table.init(8); |
| 509 | |
| 510 | g->fn_protos.append(fn_table_entry); |
| 511 | g->fn_defs.append(fn_table_entry); |
| 512 | |
| 513 | fn_table->put(proto_name, fn_table_entry); |
| 514 | |
| 515 | if (!struct_type && |
| 516 | g->bootstrap_import && |
| 517 | import == g->root_import && buf_eql_str(proto_name, "main")) |
| 518 | { |
| 519 | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); |
| 520 | } |
| 521 | |
| 522 | resolve_function_proto(g, proto_node, fn_table_entry, import); |
| 523 | |
| 524 | |
| 525 | alloc_codegen_node(proto_node); |
| 526 | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| 527 | |
| 528 | preview_function_labels(g, node->data.fn_def.body, fn_table_entry); |
| 529 | } |
| 530 | } |
| 464 | 531 | |
| 465 | 532 | static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 466 | 533 | switch (node->type) { |
| ... | ... | @@ -500,61 +567,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 500 | 567 | } |
| 501 | 568 | break; |
| 502 | 569 | case NodeTypeFnDef: |
| 503 | | { |
| 504 | | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 505 | | assert(proto_node->type == NodeTypeFnProto); |
| 506 | | Buf *proto_name = &proto_node->data.fn_proto.name; |
| 507 | | auto entry = import->fn_table.maybe_get(proto_name); |
| 508 | | bool skip = false; |
| 509 | | bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); |
| 510 | | bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); |
| 511 | | if (entry) { |
| 512 | | add_node_error(g, node, |
| 513 | | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 514 | | alloc_codegen_node(node); |
| 515 | | node->codegen_node->data.fn_def_node.skip = true; |
| 516 | | skip = true; |
| 517 | | } else if (is_pub) { |
| 518 | | auto entry = import->fn_table.maybe_get(proto_name); |
| 519 | | if (entry) { |
| 520 | | add_node_error(g, node, |
| 521 | | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 522 | | alloc_codegen_node(node); |
| 523 | | node->codegen_node->data.fn_def_node.skip = true; |
| 524 | | skip = true; |
| 525 | | } |
| 526 | | } |
| 527 | | if (proto_node->data.fn_proto.is_var_args) { |
| 528 | | add_node_error(g, node, |
| 529 | | buf_sprintf("variadic arguments only allowed in extern functions")); |
| 530 | | } |
| 531 | | if (!skip) { |
| 532 | | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 533 | | fn_table_entry->import_entry = import; |
| 534 | | fn_table_entry->proto_node = proto_node; |
| 535 | | fn_table_entry->fn_def_node = node; |
| 536 | | fn_table_entry->internal_linkage = is_internal; |
| 537 | | fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; |
| 538 | | fn_table_entry->label_table.init(8); |
| 539 | | |
| 540 | | g->fn_protos.append(fn_table_entry); |
| 541 | | g->fn_defs.append(fn_table_entry); |
| 542 | | |
| 543 | | import->fn_table.put(proto_name, fn_table_entry); |
| 544 | | |
| 545 | | if (g->bootstrap_import && import == g->root_import && buf_eql_str(proto_name, "main")) { |
| 546 | | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); |
| 547 | | } |
| 548 | | |
| 549 | | resolve_function_proto(g, proto_node, fn_table_entry, import); |
| 550 | | |
| 551 | | |
| 552 | | alloc_codegen_node(proto_node); |
| 553 | | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| 554 | | |
| 555 | | preview_function_labels(g, node->data.fn_def.body, fn_table_entry); |
| 556 | | } |
| 557 | | } |
| 570 | preview_fn_def(g, import, node, nullptr); |
| 558 | 571 | break; |
| 559 | 572 | case NodeTypeRootExportDecl: |
| 560 | 573 | if (import == g->root_import) { |
| ... | ... | @@ -605,6 +618,11 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 605 | 618 | TypeTableEntry *type_entry = struct_codegen->type_entry; |
| 606 | 619 | |
| 607 | 620 | resolve_struct_type(g, import, type_entry); |
| 621 | |
| 622 | for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { |
| 623 | AstNode *fn_def_node = node->data.struct_decl.fns.at(i); |
| 624 | preview_fn_def(g, import, fn_def_node, type_entry); |
| 625 | } |
| 608 | 626 | break; |
| 609 | 627 | } |
| 610 | 628 | case NodeTypeUse: |
| ... | ... | @@ -1624,6 +1642,94 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im |
| 1624 | 1642 | } |
| 1625 | 1643 | } |
| 1626 | 1644 | |
| 1645 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1646 | TypeTableEntry *expected_type, AstNode *node) |
| 1647 | { |
| 1648 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 1649 | TypeTableEntry *struct_type = nullptr; |
| 1650 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> *fn_table = &import->fn_table; |
| 1651 | AstNode *first_param_expr = nullptr; |
| 1652 | Buf *name; |
| 1653 | |
| 1654 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { |
| 1655 | first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; |
| 1656 | struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); |
| 1657 | name = &fn_ref_expr->data.field_access_expr.field_name; |
| 1658 | if (struct_type->id == TypeTableEntryIdStruct) { |
| 1659 | fn_table = &struct_type->data.structure.fn_table; |
| 1660 | } else if (struct_type->id == TypeTableEntryIdInvalid) { |
| 1661 | return struct_type; |
| 1662 | } else { |
| 1663 | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, |
| 1664 | buf_sprintf("member reference base type not struct or enum")); |
| 1665 | return g->builtin_types.entry_invalid; |
| 1666 | } |
| 1667 | } else if (fn_ref_expr->type == NodeTypeSymbol) { |
| 1668 | name = &fn_ref_expr->data.symbol; |
| 1669 | } else { |
| 1670 | add_node_error(g, node, |
| 1671 | buf_sprintf("function pointers not yet supported")); |
| 1672 | return g->builtin_types.entry_invalid; |
| 1673 | } |
| 1674 | |
| 1675 | auto entry = fn_table->maybe_get(name); |
| 1676 | |
| 1677 | if (!entry) { |
| 1678 | add_node_error(g, fn_ref_expr, |
| 1679 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 1680 | // still analyze the parameters, even though we don't know what to expect |
| 1681 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 1682 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 1683 | analyze_expression(g, import, context, nullptr, child); |
| 1684 | } |
| 1685 | |
| 1686 | return g->builtin_types.entry_invalid; |
| 1687 | } else { |
| 1688 | FnTableEntry *fn_table_entry = entry->value; |
| 1689 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 1690 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| 1691 | |
| 1692 | // count parameters |
| 1693 | int expected_param_count = fn_proto->params.length; |
| 1694 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 1695 | |
| 1696 | if (struct_type) { |
| 1697 | actual_param_count += 1; |
| 1698 | } |
| 1699 | |
| 1700 | if (fn_proto->is_var_args) { |
| 1701 | if (actual_param_count < expected_param_count) { |
| 1702 | add_node_error(g, node, |
| 1703 | buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", |
| 1704 | expected_param_count, actual_param_count)); |
| 1705 | } |
| 1706 | } else if (expected_param_count != actual_param_count) { |
| 1707 | add_node_error(g, node, |
| 1708 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| 1709 | expected_param_count, actual_param_count)); |
| 1710 | } |
| 1711 | |
| 1712 | // analyze each parameter. in the case of a method, we already analyzed the |
| 1713 | // first parameter in order to figure out which struct we were calling a method on. |
| 1714 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 1715 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 1716 | // determine the expected type for each parameter |
| 1717 | TypeTableEntry *expected_param_type = nullptr; |
| 1718 | int fn_proto_i = i + (struct_type ? 1 : 0); |
| 1719 | if (fn_proto_i < fn_proto->params.length) { |
| 1720 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); |
| 1721 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 1722 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| 1723 | if (param_type_node->codegen_node) |
| 1724 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; |
| 1725 | } |
| 1726 | analyze_expression(g, import, context, expected_param_type, child); |
| 1727 | } |
| 1728 | |
| 1729 | return fn_proto->return_type->codegen_node->data.type_node.entry; |
| 1730 | } |
| 1731 | } |
| 1732 | |
| 1627 | 1733 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1628 | 1734 | TypeTableEntry *expected_type, AstNode *node) |
| 1629 | 1735 | { |
| ... | ... | @@ -1739,67 +1845,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1739 | 1845 | break; |
| 1740 | 1846 | |
| 1741 | 1847 | case NodeTypeFnCallExpr: |
| 1742 | | { |
| 1743 | | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 1744 | | if (fn_ref_expr->type != NodeTypeSymbol) { |
| 1745 | | add_node_error(g, node, |
| 1746 | | buf_sprintf("function pointers not allowed")); |
| 1747 | | break; |
| 1748 | | } |
| 1749 | | |
| 1750 | | Buf *name = &fn_ref_expr->data.symbol; |
| 1751 | | |
| 1752 | | auto entry = import->fn_table.maybe_get(name); |
| 1753 | | |
| 1754 | | if (!entry) { |
| 1755 | | add_node_error(g, fn_ref_expr, |
| 1756 | | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 1757 | | // still analyze the parameters, even though we don't know what to expect |
| 1758 | | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 1759 | | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 1760 | | analyze_expression(g, import, context, nullptr, child); |
| 1761 | | } |
| 1762 | | |
| 1763 | | return_type = g->builtin_types.entry_invalid; |
| 1764 | | } else { |
| 1765 | | FnTableEntry *fn_table_entry = entry->value; |
| 1766 | | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 1767 | | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| 1768 | | |
| 1769 | | // count parameters |
| 1770 | | int expected_param_count = fn_proto->params.length; |
| 1771 | | int actual_param_count = node->data.fn_call_expr.params.length; |
| 1772 | | if (fn_proto->is_var_args) { |
| 1773 | | if (actual_param_count < expected_param_count) { |
| 1774 | | add_node_error(g, node, |
| 1775 | | buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", |
| 1776 | | expected_param_count, actual_param_count)); |
| 1777 | | } |
| 1778 | | } else if (expected_param_count != actual_param_count) { |
| 1779 | | add_node_error(g, node, |
| 1780 | | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| 1781 | | expected_param_count, actual_param_count)); |
| 1782 | | } |
| 1783 | | |
| 1784 | | // analyze each parameter |
| 1785 | | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 1786 | | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 1787 | | // determine the expected type for each parameter |
| 1788 | | TypeTableEntry *expected_param_type = nullptr; |
| 1789 | | if (i < fn_proto->params.length) { |
| 1790 | | AstNode *param_decl_node = fn_proto->params.at(i); |
| 1791 | | assert(param_decl_node->type == NodeTypeParamDecl); |
| 1792 | | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| 1793 | | if (param_type_node->codegen_node) |
| 1794 | | expected_param_type = param_type_node->codegen_node->data.type_node.entry; |
| 1795 | | } |
| 1796 | | analyze_expression(g, import, context, expected_param_type, child); |
| 1797 | | } |
| 1798 | | |
| 1799 | | return_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 1800 | | } |
| 1801 | | break; |
| 1802 | | } |
| 1848 | return_type = analyze_fn_call_expr(g, import, context, expected_type, node); |
| 1849 | break; |
| 1803 | 1850 | |
| 1804 | 1851 | case NodeTypeArrayAccessExpr: |
| 1805 | 1852 | // for reading array access; assignment handled elsewhere |
| ... | ... | @@ -1924,89 +1971,92 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1924 | 1971 | return return_type; |
| 1925 | 1972 | } |
| 1926 | 1973 | |
| 1927 | | static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 1928 | | switch (node->type) { |
| 1929 | | case NodeTypeFnDef: |
| 1930 | | { |
| 1931 | | if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { |
| 1932 | | // we detected an error with this function definition which prevents us |
| 1933 | | // from further analyzing it. |
| 1934 | | break; |
| 1935 | | } |
| 1974 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 1975 | assert(node->type == NodeTypeFnDef); |
| 1936 | 1976 | |
| 1937 | | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 1938 | | assert(fn_proto_node->type == NodeTypeFnProto); |
| 1977 | if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { |
| 1978 | // we detected an error with this function definition which prevents us |
| 1979 | // from further analyzing it. |
| 1980 | return; |
| 1981 | } |
| 1939 | 1982 | |
| 1940 | | alloc_codegen_node(node); |
| 1941 | | BlockContext *context = new_block_context(node, import->block_context); |
| 1942 | | node->codegen_node->data.fn_def_node.block_context = context; |
| 1943 | | |
| 1944 | | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| 1945 | | bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); |
| 1946 | | for (int i = 0; i < fn_proto->params.length; i += 1) { |
| 1947 | | AstNode *param_decl_node = fn_proto->params.at(i); |
| 1948 | | assert(param_decl_node->type == NodeTypeParamDecl); |
| 1949 | | |
| 1950 | | // define local variables for parameters |
| 1951 | | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; |
| 1952 | | assert(param_decl->type->type == NodeTypeType); |
| 1953 | | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; |
| 1954 | | |
| 1955 | | if (is_exported && type->id == TypeTableEntryIdStruct) { |
| 1956 | | add_node_error(g, param_decl_node, |
| 1957 | | buf_sprintf("byvalue struct parameters not yet supported on exported functions")); |
| 1958 | | } |
| 1983 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 1984 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 1959 | 1985 | |
| 1960 | | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 1961 | | buf_init_from_buf(&variable_entry->name, &param_decl->name); |
| 1962 | | variable_entry->type = type; |
| 1963 | | variable_entry->is_const = true; |
| 1964 | | variable_entry->decl_node = param_decl_node; |
| 1965 | | variable_entry->arg_index = i; |
| 1986 | alloc_codegen_node(node); |
| 1987 | BlockContext *context = new_block_context(node, import->block_context); |
| 1988 | node->codegen_node->data.fn_def_node.block_context = context; |
| 1989 | |
| 1990 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| 1991 | bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); |
| 1992 | for (int i = 0; i < fn_proto->params.length; i += 1) { |
| 1993 | AstNode *param_decl_node = fn_proto->params.at(i); |
| 1994 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 1995 | |
| 1996 | // define local variables for parameters |
| 1997 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; |
| 1998 | assert(param_decl->type->type == NodeTypeType); |
| 1999 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; |
| 2000 | |
| 2001 | if (is_exported && type->id == TypeTableEntryIdStruct) { |
| 2002 | add_node_error(g, param_decl_node, |
| 2003 | buf_sprintf("byvalue struct parameters not yet supported on exported functions")); |
| 2004 | } |
| 1966 | 2005 | |
| 1967 | | alloc_codegen_node(param_decl_node); |
| 1968 | | param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; |
| 2006 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 2007 | buf_init_from_buf(&variable_entry->name, &param_decl->name); |
| 2008 | variable_entry->type = type; |
| 2009 | variable_entry->is_const = true; |
| 2010 | variable_entry->decl_node = param_decl_node; |
| 2011 | variable_entry->arg_index = i; |
| 1969 | 2012 | |
| 1970 | | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); |
| 1971 | | if (!existing_entry) { |
| 1972 | | // unique definition |
| 1973 | | context->variable_table.put(&variable_entry->name, variable_entry); |
| 1974 | | } else { |
| 1975 | | add_node_error(g, node, |
| 1976 | | buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); |
| 1977 | | if (existing_entry->type == variable_entry->type) { |
| 1978 | | // types agree, so the type is probably good enough for the rest of analysis |
| 1979 | | } else { |
| 1980 | | // types disagree. don't trust either one of them. |
| 1981 | | existing_entry->type = g->builtin_types.entry_invalid;; |
| 1982 | | } |
| 1983 | | } |
| 1984 | | } |
| 2013 | alloc_codegen_node(param_decl_node); |
| 2014 | param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; |
| 1985 | 2015 | |
| 1986 | | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 1987 | | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); |
| 2016 | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); |
| 2017 | if (!existing_entry) { |
| 2018 | // unique definition |
| 2019 | context->variable_table.put(&variable_entry->name, variable_entry); |
| 2020 | } else { |
| 2021 | add_node_error(g, node, |
| 2022 | buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); |
| 2023 | if (existing_entry->type == variable_entry->type) { |
| 2024 | // types agree, so the type is probably good enough for the rest of analysis |
| 2025 | } else { |
| 2026 | // types disagree. don't trust either one of them. |
| 2027 | existing_entry->type = g->builtin_types.entry_invalid;; |
| 2028 | } |
| 2029 | } |
| 2030 | } |
| 1988 | 2031 | |
| 1989 | | node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; |
| 2032 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 2033 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); |
| 1990 | 2034 | |
| 1991 | | { |
| 1992 | | FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; |
| 1993 | | auto it = fn_table_entry->label_table.entry_iterator(); |
| 1994 | | for (;;) { |
| 1995 | | auto *entry = it.next(); |
| 1996 | | if (!entry) |
| 1997 | | break; |
| 2035 | node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; |
| 1998 | 2036 | |
| 1999 | | LabelTableEntry *label_entry = entry->value; |
| 2000 | | if (!label_entry->used) { |
| 2001 | | add_node_error(g, label_entry->label_node, |
| 2002 | | buf_sprintf("label '%s' defined but not used", |
| 2003 | | buf_ptr(&label_entry->label_node->data.label.name))); |
| 2004 | | } |
| 2005 | | } |
| 2006 | | } |
| 2037 | { |
| 2038 | FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; |
| 2039 | auto it = fn_table_entry->label_table.entry_iterator(); |
| 2040 | for (;;) { |
| 2041 | auto *entry = it.next(); |
| 2042 | if (!entry) |
| 2043 | break; |
| 2044 | |
| 2045 | LabelTableEntry *label_entry = entry->value; |
| 2046 | if (!label_entry->used) { |
| 2047 | add_node_error(g, label_entry->label_node, |
| 2048 | buf_sprintf("label '%s' defined but not used", |
| 2049 | buf_ptr(&label_entry->label_node->data.label.name))); |
| 2007 | 2050 | } |
| 2008 | | break; |
| 2051 | } |
| 2052 | } |
| 2053 | } |
| 2009 | 2054 | |
| 2055 | static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 2056 | switch (node->type) { |
| 2057 | case NodeTypeFnDef: |
| 2058 | analyze_top_level_fn_def(g, import, node); |
| 2059 | break; |
| 2010 | 2060 | case NodeTypeRootExportDecl: |
| 2011 | 2061 | case NodeTypeExternBlock: |
| 2012 | 2062 | // already looked at these in the preview pass |
| ... | ... | @@ -2048,8 +2098,13 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 2048 | 2098 | break; |
| 2049 | 2099 | } |
| 2050 | 2100 | case NodeTypeStructDecl: |
| 2051 | | // nothing to do |
| 2052 | | break; |
| 2101 | { |
| 2102 | for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { |
| 2103 | AstNode *fn_def_node = node->data.struct_decl.fns.at(i); |
| 2104 | analyze_top_level_fn_def(g, import, fn_def_node); |
| 2105 | } |
| 2106 | break; |
| 2107 | } |
| 2053 | 2108 | case NodeTypeVariableDeclaration: |
| 2054 | 2109 | { |
| 2055 | 2110 | VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, |